| | |
| | | <el-form-item label="已选择发货数量:"> |
| | | <el-input :model-value="selectedDeliveryQuantity" |
| | | disabled /> |
| | | <div class="delivery-quantity-tip" |
| | | :class="deliveryQuantityTipClass"> |
| | | {{ deliveryQuantityTip }} |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="超发数量:"> |
| | | <div class="delivery-excess-row"> |
| | | <el-input :model-value="excessDeliveryQuantity" |
| | | class="delivery-excess-input" |
| | | :class="{ 'is-over': excessDeliveryQuantity > 0 }" |
| | | disabled /> |
| | | <div class="delivery-over-switch"> |
| | | <el-switch v-model="deliveryForm.allowOverDelivery" |
| | | inline-prompt |
| | | active-text="允许超发" |
| | | inactive-text="禁止超发" |
| | | :width="88" |
| | | @change="handleAllowOverDeliveryChange" /> |
| | | <el-tooltip placement="top" |
| | | content="关闭时,本次发货总量不能超过待发货数量;开启后,可按库存数量超发"> |
| | | <el-icon class="delivery-over-switch__tip"> |
| | | <QuestionFilled /> |
| | | </el-icon> |
| | | </el-tooltip> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | <el-col :span="24"> |
| | | <el-form-item label="库存:" |
| | | prop="batchNo"> |
| | | <div class="delivery-batch-toolbar"> |
| | | <span class="delivery-batch-toolbar__hint"> |
| | | {{ deliveryForm.allowOverDelivery |
| | | ? "已开启超发,各批号发货数量不能大于库存数量" |
| | | : `未开启超发,本次发货总量不能超过待发货数量(${getCurrentDeliveryRowQuantity()})` }} |
| | | </span> |
| | | <div class="delivery-batch-toolbar__actions"> |
| | | <el-button size="small" |
| | | type="primary" |
| | | plain |
| | | :disabled="!canAutoAllocateDeliveryQuantity" |
| | | @click="autoAllocateDeliveryQuantity"> |
| | | 一键分配待发货数量 |
| | | </el-button> |
| | | <el-button size="small" |
| | | text |
| | | :disabled="selectedDeliveryQuantity <= 0" |
| | | @click="clearDeliveryQuantity"> |
| | | 清空 |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | <el-table :data="deliveryForm.batchNoList" |
| | | border |
| | | size="small" |
| | |
| | | roundAmount, |
| | | } from "@/utils/numberFormat"; |
| | | import ImageUpload from "@/components/AttachmentUpload/image/index.vue"; |
| | | import { QuestionFilled } from "@element-plus/icons-vue"; |
| | | import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | import { listCustomer } from "@/api/basicData/customer.js"; |
| | |
| | | ) |
| | | ); |
| | | }); |
| | | const remainingDeliveryQuantity = computed(() => { |
| | | return roundAmount( |
| | | getCurrentDeliveryRowQuantity() - selectedDeliveryQuantity.value |
| | | ); |
| | | }); |
| | | const allowOverDelivery = computed( |
| | | () => !!deliveryForm.value.allowOverDelivery |
| | | ); |
| | | const deliveryQuantityTip = computed(() => { |
| | | const pendingQuantity = getCurrentDeliveryRowQuantity(); |
| | | const remainQuantity = remainingDeliveryQuantity.value; |
| | | if (allowOverDelivery.value) { |
| | | return excessDeliveryQuantity.value > 0 |
| | | ? `已超发 ${excessDeliveryQuantity.value},请确认超发数量无误` |
| | | : "已开启超发,本次发货数量仅受库存数量限制"; |
| | | } |
| | | if (remainQuantity < 0) { |
| | | return `已超出待发货数量 ${Math.abs(remainQuantity)},请减少发货数量`; |
| | | } |
| | | if (remainQuantity === 0 && pendingQuantity > 0) { |
| | | return `已达到待发货数量 ${pendingQuantity},当前不允许超发`; |
| | | } |
| | | return `未开启超发,本次最多可发 ${pendingQuantity},还差 ${remainQuantity}`; |
| | | }); |
| | | const deliveryQuantityTipClass = computed(() => ({ |
| | | "is-over": excessDeliveryQuantity.value > 0, |
| | | "is-full": |
| | | !allowOverDelivery.value && |
| | | remainingDeliveryQuantity.value === 0 && |
| | | getCurrentDeliveryRowQuantity() > 0, |
| | | })); |
| | | const hasDeliveryStock = computed(() => { |
| | | return (deliveryForm.value.batchNoList || []).some( |
| | | item => Number(getDeliveryBatchQuantity(item) || 0) > 0 |
| | | ); |
| | | }); |
| | | const canAutoAllocateDeliveryQuantity = computed( |
| | | () => getCurrentDeliveryRowQuantity() > 0 && hasDeliveryStock.value |
| | | ); |
| | | const getDeliveryBatchDeliveryMax = row => { |
| | | const batchQuantity = Number(getDeliveryBatchQuantity(row) || 0); |
| | | return Math.max(0, batchQuantity); |
| | | const batchQuantity = Math.max( |
| | | 0, |
| | | Number(getDeliveryBatchQuantity(row) || 0) |
| | | ); |
| | | if (allowOverDelivery.value) { |
| | | return batchQuantity; |
| | | } |
| | | // 未开启超发时,单个批号最多还能填“待发货数量 - 其他批号已选数量” |
| | | const currentQuantity = Number(row?.deliveryQuantity || 0); |
| | | const otherSelectedQuantity = roundAmount( |
| | | selectedDeliveryQuantity.value - currentQuantity |
| | | ); |
| | | const availableQuantity = Math.max( |
| | | 0, |
| | | roundAmount(getCurrentDeliveryRowQuantity() - otherSelectedQuantity) |
| | | ); |
| | | return Math.min(batchQuantity, availableQuantity); |
| | | }; |
| | | const handleDeliveryBatchQuantityChange = row => { |
| | | const batchQuantity = Number(getDeliveryBatchQuantity(row) || 0); |
| | | const batchQuantity = Math.max( |
| | | 0, |
| | | Number(getDeliveryBatchQuantity(row) || 0) |
| | | ); |
| | | const currentValue = Number(row?.deliveryQuantity || 0); |
| | | const maxQuantity = getDeliveryBatchDeliveryMax(row); |
| | | |
| | | if (currentValue > batchQuantity) { |
| | | row.deliveryQuantity = batchQuantity; |
| | | if (currentValue <= maxQuantity) { |
| | | return; |
| | | } |
| | | row.deliveryQuantity = roundAmount(maxQuantity); |
| | | // 未开启超发且是待发货数量先到上限时,提示待发货数量限制 |
| | | if (!allowOverDelivery.value && maxQuantity < batchQuantity) { |
| | | proxy.$modal.msgWarning( |
| | | `未开启超发,本次发货总量不能超过待发货数量 ${getCurrentDeliveryRowQuantity()}` |
| | | ); |
| | | } else { |
| | | proxy.$modal.msgWarning("发货数量不能大于库存数量"); |
| | | } |
| | | }; |
| | | // 按批号逐条把目标数量填入各批号 |
| | | const fillDeliveryQuantity = targetQuantity => { |
| | | let remainingQuantity = roundAmount(Math.max(0, targetQuantity)); |
| | | (deliveryForm.value.batchNoList || []).forEach(row => { |
| | | const batchQuantity = Math.max( |
| | | 0, |
| | | Number(getDeliveryBatchQuantity(row) || 0) |
| | | ); |
| | | const quantity = Math.min(batchQuantity, remainingQuantity); |
| | | row.deliveryQuantity = roundAmount(quantity); |
| | | remainingQuantity = roundAmount(remainingQuantity - quantity); |
| | | }); |
| | | return remainingQuantity; |
| | | }; |
| | | const autoAllocateDeliveryQuantity = () => { |
| | | const pendingQuantity = getCurrentDeliveryRowQuantity(); |
| | | if (pendingQuantity <= 0) { |
| | | proxy.$modal.msgWarning("待发货数量为0,无需分配发货数量"); |
| | | return; |
| | | } |
| | | if (!hasDeliveryStock.value) { |
| | | proxy.$modal.msgWarning("当前没有可用库存批号"); |
| | | return; |
| | | } |
| | | const unallocatedQuantity = fillDeliveryQuantity(pendingQuantity); |
| | | if (unallocatedQuantity > 0) { |
| | | proxy.$modal.msgWarning( |
| | | `库存不足,待发货数量仍有 ${unallocatedQuantity} 未分配` |
| | | ); |
| | | } else { |
| | | proxy.$modal.msgSuccess(`已按批号逐条分配待发货数量 ${pendingQuantity}`); |
| | | } |
| | | }; |
| | | const clearDeliveryQuantity = () => { |
| | | (deliveryForm.value.batchNoList || []).forEach(row => { |
| | | row.deliveryQuantity = 0; |
| | | }); |
| | | }; |
| | | const handleAllowOverDeliveryChange = allow => { |
| | | if (allow) return; |
| | | const pendingQuantity = getCurrentDeliveryRowQuantity(); |
| | | // 待发货数量为0时关闭超发会导致无法发货,强制保持允许 |
| | | if (pendingQuantity <= 0) { |
| | | deliveryForm.value.allowOverDelivery = true; |
| | | proxy.$modal.msgWarning("待发货数量为0,无法关闭超发"); |
| | | return; |
| | | } |
| | | if (selectedDeliveryQuantity.value <= pendingQuantity) return; |
| | | ElMessageBox.confirm( |
| | | `当前已选发货数量 ${selectedDeliveryQuantity.value} 超过待发货数量 ${pendingQuantity},关闭超发后将按批号逐条自动缩减至 ${pendingQuantity},是否继续?`, |
| | | "关闭超发", |
| | | { |
| | | type: "warning", |
| | | confirmButtonText: "继续", |
| | | cancelButtonText: "取消", |
| | | } |
| | | ) |
| | | .then(() => { |
| | | fillDeliveryQuantity(pendingQuantity); |
| | | proxy.$modal.msgSuccess(`已将发货总量调整为 ${pendingQuantity}`); |
| | | }) |
| | | .catch(() => { |
| | | deliveryForm.value.allowOverDelivery = true; |
| | | }); |
| | | }; |
| | | const getSelectedDeliveryBatchRows = () => { |
| | | return (deliveryForm.value.batchNoList || []).filter( |
| | |
| | | expressCompany: "", |
| | | expressNumber: "", |
| | | type: "货车", // 货车, 快递, 自送 |
| | | allowOverDelivery: false, // 是否允许超发,默认关闭 |
| | | }, |
| | | deliveryRules: { |
| | | shippingCarNumber: [ |
| | |
| | | expressCompany: "", |
| | | expressNumber: "", |
| | | type: "货车", |
| | | // 待发货数量为0时,“禁止超发”会导致无法发货,此时默认允许超发 |
| | | allowOverDelivery: !(Number(row?.noQuantity || 0) > 0), |
| | | batchNo: [], |
| | | batchNoList, |
| | | }; |
| | |
| | | const selectedBatchRows = getSelectedDeliveryBatchRows(); |
| | | if (selectedBatchRows.length === 0) { |
| | | proxy.$modal.msgWarning("请至少填写一个批号的发货数量"); |
| | | return; |
| | | } |
| | | // 关闭超发时,发货总量不能超过待发货数量 |
| | | if ( |
| | | !allowOverDelivery.value && |
| | | selectedDeliveryQuantity.value > getCurrentDeliveryRowQuantity() |
| | | ) { |
| | | proxy.$modal.msgWarning( |
| | | `未开启超发,本次发货总量不能超过待发货数量 ${getCurrentDeliveryRowQuantity()}` |
| | | ); |
| | | return; |
| | | } |
| | | // 保存当前展开的行ID,以便发货后重新加载子表格数据 |
| | |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .delivery-quantity-tip { |
| | | margin-top: 4px; |
| | | font-size: 12px; |
| | | line-height: 18px; |
| | | color: #909399; |
| | | |
| | | &.is-full { |
| | | color: #67c23a; |
| | | } |
| | | |
| | | &.is-over { |
| | | color: #f56c6c; |
| | | } |
| | | } |
| | | |
| | | .delivery-excess-row { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 16px; |
| | | width: 100%; |
| | | } |
| | | |
| | | .delivery-excess-input { |
| | | flex: 1; |
| | | |
| | | &.is-over :deep(.el-input__inner) { |
| | | color: #f56c6c; |
| | | font-weight: 600; |
| | | } |
| | | } |
| | | |
| | | .delivery-over-switch { |
| | | display: flex; |
| | | flex-shrink: 0; |
| | | align-items: center; |
| | | gap: 4px; |
| | | } |
| | | |
| | | .delivery-over-switch__tip { |
| | | color: #909399; |
| | | cursor: help; |
| | | } |
| | | |
| | | .delivery-batch-toolbar { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 8px; |
| | | width: 100%; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .delivery-batch-toolbar__hint { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .delivery-batch-toolbar__actions { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .print-preview-dialog { |
| | | .el-dialog__body { |
| | | padding: 0; |