You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
6.7 KiB
276 lines
6.7 KiB
7 months ago
|
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<Recordable[]>;
|
||
|
columns: ComputedRef<Recordable[]>;
|
||
|
rowKey: String;
|
||
|
editable: Ref<Boolean>;
|
||
|
}
|
||
|
|
||
|
export function useTableEdit({ dataSource, columns, rowKey, editable }: UseTableEdit) {
|
||
|
const instance = getCurrentInstance();
|
||
|
const emit = instance?.emit;
|
||
|
|
||
|
const editableData: UnwrapRef<Recordable> = reactive({}); //编辑关联数据
|
||
|
const validateData: UnwrapRef<Recordable> = 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,
|
||
|
};
|
||
|
}
|