import { cloneDeep, isUndefined } from 'lodash-es'; import { ComputedRef, getCurrentInstance, inject, reactive, ref, Ref, toRaw, UnwrapRef, watch, } from 'vue'; import Schema from 'async-validator'; import { RuleItem, ValidateError } from 'async-validator/dist-types/interface'; export interface TableEdit { tableEdit?: Function; tableSave?: Function; tableCancel?: Function; tableDelete?: Function; addRow?: Function; getKey?: Function; validate?: Function; getValidate?: Function; setValidate?: Function; setValue?: Function; getValue?: Function; } export interface UseTableEdit { dataSource: Ref; columns: ComputedRef; rowKey: String; editable: Ref; } export function useTableEdit({ dataSource, columns, rowKey, editable }: UseTableEdit) { const instance = getCurrentInstance(); const emit = instance?.emit; const editableData: UnwrapRef = reactive({}); //编辑关联数据 const validateData: UnwrapRef = reactive({}); //验证数据 let autoKey = 0; function getKey(record: Recordable): string { // if (isUndefined(record[rowKey])) // console.error(`rowKey: ${rowKey} not find in ${JSON.stringify(record)}`); return record[rowKey]; } function getValue(key?: string, field?: string): any { if (!key && !field) { //表格编辑 editableData会附加额外的单元格字段 return dataSource.value; } else if (!field) { //行编辑 return editableData[key as string]; } return editableData[key] ? editableData[key][field] : editableData[`${key}_${field}`]; // 单元格编辑 } function addRow(item = {}) { const row = cloneDeep(item); row[rowKey] = ++autoKey; dataSource.value.push(row); console.log('addRow', item); console.log('dataSource.value', dataSource.value); tableEdit(row[rowKey]); } function setValue(key: string, val: any, field?: string) { if (!field) { editableData[key] = val; } else { editableData[key] ? (editableData[key][field] = val) : (editableData[`${key}_${field}`] = val); } } function deleteValue(key: string, field?: string) { if (!field) { delete editableData[key]; } else { delete editableData[`${key}_${field}`]; } } function getValidate(key: string, field?: string) { if (!field) { return validateData[key]; } else { return validateData[`${key}_${field}`]; } } function setValidate(key: string, val: any, field?: string) { if (!field) { validateData[key] = val; } else { validateData[`${key}_${field}`] = val; } } function deleteValidate(key: string, field?: string) { if (!field) { delete validateData[key]; } else { delete validateData[`${key}_${field}`]; } } const validator: Recordable = {}; const rules: RuleItem = inject('rules', ref({})).value; if (rules.defaultField?.fields) { Object.keys(rules.defaultField.fields).forEach(function (key) { validator[key] = new Schema({ [key]: rules.defaultField.fields[key] }); }); } validator['ROW'] = new Schema(rules.defaultField?.fields || {}); validator['TABLE'] = new Schema({ table: rules, }); const getValidator = (key = 'ROW') => { return validator[key]; }; /** * 验证行 * @param key */ const validate = (key?: string, field?: string) => { if (!key && !field) { return getValidator('TABLE') .validate({ table: dataSource.value }) .then(() => { return Promise.resolve(); }) .catch(({ errors }: { errors: ValidateError[] }) => { return Promise.reject(new Error(errors[0].message)); }); } else if (!field) { return getValidator('ROW') .validate(getValue(key)) .then(() => { return Promise.resolve(); }) .catch(({ errors }: { errors: ValidateError[] }) => { return Promise.reject(new Error(errors[0].message)); }); } else if (key) { return getValidator(field)?.validate({ [field]: getValue(key, field) }, (errors) => { if (errors) { setValidate(key, errors[0], field); } else { setValidate(key, undefined, field); } }); } }; /** * 编辑行 * @param key */ const tableEdit = (key: string, field?: string) => { const item = dataSource.value.filter((item) => key === item[rowKey as keyof Recordable])[0]; if (!field) { const validateItem: Recordable = {}; Object.keys(item).forEach((field) => (validateItem[field] = undefined)); setValidate(key, validateItem); // 表格编辑时为引用,否则为深拷贝 if (editable.value) { setValue(key, item); } else { setValue(key, cloneDeep(item)); } } else { setValue(key, item[field], field); setValidate(key, undefined, field); } }; /** * 保存 * @param key */ const tableSave = (key: string, field?: string) => { const data = dataSource.value.filter( (item: Recordable) => key === item[rowKey as keyof Recordable] )[0]; if (!field) { Object.assign(data, getValue(key)); deleteValue(key); deleteValidate(key); } else { data[field] = getValue(key, field); emit?.('cellChange', { field, value: data[field], key, record: toRaw(data) }); deleteValue(key, field); deleteValidate(key, field); } }; const tableDelete = (key: string) => { console.log('tableDelete', key); deleteValue(key); deleteValidate(key); dataSource.value.splice( dataSource.value.findIndex((item) => item[rowKey] === key), 1 ); }; /** * 取消编辑 * @param key */ const tableCancel = (key: string, field?: string) => { if (field) { deleteValue(key); } else { deleteValue(key, field); } }; /** * 设置dataSource111 * @param data */ watch( () => dataSource.value, (val, prev) => { // console.log(val, prev); if (editable.value) { Object.keys(editableData).forEach((key) => { delete editableData[key]; }); Object.keys(validateData).forEach((key) => { delete validateData[key]; }); console.log('dataSource.value', dataSource.value); dataSource.value.forEach((item) => { item[rowKey] = ++autoKey; tableEdit(item[rowKey as keyof Recordable]); }); } }, { immediate: true, } ); return { tableEdit, tableSave, tableCancel, tableDelete, addRow, getKey, validate, getValidate, setValidate, setValue, getValue, }; }