新疆-融邦环保
1.新增到货记录模块:销售台账页入口,车辆随出库单联动,到货上限=该台账分摊量,附件走永久链接
已修改2个文件
190 ■■■■■ 文件已修改
src/views/salesManagement/deliveryLedger/index.vue 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/components/ArrivalDialog.vue 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/deliveryLedger/index.vue
@@ -45,18 +45,13 @@
          <el-button type="danger" plain @click="handleDelete">删除</el-button>
        </div>
      </div>
      <!-- 油品出库父行的 children 是到货记录,靠 row-key + children 渲染成子行 -->
      <!-- 到货记录不在列表里展开,只在详情弹框展示 -->
      <el-table
        :data="tableData"
        border
        v-loading="tableLoading"
        @selection-change="handleSelectionChange"
        :row-key="
          (row) =>
            row.source
              ? `${row.source}-${row.stockOutRecordId ?? row.id}`
              : `arrival-${row.id}`
        "
        :row-key="deliveryRowKey"
        style="width: 100%"
        height="calc(100vh - 21.5em)"
      >
@@ -171,18 +166,6 @@
          show-overflow-tooltip
        />
        <el-table-column
          label="审核状态"
          prop="status"
          align="center"
          width="100"
        >
          <template #default="scope">
            <el-tag :type="getApprovalStatusType(scope.row.status)">
              {{ getApprovalStatusText(scope.row.status) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          label="出库单号"
          prop="outboundBatches"
          show-overflow-tooltip
@@ -197,7 +180,6 @@
            <!--                @click="openForm('edit', scope.row)">发货-->
            <!--            </el-button>-->
            <el-button
              v-if="!isArrivalRow(scope.row)"
              link
              type="primary"
              style="color: #67c23a"
@@ -317,9 +299,6 @@
          <el-descriptions-item label="发货日期">{{
            detailRow.shippingDate || "--"
          }}</el-descriptions-item>
          <el-descriptions-item label="审核状态">{{
            getApprovalStatusText(detailRow.status)
          }}</el-descriptions-item>
          <el-descriptions-item label="发货车牌号">{{
            detailRow.shippingCarNumber || "--"
          }}</el-descriptions-item>
@@ -431,8 +410,10 @@
const detailDialogVisible = ref(false);
const detailRow = ref(null);
const detailProductList = ref([]);
// 油品出库父行的到货记录(子行)
// 油品出库父行的到货记录:列表不展开,只在详情弹框里展示
const detailArrivalList = ref([]);
// 父行 row-key -> 该行的到货记录,列表接口的 children 摘下来放这里
const arrivalMap = new Map();
// 到货附件后端存 JSON 字符串,出参可能是数组也可能是串
const toAttachmentList = (value) => {
@@ -462,7 +443,7 @@
const data = reactive({
  searchForm: {
    shippingNo: "", // 发货单号(两类来源都匹配)
    salesContractNo: "", // 销售合同号(只匹配发货单行)
    salesContractNo: "", // 销售合同号(多台账出库命中任一合同号即返回该行)
    shippingCarNumber: "", // 车牌号
  },
  form: {
@@ -505,7 +486,17 @@
  deliveryLedgerListPage({ ...searchForm.value, ...page })
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.data.records || [];
      const records = res.data.records || [];
      // 到货记录不做层级展开(el-table 见到 children 就会渲染成子行),
      // 但详情弹框还要展示,先按父行摘出来存着
      arrivalMap.clear();
      records.forEach((row) => {
        if (Array.isArray(row.children) && row.children.length) {
          arrivalMap.set(deliveryRowKey(row), row.children);
        }
        delete row.children;
      });
      tableData.value = records;
      total.value = res.data.total || 0;
    })
    .catch(() => {
@@ -516,17 +507,12 @@
// 油品出库行来自 stock_out_record,id 与 shipping_info 会撞号,
// 发货/删除/详情等接口背后都是 shipping_info,不能用于这类行
const isOilOutRow = (row) => row?.source === "oilOut";
// 层级展示时到货记录挂在父行的 children 上,子行没有 source
const isArrivalRow = (row) => !row?.source;
const sourceLabel = (row) => {
  if (isArrivalRow(row)) return "到货";
  return isOilOutRow(row) ? "油品出库" : "发货单";
};
const sourceTagType = (row) => {
  if (isArrivalRow(row)) return "warning";
  return isOilOutRow(row) ? "success" : "info";
};
const isRowSelectable = (row) => !isOilOutRow(row) && !isArrivalRow(row);
// 两个来源的 id 不同域,row-key 必须带上来源;到货记录要能按父行反查回来
const deliveryRowKey = (row) =>
  `${row?.source ?? "shipping"}-${row?.stockOutRecordId ?? row?.id}`;
const sourceLabel = (row) => (isOilOutRow(row) ? "油品出库" : "发货单");
const sourceTagType = (row) => (isOilOutRow(row) ? "success" : "info");
const isRowSelectable = (row) => !isOilOutRow(row);
// 表格选择数据
const handleSelectionChange = (selection) => {
@@ -560,7 +546,7 @@
const openDetail = async (row) => {
  detailRow.value = row || null;
  detailProductList.value = [];
  detailArrivalList.value = Array.isArray(row?.children) ? row.children : [];
  detailArrivalList.value = arrivalMap.get(deliveryRowKey(row)) || [];
  detailDialogVisible.value = true;
  // 油品出库行不走发货单详情接口(id 会撞号),直接用列表行数据展示
  if (!row?.id || isOilOutRow(row)) return;
@@ -819,68 +805,6 @@
    }
  }
}
// 获取审核状态文本
const getApprovalStatusText = (status) => {
  if (status === null || status === undefined || status === "") {
    return "待审核";
  }
  // 如果是数字
  if (typeof status === "number") {
    const statusMap = {
      0: "待审核",
      1: "审核中",
      2: "审核拒绝",
      3: "审核通过",
    };
    return statusMap[status] || "待审核";
  }
  // 如果是字符串,直接返回或映射
  const statusStr = String(status).trim();
  const statusTextMap = {
    待审核: "待审核",
    审核中: "审核中",
    审核拒绝: "审核拒绝",
    审核通过: "审核通过",
    已发货: "已发货",
    0: "待审核",
    1: "审核中",
    2: "审核拒绝",
    3: "审核通过",
  };
  return statusTextMap[statusStr] || statusStr || "待审核";
};
// 获取审核状态标签类型(颜色)
const getApprovalStatusType = (status) => {
  if (status === null || status === undefined || status === "") {
    return "info";
  }
  // 如果是数字
  if (typeof status === "number") {
    const typeMap = {
      0: "info", // 待审核 - 灰色
      1: "warning", // 审核中 - 黄色
      2: "danger", // 审核拒绝 - 红色
      3: "success", // 审核通过 - 绿色
    };
    return typeMap[status] || "info";
  }
  // 如果是字符串
  const statusStr = String(status).trim();
  const typeTextMap = {
    待审核: "info",
    审核中: "warning",
    审核拒绝: "danger",
    审核通过: "success",
    已发货: "success",
    0: "info",
    1: "warning",
    2: "danger",
    3: "success",
  };
  return typeTextMap[statusStr] || "info";
};
// 检查审核状态是否为"审核通过"
const isApproved = (status) => {
src/views/salesManagement/salesLedger/components/ArrivalDialog.vue
@@ -24,9 +24,13 @@
                       min-width="150"
                       show-overflow-tooltip />
      <el-table-column label="车牌号"
                       prop="truckPlateNo"
                       min-width="110"
                       show-overflow-tooltip />
                       show-overflow-tooltip>
        <!-- 出库单没登记车辆时到货记录车辆为空,不能渲染成空白格 -->
        <template #default="scope">
          {{ scope.row.truckPlateNo || "--" }}
        </template>
      </el-table-column>
      <el-table-column label="到货数量(吨)"
                       prop="arrivalQuantity"
                       min-width="110"
@@ -112,20 +116,14 @@
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <!-- 车辆不强制:出库单没登记车辆(代储/客存出库)时留空即可 -->
            <el-form-item label="车辆"
                          prop="vehicleId"
                          :rules="[
                {
                required: true,
                message: '请选择车辆',
                trigger: 'change',
              }
              ]">
                          prop="vehicleId">
              <el-select v-model="form.vehicleId"
                         placeholder="请先选择出库单"
                         :placeholder="vehiclePlaceholder"
                         clearable
                         filterable
                         :disabled="!form.stockOutRecordId"
                         :disabled="!form.stockOutRecordId || !vehicleOptions.length"
                         style="width: 100%"
                         @change="handleVehicleChange">
                <el-option v-for="item in vehicleOptions"
@@ -142,8 +140,7 @@
                          prop="arrivalQuantity"
                          :rules="[
                {
                required: true,
                message: '请输入到货数量',
                validator: validateArrivalQuantity,
                trigger: 'blur',
              }
              ]">
@@ -286,11 +283,22 @@
    return [...map.values()];
  });
  // 没登记车辆的出库单(代储/客存不强制选车)拿不出车辆候选,不该当成一个空选项
  const vehicleOptions = computed(() =>
    bindableRows.value.filter(
      item => item.stockOutRecordId === form.value.stockOutRecordId
      item =>
        item.stockOutRecordId === form.value.stockOutRecordId &&
        item.vehicleId !== null &&
        item.vehicleId !== undefined
    )
  );
  const vehiclePlaceholder = computed(() => {
    if (!form.value.stockOutRecordId) return "请先选择出库单";
    return vehicleOptions.value.length
      ? "请选择车辆"
      : "该出库单未登记车辆,可留空";
  });
  const selectedOutbound = computed(() =>
    outboundOptions.value.find(
@@ -305,6 +313,19 @@
  // 编辑时本条已占的量要从「已到货」里加回来,否则数量改不大于原值
  const originalArrivalQuantity = ref(0);
  // 0 在 required 眼里算「已填」,拦不住,这里按后端口径要求 > 0
  const validateArrivalQuantity = (rule, value, callback) => {
    if (value === null || value === undefined || value === "") {
      callback(new Error("请输入到货数量"));
      return;
    }
    if (!(Number(value) > 0)) {
      callback(new Error("到货数量必须大于0"));
      return;
    }
    callback();
  };
  // 到货上限 = 该台账在这张出库单上分摊到的数量
  const arrivalMax = computed(() => {
@@ -395,7 +416,7 @@
        form.value.id = row.id ?? null;
        form.value.stockOutRecordId = row.stockOutRecordId;
        // 车辆/车牌以出库单登记为准,但列表行里带回的是当时的值,直接回显
        form.value.vehicleId = row.vehicleId;
        form.value.vehicleId = row.vehicleId ?? undefined;
        form.value.truckPlateNo = row.truckPlateNo || "";
        form.value.arrivalQuantity = row.arrivalQuantity ?? null;
        form.value.arrivalDate = row.arrivalDate || "";
@@ -413,6 +434,12 @@
    // 车辆随出库单联动:换了出库单,原来选的车辆可能不在候选里
    form.value.vehicleId = undefined;
    form.value.truckPlateNo = "";
    // 一张出库单只登记一个车辆,能定就直接带出来(代储/客存没登记车辆则留空)
    const only = vehicleOptions.value[0];
    if (vehicleOptions.value.length === 1) {
      form.value.vehicleId = only.vehicleId;
      form.value.truckPlateNo = only.truckPlateNo || "";
    }
  };
  const handleVehicleChange = id => {
@@ -433,14 +460,17 @@
      const payload = {
        stockOutRecordId: form.value.stockOutRecordId,
        salesLedgerId: props.ledgerId,
        vehicleId: form.value.vehicleId,
        truckPlateNo: form.value.truckPlateNo,
        arrivalQuantity: form.value.arrivalQuantity,
        arrivalDate: form.value.arrivalDate,
        // 只存永久链接,2 小时失效的签名 URL 过期后附件会打不开
        attachments: form.value.attachmentList.map(getPhotoUrl).filter(Boolean),
        remark: form.value.remark,
      };
      // 车辆/车牌以出库单为准,只有选了车才传,空值不参与后端的比对
      if (form.value.vehicleId !== undefined && form.value.vehicleId !== null) {
        payload.vehicleId = form.value.vehicleId;
        payload.truckPlateNo = form.value.truckPlateNo;
      }
      const submit = form.value.id
        ? updateSalesLedgerArrival({ ...payload, id: form.value.id })
        : addSalesLedgerArrival(payload);