Unverified 提交 b63f7d17 作者: lzdjack 提交者: GitHub

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

1. 增加可编辑单元格非编辑状态下可自定义样式
2. 扩展editComponentProps,可接受方法
上级 67d514ad
<template> <script lang="tsx">
<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">
import type { CSSProperties, PropType } from 'vue'; import type { CSSProperties, PropType } from 'vue';
import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue'; import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue';
import type { BasicColumn } from '../../types/table'; import type { BasicColumn } from '../../types/table';
...@@ -56,7 +20,7 @@ ...@@ -56,7 +20,7 @@
export default defineComponent({ export default defineComponent({
name: 'EditableCell', name: 'EditableCell',
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin }, components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, Spin },
directives: { directives: {
clickOutside, clickOutside,
}, },
...@@ -100,13 +64,6 @@ ...@@ -100,13 +64,6 @@
}); });
const getComponentProps = computed(() => { 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 isCheckValue = unref(getIsCheckComp);
const valueField = isCheckValue ? 'checked' : 'value'; const valueField = isCheckValue ? 'checked' : 'value';
...@@ -114,19 +71,30 @@ ...@@ -114,19 +71,30 @@
const value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val; 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 { return {
size: 'small', size: 'small',
getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body, getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body,
getCalendarContainer: () => unref(table?.wrapRef.value) ?? document.body,
placeholder: createPlaceholderMessage(unref(getComponent)), placeholder: createPlaceholderMessage(unref(getComponent)),
...apiSelectProps, ...apiSelectProps,
...omit(compProps, 'onChange'), ...omit(compProps, 'onChange'),
[valueField]: value, [valueField]: value,
}; } as any;
}); });
const getValues = computed(() => { const getValues = computed(() => {
const { editComponentProps, editValueMap } = props.column; const { editValueMap } = props.column;
const value = unref(currentValueRef); const value = unref(currentValueRef);
...@@ -139,7 +107,8 @@ ...@@ -139,7 +107,8 @@
return value; 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}`); const option = options.find((item) => `${item.value}` === `${value}`);
return option?.label ?? value; return option?.label ?? value;
...@@ -197,7 +166,7 @@ ...@@ -197,7 +166,7 @@
} else if (isString(e) || isBoolean(e) || isNumber(e)) { } else if (isString(e) || isBoolean(e) || isNumber(e)) {
currentValueRef.value = e; currentValueRef.value = e;
} }
const onChange = props.column?.editComponentProps?.onChange; const onChange = unref(getComponentProps)?.onChange;
if (onChange && isFunction(onChange)) onChange(...arguments); if (onChange && isFunction(onChange)) onChange(...arguments);
table.emit?.('edit-change', { table.emit?.('edit-change', {
...@@ -322,7 +291,7 @@ ...@@ -322,7 +291,7 @@
// only ApiSelect or TreeSelect // only ApiSelect or TreeSelect
function handleOptionsChange(options: LabelValueOptions) { function handleOptionsChange(options: LabelValueOptions) {
const { replaceFields } = props.column?.editComponentProps ?? {}; const { replaceFields } = unref(getComponentProps);
const component = unref(getComponent); const component = unref(getComponent);
if (component === 'ApiTreeSelect') { if (component === 'ApiTreeSelect') {
const { title = 'title', value = 'value', children = 'children' } = replaceFields || {}; const { title = 'title', value = 'value', children = 'children' } = replaceFields || {};
...@@ -355,7 +324,7 @@ ...@@ -355,7 +324,7 @@
if (props.column.dataIndex) { if (props.column.dataIndex) {
if (!props.record.editValueRefs) props.record.editValueRefs = {}; 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 */ /* eslint-disable */
props.record.onCancelEdit = () => { props.record.onCancelEdit = () => {
...@@ -398,6 +367,59 @@ ...@@ -398,6 +367,59 @@
spinning, 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> </script>
<style lang="less"> <style lang="less">
......
...@@ -441,7 +441,14 @@ export interface BasicColumn extends ColumnProps { ...@@ -441,7 +441,14 @@ export interface BasicColumn extends ColumnProps {
editRow?: boolean; editRow?: boolean;
editable?: boolean; editable?: boolean;
editComponent?: ComponentType; 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>); editRule?: boolean | ((text: string, record: Recordable) => Promise<string>);
editValueMap?: (value: any) => string; editValueMap?: (value: any) => string;
onEditRow?: () => void; onEditRow?: () => void;
...@@ -449,6 +456,13 @@ export interface BasicColumn extends ColumnProps { ...@@ -449,6 +456,13 @@ export interface BasicColumn extends ColumnProps {
auth?: RoleEnum | RoleEnum[] | string | string[]; auth?: RoleEnum | RoleEnum[] | string | string[];
// 业务控制是否显示 // 业务控制是否显示
ifShow?: boolean | ((column: BasicColumn) => boolean); ifShow?: boolean | ((column: BasicColumn) => boolean);
// 自定义修改后显示的内容
editRender?: (opt: {
text: string | number | boolean | Recordable;
record: Recordable;
column: BasicColumn;
index: number;
}) => VNodeChild | JSX.Element;
} }
export type ColumnChangeParam = { export type ColumnChangeParam = {
......
...@@ -9,13 +9,14 @@ ...@@ -9,13 +9,14 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent, h } from 'vue';
import { BasicTable, useTable, BasicColumn } from '/@/components/Table'; import { BasicTable, useTable, BasicColumn } from '/@/components/Table';
import { optionsListApi } from '/@/api/demo/select'; import { optionsListApi } from '/@/api/demo/select';
import { demoListApi } from '/@/api/demo/table'; import { demoListApi } from '/@/api/demo/table';
import { treeOptionsListApi } from '/@/api/demo/tree'; import { treeOptionsListApi } from '/@/api/demo/tree';
import { useMessage } from '/@/hooks/web/useMessage'; import { useMessage } from '/@/hooks/web/useMessage';
import { Progress } from 'ant-design-vue';
const columns: BasicColumn[] = [ const columns: BasicColumn[] = [
{ {
title: '输入框', title: '输入框',
...@@ -60,6 +61,15 @@ ...@@ -60,6 +61,15 @@
editRule: true, editRule: true,
editComponent: 'InputNumber', editComponent: 'InputNumber',
width: 200, width: 200,
editComponentProps: () => {
return {
max: 100,
min: 0,
};
},
editRender: ({ text }) => {
return h(Progress, { percent: Number(text) });
},
}, },
{ {
title: '下拉框', title: '下拉框',
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论