Commit 2c867b3d636d57cdc526a4ca600af7d747b7d833

Authored by 无木
1 parent fb43fad5

feat(table): add `beforeEditSubmit` for editable cell

单元格编辑功能新增提交回调
CHANGELOG.zh_CN.md
1 1 ### ✨ Features
2 2  
3 3 - **BasicForm** 表单组件新增`Divider`,用于较长表单的区域分割
  4 +- **BasicTable** 单元格编辑新增提交回调,将根据回调函数返回的结果来决定是否将数据提交到表格
4 5  
5 6 ### 🐛 Bug Fixes
6 7  
... ...
src/components/Table/src/components/editable/EditableCell.vue
... ... @@ -11,25 +11,27 @@
11 11 <FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" />
12 12 </div>
13 13  
14   - <div v-if="isEdit" :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
15   - <CellComponent
16   - v-bind="getComponentProps"
17   - :component="getComponent"
18   - :style="getWrapperStyle"
19   - :popoverVisible="getRuleVisible"
20   - :rule="getRule"
21   - :ruleMessage="ruleMessage"
22   - :class="getWrapperClass"
23   - ref="elRef"
24   - @change="handleChange"
25   - @options-change="handleOptionsChange"
26   - @pressEnter="handleEnter"
27   - />
28   - <div :class="`${prefixCls}__action`" v-if="!getRowEditable">
29   - <CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" />
30   - <CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
  14 + <a-spin v-if="isEdit" :spinning="spinning">
  15 + <div :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
  16 + <CellComponent
  17 + v-bind="getComponentProps"
  18 + :component="getComponent"
  19 + :style="getWrapperStyle"
  20 + :popoverVisible="getRuleVisible"
  21 + :rule="getRule"
  22 + :ruleMessage="ruleMessage"
  23 + :class="getWrapperClass"
  24 + ref="elRef"
  25 + @change="handleChange"
  26 + @options-change="handleOptionsChange"
  27 + @pressEnter="handleEnter"
  28 + />
  29 + <div :class="`${prefixCls}__action`" v-if="!getRowEditable">
  30 + <CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" />
  31 + <CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
  32 + </div>
31 33 </div>
32   - </div>
  34 + </a-spin>
33 35 </div>
34 36 </template>
35 37 <script lang="ts">
... ... @@ -48,12 +50,13 @@
48 50 import { propTypes } from '/@/utils/propTypes';
49 51 import { isArray, isBoolean, isFunction, isNumber, isString } from '/@/utils/is';
50 52 import { createPlaceholderMessage } from './helper';
51   - import { omit, set } from 'lodash-es';
  53 + import { omit, pick, set } from 'lodash-es';
52 54 import { treeToList } from '/@/utils/helper/treeHelper';
  55 + import { Spin } from 'ant-design-vue';
53 56  
54 57 export default defineComponent({
55 58 name: 'EditableCell',
56   - components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent },
  59 + components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin },
57 60 directives: {
58 61 clickOutside,
59 62 },
... ... @@ -80,6 +83,7 @@
80 83 const optionsRef = ref<LabelValueOptions>([]);
81 84 const currentValueRef = ref<any>(props.value);
82 85 const defaultValueRef = ref<any>(props.value);
  86 + const spinning = ref<boolean>(false);
83 87  
84 88 const { prefixCls } = useDesign('editable-cell');
85 89  
... ... @@ -246,6 +250,35 @@
246 250  
247 251 const dataKey = (dataIndex || key) as string;
248 252  
  253 + if (!record.editable) {
  254 + const { getBindValues } = table;
  255 +
  256 + const { beforeEditSubmit, columns } = unref(getBindValues);
  257 +
  258 + if (beforeEditSubmit && isFunction(beforeEditSubmit)) {
  259 + spinning.value = true;
  260 + const keys: string[] = columns
  261 + .map((_column) => _column.dataIndex)
  262 + .filter((field) => !!field) as string[];
  263 + let result: any = true;
  264 + try {
  265 + result = await beforeEditSubmit({
  266 + record: pick(record, keys),
  267 + index,
  268 + key,
  269 + value,
  270 + });
  271 + } catch (e) {
  272 + result = false;
  273 + } finally {
  274 + spinning.value = false;
  275 + }
  276 + if (result === false) {
  277 + return;
  278 + }
  279 + }
  280 + }
  281 +
249 282 set(record, dataKey, value);
250 283 //const record = await table.updateTableData(index, dataKey, value);
251 284 needEmit && table.emit?.('edit-end', { record, index, key, value });
... ... @@ -368,6 +401,7 @@
368 401 getValues,
369 402 handleEnter,
370 403 handleSubmitClick,
  404 + spinning,
371 405 };
372 406 },
373 407 });
... ...
src/components/Table/src/props.ts
... ... @@ -126,4 +126,14 @@ export const basicProps = {
126 126 type: Object as PropType<{ x: number | true; y: number }>,
127 127 default: null,
128 128 },
  129 + beforeEditSubmit: {
  130 + type: Function as PropType<
  131 + (data: {
  132 + record: Recordable;
  133 + index: number;
  134 + key: string | number;
  135 + value: any;
  136 + }) => Promise<any>
  137 + >,
  138 + },
129 139 };
... ...
src/components/Table/src/types/table.ts
... ... @@ -363,6 +363,18 @@ export interface BasicTableProps&lt;T = any&gt; {
363 363 transformCellText?: Function;
364 364  
365 365 /**
  366 + * Callback executed before editable cell submit value, not for row-editor
  367 + *
  368 + * The cell will not submit data while callback return false
  369 + */
  370 + beforeEditSubmit?: (data: {
  371 + record: Recordable;
  372 + index: number;
  373 + key: string | number;
  374 + value: any;
  375 + }) => Promise<any>;
  376 +
  377 + /**
366 378 * Callback executed when pagination, filters or sorter is changed
367 379 * @param pagination
368 380 * @param filters
... ...
src/views/demo/table/EditCellTable.vue
... ... @@ -4,6 +4,7 @@
4 4 @register="registerTable"
5 5 @edit-end="handleEditEnd"
6 6 @edit-cancel="handleEditCancel"
  7 + :beforeEditSubmit="beforeEditSubmit"
7 8 />
8 9 </div>
9 10 </template>
... ... @@ -14,6 +15,7 @@
14 15  
15 16 import { demoListApi } from '/@/api/demo/table';
16 17 import { treeOptionsListApi } from '/@/api/demo/tree';
  18 + import { useMessage } from '/@/hooks/web/useMessage';
17 19 const columns: BasicColumn[] = [
18 20 {
19 21 title: '输入框',
... ... @@ -93,7 +95,7 @@
93 95 },
94 96 {
95 97 title: '远程下拉树',
96   - dataIndex: 'name7',
  98 + dataIndex: 'name71',
97 99 edit: true,
98 100 editComponent: 'ApiTreeSelect',
99 101 editRule: false,
... ... @@ -157,8 +159,44 @@
157 159 bordered: true,
158 160 });
159 161  
  162 + const { createMessage } = useMessage();
  163 +
160 164 function handleEditEnd({ record, index, key, value }: Recordable) {
161 165 console.log(record, index, key, value);
  166 + return false;
  167 + }
  168 +
  169 + // 模拟将指定数据保存
  170 + function feakSave({ value, key, id }) {
  171 + createMessage.loading({
  172 + content: `正在模拟保存${key}`,
  173 + key: '_save_fake_data',
  174 + duration: 0,
  175 + });
  176 + return new Promise((resolve) => {
  177 + setTimeout(() => {
  178 + if (value === '') {
  179 + createMessage.error({
  180 + content: '保存失败:不能为空',
  181 + key: '_save_fake_data',
  182 + duration: 2,
  183 + });
  184 + resolve(false);
  185 + } else {
  186 + createMessage.success({
  187 + content: `记录${id}的${key}已保存`,
  188 + key: '_save_fake_data',
  189 + duration: 2,
  190 + });
  191 + resolve(true);
  192 + }
  193 + }, 2000);
  194 + });
  195 + }
  196 +
  197 + async function beforeEditSubmit({ record, index, key, value }) {
  198 + console.log('单元格数据正在准备提交', { record, index, key, value });
  199 + return await feakSave({ id: record.id, key, value });
162 200 }
163 201  
164 202 function handleEditCancel() {
... ... @@ -169,6 +207,7 @@
169 207 registerTable,
170 208 handleEditEnd,
171 209 handleEditCancel,
  210 + beforeEditSubmit,
172 211 };
173 212 },
174 213 });
... ...