# 招聘信息管理双 Sheet 导入实施记录

## 文档信息

- 保存路径：`docs/reports/implementation/2026-04-23-staff-recruitment-dual-sheet-import-implementation.md`
- 实施日期：2026-04-23
- 关联范围：招聘信息管理前后端

## 本次修改内容

### 后端

1. 将招聘导入控制器收口为单一模板下载接口与单一导入入口：
   - 模板改为 `招聘信息` + `历史工作经历` 双 Sheet；
   - 移除独立 `workImportTemplate`、`importWorkData` 入口。
2. 调整 `ICcdiStaffRecruitmentService`、`ICcdiStaffRecruitmentImportService` 签名，统一为双 Sheet 单任务提交。
3. 在 `CcdiStaffRecruitmentServiceImpl` 中统一初始化 Redis 任务状态，任务总数按 `recruitmentList.size() + workList.size()` 统计。
4. 重写 `CcdiStaffRecruitmentImportServiceImpl` 导入编排：
   - 主 Sheet 先校验并落库；
   - 工作经历 Sheet 按 `recruitId` 分组校验；
   - 工作经历既支持匹配“本次主 Sheet 成功数据”，也支持匹配数据库已有招聘主信息；
   - 若数据库已存在该招聘记录的历史工作经历，则整组失败，不做覆盖。
5. 为 `RecruitmentImportFailureVO` 补充 `sheetName`、`sheetRowNum` 字段，失败记录可直接定位到具体 Sheet 和 Excel 行号。
6. 新增/补充招聘导入回归测试：
   - `CcdiStaffRecruitmentDualImportContractTest`
   - `CcdiStaffRecruitmentImportServiceImplTest`
   - `EasyExcelUtilTemplateTest`

### 前端

1. 招聘信息管理页工具栏只保留一个“导入”按钮，删除独立“导入工作经历”入口。
2. 上传弹窗文案统一为双 Sheet 模式，模板说明明确为“招聘信息 + 历史工作经历”。
3. 页面本地状态收口为单任务轮询：
   - 只保存一个 `currentTaskId`；
   - 删除按导入类型分流的状态与提示文案。
4. 失败弹窗统一展示：
   - `失败Sheet`
   - `失败行号`
   - `失败原因`
   - 以及招聘编号/项目/岗位/候选人/工作单位等辅助字段。
5. 新增前端静态契约测试：
   - `staff-recruitment-import-toolbar.test.js`
   - `staff-recruitment-import-state.test.js`
   - `staff-recruitment-import-failure-dialog.test.js`

## 影响范围

- 后端：招聘导入模板下载、导入提交、异步导入编排、失败记录返回。
- 前端：招聘信息管理页导入入口、上传弹窗、导入轮询、失败弹窗。
- 测试：招聘导入后端定向测试、前端静态契约测试、真实页面 Playwright 验证。
- 文档：新增本实施记录。

## 验证情况

1. 后端定向测试通过：
   - 命令：
     `mvn -pl ccdi-info-collection -am -Dtest=CcdiStaffRecruitmentDualImportContractTest,CcdiStaffRecruitmentImportServiceImplTest,EasyExcelUtilTemplateTest -Dsurefire.failIfNoSpecifiedTests=false test`
   - 结果：7 个测试全部通过。
2. 后端编译通过：
   - 命令：
     `mvn -pl ccdi-info-collection,ruoyi-admin -am -DskipTests compile`
   - 结果：`BUILD SUCCESS`。
3. 前端静态契约测试通过：
   - 命令：
     `source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && node ruoyi-ui/tests/unit/staff-recruitment-import-toolbar.test.js && node ruoyi-ui/tests/unit/staff-recruitment-import-state.test.js && node ruoyi-ui/tests/unit/staff-recruitment-import-failure-dialog.test.js`
   - 结果：3 个脚本全部通过。
4. 前端生产构建通过：
   - 命令：
     `source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && cd ruoyi-ui && npm run build:prod`
   - 结果：构建成功，仅存在原有体积告警，无新增构建错误。
5. 真实页面 Playwright 验证通过：
   - 从真实登录页进入 `/maintain/staffRecruitment`；
   - 在真实导入弹窗中下载双 Sheet 模板；
   - 使用真实模板生成并上传 `只导招聘信息 Sheet` 样本，成功新增 `RC202604230901`；
   - 使用真实模板生成并上传 `只导历史工作经历 Sheet` 样本，`RC202604230901` 从 `0段` 变为 `1段`；
   - 使用真实模板生成并上传 `双 Sheet 同时导入` 样本，成功新增 `RC202604230902` 且直接显示 `1段`；
   - 再次上传 `RC202604230902` 的工作经历样本，页面出现失败按钮；
   - 打开失败弹窗后，确认展示了 `失败Sheet / 失败行号 / 失败原因`，并看到错误文案：
     `招聘记录编号[RC202604230902]已存在历史工作经历，不允许重复导入`。
6. 测试数据与缓存清理完成：
   - 通过后端删除接口清理 `RC202604230901`、`RC202604230902`；
   - 再次查询两条测试招聘名称，返回 `total=0`；
   - 浏览器侧 `localStorage.staff_recruitment_import_last_task` 已清空；
   - 已关闭本轮 Playwright 浏览器、前端 `8080` dev server 和后端 `62318` 进程。
