feat(table): add `beforeEditSubmit` for editable cell
单元格编辑功能新增提交回调
| | |
| | | ### ✨ Features |
| | | |
| | | - **BasicForm** 表单组件新增`Divider`,用于较长表单的区域分割 |
| | | - **BasicTable** 单元格编辑新增提交回调,将根据回调函数返回的结果来决定是否将数据提交到表格 |
| | | |
| | | ### 🐛 Bug Fixes |
| | | |
| | |
| | | <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"> |
| | |
| | | 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, |
| | | }, |
| | |
| | | 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'); |
| | | |
| | |
| | | |
| | | 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 }); |
| | |
| | | getValues, |
| | | handleEnter, |
| | | handleSubmitClick, |
| | | spinning, |
| | | }; |
| | | }, |
| | | }); |
| | |
| | | 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> |
| | | >, |
| | | }, |
| | | }; |
| | |
| | | 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 |
| | |
| | | @register="registerTable" |
| | | @edit-end="handleEditEnd" |
| | | @edit-cancel="handleEditCancel" |
| | | :beforeEditSubmit="beforeEditSubmit" |
| | | /> |
| | | </div> |
| | | </template> |
| | |
| | | |
| | | import { demoListApi } from '/@/api/demo/table'; |
| | | import { treeOptionsListApi } from '/@/api/demo/tree'; |
| | | import { useMessage } from '/@/hooks/web/useMessage'; |
| | | const columns: BasicColumn[] = [ |
| | | { |
| | | title: '输入框', |
| | |
| | | }, |
| | | { |
| | | title: '远程下拉树', |
| | | dataIndex: 'name7', |
| | | dataIndex: 'name71', |
| | | edit: true, |
| | | editComponent: 'ApiTreeSelect', |
| | | editRule: false, |
| | |
| | | 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() { |
| | |
| | | registerTable, |
| | | handleEditEnd, |
| | | handleEditCancel, |
| | | beforeEditSubmit, |
| | | }; |
| | | }, |
| | | }); |