<script lang="ts" setup>
|
import type { BasicColumn } from '@jnpf/ui/vxeTable';
|
|
import type { FormulaStatus, ParameterSlot } from '#/api/x/eln/formulas';
|
|
import { computed, shallowReactive, toRaw } from 'vue';
|
|
import { BasicVxeTable, useVxeTable } from '@jnpf/ui/vxeTable';
|
|
defineOptions({ name: 'ElnFormulaParameterTable' });
|
|
const props = withDefaults(defineProps<{ fullHeight?: boolean; modelValue: EditableParameterSlot[]; readonly?: boolean; status: FormulaStatus }>(), {
|
fullHeight: false,
|
readonly: false,
|
});
|
const emit = defineEmits<{ 'update:modelValue': [value: EditableParameterSlot[]] }>();
|
type EditableParameterSlot = Omit<ParameterSlot, 'canshuBianma'> & { _clientKey?: string; canshuBianma?: string };
|
type TextField = 'canshuMingcheng' | 'danwei';
|
|
const editable = computed(() => props.status === 'DRAFT' && !props.readonly);
|
const slots = computed(() => props.modelValue);
|
const textDrafts = shallowReactive<Record<string, Partial<Record<TextField, string>>>>({});
|
const columns: BasicColumn[] = [
|
{ dataIndex: 'canshuMingcheng', minWidth: 130, title: '名称', slots: { default: 'canshuMingcheng' } },
|
{ dataIndex: 'canshuBianma', minWidth: 150, title: '编码', slots: { default: 'canshuBianma' } },
|
{ dataIndex: 'shujuLeixing', title: '类型', width: 130, slots: { default: 'shujuLeixing' } },
|
{ dataIndex: 'danwei', title: '单位', width: 100, slots: { default: 'danwei' } },
|
{ dataIndex: 'shifouBitian', title: '必填', width: 80, slots: { default: 'shifouBitian' } },
|
{ dataIndex: 'paixu', title: '排序', width: 110, slots: { default: 'paixu' } },
|
];
|
const [registerTable] = useVxeTable({
|
actionColumn: { dataIndex: 'action', fixed: 'right', title: '操作', width: 72 },
|
columns,
|
dataSource: slots,
|
height: props.fullHeight ? 420 : 220,
|
immediate: false,
|
pagination: false,
|
rowKey: (row) => row._clientKey || row.id,
|
showIndexColumn: false,
|
showTableSetting: false,
|
});
|
const typeOptions = [
|
{ fullName: '数值', id: 'DECIMAL' },
|
{ fullName: '数值集合', id: 'DECIMAL_LIST' },
|
{ fullName: '文本', id: 'TEXT' },
|
{ fullName: '布尔值', id: 'BOOLEAN' },
|
];
|
|
function update(slot: EditableParameterSlot, key: keyof EditableParameterSlot, value: unknown) {
|
if (!editable.value) return;
|
emit(
|
'update:modelValue',
|
props.modelValue.map((item) => (item === slot ? { ...item, [key]: value } : item)),
|
);
|
}
|
|
function slotKey(slot: EditableParameterSlot) {
|
return slot._clientKey || slot.id || slot.canshuBianma;
|
}
|
|
function textValue(slot: EditableParameterSlot, field: TextField) {
|
const key = slotKey(slot);
|
return (key && textDrafts[key]?.[field]) ?? slot[field];
|
}
|
|
function updateText(slot: EditableParameterSlot, field: TextField, value: string) {
|
if (!editable.value) return;
|
const key = slotKey(slot);
|
if (!key) return;
|
textDrafts[key] = { ...textDrafts[key], [field]: value };
|
const source = props.modelValue.find((item) => slotKey(item) === key);
|
if (!source) return;
|
if (field === 'canshuMingcheng') {
|
toRaw(source).canshuMingcheng = value;
|
} else {
|
toRaw(source).danwei = value || undefined;
|
}
|
}
|
|
function add() {
|
if (!editable.value) return;
|
emit('update:modelValue', [
|
...props.modelValue,
|
{
|
_clientKey: `new-${Date.now()}-${props.modelValue.length}`,
|
canshuMingcheng: '',
|
paixu: props.modelValue.length + 1,
|
shifouBitian: 1,
|
shujuLeixing: 'DECIMAL',
|
},
|
]);
|
}
|
|
function remove(slot: EditableParameterSlot) {
|
if (!editable.value) return;
|
emit(
|
'update:modelValue',
|
props.modelValue.filter((item) => item !== slot).map((item, index) => ({ ...item, paixu: index + 1 })),
|
);
|
}
|
</script>
|
|
<template>
|
<div class="parameter-table" :class="{ 'is-full-height': fullHeight }">
|
<div class="parameter-table__header">
|
<a-button v-if="editable" type="default" pre-icon="icon-ym icon-ym-btn-add" @click="add">新增参数</a-button>
|
</div>
|
<BasicVxeTable @register="registerTable" :data-source="slots">
|
<template #canshuMingcheng="{ record }">
|
<a-input
|
:disabled="!editable"
|
:maxlength="200"
|
placeholder="请输入参数名称"
|
:value="textValue(record, 'canshuMingcheng')"
|
@update:value="updateText(record, 'canshuMingcheng', $event)" />
|
</template>
|
<template #canshuBianma="{ record }">
|
<span>{{ record.canshuBianma || '保存后由系统生成' }}</span>
|
</template>
|
<template #shujuLeixing="{ record }">
|
<a-select
|
:disabled="!editable"
|
:field-names="{ label: 'fullName', value: 'id' }"
|
:options="typeOptions"
|
placeholder="请选择类型"
|
:value="record.shujuLeixing"
|
@update:value="update(record, 'shujuLeixing', $event)" />
|
</template>
|
<template #danwei="{ record }">
|
<a-input
|
:disabled="!editable"
|
:maxlength="50"
|
placeholder="请输入单位"
|
:value="textValue(record, 'danwei')"
|
@update:value="updateText(record, 'danwei', $event)" />
|
</template>
|
<template #shifouBitian="{ record }">
|
<a-switch :checked="record.shifouBitian === 1" :disabled="!editable" @update:checked="update(record, 'shifouBitian', $event ? 1 : 0)" />
|
</template>
|
<template #paixu="{ record }">
|
<a-input-number
|
:disabled="!editable"
|
:min="1"
|
placeholder="请输入排序"
|
:precision="0"
|
:value="record.paixu"
|
@update:value="update(record, 'paixu', $event)" />
|
</template>
|
<template v-if="editable" #action="{ record }"><a-button danger type="link" @click="remove(record)">删除</a-button></template>
|
</BasicVxeTable>
|
<a-alert banner class="parameter-table__notice" message="集合参数仅支持映射重复区域的数值字段,不支持普通字段或逐行公式" show-icon type="info" />
|
</div>
|
</template>
|
|
<style lang="scss" scoped>
|
.parameter-table {
|
margin-top: 12px;
|
}
|
.parameter-table.is-full-height {
|
display: flex;
|
flex-direction: column;
|
min-height: 0;
|
margin-top: 0;
|
}
|
.parameter-table__header {
|
display: flex;
|
align-items: center;
|
justify-content: flex-end;
|
margin-bottom: 8px;
|
}
|
.parameter-table__notice {
|
margin-top: 8px;
|
}
|
</style>
|