| | |
| | | <el-dialog |
| | | v-model="isShow" |
| | | title="编辑工艺路线" |
| | | width="400" |
| | | width="800" |
| | | @close="closeModal" |
| | | > |
| | | <el-form label-width="140px" :model="formState" label-position="top" ref="formRef"> |
| | | <el-form ref="formRef" label-width="140px" :model="formState" label-position="top"> |
| | | <el-form-item |
| | | label="产品名称" |
| | | prop="productModelId" |
| | | prop="selectedProducts" |
| | | :rules="[ |
| | | { |
| | | required: true, |
| | | message: '请选择产品', |
| | | trigger: 'change', |
| | | } |
| | | }, |
| | | ]" |
| | | > |
| | | <div class="product-picker"> |
| | | <el-button type="primary" @click="showProductSelectDialog = true"> |
| | | {{ formState.productName && formState.productModelName |
| | | ? `${formState.productName} - ${formState.productModelName}` |
| | | : '选择产品' }} |
| | | {{ formState.selectedProducts.length ? "重新选择产品" : "选择产品" }} |
| | | </el-button> |
| | | <div v-if="formState.selectedProducts.length" class="product-tags"> |
| | | <el-tag |
| | | v-for="product in formState.selectedProducts" |
| | | :key="product.id" |
| | | type="info" |
| | | effect="plain" |
| | | class="product-tag" |
| | | > |
| | | {{ product.productName }} / {{ product.model }} |
| | | </el-tag> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="BOM" |
| | | prop="bomId" |
| | | :rules="[ |
| | | { |
| | | required: true, |
| | | message: '请选择BOM', |
| | | trigger: 'change', |
| | | } |
| | | ]" |
| | | > |
| | | <el-form-item label="BOM" prop="bomId"> |
| | | <el-select |
| | | v-model="formState.bomId" |
| | | placeholder="请选择BOM" |
| | | clearable |
| | | :disabled="!formState.productModelId || bomOptions.length === 0" |
| | | :disabled="bomOptions.length === 0" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- 产品选择弹窗 --> |
| | | <ProductSelectDialog |
| | | v-model="showProductSelectDialog" |
| | | @confirm="handleProductSelect" |
| | | single |
| | | /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, computed, getCurrentInstance, onMounted, nextTick, watch} from "vue"; |
| | | import { computed, getCurrentInstance, nextTick, ref, watch } from "vue"; |
| | | import {update} from "@/api/productionManagement/processRoute.js"; |
| | | import {getByModel} from "@/api/productionManagement/productBom.js"; |
| | | import { getByModelList } from "@/api/productionManagement/productBom.js"; |
| | | import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue"; |
| | | |
| | | const props = defineProps({ |
| | |
| | | type: Boolean, |
| | | required: true, |
| | | }, |
| | | |
| | | record: { |
| | | type: Object, |
| | | required: true, |
| | | } |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits(['update:visible', 'completed']); |
| | | const emit = defineEmits(["update:visible", "completed"]); |
| | | |
| | | // 响应式数据(替代选项式的 data) |
| | | const formState = ref({ |
| | | productId: undefined, |
| | | productModelId: undefined, |
| | | productName: "", |
| | | productModelName: "", |
| | | bomId: undefined, |
| | | description: '', |
| | | }); |
| | | const formRef = ref(); |
| | | const showProductSelectDialog = ref(false); |
| | | const bomOptions = ref([]); |
| | | const formState = ref(createDefaultFormState()); |
| | | |
| | | const isShow = computed({ |
| | | get() { |
| | | return props.visible; |
| | | }, |
| | | set(val) { |
| | | emit('update:visible', val); |
| | | emit("update:visible", val); |
| | | }, |
| | | }); |
| | | |
| | | const showProductSelectDialog = ref(false); |
| | | const bomOptions = ref([]); |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | let { proxy } = getCurrentInstance() |
| | | const splitFieldValues = value => |
| | | String(value || "") |
| | | .split(/[,\uff0c]/) |
| | | .map(item => item.trim()) |
| | | .filter(Boolean); |
| | | |
| | | function createDefaultFormState() { |
| | | return { |
| | | id: undefined, |
| | | productId: undefined, |
| | | productModelId: undefined, |
| | | productModelIds: "", |
| | | productName: "", |
| | | productModelName: "", |
| | | selectedProducts: [], |
| | | bomId: undefined, |
| | | description: "", |
| | | }; |
| | | } |
| | | |
| | | const resetForm = () => { |
| | | formState.value = createDefaultFormState(); |
| | | bomOptions.value = []; |
| | | }; |
| | | |
| | | const closeModal = () => { |
| | | resetForm(); |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | // 设置表单数据 |
| | | const setFormData = () => { |
| | | if (props.record) { |
| | | formState.value = { |
| | | ...props.record, |
| | | productId: props.record.productId, |
| | | productModelId: props.record.productModelId, |
| | | productName: props.record.productName || "", |
| | | // 注意:record中的字段是model,需要映射到productModelName |
| | | productModelName: props.record.model || props.record.productModelName || "", |
| | | bomId: props.record.bomId, |
| | | description: props.record.description || '', |
| | | }; |
| | | // 如果有产品型号ID,加载BOM列表 |
| | | if (props.record.productModelId) { |
| | | loadBomList(props.record.productModelId); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 加载BOM列表 |
| | | const loadBomList = async (productModelId) => { |
| | | if (!productModelId) { |
| | | const loadBomList = async productModelIds => { |
| | | if (!productModelIds?.length) { |
| | | bomOptions.value = []; |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | const res = await getByModel(productModelId); |
| | | // 处理返回的BOM数据:可能是数组、对象或包含data字段 |
| | | let bomList = []; |
| | | const res = await getByModelList(productModelIds); |
| | | if (Array.isArray(res)) { |
| | | bomList = res; |
| | | } else if (res && res.data) { |
| | | bomList = Array.isArray(res.data) ? res.data : [res.data]; |
| | | } else if (res && typeof res === 'object') { |
| | | bomList = [res]; |
| | | bomOptions.value = res; |
| | | return; |
| | | } |
| | | bomOptions.value = bomList; |
| | | if (res && res.data) { |
| | | bomOptions.value = Array.isArray(res.data) ? res.data : [res.data]; |
| | | return; |
| | | } |
| | | bomOptions.value = res && typeof res === "object" ? [res] : []; |
| | | } catch (error) { |
| | | console.error("加载BOM列表失败:", error); |
| | | bomOptions.value = []; |
| | | } |
| | | }; |
| | | |
| | | // 产品选择处理 |
| | | const handleProductSelect = async (products) => { |
| | | if (products && products.length > 0) { |
| | | const product = products[0]; |
| | | // 先查询BOM列表(必选) |
| | | try { |
| | | const res = await getByModel(product.id); |
| | | // 处理返回的BOM数据:可能是数组、对象或包含data字段 |
| | | let bomList = []; |
| | | if (Array.isArray(res)) { |
| | | bomList = res; |
| | | } else if (res && res.data) { |
| | | bomList = Array.isArray(res.data) ? res.data : [res.data]; |
| | | } else if (res && typeof res === 'object') { |
| | | bomList = [res]; |
| | | const buildSelectedProducts = record => { |
| | | const ids = splitFieldValues(record.productModelIds || record.productModelId); |
| | | const productNames = splitFieldValues(record.productName); |
| | | const modelNames = splitFieldValues(record.model || record.productModelName); |
| | | const productIds = splitFieldValues(record.productIds || record.productId); |
| | | |
| | | return ids.map((id, index) => ({ |
| | | id, |
| | | productId: productIds[index] || undefined, |
| | | productName: productNames[index] || record.productName || "", |
| | | model: modelNames[index] || record.model || record.productModelName || "", |
| | | })); |
| | | }; |
| | | |
| | | const setFormData = async () => { |
| | | if (!props.record) return; |
| | | |
| | | const selectedProducts = buildSelectedProducts(props.record); |
| | | |
| | | const productModelIds = props.record.productModelIds |
| | | || (props.record.productModelId ? String(props.record.productModelId) : ""); |
| | | |
| | | formState.value = { |
| | | id: props.record.id, |
| | | productId: props.record.productId, |
| | | productModelId: props.record.productModelId, |
| | | productModelIds, |
| | | productName: props.record.productName || "", |
| | | productModelName: props.record.model || props.record.productModelName || "", |
| | | selectedProducts, |
| | | bomId: props.record.bomId, |
| | | description: props.record.description || "", |
| | | }; |
| | | |
| | | const ids = productModelIds |
| | | ? splitFieldValues(productModelIds) |
| | | : []; |
| | | await loadBomList(ids); |
| | | }; |
| | | |
| | | const handleProductSelect = async products => { |
| | | if (!products?.length) { |
| | | return; |
| | | } |
| | | |
| | | if (bomList.length > 0) { |
| | | formState.value.selectedProducts = products; |
| | | formState.value.productModelIds = products.map(product => product.id).join(","); |
| | | formState.value.bomId = undefined; |
| | | |
| | | if (products.length === 1) { |
| | | const product = products[0]; |
| | | formState.value.productId = product.productId; |
| | | formState.value.productModelId = product.id; |
| | | formState.value.productName = product.productName; |
| | | formState.value.productModelName = product.model; |
| | | // 如果当前选择的BOM不在新列表中,则重置BOM选择 |
| | | const currentBomExists = bomList.some(bom => bom.id === formState.value.bomId); |
| | | if (!currentBomExists) { |
| | | formState.value.bomId = undefined; |
| | | } |
| | | bomOptions.value = bomList; |
| | | showProductSelectDialog.value = false; |
| | | // 触发表单验证更新 |
| | | proxy.$refs["formRef"]?.validateField('productModelId'); |
| | | await loadBomList([product.id]); |
| | | } else { |
| | | proxy.$modal.msgError("该产品没有BOM,请先创建BOM"); |
| | | formState.value.productId = undefined; |
| | | formState.value.productModelId = undefined; |
| | | formState.value.productName = ""; |
| | | formState.value.productModelName = ""; |
| | | await loadBomList(products.map(product => product.id)); |
| | | } |
| | | } catch (error) { |
| | | // 如果接口返回404或其他错误,说明没有BOM |
| | | proxy.$modal.msgError("该产品没有BOM,请先创建BOM"); |
| | | } |
| | | } |
| | | |
| | | showProductSelectDialog.value = false; |
| | | formRef.value?.validateField("selectedProducts"); |
| | | }; |
| | | |
| | | const handleSubmit = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | // 验证是否选择了产品和BOM |
| | | if (!formState.value.productModelId) { |
| | | formRef.value.validate(valid => { |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | if (!formState.value.selectedProducts.length) { |
| | | proxy.$modal.msgError("请选择产品"); |
| | | return; |
| | | } |
| | | if (!formState.value.bomId) { |
| | | proxy.$modal.msgError("请选择BOM"); |
| | | return; |
| | | } |
| | | update(formState.value).then(res => { |
| | | // 关闭模态框 |
| | | |
| | | update({ |
| | | ...props.record, |
| | | id: formState.value.id, |
| | | productId: formState.value.selectedProducts.length === 1 |
| | | ? formState.value.selectedProducts[0].productId |
| | | : undefined, |
| | | productModelId: formState.value.selectedProducts.length === 1 |
| | | ? formState.value.selectedProducts[0].id |
| | | : undefined, |
| | | productModelIds: formState.value.productModelIds, |
| | | productName: formState.value.selectedProducts.length === 1 |
| | | ? formState.value.selectedProducts[0].productName |
| | | : undefined, |
| | | productModelName: formState.value.selectedProducts.length === 1 |
| | | ? formState.value.selectedProducts[0].model |
| | | : undefined, |
| | | bomId: formState.value.bomId, |
| | | description: formState.value.description, |
| | | }).then(() => { |
| | | isShow.value = false; |
| | | // 告知父组件已完成 |
| | | emit('completed'); |
| | | emit("completed"); |
| | | proxy.$modal.msgSuccess("提交成功"); |
| | | }) |
| | | } |
| | | }) |
| | | resetForm(); |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | defineExpose({ |
| | |
| | | isShow, |
| | | }); |
| | | |
| | | |
| | | // 监听弹窗打开,初始化表单数据 |
| | | watch(() => props.visible, (visible) => { |
| | | if (visible && props.record) { |
| | | watch( |
| | | () => [props.visible, props.record?.id], |
| | | ([visible]) => { |
| | | if (visible && props.record?.id) { |
| | | nextTick(() => { |
| | | setFormData(); |
| | | }); |
| | | } |
| | | }, { immediate: true }); |
| | | |
| | | onMounted(() => { |
| | | if (props.visible && props.record) { |
| | | setFormData(); |
| | | } |
| | | }); |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .product-picker { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | align-items: flex-start; |
| | | } |
| | | |
| | | .product-tags { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .product-tag { |
| | | max-width: 220px; |
| | | } |
| | | </style> |