feat(table): add `beforeEditSubmit` for editable cell
单元格编辑功能新增提交回调
This commit is contained in:
parent
fb43fad555
commit
2c867b3d63
|
|
@ -1,6 +1,7 @@
|
||||||
### ✨ Features
|
### ✨ Features
|
||||||
|
|
||||||
- **BasicForm** 表单组件新增`Divider`,用于较长表单的区域分割
|
- **BasicForm** 表单组件新增`Divider`,用于较长表单的区域分割
|
||||||
|
- **BasicTable** 单元格编辑新增提交回调,将根据回调函数返回的结果来决定是否将数据提交到表格
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,25 +11,27 @@
|
||||||
<FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" />
|
<FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="isEdit" :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
|
<a-spin v-if="isEdit" :spinning="spinning">
|
||||||
<CellComponent
|
<div :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
|
||||||
v-bind="getComponentProps"
|
<CellComponent
|
||||||
:component="getComponent"
|
v-bind="getComponentProps"
|
||||||
:style="getWrapperStyle"
|
:component="getComponent"
|
||||||
:popoverVisible="getRuleVisible"
|
:style="getWrapperStyle"
|
||||||
:rule="getRule"
|
:popoverVisible="getRuleVisible"
|
||||||
:ruleMessage="ruleMessage"
|
:rule="getRule"
|
||||||
:class="getWrapperClass"
|
:ruleMessage="ruleMessage"
|
||||||
ref="elRef"
|
:class="getWrapperClass"
|
||||||
@change="handleChange"
|
ref="elRef"
|
||||||
@options-change="handleOptionsChange"
|
@change="handleChange"
|
||||||
@pressEnter="handleEnter"
|
@options-change="handleOptionsChange"
|
||||||
/>
|
@pressEnter="handleEnter"
|
||||||
<div :class="`${prefixCls}__action`" v-if="!getRowEditable">
|
/>
|
||||||
<CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" />
|
<div :class="`${prefixCls}__action`" v-if="!getRowEditable">
|
||||||
<CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
|
<CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" />
|
||||||
|
<CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a-spin>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
@ -48,12 +50,13 @@
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
import { isArray, isBoolean, isFunction, isNumber, isString } from '/@/utils/is';
|
import { isArray, isBoolean, isFunction, isNumber, isString } from '/@/utils/is';
|
||||||
import { createPlaceholderMessage } from './helper';
|
import { createPlaceholderMessage } from './helper';
|
||||||
import { omit, set } from 'lodash-es';
|
import { omit, pick, set } from 'lodash-es';
|
||||||
import { treeToList } from '/@/utils/helper/treeHelper';
|
import { treeToList } from '/@/utils/helper/treeHelper';
|
||||||
|
import { Spin } from 'ant-design-vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'EditableCell',
|
name: 'EditableCell',
|
||||||
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent },
|
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin },
|
||||||
directives: {
|
directives: {
|
||||||
clickOutside,
|
clickOutside,
|
||||||
},
|
},
|
||||||
|
|
@ -80,6 +83,7 @@
|
||||||
const optionsRef = ref<LabelValueOptions>([]);
|
const optionsRef = ref<LabelValueOptions>([]);
|
||||||
const currentValueRef = ref<any>(props.value);
|
const currentValueRef = ref<any>(props.value);
|
||||||
const defaultValueRef = ref<any>(props.value);
|
const defaultValueRef = ref<any>(props.value);
|
||||||
|
const spinning = ref<boolean>(false);
|
||||||
|
|
||||||
const { prefixCls } = useDesign('editable-cell');
|
const { prefixCls } = useDesign('editable-cell');
|
||||||
|
|
||||||
|
|
@ -246,6 +250,35 @@
|
||||||
|
|
||||||
const dataKey = (dataIndex || key) as string;
|
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);
|
set(record, dataKey, value);
|
||||||
//const record = await table.updateTableData(index, dataKey, value);
|
//const record = await table.updateTableData(index, dataKey, value);
|
||||||
needEmit && table.emit?.('edit-end', { record, index, key, value });
|
needEmit && table.emit?.('edit-end', { record, index, key, value });
|
||||||
|
|
@ -368,6 +401,7 @@
|
||||||
getValues,
|
getValues,
|
||||||
handleEnter,
|
handleEnter,
|
||||||
handleSubmitClick,
|
handleSubmitClick,
|
||||||
|
spinning,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -126,4 +126,14 @@ export const basicProps = {
|
||||||
type: Object as PropType<{ x: number | true; y: number }>,
|
type: Object as PropType<{ x: number | true; y: number }>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
beforeEditSubmit: {
|
||||||
|
type: Function as PropType<
|
||||||
|
(data: {
|
||||||
|
record: Recordable;
|
||||||
|
index: number;
|
||||||
|
key: string | number;
|
||||||
|
value: any;
|
||||||
|
}) => Promise<any>
|
||||||
|
>,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,18 @@ export interface BasicTableProps<T = any> {
|
||||||
*/
|
*/
|
||||||
transformCellText?: Function;
|
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
|
* Callback executed when pagination, filters or sorter is changed
|
||||||
* @param pagination
|
* @param pagination
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
@register="registerTable"
|
@register="registerTable"
|
||||||
@edit-end="handleEditEnd"
|
@edit-end="handleEditEnd"
|
||||||
@edit-cancel="handleEditCancel"
|
@edit-cancel="handleEditCancel"
|
||||||
|
:beforeEditSubmit="beforeEditSubmit"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -14,6 +15,7 @@
|
||||||
|
|
||||||
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';
|
||||||
const columns: BasicColumn[] = [
|
const columns: BasicColumn[] = [
|
||||||
{
|
{
|
||||||
title: '输入框',
|
title: '输入框',
|
||||||
|
|
@ -93,7 +95,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '远程下拉树',
|
title: '远程下拉树',
|
||||||
dataIndex: 'name7',
|
dataIndex: 'name71',
|
||||||
edit: true,
|
edit: true,
|
||||||
editComponent: 'ApiTreeSelect',
|
editComponent: 'ApiTreeSelect',
|
||||||
editRule: false,
|
editRule: false,
|
||||||
|
|
@ -157,8 +159,44 @@
|
||||||
bordered: true,
|
bordered: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
function handleEditEnd({ record, index, key, value }: Recordable) {
|
function handleEditEnd({ record, index, key, value }: Recordable) {
|
||||||
console.log(record, index, key, value);
|
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() {
|
function handleEditCancel() {
|
||||||
|
|
@ -169,6 +207,7 @@
|
||||||
registerTable,
|
registerTable,
|
||||||
handleEditEnd,
|
handleEditEnd,
|
||||||
handleEditCancel,
|
handleEditCancel,
|
||||||
|
beforeEditSubmit,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue