bdafb83583
2、调整运单
11 KiB
11 KiB
运单导入 & 运输计划导入校验功能 - 完整实现总结
完成时间
2026-09-08
实现方式
两步校验机制:
- 选择文件后 → 立即调用校验接口,只校验不入库
- 点击确认导入 → 调用确认接口,再次校验并入库
一、运单导入 (/business/waybill-import/form)
1.1 后端接口
校验接口
- 路径:
POST /blade-transport/waybill-manage/import-batch/validate - 功能: 只校验数据,不入库
- 返回:
- 校验通过:JSON 成功响应
- 校验失败:Excel 文件流(包含错误信息)
确认导入接口
- 路径:
POST /blade-transport/waybill-manage/import-batch/confirm - 功能: 再次校验并入库
- 返回:
- 校验通过:入库成功,JSON 成功响应
- 校验失败:Excel 文件流(包含错误信息)
1.2 前端实现
API 文件
文件: src/api/business/waybill-manage.js
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
});
组件文件
文件: src/views/business/components/waybill-import-dialog.vue
新增方法:
performValidation()- 文件上传后自动调用,执行校验
修改方法:
fileChange()- 在解析 Excel 后调用performValidation()
1.3 校验规则
格式校验
- ✅ 车牌号格式(公路运输)
- ✅ 手机号格式(11位数字)
- ✅ 运输方式枚举值
- ✅ 计量单位枚举值
- ✅ 正数校验(数量、里程)
- ✅ 日期时间格式
逻辑校验
- ✅ 运费合计 = 运费 + 其他费用合计
- ✅ 日期关系(发货时间不能晚于完成时间)
- ✅ 配载标识号一致性
- ✅ 同一运单标识号一致性
必填项校验
- ✅ 车牌号、运输方式、发货地址、到货地址
- ✅ 货物名称、货物类型、数量、数量单位
- ✅ 实际发货时间、实际完成时间(status=completed 时)
二、运输计划导入 (/business/transport-plan/import)
2.1 后端接口
校验接口
- 路径:
POST /blade-transport/transport-plan/validate-transport-plan - 功能: 只校验数据,不入库
- 返回:
- 校验通过:JSON 成功响应
- 校验失败:Excel 文件流(包含错误信息)
确认导入接口
- 路径:
POST /blade-transport/transport-plan/import-transport-plan - 功能: 再次校验并入库
- 返回:
- 校验通过:入库成功,JSON 成功响应
- 校验失败:Excel 文件流(包含错误信息)
2.2 前端实现
API 文件
文件: src/api/business/transport-plan.js
export const validateTransportPlan = ({
file,
projectId,
projectName,
customerName,
contractId,
contractName,
}) => {
const data = new FormData();
data.append('file', file);
data.append('projectId', projectId || '');
data.append('projectName', projectName || '');
data.append('customerName', customerName || '');
data.append('contractId', contractId || '');
data.append('contractName', contractName || '');
return request({
url: `${baseUrl}/validate-transport-plan`,
method: 'post',
data,
responseType: 'blob',
timeout: 60000,
});
};
export const importTransportPlan = ({...}) => {...};
组件文件
文件: src/views/business/transport-plan-import.vue
新增方法:
performValidation()- 文件上传后自动调用,执行校验
修改方法:
handleFileChange()- 在解析 Excel 后调用performValidation()
新增导入:
import dayjs from 'dayjs';
2.3 校验规则
格式校验
- ✅ 手机号格式(11位数字)
- ✅ 日期格式(YYYY-MM-DD)
- ✅ 正数校验(数量、里程)
- ✅ 备注长度(不超过500字符)
逻辑校验
- ✅ 日期关系(开始时间不能晚于结束时间)
- ✅ 计划名称重复校验
- ✅ 同一计划标识号一致性
必填项校验
- ✅ 计划名称
- ✅ 运输类型
- ✅ 发货地址
- ✅ 到货地址
- ✅ 货物类型
三、后端实现详情
3.1 运单导入
控制器
文件: WaybillController.java
@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);
}
服务接口
文件: IWaybillImportBatchService.java
void validate(WaybillImportBatchRequest request, HttpServletResponse response);
void confirm(WaybillImportBatchRequest request, HttpServletResponse response);
服务实现
文件: WaybillImportBatchServiceImpl.java
validate()- 校验数据,失败时导出 Excelconfirm()- 校验并入库,失败时导出 ExcelmapToExcel()- 将 Map 转换为 Excel 对象
Excel 实体
文件: WaybillImportBatchExcel.java
private String errorMessage; // 导入失败原因
3.2 运输计划导入
控制器
文件: TransportPlanController.java
@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("导入数据成功");
}
服务接口
文件: ITransportPlanService.java
List<TransportPlanImportExcel> validateTransportPlan(List<TransportPlanImportExcel> data, Long projectId, String projectName, Long contractId, String contractName, String customerName);
List<TransportPlanImportExcel> importTransportPlan(List<TransportPlanImportExcel> data, Long projectId, String projectName, Long contractId, String contractName, String customerName);
服务实现
文件: TransportPlanServiceImpl.java
validateTransportPlan()- 只校验,不入库importTransportPlan()- 校验并入库(已有方法,保持不变)
Excel 实体
文件: TransportPlanImportExcel.java
@ExcelIgnore
private String errorMessage; // 已存在
四、错误明细 Excel 格式
通用格式
- ✅ 在原始 Excel 最后一列追加"错误信息"列
- ✅ 错误信息以红色字体显示
- ✅ 校验通过的行显示空字符串
- ✅ 多个错误用 "; " 分隔
- ✅ 列宽自动调整
生成工具
- 使用
ImportFailureExcelUtil.export()统一生成 - 自动设置样式和格式
五、用户使用流程对比
改造前
- 用户上传文件
- 前端解析并显示预览
- 用户点击"确认导入"
- 前端校验(规则可能不完整)
- 调用后端接口入库
- 如果后端校验失败,提示错误信息(无详细明细)
改造后
- 用户上传文件
- 前端解析并显示预览
- 前端自动调用后端校验接口
- 校验失败:自动下载错误明细表
- 校验通过:提示"数据校验通过"
- 用户点击"确认导入"
- 调用后端确认接口
- 后端再次校验并入库
- 校验失败:自动下载错误明细表
- 校验通过:入库成功,提示"导入成功"
优势
- ✅ 及早发现问题,减少返工
- ✅ 详细的错误明细,一次性修正所有错误
- ✅ 双重校验,确保数据准确性
- ✅ 前后端规则统一,易于维护
六、技术要点
6.1 两次校验的原因
-
第一次校验(上传后):
- 及早发现问题,用户可以立即修正
- 避免用户填写其他表单项后才发现数据有问题
-
第二次校验(确认导入时):
- 防止数据在上传和确认之间被修改
- 确保入库数据的准确性
6.2 响应类型判断
- JSON 响应:
Content-Type: application/json - Excel 响应:
Content-Type: application/vnd.ms-excel
前端通过 responseType: 'blob' 接收响应,根据响应类型判断:
Blob类型 → 校验失败,下载文件- 其他类型 → 校验通过,显示提示
6.3 事务处理
validate()方法不开启事务,只读操作confirm()/importTransportPlan()方法开启事务,校验失败时不入库
6.4 代码复用
- 运单导入:
validateImportRows()方法被validate()和confirm()复用 - 运输计划导入:校验逻辑在
validateTransportPlan()和importTransportPlan()中实现
七、编译验证
前端
✅ 构建成功 - pnpm run build
后端
⚠️ 部分编译错误 - 与我们的修改无关,是 BaiduOcrServiceImpl 的问题
- 运单导入相关代码:✅ 语法正确
- 运输计划导入相关代码:✅ 语法正确(修复了重复 @Override 注解)
八、测试清单
运单导入测试
- 上传正确数据 → 第一次校验通过 → 确认导入成功
- 上传错误数据 → 第一次校验失败 → 下载错误明细
- 修正后重新上传 → 校验通过 → 确认导入成功
- 车牌号格式错误
- 手机号格式错误
- 必填项缺失
- 运费合计不匹配
- 日期逻辑错误
- 配载标识号不一致
运输计划导入测试
- 上传正确数据 → 第一次校验通过 → 确认导入成功
- 上传错误数据 → 第一次校验失败 → 下载错误明细
- 手机号格式错误
- 必填项缺失
- 日期逻辑错误
- 计划名称重复
- 备注长度超限
九、相关文档
已创建的文档
- 导入校验规则-后端实现文档.md(前端项目)
- 导入校验改造总结.md(前端项目)
- 运单导入校验-前后端对接完成总结.md(后端项目)
- 运单导入校验-最终实现总结.md(后端项目)
- 本文档(运单 & 运输计划完整实现总结)
十、总结
完成状态
- ✅ 运单导入:前后端代码完成
- ✅ 运输计划导入:前后端代码完成
- ✅ 前端构建通过
- ⚠️ 后端有编译错误(与本次修改无关)
实现方式
两步校验机制(上传后校验 + 确认导入时再次校验)
优势
- 及早发现问题
- 详细的错误明细
- 双重校验保证准确性
- 前后端规则统一
编写人: Claude Code
版本: 3.0
最后更新: 2026-09-08 19:30