2 天以前 027222214c48a4752515fcf2e129487feb7c233b
Merge remote-tracking branch 'origin/dev_NEW_pro' into dev_NEW_pro
已修改5个文件
1633 ■■■■■ 文件已修改
src/views/inventoryManagement/dispatchLog/Record.vue 897 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/receiptManagement/Record.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/deliveryLedger/index.vue 636 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/returnOrder/components/formDia.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/index.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/dispatchLog/Record.vue
@@ -1,117 +1,110 @@
<template>
    <div>
        <div class="search_form" style="margin-bottom: 10px;">
            <div>
                <span class="search_title ml10">出库日期:</span>
                <el-date-picker
                    v-model="searchForm.timeStr"
                    type="date"
                    placeholder="请选择日期"
                    value-format="YYYY-MM-DD"
                    format="YYYY-MM-DD"
                    clearable
                    @change="handleQuery"
                />
        <span class="search_title ml10">来源:</span>
        <el-select v-model="searchForm.recordType"
                   style="width: 240px"
                   placeholder="请选择"
                   clearable>
          <el-option v-for="item in stockRecordTypeOptions"
                     :key="item.value"
                     :label="item.label"
                     :value="item.value"/>
        </el-select>
                <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
                >搜索</el-button
                >
            </div>
            <div>
                <el-button type="primary" @click="handleBatchApprove">审批</el-button>
                <el-button @click="handleOut">导出</el-button>
                <el-button type="danger" plain @click="handleDelete">删除</el-button>
                <el-button type="primary" plain @click="handlePrint">打印</el-button>
            </div>
        </div>
        <div class="table_list">
            <el-table
                :data="tableData"
                border
                v-loading="tableLoading"
                @selection-change="handleSelectionChange"
                :expand-row-keys="expandedRowKeys"
                :row-key="(row) => row.id"
                style="width: 100%"
                height="calc(100vh - 18.5em)"
            >
                <el-table-column align="center" type="selection" width="55" />
                <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column
            label="出库批次"
            prop="outboundBatches"
            min-width="100"
            show-overflow-tooltip
  <div>
    <div class="search_form" style="margin-bottom: 10px">
      <div>
        <span class="search_title ml10">出库日期:</span>
        <el-date-picker
          v-model="searchForm.timeStr"
          type="date"
          placeholder="请选择日期"
          value-format="YYYY-MM-DD"
          format="YYYY-MM-DD"
          clearable
          @change="handleQuery"
        />
                <el-table-column
                    label="出库日期"
                    prop="createTime"
                    show-overflow-tooltip
                />
                <el-table-column
                    label="产品大类"
                    prop="productName"
                    show-overflow-tooltip
                />
                <el-table-column
                    label="规格型号"
                    prop="model"
                    show-overflow-tooltip
                />
                <el-table-column
                    label="批号"
                    prop="batchNo"
                    show-overflow-tooltip
                />
                <el-table-column
                    label="单位"
                    prop="unit"
                    show-overflow-tooltip
                />
                <el-table-column
                    label="出库数量"
                    prop="stockOutNum"
                    show-overflow-tooltip
                />
                <el-table-column
                    label="出库人"
                    prop="createBy"
                    show-overflow-tooltip
                />
        <el-table-column label="来源"
                         prop="recordType"
                         show-overflow-tooltip>
        <span class="search_title ml10">来源:</span>
        <el-select
          v-model="searchForm.recordType"
          style="width: 240px"
          placeholder="请选择"
          clearable
        >
          <el-option
            v-for="item in stockRecordTypeOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
          >搜索</el-button
        >
      </div>
      <div>
        <el-button type="primary" @click="handleBatchApprove">审批</el-button>
        <el-button @click="handleOut">导出</el-button>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
        <el-button type="primary" plain @click="handlePrint">打印</el-button>
      </div>
    </div>
    <div class="table_list">
      <el-table
        :data="tableData"
        border
        v-loading="tableLoading"
        @selection-change="handleSelectionChange"
        :expand-row-keys="expandedRowKeys"
        :row-key="(row) => row.id"
        style="width: 100%"
        height="calc(100vh - 18.5em)"
      >
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column
          label="出库批次"
          prop="outboundBatches"
          min-width="100"
          show-overflow-tooltip
        />
        <el-table-column
          label="出库日期"
          prop="createTime"
          show-overflow-tooltip
        />
        <el-table-column
          label="产品大类"
          prop="productName"
          show-overflow-tooltip
        />
        <el-table-column label="规格型号" prop="model" show-overflow-tooltip />
        <el-table-column label="批号" prop="batchNo" show-overflow-tooltip />
        <el-table-column label="单位" prop="unit" show-overflow-tooltip />
        <el-table-column
          label="出库数量"
          prop="stockOutNum"
          show-overflow-tooltip
        />
        <el-table-column label="出库人" prop="createBy" show-overflow-tooltip />
        <el-table-column label="来源" prop="recordType" show-overflow-tooltip>
          <template #default="scope">
            {{ getRecordType(scope.row.recordType) }}
          </template>
        </el-table-column>
                <el-table-column label="审批状态" prop="approvalStatus" show-overflow-tooltip>
                    <template #default="scope">
                        <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)" size="small">
                            {{ getApprovalStatusLabel(scope.row.approvalStatus) }}
                        </el-tag>
                    </template>
                </el-table-column>
            </el-table>
            <pagination
                v-show="total > 0"
                :total="total"
                layout="total, sizes, prev, pager, next, jumper"
                :page="page.current"
                :limit="page.size"
                @pagination="paginationChange"
            />
        </div>
    </div>
        <el-table-column
          label="审批状态"
          prop="approvalStatus"
          show-overflow-tooltip
        >
          <template #default="scope">
            <el-tag
              :type="getApprovalStatusTagType(scope.row.approvalStatus)"
              size="small"
            >
              {{ getApprovalStatusLabel(scope.row.approvalStatus) }}
            </el-tag>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="total > 0"
        :total="total"
        layout="total, sizes, prev, pager, next, jumper"
        :page="page.current"
        :limit="page.size"
        @pagination="paginationChange"
      />
    </div>
  </div>
</template>
<script setup>
@@ -121,12 +114,13 @@
import useUserStore from "@/store/modules/user";
import { getCurrentDate } from "@/utils/index.js";
import {
    getStockOutPage,
    delPendingStockOut,
    batchApproveStockOutRecords,
  getStockOutPage,
  delPendingStockOut,
  batchApproveStockOutRecords,
} from "@/api/inventoryManagement/stockOut.js";
import {
  findAllQualifiedStockOutRecordTypeOptions, findAllUnQualifiedStockOutRecordTypeOptions,
  findAllQualifiedStockOutRecordTypeOptions,
  findAllUnQualifiedStockOutRecordTypeOptions,
} from "@/api/basicData/enum.js";
const userStore = useUserStore();
@@ -137,8 +131,8 @@
// 来源类型选项
const stockRecordTypeOptions = ref([]);
const page = reactive({
    current: 1,
    size: 100,
  current: 1,
  size: 100,
});
const total = ref(0);
@@ -146,13 +140,13 @@
  type: {
    type: String,
    required: true,
    default: '0'
    default: "0",
  },
  topParentProductId: {
    type: [String, Number],
    default: undefined
  }
})
    default: undefined,
  },
});
// 打印相关
const printPreviewVisible = ref(false);
@@ -160,193 +154,215 @@
// 用户信息表单弹框数据
const data = reactive({
    searchForm: {
        supplierName: "",
        timeStr: "",
  searchForm: {
    supplierName: "",
    timeStr: "",
    recordType: "",
    }
  },
});
const { searchForm } = toRefs(data);
// 查询列表
/** 搜索按钮操作 */
const handleQuery = () => {
    page.current = 1;
    getList();
  page.current = 1;
  getList();
};
const paginationChange = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  page.current = obj.page;
  page.size = obj.limit;
  getList();
};
const getList = () => {
    tableLoading.value = true;
    getStockOutPage({ ...searchForm.value, ...page,  topParentProductId: props.topParentProductId })
        .then((res) => {
            tableLoading.value = false;
            tableData.value = res.data.records;
            tableData.value.map((item) => {
                item.children = [];
            });
            total.value = res.data.total;
        })
        .catch(() => {
            tableLoading.value = false;
        });
  tableLoading.value = true;
  getStockOutPage({
    ...searchForm.value,
    ...page,
    topParentProductId: props.topParentProductId,
  })
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.data.records;
      tableData.value.map((item) => {
        item.children = [];
      });
      total.value = res.data.total;
    })
    .catch(() => {
      tableLoading.value = false;
    });
};
const getRecordType = (recordType) => {
  return stockRecordTypeOptions.value.find(item => item.value === recordType)?.label || ''
}
  return (
    stockRecordTypeOptions.value.find((item) => item.value === recordType)
      ?.label || ""
  );
};
const approvalStatusLabelMap = {
    0: "待审批",
    1: "通过",
    2: "驳回",
    pending: "待审批",
    approved: "通过",
    rejected: "驳回",
    PENDING: "待审批",
    APPROVED: "通过",
    REJECTED: "驳回",
  0: "待审批",
  1: "通过",
  2: "驳回",
  3: "待确认",
  pending: "待审批",
  approved: "通过",
  rejected: "驳回",
  PENDING: "待审批",
  APPROVED: "通过",
  REJECTED: "驳回",
};
const getApprovalStatusLabel = (status) => {
    if (status === null || status === undefined || status === "") {
        return "待审批";
    }
    return approvalStatusLabelMap[status] || "待审批";
  if (status === null || status === undefined || status === "") {
    return "待审批";
  }
  return approvalStatusLabelMap[status] || "待审批";
};
// 通过/驳回固定色;其余(含待审批、空值、未映射但文案为待审批)统一用 warning 预警色
const getApprovalStatusTagType = (status) => {
    if (status === 1 || status === "1" || status === "approved" || status === "APPROVED") return "success";
    if (status === 2 || status === "2" || status === "rejected" || status === "REJECTED") return "danger";
    return "warning";
  if (
    status === 1 ||
    status === "1" ||
    status === "approved" ||
    status === "APPROVED"
  )
    return "success";
  if (
    status === 2 ||
    status === "2" ||
    status === "rejected" ||
    status === "REJECTED"
  )
    return "danger";
  return "warning";
};
// 获取来源类型选项
const fetchStockRecordTypeOptions = () => {
  if (props.type === '0') {
    findAllQualifiedStockOutRecordTypeOptions()
        .then(res => {
          stockRecordTypeOptions.value = res.data;
        })
    return
  if (props.type === "0") {
    findAllQualifiedStockOutRecordTypeOptions().then((res) => {
      stockRecordTypeOptions.value = res.data;
    });
    return;
  }
  findAllUnQualifiedStockOutRecordTypeOptions()
      .then(res => {
        stockRecordTypeOptions.value = res.data;
      })
}
  findAllUnQualifiedStockOutRecordTypeOptions().then((res) => {
    stockRecordTypeOptions.value = res.data;
  });
};
// 表格选择数据
const handleSelectionChange = (selection) => {
    // 过滤掉子数据
    selectedRows.value = selection.filter((item) => item.id);
    console.log("selection", selectedRows.value);
  // 过滤掉子数据
  selectedRows.value = selection.filter((item) => item.id);
  console.log("selection", selectedRows.value);
};
const expandedRowKeys = ref([]);
const handleBatchApprove = () => {
    if (selectedRows.value.length === 0) {
        proxy.$modal.msgWarning("请选择数据");
        return;
    }
    const ids = selectedRows.value.map((item) => item.id);
    ElMessageBox.confirm("请选择审批结果", "审批", {
        confirmButtonText: "通过",
        cancelButtonText: "驳回",
        type: "warning",
        distinguishCancelAndClose: true,
    })
        .then(() => {
            batchApproveStockOutRecords({ ids, approvalStatus: 1 })
                .then(() => {
                    proxy.$modal.msgSuccess("审批通过成功");
                    getList();
                })
                .catch(() => {
                    proxy.$modal.msgError("审批通过失败");
                });
        })
        .catch((action) => {
            if (action === "cancel") {
                batchApproveStockOutRecords({ ids, approvalStatus: 2 })
                    .then(() => {
                        proxy.$modal.msgSuccess("审批驳回成功");
                        getList();
                    })
                    .catch(() => {
                        proxy.$modal.msgError("审批驳回失败");
                    });
                return;
            }
            proxy.$modal.msg("已取消");
        });
  if (selectedRows.value.length === 0) {
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  const ids = selectedRows.value.map((item) => item.id);
  ElMessageBox.confirm("请选择审批结果", "审批", {
    confirmButtonText: "通过",
    cancelButtonText: "驳回",
    type: "warning",
    distinguishCancelAndClose: true,
  })
    .then(() => {
      batchApproveStockOutRecords({ ids, approvalStatus: 1 })
        .then(() => {
          proxy.$modal.msgSuccess("审批通过成功");
          getList();
        })
        .catch(() => {
          proxy.$modal.msgError("审批通过失败");
        });
    })
    .catch((action) => {
      if (action === "cancel") {
        batchApproveStockOutRecords({ ids, approvalStatus: 2 })
          .then(() => {
            proxy.$modal.msgSuccess("审批驳回成功");
            getList();
          })
          .catch(() => {
            proxy.$modal.msgError("审批驳回失败");
          });
        return;
      }
      proxy.$modal.msg("已取消");
    });
};
// 导出
const handleOut = () => {
    ElMessageBox.confirm("是否确认导出?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            proxy.download("/stockOutRecord/exportStockOutRecord", {type: props.type}, props.type === '0' ? "合格出库台账.xlsx" : "不合格出库台账.xlsx");
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
  ElMessageBox.confirm("是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download(
        "/stockOutRecord/exportStockOutRecord",
        { type: props.type },
        props.type === "0" ? "合格出库台账.xlsx" : "不合格出库台账.xlsx"
      );
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// 删除
const handleDelete = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
        ids = selectedRows.value.map((item) => item.id);
    } else {
        proxy.$modal.msgWarning("请选择数据");
        return;
    }
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            delPendingStockOut(ids).then((res) => {
                proxy.$modal.msgSuccess("删除成功");
                getList();
            });
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
  let ids = [];
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      delPendingStockOut(ids).then((res) => {
        proxy.$modal.msgSuccess("删除成功");
        getList();
      });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// 打印功能
const handlePrint = () => {
    if (selectedRows.value.length === 0) {
        proxy.$modal.msgWarning("请选择要打印的数据");
        return;
    }
    printData.value = [...selectedRows.value];
    console.log('打印数据:', printData.value);
    printPreviewVisible.value = true;
  if (selectedRows.value.length === 0) {
    proxy.$modal.msgWarning("请选择要打印的数据");
    return;
  }
  printData.value = [...selectedRows.value];
  console.log("打印数据:", printData.value);
  printPreviewVisible.value = true;
};
// 执行打印
const executePrint = () => {
    console.log('开始执行打印,数据条数:', printData.value.length);
    console.log('打印数据:', printData.value);
    // 创建一个新的打印窗口
    const printWindow = window.open('', '_blank', 'width=800,height=600');
    // 构建打印内容
    let printContent = `
  console.log("开始执行打印,数据条数:", printData.value.length);
  console.log("打印数据:", printData.value);
  // 创建一个新的打印窗口
  const printWindow = window.open("", "_blank", "width=800,height=600");
  // 构建打印内容
  let printContent = `
    <!DOCTYPE html>
    <html>
    <head>
@@ -480,10 +496,10 @@
    </head>
    <body>
  `;
    // 为每条数据生成打印页面
    printData.value.forEach((item, index) => {
        printContent += `
  // 为每条数据生成打印页面
  printData.value.forEach((item, index) => {
    printContent += `
      <div class="print-page">
        <div class="delivery-note">
          <div class="header">
@@ -503,7 +519,7 @@
            </div>
            <div class="info-row">
              <span class="label">单号:</span>
              <span class="value">${item.code || ''}</span>
              <span class="value">${item.code || ""}</span>
            </div>
          </div>
@@ -521,12 +537,12 @@
              </thead>
              <tbody>
                <tr>
                  <td>${item.productName || '砂灰砖'}</td>
                  <td>${item.model || '标准'}</td>
                  <td>${item.unit || '块'}</td>
                  <td>${item.taxInclusiveUnitPrice || '0'}</td>
                  <td>${item.inboundNum || '2000'}</td>
                  <td>${item.taxInclusiveTotalPrice || '0'}</td>
                  <td>${item.productName || "砂灰砖"}</td>
                  <td>${item.model || "标准"}</td>
                  <td>${item.unit || "块"}</td>
                  <td>${item.taxInclusiveUnitPrice || "0"}</td>
                  <td>${item.inboundNum || "2000"}</td>
                  <td>${item.taxInclusiveTotalPrice || "0"}</td>
                </tr>
              </tbody>
              <tfoot>
@@ -535,8 +551,10 @@
                  <td class="total-value"></td>
                  <td class="total-value"></td>
                  <td class="total-value"></td>
                  <td class="total-value">${item.inboundNum || '2000'}</td>
                  <td class="total-value">${item.taxInclusiveTotalPrice || '0'}</td>
                  <td class="total-value">${item.inboundNum || "2000"}</td>
                  <td class="total-value">${
                    item.taxInclusiveTotalPrice || "0"
                  }</td>
                </tr>
              </tfoot>
            </table>
@@ -560,7 +578,7 @@
            <div class="footer-row">
              <div class="footer-item">
                <span class="label">操作员:</span>
                <span class="value">${userStore.nickName || '撕开前'}</span>
                <span class="value">${userStore.nickName || "撕开前"}</span>
              </div>
              <div class="footer-item">
                <span class="label">打印日期:</span>
@@ -571,51 +589,49 @@
        </div>
      </div>
    `;
    });
    printContent += `
  });
  printContent += `
    </body>
    </html>
  `;
    // 写入内容到新窗口
    printWindow.document.write(printContent);
    printWindow.document.close();
    // 等待内容加载完成后打印
    printWindow.onload = () => {
        setTimeout(() => {
            printWindow.print();
            printWindow.close();
            printPreviewVisible.value = false;
        }, 500);
    };
  // 写入内容到新窗口
  printWindow.document.write(printContent);
  printWindow.document.close();
  // 等待内容加载完成后打印
  printWindow.onload = () => {
    setTimeout(() => {
      printWindow.print();
      printWindow.close();
      printPreviewVisible.value = false;
    }, 500);
  };
};
// 格式化日期
const formatDate = (dateString) => {
    if (!dateString) return getCurrentDate();
    const date = new Date(dateString);
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    return `${year}/${month}/${day}`;
  if (!dateString) return getCurrentDate();
  const date = new Date(dateString);
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  return `${year}/${month}/${day}`;
};
// 格式化日期时间
const formatDateTime = (date) => {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    const hours = String(date.getHours()).padStart(2, "0");
    const minutes = String(date.getMinutes()).padStart(2, "0");
    const seconds = String(date.getSeconds()).padStart(2, "0");
    return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  const hours = String(date.getHours()).padStart(2, "0");
  const minutes = String(date.getMinutes()).padStart(2, "0");
  const seconds = String(date.getSeconds()).padStart(2, "0");
  return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
};
onMounted(() => {
    getList();
  getList();
  fetchStockRecordTypeOptions();
});
@@ -630,169 +646,170 @@
<style scoped lang="scss">
.print-preview-dialog {
    .el-dialog__body {
        padding: 0;
        max-height: 80vh;
        overflow-y: auto;
    }
  .el-dialog__body {
    padding: 0;
    max-height: 80vh;
    overflow-y: auto;
  }
}
.print-preview-container {
    .print-preview-header {
        padding: 15px;
        border-bottom: 1px solid #e4e7ed;
        text-align: center;
        .el-button {
            margin: 0 10px;
        }
    }
    .print-preview-content {
        padding: 20px;
        background-color: #f5f5f5;
        min-height: 400px;
    }
  .print-preview-header {
    padding: 15px;
    border-bottom: 1px solid #e4e7ed;
    text-align: center;
    .el-button {
      margin: 0 10px;
    }
  }
  .print-preview-content {
    padding: 20px;
    background-color: #f5f5f5;
    min-height: 400px;
  }
}
.print-page {
    width: 220mm;
    height: 90mm;
    padding: 10mm;
    margin: 0 auto;
    background: white;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    margin-bottom: 10px;
    box-sizing: border-box;
  width: 220mm;
  height: 90mm;
  padding: 10mm;
  margin: 0 auto;
  background: white;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  margin-bottom: 10px;
  box-sizing: border-box;
}
.delivery-note {
    width: 100%;
    height: 100%;
    font-family: "SimSun", serif;
    font-size: 10px;
    line-height: 1.2;
    display: flex;
    flex-direction: column;
  width: 100%;
  height: 100%;
  font-family: "SimSun", serif;
  font-size: 10px;
  line-height: 1.2;
  display: flex;
  flex-direction: column;
}
.header {
    text-align: center;
    margin-bottom: 8px;
    .company-name {
        font-size: 18px;
        font-weight: bold;
        margin-bottom: 4px;
    }
    .document-title {
        font-size: 16px;
        font-weight: bold;
    }
  text-align: center;
  margin-bottom: 8px;
  .company-name {
    font-size: 18px;
    font-weight: bold;
    margin-bottom: 4px;
  }
  .document-title {
    font-size: 16px;
    font-weight: bold;
  }
}
.info-section {
    margin-bottom: 8px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    .info-row {
        line-height: 20px;
        .label {
            font-weight: bold;
            width: 60px;
            font-size: 14px;
        }
        .value {
            margin-right: 20px;
            min-width: 80px;
            font-size: 14px;
        }
    }
  margin-bottom: 8px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  .info-row {
    line-height: 20px;
    .label {
      font-weight: bold;
      width: 60px;
      font-size: 14px;
    }
    .value {
      margin-right: 20px;
      min-width: 80px;
      font-size: 14px;
    }
  }
}
.table-section {
    margin-bottom: 4px;
    flex: 1;
    .product-table {
        width: 100%;
        border-collapse: collapse;
        border: 1px solid #000;
        th, td {
            border: 1px solid #000;
            padding: 6px;
            text-align: center;
            font-size: 14px;
            line-height: 1.4;
        }
        th {
            font-weight: bold;
        }
        .total-label {
            text-align: right;
            font-weight: bold;
        }
        .total-value {
            font-weight: bold;
        }
    }
  margin-bottom: 4px;
  flex: 1;
  .product-table {
    width: 100%;
    border-collapse: collapse;
    border: 1px solid #000;
    th,
    td {
      border: 1px solid #000;
      padding: 6px;
      text-align: center;
      font-size: 14px;
      line-height: 1.4;
    }
    th {
      font-weight: bold;
    }
    .total-label {
      text-align: right;
      font-weight: bold;
    }
    .total-value {
      font-weight: bold;
    }
  }
}
.footer-section {
    .footer-row {
        display: flex;
        margin-bottom: 3px;
        line-height: 20px;
        justify-content: space-between;
        .footer-item {
            display: flex;
            margin-right: 20px;
            .label {
                font-weight: bold;
                width: 80px;
                font-size: 14px;
            }
            .value {
                min-width: 80px;
                font-size: 14px;
            }
            &.address-item {
                .address-value {
                    min-width: 200px;
                }
            }
        }
    }
  .footer-row {
    display: flex;
    margin-bottom: 3px;
    line-height: 20px;
    justify-content: space-between;
    .footer-item {
      display: flex;
      margin-right: 20px;
      .label {
        font-weight: bold;
        width: 80px;
        font-size: 14px;
      }
      .value {
        min-width: 80px;
        font-size: 14px;
      }
      &.address-item {
        .address-value {
          min-width: 200px;
        }
      }
    }
  }
}
@media print {
    .app-container {
        display: none;
    }
    .print-page {
        box-shadow: none;
        margin: 0;
        padding: 10mm;
        padding-left: 20mm;
        page-break-inside: avoid;
        page-break-after: always;
    }
    .print-page:last-child {
        page-break-after: avoid;
    }
  .app-container {
    display: none;
  }
  .print-page {
    box-shadow: none;
    margin: 0;
    padding: 10mm;
    padding-left: 20mm;
    page-break-inside: avoid;
    page-break-after: always;
  }
  .print-page:last-child {
    page-break-after: avoid;
  }
}
</style>
src/views/inventoryManagement/receiptManagement/Record.vue
@@ -50,6 +50,7 @@
                height="calc(100vh - 18.5em)">
        <el-table-column align="center"
                         type="selection"
                         :selectable="isRowSelectableForApprove"
                         width="55"/>
        <el-table-column align="center"
                         label="序号"
@@ -181,6 +182,7 @@
  APPROVED: "通过",
  REJECTED: "驳回",
};
approvalStatusLabelMap[3] = "待确认";
const getApprovalStatusLabel = (status) => {
  if (status === null || status === undefined || status === "") {
@@ -194,6 +196,14 @@
  if (status === 1 || status === "1" || status === "approved" || status === "APPROVED") return "success";
  if (status === 2 || status === "2" || status === "rejected" || status === "REJECTED") return "danger";
  return "warning";
};
const isPendingApproval = status => {
  return status === 0 || status === "0" || status === "pending" || status === "PENDING" || status === null || status === undefined || status === "";
};
const isRowSelectableForApprove = row => {
  return isPendingApproval(row?.approvalStatus);
};
const pageProductChange = obj => {
@@ -234,7 +244,7 @@
// 表格选择数据
const handleSelectionChange = selection => {
  selectedRows.value = selection.filter(item => item.id);
  selectedRows.value = selection.filter(item => item.id && isPendingApproval(item.approvalStatus));
};
const expandedRowKeys = ref([]);
src/views/salesManagement/deliveryLedger/index.vue
@@ -3,19 +3,34 @@
    <div class="search_form">
      <el-form :model="searchForm" :inline="true">
        <el-form-item label="销售订单号:">
          <el-input v-model="searchForm.salesContractNo" placeholder="请输入" clearable prefix-icon="Search"
                    style="width: 200px"
                    @change="handleQuery"/>
          <el-input
            v-model="searchForm.salesContractNo"
            placeholder="请输入"
            clearable
            prefix-icon="Search"
            style="width: 200px"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="车牌号:">
          <el-input v-model="searchForm.shippingCarNumber" placeholder="请输入" clearable prefix-icon="Search"
                    style="width: 200px"
                    @change="handleQuery"/>
          <el-input
            v-model="searchForm.shippingCarNumber"
            placeholder="请输入"
            clearable
            prefix-icon="Search"
            style="width: 200px"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="快递单号:">
          <el-input v-model="searchForm.expressNumber" placeholder="请输入" clearable prefix-icon="Search"
                    style="width: 200px"
                    @change="handleQuery"/>
          <el-input
            v-model="searchForm.expressNumber"
            placeholder="请输入"
            clearable
            prefix-icon="Search"
            style="width: 200px"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleQuery"> 搜索</el-button>
@@ -30,20 +45,68 @@
          <el-button type="danger" plain @click="handleDelete">删除</el-button>
        </div>
      </div>
      <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
                :row-key="(row) => row.id" style="width: 100%" height="calc(100vh - 21.5em)">
        <el-table-column align="center" type="selection" width="55"/>
        <el-table-column align="center" label="序号" type="index" width="60"/>
        <el-table-column label="销售订单" prop="salesContractNo" show-overflow-tooltip/>
        <el-table-column label="发货订单号" prop="shippingNo" show-overflow-tooltip/>
        <el-table-column label="客户名称" prop="customerName" show-overflow-tooltip/>
        <el-table-column label="产品名称" prop="productName" show-overflow-tooltip/>
        <el-table-column label="规格型号" prop="specificationModel" show-overflow-tooltip/>
        <el-table-column label="发货时间" prop="shippingDate" show-overflow-tooltip/>
        <el-table-column label="发货车牌号" prop="shippingCarNumber" show-overflow-tooltip/>
        <el-table-column label="快递公司" prop="expressCompany" show-overflow-tooltip/>
        <el-table-column label="快递单号" prop="expressNumber" show-overflow-tooltip/>
        <el-table-column label="审核状态" prop="status" align="center" width="120">
      <el-table
        :data="tableData"
        border
        v-loading="tableLoading"
        @selection-change="handleSelectionChange"
        :row-key="(row) => row.id"
        style="width: 100%"
        height="calc(100vh - 21.5em)"
      >
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column
          label="销售订单"
          prop="salesContractNo"
          show-overflow-tooltip
        />
        <el-table-column
          label="发货订单号"
          prop="shippingNo"
          show-overflow-tooltip
        />
        <el-table-column
          label="客户名称"
          prop="customerName"
          show-overflow-tooltip
        />
        <el-table-column
          label="产品名称"
          prop="productName"
          show-overflow-tooltip
        />
        <el-table-column
          label="规格型号"
          prop="specificationModel"
          show-overflow-tooltip
        />
        <el-table-column
          label="发货时间"
          prop="shippingDate"
          show-overflow-tooltip
        />
        <el-table-column
          label="发货车牌号"
          prop="shippingCarNumber"
          show-overflow-tooltip
        />
        <el-table-column
          label="快递公司"
          prop="expressCompany"
          show-overflow-tooltip
        />
        <el-table-column
          label="快递单号"
          prop="expressNumber"
          show-overflow-tooltip
        />
        <el-table-column
          label="审核状态"
          prop="status"
          align="center"
          width="120"
        >
          <template #default="scope">
            <el-tag :type="getApprovalStatusType(scope.row.status)">
              {{ getApprovalStatusText(scope.row.status) }}
@@ -52,46 +115,62 @@
        </el-table-column>
        <el-table-column fixed="right" label="操作" width="220" align="center">
          <template #default="scope">
            <!--            <el-button-->
            <!--                link-->
            <!--                type="primary"-->
            <!--                :disabled="!isApproved(scope.row.status)"-->
            <!--                @click="openForm('edit', scope.row)">发货-->
            <!--            </el-button>-->
            <el-button
                link
                type="primary"
                :disabled="!isApproved(scope.row.status)"
                @click="openForm('edit', scope.row)">发货
              link
              type="primary"
              style="color: #67c23a"
              @click="openDetail(scope.row)"
              >详情
            </el-button>
            <el-button
                link
                type="primary"
                style="color: #67C23A"
                @click="openDetail(scope.row)"
            >详情
            </el-button>
            <el-button
                link
                type="danger"
                :disabled="isApproving(scope.row.status)"
                @click="handleDeleteSingle(scope.row)">删除
              link
              type="danger"
              :disabled="isApproving(scope.row.status)"
              @click="handleDeleteSingle(scope.row)"
              >删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper"
                  :page="page.current" :limit="page.size" @pagination="paginationChange"/>
      <pagination
        v-show="total > 0"
        :total="total"
        layout="total, sizes, prev, pager, next, jumper"
        :page="page.current"
        :limit="page.size"
        @pagination="paginationChange"
      />
    </div>
    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增发货台账' : '编辑发货台账'"
               width="40%"
               @close="closeDia">
      <el-form :model="form" label-width="120px" label-position="top" :rules="rules" ref="formRef">
    <el-dialog
      v-model="dialogFormVisible"
      :title="operationType === 'add' ? '新增发货台账' : '编辑发货台账'"
      width="40%"
      @close="closeDia"
    >
      <el-form
        :model="form"
        label-width="120px"
        label-position="top"
        :rules="rules"
        ref="formRef"
      >
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="发货类型:" prop="type">
              <el-select
                  v-model="form.type"
                  placeholder="请选择发货类型"
                  style="width: 100%"
                  @change="handleShippingTypeChange"
                v-model="form.type"
                placeholder="请选择发货类型"
                style="width: 100%"
                @change="handleShippingTypeChange"
              >
                <el-option label="货车" value="货车"/>
                <el-option label="快递" value="快递"/>
                <el-option label="货车" value="货车" />
                <el-option label="快递" value="快递" />
              </el-select>
            </el-form-item>
          </el-col>
@@ -100,13 +179,13 @@
          <el-col :span="24">
            <el-form-item label="发货日期:" prop="shippingDate">
              <el-date-picker
                  style="width: 100%"
                  v-model="form.shippingDate"
                  value-format="YYYY-MM-DD"
                  format="YYYY-MM-DD"
                  type="date"
                  placeholder="请选择发货日期"
                  clearable
                style="width: 100%"
                v-model="form.shippingDate"
                value-format="YYYY-MM-DD"
                format="YYYY-MM-DD"
                type="date"
                placeholder="请选择发货日期"
                clearable
              />
            </el-form-item>
          </el-col>
@@ -115,18 +194,18 @@
          <el-col :span="24" v-if="form.type === '货车'">
            <el-form-item label="发货车牌号:" prop="shippingCarNumber">
              <el-input
                  v-model="form.shippingCarNumber"
                  placeholder="请输入发货车牌号"
                  clearable
                v-model="form.shippingCarNumber"
                placeholder="请输入发货车牌号"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="24" v-else>
            <el-form-item label="快递公司:" prop="expressCompany">
              <el-input
                  v-model="form.expressCompany"
                  placeholder="请输入快递公司"
                  clearable
                v-model="form.expressCompany"
                placeholder="请输入快递公司"
                clearable
              />
            </el-form-item>
          </el-col>
@@ -135,9 +214,9 @@
          <el-col :span="24">
            <el-form-item label="快递单号:" prop="expressNumber">
              <el-input
                  v-model="form.expressNumber"
                  placeholder="请输入快递单号"
                  clearable
                v-model="form.expressNumber"
                placeholder="请输入快递单号"
                clearable
              />
            </el-form-item>
          </el-col>
@@ -145,7 +224,7 @@
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="发货图片:">
              <ImageUpload v-model:file-list="deliveryFileList" :limit="9"/>
              <ImageUpload v-model:file-list="deliveryFileList" :limit="9" />
            </el-form-item>
          </el-col>
        </el-row>
@@ -159,42 +238,79 @@
    </el-dialog>
    <!-- 详情弹框 -->
    <el-dialog v-model="detailDialogVisible" title="发货台账详情" width="55%" @close="closeDetail">
    <el-dialog
      v-model="detailDialogVisible"
      title="发货台账详情"
      width="55%"
      @close="closeDetail"
    >
      <div v-if="detailRow" class="detail-wrapper">
        <el-descriptions :column="2" border>
          <el-descriptions-item label="销售订单">{{ detailRow.salesContractNo || '--' }}</el-descriptions-item>
          <el-descriptions-item label="发货订单号">{{ detailRow.shippingNo || '--' }}</el-descriptions-item>
          <el-descriptions-item label="客户名称">{{ detailRow.customerName || '--' }}</el-descriptions-item>
          <el-descriptions-item label="产品名称">{{ detailRow.productName || '--' }}</el-descriptions-item>
          <el-descriptions-item label="规格型号">{{ detailRow.specificationModel || '--' }}</el-descriptions-item>
          <el-descriptions-item label="发货类型">{{ detailRow.type || '--' }}</el-descriptions-item>
          <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>
          <el-descriptions-item label="快递公司">{{ detailRow.expressCompany || '--' }}</el-descriptions-item>
          <el-descriptions-item label="快递单号" :span="2">{{ detailRow.expressNumber || '--' }}</el-descriptions-item>
          <el-descriptions-item label="销售订单">{{
            detailRow.salesContractNo || "--"
          }}</el-descriptions-item>
          <el-descriptions-item label="发货订单号">{{
            detailRow.shippingNo || "--"
          }}</el-descriptions-item>
          <el-descriptions-item label="客户名称">{{
            detailRow.customerName || "--"
          }}</el-descriptions-item>
          <el-descriptions-item label="产品名称">{{
            detailRow.productName || "--"
          }}</el-descriptions-item>
          <el-descriptions-item label="规格型号">{{
            detailRow.specificationModel || "--"
          }}</el-descriptions-item>
          <el-descriptions-item label="发货类型">{{
            detailRow.type || "--"
          }}</el-descriptions-item>
          <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>
          <el-descriptions-item label="快递公司">{{
            detailRow.expressCompany || "--"
          }}</el-descriptions-item>
          <el-descriptions-item label="快递单号" :span="2">{{
            detailRow.expressNumber || "--"
          }}</el-descriptions-item>
        </el-descriptions>
        <el-table :data="getDeliveryProductInfoList()"
                  border
                  size="small"
                  class="delivery-product-table"
                  style="width: 100%; margin-top: 16px;">
          <el-table-column label="批号"
                           prop="batchNo"
                           min-width="160"
                           show-overflow-tooltip/>
          <el-table-column label="产品名称"
                           prop="productName"
                           min-width="160"
                           show-overflow-tooltip/>
          <el-table-column label="规格型号"
                           prop="specificationModel"
                           min-width="160"
                           show-overflow-tooltip/>
          <el-table-column label="发货数量"
                           prop="deliveryQuantity"
                           min-width="120"
                           align="center"/>
        <el-table
          :data="getDeliveryProductInfoList()"
          border
          size="small"
          class="delivery-product-table"
          style="width: 100%; margin-top: 16px"
        >
          <el-table-column
            label="批号"
            prop="batchNo"
            min-width="160"
            show-overflow-tooltip
          />
          <el-table-column
            label="产品名称"
            prop="productName"
            min-width="160"
            show-overflow-tooltip
          />
          <el-table-column
            label="规格型号"
            prop="specificationModel"
            min-width="160"
            show-overflow-tooltip
          />
          <el-table-column
            label="发货数量"
            prop="deliveryQuantity"
            min-width="120"
            align="center"
          />
        </el-table>
        <ImagePreview :file-list="detailRow.storageBlobVOs || []" />
      </div>
@@ -209,21 +325,20 @@
<script setup>
import pagination from "@/components/PIMTable/Pagination.vue";
import {onMounted, ref, reactive, toRefs, getCurrentInstance} from "vue";
import {ElMessageBox} from "element-plus";
import {getCurrentDate} from "@/utils/index.js";
import { onMounted, ref, reactive, toRefs, getCurrentInstance } from "vue";
import { ElMessageBox } from "element-plus";
import { getCurrentDate } from "@/utils/index.js";
import {
  deliveryLedgerListPage,
  delDeliveryLedger,
  deductStock,
  getDeliveryDetail,
} from "@/api/salesManagement/deliveryLedger.js";
import {delLedgerFile} from "@/api/salesManagement/salesLedger.js";
import { delLedgerFile } from "@/api/salesManagement/salesLedger.js";
import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
import ImagePreview from "@/components/AttachmentPreview/image/index.vue";
const {proxy} = getCurrentInstance();
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const selectedRows = ref([]);
const tableLoading = ref(false);
@@ -261,23 +376,34 @@
    expressNumber: "", // 快递单号
  },
  rules: {
    salesContractNo: [{required: true, message: "请选择销售订单", trigger: "change"}],
    customerName: [{required: true, message: "请输入客户名称", trigger: "blur"}],
    type: [
      {required: true, message: "请选择发货类型", trigger: "change"}
    salesContractNo: [
      { required: true, message: "请选择销售订单", trigger: "change" },
    ],
    shippingDate: [{required: true, message: "请选择发货时间", trigger: "change"}],
    customerName: [
      { required: true, message: "请输入客户名称", trigger: "blur" },
    ],
    type: [{ required: true, message: "请选择发货类型", trigger: "change" }],
    shippingDate: [
      { required: true, message: "请选择发货时间", trigger: "change" },
    ],
    shippingCarNumber: [
      {validator: (_, value, callback) => validateShippingCarNumber(value, callback), trigger: "blur"}
      {
        validator: (_, value, callback) =>
          validateShippingCarNumber(value, callback),
        trigger: "blur",
      },
    ],
    expressCompany: [
      {validator: (_, value, callback) => validateExpressCompany(value, callback), trigger: "blur"}
      {
        validator: (_, value, callback) =>
          validateExpressCompany(value, callback),
        trigger: "blur",
      },
    ],
  },
});
const {form, rules} = toRefs(data);
const {searchForm} = toRefs(data);
const { form, rules } = toRefs(data);
const { searchForm } = toRefs(data);
// 查询列表
const handleQuery = () => {
@@ -293,20 +419,22 @@
const getList = () => {
  tableLoading.value = true;
  deliveryLedgerListPage({...searchForm.value, ...page})
      .then((res) => {
        tableLoading.value = false;
        tableData.value = res.data.records || [];
        total.value = res.data.total || 0;
      })
      .catch(() => {
        tableLoading.value = false;
      });
  deliveryLedgerListPage({ ...searchForm.value, ...page })
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.data.records || [];
      total.value = res.data.total || 0;
    })
    .catch(() => {
      tableLoading.value = false;
    });
};
// 销售订单变化时自动填充客户名称
const handleSalesOrderChange = (value) => {
  const selectedOrder = salesOrderOptions.value.find(item => item.salesContractNo === value);
  const selectedOrder = salesOrderOptions.value.find(
    (item) => item.salesContractNo === value
  );
  if (selectedOrder) {
    form.value.customerName = selectedOrder.customerName;
  }
@@ -320,14 +448,14 @@
// 打开弹框
const openForm = async (type, row) => {
  // 发货:仅“审核通过”允许编辑
  if (type === 'edit' && row && !isApproved(row.status)) {
  if (type === "edit" && row && !isApproved(row.status)) {
    proxy.$modal.msgWarning("只有审核通过的数据才可以发货");
    return;
  }
  operationType.value = type;
  if (type === 'edit' && row) {
  if (type === "edit" && row) {
    form.value = {
      id: row.id ?? null,
      salesContractNo: row.salesContractNo ?? "",
@@ -362,62 +490,69 @@
    proxy.$modal.msgError("加载发货台账详情失败");
  }
};
const resolveDeliveryDetailList = data => {
const resolveDeliveryDetailList = (data) => {
  if (Array.isArray(data)) return data;
  if (!data || typeof data !== "object") return [];
  return [
    data.batchNoDetailList,
    data.batchNoList,
    data.shippingBatchList,
    data.shippingInfoDetailList,
    data.detailList,
    data.batchDetailList,
    data.rows,
    data.records,
    data.list,
    data.data,
  ].find(value => Array.isArray(value) && value.length) || [];
  return (
    [
      data.batchNoDetailList,
      data.batchNoList,
      data.shippingBatchList,
      data.shippingInfoDetailList,
      data.detailList,
      data.batchDetailList,
      data.rows,
      data.records,
      data.list,
      data.data,
    ].find((value) => Array.isArray(value) && value.length) || []
  );
};
const getDeliveryProductInfoList = () => {
  const row = detailRow.value;
  if (!row) return [];
  const normalizeBatchNoList = value => {
  const normalizeBatchNoList = (value) => {
    if (Array.isArray(value)) return value;
    if (typeof value === "string" && value.includes(",")) {
      return value.split(",").map(item => item.trim()).filter(Boolean);
      return value
        .split(",")
        .map((item) => item.trim())
        .filter(Boolean);
    }
    return value ? [value] : [];
  };
  const detailList = detailProductList.value.length ? detailProductList.value : [
    row.batchNoDetailList,
    row.batchNoList,
    row.shippingBatchList,
    row.shippingInfoDetailList,
    row.detailList,
    row.batchDetailList,
  ].find(value => Array.isArray(value) && value.length);
  const detailList = detailProductList.value.length
    ? detailProductList.value
    : [
        row.batchNoDetailList,
        row.batchNoList,
        row.shippingBatchList,
        row.shippingInfoDetailList,
        row.detailList,
        row.batchDetailList,
      ].find((value) => Array.isArray(value) && value.length);
  const batchNoList = normalizeBatchNoList(row.batchNo);
  const toTableRow = (item = {}) => ({
    batchNo:
        typeof item === "string" || typeof item === "number"
            ? item
            : item.batchNo ?? item.batchNumber ?? row.batchNo ?? "--",
      typeof item === "string" || typeof item === "number"
        ? item
        : item.batchNo ?? item.batchNumber ?? row.batchNo ?? "--",
    productName: item.productName ?? row.productName ?? "--",
    specificationModel:
        item.specificationModel ?? item.model ?? row.specificationModel ?? "--",
      item.specificationModel ?? item.model ?? row.specificationModel ?? "--",
    deliveryQuantity:
        item.deliveryQuantity ??
        item.quantity ??
        item.shippingQuantity ??
        row.deliveryQuantity ??
        row.quantity ??
        "--",
      item.deliveryQuantity ??
      item.quantity ??
      item.shippingQuantity ??
      row.deliveryQuantity ??
      row.quantity ??
      "--",
  });
  if (detailList?.length) {
    return detailList.map(toTableRow);
  }
  if (batchNoList.length) {
    return batchNoList.map(batchNo => toTableRow({batchNo}));
    return batchNoList.map((batchNo) => toTableRow({ batchNo }));
  }
  return [toTableRow()];
};
@@ -435,9 +570,12 @@
        id: form.value.id,
        type: form.value.type,
        shippingDate: form.value.shippingDate,
        shippingCarNumber: form.value.type === "货车" ? form.value.shippingCarNumber : "",
        expressCompany: form.value.type === "快递" ? form.value.expressCompany : "",
        expressNumber: form.value.type === "快递" ? form.value.expressNumber : "",
        shippingCarNumber:
          form.value.type === "货车" ? form.value.shippingCarNumber : "",
        expressCompany:
          form.value.type === "快递" ? form.value.expressCompany : "",
        expressNumber:
          form.value.type === "快递" ? form.value.expressNumber : "",
        storageBlobDTOs: deliveryFileList.value || [],
      };
      deductStock(payload).then((res) => {
@@ -463,12 +601,12 @@
    cancelButtonText: "取消",
    type: "warning",
  })
      .then(() => {
        proxy.download("/shippingInfo/export", {}, "发货台账.xlsx");
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
    .then(() => {
      proxy.download("/shippingInfo/export", {}, "发货台账.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// 批量删除
@@ -479,7 +617,9 @@
  }
  // 检查选中的行是否有"审核中"状态
  const approvingRows = selectedRows.value.filter(row => isApproving(row.status));
  const approvingRows = selectedRows.value.filter((row) =>
    isApproving(row.status)
  );
  if (approvingRows.length > 0) {
    proxy.$modal.msgWarning("审核中的数据不能删除");
    return;
@@ -491,15 +631,15 @@
    cancelButtonText: "取消",
    type: "warning",
  })
      .then(() => {
        delDeliveryLedger(ids).then((res) => {
          proxy.$modal.msgSuccess("删除成功");
          getList();
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
    .then(() => {
      delDeliveryLedger(ids).then((res) => {
        proxy.$modal.msgSuccess("删除成功");
        getList();
      });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// 单个删除
@@ -515,15 +655,15 @@
    cancelButtonText: "取消",
    type: "warning",
  })
      .then(() => {
        delDeliveryLedger([row.id]).then((res) => {
          proxy.$modal.msgSuccess("删除成功");
          getList();
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
    .then(() => {
      delDeliveryLedger([row.id]).then((res) => {
        proxy.$modal.msgSuccess("删除成功");
        getList();
      });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// 发货类型校验:货车时要求车牌,快递时要求快递公司
@@ -543,7 +683,10 @@
// 发货图片上传前校检
function handleDeliveryBeforeUpload(file) {
  // 校检文件类型
  const isImage = file.type === 'image/png' || file.type === 'image/jpeg' || file.type === 'image/jpg';
  const isImage =
    file.type === "image/png" ||
    file.type === "image/jpeg" ||
    file.type === "image/jpg";
  if (!isImage) {
    proxy.$modal.msgError("只能上传 jpg、jpeg、png 格式的图片!");
    return false;
@@ -578,24 +721,30 @@
// 移除发货图片
function handleDeliveryRemove(file) {
  console.log('file--', file)
  console.log("file--", file);
  // 如果是编辑模式且文件有 id,需要调用接口删除
  if (operationType.value === "edit") {
    let ids = [];
    ids.push(file.uid);
    delLedgerFile(ids).then((res) => {
      proxy.$modal.msgSuccess("删除成功");
      // 从文件列表中移除
      const index = deliveryFileList.value.findIndex(item => item.uid === file.uid);
      if (index > -1) {
        deliveryFileList.value.splice(index, 1);
      }
    }).catch(() => {
      proxy.$modal.msgError("删除失败");
    });
    delLedgerFile(ids)
      .then((res) => {
        proxy.$modal.msgSuccess("删除成功");
        // 从文件列表中移除
        const index = deliveryFileList.value.findIndex(
          (item) => item.uid === file.uid
        );
        if (index > -1) {
          deliveryFileList.value.splice(index, 1);
        }
      })
      .catch(() => {
        proxy.$modal.msgError("删除失败");
      });
  } else {
    // 新增模式或没有 id 的文件,直接从列表中移除
    const index = deliveryFileList.value.findIndex(item => item.uid === file.uid);
    const index = deliveryFileList.value.findIndex(
      (item) => item.uid === file.uid
    );
    if (index > -1) {
      deliveryFileList.value.splice(index, 1);
    }
@@ -614,92 +763,92 @@
// 获取审核状态文本
const getApprovalStatusText = (status) => {
  if (status === null || status === undefined || status === '') {
    return '待审核';
  if (status === null || status === undefined || status === "") {
    return "待审核";
  }
  // 如果是数字
  if (typeof status === 'number') {
  if (typeof status === "number") {
    const statusMap = {
      0: '待审核',
      1: '审核中',
      2: '审核拒绝',
      3: '审核通过'
      0: "待审核",
      1: "审核中",
      2: "审核拒绝",
      3: "审核通过",
    };
    return statusMap[status] || '待审核';
    return statusMap[status] || "待审核";
  }
  // 如果是字符串,直接返回或映射
  const statusStr = String(status).trim();
  const statusTextMap = {
    '待审核': '待审核',
    '审核中': '审核中',
    '审核拒绝': '审核拒绝',
    '审核通过': '审核通过',
    '已发货': '已发货',
    '0': '待审核',
    '1': '审核中',
    '2': '审核拒绝',
    '3': '审核通过'
    待审核: "待审核",
    审核中: "审核中",
    审核拒绝: "审核拒绝",
    审核通过: "审核通过",
    已发货: "已发货",
    0: "待审核",
    1: "审核中",
    2: "审核拒绝",
    3: "审核通过",
  };
  return statusTextMap[statusStr] || statusStr || '待审核';
  return statusTextMap[statusStr] || statusStr || "待审核";
};
// 获取审核状态标签类型(颜色)
const getApprovalStatusType = (status) => {
  if (status === null || status === undefined || status === '') {
    return 'info';
  if (status === null || status === undefined || status === "") {
    return "info";
  }
  // 如果是数字
  if (typeof status === 'number') {
  if (typeof status === "number") {
    const typeMap = {
      0: 'info',      // 待审核 - 灰色
      1: 'warning',   // 审核中 - 黄色
      2: 'danger',    // 审核拒绝 - 红色
      3: 'success'    // 审核通过 - 绿色
      0: "info", // 待审核 - 灰色
      1: "warning", // 审核中 - 黄色
      2: "danger", // 审核拒绝 - 红色
      3: "success", // 审核通过 - 绿色
    };
    return typeMap[status] || 'info';
    return typeMap[status] || "info";
  }
  // 如果是字符串
  const statusStr = String(status).trim();
  const typeTextMap = {
    '待审核': 'info',
    '审核中': 'warning',
    '审核拒绝': 'danger',
    '审核通过': 'success',
    '已发货': 'success',
    '0': 'info',
    '1': 'warning',
    '2': 'danger',
    '3': 'success'
    待审核: "info",
    审核中: "warning",
    审核拒绝: "danger",
    审核通过: "success",
    已发货: "success",
    0: "info",
    1: "warning",
    2: "danger",
    3: "success",
  };
  return typeTextMap[statusStr] || 'info';
  return typeTextMap[statusStr] || "info";
};
// 检查审核状态是否为"审核通过"
const isApproved = (status) => {
  if (status === null || status === undefined || status === '') {
  if (status === null || status === undefined || status === "") {
    return false;
  }
  // 如果是数字,3 表示审核通过
  if (typeof status === 'number') {
  if (typeof status === "number") {
    return status === 3;
  }
  // 如果是字符串
  const statusStr = String(status).trim();
  return statusStr === '审核通过' || statusStr === '3';
  return statusStr === "审核通过" || statusStr === "3";
};
// 检查审核状态是否为"审核中"
const isApproving = (status) => {
  if (status === null || status === undefined || status === '') {
  if (status === null || status === undefined || status === "") {
    return false;
  }
  // 如果是数字,1 表示审核中
  if (typeof status === 'number') {
  if (typeof status === "number") {
    return status === 1;
  }
  // 如果是字符串
  const statusStr = String(status).trim();
  return statusStr === '审核中' || statusStr === '1';
  return statusStr === "审核中" || statusStr === "1";
};
onMounted(() => {
@@ -752,4 +901,3 @@
  color: #909399;
}
</style>
src/views/salesManagement/returnOrder/components/formDia.vue
@@ -170,7 +170,7 @@
import { returnManagementAdd, returnManagementUpdate, returnManagementGetByShippingId, getSalesLedger, returnManagementGetById } from "@/api/salesManagement/returnOrder.js";
import useUserStore from "@/store/modules/user.js";
import { userListNoPageByTenantId } from "@/api/system/user.js";
import { listProject } from "@/api/oaSystem/projectManagement.js";
import { listProject } from "@/api/projectManagement/project.js";
import {listCustomer} from "@/api/basicData/customer.js";
const { proxy } = getCurrentInstance();
src/views/salesManagement/salesLedger/index.vue
@@ -898,7 +898,8 @@
                          prop="type">
              <el-select v-model="deliveryForm.type"
                         placeholder="请选择发货类型"
                         style="width: 100%">
                         style="width: 100%"
                         @change="handleDeliveryTypeChange">
                <el-option label="货车"
                           value="货车" />
                <el-option label="快递"
@@ -910,6 +911,41 @@
            <el-form-item label="待发货数量:">
              <el-input :model-value="currentDeliveryRow?.noQuantity"
                        disabled />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24" v-if="deliveryForm.type === '货车'">
            <el-form-item label="发货车牌号:"
                          prop="shippingCarNumber">
              <el-input v-model="deliveryForm.shippingCarNumber"
                        placeholder="请输入发货车牌号"
                        clearable />
            </el-form-item>
          </el-col>
          <el-col :span="24" v-else>
            <el-form-item label="快递公司:"
                          prop="expressCompany">
              <el-input v-model="deliveryForm.expressCompany"
                        placeholder="请输入快递公司"
                        clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30" v-if="deliveryForm.type === '快递'">
          <el-col :span="24">
            <el-form-item label="快递单号:"
                          prop="expressNumber">
              <el-input v-model="deliveryForm.expressNumber"
                        placeholder="请输入快递单号"
                        clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="发货图片:">
              <ImageUpload v-model:file-list="deliveryFileList" :limit="9" />
            </el-form-item>
          </el-col>
        </el-row>
@@ -990,6 +1026,7 @@
  import useFormData from "@/hooks/useFormData.js";
  import dayjs from "dayjs";
  import FileUpload from "@/components/AttachmentUpload/file/index.vue";
  import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
  import { getCurrentDate } from "@/utils/index.js";
  import { listCustomer } from "@/api/basicData/customer.js";
@@ -1017,6 +1054,7 @@
  });
  const total = ref(0);
  const fileList = ref([]);
  const deliveryFileList = ref([]);
  // 用户信息表单弹框数据
  const operationType = ref("");
@@ -1195,11 +1233,30 @@
        deliveryQuantity: 0,
      }));
  };
  const validateDeliveryShippingCarNumber = (_rule, value, callback) => {
    if (deliveryForm.value.type === "货车" && !value) {
      return callback(new Error("请输入发货车牌号"));
    }
    callback();
  };
  const validateDeliveryExpressCompany = (_rule, value, callback) => {
    if (deliveryForm.value.type === "快递" && !value) {
      return callback(new Error("请输入快递公司"));
    }
    callback();
  };
  const deliveryFormData = reactive({
    deliveryForm: {
      shippingCarNumber: "",
      expressCompany: "",
      expressNumber: "",
      type: "货车", // 货车, 快递
    },
    deliveryRules: {
      shippingCarNumber: [
        { validator: validateDeliveryShippingCarNumber, trigger: "blur" },
      ],
      expressCompany: [{ validator: validateDeliveryExpressCompany, trigger: "blur" }],
      type: [{ required: true, message: "请选择发货类型", trigger: "change" }],
    },
  });
@@ -2621,10 +2678,14 @@
      row.productModelId || row.modelId
    );
    deliveryForm.value = {
      shippingCarNumber: "",
      expressCompany: "",
      expressNumber: "",
      type: "货车",
      batchNo: [],
      batchNoList,
    };
    deliveryFileList.value = [];
    deliveryFormVisible.value = true;
  };
@@ -2662,6 +2723,19 @@
          salesLedgerId: salesLedgerId,
          salesLedgerProductId: currentDeliveryRow.value.id,
          type: deliveryForm.value.type,
          shippingCarNumber:
            deliveryForm.value.type === "货车"
              ? deliveryForm.value.shippingCarNumber
              : "",
          expressCompany:
            deliveryForm.value.type === "快递"
              ? deliveryForm.value.expressCompany
              : "",
          expressNumber:
            deliveryForm.value.type === "快递"
              ? deliveryForm.value.expressNumber
              : "",
          storageBlobDTOs: deliveryFileList.value || [],
          batchNo: deliveryForm.value.batchNo,
          batchNoDetailList: selectedBatchRows.map(item => ({
            stockInventoryId: item.id,
@@ -2701,8 +2775,18 @@
  };
  // 关闭发货弹框
  const handleDeliveryTypeChange = val => {
    if (val === "货车") {
      deliveryForm.value.expressCompany = "";
      deliveryForm.value.expressNumber = "";
    } else {
      deliveryForm.value.shippingCarNumber = "";
    }
  };
  const closeDeliveryDia = () => {
    proxy.resetForm("deliveryFormRef");
    deliveryFileList.value = [];
    deliveryFormVisible.value = false;
    currentDeliveryRow.value = null;
  };