| | |
| | | <el-table-column label="材料名称"> |
| | | <template #default="{ row, $index }"> |
| | | <el-tree-select |
| | | v-if="!isDetail" |
| | | v-if="props.type === 'add'" |
| | | v-model="row.productById" |
| | | placeholder="请选择" |
| | | clearable |
| | |
| | | </template> |
| | | <template #default="{ row }"> |
| | | <el-select |
| | | v-if="!isDetail" |
| | | v-if="props.type === 'add'" |
| | | v-model="row.productModelId" |
| | | placeholder="请选择规格" |
| | | filterable |
| | |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | <el-text class="mx-1" v-else>Default</el-text> |
| | | <!-- <span v-else>{{ row.model }}</span>--> |
| | | <span v-else>{{ row.model }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="数量"> |
| | |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="计量单位"> |
| | | <template #default="{ row }"> |
| | | <el-input v-model="row.unit" placeholder="计量单位" :disabled="isDetail"/> |
| | | <template #default="{ row }"> |
| | | <el-input v-if="props.type === 'add'" v-model="row.unit" placeholder="计量单位" :disabled="isDetail"/> |
| | | <span v-else>{{ row.unit }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="单价"> |
| | |
| | | |
| | | const filePreviewRef = ref() |
| | | const formData = reactive({ |
| | | id: null, |
| | | productOrderList: null, |
| | | salesLedgerId: null, |
| | | productOrderId: null, |
| | |
| | | ], |
| | | materialInfo: [ |
| | | { |
| | | parentId: "", |
| | | productById: "", |
| | | productId: "", |
| | | name: "", |
| | | productModelId: "", |
| | |
| | | const cloneDeep = (val) => JSON.parse(JSON.stringify(val)) |
| | | |
| | | const createDefaultFormData = () => ({ |
| | | id: null, |
| | | productOrderList: null, |
| | | salesLedgerId: null, |
| | | productOrderId: null, |
| | |
| | | ], |
| | | materialInfo: [ |
| | | { |
| | | parentId: "", |
| | | productById: "", |
| | | productId: "", |
| | | name: "", |
| | | productModelId: "", |
| | |
| | | } |
| | | |
| | | Object.keys(formData).forEach((key) => { |
| | | if (key === 'id') return |
| | | if (source[key] !== undefined) { |
| | | formData[key] = Array.isArray(source[key]) ? cloneDeep(source[key]) : source[key] |
| | | } |
| | |
| | | })) |
| | | } |
| | | |
| | | if (Array.isArray(formData.materialInfo)) { |
| | | formData.materialInfo = formData.materialInfo.map((m) => { |
| | | const parentId = m?.parentId ? String(m.parentId) : "" |
| | | const productById = m?.productById ? String(m.productById) : "" |
| | | const name = m?.name ?? "" |
| | | return { |
| | | ...m, |
| | | parentId, |
| | | productById: productById || parentId || "", |
| | | name: name || (parentId ? findProductLabelById(productOptions.value, parentId) : "") |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 兼容 index.vue 里常用字段名与弹窗字段名不一致的情况 |
| | | if (source.productName === undefined && source.productCategory !== undefined) { |
| | | formData.productName = source.productCategory |
| | |
| | | } |
| | | if (source.productOrderId === undefined && source.id !== undefined) { |
| | | formData.productOrderId = source.id |
| | | } |
| | | |
| | | // 编辑/查看时需要把 productionProductInput 的 id 带回去(后端 save 走更新) |
| | | // 列表行里一般是 printId;详情接口一般返回 { id, productOrderId, ... } |
| | | if (source.printId !== undefined && source.printId !== null && source.printId !== '') { |
| | | formData.id = source.printId |
| | | } else if (source.productionProductInputId !== undefined && source.productionProductInputId !== null && source.productionProductInputId !== '') { |
| | | formData.id = source.productionProductInputId |
| | | } else if (source.productOrderId !== undefined && source.id !== undefined && source.id !== null && source.id !== '') { |
| | | formData.id = source.id |
| | | } |
| | | |
| | | introductionLetterList.value = String(formData.introductionLetter || "") |
| | |
| | | (val) => { |
| | | mergeRowDataToForm(val) |
| | | getProductOrder() |
| | | Promise.resolve().then(() => hydrateMaterialInfo()) |
| | | }, |
| | | {immediate: true, deep: true} |
| | | ) |
| | |
| | | const convertProductOptions = (data) => { |
| | | return data.map(item => ({ |
| | | label: item.label || item.productName || item.name || "", |
| | | value: item.id, |
| | | value: String(item.id ?? ""), |
| | | children: item.children?.length ? convertProductOptions(item.children) : undefined |
| | | })) |
| | | } |
| | | |
| | | const findProductLabelById = (options, productId) => { |
| | | for (const item of options) { |
| | | if (item.value === productId) { |
| | | if (String(item.value) === String(productId)) { |
| | | return item.label |
| | | } |
| | | if (item.children?.length) { |
| | |
| | | return "" |
| | | } |
| | | |
| | | const normalizeId = (v) => { |
| | | if (v === 0 || v === "0") return "0" |
| | | if (v === null || v === undefined) return "" |
| | | const s = String(v) |
| | | return s === "null" || s === "undefined" ? "" : s |
| | | } |
| | | |
| | | const materialModelOptionsCache = new Map() |
| | | |
| | | const normalizeModelOptions = (res) => { |
| | | return Array.isArray(res) ? res : |
| | | Array.isArray(res?.data) ? res.data : |
| | | Array.isArray(res?.rows) ? res.rows : |
| | | Array.isArray(res?.data?.records) ? res.data.records : |
| | | [] |
| | | } |
| | | |
| | | const getModelOptionsByParentId = async (parentId) => { |
| | | const key = normalizeId(parentId) |
| | | if (!key) return [] |
| | | if (materialModelOptionsCache.has(key)) return materialModelOptionsCache.get(key) |
| | | const res = await modelList({id: key}) |
| | | const options = normalizeModelOptions(res) |
| | | materialModelOptionsCache.set(key, options) |
| | | return options |
| | | } |
| | | |
| | | const hydrateMaterialInfo = async () => { |
| | | const rows = Array.isArray(formData.materialInfo) ? formData.materialInfo : [] |
| | | await Promise.all(rows.map(async (row) => { |
| | | if (!row || typeof row !== 'object') return |
| | | const parentId = normalizeId(row.parentId || row.productById) |
| | | if (!parentId) return |
| | | |
| | | row.parentId = parentId |
| | | row.productById = parentId |
| | | if (!row.name) { |
| | | row.name = findProductLabelById(productOptions.value, parentId) |
| | | } |
| | | |
| | | if (!Array.isArray(row.modelOptions) || row.modelOptions.length === 0) { |
| | | row.modelOptions = await getModelOptionsByParentId(parentId) |
| | | } |
| | | |
| | | const productModelId = normalizeId(row.productModelId) |
| | | if (productModelId && Array.isArray(row.modelOptions) && row.modelOptions.length) { |
| | | const currentModel = row.modelOptions.find(item => normalizeId(item?.id) === productModelId) |
| | | if (currentModel) { |
| | | row.model = currentModel?.model || row.model || "" |
| | | row.unit = currentModel?.unit || row.unit || "" |
| | | if (!row.productId) { |
| | | row.productId = currentModel?.id || "" |
| | | } |
| | | } |
| | | } |
| | | })) |
| | | } |
| | | |
| | | const getMaterialProductOptions = () => { |
| | | productTreeList().then(res => { |
| | | const rawData = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : [] |
| | | productOptions.value = convertProductOptions(rawData) |
| | | Promise.resolve().then(() => hydrateMaterialInfo()) |
| | | }) |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | const getModels = async (val, row, index) => { |
| | | const targetRow = formData.materialInfo[index] |
| | | row.productId = val || "" |
| | | row.productById = val || "" |
| | | row.name = val ? findProductLabelById(productOptions.value, val) : "" |
| | | const targetRow = formData.materialInfo[index] || {} |
| | | const parentId = val ? String(val) : "" |
| | | const name = parentId ? findProductLabelById(productOptions.value, parentId) : "" |
| | | |
| | | row.productModelId = "" |
| | | row.model = "" |
| | | row.unit = "" |
| | | row.modelOptions = [] |
| | | |
| | | if (!val) return |
| | | |
| | | const res = await modelList({id: val}) |
| | | formData.materialInfo[index] = { |
| | | const baseRow = { |
| | | ...targetRow, |
| | | modelOptions: Array.isArray(res) ? res : |
| | | Array.isArray(res?.data) ? res.data : |
| | | Array.isArray(res?.rows) ? res.rows : |
| | | Array.isArray(res?.data?.records) ? res.data.records : |
| | | [] |
| | | parentId, |
| | | productId: "", |
| | | productById: parentId, |
| | | name, |
| | | productModelId: "", |
| | | model: "", |
| | | unit: "", |
| | | modelOptions: [] |
| | | } |
| | | |
| | | formData.materialInfo[index] = baseRow |
| | | |
| | | if (!parentId) return |
| | | |
| | | const modelOptions = await getModelOptionsByParentId(parentId) |
| | | |
| | | formData.materialInfo[index] = { |
| | | ...baseRow, |
| | | modelOptions |
| | | } |
| | | // row.modelOptions = Array.isArray(res) ? res : |
| | | // Array.isArray(res?.data) ? res.data : |
| | |
| | | const addMaterialRow = () => { |
| | | formData.materialInfo.push({ |
| | | id: Date.now().toString(), |
| | | parentId: "", |
| | | productById: "", |
| | | productId: "", |
| | | name: "", |
| | | productModelId: "", |
| | |
| | | const materialRows = Array.isArray(formData.materialInfo) ? formData.materialInfo : [] |
| | | for (let i = 0; i < materialRows.length; i++) { |
| | | const row = materialRows[i] || {} |
| | | if (!row.productId) { |
| | | if (!row.productModelId) { |
| | | ElMessage.warning(`材料信息第${i + 1}行: 规格必填`) |
| | | return |
| | | } |
| | | |
| | | } |
| | | const rows = Array.isArray(formData.processContent) ? formData.processContent : [] |
| | | for (let i = 0; i < rows.length; i++) { |
| | | const row = rows[i] || {} |
| | | if (!row.deviceId) { |
| | | ElMessage.warning(`工艺加工第${i + 1}行:机台必填`) |
| | | return |
| | | } |
| | | if (!Array.isArray(row.reportUserIds) || row.reportUserIds.length === 0) { |
| | | ElMessage.warning(`工艺加工第${i + 1}行:报工人必填`) |
| | | return |
| | | } |
| | | } |
| | | // for (let i = 0; i < rows.length; i++) { |
| | | // const row = rows[i] || {} |
| | | // if (!row.deviceId) { |
| | | // ElMessage.warning(`工艺加工第${i + 1}行:机台必填`) |
| | | // return |
| | | // } |
| | | // if (!Array.isArray(row.reportUserIds) || row.reportUserIds.length === 0) { |
| | | // ElMessage.warning(`工艺加工第${i + 1}行:报工人必填`) |
| | | // return |
| | | // } |
| | | // } |
| | | const payload = cloneDeep(formData) |
| | | delete payload.productOrderList |
| | | if (Array.isArray(payload.materialInfo)) { |