| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="项目阶段:" prop="projectStage"> |
| | | <el-input v-model="form.projectStage" placeholder="项目阶段" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="制单人:" prop="maker"> |
| | | <el-select v-model="form.maker" filterable placeholder="请选择制单人"> |
| | | <el-option v-for="u in userOptions" :key="u.value" :label="u.label" :value="u.value" /> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="结算人:" prop="settler"> |
| | | <el-select v-model="form.settler" filterable placeholder="请选择结算人"> |
| | | <el-option v-for="u in userOptions" :key="u.value" :label="u.label" :value="u.value" /> |
| | | <el-form-item label="状态:" prop="status"> |
| | | <el-select v-model="form.status" placeholder="请选择状态"> |
| | | <el-option label="待处理" :value="0" /> |
| | | <el-option label="已处理" :value="1" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="状态:" prop="status"> |
| | | <el-select v-model="form.status" placeholder="请选择状态"> |
| | | <el-option label="待审核" :value="0" /> |
| | | <el-option label="审核中" :value="1" /> |
| | | <el-option label="已审核" :value="2" /> |
| | | </el-select> |
| | | <el-form-item label="退货原因:" prop="returnReason"> |
| | | <el-input v-model="form.returnReason" placeholder="请输入退货原因" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="退款总额:" prop="refundAmount"> |
| | | <el-input v-model="form.refundAmount" disabled placeholder="自动计算" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | placeholder="请输入" |
| | | type="number" |
| | | @input="(val) => handleReturnQuantityChange(val, row)" |
| | | /> |
| | | </template> |
| | | <template #price="{ row }"> |
| | | <el-input |
| | | v-model="row.price" |
| | | style="width:100px" |
| | | placeholder="请输入" |
| | | type="number" |
| | | @input="(val) => handlePriceChange(val, row)" |
| | | /> |
| | | </template> |
| | | <template #amount="{ row }"> |
| | | <el-input |
| | | v-model="row.amount" |
| | | style="width:100px" |
| | | placeholder="自动计算" |
| | | type="number" |
| | | disabled |
| | | /> |
| | | </template> |
| | | <template #isQuality="{ row }"> |
| | | <el-select v-model="row.isQuality" placeholder="请选择" style="width:120px"> |
| | | <el-option label="是" :value="1" /> |
| | | <el-option label="否" :value="2" /> |
| | | </el-select> |
| | | </template> |
| | | <template #remark="{ row }"> |
| | | <el-input |
| | | v-model="row.remark" |
| | | style="width:130px" |
| | | placeholder="请输入" |
| | | /> |
| | | </template> |
| | | <template #action="{ row, index }"> |
| | |
| | | customerId: "", |
| | | shippingId: "", |
| | | projectId: "", |
| | | projectStage: "", |
| | | maker: "", |
| | | makeTime: "", |
| | | settler: "", |
| | | status: 0, |
| | | returnReason: "", |
| | | refundAmount: "", |
| | | }, |
| | | rules: { |
| | | returnNo: [{ |
| | |
| | | {align: "center", label: "已退货数量", prop: "totalReturnNum", width: 120 }, |
| | | {align: "center", label: "未退货数量", prop: "unQuantity", width: 120 }, |
| | | {align: "center", label: "退货数量", prop: "returnQuantity", dataType: "slot", slot: "returnQuantity", width: 120 }, |
| | | {align: "center", label: "退货产品单价", prop: "price", dataType: "slot", slot: "price", width: 120 }, |
| | | {align: "center", label: "退货产品金额", prop: "amount", dataType: "slot", slot: "amount", width: 120 }, |
| | | {align: "center", label: "是否有质量问题", prop: "isQuality", dataType: "slot", slot: "isQuality", width: 140 }, |
| | | {align: "center", label: "备注", prop: "remark", dataType: "slot", slot: "remark", width: 150 }, |
| | | {align: "center", label: "操作" , prop: "action", dataType: "slot", slot: "action", width: 120 }, |
| | | ]); |
| | | const tableData = ref([]); |
| | |
| | | id: productId, |
| | | returnSaleProductId, |
| | | returnSaleLedgerProductId: productId, |
| | | productModelId: raw?.productModelId, |
| | | num, |
| | | returnQuantity: Number.isFinite(num) ? num : 0, |
| | | price: Number(raw?.taxInclusiveUnitPrice ?? raw?.price ?? 0), |
| | | amount: Number(raw?.amount ?? 0).toFixed(2), |
| | | isQuality: raw?.isQuality ?? 2, |
| | | remark: raw?.remark ?? "", |
| | | }; |
| | | }; |
| | | |
| | |
| | | return product ? { ...product, ...normalized } : normalized; |
| | | }) |
| | | : []; |
| | | |
| | | calculateTotalRefund(); |
| | | }; |
| | | |
| | | const openDialog = async (type, row) => { |
| | |
| | | customerId: "", |
| | | shippingId: "", |
| | | projectId: "", |
| | | projectStage: "", |
| | | maker: "", |
| | | makeTime: "", |
| | | settler: "", |
| | | status: 0, |
| | | returnReason: "", |
| | | refundAmount: "", |
| | | }); |
| | | form.value.maker = userStore.nickName || userStore.name || ""; |
| | | form.value.makeTime = new Date().toISOString().replace('T', ' ').split('.')[0]; // Default to now |
| | |
| | | if (!valid) return; |
| | | const returnSaleProducts = (tableData.value || []).map(el => ({ |
| | | returnSaleLedgerProductId: el.returnSaleLedgerProductId ?? el.id, |
| | | productModelId: el.productModelId, |
| | | unit: el.unit, |
| | | num: Number(el.num ?? el.returnQuantity ?? 0), |
| | | price: Number(el.price ?? 0), |
| | | amount: Number(el.amount ?? 0), |
| | | isQuality: el.isQuality ?? 2, |
| | | remark: el.remark ?? "", |
| | | id: operationType.value === "edit" ? (el.returnSaleProductId ?? "") : "" |
| | | })); |
| | | const payload = { ...form.value, returnSaleProducts }; |
| | |
| | | if(res.code === 200){ |
| | | // If backend returns project info, set it |
| | | if (res.data.projectId) form.value.projectId = res.data.projectId; |
| | | if (res.data.projectStage) form.value.projectStage = res.data.projectStage; |
| | | |
| | | // Store available products for selection |
| | | availableProducts.value = res.data.productDtoData || []; |
| | |
| | | const current = Number(val); |
| | | |
| | | if (current > max) { |
| | | // Need nextTick to ensure update if user typed too fast or pasted |
| | | proxy.$nextTick(() => { |
| | | row.returnQuantity = max; |
| | | row.num = max; |
| | |
| | | } else { |
| | | row.num = current; |
| | | } |
| | | calculateRowAmount(row); |
| | | calculateTotalRefund(); |
| | | }; |
| | | |
| | | const handlePriceChange = (val, row) => { |
| | | if (val === "" || val === null) { |
| | | row.price = 0; |
| | | } |
| | | calculateRowAmount(row); |
| | | calculateTotalRefund(); |
| | | }; |
| | | |
| | | const calculateRowAmount = (row) => { |
| | | const quantity = Number(row.returnQuantity || 0); |
| | | const price = Number(row.price || 0); |
| | | row.amount = (quantity * price).toFixed(2); |
| | | }; |
| | | |
| | | const calculateTotalRefund = () => { |
| | | const total = tableData.value.reduce((sum, row) => { |
| | | return sum + Number(row.amount || 0); |
| | | }, 0); |
| | | form.value.refundAmount = total.toFixed(2); |
| | | }; |
| | | |
| | | const availableProducts = ref([]); |
| | |
| | | |
| | | // Removed checkSelectable to allow toggling existing items |
| | | const confirmProductSelection = () => { |
| | | // Rebuild tableData based on selection, preserving existing data (returnQuantity) |
| | | const newTableData = []; |
| | | |
| | | selectedProducts.value.forEach(product => { |
| | | // Check if product was already in tableData to preserve user input |
| | | const existing = tableData.value.find(item => item.id === product.id); |
| | | if (existing) { |
| | | newTableData.push(existing); |
| | | } else { |
| | | // Create new entry |
| | | newTableData.push({ |
| | | ...product, // Keep all product display fields (productName, model, unit, etc.) |
| | | |
| | | // Map to backend entity structure for submission |
| | | ...product, |
| | | returnSaleLedgerProductId: product.id, |
| | | returnQuantity: 0, // Default input |
| | | num: 0, // Backend quantity field |
| | | |
| | | // Ensure display fields are available if they come from 'product' |
| | | // If product has different field names than tableColumn expects, map them here |
| | | productModelId: product.productModelId, |
| | | returnQuantity: 0, |
| | | num: 0, |
| | | price: Number(product.taxInclusiveUnitPrice ?? 0), |
| | | amount: "0.00", |
| | | isQuality: 2, |
| | | remark: "", |
| | | productName: product.productName, |
| | | specificationModel: product.specificationModel, |
| | | unit: product.unit, |