You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
6.1 KiB
244 lines
6.1 KiB
7 months ago
|
<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>
|