# 运输计划导入增强校验说明 ## 修改日期 2026-09-08 ## 一、导入逻辑变更 ### 原有逻辑 - 逐条导入,遇错即停 - 部分数据可能已入库 - 错误信息简单 ### 新逻辑(参考 /base/port-terminal) 1. **第一阶段:全部校验** - 先校验所有数据 - 收集所有错误信息 - 不进行任何数据库操作 2. **第二阶段:批量导入** - 仅当所有数据校验通过后才导入 - 任何一条数据有错误,全部回滚 - 保证数据一致性 3. **错误处理** - 导出包含错误信息的Excel - 每条错误数据标注具体错误原因 - 支持多个错误信息(编号列表) ## 二、详细校验规则 ### 1. 必填字段校验 | 字段 | 校验规则 | 错误提示 | |------|---------|---------| | *计划名称 | 不能为空 | 计划名称不能为空 | | *运输类型 | 不能为空 | 运输类型不能为空 | | *发货地址 | 不能为空 | 发货地址不能为空 | | *到货地址 | 不能为空 | 到货地址不能为空 | | *货物类型 | 不能为空 | 货物类型不能为空 | ### 2. 枚举值校验 #### 运输类型 **允许值:** - 公路整车 - 公路配载/零担 - 铁路运输 - 水路运输 - 跨境海运 - 航空运输 **错误提示:** 运输类型需系统枚举值(公路整车、公路配载/零担、铁路运输、水路运输、跨境海运、航空运输) #### 计量单位 **常用值:** - 吨、千克、立方米、件、车、箱、托盘、个、套、台 **错误提示:** 计量单位不存在 ### 3. 唯一性校验 #### 计划名称(当前组织下不重复) - 检查本次导入数据中的重复 - 检查数据库中当前组织的重复 - **错误提示:** - 计划名称在导入数据中重复 - 计划名称在当前组织下已存在 ### 4. 格式校验 #### 联系电话 **规则:** 11位数字 - 发货联系人电话 - 收货联系人电话 **错误提示:** - 发货联系人电话格式不正确(需11位数字) - 收货联系人电话格式不正确(需11位数字) #### 日期时间 **格式:** YYYY-MM-DD - 计划开始时间(非必填) - 计划结束时间(非必填) **逻辑校验:** 计划结束时间不得早于计划开始时间 **错误提示:** - 计划开始时间格式必须为 YYYY-MM-DD - 计划结束时间格式必须为 YYYY-MM-DD - 计划结束时间不得早于计划开始时间 ### 5. 数值校验 #### 数量 **规则:** 必须为正数或零 **错误提示:** 数量必须为正数 #### 里程(km) **规则:** 必须为正数或零 **错误提示:** 里程必须为正数 ### 6. 长度校验 | 字段 | 最大长度 | 错误提示 | |------|---------|---------| | 计划名称 | 255字符 | 计划名称不能超过255个字符 | | 发货地址 | 255字符 | 发货地址不能超过255个字符 | | 到货地址 | 255字符 | 到货地址不能超过255个字符 | | 发货联系人 | 255字符 | 发货联系人不能超过255个字符 | | 收货联系人 | 255字符 | 收货联系人不能超过255个字符 | | 同一计划标识号 | 255字符 | 同一计划标识号不能超过255个字符 | | 备注 | 500字符 | 备注不能超过500个字符 | ### 7. 同一计划标识号校验 **用途:** 当需要导入的计划的货物包含多个时,需拆分多行,并填写该标识,来标记多行为同一计划 **校验规则:** - 同一标识号下的所有记录应保持以下字段一致: - 计划名称 - 运输类型 - 发货地址 - 到货地址 **警告提示:** 注意:同一计划标识号应保持计划名称、运输类型、发货地址、到货地址一致 ### 8. 地址匹配校验(警告级别) **规则:** 地址应能匹配到系统地址库 **警告提示:** - 警告:发货地址未匹配到地址库,轨迹回放将受影响 - 警告:到货地址未匹配到地址库,轨迹回放将受影响 **说明:** 此为警告级别,不阻止导入,但会影响后续功能 ## 三、错误信息格式 ### 单条错误 ``` 1. 计划名称不能为空 ``` ### 多条错误 ``` 1. 计划名称不能为空 2. 运输类型需系统枚举值(公路整车、公路配载/零担、铁路运输、水路运输、跨境海运、航空运输) 3. 发货联系人电话格式不正确(需11位数字) ``` ## 四、导入流程 ### 用户操作流程 1. 下载导入模板 2. 填写计划数据 3. 上传Excel文件 4. 等待校验结果 ### 系统处理流程 #### 情况1:所有数据校验通过 ``` 解析Excel → 全部校验(通过) → 批量导入 → 提示成功 ``` #### 情况2:存在校验错误 ``` 解析Excel → 全部校验(失败) → 生成错误Excel → 下载错误明细 ``` - 不会导入任何数据 - 用户下载包含错误信息的Excel - 修正后重新导入 ## 五、后端实现要点 ### 1. 两阶段提交 ```java @Transactional(rollbackFor = Exception.class) public List importTransportPlan(...) { // 第一阶段:全部校验 Map errorMap = new TreeMap<>(); for (int index = 0; index < data.size(); index++) { List errors = validateImportExcel(excel, ...); if (Func.isNotEmpty(errors)) { excel.setErrorMessage(formatErrorMessage(errors)); errorMap.put(index, excel); } } // 如果有错误,回滚事务 if (Func.isNotEmpty(errorMap)) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return new ArrayList<>(errorMap.values()); } // 第二阶段:批量导入 for (TransportPlan plan : importPlans) { save(plan); } return new ArrayList<>(); } ``` ### 2. 错误收集器 - 使用 `TreeMap` 保持顺序 - 索引作为key,保持与Excel行号对应 - 错误信息格式化为编号列表 ### 3. 校验方法 ```java private List validateImportExcel(...) { List errors = new ArrayList<>(); // 收集所有错误,不立即抛出异常 if (condition) { errors.add("错误信息"); } return errors; } ``` ## 六、前端修改(transport-plan-import.vue) ### 无需修改 前端保持原有逻辑,后端返回的错误Excel会自动触发下载 ## 七、测试用例 ### 测试用例1:必填字段缺失 **输入:** 计划名称为空 **预期:** - 不导入任何数据 - 错误信息:计划名称不能为空 ### 测试用例2:运输类型枚举值错误 **输入:** 运输类型 = "陆运" **预期:** - 不导入任何数据 - 错误信息:运输类型需系统枚举值 ### 测试用例3:电话格式错误 **输入:** 发货联系人电话 = "12345" **预期:** - 不导入任何数据 - 错误信息:发货联系人电话格式不正确(需11位数字) ### 测试用例4:计划名称重复 **输入:** 两条数据的计划名称相同 **预期:** - 不导入任何数据 - 错误信息:计划名称在导入数据中重复 ### 测试用例5:部分数据错误 **输入:** 10条数据,第5条有错误 **预期:** - 不导入任何数据(包括前4条正确的) - 仅第5条有错误信息 ### 测试用例6:多个错误 **输入:** 一条数据同时缺少计划名称和运输类型 **预期:** ``` 1. 计划名称不能为空 2. 运输类型不能为空 ``` ### 测试用例7:同一计划标识号 **输入:** 3条数据,同一标识号,货物信息不同 **预期:** - 可以导入 - 3条记录关联到同一计划标识号 ## 八、与 port-terminal 导入的对比 | 特性 | port-terminal | transport-plan | |------|---------------|----------------| | 两阶段校验 | ✓ | ✓ | | 错误即回滚 | ✓ | ✓ | | 错误信息编号 | ✓ | ✓ | | 唯一性校验 | ✓ | ✓ | | 枚举值校验 | ✓ | ✓ | | 格式校验 | ✓ | ✓ | | 批量导入 | ✓ | ✓ | ## 九、后续优化建议 1. **地址匹配校验** - 实现发货地址和到货地址的地址库匹配 - 返回警告信息(不阻止导入) 2. **货物类型智能匹配** - 根据货物名称自动匹配货物类型 - 未匹配到时归为"其他"类 3. **同一计划标识号一致性校验** - 完整实现同一标识号的字段一致性检查 - 在第一阶段校验中完成 4. **计量单位字典化** - 从数据字典读取有效的计量单位列表 - 支持自定义扩展 5. **导入预览** - 前端增加导入预览功能 - 用户可在导入前查看解析结果