2026-04-30 16:36:52 +08:00
|
|
|
# 导入模板下拉框结构校验后端设计
|
|
|
|
|
|
|
|
|
|
## 背景
|
|
|
|
|
|
|
|
|
|
本次问题来自员工信息维护批量导入文件:
|
|
|
|
|
|
|
|
|
|
- 文件路径:`/Users/wkc/Desktop/ccdi/ccdi_bulk_20260430/员工信息维护导入模板_批量测试数据.xlsx`
|
|
|
|
|
- 问题表现:`员工信息` Sheet 的 `状态` 列没有 Excel 下拉框,但当前导入链路会继续读取数据并进入业务导入。
|
|
|
|
|
|
|
|
|
|
用户已确认本次范围为:所有 Excel 导入中,凡是导入对象字段标注了 `@DictDropdown`,上传文件对应 Sheet 的对应列都必须保留模板下拉框;缺失下拉框时导入应立即报错。
|
|
|
|
|
|
|
|
|
|
## 目标
|
|
|
|
|
|
|
|
|
|
1. 统一拦截缺少下拉框的数据文件,避免模板结构被破坏后仍被导入。
|
|
|
|
|
2. 覆盖所有使用 `EasyExcelUtil.importExcel(...)` 读取、且导入对象含 `@DictDropdown` 字段的导入接口。
|
|
|
|
|
3. 双 Sheet 导入按 Sheet 分别校验,任一应有下拉框的列缺失时立即失败。
|
|
|
|
|
4. 错误提示明确到 Sheet 和列,便于用户重新下载模板处理。
|
|
|
|
|
|
|
|
|
|
## 非目标
|
|
|
|
|
|
|
|
|
|
1. 不改造无 `@DictDropdown` 字段的导入,例如当前未使用字典下拉模板的导入不强行纳入。
|
|
|
|
|
2. 不改变现有业务字段校验、重复校验、异步导入、失败记录展示逻辑。
|
|
|
|
|
3. 不新增兼容旧模板或降级导入逻辑;缺少下拉框即按模板不合规处理。
|
|
|
|
|
|
|
|
|
|
## 推荐方案
|
|
|
|
|
|
|
|
|
|
采用工具层统一校验:
|
|
|
|
|
|
|
|
|
|
1. 在 `EasyExcelUtil.importExcel(InputStream, Class<T>)` 和 `EasyExcelUtil.importExcel(InputStream, Class<T>, String)` 内部先读取上传文件字节。
|
|
|
|
|
2. 使用 POI 打开工作簿,根据导入类上的 `@DictDropdown` 和 `@ExcelProperty(index)` 解析应校验的列。
|
|
|
|
|
3. 校验对应 Sheet 中是否存在覆盖该列数据区的数据验证规则。
|
|
|
|
|
4. 校验通过后,再使用 EasyExcel 按现有方式读取数据。
|
|
|
|
|
|
|
|
|
|
该方案集中在公共导入工具,能随现有导入调用链自然覆盖员工信息、员工资产、亲属关系、招聘、调动、招投标、实体库、中介等使用字典下拉模板的导入。
|
|
|
|
|
|
|
|
|
|
## 校验规则
|
|
|
|
|
|
|
|
|
|
### 字段解析
|
|
|
|
|
|
|
|
|
|
- 扫描导入类及父类字段。
|
|
|
|
|
- 仅处理同时具备 `@DictDropdown` 和带明确 `index` 的 `@ExcelProperty` 字段。
|
|
|
|
|
- 列标题优先取 `@ExcelProperty.value()` 的第一个值。
|
|
|
|
|
|
|
|
|
|
### Sheet 定位
|
|
|
|
|
|
|
|
|
|
- 指定 Sheet 名读取时,校验该 Sheet。
|
|
|
|
|
- 未指定 Sheet 名读取时,校验第一个 Sheet。
|
|
|
|
|
- 若 Sheet 不存在,保持现有读取失败语义,不额外设计兜底。
|
|
|
|
|
|
|
|
|
|
### 下拉框判断
|
|
|
|
|
|
|
|
|
|
- 读取 Sheet 的 `DataValidation` 列表。
|
2026-04-30 16:39:58 +08:00
|
|
|
- 只认可 `DataValidationConstraint.ValidationType.LIST` 类型的数据验证;数字、日期、自定义公式等其他校验类型不能视为模板下拉框。
|
|
|
|
|
- 数据区定义为:从第 2 行开始,到本次上传文件中该 Sheet 的最后一行有效数据。
|
|
|
|
|
- 对每个实际数据行,目标列单元格都必须被 `LIST` 数据验证区域覆盖;只覆盖表头、只覆盖单个样例行、或只覆盖部分数据行,都视为该列下拉框缺失。
|
2026-04-30 16:36:52 +08:00
|
|
|
- 校验目标为模板结构是否保留,不判断用户是否逐单元格从下拉框选择。
|
|
|
|
|
|
|
|
|
|
### 失败行为
|
|
|
|
|
|
|
|
|
|
任一应有下拉框的列缺失数据验证时,导入立即失败,不进入异步任务,不写 Redis 状态,不产生部分成功。
|
|
|
|
|
|
|
|
|
|
建议错误文案:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
员工信息 Sheet 的 状态 列缺少下拉框,请下载最新导入模板填写后重新导入
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
双 Sheet 场景示例:
|
|
|
|
|
|
|
|
|
|
- `员工信息` Sheet 的 `是否党员` 或 `状态` 缺失下拉框:失败。
|
|
|
|
|
- `员工资产信息` Sheet 的 `资产状态` 缺失下拉框:失败。
|
|
|
|
|
- 两个 Sheet 都保留下拉框:继续现有导入读取和业务校验。
|
|
|
|
|
|
|
|
|
|
## 影响范围
|
|
|
|
|
|
|
|
|
|
后端主要影响:
|
|
|
|
|
|
|
|
|
|
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/utils/EasyExcelUtil.java`
|
|
|
|
|
- 使用 `EasyExcelUtil.importExcel(...)` 的导入 Controller。
|
|
|
|
|
|
|
|
|
|
前端不需要改动。后端抛出的错误沿现有上传失败链路返回,页面展示现有错误提示即可。
|
|
|
|
|
|
|
|
|
|
## 测试设计
|
|
|
|
|
|
|
|
|
|
### 单元测试
|
|
|
|
|
|
|
|
|
|
新增工具层测试覆盖:
|
|
|
|
|
|
|
|
|
|
1. 带 `@DictDropdown` 且保留下拉数据验证的模板读取通过。
|
|
|
|
|
2. 员工信息 `状态` 列缺少下拉数据验证时报错。
|
2026-04-30 16:39:58 +08:00
|
|
|
3. 非 `LIST` 类型数据验证不能替代下拉框。
|
|
|
|
|
4. 只覆盖部分实际数据行的下拉框应报错。
|
|
|
|
|
5. 双 Sheet 中任一 Sheet 的字典下拉列缺失时报错。
|
|
|
|
|
6. 无 `@DictDropdown` 字段的导入对象不触发结构校验。
|
2026-04-30 16:36:52 +08:00
|
|
|
|
|
|
|
|
### 样例文件验证
|
|
|
|
|
|
|
|
|
|
使用用户提供文件验证:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
/Users/wkc/Desktop/ccdi/ccdi_bulk_20260430/员工信息维护导入模板_批量测试数据.xlsx
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
预期:导入员工信息 Sheet 时提示 `状态` 列缺少下拉框。
|
|
|
|
|
|
|
|
|
|
### 真实页面验证
|
|
|
|
|
|
|
|
|
|
实现完成后按仓库规则使用 `browser-use` 打开真实员工信息维护页面验证:
|
|
|
|
|
|
|
|
|
|
1. 下载页面当前真实导入模板。
|
|
|
|
|
2. 上传缺少下拉框的批量测试文件,确认页面提示导入失败。
|
|
|
|
|
3. 上传保留下拉框的测试文件,确认能进入现有正常导入链路。
|
|
|
|
|
4. 测试结束关闭本轮启动的前后端进程。
|
|
|
|
|
|
|
|
|
|
## 文档与实施记录
|
|
|
|
|
|
|
|
|
|
实现完成后新增实施记录:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
docs/reports/implementation/2026-04-30-import-dropdown-validation-implementation.md
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
实施记录需包含:
|
|
|
|
|
|
|
|
|
|
- 修改内容。
|
|
|
|
|
- 影响范围。
|
|
|
|
|
- 测试命令与真实页面验证结果。
|
|
|
|
|
- 用户提供缺下拉框文件的验证结果。
|