lzdjack
2022-01-18 b63f7d17dee2c0332e753ee445d61db63bd28236
feat: 增强可编辑单元格功能 (#1576)

1. 增加可编辑单元格非编辑状态下可自定义样式
2. 扩展editComponentProps,可接受方法
3个文件已修改
154 ■■■■■ 已修改文件
src/components/Table/src/components/editable/EditableCell.vue 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/src/types/table.ts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/table/EditCellTable.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/src/components/editable/EditableCell.vue
@@ -1,40 +1,4 @@
<template>
  <div :class="prefixCls">
    <div
      v-show="!isEdit"
      :class="{ [`${prefixCls}__normal`]: true, 'ellipsis-cell': column.ellipsis }"
      @click="handleEdit"
    >
      <div class="cell-content" :title="column.ellipsis ? getValues ?? '' : ''">
        {{ getValues || getValues === 0 ? getValues : '&nbsp;' }}
      </div>
      <FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" />
    </div>
    <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>
    </a-spin>
  </div>
</template>
<script lang="ts">
<script lang="tsx">
  import type { CSSProperties, PropType } from 'vue';
  import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue';
  import type { BasicColumn } from '../../types/table';
@@ -56,7 +20,7 @@
  export default defineComponent({
    name: 'EditableCell',
    components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin },
    components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, Spin },
    directives: {
      clickOutside,
    },
@@ -100,13 +64,6 @@
      });
      const getComponentProps = computed(() => {
        const compProps = props.column?.editComponentProps ?? {};
        const component = unref(getComponent);
        const apiSelectProps: Recordable = {};
        if (component === 'ApiSelect') {
          apiSelectProps.cache = true;
        }
        const isCheckValue = unref(getIsCheckComp);
        const valueField = isCheckValue ? 'checked' : 'value';
@@ -114,19 +71,30 @@
        const value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val;
        let compProps = props.column?.editComponentProps ?? {};
        const { record, column, index } = props;
        if (isFunction(compProps)) {
          compProps = compProps({ text: val, record, column, index }) ?? {};
        }
        const component = unref(getComponent);
        const apiSelectProps: Recordable = {};
        if (component === 'ApiSelect') {
          apiSelectProps.cache = true;
        }
        return {
          size: 'small',
          getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body,
          getCalendarContainer: () => unref(table?.wrapRef.value) ?? document.body,
          placeholder: createPlaceholderMessage(unref(getComponent)),
          ...apiSelectProps,
          ...omit(compProps, 'onChange'),
          [valueField]: value,
        };
        } as any;
      });
      const getValues = computed(() => {
        const { editComponentProps, editValueMap } = props.column;
        const { editValueMap } = props.column;
        const value = unref(currentValueRef);
@@ -139,7 +107,8 @@
          return value;
        }
        const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []);
        const options: LabelValueOptions =
          unref(getComponentProps)?.options ?? (unref(optionsRef) || []);
        const option = options.find((item) => `${item.value}` === `${value}`);
        return option?.label ?? value;
@@ -197,7 +166,7 @@
        } else if (isString(e) || isBoolean(e) || isNumber(e)) {
          currentValueRef.value = e;
        }
        const onChange = props.column?.editComponentProps?.onChange;
        const onChange = unref(getComponentProps)?.onChange;
        if (onChange && isFunction(onChange)) onChange(...arguments);
        table.emit?.('edit-change', {
@@ -322,7 +291,7 @@
      // only ApiSelect or TreeSelect
      function handleOptionsChange(options: LabelValueOptions) {
        const { replaceFields } = props.column?.editComponentProps ?? {};
        const { replaceFields } = unref(getComponentProps);
        const component = unref(getComponent);
        if (component === 'ApiTreeSelect') {
          const { title = 'title', value = 'value', children = 'children' } = replaceFields || {};
@@ -355,7 +324,7 @@
        if (props.column.dataIndex) {
          if (!props.record.editValueRefs) props.record.editValueRefs = {};
          props.record.editValueRefs[props.column.dataIndex] = currentValueRef;
          props.record.editValueRefs[props.column.dataIndex as any] = currentValueRef;
        }
        /* eslint-disable  */
        props.record.onCancelEdit = () => {
@@ -398,6 +367,59 @@
        spinning,
      };
    },
    render() {
      return (
        <div class={this.prefixCls}>
          <div
            v-show={!this.isEdit}
            class={{ [`${this.prefixCls}__normal`]: true, 'ellipsis-cell': this.column.ellipsis }}
            onClick={this.handleEdit}
          >
            <div class="cell-content" title={this.column.ellipsis ? this.getValues ?? '' : ''}>
              {this.column.editRender
                ? this.column.editRender({
                    text: this.value,
                    record: this.record as Recordable,
                    column: this.column,
                    index: this.index,
                  })
                : this.getValues
                ? this.getValues
                : '\u00A0'}
            </div>
            {!this.column.editRow && <FormOutlined class={`${this.prefixCls}__normal-icon`} />}
          </div>
          {this.isEdit && (
            <Spin spinning={this.spinning}>
              <div class={`${this.prefixCls}__wrapper`} v-click-outside={this.onClickOutside}>
                <CellComponent
                  {...this.getComponentProps}
                  component={this.getComponent}
                  style={this.getWrapperStyle}
                  popoverVisible={this.getRuleVisible}
                  rule={this.getRule}
                  ruleMessage={this.ruleMessage}
                  class={this.getWrapperClass}
                  ref="elRef"
                  onChange={this.handleChange}
                  onOptionsChange={this.handleOptionsChange}
                  onPressEnter={this.handleEnter}
                />
                {!this.getRowEditable && (
                  <div class={`${this.prefixCls}__action`}>
                    <CheckOutlined
                      class={[`${this.prefixCls}__icon`, 'mx-2']}
                      onClick={this.handleSubmitClick}
                    />
                    <CloseOutlined class={`${this.prefixCls}__icon `} onClick={this.handleCancel} />
                  </div>
                )}
              </div>
            </Spin>
          )}
        </div>
      );
    },
  });
</script>
<style lang="less">
src/components/Table/src/types/table.ts
@@ -441,7 +441,14 @@
  editRow?: boolean;
  editable?: boolean;
  editComponent?: ComponentType;
  editComponentProps?: Recordable;
  editComponentProps?:
    | ((opt: {
        text: string | number | boolean | Recordable;
        record: Recordable;
        column: BasicColumn;
        index: number;
      }) => Recordable)
    | Recordable;
  editRule?: boolean | ((text: string, record: Recordable) => Promise<string>);
  editValueMap?: (value: any) => string;
  onEditRow?: () => void;
@@ -449,6 +456,13 @@
  auth?: RoleEnum | RoleEnum[] | string | string[];
  // 业务控制是否显示
  ifShow?: boolean | ((column: BasicColumn) => boolean);
  // 自定义修改后显示的内容
  editRender?: (opt: {
    text: string | number | boolean | Recordable;
    record: Recordable;
    column: BasicColumn;
    index: number;
  }) => VNodeChild | JSX.Element;
}
export type ColumnChangeParam = {
src/views/demo/table/EditCellTable.vue
@@ -9,13 +9,14 @@
  </div>
</template>
<script lang="ts">
  import { defineComponent } from 'vue';
  import { defineComponent, h } from 'vue';
  import { BasicTable, useTable, BasicColumn } from '/@/components/Table';
  import { optionsListApi } from '/@/api/demo/select';
  import { demoListApi } from '/@/api/demo/table';
  import { treeOptionsListApi } from '/@/api/demo/tree';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { Progress } from 'ant-design-vue';
  const columns: BasicColumn[] = [
    {
      title: '输入框',
@@ -60,6 +61,15 @@
      editRule: true,
      editComponent: 'InputNumber',
      width: 200,
      editComponentProps: () => {
        return {
          max: 100,
          min: 0,
        };
      },
      editRender: ({ text }) => {
        return h(Progress, { percent: Number(text) });
      },
    },
    {
      title: '下拉框',