|
|
|
@ -1,57 +1,26 @@
@@ -1,57 +1,26 @@
|
|
|
|
|
<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 ?? ' ' |
|
|
|
|
}}</div> |
|
|
|
|
<FormOutlined v-if="!column.editRow" :class="`${prefixCls}__normal-icon`"/> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div v-if="isEdit" v-click-outside="onClickOutside" :class="`${prefixCls}__wrapper`"> |
|
|
|
|
<CellComponent |
|
|
|
|
v-bind="getComponentProps" |
|
|
|
|
ref="elRef" |
|
|
|
|
:component="getComponent" |
|
|
|
|
:style="getWrapperStyle" |
|
|
|
|
:popoverVisible="getRuleVisible" |
|
|
|
|
:rule="getRule" |
|
|
|
|
:ruleMessage="ruleMessage" |
|
|
|
|
:class="getWrapperClass" |
|
|
|
|
size="small" |
|
|
|
|
@change="handleChange" |
|
|
|
|
@options-change="handleOptionsChange" |
|
|
|
|
@pressEnter="handleEnter" |
|
|
|
|
/> |
|
|
|
|
<div v-if="!getRowEditable" :class="`${prefixCls}__action`"> |
|
|
|
|
<CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmit"/> |
|
|
|
|
<CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel"/> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</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'; |
|
|
|
|
import type { EditRecordRow } from './index'; |
|
|
|
|
import { CheckOutlined, CloseOutlined, FormOutlined } from '@ant-design/icons-vue'; |
|
|
|
|
import { CellComponent } from './CellComponent'; |
|
|
|
|
|
|
|
|
|
import { useDesign } from '/@/hooks/web/useDesign'; |
|
|
|
|
import { useTableContext } from '../../hooks/useTableContext'; |
|
|
|
|
|
|
|
|
|
import clickOutside from '/@/directives/clickOutside'; |
|
|
|
|
|
|
|
|
|
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, Spin }, |
|
|
|
|
directives: { |
|
|
|
|
clickOutside, |
|
|
|
|
}, |
|
|
|
@ -78,6 +47,7 @@
@@ -78,6 +47,7 @@
|
|
|
|
|
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'); |
|
|
|
|
|
|
|
|
@ -94,13 +64,6 @@
@@ -94,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'; |
|
|
|
@ -108,18 +71,49 @@
@@ -108,18 +71,49 @@
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
upEditDynamicDisabled(record, column, value); |
|
|
|
|
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'), |
|
|
|
|
...compProps, |
|
|
|
|
[valueField]: value, |
|
|
|
|
}; |
|
|
|
|
disabled: unref(getDisable), |
|
|
|
|
} as any; |
|
|
|
|
}); |
|
|
|
|
function upEditDynamicDisabled(record, column, value) { |
|
|
|
|
if (!record) return false; |
|
|
|
|
const { key, dataIndex } = column; |
|
|
|
|
if (!key && !dataIndex) return; |
|
|
|
|
const dataKey = (dataIndex || key) as string; |
|
|
|
|
set(record, dataKey, value); |
|
|
|
|
} |
|
|
|
|
const getDisable = computed(() => { |
|
|
|
|
const { editDynamicDisabled } = props.column; |
|
|
|
|
let disabled = false; |
|
|
|
|
if (isBoolean(editDynamicDisabled)) { |
|
|
|
|
disabled = editDynamicDisabled; |
|
|
|
|
} |
|
|
|
|
if (isFunction(editDynamicDisabled)) { |
|
|
|
|
const { record } = props; |
|
|
|
|
disabled = editDynamicDisabled({ record }); |
|
|
|
|
} |
|
|
|
|
return disabled; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const getValues = computed(() => { |
|
|
|
|
const { editComponentProps, editValueMap } = props.column; |
|
|
|
|
const { editValueMap } = props.column; |
|
|
|
|
|
|
|
|
|
const value = unref(currentValueRef); |
|
|
|
|
|
|
|
|
@ -132,7 +126,8 @@
@@ -132,7 +126,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; |
|
|
|
@ -183,14 +178,16 @@
@@ -183,14 +178,16 @@
|
|
|
|
|
const component = unref(getComponent); |
|
|
|
|
if (!e) { |
|
|
|
|
currentValueRef.value = e; |
|
|
|
|
} else if (e?.target && Reflect.has(e.target, 'value')) { |
|
|
|
|
currentValueRef.value = (e as ChangeEvent).target.value; |
|
|
|
|
} else if (component === 'Checkbox') { |
|
|
|
|
currentValueRef.value = (e as ChangeEvent).target.checked; |
|
|
|
|
} else if (component === 'Switch') { |
|
|
|
|
currentValueRef.value = e; |
|
|
|
|
} else if (e?.target && Reflect.has(e.target, 'value')) { |
|
|
|
|
currentValueRef.value = (e as ChangeEvent).target.value; |
|
|
|
|
} else if (isString(e) || isBoolean(e) || isNumber(e) || isArray(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', { |
|
|
|
@ -243,9 +240,38 @@
@@ -243,9 +240,38 @@
|
|
|
|
|
|
|
|
|
|
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: dataKey as string, |
|
|
|
|
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 }); |
|
|
|
|
needEmit && table.emit?.('edit-end', { record, index, key: dataKey, value }); |
|
|
|
|
isEdit.value = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -256,6 +282,10 @@
@@ -256,6 +282,10 @@
|
|
|
|
|
handleSubmit(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function handleSubmitClick() { |
|
|
|
|
handleSubmit(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function handleCancel() { |
|
|
|
|
isEdit.value = false; |
|
|
|
|
currentValueRef.value = defaultValueRef.value; |
|
|
|
@ -282,7 +312,7 @@
@@ -282,7 +312,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 || {}; |
|
|
|
@ -315,7 +345,7 @@
@@ -315,7 +345,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 = () => { |
|
|
|
@ -354,9 +384,63 @@
@@ -354,9 +384,63 @@
|
|
|
|
|
getRowEditable, |
|
|
|
|
getValues, |
|
|
|
|
handleEnter, |
|
|
|
|
// getSize, |
|
|
|
|
handleSubmitClick, |
|
|
|
|
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"> |
|
|
|
|