diff --git a/src/table/_example/editable-row.vue b/src/table/_example/editable-row.vue index 7fb9c6943c..97d3479020 100644 --- a/src/table/_example/editable-row.vue +++ b/src/table/_example/editable-row.vue @@ -179,6 +179,12 @@ const columns = computed(() => [ // 校验规则,此处同 Form 表单 rules: [{ required: true, message: '不能为空' }], showEditIcon: false, + on: ({ updateEditedCellValue }) => ({ + onChange: () => { + // clear `letters` on status changed + updateEditedCellValue({ colKey: 'letters', value: [] }); + }, + }), }, }, { @@ -208,7 +214,10 @@ const columns = computed(() => [ }; }, // 校验规则,此处同 Form 表单 - rules: [{ validator: (val) => val && val.length < 3, message: '数量不能超过 2 个' }], + rules: [ + { validator: (val) => val && val.length < 3, message: '数量不能超过 2 个' }, + { validator: (val) => Boolean(val?.length), message: '至少选择一个' }, + ], showEditIcon: false, }, }, diff --git a/src/table/editable-cell.tsx b/src/table/editable-cell.tsx index 99cff79727..67fcd93eeb 100644 --- a/src/table/editable-cell.tsx +++ b/src/table/editable-cell.tsx @@ -10,6 +10,7 @@ import { PrimaryTableRowEditContext, PrimaryTableRowValidateContext, TdBaseTableProps, + TableEditableCellPropsParams, } from './type'; import { TableClassName } from './hooks/useClassName'; import { useGlobalIcon } from '../hooks/useGlobalIcon'; @@ -27,6 +28,7 @@ export interface OnEditableChangeContext extends PrimaryTableRowEditContext; @@ -52,6 +54,7 @@ export default defineComponent({ name: 'TableEditableCell', props: { row: Object as PropType, + rowKey: String, rowIndex: Number, col: Object as PropType, colIndex: Number, @@ -75,6 +78,8 @@ export default defineComponent({ onEditableChange: Function as PropType, }, + emits: ['update-edited-cell'], + setup(props: EditableCellProps, context: SetupContext) { const { row, col } = toRefs(props); // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -87,8 +92,12 @@ export default defineComponent({ const { Edit1Icon } = useGlobalIcon({ Edit1Icon: TdEdit1Icon }); - const updateEditedCellValue = (val: any) => { - editValue.value = val; + const updateEditedCellValue: TableEditableCellPropsParams['updateEditedCellValue'] = (obj) => { + if (typeof obj === 'object' && obj.colKey && 'value' in obj) { + context.emit('update-edited-cell', { ...obj, rowValue: get(row.value, props.rowKey) }); + } else { + editValue.value = obj; + } }; watch([isKeepEditMode], (val) => { diff --git a/src/table/hooks/useEditableRow.ts b/src/table/hooks/useEditableRow.ts index 2b3af9295d..c3b1e787eb 100644 --- a/src/table/hooks/useEditableRow.ts +++ b/src/table/hooks/useEditableRow.ts @@ -1,5 +1,6 @@ import { ref, computed } from 'vue'; import get from 'lodash/get'; +import set from 'lodash/set'; import isFunction from 'lodash/isFunction'; import { PrimaryTableProps } from '../interface'; import { getEditableKeysMap } from '../../_common/js/table/utils'; @@ -10,6 +11,7 @@ import { TableErrorListMap, PrimaryTableInstanceFunctions, ErrorListObjectType, + PrimaryTableCellParams, } from '../type'; import { getCellKey } from './useRowspanAndColspan'; import { OnEditableChangeContext } from '../editable-cell'; @@ -27,6 +29,8 @@ export default function useRowEdit(props: PrimaryTableProps) { const editableKeysMap = computed(() => getEditableKeysMap(props.editableRowKeys, props.data, props.rowKey || 'id')); // 当前编辑的单元格 const editingCells = ref<{ [cellKey: string]: OnEditableChangeContext }>({}); + // 编辑状态的数据 + const editedFormData = ref<{ [rowValue: string]: { [colKey: string]: {} } }>({}); const getErrorListMapByErrors = (errors: ErrorListObjectType[]): TableErrorListMap => { const errorMap: TableErrorListMap = {}; @@ -128,6 +132,13 @@ export default function useRowEdit(props: PrimaryTableProps) { }); }; + const onUpdateEditedCell = (params: { rowValue: any; colKey: string; value: any }) => { + if (!editedFormData.value[params.rowValue]) { + editedFormData.value[params.rowValue] = {}; + } + editedFormData.value[params.rowValue][params.colKey] = params.value; + }; + const onRuleChange = (context: PrimaryTableRowEditContext) => { // 编辑行,预存校验信息,方便最终校验 if (props.editableRowKeys) { @@ -161,13 +172,28 @@ export default function useRowEdit(props: PrimaryTableProps) { } }; + const getEditRowData = ({ row, col }: PrimaryTableCellParams) => { + const rowValue = get(row, props.rowKey || 'id'); + const editedRowValue = editedFormData.value[rowValue]; + const hasEditedCellValue = editedRowValue && col.colKey in editedRowValue; + if (hasEditedCellValue) { + const tmpRow = { ...row }; + set(tmpRow, col.colKey, editedRowValue[col.colKey]); + return tmpRow; + } + return row; + }; + return { + editedFormData, errorListMap, editableKeysMap, validateTableData, validateRowData, onRuleChange, clearValidateData, + onUpdateEditedCell, + getEditRowData, onPrimaryTableCellEditChange, }; } diff --git a/src/table/primary-table.tsx b/src/table/primary-table.tsx index da8049ece2..c5e885515d 100644 --- a/src/table/primary-table.tsx +++ b/src/table/primary-table.tsx @@ -145,6 +145,8 @@ export default defineComponent({ validateTableData, onRuleChange, clearValidateData, + onUpdateEditedCell, + getEditRowData, onPrimaryTableCellEditChange, } = useEditableRow(props); @@ -204,6 +206,15 @@ export default defineComponent({ baseTableRef: primaryTableRef, }); + const onEditableCellChange: EditableCellProps['onChange'] = (params) => { + props.onRowEdit?.(params); + onUpdateEditedCell({ + rowValue: get(params.editedRow, props.rowKey || 'id'), + colKey: params.col.colKey, + value: params.value, + }); + }; + // 1. 影响列数量的因素有:自定义列配置、展开/收起行、多级表头;2. 影响表头内容的因素有:排序图标、筛选图标 const getColumns = (columns: PrimaryTableCol[]) => { const arr: PrimaryTableCol[] = []; @@ -256,10 +267,12 @@ export default defineComponent({ item.cell = (h, p: PrimaryTableCellParams) => { const cellProps: EditableCellProps = { ...p, + row: getEditRowData(p), oldCell, + rowKey: props.rowKey || 'id', tableBaseClass, cellEmptyContent: props.cellEmptyContent, - onChange: props.onRowEdit, + onChange: onEditableCellChange, onValidate: props.onRowValidate, onRuleChange, onEditableChange: onPrimaryTableCellEditChange, @@ -274,7 +287,7 @@ export default defineComponent({ if (props.editableCellState) { cellProps.readonly = !props.editableCellState(p); } - return ; + return ; }; } if (item.children?.length) { diff --git a/src/table/table.en-US.md b/src/table/table.en-US.md index 265c34fffc..ac2240f428 100644 --- a/src/table/table.en-US.md +++ b/src/table/table.en-US.md @@ -312,9 +312,9 @@ abortEditOnEvent | Array | - | Typescript:`string[]` | N component | \- | - | component definition。Typescript:`ComponentType`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N defaultEditable | Boolean | false | set default editable once | N keepEditMode | Boolean | false | set table cell always to be editable | N -on | Function | - | Typescript:`(context: TableEditableCellPropsParams) => { [eventName: string]: Function }` | N +on | Function | - | edit component events, you can update any cell value of current row with param `updateEditedCellValue`。Typescript:`(context: TableEditableCellPropsParams) => { [eventName: string]: Function }` | N onEdited | Function | - | trigger on finishing editing。Typescript:`(context: PrimaryTableOnEditedContext) => void` `type PrimaryTableOnEditedContext = PrimaryTableCellParams & { trigger: string; newRowData: T; }`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N -props | Object | - | props of `edit.component`。Typescript:`TableEditableCellProps` `type TableEditableCellProps = TablePlainObject \| ((params: TableEditableCellPropsParams) => TablePlainObject)` `interface TableEditableCellPropsParams extends PrimaryTableCellParams { editedRow: T; updateEditedCellValue: (val: any) => void }` `interface TablePlainObject{ [key: string]: any }`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts)。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N +props | Object / Function | - | props of `edit.component`, you can update any cell value of current row with param `updateEditedCellValue`。Typescript:`TableEditableCellProps` `type TableEditableCellProps = TablePlainObject \| ((params: TableEditableCellPropsParams) => TablePlainObject)` `interface TableEditableCellPropsParams extends PrimaryTableCellParams { editedRow: T; updateEditedCellValue: (val: any \| { colKey: string, value: any }) => void }` `interface TablePlainObject{ [key: string]: any }`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts)。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N rules | Array | - | form rules。Typescript:`TableEditableCellRules` `type TableEditableCellRules = FormRule[] \| ((params: PrimaryTableCellParams) => FormRule[])`,[Form API Documents](./form?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N showEditIcon | Boolean | true | show edit icon | N validateTrigger | String | 'exit' | when to trigger validate。Typescript:`'exit' \| 'change'` | N diff --git a/src/table/table.md b/src/table/table.md index 1c7354cb3a..9380ffabfc 100644 --- a/src/table/table.md +++ b/src/table/table.md @@ -312,9 +312,9 @@ abortEditOnEvent | Array | - | 除了点击非自身元素退出编辑态之外 component | \- | - | 组件定义,如:`Input` `Select`。对于完全自定义的组件(非组件库内的组件),组件需要支持 `value` 和 `onChange` ;如果还需要支持校验规则,则组件还需实现 `tips` 和 `status` 两个 API,实现规则可参考 `Input` 组件。TS 类型:`ComponentType`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N defaultEditable | Boolean | false | 单元格默认状态是否为编辑态 | N keepEditMode | Boolean | false | 设置当前列的单元格始终保持为编辑态 | N -on | Function | - | 透传给编辑组件的事件。TS 类型:`(context: TableEditableCellPropsParams) => { [eventName: string]: Function }` | N +on | Function | - | 透传给编辑组件的事件,可以使用参数 `updateEditedCellValue` 更新当前行任意编辑状态单元格的值。TS 类型:`(context: TableEditableCellPropsParams) => { [eventName: string]: Function }` | N onEdited | Function | - | 编辑完成后,退出编辑模式时触发。TS 类型:`(context: PrimaryTableOnEditedContext) => void` `type PrimaryTableOnEditedContext = PrimaryTableCellParams & { trigger: string; newRowData: T; }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N -props | Object | - | 透传给组件 `edit.component` 的属性。TS 类型:`TableEditableCellProps` `type TableEditableCellProps = TablePlainObject \| ((params: TableEditableCellPropsParams) => TablePlainObject)` `interface TableEditableCellPropsParams extends PrimaryTableCellParams { editedRow: T; updateEditedCellValue: (val: any) => void }` `interface TablePlainObject{ [key: string]: any }`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N +props | Object / Function | - | 透传给组件 `edit.component` 的属性,可以使用 `updateEditedCellValue` 更新当前行任意编辑状态单元格的值。TS 类型:`TableEditableCellProps` `type TableEditableCellProps = TablePlainObject \| ((params: TableEditableCellPropsParams) => TablePlainObject)` `interface TableEditableCellPropsParams extends PrimaryTableCellParams { editedRow: T; updateEditedCellValue: (val: any \| { colKey: string, value: any }) => void }` `interface TablePlainObject{ [key: string]: any }`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N rules | Array | - | 校验规则。TS 类型:`TableEditableCellRules` `type TableEditableCellRules = FormRule[] \| ((params: PrimaryTableCellParams) => FormRule[])`,[Form API Documents](./form?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N showEditIcon | Boolean | true | 是否显示编辑图标 | N validateTrigger | String | 'exit' | 触发校验的时机,有 2 种:退出编辑时和数据变化时。TS 类型:`'exit' \| 'change'` | N diff --git a/src/table/type.ts b/src/table/type.ts index a7fea3d0de..7ade3480eb 100644 --- a/src/table/type.ts +++ b/src/table/type.ts @@ -951,7 +951,7 @@ export interface TableEditableCellConfig */ keepEditMode?: boolean; /** - * 透传给编辑组件的事件 + * 透传给编辑组件的事件,可以使用参数 `updateEditedCellValue` 更新当前行任意编辑状态单元格的值 */ on?: (context: TableEditableCellPropsParams) => { [eventName: string]: Function }; /** @@ -959,7 +959,7 @@ export interface TableEditableCellConfig */ onEdited?: (context: PrimaryTableOnEditedContext) => void; /** - * 透传给组件 `edit.component` 的属性 + * 透传给组件 `edit.component` 的属性,可以使用 `updateEditedCellValue` 更新当前行任意编辑状态单元格的值 */ props?: TableEditableCellProps; /** @@ -1265,7 +1265,7 @@ export type TableEditableCellProps = export interface TableEditableCellPropsParams extends PrimaryTableCellParams { editedRow: T; - updateEditedCellValue: (val: any) => void; + updateEditedCellValue: (val: any | { colKey: string; value: any }) => void; } export interface TablePlainObject {