Browse Source

feat: 增强可编辑单元格功能 (#1576)

1. 增加可编辑单元格非编辑状态下可自定义样式
2. 扩展editComponentProps,可接受方法
lzdjack 3 years ago
parent
commit
b63f7d17de

+ 74 - 52
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">

+ 15 - 1
src/components/Table/src/types/table.ts

@@ -441,7 +441,14 @@ export interface BasicColumn extends ColumnProps {
   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 @@ export interface BasicColumn extends ColumnProps {
   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 = {

+ 11 - 1
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: '下拉框',