Files
tms-erp-api/运单与运输计划导入校验-最终完成报告.md
T
b2894lxlx bdafb83583 1、调整凭证
2、调整运单
2026-09-08 22:41:40 +08:00

10 KiB
Raw Blame History

运单与运输计划导入校验功能 - 最终完成报告

完成时间

2026-09-08 19:45

实现方式

两步校验机制

  1. 选择文件后 → 立即调用校验接口(只校验不入库)
  2. 点击确认导入 → 调用确认接口(再次校验并入库)

一、已完成的工作

1.1 运单导入 (/business/waybill-import/form)

后端

  • 添加校验接口 POST /import-batch/validate(只校验不入库)
  • 修改确认接口 POST /import-batch/confirm(校验并入库)
  • 实现完整的校验规则(格式、逻辑、必填项)
  • 校验失败时导出错误明细 Excel

前端

  • 添加 validateImport API
  • 文件上传后自动调用校验接口
  • 根据响应 MIME 类型正确判断是否下载错误明细
  • 校验失败自动下载错误明细表

1.2 运输计划导入 (/business/transport-plan/import)

后端

  • 添加校验接口 POST /validate-transport-plan(只校验不入库)
  • 保留确认接口 POST /import-transport-plan(校验并入库)
  • 实现完整的校验规则
  • 校验失败时导出错误明细 Excel

前端

  • 添加 validateTransportPlan API
  • 文件上传后自动调用校验接口
  • 根据响应 MIME 类型正确判断是否下载错误明细
  • 校验失败自动下载错误明细表

二、关键问题修复

2.1 前端响应类型判断问题

问题描述

当 API 设置 responseType: 'blob' 时,axios 会将所有响应(包括 JSON)都当作 Blob 处理,导致无法正确判断校验结果。

解决方案

根据 Blob 的 MIME 类型判断实际内容:

const blob = response.data || response;

if (blob instanceof Blob) {
  // Excel 文件
  if (blob.type.includes('application/vnd.ms-excel') ||
      blob.type.includes('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')) {
    // 下载错误明细
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = `运单导入失败明细_${dayjs().format('YYYYMMDDHHmmss')}.xlsx`;
    link.click();
    window.URL.revokeObjectURL(url);
    ElMessage.warning('数据校验失败,已自动下载错误明细表');
  } 
  // JSON 响应
  else if (blob.type.includes('application/json')) {
    const text = await blob.text();
    const json = JSON.parse(text);
    if (json.success) {
      ElMessage.success('数据校验通过');
    } else {
      ElMessage.error(json.msg || '校验失败');
    }
  }
}

修改的文件

  • src/views/business/components/waybill-import-dialog.vue
  • src/views/business/transport-plan-import.vue

2.2 后端导入语句顺序问题

问题描述

TransportPlanServiceImpl.java 中的导入语句顺序混乱,导致编译错误。

解决方案

重新整理导入语句,按照标准顺序:

  1. Java 标准库
  2. 第三方库
  3. 项目内部包

修改的文件

  • TransportPlanServiceImpl.java - 重新整理了所有导入语句

三、用户使用流程

3.1 上传文件阶段

  1. 用户点击"添加附件"按钮
  2. 选择 Excel 文件
  3. 前端解析 Excel 并自动调用后端校验接口
  4. 后端校验结果:
    • 校验通过:返回 JSON (application/json),前端提示"数据校验通过"
    • 校验失败:返回 Excel 文件流 (application/vnd.ms-excel),浏览器自动下载错误明细表

3.2 确认导入阶段

  1. 用户查看预览数据,确认无误
  2. 点击"确认导入"按钮
  3. 前端调用确认接口
  4. 后端再次校验并入库:
    • 校验通过:入库成功,返回 JSON,前端提示"导入成功"
    • 校验失败:返回 Excel 文件流,浏览器自动下载错误明细表

3.3 错误明细 Excel 格式

  • 在原始 Excel 最后一列追加"错误信息"列
  • 错误信息以红色字体显示
  • 校验通过的行显示空字符串
  • 多个错误用 "; " 分隔
  • 列宽自动调整

四、技术实现细节

4.1 后端接口

运单导入

// 校验接口
@PostMapping("/import-batch/validate")
public void validateImportBatch(@RequestBody WaybillImportBatchRequest request, 
                                HttpServletResponse response) {
    waybillImportBatchService.validate(request, response);
}

// 确认导入接口
@PostMapping("/import-batch/confirm")
public void confirmImportBatch(@RequestBody WaybillImportBatchRequest request, 
                               HttpServletResponse response) {
    waybillImportBatchService.confirm(request, response);
}

运输计划导入

// 校验接口
@PostMapping("/validate-transport-plan")
public R validateTransportPlan(MultipartFile file, @RequestParam Long projectId, ..., 
                               HttpServletResponse response) {
    List<TransportPlanImportExcel> failureList = 
        transportPlanService.validateTransportPlan(...);
    if (Func.isNotEmpty(failureList)) {
        ImportFailureExcelUtil.export(response, "运输计划导入失败明细" + 
            DateUtil.time(), "导入失败明细", failureList, 
            TransportPlanImportExcel.class);
        return null;
    }
    return R.success("校验通过");
}

// 确认导入接口(已有方法,保持不变)
@PostMapping("/import-transport-plan")
public R importTransportPlan(MultipartFile file, @RequestParam Long projectId, ..., 
                             HttpServletResponse response) {
    List<TransportPlanImportExcel> failureList = 
        transportPlanService.importTransportPlan(...);
    if (Func.isNotEmpty(failureList)) {
        ImportFailureExcelUtil.export(response, "运输计划导入失败明细" + 
            DateUtil.time(), "导入失败明细", failureList, 
            TransportPlanImportExcel.class);
        return null;
    }
    return R.success("导入数据成功");
}

4.2 前端 API

运单导入

export const validateImport = data => request({ 
  url: `${baseUrl}/import-batch/validate`, 
  method: 'post', 
  data, 
  responseType: 'blob' 
});

export const confirmImport = data => request({ 
  url: `${baseUrl}/import-batch/confirm`, 
  method: 'post', 
  data 
});

运输计划导入

export const validateTransportPlan = ({ file, projectId, ... }) => {
  const data = new FormData();
  data.append('file', file);
  data.append('projectId', projectId || '');
  // ...
  return request({
    url: `${baseUrl}/validate-transport-plan`,
    method: 'post',
    data,
    responseType: 'blob',
    timeout: 60000,
  });
};

export const importTransportPlan = ({ file, projectId, ... }) => {
  // 类似结构
};

4.3 响应类型判断

关键点

  • 设置 responseType: 'blob' 后,所有响应都会被当作 Blob
  • 必须通过 blob.typeMIME 类型)来判断实际内容
  • Excel 文件:application/vnd.ms-excelapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
  • JSON 响应:application/json

五、编译验证

5.1 后端编译

编译成功 - mvn compile -DskipTests

问题修复:

  • 修复了 TransportPlanServiceImpl.java 的导入语句顺序问题

5.2 前端构建

构建成功 - pnpm run build


六、测试清单

运单导入测试

  • 上传正确数据 → 校验通过 → 确认导入成功
  • 上传错误数据 → 自动下载错误明细(红字显示错误)
  • 修正后重新上传 → 校验通过 → 确认导入成功
  • 车牌号格式错误 → 错误明细显示"车牌号格式错误"
  • 必填项缺失 → 错误明细显示"XXX不能为空"
  • 运费合计不匹配 → 错误明细显示"运费合计不匹配"

运输计划导入测试

  • 上传正确数据 → 校验通过 → 确认导入成功
  • 上传错误数据 → 自动下载错误明细(红字显示错误)
  • 必填项缺失 → 错误明细显示相应错误
  • 日期格式错误 → 错误明细显示相应错误

七、相关文档

已创建的文档

  1. 导入校验规则-后端实现文档.md(前端项目)
  2. 导入校验改造总结.md(前端项目)
  3. 运单导入校验-前后端对接完成总结.md(后端项目)
  4. 运单导入校验-最终实现总结.md(后端项目)
  5. 运单与运输计划导入校验-完整实现总结.md(后端项目)
  6. 本文档(最终完成报告)

八、改造前后对比

改造前

  • 前端校验,规则可能不完整
  • 只在确认导入时校验
  • 校验失败时提示不够详细
  • 前后端规则不一致

改造后

  • 后端统一校验,规则完整
  • 上传后立即校验 + 确认导入时再次校验
  • 校验失败自动下载详细的错误明细表
  • 前后端规则统一,易于维护
  • 双重校验确保数据准确性

九、核心优势

  1. 及早发现问题 - 上传后立即校验,用户可以立即修正
  2. 详细的错误明细 - Excel 格式,红字显示错误,一目了然
  3. 双重校验 - 确保数据准确性
  4. 用户体验好 - 自动下载错误明细,无需手动操作
  5. 易于维护 - 校验规则集中在后端,前后端规则统一

十、总结

完成状态

全部完成

  • 运单导入:前后端代码完成,编译通过
  • 运输计划导入:前后端代码完成,编译通过
  • 问题修复:响应类型判断、导入语句顺序
  • 文档完善:创建了 6 份详细文档

核心改进

  1. 两步校验机制 - 上传后校验 + 确认导入时再次校验
  2. 智能响应判断 - 根据 MIME 类型判断是下载文件还是显示提示
  3. 详细错误明细 - Excel 格式,红字显示,易于修正

下一步

  • 启动前后端服务进行联调测试
  • 验证各种错误场景
  • 收集用户反馈并优化

编写人: Claude Code
版本: 4.0(最终版)
最后更新: 2026-09-08 19:45
状态: 全部完成,编译通过,等待测试