Commit b63f7d17dee2c0332e753ee445d61db63bd28236
Committed by
GitHub
1 parent
67d514ad
feat: 增强可编辑单元格功能 (#1576)
1. 增加可编辑单元格非编辑状态下可自定义样式 2. 扩展editComponentProps,可接受方法
Showing
3 changed files
with
100 additions
and
54 deletions
src/components/Table/src/components/editable/EditableCell.vue
1 | -<template> | |
2 | - <div :class="prefixCls"> | |
3 | - <div | |
4 | - v-show="!isEdit" | |
5 | - :class="{ [`${prefixCls}__normal`]: true, 'ellipsis-cell': column.ellipsis }" | |
6 | - @click="handleEdit" | |
7 | - > | |
8 | - <div class="cell-content" :title="column.ellipsis ? getValues ?? '' : ''"> | |
9 | - {{ getValues || getValues === 0 ? getValues : ' ' }} | |
10 | - </div> | |
11 | - <FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" /> | |
12 | - </div> | |
13 | - | |
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> | |
33 | - </div> | |
34 | - </a-spin> | |
35 | - </div> | |
36 | -</template> | |
37 | -<script lang="ts"> | |
1 | +<script lang="tsx"> | |
38 | 2 | import type { CSSProperties, PropType } from 'vue'; |
39 | 3 | import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue'; |
40 | 4 | import type { BasicColumn } from '../../types/table'; |
... | ... | @@ -56,7 +20,7 @@ |
56 | 20 | |
57 | 21 | export default defineComponent({ |
58 | 22 | name: 'EditableCell', |
59 | - components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin }, | |
23 | + components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, Spin }, | |
60 | 24 | directives: { |
61 | 25 | clickOutside, |
62 | 26 | }, |
... | ... | @@ -100,13 +64,6 @@ |
100 | 64 | }); |
101 | 65 | |
102 | 66 | const getComponentProps = computed(() => { |
103 | - const compProps = props.column?.editComponentProps ?? {}; | |
104 | - const component = unref(getComponent); | |
105 | - const apiSelectProps: Recordable = {}; | |
106 | - if (component === 'ApiSelect') { | |
107 | - apiSelectProps.cache = true; | |
108 | - } | |
109 | - | |
110 | 67 | const isCheckValue = unref(getIsCheckComp); |
111 | 68 | |
112 | 69 | const valueField = isCheckValue ? 'checked' : 'value'; |
... | ... | @@ -114,19 +71,30 @@ |
114 | 71 | |
115 | 72 | const value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val; |
116 | 73 | |
74 | + let compProps = props.column?.editComponentProps ?? {}; | |
75 | + const { record, column, index } = props; | |
76 | + | |
77 | + if (isFunction(compProps)) { | |
78 | + compProps = compProps({ text: val, record, column, index }) ?? {}; | |
79 | + } | |
80 | + const component = unref(getComponent); | |
81 | + const apiSelectProps: Recordable = {}; | |
82 | + if (component === 'ApiSelect') { | |
83 | + apiSelectProps.cache = true; | |
84 | + } | |
85 | + | |
117 | 86 | return { |
118 | 87 | size: 'small', |
119 | 88 | getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body, |
120 | - getCalendarContainer: () => unref(table?.wrapRef.value) ?? document.body, | |
121 | 89 | placeholder: createPlaceholderMessage(unref(getComponent)), |
122 | 90 | ...apiSelectProps, |
123 | 91 | ...omit(compProps, 'onChange'), |
124 | 92 | [valueField]: value, |
125 | - }; | |
93 | + } as any; | |
126 | 94 | }); |
127 | 95 | |
128 | 96 | const getValues = computed(() => { |
129 | - const { editComponentProps, editValueMap } = props.column; | |
97 | + const { editValueMap } = props.column; | |
130 | 98 | |
131 | 99 | const value = unref(currentValueRef); |
132 | 100 | |
... | ... | @@ -139,7 +107,8 @@ |
139 | 107 | return value; |
140 | 108 | } |
141 | 109 | |
142 | - const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []); | |
110 | + const options: LabelValueOptions = | |
111 | + unref(getComponentProps)?.options ?? (unref(optionsRef) || []); | |
143 | 112 | const option = options.find((item) => `${item.value}` === `${value}`); |
144 | 113 | |
145 | 114 | return option?.label ?? value; |
... | ... | @@ -197,7 +166,7 @@ |
197 | 166 | } else if (isString(e) || isBoolean(e) || isNumber(e)) { |
198 | 167 | currentValueRef.value = e; |
199 | 168 | } |
200 | - const onChange = props.column?.editComponentProps?.onChange; | |
169 | + const onChange = unref(getComponentProps)?.onChange; | |
201 | 170 | if (onChange && isFunction(onChange)) onChange(...arguments); |
202 | 171 | |
203 | 172 | table.emit?.('edit-change', { |
... | ... | @@ -322,7 +291,7 @@ |
322 | 291 | |
323 | 292 | // only ApiSelect or TreeSelect |
324 | 293 | function handleOptionsChange(options: LabelValueOptions) { |
325 | - const { replaceFields } = props.column?.editComponentProps ?? {}; | |
294 | + const { replaceFields } = unref(getComponentProps); | |
326 | 295 | const component = unref(getComponent); |
327 | 296 | if (component === 'ApiTreeSelect') { |
328 | 297 | const { title = 'title', value = 'value', children = 'children' } = replaceFields || {}; |
... | ... | @@ -355,7 +324,7 @@ |
355 | 324 | |
356 | 325 | if (props.column.dataIndex) { |
357 | 326 | if (!props.record.editValueRefs) props.record.editValueRefs = {}; |
358 | - props.record.editValueRefs[props.column.dataIndex] = currentValueRef; | |
327 | + props.record.editValueRefs[props.column.dataIndex as any] = currentValueRef; | |
359 | 328 | } |
360 | 329 | /* eslint-disable */ |
361 | 330 | props.record.onCancelEdit = () => { |
... | ... | @@ -398,6 +367,59 @@ |
398 | 367 | spinning, |
399 | 368 | }; |
400 | 369 | }, |
370 | + render() { | |
371 | + return ( | |
372 | + <div class={this.prefixCls}> | |
373 | + <div | |
374 | + v-show={!this.isEdit} | |
375 | + class={{ [`${this.prefixCls}__normal`]: true, 'ellipsis-cell': this.column.ellipsis }} | |
376 | + onClick={this.handleEdit} | |
377 | + > | |
378 | + <div class="cell-content" title={this.column.ellipsis ? this.getValues ?? '' : ''}> | |
379 | + {this.column.editRender | |
380 | + ? this.column.editRender({ | |
381 | + text: this.value, | |
382 | + record: this.record as Recordable, | |
383 | + column: this.column, | |
384 | + index: this.index, | |
385 | + }) | |
386 | + : this.getValues | |
387 | + ? this.getValues | |
388 | + : '\u00A0'} | |
389 | + </div> | |
390 | + {!this.column.editRow && <FormOutlined class={`${this.prefixCls}__normal-icon`} />} | |
391 | + </div> | |
392 | + {this.isEdit && ( | |
393 | + <Spin spinning={this.spinning}> | |
394 | + <div class={`${this.prefixCls}__wrapper`} v-click-outside={this.onClickOutside}> | |
395 | + <CellComponent | |
396 | + {...this.getComponentProps} | |
397 | + component={this.getComponent} | |
398 | + style={this.getWrapperStyle} | |
399 | + popoverVisible={this.getRuleVisible} | |
400 | + rule={this.getRule} | |
401 | + ruleMessage={this.ruleMessage} | |
402 | + class={this.getWrapperClass} | |
403 | + ref="elRef" | |
404 | + onChange={this.handleChange} | |
405 | + onOptionsChange={this.handleOptionsChange} | |
406 | + onPressEnter={this.handleEnter} | |
407 | + /> | |
408 | + {!this.getRowEditable && ( | |
409 | + <div class={`${this.prefixCls}__action`}> | |
410 | + <CheckOutlined | |
411 | + class={[`${this.prefixCls}__icon`, 'mx-2']} | |
412 | + onClick={this.handleSubmitClick} | |
413 | + /> | |
414 | + <CloseOutlined class={`${this.prefixCls}__icon `} onClick={this.handleCancel} /> | |
415 | + </div> | |
416 | + )} | |
417 | + </div> | |
418 | + </Spin> | |
419 | + )} | |
420 | + </div> | |
421 | + ); | |
422 | + }, | |
401 | 423 | }); |
402 | 424 | </script> |
403 | 425 | <style lang="less"> | ... | ... |
src/components/Table/src/types/table.ts
... | ... | @@ -441,7 +441,14 @@ export interface BasicColumn extends ColumnProps { |
441 | 441 | editRow?: boolean; |
442 | 442 | editable?: boolean; |
443 | 443 | editComponent?: ComponentType; |
444 | - editComponentProps?: Recordable; | |
444 | + editComponentProps?: | |
445 | + | ((opt: { | |
446 | + text: string | number | boolean | Recordable; | |
447 | + record: Recordable; | |
448 | + column: BasicColumn; | |
449 | + index: number; | |
450 | + }) => Recordable) | |
451 | + | Recordable; | |
445 | 452 | editRule?: boolean | ((text: string, record: Recordable) => Promise<string>); |
446 | 453 | editValueMap?: (value: any) => string; |
447 | 454 | onEditRow?: () => void; |
... | ... | @@ -449,6 +456,13 @@ export interface BasicColumn extends ColumnProps { |
449 | 456 | auth?: RoleEnum | RoleEnum[] | string | string[]; |
450 | 457 | // 业务控制是否显示 |
451 | 458 | ifShow?: boolean | ((column: BasicColumn) => boolean); |
459 | + // 自定义修改后显示的内容 | |
460 | + editRender?: (opt: { | |
461 | + text: string | number | boolean | Recordable; | |
462 | + record: Recordable; | |
463 | + column: BasicColumn; | |
464 | + index: number; | |
465 | + }) => VNodeChild | JSX.Element; | |
452 | 466 | } |
453 | 467 | |
454 | 468 | export type ColumnChangeParam = { | ... | ... |
src/views/demo/table/EditCellTable.vue
... | ... | @@ -9,13 +9,14 @@ |
9 | 9 | </div> |
10 | 10 | </template> |
11 | 11 | <script lang="ts"> |
12 | - import { defineComponent } from 'vue'; | |
12 | + import { defineComponent, h } from 'vue'; | |
13 | 13 | import { BasicTable, useTable, BasicColumn } from '/@/components/Table'; |
14 | 14 | import { optionsListApi } from '/@/api/demo/select'; |
15 | 15 | |
16 | 16 | import { demoListApi } from '/@/api/demo/table'; |
17 | 17 | import { treeOptionsListApi } from '/@/api/demo/tree'; |
18 | 18 | import { useMessage } from '/@/hooks/web/useMessage'; |
19 | + import { Progress } from 'ant-design-vue'; | |
19 | 20 | const columns: BasicColumn[] = [ |
20 | 21 | { |
21 | 22 | title: '输入框', |
... | ... | @@ -60,6 +61,15 @@ |
60 | 61 | editRule: true, |
61 | 62 | editComponent: 'InputNumber', |
62 | 63 | width: 200, |
64 | + editComponentProps: () => { | |
65 | + return { | |
66 | + max: 100, | |
67 | + min: 0, | |
68 | + }; | |
69 | + }, | |
70 | + editRender: ({ text }) => { | |
71 | + return h(Progress, { percent: Number(text) }); | |
72 | + }, | |
63 | 73 | }, |
64 | 74 | { |
65 | 75 | title: '下拉框', | ... | ... |