import '../style/editable-cell.less';
|
|
import { defineComponent, PropType, ref, unref, nextTick, watchEffect } from 'vue';
|
import { ClickOutSide } from '/@/components/ClickOutSide';
|
|
import { RenderEditableCellParams } from '../types/table';
|
import { ComponentType } from '../types/componentType';
|
|
import { componentMap } from '../componentMap';
|
import { isString, isBoolean, isArray } from '/@/utils/is';
|
import { FormOutlined, CloseOutlined, CheckOutlined } from '@ant-design/icons-vue';
|
|
const prefixCls = 'editable-cell';
|
const EditableCell = defineComponent({
|
name: 'EditableCell',
|
props: {
|
value: {
|
type: String as PropType<string>,
|
default: '',
|
},
|
componentProps: {
|
type: Object as PropType<any>,
|
default: null,
|
},
|
|
dataKey: {
|
type: String as PropType<string>,
|
default: '',
|
},
|
|
dataIndex: {
|
type: String as PropType<string>,
|
default: '',
|
},
|
|
component: {
|
type: String as PropType<ComponentType>,
|
default: 'Input',
|
},
|
editable: {
|
type: Boolean as PropType<boolean>,
|
default: false,
|
},
|
editRow: {
|
type: Boolean as PropType<boolean>,
|
default: false,
|
},
|
record: {
|
type: Object as PropType<EditRecordRow>,
|
},
|
placeholder: {
|
type: String as PropType<string>,
|
default: '',
|
},
|
},
|
emits: ['submit', 'cancel'],
|
setup(props, { attrs, emit }) {
|
const elRef = ref<any>(null);
|
|
const isEditRef = ref(false);
|
const currentValueRef = ref<string | boolean>(props.value);
|
const defaultValueRef = ref<string | boolean>(props.value);
|
|
watchEffect(() => {
|
defaultValueRef.value = props.value;
|
if (isBoolean(props.editable)) {
|
isEditRef.value = props.editable;
|
}
|
});
|
|
function handleChange(e: any) {
|
if (e && e.target && Reflect.has(e.target, 'value')) {
|
currentValueRef.value = (e as ChangeEvent).target.value;
|
}
|
if (isString(e) || isBoolean(e)) {
|
currentValueRef.value = e;
|
}
|
}
|
|
function handleEdit() {
|
isEditRef.value = true;
|
nextTick(() => {
|
const el = unref(elRef);
|
el && el.focus();
|
});
|
}
|
|
function handleCancel() {
|
isEditRef.value = false;
|
currentValueRef.value = defaultValueRef.value;
|
emit('cancel');
|
}
|
|
if (props.record) {
|
/* eslint-disable */
|
isArray(props.record.submitCbs)
|
? props.record.submitCbs.push(handleSubmit)
|
: (props.record.submitCbs = [handleSubmit]);
|
/* eslint-disable */
|
isArray(props.record.cancelCbs)
|
? props.record.cancelCbs.push(handleCancel)
|
: (props.record.cancelCbs = [handleCancel]);
|
|
/* eslint-disable */
|
props.record.onCancel = () => {
|
isArray(props.record?.cancelCbs) && props.record?.cancelCbs.forEach((fn) => fn());
|
};
|
/* eslint-disable */
|
props.record.onSubmit = () => {
|
isArray(props.record?.submitCbs) && props.record?.submitCbs.forEach((fn) => fn());
|
};
|
}
|
|
function handleSubmit() {
|
const { dataKey, dataIndex } = props;
|
if (!dataKey || !dataIndex) return;
|
|
if (props.record) {
|
/* eslint-disable */
|
props.record[dataIndex] = unref(currentValueRef) as string;
|
}
|
isEditRef.value = false;
|
}
|
|
function onClickOutside() {
|
if (props.editRow) return;
|
const { component } = props;
|
|
if (component && component.includes('Input')) {
|
handleCancel();
|
}
|
}
|
|
function renderValue() {
|
const { value } = props;
|
if (props.editRow) {
|
return !unref(isEditRef) ? value : null;
|
}
|
return (
|
!unref(isEditRef) && (
|
<div class={`${prefixCls}__normal`} onClick={handleEdit}>
|
{value}
|
<FormOutlined class={`${prefixCls}__normal-icon`} />
|
</div>
|
)
|
);
|
}
|
return () => {
|
const { component, componentProps = {} } = props;
|
|
const Comp = componentMap.get(component!) as any;
|
return (
|
<div class={prefixCls}>
|
{unref(isEditRef) && (
|
<ClickOutSide onClickOutside={onClickOutside}>
|
{() => (
|
<div class={`${prefixCls}__wrapper`}>
|
<Comp
|
placeholder={props.placeholder}
|
{...{
|
...attrs,
|
...componentProps,
|
}}
|
style={{ width: 'calc(100% - 48px)' }}
|
ref={elRef}
|
value={unref(currentValueRef)}
|
size="small"
|
onChange={handleChange}
|
onPressEnter={handleSubmit}
|
/>
|
{!props.editRow && (
|
<div class={`${prefixCls}__action`}>
|
<CheckOutlined
|
class={[`${prefixCls}__icon`, 'mx-2']}
|
onClick={handleSubmit}
|
/>
|
<CloseOutlined class={[`${prefixCls}__icon `]} onClick={handleCancel} />
|
</div>
|
)}
|
</div>
|
)}
|
</ClickOutSide>
|
)}
|
{renderValue()}
|
</div>
|
);
|
};
|
},
|
});
|
|
export function renderEditableCell({
|
dataIndex,
|
component,
|
componentProps = {},
|
placeholder,
|
}: RenderEditableCellParams) {
|
return ({ text, record }: { text: string; record: EditRecordRow }) => {
|
return (
|
<EditableCell
|
{...componentProps}
|
placeholder={placeholder}
|
value={text}
|
record={record}
|
dataKey={record.key}
|
dataIndex={dataIndex}
|
component={component}
|
/>
|
);
|
};
|
}
|
|
export function renderEditableRow({
|
dataIndex,
|
component,
|
componentProps = {},
|
placeholder,
|
}: RenderEditableCellParams) {
|
return ({ text, record }: { text: string; record: EditRecordRow }) => {
|
return (
|
<EditableCell
|
{...componentProps}
|
value={text}
|
placeholder={placeholder}
|
editRow={true}
|
editable={record.editable}
|
dataKey={record.key}
|
record={record}
|
dataIndex={dataIndex}
|
component={component}
|
/>
|
);
|
};
|
}
|
|
export type EditRecordRow<T = Hash<any>> = {
|
editable: boolean;
|
onCancel: Fn;
|
onSubmit: Fn;
|
submitCbs: Fn[];
|
cancelCbs: Fn[];
|
} & T;
|