Files
tms-erp-api/运单导入校验-最终实现总结.md
T
b2894lxlx bdafb83583 1、调整凭证
2、调整运单
2026-09-08 22:41:40 +08:00

11 KiB
Raw Blame History

运单导入校验功能 - 最终实现总结

完成时间

2026-09-08

实现方式

两步校验机制

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

一、用户使用流程

1. 上传文件阶段

  1. 用户点击"添加附件"按钮
  2. 选择 Excel 文件
  3. 前端自动调用校验接口 POST /blade-transport/waybill-manage/import-batch/validate
  4. 后端返回结果:
    • 校验通过:返回 JSON,前端提示"数据校验通过"
    • 校验失败:返回 Excel 文件流,浏览器自动下载错误明细表,前端提示"数据校验失败,已自动下载错误明细表,请修正后重新上传"

2. 确认导入阶段

  1. 用户查看预览数据,确认无误
  2. 点击"确认导入"按钮
  3. 前端调用确认接口 POST /blade-transport/waybill-manage/import-batch/confirm
  4. 后端再次校验并入库:
    • 校验通过:入库成功,返回 JSON,前端提示"导入成功"
    • 校验失败:返回 Excel 文件流,浏览器自动下载错误明细表(防止数据在上传和确认之间被修改)

二、后端实现

1. 新增接口

1.1 校验接口

路径: POST /blade-transport/waybill-manage/import-batch/validate

功能: 只校验数据,不入库

返回:

  • 校验通过:JSON 成功响应
  • 校验失败:Excel 文件流(包含错误信息)

实现位置:

  • 控制器:WaybillController.validateImportBatch()
  • 服务接口:IWaybillImportBatchService.validate()
  • 服务实现:WaybillImportBatchServiceImpl.validate()

1.2 确认导入接口(修改)

路径: POST /blade-transport/waybill-manage/import-batch/confirm

功能: 再次校验并入库

返回:

  • 校验通过:入库成功,JSON 成功响应
  • 校验失败:Excel 文件流(包含错误信息)

实现位置:

  • 控制器:WaybillController.confirmImportBatch()
  • 服务接口:IWaybillImportBatchService.confirm()
  • 服务实现:WaybillImportBatchServiceImpl.confirm()

2. 修改的文件

2.1 控制器

文件: /blade-service/blade-transport/src/main/java/org/springblade/transport/controller/WaybillController.java

@PostMapping("/import-batch/validate")
@ApiOperationSupport(order = 6)
@Operation(summary = "校验运单批量导入数据")
public void validateImportBatch(@RequestBody WaybillImportBatchRequest request, HttpServletResponse response) {
    waybillImportBatchService.validate(request, response);
}

@PostMapping("/import-batch/confirm")
@ApiOperationSupport(order = 7)
@Operation(summary = "确认运单批量导入")
public void confirmImportBatch(@RequestBody WaybillImportBatchRequest request, HttpServletResponse response) {
    waybillImportBatchService.confirm(request, response);
}

2.2 服务接口

文件: /blade-service/blade-transport/src/main/java/org/springblade/transport/service/IWaybillImportBatchService.java

public interface IWaybillImportBatchService extends BaseService<WaybillImportBatch> {
    WaybillImportBatch saveDraft(WaybillImportBatchRequest request);
    void validate(WaybillImportBatchRequest request, HttpServletResponse response);
    void confirm(WaybillImportBatchRequest request, HttpServletResponse response);
    IPage<WaybillImportBatchVO> page(IPage<WaybillImportBatch> page, WaybillImportBatchRequest request);
    BusinessRemoveResultVO removeBatches(String ids);
}

2.3 服务实现

文件: /blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillImportBatchServiceImpl.java

新增方法:

  • validate() - 校验数据,不入库
  • mapToExcel() - 将 Map 转换为 Excel 对象

修改方法:

  • confirm() - 校验并入库
  • persist() - 移除内部校验逻辑

2.4 Excel 实体

文件: /blade-service/blade-transport/src/main/java/org/springblade/transport/excel/WaybillImportBatchExcel.java

新增字段:

/** 导入失败原因(不导出到模板,仅用于失败明细) */
private String errorMessage;

三、前端实现

1. 修改的文件

1.1 API 文件

文件: src/api/business/waybill-manage.js

新增接口:

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

1.2 组件文件

文件: src/views/business/components/waybill-import-dialog.vue

新增方法:

const performValidation = async () => {
  if (!rows.value.length) return;

  try {
    const response = await api.validateImport(buildImportPayload());

    if (response instanceof Blob) {
      // 校验失败,下载错误明细
      const url = window.URL.createObjectURL(response);
      const link = document.createElement('a');
      link.href = url;
      link.download = `运单导入失败明细_${dayjs().format('YYYYMMDDHHmmss')}.xlsx`;
      link.click();
      window.URL.revokeObjectURL(url);
      ElMessage.warning('数据校验失败,已自动下载错误明细表,请修正后重新上传');
    } else {
      // 校验通过
      ElMessage.success('数据校验通过');
    }
  } catch (error) {
    console.error('校验失败:', error);
    ElMessage.error('校验接口调用失败');
  }
};

修改方法:

  • fileChange() - 文件上传后调用 performValidation()

四、校验规则

已实现的校验规则

4.1 格式校验

  • 车牌号格式(公路运输:首位汉字 + 次位大写字母 + 7-8 位长度)
  • 手机号格式(11 位数字)
  • 运输方式枚举值
  • 计量单位枚举值
  • 正数校验(数量、里程)
  • 日期时间格式(YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss

4.2 逻辑校验

  • 运费合计 = 运费 + 其他费用合计
  • 日期关系(发货时间不能晚于完成时间)
  • 配载标识号一致性(同一配载标识号的车牌号必须一致)
  • 同一运单标识号一致性(同一运单标识号的车牌号必须一致)

4.3 必填项校验

  • 车牌号/航班号/船号/班列号
  • 运输方式
  • 发货地址
  • 到货地址
  • 货物名称
  • 货物类型
  • 数量
  • 数量单位
  • 实际发货时间(status=completed 时)
  • 实际完成时间(status=completed 时)

错误明细 Excel 格式

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

五、技术要点

5.1 两次校验的原因

  1. 第一次校验(上传后)

    • 及早发现问题,用户可以立即修正
    • 避免用户填写其他表单项后才发现数据有问题
  2. 第二次校验(确认导入时)

    • 防止数据在上传和确认之间被修改
    • 确保入库数据的准确性

5.2 响应类型判断

  • JSON 响应Content-Type: application/json
  • Excel 响应Content-Type: application/vnd.ms-excel

前端通过 responseType: 'blob' 接收响应,根据响应类型判断:

  • Blob 类型 → 校验失败,下载文件
  • 其他类型 → 校验通过,显示提示

5.3 事务处理

  • validate() 方法不开启事务,只读操作
  • confirm() 方法开启事务,校验失败时不入库,校验通过后才入库

5.4 性能优化

  • 校验逻辑复用(validateImportRows() 方法)
  • 使用 TreeMap 确保错误信息按行号排序
  • 使用 Map 数据结构优化跨行校验性能

六、测试验证

6.1 编译验证

后端编译成功 - mvn clean compile -DskipTests 前端构建成功 - pnpm run build

6.2 待测试项

功能测试

  • 上传完全正确的数据

    • 第一次校验提示"数据校验通过"
    • 点击确认导入,提示"导入成功"
  • 上传错误数据(如车牌号格式错误)

    • 第一次校验自动下载错误明细
    • 修正后重新上传,校验通过
    • 点击确认导入,提示"导入成功"
  • 上传混合数据(部分正确部分错误)

    • 下载的错误明细最后一列显示错误信息(红色)
    • 正确的行显示空字符串

边界测试

  • 上传空文件
  • 上传非 Excel 文件
  • 上传超大文件(>5000 行)
  • 同一配载标识号车牌不一致
  • 运费合计不匹配

性能测试

  • 上传 1000 行数据,校验响应时间
  • 上传 5000 行数据,校验响应时间
  • 并发上传测试

七、对比改造前后

改造前

  • 前端校验,规则分散
  • 前端生成错误 Excel
  • 前后端规则不一致
  • 只在确认导入时校验

改造后

  • 后端校验,规则集中
  • 后端生成错误 Excel
  • 统一的校验规则
  • 上传后立即校验 + 确认导入时再次校验
  • 使用成熟的工具类(ImportFailureExcelUtil

八、后续工作

短期

  1. 联调测试 - 启动前后端服务,完整流程测试
  2. Bug 修复 - 根据测试结果修复问题
  3. 运输计划导入 - 实现类似的两步校验机制

长期

  1. 校验规则配置化 - 将规则抽取为配置,便于维护
  2. 地址库集成 - 实现真实的地址匹配校验
  3. 性能优化 - 针对大文件导入进行优化
  4. 国际化 - 支持多语言错误信息

九、相关文档

已创建的文档

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

参考实现

  • 港口码头导入: /blade-system/port-terminal/import-port-terminal
  • 导入失败工具类: org.springblade.common.excel.ImportFailureExcelUtil

十、API 接口文档

10.1 校验接口

请求

POST /blade-transport/waybill-manage/import-batch/validate
Content-Type: application/json

{
  "projectId": 123,
  "contractId": 456,
  "status": "completed",
  "rows": [...]
}

响应

成功(校验通过):

HTTP/1.1 200 OK
Content-Type: application/json

{
  "code": 200,
  "success": true,
  "msg": "校验通过"
}

失败(校验不通过):

HTTP/1.1 200 OK
Content-Type: application/vnd.ms-excel
Content-Disposition: attachment; filename=运单导入失败明细20260908190730.xlsx

[Excel Binary Data]

10.2 确认导入接口

请求

POST /blade-transport/waybill-manage/import-batch/confirm
Content-Type: application/json

{
  "projectId": 123,
  "contractId": 456,
  "status": "completed",
  "rows": [...]
}

响应

成功(导入成功):

HTTP/1.1 200 OK
Content-Type: application/json

{
  "code": 200,
  "success": true,
  "msg": "操作成功"
}

失败(校验不通过):

HTTP/1.1 200 OK
Content-Type: application/vnd.ms-excel
Content-Disposition: attachment; filename=运单导入失败明细20260908190730.xlsx

[Excel Binary Data]

完成状态: 前后端代码已完成,编译通过,等待联调测试

实现方式: 两步校验机制(上传后校验 + 确认导入时再次校验)

编写人: Claude Code
版本: 2.0
最后更新: 2026-09-08 19:10