From 2c867b3d636d57cdc526a4ca600af7d747b7d833 Mon Sep 17 00:00:00 2001 From: 无木 <netfan@foxmail.com> Date: Thu, 19 Aug 2021 23:57:42 +0800 Subject: [PATCH] feat(table): add `beforeEditSubmit` for editable cell --- CHANGELOG.zh_CN.md | 1 + src/components/Table/src/components/editable/EditableCell.vue | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- src/components/Table/src/props.ts | 10 ++++++++++ src/components/Table/src/types/table.ts | 12 ++++++++++++ src/views/demo/table/EditCellTable.vue | 41 ++++++++++++++++++++++++++++++++++++++++- 5 files changed, 117 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.zh_CN.md b/CHANGELOG.zh_CN.md index 8589484..2757cbc 100644 --- a/CHANGELOG.zh_CN.md +++ b/CHANGELOG.zh_CN.md @@ -1,6 +1,7 @@ ### ✨ Features - **BasicForm** 表单组件新增`Divider`,用于较长表单的区域分割 +- **BasicTable** 单元格编辑新增提交回调,将根据回调函数返回的结果来决定是否将数据提交到表格 ### 🐛 Bug Fixes diff --git a/src/components/Table/src/components/editable/EditableCell.vue b/src/components/Table/src/components/editable/EditableCell.vue index 8922afe..259bb04 100644 --- a/src/components/Table/src/components/editable/EditableCell.vue +++ b/src/components/Table/src/components/editable/EditableCell.vue @@ -11,25 +11,27 @@ <FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" /> </div> - <div v-if="isEdit" :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside"> - <CellComponent - v-bind="getComponentProps" - :component="getComponent" - :style="getWrapperStyle" - :popoverVisible="getRuleVisible" - :rule="getRule" - :ruleMessage="ruleMessage" - :class="getWrapperClass" - ref="elRef" - @change="handleChange" - @options-change="handleOptionsChange" - @pressEnter="handleEnter" - /> - <div :class="`${prefixCls}__action`" v-if="!getRowEditable"> - <CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" /> - <CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" /> + <a-spin v-if="isEdit" :spinning="spinning"> + <div :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside"> + <CellComponent + v-bind="getComponentProps" + :component="getComponent" + :style="getWrapperStyle" + :popoverVisible="getRuleVisible" + :rule="getRule" + :ruleMessage="ruleMessage" + :class="getWrapperClass" + ref="elRef" + @change="handleChange" + @options-change="handleOptionsChange" + @pressEnter="handleEnter" + /> + <div :class="`${prefixCls}__action`" v-if="!getRowEditable"> + <CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" /> + <CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" /> + </div> </div> - </div> + </a-spin> </div> </template> <script lang="ts"> @@ -48,12 +50,13 @@ import { propTypes } from '/@/utils/propTypes'; import { isArray, isBoolean, isFunction, isNumber, isString } from '/@/utils/is'; import { createPlaceholderMessage } from './helper'; - import { omit, set } from 'lodash-es'; + import { omit, pick, set } from 'lodash-es'; import { treeToList } from '/@/utils/helper/treeHelper'; + import { Spin } from 'ant-design-vue'; export default defineComponent({ name: 'EditableCell', - components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent }, + components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin }, directives: { clickOutside, }, @@ -80,6 +83,7 @@ const optionsRef = ref<LabelValueOptions>([]); const currentValueRef = ref<any>(props.value); const defaultValueRef = ref<any>(props.value); + const spinning = ref<boolean>(false); const { prefixCls } = useDesign('editable-cell'); @@ -246,6 +250,35 @@ const dataKey = (dataIndex || key) as string; + if (!record.editable) { + const { getBindValues } = table; + + const { beforeEditSubmit, columns } = unref(getBindValues); + + if (beforeEditSubmit && isFunction(beforeEditSubmit)) { + spinning.value = true; + const keys: string[] = columns + .map((_column) => _column.dataIndex) + .filter((field) => !!field) as string[]; + let result: any = true; + try { + result = await beforeEditSubmit({ + record: pick(record, keys), + index, + key, + value, + }); + } catch (e) { + result = false; + } finally { + spinning.value = false; + } + if (result === false) { + return; + } + } + } + set(record, dataKey, value); //const record = await table.updateTableData(index, dataKey, value); needEmit && table.emit?.('edit-end', { record, index, key, value }); @@ -368,6 +401,7 @@ getValues, handleEnter, handleSubmitClick, + spinning, }; }, }); diff --git a/src/components/Table/src/props.ts b/src/components/Table/src/props.ts index e36e2ab..b4df61a 100644 --- a/src/components/Table/src/props.ts +++ b/src/components/Table/src/props.ts @@ -126,4 +126,14 @@ export const basicProps = { type: Object as PropType<{ x: number | true; y: number }>, default: null, }, + beforeEditSubmit: { + type: Function as PropType< + (data: { + record: Recordable; + index: number; + key: string | number; + value: any; + }) => Promise<any> + >, + }, }; diff --git a/src/components/Table/src/types/table.ts b/src/components/Table/src/types/table.ts index 1a130a3..2cf32ec 100644 --- a/src/components/Table/src/types/table.ts +++ b/src/components/Table/src/types/table.ts @@ -363,6 +363,18 @@ export interface BasicTableProps<T = any> { transformCellText?: Function; /** + * Callback executed before editable cell submit value, not for row-editor + * + * The cell will not submit data while callback return false + */ + beforeEditSubmit?: (data: { + record: Recordable; + index: number; + key: string | number; + value: any; + }) => Promise<any>; + + /** * Callback executed when pagination, filters or sorter is changed * @param pagination * @param filters diff --git a/src/views/demo/table/EditCellTable.vue b/src/views/demo/table/EditCellTable.vue index 8131f41..70d6ee9 100644 --- a/src/views/demo/table/EditCellTable.vue +++ b/src/views/demo/table/EditCellTable.vue @@ -4,6 +4,7 @@ @register="registerTable" @edit-end="handleEditEnd" @edit-cancel="handleEditCancel" + :beforeEditSubmit="beforeEditSubmit" /> </div> </template> @@ -14,6 +15,7 @@ import { demoListApi } from '/@/api/demo/table'; import { treeOptionsListApi } from '/@/api/demo/tree'; + import { useMessage } from '/@/hooks/web/useMessage'; const columns: BasicColumn[] = [ { title: '输入框', @@ -93,7 +95,7 @@ }, { title: '远程下拉树', - dataIndex: 'name7', + dataIndex: 'name71', edit: true, editComponent: 'ApiTreeSelect', editRule: false, @@ -157,8 +159,44 @@ bordered: true, }); + const { createMessage } = useMessage(); + function handleEditEnd({ record, index, key, value }: Recordable) { console.log(record, index, key, value); + return false; + } + + // 模拟将指定数据保存 + function feakSave({ value, key, id }) { + createMessage.loading({ + content: `正在模拟保存${key}`, + key: '_save_fake_data', + duration: 0, + }); + return new Promise((resolve) => { + setTimeout(() => { + if (value === '') { + createMessage.error({ + content: '保存失败:不能为空', + key: '_save_fake_data', + duration: 2, + }); + resolve(false); + } else { + createMessage.success({ + content: `记录${id}的${key}已保存`, + key: '_save_fake_data', + duration: 2, + }); + resolve(true); + } + }, 2000); + }); + } + + async function beforeEditSubmit({ record, index, key, value }) { + console.log('单元格数据正在准备提交', { record, index, key, value }); + return await feakSave({ id: record.id, key, value }); } function handleEditCancel() { @@ -169,6 +207,7 @@ registerTable, handleEditEnd, handleEditCancel, + beforeEditSubmit, }; }, }); -- libgit2 0.23.3