# Staff Recruitment Dual-Sheet Import Frontend Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 将招聘信息管理前端导入交互改为单入口双 Sheet 模式,统一任务轮询与失败弹窗,并在失败列表中展示失败 Sheet、失败行号、失败原因。
**Architecture:** 前端只保留一个导入按钮和一个上传弹窗,统一使用 `/ccdi/staffRecruitment/importTemplate` 与 `/importData`。页面本地状态从“按导入类型区分任务”收口为“按唯一任务 ID 轮询”,失败记录统一通过一个弹窗展示,并用 `sheetName`、`sheetRowNum` 区分失败来源。
**Tech Stack:** Vue 2, Element UI, axios request wrapper, Node 14.21.3 via nvm, source-inspection unit tests, Playwright browser validation
---
## File Map
- Modify: `ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue`
- 删除独立“导入工作经历”入口,收口上传弹窗、轮询状态和失败列表
- Modify: `ruoyi-ui/src/api/ccdiStaffRecruitment.js`
- 去掉独立工作经历导入模板/上传调用,保留统一导入 API
- Create: `ruoyi-ui/tests/unit/staff-recruitment-import-toolbar.test.js`
- 锁定顶部工具栏已收口为单入口
- Create: `ruoyi-ui/tests/unit/staff-recruitment-import-state.test.js`
- 锁定统一任务状态与轮询逻辑
- Create: `ruoyi-ui/tests/unit/staff-recruitment-import-failure-dialog.test.js`
- 锁定失败弹窗列定义与 `sheetRowNum` 展示格式
- Modify: `docs/reports/implementation/2026-04-23-staff-recruitment-dual-sheet-import-implementation.md`
- 追加前端改造与真实页面验证结果
### Task 1: 收口工具栏与上传 API
**Files:**
- Create: `ruoyi-ui/tests/unit/staff-recruitment-import-toolbar.test.js`
- Modify: `ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue`
- Modify: `ruoyi-ui/src/api/ccdiStaffRecruitment.js`
- [ ] **Step 1: 先写工具栏与 API 契约失败测试**
```js
[
"handleImport()",
'"/ccdi/staffRecruitment/importData"',
"招聘信息管理导入模板"
].forEach((token) => {
assert(source.includes(token), `招聘导入入口缺少统一双Sheet能力: ${token}`)
})
[
"handleWorkImport",
"importWorkData",
"workImportTemplate"
].forEach((token) => {
assert(!source.includes(token), `招聘页不应继续保留独立工作经历导入: ${token}`)
})
```
- [ ] **Step 2: 运行测试确认失败**
Run: `node ruoyi-ui/tests/unit/staff-recruitment-import-toolbar.test.js`
Expected: FAIL,提示页面仍保留“导入工作经历”按钮或 API 仍存在旧入口
- [ ] **Step 3: 最小化修改页面与 API**
```js
export function importTemplate() {
return request({
url: "/ccdi/staffRecruitment/importTemplate",
method: "post"
})
}
```
- [ ] **Step 4: 重跑测试**
Run: `node ruoyi-ui/tests/unit/staff-recruitment-import-toolbar.test.js`
Expected: PASS,页面只剩一个导入入口,API 只调用统一模板与上传接口
- [ ] **Step 5: 提交这一小步**
```bash
git add \
ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue \
ruoyi-ui/src/api/ccdiStaffRecruitment.js \
ruoyi-ui/tests/unit/staff-recruitment-import-toolbar.test.js
git commit -m "收口招聘双Sheet导入前端入口"
```
### Task 2: 收口上传弹窗文案与统一任务状态
**Files:**
- Create: `ruoyi-ui/tests/unit/staff-recruitment-import-state.test.js`
- Modify: `ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue`
- [ ] **Step 1: 先写统一状态失败测试**
```js
[
"模板包含“招聘信息”和“历史工作经历”两个 Sheet。",
"this.currentTaskId = taskId",
"this.showFailureButton = false",
"this.startImportStatusPolling(taskId)"
].forEach((token) => {
assert(source.includes(token), `招聘导入状态未统一到单任务: ${token}`)
})
[
"currentImportType",
"upload.importType",
"getImportTypeLabel"
].forEach((token) => {
assert(!source.includes(token), `招聘导入状态不应再按类型拆分: ${token}`)
})
```
- [ ] **Step 2: 运行测试确认失败**
Run: `node ruoyi-ui/tests/unit/staff-recruitment-import-state.test.js`
Expected: FAIL,提示页面仍保留类型切换状态
- [ ] **Step 3: 最小化实现统一轮询状态**
```js
this.saveImportTaskToStorage({
taskId,
status: "PROCESSING",
hasFailures: false
})
this.currentTaskId = taskId
this.startImportStatusPolling(taskId)
```
- [ ] **Step 4: 重跑测试**
Run: `node ruoyi-ui/tests/unit/staff-recruitment-import-state.test.js`
Expected: PASS,弹窗文案改为双 Sheet,页面状态只围绕一个任务 ID 轮询
- [ ] **Step 5: 提交这一小步**
```bash
git add \
ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue \
ruoyi-ui/tests/unit/staff-recruitment-import-state.test.js
git commit -m "统一招聘双Sheet导入轮询状态"
```
### Task 3: 调整统一失败弹窗列定义
**Files:**
- Create: `ruoyi-ui/tests/unit/staff-recruitment-import-failure-dialog.test.js`
- Modify: `ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue`
- [ ] **Step 1: 先写失败弹窗失败测试**
```js
[
'label="失败Sheet"',
'label="失败行号"',
"scope.row.sheetName",
"scope.row.sheetRowNum",
"失败原因"
].forEach((token) => {
assert(source.includes(token), `招聘失败弹窗缺少双Sheet定位列: ${token}`)
})
```
- [ ] **Step 2: 运行测试确认失败**
Run: `node ruoyi-ui/tests/unit/staff-recruitment-import-failure-dialog.test.js`
Expected: FAIL,提示弹窗仍按旧类型列展示
- [ ] **Step 3: 实现统一失败表格**
```vue
{{ scope.row.sheetRowNum ? `第${scope.row.sheetRowNum}行` : "-" }}
```
- [ ] **Step 4: 重跑测试**
Run: `node ruoyi-ui/tests/unit/staff-recruitment-import-failure-dialog.test.js`
Expected: PASS,失败弹窗明确展示失败 Sheet、失败行号、失败原因
- [ ] **Step 5: 提交这一小步**
```bash
git add \
ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue \
ruoyi-ui/tests/unit/staff-recruitment-import-failure-dialog.test.js
git commit -m "完善招聘双Sheet失败弹窗展示"
```
### Task 4: 做前端构建、真实页面验证与实施记录
**Files:**
- Modify: `ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue`
- Modify: `ruoyi-ui/src/api/ccdiStaffRecruitment.js`
- Modify: `docs/reports/implementation/2026-04-23-staff-recruitment-dual-sheet-import-implementation.md`
- [ ] **Step 1: 切换 Node 版本并执行前端静态回归**
Run: `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`
Expected: PASS,三个静态契约测试全部通过
- [ ] **Step 2: 执行前端构建**
Run: `source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && cd ruoyi-ui && npm run build:prod`
Expected: BUILD SUCCESS
- [ ] **Step 3: 启动真实页面并做浏览器验证**
Run:
```bash
source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null
cd ruoyi-ui
npm run dev -- --port 8080
```
Expected: 前端开发服务启动成功,真实页面 `http://localhost:8080` 可访问
Playwright 验证最少覆盖:
- 进入真实 `招聘信息管理` 页面,不使用 prototype 页面
- 从页面下载双 Sheet 模板
- 只导 `招聘信息` Sheet
- 只导 `历史工作经历` Sheet
- 双 Sheet 同时导入
- 已存在工作经历时报错
- 失败弹窗显示 `失败Sheet / 失败行号 / 失败原因`
- [ ] **Step 4: 补前端实施记录**
```md
- 页面导入入口收口为一个按钮
- 上传弹窗提示调整为双 Sheet 文案
- 页面状态收口为单任务轮询
- 失败弹窗新增失败 Sheet、失败行号、失败原因
- 已完成真实页面 Playwright 验证
```
- [ ] **Step 5: 关闭测试进程并提交前端收尾**
Run: 关闭本轮 `npm run dev` 与后端联调用到的进程,确保无残留端口占用
```bash
git add \
ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue \
ruoyi-ui/src/api/ccdiStaffRecruitment.js \
ruoyi-ui/tests/unit/staff-recruitment-import-toolbar.test.js \
ruoyi-ui/tests/unit/staff-recruitment-import-state.test.js \
ruoyi-ui/tests/unit/staff-recruitment-import-failure-dialog.test.js \
docs/reports/implementation/2026-04-23-staff-recruitment-dual-sheet-import-implementation.md
git commit -m "完成招聘双Sheet导入前端改造"
```