vben
2020-12-25 4ff1c408dc1acfc49e0adc61dc2e539c0c198158
提交 | 用户 | age
73c8e0 1 import '../style/editable-cell.less';
V 2
0b6110 3 import { defineComponent, PropType, ref, unref, nextTick, watchEffect } from 'vue';
73c8e0 4 import { ClickOutSide } from '/@/components/ClickOutSide';
0b6110 5
V 6 import { RenderEditableCellParams } from '../types/table';
7 import { ComponentType } from '../types/componentType';
8
9 import { componentMap } from '../componentMap';
404db2 10 import { isString, isBoolean, isArray } from '/@/utils/is';
0b6110 11 import { FormOutlined, CloseOutlined, CheckOutlined } from '@ant-design/icons-vue';
V 12
13 const prefixCls = 'editable-cell';
14 const EditableCell = defineComponent({
15   name: 'EditableCell',
16   props: {
17     value: {
18       type: String as PropType<string>,
19       default: '',
20     },
21     componentProps: {
22       type: Object as PropType<any>,
23       default: null,
24     },
25
26     dataKey: {
27       type: String as PropType<string>,
28       default: '',
29     },
30
31     dataIndex: {
32       type: String as PropType<string>,
33       default: '',
34     },
35
36     component: {
37       type: String as PropType<ComponentType>,
38       default: 'Input',
39     },
40     editable: {
41       type: Boolean as PropType<boolean>,
42       default: false,
43     },
44     editRow: {
45       type: Boolean as PropType<boolean>,
46       default: false,
47     },
48     record: {
49       type: Object as PropType<EditRecordRow>,
50     },
51     placeholder: {
52       type: String as PropType<string>,
404db2 53       default: '',
0b6110 54     },
V 55   },
56   emits: ['submit', 'cancel'],
57   setup(props, { attrs, emit }) {
58     const elRef = ref<any>(null);
59
60     const isEditRef = ref(false);
61     const currentValueRef = ref<string | boolean>(props.value);
62     const defaultValueRef = ref<string | boolean>(props.value);
63
64     watchEffect(() => {
65       defaultValueRef.value = props.value;
66       if (isBoolean(props.editable)) {
67         isEditRef.value = props.editable;
68       }
69     });
70
71     function handleChange(e: any) {
72       if (e && e.target && Reflect.has(e.target, 'value')) {
73         currentValueRef.value = (e as ChangeEvent).target.value;
74       }
75       if (isString(e) || isBoolean(e)) {
76         currentValueRef.value = e;
77       }
78     }
79
80     function handleEdit() {
81       isEditRef.value = true;
82       nextTick(() => {
83         const el = unref(elRef);
84         el && el.focus();
85       });
86     }
87
88     function handleCancel() {
89       isEditRef.value = false;
90       currentValueRef.value = defaultValueRef.value;
91       emit('cancel');
92     }
93
94     if (props.record) {
95       /* eslint-disable  */
404db2 96       isArray(props.record.submitCbs)
H 97         ? props.record.submitCbs.push(handleSubmit)
98         : (props.record.submitCbs = [handleSubmit]);
99       /* eslint-disable  */
100       isArray(props.record.cancelCbs)
101         ? props.record.cancelCbs.push(handleCancel)
102         : (props.record.cancelCbs = [handleCancel]);
103
104       /* eslint-disable  */
105       props.record.onCancel = () => {
106         isArray(props.record?.cancelCbs) && props.record?.cancelCbs.forEach((fn) => fn());
107       };
0b6110 108       /* eslint-disable */
404db2 109       props.record.onSubmit = () => {
H 110         isArray(props.record?.submitCbs) && props.record?.submitCbs.forEach((fn) => fn());
111       };
0b6110 112     }
V 113
114     function handleSubmit() {
115       const { dataKey, dataIndex } = props;
116       if (!dataKey || !dataIndex) return;
117
118       if (props.record) {
119         /* eslint-disable */
120         props.record[dataIndex] = unref(currentValueRef) as string;
121       }
122       isEditRef.value = false;
123     }
124
125     function onClickOutside() {
126       if (props.editRow) return;
127       const { component } = props;
128
129       if (component && component.includes('Input')) {
130         handleCancel();
131       }
132     }
133
134     function renderValue() {
135       const { value } = props;
136       if (props.editRow) {
137         return !unref(isEditRef) ? value : null;
138       }
139       return (
140         !unref(isEditRef) && (
141           <div class={`${prefixCls}__normal`} onClick={handleEdit}>
142             {value}
143             <FormOutlined class={`${prefixCls}__normal-icon`} />
144           </div>
145         )
146       );
147     }
148     return () => {
149       const { component, componentProps = {} } = props;
150
151       const Comp = componentMap.get(component!) as any;
152       return (
153         <div class={prefixCls}>
154           {unref(isEditRef) && (
155             <ClickOutSide onClickOutside={onClickOutside}>
156               {() => (
157                 <div class={`${prefixCls}__wrapper`}>
158                   <Comp
159                     placeholder={props.placeholder}
160                     {...{
161                       ...attrs,
162                       ...componentProps,
163                     }}
164                     style={{ width: 'calc(100% - 48px)' }}
165                     ref={elRef}
166                     value={unref(currentValueRef)}
167                     size="small"
168                     onChange={handleChange}
169                     onPressEnter={handleSubmit}
170                   />
171                   {!props.editRow && (
172                     <div class={`${prefixCls}__action`}>
173                       <CheckOutlined
174                         class={[`${prefixCls}__icon`, 'mx-2']}
175                         onClick={handleSubmit}
176                       />
177                       <CloseOutlined class={[`${prefixCls}__icon `]} onClick={handleCancel} />
178                     </div>
179                   )}
180                 </div>
181               )}
182             </ClickOutSide>
183           )}
184           {renderValue()}
185         </div>
186       );
187     };
188   },
189 });
190
191 export function renderEditableCell({
192   dataIndex,
193   component,
194   componentProps = {},
195   placeholder,
196 }: RenderEditableCellParams) {
197   return ({ text, record }: { text: string; record: EditRecordRow }) => {
198     return (
199       <EditableCell
200         {...componentProps}
201         placeholder={placeholder}
202         value={text}
203         record={record}
204         dataKey={record.key}
205         dataIndex={dataIndex}
206         component={component}
207       />
208     );
209   };
210 }
211
212 export function renderEditableRow({
213   dataIndex,
214   component,
215   componentProps = {},
216   placeholder,
217 }: RenderEditableCellParams) {
218   return ({ text, record }: { text: string; record: EditRecordRow }) => {
219     return (
220       <EditableCell
221         {...componentProps}
222         value={text}
223         placeholder={placeholder}
224         editRow={true}
225         editable={record.editable}
226         dataKey={record.key}
227         record={record}
228         dataIndex={dataIndex}
229         component={component}
230       />
231     );
232   };
233 }
234
4ff1c4 235 export type EditRecordRow<T = Hash<any>> = {
0b6110 236   editable: boolean;
V 237   onCancel: Fn;
238   onSubmit: Fn;
404db2 239   submitCbs: Fn[];
H 240   cancelCbs: Fn[];
0b6110 241 } & T;