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

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,
};
}