| | |
| | | placeholder="请输入" |
| | | /> |
| | | </template> |
| | | <template #action="{ row, index }"> |
| | | <template #action="{ index }"> |
| | | <el-button type="danger" link @click="deleteRow(index)">删除</el-button> |
| | | </template> |
| | | </PIMTable> |
| | |
| | | tableData.value.splice(index, 1); |
| | | }; |
| | | |
| | | const sameKey = (a, b) => a != null && b != null && String(a) === String(b); |
| | | |
| | | /** 接口可能拆成 shippingProductVoList / productDtoData 两份,只取其一会缺批次、数量等字段 */ |
| | | const mergeShippingProductLists = (data) => { |
| | | const lists = [data?.shippingProductVoList, data?.productDtoData].filter(Array.isArray); |
| | | if (!lists.length) return []; |
| | | const map = new Map(); |
| | | for (const list of lists) { |
| | | for (const p of list) { |
| | | if (p == null) continue; |
| | | const key = p.id != null ? String(p.id) : null; |
| | | if (!key) continue; |
| | | const prev = map.get(key); |
| | | map.set(key, prev ? { ...prev, ...p } : { ...p }); |
| | | } |
| | | } |
| | | return Array.from(map.values()); |
| | | }; |
| | | |
| | | const pickShippingLine = (normalized) => { |
| | | const pid = normalized?.returnSaleLedgerProductId ?? normalized?.id; |
| | | const sid = normalized?.stockOutRecordId ?? normalized?.shippingProductId; |
| | | const direct = availableProducts.value.find( |
| | | (p) => |
| | | sameKey(p?.id, pid) || |
| | | sameKey(p?.stockOutRecordId, pid) || |
| | | sameKey(p?.id, sid) || |
| | | sameKey(p?.stockOutRecordId, sid) |
| | | ); |
| | | if (direct) return direct; |
| | | const pmid = normalized?.productModelId; |
| | | if (pmid == null || pmid === "") return undefined; |
| | | const candidates = availableProducts.value.filter((p) => sameKey(p?.productModelId, pmid)); |
| | | if (!candidates.length) return undefined; |
| | | if (candidates.length === 1) return candidates[0]; |
| | | const spec = String(normalized?.specificationModel ?? normalized?.model ?? ""); |
| | | if (spec) { |
| | | const hit = candidates.find((p) => { |
| | | const ps = String(p?.specificationModel ?? p?.model ?? ""); |
| | | return ps && ps === spec; |
| | | }); |
| | | if (hit) return hit; |
| | | } |
| | | return candidates[0]; |
| | | }; |
| | | |
| | | const isEmptyText = (v) => v === "" || v == null || v === undefined; |
| | | |
| | | const firstFiniteNumber = (...vals) => { |
| | | for (const v of vals) { |
| | | if (v === "" || v == null || v === undefined) continue; |
| | | const n = Number(v); |
| | | if (Number.isFinite(n)) return n; |
| | | } |
| | | return undefined; |
| | | }; |
| | | |
| | | const firstNonEmptyText = (...vals) => { |
| | | const hit = vals.find((v) => !isEmptyText(v)); |
| | | return hit === undefined ? "" : hit; |
| | | }; |
| | | |
| | | /** 详情接口字段常不全;{...product,...normalized} 会被 normalized 里的空串盖掉出库行上的展示字段 */ |
| | | const mergeShippingLineWithDetail = (product, normalized) => { |
| | | const row = { ...product, ...normalized }; |
| | | row.outboundBatches = firstNonEmptyText( |
| | | row.outboundBatches, |
| | | product?.outboundBatches, |
| | | product?.shippingNo, |
| | | product?.outboundNo, |
| | | normalized?.outboundBatches, |
| | | normalized?.outboundNo, |
| | | normalized?.shippingNo |
| | | ); |
| | | row.batchNo = firstNonEmptyText( |
| | | row.batchNo, |
| | | product?.batchNo, |
| | | product?.batchNumber, |
| | | product?.lotNo, |
| | | product?.batchCode, |
| | | product?.shippingBatchNo, |
| | | normalized?.batchNo, |
| | | normalized?.batchNumber, |
| | | normalized?.lotNo, |
| | | normalized?.shippingBatchNo |
| | | ); |
| | | const stock = firstFiniteNumber( |
| | | row.stockOutNum, |
| | | product?.stockOutNum, |
| | | product?.totalQuantity, |
| | | product?.shippingQuantity, |
| | | product?.deliveryQuantity, |
| | | product?.quantity, |
| | | product?.outQuantity, |
| | | normalized?.stockOutNum, |
| | | normalized?.totalQuantity, |
| | | normalized?.shippingQuantity, |
| | | normalized?.deliveryQuantity |
| | | ); |
| | | if (stock !== undefined) row.stockOutNum = stock; |
| | | const un = firstFiniteNumber( |
| | | row.unQuantity, |
| | | product?.unQuantity, |
| | | product?.remainingQuantity, |
| | | product?.noReturnQuantity, |
| | | product?.canReturnQuantity, |
| | | product?.availableReturnNum, |
| | | normalized?.unQuantity, |
| | | normalized?.remainingQuantity, |
| | | normalized?.noReturnQuantity, |
| | | normalized?.canReturnQuantity |
| | | ); |
| | | if (un !== undefined) row.unQuantity = un; |
| | | else { |
| | | const s = Number(row.stockOutNum); |
| | | const ret = Number(row.totalReturnNum ?? 0); |
| | | if (Number.isFinite(s) && s >= 0 && Number.isFinite(ret) && ret >= 0) { |
| | | row.unQuantity = Math.max(0, s - ret); |
| | | } |
| | | } |
| | | const returned = firstFiniteNumber( |
| | | row.totalReturnNum, |
| | | product?.totalReturnNum, |
| | | product?.totalReturnedNum, |
| | | normalized?.totalReturnNum, |
| | | normalized?.totalReturnedNum |
| | | ); |
| | | if (returned !== undefined) row.totalReturnNum = returned; |
| | | else if (isEmptyText(row.totalReturnNum)) row.totalReturnNum = 0; |
| | | if (isEmptyText(row.unit)) { |
| | | row.unit = firstNonEmptyText(product?.unit, normalized?.unit); |
| | | } |
| | | if (isEmptyText(row.productCategory)) { |
| | | row.productCategory = firstNonEmptyText( |
| | | normalized?.productCategory, |
| | | normalized?.productName, |
| | | product?.productCategory, |
| | | product?.productName |
| | | ); |
| | | } |
| | | if (isEmptyText(row.specificationModel)) { |
| | | row.specificationModel = firstNonEmptyText( |
| | | normalized?.specificationModel, |
| | | normalized?.model, |
| | | product?.specificationModel, |
| | | product?.model |
| | | ); |
| | | } |
| | | return row; |
| | | }; |
| | | |
| | | const normalizeDetailRow = (raw) => { |
| | | const productId = raw?.returnSaleLedgerProductId ?? raw?.saleLedgerProductId ?? raw?.id; |
| | | const ledgerId = |
| | | raw?.returnSaleLedgerProductId ?? |
| | | raw?.saleLedgerProductId ?? |
| | | raw?.stockOutRecordId ?? |
| | | raw?.shippingProductId; |
| | | const productId = ledgerId ?? raw?.id; |
| | | const returnSaleProductId = raw?.returnSaleProductId ?? raw?.id; |
| | | const num = Number(raw?.num ?? raw?.returnQuantity ?? 0); |
| | | return { |
| | |
| | | returnSaleProductId, |
| | | returnSaleLedgerProductId: productId, |
| | | productModelId: raw?.productModelId, |
| | | stockOutRecordId: raw?.stockOutRecordId, |
| | | shippingProductId: raw?.shippingProductId, |
| | | productCategory: raw?.productCategory ?? raw?.productName ?? raw?.productTypeName ?? "", |
| | | specificationModel: raw?.specificationModel ?? raw?.model ?? raw?.specModel ?? "", |
| | | outboundBatches: raw?.outboundBatches ?? raw?.outboundNo ?? raw?.shippingNo, |
| | | batchNo: |
| | | raw?.batchNo ?? |
| | | raw?.batchNumber ?? |
| | | raw?.lotNo ?? |
| | | raw?.batchCode ?? |
| | | raw?.shippingBatchNo, |
| | | stockOutNum: |
| | | raw?.stockOutNum ?? |
| | | raw?.totalQuantity ?? |
| | | raw?.shippingQuantity ?? |
| | | raw?.deliveryQuantity ?? |
| | | raw?.quantity, |
| | | totalReturnNum: raw?.totalReturnNum ?? raw?.totalReturnedNum, |
| | | unQuantity: |
| | | raw?.unQuantity ?? |
| | | raw?.remainingQuantity ?? |
| | | raw?.noReturnQuantity ?? |
| | | raw?.canReturnQuantity, |
| | | num, |
| | | returnQuantity: Number.isFinite(num) ? num : 0, |
| | | price: Number(raw?.taxInclusiveUnitPrice ?? raw?.price ?? 0), |
| | |
| | | |
| | | const setFormForEdit = async (row) => { |
| | | const res = await returnManagementGetById({ returnManagementId: row?.id }); |
| | | console.log("res", res); |
| | | const detail = res?.data ?? res ?? {}; |
| | | |
| | | Object.assign(form.value, detail); |
| | |
| | | tableData.value = Array.isArray(list) |
| | | ? list.map((raw) => { |
| | | const normalized = normalizeDetailRow(raw); |
| | | const product = availableProducts.value.find((p) => p.id === normalized.id); |
| | | return product ? { ...product, ...normalized } : normalized; |
| | | const product = pickShippingLine(normalized); |
| | | return product ? mergeShippingLineWithDetail(product, normalized) : normalized; |
| | | }) |
| | | : []; |
| | | |
| | | |
| | | const headerShipNo = detail?.shippingNo ?? form.value?.shippingNo; |
| | | if (headerShipNo && Array.isArray(tableData.value) && tableData.value.length) { |
| | | tableData.value = tableData.value.map((r) => |
| | | isEmptyText(r.outboundBatches) ? { ...r, outboundBatches: headerShipNo } : r |
| | | ); |
| | | } |
| | | |
| | | calculateTotalRefund(); |
| | | }; |
| | | |
| | |
| | | // If backend returns project info, set it |
| | | if (res.data.projectId) form.value.projectId = res.data.projectId; |
| | | |
| | | availableProducts.value = |
| | | res.data.shippingProductVoList || []; |
| | | availableProducts.value = mergeShippingProductLists(res.data); |
| | | if (clearTable) tableData.value = []; |
| | | } |
| | | }; |
| | |
| | | amount: "0.00", |
| | | isQuality: 2, |
| | | remark: "", |
| | | productCategory: product.productCategory ?? product.productName ?? "", |
| | | productName: product.productName, |
| | | specificationModel: product.specificationModel, |
| | | specificationModel: product.specificationModel ?? product.model ?? "", |
| | | unit: product.unit, |
| | | stockOutNum: product.stockOutNum, |
| | | totalReturnNum: product.totalReturnNum, |