gongchunyi
5 小时以前 477f9e61542753ea7338eadc59654200f3146f79
feat: 发货台账添加是否超发按钮
已修改1个文件
266 ■■■■■ 文件已修改
src/views/salesManagement/salesLedger/index.vue 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/index.vue
@@ -990,12 +990,34 @@
            <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="超发数量:">
              <el-input :model-value="excessDeliveryQuantity"
                        disabled />
              <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>
@@ -1044,6 +1066,28 @@
          <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"
@@ -1141,6 +1185,7 @@
    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";
@@ -1327,18 +1372,149 @@
      )
    );
  });
  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(
@@ -1383,6 +1559,7 @@
      expressCompany: "",
      expressNumber: "",
      type: "货车", // 货车, 快递, 自送
      allowOverDelivery: false, // 是否允许超发,默认关闭
    },
    deliveryRules: {
      shippingCarNumber: [
@@ -2578,6 +2755,8 @@
      expressCompany: "",
      expressNumber: "",
      type: "货车",
      // 待发货数量为0时,“禁止超发”会导致无法发货,此时默认允许超发
      allowOverDelivery: !(Number(row?.noQuantity || 0) > 0),
      batchNo: [],
      batchNoList,
    };
@@ -2592,6 +2771,16 @@
        const selectedBatchRows = getSelectedDeliveryBatchRows();
        if (selectedBatchRows.length === 0) {
          proxy.$modal.msgWarning("请至少填写一个批号的发货数量");
          return;
        }
        // 关闭超发时,发货总量不能超过待发货数量
        if (
          !allowOverDelivery.value &&
          selectedDeliveryQuantity.value > getCurrentDeliveryRowQuantity()
        ) {
          proxy.$modal.msgWarning(
            `未开启超发,本次发货总量不能超过待发货数量 ${getCurrentDeliveryRowQuantity()}`
          );
          return;
        }
        // 保存当前展开的行ID,以便发货后重新加载子表格数据
@@ -2725,6 +2914,69 @@
    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;