| | |
| | | <script setup lang="ts"> |
| | | import {computed, reactive, ref, watch} from "vue"; |
| | | import {computed, reactive, ref, watch, withDefaults} from "vue"; |
| | | |
| | | defineOptions({ |
| | | name: "ProductionRecordForm" |
| | | }); |
| | | |
| | | const props = defineProps({ |
| | | list: { |
| | | type: Array, |
| | | default() { |
| | | return []; |
| | | type DeviceOption = { |
| | | id: string | number; |
| | | deviceName: string; |
| | | deviceCode?: string | number | null; |
| | | rpm?: string | number | null; |
| | | }; |
| | | |
| | | const props = withDefaults( |
| | | defineProps<{ |
| | | list: any[]; |
| | | labelWidth: number; |
| | | deviceOptions: DeviceOption[]; |
| | | selectedDeviceId: string | number | null; |
| | | }>(), |
| | | { |
| | | list: () => [], |
| | | labelWidth: 120, |
| | | deviceOptions: () => [], |
| | | selectedDeviceId: null, |
| | | } |
| | | }, |
| | | labelWidth: { |
| | | type: Number, |
| | | default: 120 |
| | | } |
| | | }); |
| | | ); |
| | | |
| | | const formRef = ref(); |
| | | const formData = reactive({ |
| | |
| | | |
| | | const getType = (item: any) => item.type || "文本格式"; |
| | | |
| | | const machineSelectItem = computed(() => { |
| | | return formData.list.find(item => getType(item) === '机台选择') || null; |
| | | }); |
| | | |
| | | const selectedDevice = computed(() => { |
| | | const machineValue = machineSelectItem.value?.value; |
| | | if (machineValue === null || machineValue === undefined || machineValue === '') return null; |
| | | return props.deviceOptions.find(device => String(device.id) === String(machineValue)) || null; |
| | | }); |
| | | |
| | | const AUTO_DEVICE_CODE_ID = "__auto_deviceCode__"; |
| | | const AUTO_RPM_ID = "__auto_rpm__"; |
| | | |
| | | let isSyncingAutoFields = false; |
| | | |
| | | const syncAutoDeviceFields = () => { |
| | | if (isSyncingAutoFields) return; |
| | | isSyncingAutoFields = true; |
| | | |
| | | try { |
| | | const machineIndex = formData.list.findIndex(item => getType(item) === "机台选择"); |
| | | if (machineIndex === -1) return; |
| | | |
| | | const removeById = (id: string) => { |
| | | const idx = formData.list.findIndex(x => x?.id === id); |
| | | if (idx !== -1) formData.list.splice(idx, 1); |
| | | }; |
| | | |
| | | removeById(AUTO_DEVICE_CODE_ID); |
| | | removeById(AUTO_RPM_ID); |
| | | |
| | | const dev = selectedDevice.value as any; |
| | | let insertPos = machineIndex + 1; |
| | | |
| | | const hasCode = |
| | | dev && |
| | | dev.deviceCode !== null && |
| | | dev.deviceCode !== undefined && |
| | | String(dev.deviceCode) !== ""; |
| | | |
| | | const hasRpm = dev && dev.rpm !== null && dev.rpm !== undefined; |
| | | |
| | | if (hasCode) { |
| | | formData.list.splice(insertPos, 0, { |
| | | id: AUTO_DEVICE_CODE_ID, |
| | | parameterItem: "设备编号", |
| | | value: dev.deviceCode, |
| | | // 只读展示:避免影响后端参数结构(submitData 会过滤) |
| | | readonly: true, |
| | | isRequired: "0", |
| | | __autoExtra: true, |
| | | }); |
| | | insertPos++; |
| | | } |
| | | |
| | | if (hasRpm) { |
| | | formData.list.splice(insertPos, 0, { |
| | | id: AUTO_RPM_ID, |
| | | parameterItem: "转数", |
| | | value: dev.rpm, |
| | | readonly: true, |
| | | isRequired: "0", |
| | | __autoExtra: true, |
| | | }); |
| | | } |
| | | } finally { |
| | | isSyncingAutoFields = false; |
| | | } |
| | | }; |
| | | |
| | | const rules = computed(() => { |
| | | const result: Record<string, any[]> = {}; |
| | | formData.list.forEach((item, index) => { |
| | |
| | | }); |
| | | |
| | | const initData = () => { |
| | | formData.list = props.list || []; |
| | | // 重要:不要直接复用 props.list 的引用,否则后续 splice formData.list 会触发 props watch,导致递归更新 |
| | | formData.list = (props.list || []).map(item => ({ ...item })); |
| | | formData.list.forEach(item => { |
| | | if (item.value === undefined) { |
| | | item.value = null; |
| | | } |
| | | // 如果参数中存在“机台选择”,则使用父组件传入的默认机台回填 |
| | | if (getType(item) === '机台选择' && (item.value === null || item.value === undefined || item.value === '')) { |
| | | item.value = props.selectedDeviceId ?? item.value; |
| | | } |
| | | }); |
| | | }; |
| | |
| | | const valid = await formRef.value.validate().catch(() => false) |
| | | |
| | | if (valid) { |
| | | return formData.list |
| | | // 自动插入的只读字段不参与提交,避免后端参数结构变化 |
| | | return formData.list.filter(item => !item.__autoExtra) |
| | | } else { |
| | | return null |
| | | } |
| | |
| | | () => props.list, |
| | | () => { |
| | | initData(); |
| | | // 初始化后再同步自动插入字段 |
| | | syncAutoDeviceFields(); |
| | | }, |
| | | {immediate: true, deep: true} |
| | | ); |
| | | |
| | | watch( |
| | | () => selectedDevice.value, |
| | | () => { |
| | | syncAutoDeviceFields(); |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | |
| | | defineExpose({ |
| | |
| | | |
| | | <template> |
| | | <el-form ref="formRef" :model="formData" :rules="rules" :label-width="`${labelWidth}px`"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12" v-for="(item, index) in formData.list" |
| | | :key="item.id"> |
| | | <el-form-item |
| | | v-for="(item, index) in formData.list" |
| | | :key="item.id" |
| | | |
| | | :label="fieldLabel(item)" |
| | | :prop="`list.${index}.value`" |
| | | > |
| | |
| | | <el-option label="是" value="是"/> |
| | | <el-option label="否" value="否"/> |
| | | </el-select> |
| | | <el-select |
| | | v-else-if="getType(item) === '机台选择'" |
| | | v-model="item.value" |
| | | placeholder="请选择" |
| | | clearable |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="device in props.deviceOptions" |
| | | :key="device.id" |
| | | :label="device.deviceName" |
| | | :value="device.id" |
| | | /> |
| | | </el-select> |
| | | <el-input |
| | | v-else |
| | | v-model="item.value" |
| | | placeholder="请输入" |
| | | clearable |
| | | :disabled="item.readonly" |
| | | :clearable="!item.readonly" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </template> |