2、调整运单
11 KiB
运单导入校验功能 - 最终实现总结
完成时间
2026-09-08
实现方式
两步校验机制:
- 选择文件后 → 立即调用校验接口(
/import-batch/validate),只校验不入库 - 点击确认导入 → 调用确认接口(
/import-batch/confirm),再次校验并入库
一、用户使用流程
1. 上传文件阶段
- 用户点击"添加附件"按钮
- 选择 Excel 文件
- 前端自动调用校验接口
POST /blade-transport/waybill-manage/import-batch/validate - 后端返回结果:
- 校验通过:返回 JSON,前端提示"数据校验通过"
- 校验失败:返回 Excel 文件流,浏览器自动下载错误明细表,前端提示"数据校验失败,已自动下载错误明细表,请修正后重新上传"
2. 确认导入阶段
- 用户查看预览数据,确认无误
- 点击"确认导入"按钮
- 前端调用确认接口
POST /blade-transport/waybill-manage/import-batch/confirm - 后端再次校验并入库:
- 校验通过:入库成功,返回 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 两次校验的原因
-
第一次校验(上传后):
- 及早发现问题,用户可以立即修正
- 避免用户填写其他表单项后才发现数据有问题
-
第二次校验(确认导入时):
- 防止数据在上传和确认之间被修改
- 确保入库数据的准确性
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)
八、后续工作
短期
- 联调测试 - 启动前后端服务,完整流程测试
- Bug 修复 - 根据测试结果修复问题
- 运输计划导入 - 实现类似的两步校验机制
长期
- 校验规则配置化 - 将规则抽取为配置,便于维护
- 地址库集成 - 实现真实的地址匹配校验
- 性能优化 - 针对大文件导入进行优化
- 国际化 - 支持多语言错误信息
九、相关文档
已创建的文档
- 导入校验规则-后端实现文档.md(前端项目)
- 导入校验改造总结.md(前端项目)
- 运单导入校验-前后端对接完成总结.md(后端项目)
- 本文档(最终实现总结)
参考实现
- 港口码头导入:
/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