| | |
| | | <el-button type="primary" |
| | | plain |
| | | @click="handlePrint">打印</el-button> |
| | | <el-button type="primary" |
| | | plain |
| | | :disabled="selectedRows.length === 0" |
| | | @click="handleBatchShipping">批量发货</el-button> |
| | | </div> |
| | | </div> |
| | | <el-table :data="tableData" |
| | |
| | | ref="deliveryFormRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="发货类型:" |
| | | prop="type"> |
| | | <el-select v-model="deliveryForm.type" |
| | | placeholder="请选择发货类型" |
| | | style="width: 100%"> |
| | | <el-option label="货车" |
| | | value="货车" /> |
| | | <el-option label="快递" |
| | | value="快递" /> |
| | | </el-select> |
| | | <el-form-item label="本次发货数量:" |
| | | prop="quantity"> |
| | | <el-input-number v-model="deliveryForm.quantity" |
| | | :min="0.01" |
| | | :max="Number(deliveryForm.unshippedQuantity)" |
| | | :precision="2" |
| | | placeholder="请输入本次发货数量" |
| | | style="width: 100%" /> |
| | | <span style="margin-left: 8px; color: #909399;">剩余可发:{{ deliveryForm.unshippedQuantity }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 批量发货弹框 --> |
| | | <el-dialog v-model="batchShippingOpen" |
| | | title="批量发货" |
| | | width="60%" |
| | | @close="closeBatchShipping"> |
| | | <el-table :data="batchShippingRows" |
| | | border> |
| | | <el-table-column label="产品大类" |
| | | prop="productCategory" /> |
| | | <el-table-column label="规格型号" |
| | | prop="specificationModel" /> |
| | | <el-table-column label="订单数量" |
| | | prop="quantity" /> |
| | | <el-table-column label="剩余可发" |
| | | prop="unshippedQuantity" /> |
| | | <el-table-column label="本次发货数量"> |
| | | <template #default="scope"> |
| | | <el-input-number v-model="scope.row.shipQuantity" |
| | | :min="0.01" |
| | | :max="Number(scope.row.unshippedQuantity)" |
| | | :precision="2" |
| | | size="small" /> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitBatchShipping">确认发货</el-button> |
| | | <el-button @click="closeBatchShipping">取消</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { getToken } from "@/utils/auth"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { onMounted, ref, getCurrentInstance } from "vue"; |
| | | import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js"; |
| | | import { addShippingInfo, batchAdd } from "@/api/salesManagement/deliveryLedger.js"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import { UploadFilled, Download } from "@element-plus/icons-vue"; |
| | | import useUserStore from "@/store/modules/user"; |
| | |
| | | const currentDeliveryRow = ref(null); |
| | | const deliveryFormData = reactive({ |
| | | deliveryForm: { |
| | | type: "货车", // 货车, 快递 |
| | | salesLedgerProductId: null, |
| | | salesLedgerId: null, |
| | | quantity: null, // 本次发货数量 |
| | | unshippedQuantity: 0, // 剩余可发数量(打开弹窗时赋值) |
| | | type: "部分发货", |
| | | approveUserIds: [], |
| | | tempFileIds: [], |
| | | }, |
| | | deliveryRules: { |
| | | type: [{ required: true, message: "请选择发货类型", trigger: "change" }], |
| | | quantity: [{ required: true, message: "请输入本次发货数量", trigger: "blur" }], |
| | | }, |
| | | }); |
| | | const { deliveryForm, deliveryRules } = toRefs(deliveryFormData); |
| | | |
| | | // 批量发货相关 |
| | | const batchShippingOpen = ref(false); |
| | | const batchShippingRows = ref([]); |
| | | |
| | | // 导入相关 |
| | | const importUploadRef = ref(null); |
| | |
| | | * @param row 行数据 |
| | | */ |
| | | const canShip = row => { |
| | | if (!row || !row.hasStockInventory) { |
| | | if (!row) { |
| | | return false; |
| | | } |
| | | |
| | | // 获取发货状态 |
| | | const shippingStatus = row.shippingStatus; |
| | | |
| | | // 如果已发货(有发货日期或车牌号),不能再次发货 |
| | | if (row.shippingDate || row.shippingCarNumber) { |
| | | return false; |
| | | } |
| | | |
| | | // 仅需存在剩余可发数量(不再要求有库存记录/已完工) |
| | | const qty = Number(row.unshippedQuantity); |
| | | if (!qty || qty <= 0) { |
| | | return false; |
| | | } |
| | | |
| | | // 发货状态必须是"待发货"或"审核拒绝" |
| | | const statusStr = shippingStatus ? String(shippingStatus).trim() : ""; |
| | | const statusStr = row.shippingStatus ? String(row.shippingStatus).trim() : ""; |
| | | return statusStr === "待发货" || statusStr === "审核拒绝"; |
| | | }; |
| | | |
| | |
| | | // 检查是否可以发货 |
| | | if (!canShip(row)) { |
| | | proxy.$modal.msgWarning( |
| | | "只有在产品有库存数量,发货状态是待发货或审核拒绝的时候才可以发货" |
| | | "只有存在剩余可发数量且发货状态为待发货或审核拒绝的时候才可以发货" |
| | | ); |
| | | return; |
| | | } |
| | | |
| | | currentDeliveryRow.value = row; |
| | | deliveryForm.value = { |
| | | type: "货车", |
| | | salesLedgerProductId: row.id, |
| | | salesLedgerId: row.salesLedgerId, |
| | | quantity: row.unshippedQuantity, // 默认取剩余可发数量 |
| | | unshippedQuantity: row.unshippedQuantity, |
| | | type: "部分发货", |
| | | approveUserIds: [], |
| | | tempFileIds: [], |
| | | }; |
| | | deliveryFormVisible.value = true; |
| | | }; |
| | | |
| | | // 提交发货表单 |
| | | const submitDelivery = () => { |
| | | proxy.$refs["deliveryFormRef"].validate(valid => { |
| | | if (valid) { |
| | | // 保存当前展开的行ID,以便发货后重新加载子表格数据 |
| | | const currentExpandedKeys = [...expandedRowKeys.value]; |
| | | const salesLedgerId = currentDeliveryRow.value.salesLedgerId; |
| | | addShippingInfo({ |
| | | salesLedgerId: salesLedgerId, |
| | | salesLedgerProductId: currentDeliveryRow.value.id, |
| | | type: deliveryForm.value.type, |
| | | }).then(() => { |
| | | proxy.$modal.msgSuccess("发货成功"); |
| | | closeDeliveryDia(); |
| | | // 刷新主表数据 |
| | | getList().then(() => { |
| | | // 如果之前有展开的行,重新加载这些行的子表格数据 |
| | | if (currentExpandedKeys.length > 0) { |
| | | // 使用 Promise.all 并行加载所有展开行的子表格数据 |
| | | const loadPromises = currentExpandedKeys.map(ledgerId => { |
| | | return productList({ salesLedgerId: ledgerId, type: 1 }).then( |
| | | res => { |
| | | const index = tableData.value.findIndex( |
| | | item => item.id === ledgerId |
| | | ); |
| | | if (index > -1) { |
| | | tableData.value[index].children = res.data; |
| | | } |
| | | const qty = Number(deliveryForm.value.quantity); |
| | | if (!qty || qty <= 0) { |
| | | proxy.$modal.msgError("本次发货数量必须大于 0"); |
| | | return; |
| | | } |
| | | if (qty > Number(deliveryForm.value.unshippedQuantity)) { |
| | | proxy.$modal.msgError("本次发货数量不能超过剩余可发数量"); |
| | | return; |
| | | } |
| | | // 保存当前展开的行ID,以便发货后重新加载子表格数据 |
| | | const currentExpandedKeys = [...expandedRowKeys.value]; |
| | | addShippingInfo({ |
| | | salesLedgerId: deliveryForm.value.salesLedgerId, |
| | | salesLedgerProductId: deliveryForm.value.salesLedgerProductId, |
| | | quantity: qty, |
| | | type: deliveryForm.value.type, |
| | | approveUserIds: deliveryForm.value.approveUserIds, |
| | | tempFileIds: deliveryForm.value.tempFileIds, |
| | | }).then(res => { |
| | | if (res.code === 200) { |
| | | proxy.$modal.msgSuccess("发货成功,已发起审批"); |
| | | closeDeliveryDia(); |
| | | // 刷新主表数据 |
| | | getList().then(() => { |
| | | // 如果之前有展开的行,重新加载这些行的子表格数据 |
| | | if (currentExpandedKeys.length > 0) { |
| | | // 使用 Promise.all 并行加载所有展开行的子表格数据 |
| | | const loadPromises = currentExpandedKeys.map(ledgerId => { |
| | | return productList({ salesLedgerId: ledgerId, type: 1 }).then( |
| | | res => { |
| | | const index = tableData.value.findIndex( |
| | | item => item.id === ledgerId |
| | | ); |
| | | if (index > -1) { |
| | | tableData.value[index].children = res.data; |
| | | } |
| | | ); |
| | | }); |
| | | Promise.all(loadPromises).then(() => { |
| | | // 恢复展开状态 |
| | | expandedRowKeys.value = currentExpandedKeys; |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | ); |
| | | }); |
| | | Promise.all(loadPromises).then(() => { |
| | | // 恢复展开状态 |
| | | expandedRowKeys.value = currentExpandedKeys; |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | |
| | | deliveryFormVisible.value = false; |
| | | currentDeliveryRow.value = null; |
| | | }; |
| | | |
| | | // 批量发货:校验同一客户后拉取可发产品行 |
| | | const handleBatchShipping = async () => { |
| | | if (!selectedRows.value.length) { |
| | | proxy.$modal.msgWarning("请先勾选要发货的订单"); |
| | | return; |
| | | } |
| | | // 同一客户校验(后端也会校验) |
| | | const customerNames = [ |
| | | ...new Set(selectedRows.value.map(l => l.customerName)), |
| | | ]; |
| | | if (customerNames.length > 1) { |
| | | proxy.$modal.msgError("批量发货仅支持同一客户的多条订单"); |
| | | return; |
| | | } |
| | | // 拉取各订单的产品明细,收集剩余可发数量 > 0 的行 |
| | | batchShippingRows.value = []; |
| | | for (const ledger of selectedRows.value) { |
| | | const res = await productList({ salesLedgerId: ledger.id, type: 1 }); |
| | | const rows = (res.data || []).filter(r => Number(r.unshippedQuantity) > 0); |
| | | rows.forEach(r => { |
| | | r.salesLedgerId = ledger.id; |
| | | r.shipQuantity = r.unshippedQuantity; // 默认本次发货数量 = 剩余可发 |
| | | }); |
| | | batchShippingRows.value = batchShippingRows.value.concat(rows); |
| | | } |
| | | if (!batchShippingRows.value.length) { |
| | | proxy.$modal.msgWarning("所选订单无剩余可发货产品"); |
| | | return; |
| | | } |
| | | batchShippingOpen.value = true; |
| | | }; |
| | | |
| | | // 批量提交发货 |
| | | const submitBatchShipping = () => { |
| | | // 逐行校验数量 |
| | | for (const row of batchShippingRows.value) { |
| | | const qty = Number(row.shipQuantity); |
| | | if (!qty || qty <= 0) { |
| | | proxy.$modal.msgError("存在本次发货数量为空或为 0 的行"); |
| | | return; |
| | | } |
| | | if (qty > Number(row.unshippedQuantity)) { |
| | | proxy.$modal.msgError("存在超过剩余可发数量的行"); |
| | | return; |
| | | } |
| | | } |
| | | const reqs = batchShippingRows.value.map(r => ({ |
| | | salesLedgerId: r.salesLedgerId, |
| | | salesLedgerProductId: r.id, |
| | | quantity: r.shipQuantity, |
| | | type: "批量发货", |
| | | approveUserIds: [], |
| | | })); |
| | | batchAdd(reqs).then(res => { |
| | | if (res.code === 200) { |
| | | proxy.$modal.msgSuccess("批量发货成功,已发起审批"); |
| | | batchShippingOpen.value = false; |
| | | getList(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 关闭批量发货弹框 |
| | | const closeBatchShipping = () => { |
| | | batchShippingOpen.value = false; |
| | | batchShippingRows.value = []; |
| | | }; |
| | | |
| | | const currentFactoryName = ref(""); |
| | | const getCurrentFactoryName = async () => { |
| | | let res = await userStore.getInfo(); |