Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions packages/components/table/components/editable-cell.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { computed, defineComponent, onMounted, PropType, ref, SetupContext, toRefs, watch } from 'vue';
import { computed, defineComponent, onMounted, PropType, ref, SetupContext, toRefs, watch, inject } from 'vue';
import { get, set, isFunction, cloneDeep, isObject } from 'lodash-es';
import { Edit1Icon as TdEdit1Icon } from 'tdesign-icons-vue-next';
import {
Expand All @@ -20,6 +20,7 @@ import { on, off } from '@tdesign/shared-utils';
export interface OnEditableChangeContext<T> extends PrimaryTableRowEditContext<T> {
isEdit: boolean;
validateEdit: (trigger: 'self' | 'parent') => Promise<true | AllValidateResult[]>;
clearErrors?: () => void;
}

export interface EditableCellProps {
Expand Down Expand Up @@ -86,6 +87,8 @@ export default defineComponent({
const classPrefix = usePrefixClass();

const { Edit1Icon } = useGlobalIcon({ Edit1Icon: TdEdit1Icon });
// 表格作用域内的临时抑制标志(由 primary-table 提供)
const tableValidSuppress = inject('TD_TABLE_SUPPRESS_VALIDATE') as { value?: boolean } | undefined;

const updateEditedCellValue: TableEditableCellPropsParams<TableRowData>['updateEditedCellValue'] = (obj) => {
if (typeof obj === 'object' && ('rowValue' in obj || obj.isUpdateCurrentRow)) {
Expand Down Expand Up @@ -175,6 +178,11 @@ export default defineComponent({

const validateEdit = (trigger: 'self' | 'parent'): Promise<true | AllValidateResult[]> => {
return new Promise((resolve) => {
// 如果父表格临时抑制了校验(例如点击清理按钮导致 blur),则直接短路校验
if (tableValidSuppress?.value) {
resolve(true);
return;
}
const params: PrimaryTableRowValidateContext<TableRowData> = {
result: [
{
Expand Down Expand Up @@ -209,6 +217,10 @@ export default defineComponent({
});
};

const clearErrors = () => {
errorList.value = [];
};

const isSame = (a: any, b: any) => {
if (isObject(a) && isObject(b)) {
return JSON.stringify(a) === JSON.stringify(b);
Expand All @@ -218,6 +230,8 @@ export default defineComponent({

const updateAndSaveAbort = (outsideAbortEvent: Function, eventName: string, ...args: any) => {
validateEdit('self').then((result) => {
// 如果表格层面正在抑制校验(例如 clearValidateData 期间),不要因校验短路而退出编辑态
if (tableValidSuppress?.value) return;
if (result !== true) return;
const oldValue = get(row.value, col.value.colKey);
// 相同的值无需触发变化
Expand All @@ -237,7 +251,8 @@ export default defineComponent({
editedRow: { ...props.row, [props.col.colKey]: editValue.value },
validateEdit,
isEdit: false,
});
clearErrors,
} as OnEditableChangeContext<TableRowData>);
clearTimeout(timer);
}, 0);
});
Expand Down Expand Up @@ -324,7 +339,8 @@ export default defineComponent({
editedRow: props.row,
isEdit: true,
validateEdit,
});
clearErrors,
} as OnEditableChangeContext<TableRowData>);
};

const onCellClick = (e: MouseEvent) => {
Expand Down
30 changes: 28 additions & 2 deletions packages/components/table/hooks/useEditableRow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export default function useRowEdit(props: PrimaryTableProps) {
const editingCells = ref<{ [cellKey: string]: OnEditableChangeContext<TableRowData> }>({});
// 编辑状态的数据
const editedFormData = ref<{ [rowValue: string]: { [colKey: string]: any } }>({});
// 用于在表格实例内临时抑制单元格校验(例如:在点击清理按钮导致 blur 触发校验时)
const tableSuppressValidate = ref(false);
// suppressValidate 计时器,避免快速多次点击导致的竞态
let tableSuppressTimer: NodeJS.Timeout | undefined;

const getErrorListMapByErrors = (errors: ErrorListObjectType<TableRowData>[]): TableErrorListMap => {
const errorMap: TableErrorListMap = {};
Expand Down Expand Up @@ -106,6 +110,8 @@ export default function useRowEdit(props: PrimaryTableProps) {
if (result === true) return;
allErrorListMap[cellKeys[index]] = result;
});
// 持久化单元格校验结果
errorListMap.value = allErrorListMap;
props.onValidate?.({ result: allErrorListMap });
resolve({ result: allErrorListMap });
}, reject);
Expand Down Expand Up @@ -169,14 +175,32 @@ export default function useRowEdit(props: PrimaryTableProps) {
};

const clearValidateData = () => {
// 短暂抑制子单元格校验,避免在清理过程中被 blur/click 触发新的校验
tableSuppressValidate.value = true;

// 彻底清空持久化错误
errorListMap.value = {};

// 清理编辑单元格内的错误显示
Object.values(editingCells.value).forEach((cell) => {
cell?.clearErrors?.();
});

// 通知外部校验结果已清空
props.onValidate?.({ result: {} });
props.onRowValidate?.({ trigger: 'parent', result: [] });

if (tableSuppressTimer) clearTimeout(tableSuppressTimer);
tableSuppressTimer = setTimeout(() => {
tableSuppressValidate.value = false;
tableSuppressTimer = undefined;
}, 200);
};

const onPrimaryTableCellEditChange = (params: OnEditableChangeContext<TableRowData>) => {
const cellKey = getCellKey(params.row, props.rowKey, params.col.colKey, params.colIndex);

if (params.isEdit) {
// @ts-ignore
editingCells.value[cellKey] = params;
} else {
delete editingCells.value[cellKey];
Expand All @@ -201,7 +225,7 @@ export default function useRowEdit(props: PrimaryTableProps) {
const rowValueList = Object.keys(editedFormData.value);
rowValueList.forEach((key) => {
if (!editableRowKeys.includes(key)) {
// clear exited editable state row data
// 清理已退出编辑态的行数据
delete editedFormData.value[key];
}
});
Expand All @@ -211,6 +235,7 @@ export default function useRowEdit(props: PrimaryTableProps) {
return {
editedFormData,
errorListMap,
editingCells,
editableKeysMap,
validateTableData,
validateTableCellData,
Expand All @@ -220,5 +245,6 @@ export default function useRowEdit(props: PrimaryTableProps) {
onUpdateEditedCell,
getEditRowData,
onPrimaryTableCellEditChange,
tableSuppressValidate,
};
}
6 changes: 5 additions & 1 deletion packages/components/table/primary-table.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { computed, defineComponent, toRefs, h, ref, onMounted, getCurrentInstance } from 'vue';
import { computed, defineComponent, toRefs, h, ref, onMounted, getCurrentInstance, provide } from 'vue';
import { get, omit } from 'lodash-es';
import baseTableProps from './base-table-props';
import primaryTableProps from './primary-table-props';
Expand Down Expand Up @@ -155,6 +155,7 @@ export default defineComponent({
onUpdateEditedCell,
getEditRowData,
onPrimaryTableCellEditChange,
tableSuppressValidate,
} = useEditableRow(props);

const innerKeyboardRowHover = computed(() => Boolean(showExpandedRow.value || showRowSelect.value));
Expand Down Expand Up @@ -195,6 +196,9 @@ export default defineComponent({
setDragSortPrimaryTableRef(primaryTableRef.value);
});

// 将表格作用域内的抑制校验标志注入子组件
provide('TD_TABLE_SUPPRESS_VALIDATE', tableSuppressValidate);

// 对外暴露的方法
context.expose({
validateRowData,
Expand Down
Loading