<template> <div class="editable-cell"> <!-- 显示模式 --> <div class="editable-cell-text-wrapper" v-if="!getRowValue && !editable"> <div> {{ value }}</div> <div class="editable-cell-action"> <edit-outlined class="editable-cell-icon" @click="editCell" /> </div> </div> <!-- 编辑模式 --> <a-popover v-else :destroyTooltipOnHide="true" :visible="!isUndefined(getValidateInfo) && visible" :content="getValidateInfo?.message" :overlayClassName="'ns-cell-rule-popover'" :getPopupContainer="(triggerNode) => triggerNode.parentNode" > <div class="editable-cell-input-wrapper"> <component :is="column.edit.component || 'NsInput'" v-bind="formProps" /> <!--单元格编辑--> <div class="editable-cell-action" v-if="editable"> <check-outlined class="editable-cell-icon" @click="saveCell" /> <!-- <close-outlined class="editable-cell-icon" @click="cancelCell" /> --> </div> </div> </a-popover> </div> </template> <script lang="ts"> import { computed, defineComponent, inject, nextTick, PropType, ref, watch } from 'vue'; import { PropTypes } from '/nerv-lib/util/type'; import { CheckOutlined, CloseOutlined, EditOutlined } from '@ant-design/icons-vue'; import { TableEdit } from '/nerv-lib/component/table/use-table-edit'; import { isUndefined, upperFirst } from 'lodash-es'; import Schema from 'async-validator'; export default defineComponent({ name: 'NsTableCell', components: { EditOutlined, CheckOutlined, CloseOutlined, }, props: { value: { type: [String, Number, Boolean, Object] as PropType<string | number | boolean | Recordable>, default: '', required: true, }, record: { type: Object as PropType<Recordable>, required: true, }, column: { type: Object as PropType<Recordable>, required: true, default: () => ({}), }, index: PropTypes.number, }, setup(props) { const { getValidate, setValidate, setValue, getValue, getKey, validate, tableEdit, tableSave, } = inject('tableEdit') as TableEdit; const visible = ref(true); const getRowKey = computed(() => { return getKey({ ...props.record }); }); const getField = computed(() => { return props.column.dataIndex; }); let editable = ref(false); const getCellValue = computed({ get: () => getValue(getRowKey.value, getField.value), set: (val) => setValue(getRowKey.value, val, getField.value), }); watch( () => props.index, () => { console.log('index', props.record, props.index); }, { deep: true, } ); const getRowValue = computed(() => { return getValue(getRowKey.value); }); const getValidateInfo = computed({ get: () => getValidate(getRowKey.value, getField.value), set: (val) => setValidate(getRowKey.value, val, getField.value), }); // setTimeout(() => console.log('getCellValue', getCellValue.value), 1000); watch( [() => getCellValue.value, () => getRowValue.value], () => { validate(getRowKey.value, getField.value); }, { immediate: true, } ); /** * 解决删除后验证遗留的问题 */ watch( () => props.index, () => { if (getValidateInfo.value) { visible.value = false; // 延迟等待隐藏动画操作 setTimeout(() => { visible.value = true; }); } } ); const editCell = () => { tableEdit(getRowKey.value, getField.value); editable.value = true; }; const cancelCell = () => { getValidateInfo.value = undefined; //清空验证信息 editable.value = false; }; const saveCell = () => { // console.log('getValidated.value', getValidated.value); if (!getValidateInfo.value) { editable.value = false; tableSave(getRowKey.value, getField.value); } }; const formProps = computed(() => { const { component, valueField, changeEvent = 'change', props: componentProps, } = props.column.edit; const isCheck = component && ['NsSwitch', 'NsCheckbox', 'Switch', 'Checkbox'].includes(component); const bindValue: Recordable = { [valueField || (isCheck ? 'checked' : 'value')]: getCellValue.value, }; const eventKey = `on${upperFirst(changeEvent)}`; const on = { [eventKey]: (...args: Nullable<Recordable>[]) => { const [e] = args; const target = e ? e.target : null; getCellValue.value = target ? (isCheck ? target.checked : target.value) : e; }, }; return { ...componentProps, ...bindValue, ...on, }; }); return { editCell, saveCell, cancelCell, editable, formProps, visible, getValidateInfo, getCellValue, getRowValue, isUndefined, }; }, }); </script> <style lang="less" scoped> .ns-cell-rule-popover { color: @error-color; } .editable-cell { position: relative; .editable-cell-input-wrapper, .editable-cell-text-wrapper { display: flex; align-items: center; justify-content: space-between; } .editable-cell-action { width: 36px; display: flex; align-items: center; justify-content: center; } .editable-cell-icon { width: 24px; line-height: 28px; opacity: 0; } &:hover .editable-cell-icon { color: #108ee9; opacity: 1; } .editable-add-btn { margin-bottom: 8px; } } .editable-cell:hover .editable-cell-icon { display: inline-block; } :deep(.ant-popover) { z-index: 50; } </style>