ソースを参照

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

单元格编辑功能新增提交回调
无木 3 年 前
コミット
2c867b3d63

+ 1 - 0
CHANGELOG.zh_CN.md

@@ -1,6 +1,7 @@
 ### ✨ Features
 
 - **BasicForm** 表单组件新增`Divider`,用于较长表单的区域分割
+- **BasicTable** 单元格编辑新增提交回调,将根据回调函数返回的结果来决定是否将数据提交到表格
 
 ### 🐛 Bug Fixes
 

+ 54 - 20
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,
       };
     },
   });

+ 10 - 0
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>
+    >,
+  },
 };

+ 12 - 0
src/components/Table/src/types/table.ts

@@ -362,6 +362,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

+ 40 - 1
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,
       };
     },
   });