无木
2021-08-19 2c867b3d636d57cdc526a4ca600af7d747b7d833
feat(table): add `beforeEditSubmit` for editable cell

单元格编辑功能新增提交回调
5个文件已修改
138 ■■■■ 已修改文件
CHANGELOG.zh_CN.md 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/src/components/editable/EditableCell.vue 74 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/src/props.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/src/types/table.ts 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/table/EditCellTable.vue 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CHANGELOG.zh_CN.md
@@ -1,6 +1,7 @@
### ✨ Features
- **BasicForm** 表单组件新增`Divider`,用于较长表单的区域分割
- **BasicTable** 单元格编辑新增提交回调,将根据回调函数返回的结果来决定是否将数据提交到表格
### 🐛 Bug Fixes
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,
      };
    },
  });
src/components/Table/src/props.ts
@@ -126,4 +126,14 @@
    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>
    >,
  },
};
src/components/Table/src/types/table.ts
@@ -363,6 +363,18 @@
  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
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,
      };
    },
  });