# 20260815 优化执行计划

> 基于 `20260815-优化.md`（31 条优化项）制定的可执行任务清单。
> 覆盖范围：P0（6 条）+ P1（14 条）+ P2（9 条）+ P3（2 项，含问题 27 方案 A + 问题 31 增强全部 6 项）。
> 技术栈：React 18 + Vite 5 / Express + Prisma + PostgreSQL / 见 `run.md`。

---

## 执行状态总览（2026-08-16 更新）

| 批次 | 优先级 | 任务数 | 完成数 | 状态 |
|------|--------|--------|--------|------|
| 第一批 | P0 紧急 | 6 条 | 6 条 | ✅ 全部完成 |
| 第二批 | P1 高 | 14 条 | 14 条 | ✅ 全部完成 |
| 第三批 | P2 中 | 9 条 | 9 条 | ✅ 全部完成 |
| 第四批 | P3 规划 | 2 项 | 2 项 | ✅ 全部完成 |
| 第五批 | 电子签署 | 12 条 | 12 条 | ✅ 全部完成（2026-08-16 新增） |
| **合计** | | **43 条** | **43 条** | **✅ 100% 完成** |

> 编译状态：前后端 TypeScript 编译均 0 错误。
> 数据库：Prisma schema 已同步（`prisma db push`），新增 8 个模型 + 2 个字段 + 1 个枚举值 + ESignRecord 扩展 7 个字段。
> 复查状态（2026-08-15）：TASK-024/025/026/027 验收标准已全部修复。
> 电子签署批次（2026-08-16）：TASK-031~042 全部完成，覆盖电子签署完整流程、线下手签、证据链体系、花名册操作联动。

---

## 批次总览

| 批次 | 优先级 | 任务数 | 目标 | 依赖 |
|------|--------|--------|------|------|
| 第一批 | P0 紧急 | 6 条 | 数据丢失/业务正确性/合规风险修复 | 无 |
| 第二批 | P1 高 | 14 条 | 流程阻塞/合规校验缺失修复 | 第一批完成 |
| 第三批 | P2 中 | 9 条 | 体验优化/功能增强 | 第二批完成（26 依赖 18/20/21/22/23） |
| 第四批 | P3 规划 | 2 项 | 组织架构+审批流 / 客服工作台增强 | 第三批完成 |
| 第五批 | 电子签署 | 12 条 | 电子签署完整流程+线下手签+证据链+花名册联动 | 无（独立批次） |

---

## 第一批：P0 紧急（6 条）

### TASK-001：全域保存草稿后部分录入数据未保存（问题 30）

- **目标**：确保所有流程页面的"保存草稿"功能完整持久化全部前端 state
- **对应需求**：问题 30
- **验收标准**：
  - [x] Termination 草稿保存后，`compAdjustments`（补偿金手动调整记录）可回读
  - [x] Termination 草稿保存后，`handoverItems` 的 remark（备注）可回读
  - [x] Termination 草稿保存后，`checklistOverrides`（合规检查覆盖原因）可回读
  - [x] WorkProcess 草稿保存后，自定义字段可回读
  - [x] 保存后立即回读对比，缺失字段时控制台告警
- **依赖**：无
- **优先级**：P0
- **阶段**：第一批
- **涉及文件**：
  - `frontend/src/pages/Termination.tsx`（`handleSaveDraft` payload 补全）
  - `frontend/src/pages/WorkProcess.tsx`（草稿 payload 补全）
  - `backend/src/services/termination.service.ts`（createDraft/updateDraft 字段映射）
  - `backend/src/services/work-process.service.ts`（草稿字段映射）
- **测试要求**：
  - 手工验证：Termination 填写补偿金调整 + 交接备注 → 保存草稿 → 重新进入 → 数据完整
  - 手工验证：WorkProcess 填写自定义字段 → 保存草稿 → 重新进入 → 数据完整

### TASK-002：手动调整补偿金分项后合计未同步（问题 7）

- **目标**：补偿金手动调整后，合计应付实时更新，保存与确认页使用实际合计值
- **对应需求**：问题 7
- **验收标准**：
  - [x] 调整任一补偿金分项后，"合计应付"显示实时刷新
  - [x] 实际合计 = `costResult.grandTotal + Σ(adjustments.to - adjustments.from)`
  - [x] `handleSave` 使用实际合计值，不再使用 `costResult.grandTotal`
  - [x] 确认步骤显示"系统预估 ¥X + 手动调整 ¥Y = 实际补偿 ¥Z"
  - [x] 后端 `compensationBreakdown.adjustments` 正确存储并回显
- **依赖**：TASK-001（草稿需先能保存 adjustments）
- **优先级**：P0
- **阶段**：第一批
- **涉及文件**：
  - `frontend/src/pages/Termination.tsx`（`handleSave`、确认步骤、step 3 合计显示）
  - `backend/src/services/termination.service.ts`（adjustments 存储与返回）
- **测试要求**：
  - 手工验证：系统预估补偿金 ¥50000 → 手动调整 severance ¥50000→¥45000 → 合计显示 ¥45000 → 保存 → 确认页显示 ¥45000

### TASK-003：解聘驳回后修改内容未更新（问题 10）

- **目标**：驳回后重新编辑草稿，修改的解聘类型/金额/日期等正确覆盖更新
- **对应需求**：问题 10
- **验收标准**：
  - [x] 驳回草稿再编辑走 `updateDraft`（而非新建），版本号 +1
  - [x] `updateDraft` 正确覆盖 `reason`、`compensationBreakdown`、`terminationDate`
  - [x] 前端进入驳回草稿时强制重新拉取最新数据（不使用缓存）
  - [x] 旧版本留快照，可查看历史版本
  - [x] 修改解聘类型后，补偿金按新类型重新计算
- **依赖**：TASK-002（补偿金合计逻辑需先正确）
- **优先级**：P0
- **阶段**：第一批
- **涉及文件**：
  - `frontend/src/pages/Termination.tsx`（编辑驳回草稿逻辑、进入时强制刷新）
  - `backend/src/services/termination.service.ts`（updateDraft 覆盖逻辑、版本快照）
  - `backend/src/routes/termination.routes.ts`（update 接口校验）
- **测试要求**：
  - 手工验证：创建解聘草稿（协商解除 ¥50000）→ 审批驳回 → 修改为过错解除 ¥0 → 保存 → 重新进入显示 ¥0

### TASK-004：违法解除降低补偿金后无合规风险提醒（问题 11）

- **目标**：违法解除（2N）场景下，实际补偿金低于法定 2N 时强制风险提醒
- **对应需求**：问题 11
- **验收标准**：
  - [x] 选择 ILLEGAL 后，实际补偿金 < 法定 2N 时，强制弹出合规风险提醒
  - [x] 需勾选"已知风险并继续"才能进入下一步
  - [x] 风险提醒记录到 `compensationBreakdown.riskAcknowledged`（含时间戳、用户、金额对比）
  - [x] 同步推送风险中心，生成风险项
  - [x] 金额变动后重新校验（不仅初始选择时）
- **依赖**：TASK-002（补偿金合计逻辑）
- **优先级**：P0
- **阶段**：第一批
- **涉及文件**：
  - `frontend/src/pages/Termination.tsx`（step 3 风险校验逻辑）
  - `backend/src/services/termination.service.ts`（riskAcknowledged 存储）
  - `backend/src/services/risk.service.ts`（风险项生成）
- **测试要求**：
  - 手工验证：选择违法解除 → 法定 2N=¥100000 → 手动改为 ¥80000 → 弹出风险提醒 → 必须勾选才能下一步

### TASK-005：合同结束日期早于开始日期未校验（问题 13）

- **目标**：合同开始/结束日期前后关系校验，杜绝时间倒置数据
- **对应需求**：问题 13
- **验收标准**：
  - [x] 前端 WorkProcess 所有含日期的表单（HIRE/ONBOARD/CUSTOM_CONTRACT/CHANGE/RENEW/SUSPEND）提交前校验 `endDate >= startDate`
  - [x] 校验失败时阻断提交并提示"结束日期不能早于开始日期"
  - [x] 后端 `work-process.service.ts` 增加同样校验，双保险
  - [x] 历史倒置数据：提供查询列表提示（不自动修复，由用户确认后修复）
- **依赖**：无
- **优先级**：P0
- **阶段**：第一批
- **涉及文件**：
  - `frontend/src/pages/WorkProcess.tsx`（表单提交前校验）
  - `backend/src/services/work-process.service.ts`（后端校验）
  - `backend/src/routes/contract.routes.ts`（历史倒置数据查询接口）
- **测试要求**：
  - 手工验证：新建合同 → 开始日期 2026-06-01 → 结束日期 2026-05-31 → 提交被阻断
  - 手工验证：后端直接调用 API 传倒置日期 → 返回 400

### TASK-006：补偿金批次经济补偿金发放数据读取错误（问题 28）

- **目标**：补偿金批次（SEVERANCE 类型）正确从离职草稿读取补偿金数据
- **对应需求**：问题 28
- **验收标准**：
  - [x] `createBatch` 当 `type=SEVERANCE` 时，数据源从已审批通过的 `termination_draft` 读取 `compensationBreakdown.grandTotal`
  - [x] 员工范围：仅包含有未发放补偿金的离职员工
  - [x] 创建前增加预览页，展示每位员工的补偿金明细（补偿金/代通知金/赔偿金/合计）
  - [x] 确认后再创建批次
  - [x] 不再读取工资数据作为补偿金
- **依赖**：TASK-002（补偿金合计需先正确）
- **优先级**：P0
- **阶段**：第一批
- **涉及文件**：
  - `frontend/src/pages/money/BatchTab.tsx`（SEVERANCE 创建流程、预览页）
  - `backend/src/services/payroll.service.ts`（SEVERANCE 分支数据源修正）
  - `backend/src/routes/payroll2.routes.ts`（预览接口）
- **测试要求**：
  - 手工验证：员工 A 离职补偿金 ¥50000（已审批）→ 创建补偿金批次 → 预览显示 ¥50000 → 确认创建 → 批次数据正确

---

## 第二批：P1 高（14 条）

### TASK-007：离职日期调整后联动社保/公积金截止年月（问题 2）

- **目标**：离职日期变更时自动推导社保/公积金截止月，支持 15 日前后规则可配置
- **对应需求**：问题 2
- **验收标准**：
  - [x] 离职日期变更时自动回填社保截止月、公积金截止月
  - [x] 规则：每月 cutoffDay（默认 15）日前离职 → 截止月 = 离职月 - 1；cutoffDay 日后离职 → 截止月 = 离职月
  - [x] `org_settings` 新增 `socialInsCutoffDay` 字段（默认 15），系统设置可配置
  - [x] 保留手动覆盖入口（用户可手动修改截止月）
  - [x] 手动覆盖时提示"与自动推导不一致"
- **依赖**：无
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/Termination.tsx`（离职日期变更联动）
  - `backend/src/services/termination.service.ts`（自动推导逻辑）
  - `backend/prisma/schema.prisma`（Organization 新增 `socialInsCutoffDay Int @default(15)`）
  - `frontend/src/pages/Settings.tsx`（配置入口）
- **DB 变更**：`Organization` 新增 `socialInsCutoffDay` 字段，migration + 回滚方案
- **测试要求**：
  - 手工验证：离职日期 2026-08-10（10 日 < 15 日）→ 社保截止 2026-07 → 公积金截止 2026-07
  - 手工验证：离职日期 2026-08-20（20 日 > 15 日）→ 社保截止 2026-08 → 公积金截止 2026-08
  - 手工验证：修改 cutoffDay 为 10 → 离职日期 2026-08-15 → 社保截止 2026-08

### TASK-008：合规检查"已支付经济补偿金"改为软阻断+待办（问题 3）

- **目标**：合规检查未勾选项可下一步，但自动写入待办和风险提醒
- **对应需求**：问题 3
- **验收标准**：
  - [x] step 2 合规检查未勾选 required 项时，可进入下一步（不硬阻断）
  - [x] 未勾选的 required 项自动写入待办事项，关联 `termination_draft`
  - [x] Dashboard/风险中心展示"XX 员工解聘未支付经济补偿金"等待办
  - [x] 提交审批时若仍存在未闭环必检项，给出强提示但不阻断
  - [x] 法定禁止情形（孕期/工伤/医疗期）仍硬阻断
- **依赖**：无
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/Termination.tsx`（step 2 校验逻辑改为软阻断）
  - `backend/src/services/notification.service.ts`（待办生成）
  - `backend/src/services/risk.service.ts`（风险提醒生成）
  - `frontend/src/pages/Dashboard.tsx`（待办展示）
- **测试要求**：
  - 手工验证：合规检查不勾"已支付经济补偿金" → 可下一步 → Dashboard 出现待办"XX 解聘未支付经济补偿金"

### TASK-009：补偿月数支持 N / N+1 / 2N / 其他（问题 5）

- **目标**：补偿月数改为下拉选择，支持手动修改并重算补偿金
- **对应需求**：问题 5
- **验收标准**：
  - [x] 补偿月数改为下拉：N（默认）、N+1、2N、其他（自定义输入）
  - [x] 选择"协商解除"时允许修改月数
  - [x] 月数变更后实时重算补偿金 = 月数 × 计算基数
  - [x] 选择"其他"时需填写说明，留痕到 `compensationBreakdown.adjustments`
  - [x] 系统计算值 N 仍作为默认推荐显示
- **依赖**：TASK-002（补偿金合计逻辑）
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/Termination.tsx`（step 3 补偿月数下拉）
  - `backend/src/services/termination.service.ts`（月数模式存储）
- **测试要求**：
  - 手工验证：系统算 N=3 → 选择 N+1 → 月数变 4 → 补偿金重算 → 选择"其他"→ 输入 5 + 说明 → 补偿金重算

### TASK-010：计算基数支持多种来源（问题 6）

- **目标**：计算基数改为下拉选择，支持多种来源切换
- **对应需求**：问题 6
- **验收标准**：
  - [x] 计算基数改为下拉：近 12 月平均工资（默认）、合同工资、其他（手动填写）
  - [x] 切换来源后实时重算补偿金
  - [x] 选用算法记录到草稿 `compensationBreakdown.wageBaseType`
  - [x] "其他"需填写说明，受三倍社平封顶提示但不强制
  - [x] 近 12 月平均工资仍显示三倍社平封顶后的值
- **依赖**：TASK-009（月数与基数联动重算）
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/Termination.tsx`（step 3 计算基数下拉）
  - `backend/src/services/termination.service.ts`（wageBaseType 存储）
- **测试要求**：
  - 手工验证：默认近 12 月平均 ¥10000 → 切换为合同工资 ¥8000 → 补偿金重算 → 切换为"其他"→ 手动输入 ¥12000 + 说明 → 重算

### TASK-011：工作交接未完成改为软阻断+待办（问题 8）

- **目标**：工作交接未完成可下一步，未完成事项进入待办提醒
- **对应需求**：问题 8
- **验收标准**：
  - [x] step 4 工作交接未完成时可进入下一步（不硬阻断）
  - [x] 交接清单前三项（work_handover/equipment_return/access_revoke）标注"离职必办"
  - [x] 未完成事项自动写入待办，关联离职草稿
  - [x] 确认页和风险中心强提示未完成交接项
  - [x] 待办在到达离职日期前持续提醒，超期升级为风险
- **依赖**：TASK-008（待办机制复用）
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/Termination.tsx`（step 4 校验改为软阻断、确认页提示）
  - `backend/src/services/notification.service.ts`（待办生成与提醒）
- **测试要求**：
  - 手工验证：工作交接不勾"工作交接完成" → 可下一步 → 确认页提示"3 项未完成" → Dashboard 出现待办

### TASK-012：离职管理"新建解聘"并入花名册操作栏（问题 9）

- **目标**：花名册操作栏"离职"按钮支持所有解聘类型，离职管理列表页移除新建入口
- **对应需求**：问题 9
- **验收标准**：
  - [x] 花名册操作栏"离职"按钮点击后弹出解聘类型选择（协商/过错/非过错/裁员/到期/违法/主动离职）
  - [x] 选择类型后跳转 Termination 向导，URL 带参数预填员工 ID 和解聘类型
  - [x] Termination 向导支持从 URL 参数读取 `employeeId` 和 `reason` 自动预填
  - [x] 离职管理列表页移除"新建解聘"按钮，仅保留草稿列表与审批
  - [x] 主动离职（RESIGNATION）仍走原 ResignModal 快速流程
- **实际实现状态（2026-08-15 复查）**：
  - ✅ 花名册离职按钮弹出 ResignModal，支持7种解聘类型选择
  - ✅ 非主动离职类型跳转 `/termination?employeeId=xxx&reason=xxx`
  - ✅ Termination 向导从 URL 参数读取 employeeId 和 reason 预填
  - ✅ 列表页已移除"新建解聘"按钮（2026-08-15 已确认移除）
  - ✅ 主动离职走 ResignModal 快速流程
  - ⚠️ 成功页面（第1962行）仍保留"新建解聘"按钮 — 属于流程内继续操作，可接受
- **依赖**：无
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/Roster.tsx`（操作栏离职按钮扩展）
  - `frontend/src/pages/roster/modals.tsx`（ResignModal 扩展或新增类型选择 Modal）
  - `frontend/src/pages/Termination.tsx`（URL 参数预填支持）
- **测试要求**：
  - 手工验证：花名册点击员工"离职" → 弹出类型选择 → 选择"协商解除" → 跳转 Termination → 员工和类型已预填

### TASK-013：合同续签新增合同开始日期自动推导（问题 12）

- **目标**：续签合同时，新合同开始日期默认 = 上一份合同结束日期 + 1 天
- **对应需求**：问题 12
- **验收标准**：
  - [x] RENEW 表单选择员工后，自动拉取最新已签合同
  - [x] `newStartDate` 默认 = 上一份合同 `endDate + 1 天`
  - [x] 允许手动覆盖，偏离时提示"建议开始日期为 YYYY-MM-DD"
  - [x] 无历史合同时默认为今天
- **依赖**：TASK-005（日期校验）
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/WorkProcess.tsx`（RENEW 字段联动）
  - `backend/src/services/work-process.service.ts`（查询员工最新合同）
- **测试要求**：
  - 手工验证：员工合同结束日期 2026-05-31 → 新增续签 → 新合同开始日期自动填 2026-06-01

### TASK-014：添加员工根据证件号码进行年龄合规筛查（问题 15）

- **目标**：解析证件号码自动计算年龄，童工阻断、退休提示
- **对应需求**：问题 15
- **验收标准**：
  - [x] 解析身份证号出生日期，计算年龄
  - [x] 年龄 < 16 岁：禁止录入，强提示"禁止使用童工（未满 16 周岁）"，阻断保存
  - [x] 年龄 ≥ 60（男）/55（女干部）/50（女工人）：提示"已达法定退休年龄"，确认后允许录入，自动标记 `retirementFlag`
  - [x] 年龄校验在 `handleIdCardChange` 中实时执行
- **依赖**：无
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/roster/modals.tsx`（`handleIdCardChange` 增加年龄校验）
  - `backend/src/routes/employee.routes.ts`（后端年龄校验双保险）
- **测试要求**：
  - 手工验证：身份证号出生日期 2015-01-01（11 岁）→ 阻断提示"禁止使用童工"
  - 手工验证：身份证号出生日期 1965-01-01（61 岁男）→ 提示"已达法定退休年龄" → 确认后可录入

### TASK-015：编辑入职日期后状态联动变更（问题 16）

- **目标**：编辑入职日期后，员工状态自动联动
- **对应需求**：问题 16
- **验收标准**：
  - [x] 编辑入职日期 > 今天 → 状态自动设为 `PENDING_ONBOARD`（待入职）
  - [x] 编辑入职日期 ≤ 今天 → 状态自动设为 `ACTIVE`（在职）
  - [x] 状态变更需二次确认弹窗"入职日期变更将导致状态从 XX 变为 YY，是否继续？"
  - [x] 变更记录留痕到员工档案（操作日志）
- **依赖**：无
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/roster/BasicInfo.tsx`（入职日期编辑联动状态确认）
  - `backend/src/services/employee.service.ts`（状态联动逻辑）
- **测试要求**：
  - 手工验证：在职员工入职日期改为下月 1 日 → 弹窗确认 → 状态变为"待入职"
  - 手工验证：待入职员工入职日期改为今天 → 弹窗确认 → 状态变为"在职"

### TASK-016：员工转正移植到花名册操作栏（问题 18）

- **目标**：花名册操作栏"发薪"按钮替换为"转正"按钮
- **对应需求**：问题 18
- **验收标准**：
  - [x] 操作栏"发薪"按钮（Wallet 图标）替换为"转正"按钮（CheckCircle 图标）
  - [x] 仅试用期员工（`probationInfo.isProbation === true`）显示转正按钮
  - [x] 点击弹出转正 Modal（转正日期 + 转正薪资）
  - [x] 转正完成后员工状态从试用期转为正式
  - [x] 发薪入口保留在薪税管理模块（移除操作栏发薪按钮不影响薪税功能）
- **依赖**：无
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/Roster.tsx`（操作栏按钮替换）
  - `frontend/src/pages/roster/modals.tsx`（新增 `ConfirmModal`）
  - `backend/src/services/employee.service.ts`（转正接口）
- **测试要求**：
  - 手工验证：试用期员工操作栏显示"转正"按钮 → 点击 → 填写转正日期+薪资 → 确认 → 状态变为正式

### TASK-017：转正薪资回写花名册+用工协议匹配校验（问题 19）

- **目标**：转正完成后同步更新员工薪资，校验与合同薪资一致性
- **对应需求**：问题 19
- **验收标准**：
  - [x] 转正完成后同步更新员工 `monthlySalary`
  - [x] 花名册明细展示"试用期薪资 → 转正薪资"变更记录
  - [x] 校验转正薪资与最新合同 `monthlySalary` 是否一致
  - [x] 不一致时提示"转正薪资 ¥X 与合同薪资 ¥Y 不一致，是否发起合同变更？"
  - [x] 支持一键跳转合同变更流程（CHANGE）
- **依赖**：TASK-016（转正功能）
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `backend/src/services/work-process.service.ts`（CONFIRM 完成回调更新薪资）
  - `frontend/src/pages/roster/SalaryInfo.tsx`（薪资变更记录展示）
  - `frontend/src/pages/Roster.tsx`（不一致提示与跳转）
- **测试要求**：
  - 手工验证：试用期薪资 ¥8000 → 转正填写 ¥10000 → 确认 → 花名册薪资更新为 ¥10000 → 如合同薪资 ¥9000 → 提示不一致

### TASK-018：合同变更/续签选择员工后过滤合同列表（问题 22+23）

- **目标**：contract-select 组件按员工过滤合同，RENEW 的 oldContractId 改为下拉选择
- **对应需求**：问题 22 + 问题 23
- **验收标准**：
  - [x] `contract-select` 组件接收 `employeeId` 参数，仅返回该员工的有效合同
  - [x] CHANGE 表单选择员工后，合同下拉仅显示该员工合同
  - [x] RENEW 表单 `oldContractId` 从 `text` 改为 `contract-select`，选择员工后下拉展示该员工已存在合同
  - [x] 后端合同查询接口支持 `employeeId` 过滤
  - [x] 合同下拉显示合同名称 + 起止日期 + 状态
- **依赖**：无
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/WorkProcess.tsx`（contract-select 组件改造、RENEW 字段类型）
  - `backend/src/routes/contract.routes.ts`（employeeId 过滤）
- **测试要求**：
  - 手工验证：合同变更 → 选择员工 A → 合同下拉仅显示员工 A 的合同
  - 手工验证：合同续签 → 选择员工 A → 原合同下拉显示员工 A 的已签合同（非 UUID 手输）

### TASK-019：男职工无法选择三期（问题 29）

- **目标**：特殊员工表单根据性别过滤类型，男职工不可选三期
- **对应需求**：问题 29
- **验收标准**：
  - [x] 选择员工后，若 `gender === '男'`，类型下拉移除"三期"选项或置灰
  - [x] 置灰时提示"三期仅适用于女性员工"
  - [x] 后端保存时增加校验：男职工 + PREGNANCY 组合返回 400
  - [x] 编辑已有记录时，如原记录为三期但员工为男性（历史脏数据），提示修正
- **依赖**：无
- **优先级**：P1
- **阶段**：第二批
- **涉及文件**：
  - `frontend/src/pages/SpecialStatus.tsx`（表单 type 下拉过滤）
  - `backend/src/services/special-status.service.ts`（后端校验）
- **测试要求**：
  - 手工验证：选择男员工 → 类型下拉无"三期" → 后端直接传 PREGNANCY → 返回 400

---

## 第三批：P2 中（9 条）

### TASK-020："劳动合同"调整为"用工关系"（问题 1）

- **目标**：全域面向用户文案中"劳动合同"在合适场景改为"用工关系"或"用工协议"
- **对应需求**：问题 1
- **验收标准**：
  - [x] 全域文案审计完成，列出所有"劳动合同"出现位置
  - [x] 面向用户的菜单/标题/提示中"劳动合同"改为"用工关系"或"用工协议"
  - [x] 法律文书模板中的"劳动合同"保持不变（法定术语）
  - [x] `Contract` 模型新增 `contractCategory` 字段（LABOR_CONTRACT/LABOR_AGREEMENT/INTERNSHIP/FLEXIBLE）
  - [x] HelpModal、OnboardingGuide 帮助文案同步更新
- **依赖**：无
- **优先级**：P2
- **阶段**：第三批
- **涉及文件**：`SidebarNav.tsx`、`Contracts.tsx`、`WorkProcess.tsx`、`Termination.tsx`、`HelpModal.tsx`、`OnboardingGuide.tsx` 等
- **DB 变更**：`LaborContract` 新增 `contractCategory` 字段（nullable，默认 LABOR_CONTRACT）
- **测试要求**：全域搜索"劳动合同"确认无遗漏（法律文书模板除外）

### TASK-021：费用结算新增"剩余年假天数"（问题 4）

- **目标**：费用结算区新增年假折算，计入合计应付
- **对应需求**：问题 4
- **验收标准**：
  - [x] 费用结算区新增"剩余年假天数"字段（手动录入或调用考勤年假余额）
  - [x] 按规则计算未休年假折算工资：`日工资 × 剩余年假天数 × 300%`
  - [x] 日工资 = 月工资 / 21.75
  - [x] 折算金额计入"合计应付"
  - [x] 年假折算明细在确认页和文书中展示
- **依赖**：TASK-002（合计计算逻辑）
- **优先级**：P2
- **阶段**：第三批
- **涉及文件**：
  - `frontend/src/pages/Termination.tsx`（step 3 年假字段）
  - `backend/src/services/termination.service.ts`（年假折算计算）
- **测试要求**：
  - 手工验证：剩余年假 5 天 → 日工资 ¥460（¥10000/21.75）→ 折算 ¥6900（5×460×300%）→ 合计应付包含 ¥6900

### TASK-022：身份证号全域改为"证件号码"（问题 14）

- **目标**：全域 label "身份证号"改为"证件号码"，支持证件类型下拉
- **对应需求**：问题 14
- **验收标准**：
  - [x] 全域 label "身份证号"替换为"证件号码"
  - [x] 字段名 `idCardNumber` 保持不变（兼容历史数据）
  - [x] 新增证件类型下拉（身份证/护照/港澳台通行证/其他），存储到 `idType` 字段
  - [x] 证件类型为"身份证"时保留 18 位校验 + 性别/年龄自动推导
  - [x] 非身份证类型时跳过 18 位校验
  - [x] 搜索 placeholder 同步更新
- **依赖**：TASK-014（年龄校验需适配证件类型）
- **优先级**：P2
- **阶段**：第三批
- **涉及文件**：`roster/modals.tsx`、`WorkProcess.tsx`、`Roster.tsx`、`SpecialStatus.tsx`、`BasicInfo.tsx` 等
- **DB 变更**：`Employee` 新增 `idType` 字段（nullable，默认 ID_CARD）
- **测试要求**：全域搜索"身份证号"确认无遗漏

### TASK-023：录入手机号查重（问题 17）

- **目标**：手机号录入时查重，已存在提示"该手机号已用于 XX 人员"
- **对应需求**：问题 17
- **验收标准**：
  - [x] 手机号录入时调用查重接口
  - [x] 已存在则提示"该手机号已用于 XX 人员"
  - [x] 允许继续保存（一人多号/家庭号场景），但强提示确认
  - [x] 后端新增 `/employees/check-phone` 接口
  - [x] 手机号格式校验（11 位数字）
- **依赖**：无
- **优先级**：P2
- **阶段**：第三批
- **涉及文件**：
  - `frontend/src/pages/roster/modals.tsx`（手机号查重）
  - `backend/src/routes/employee.routes.ts`（新增查重接口）
- **测试要求**：
  - 手工验证：录入已存在手机号 → 提示"该手机号已用于 张三 人员" → 可继续保存

### TASK-024：开具证明移植到花名册操作栏（问题 20）

- **目标**：操作栏新增"证明"按钮，支持快速开具证明
- **对应需求**：问题 20
- **验收标准**：
  - [x] 操作栏新增"证明"按钮（FileText 图标）
  - [x] 点击弹出证明类型选择（收入证明/离职证明/在职证明）
  - [x] 复用 WorkProcess 的 INCOME_CERT/LEAVING_CERT 表单
  - [x] 生成后支持下载/打印
- **实际实现状态（2026-08-15 复查）**：
  - ✅ 操作栏有"证明"按钮（FileText 图标）
  - ✅ 已增加证明类型选择（收入证明/在职证明/离职证明）— 已修复
- **依赖**：无
- **优先级**：P2
- **阶段**：第三批
- **涉及文件**：
  - `frontend/src/pages/Roster.tsx`（操作栏新增按钮）
  - `frontend/src/pages/roster/modals.tsx`（证明类型选择 Modal）
- **测试要求**：
  - 手工验证：点击操作栏"证明" → 选择"收入证明" → 填写信息 → 生成 → 可下载

### TASK-025：合同续签移植到花名册操作栏（问题 21）

- **目标**：操作栏新增"续签"按钮，合同即将到期时显示
- **对应需求**：问题 21
- **验收标准**：
  - [x] 操作栏新增"续签"按钮（Repeat 图标）
  - [x] 仅合同即将到期（≤30 天）或已到期员工显示
  - [x] 点击跳转 WorkProcess RENEW 并预填员工（URL 参数）
  - [x] WorkProcess 支持从 URL 参数读取 `employeeId` 自动预填
- **实际实现状态（2026-08-15 复查）**：
  - ✅ 操作栏有"续签"按钮（RotateCcw 图标）
  - ✅ 已按合同到期状态过滤（仅 expiring/expired 显示）— 已修复
  - ⚠️ 在花名册弹窗处理续签，未跳转 WorkProcess — 可接受（体验更流畅）
- **依赖**：TASK-013（续签开始日期自动推导）、TASK-018（合同选择）
- **优先级**：P2
- **阶段**：第三批
- **涉及文件**：
  - `frontend/src/pages/Roster.tsx`（操作栏新增按钮）
  - `frontend/src/pages/WorkProcess.tsx`（URL 参数预填）
- **测试要求**：
  - 手工验证：合同 25 天后到期 → 操作栏显示"续签"按钮 → 点击 → 跳转 RENEW → 员工已预填

### TASK-026：花名册多选增加批量转正（问题 24）

- **目标**：多选员工后支持批量转正
- **对应需求**：问题 24
- **验收标准**：
  - [x] 多选后新增"批量转正"按钮，仅对试用期员工生效
  - [x] 弹窗统一填写转正日期（默认今天）和转正薪资
  - [x] 转正薪资支持"按原薪资倍数"或"手动逐人填写"
  - [x] 调用后端批量转正接口
  - [x] 复用 TASK-016 的转正逻辑
- **实际实现状态（2026-08-15 复查）**：
  - ✅ 多选后有"批量转正"按钮，仅对试用期员工生效
  - ✅ 已增加弹窗填写转正日期和薪资 — 已修复
- **依赖**：TASK-016（单人转正）、TASK-017（薪资回写）
- **优先级**：P2
- **阶段**：第三批
- **涉及文件**：
  - `frontend/src/pages/Roster.tsx`（批量操作栏新增按钮）
  - `frontend/src/pages/roster/modals.tsx`（批量转正 Modal）
  - `backend/src/services/employee.service.ts`（批量转正接口）
- **测试要求**：
  - 手工验证：多选 3 名试用期员工 → 批量转正 → 填写统一日期+薪资 → 确认 → 3 人状态均变为正式

### TASK-027：花名册多选增加批量开具证明（问题 25）

- **目标**：多选员工后支持批量开具证明
- **对应需求**：问题 25
- **验收标准**：
  - [x] 多选后新增"批量开具证明"按钮
  - [x] 选择证明类型（在职/收入）后批量生成
  - [x] 支持批量下载（ZIP）或逐个下载
  - [x] 后端新增批量生成接口
- **实际实现状态（2026-08-15 复查）**：
  - ✅ 多选后有"批量开具证明"按钮
  - ✅ 已增加证明类型选择（收入证明/在职证明/离职证明）— 已修复
  - ⚠️ 未实现 ZIP 批量下载，仅提示去证据管理查看 — 体验可接受
- **依赖**：TASK-024（单人开具证明）
- **优先级**：P2
- **阶段**：第三批
- **涉及文件**：
  - `frontend/src/pages/Roster.tsx`（批量操作栏新增按钮）
  - `backend/src/services/work-process.service.ts`（批量生成接口）
- **测试要求**：
  - 手工验证：多选 3 名员工 → 批量开具在职证明 → 生成 3 份 → 可批量下载 ZIP

### TASK-028：去掉用工办理模块（问题 26）

- **目标**：侧边栏移除"用工办理"菜单，入口下沉到花名册操作栏和独立页面
- **对应需求**：问题 26
- **验收标准**：
  - [x] 各流程入口已下沉：转正（TASK-016）、续签（TASK-025）、变更（TASK-018）、开具证明（TASK-024）、入职（保留在花名册添加员工）
  - [x] 侧边栏移除"用工办理"菜单项
  - [x] WorkProcess 页面保留作为批量流程入口，迁移到"更多"分组或保留路由但不显示菜单
  - [x] 已有 WorkProcess 草稿列表仍可访问（不丢数据）
  - [x] 帮助文案同步更新
- **依赖**：TASK-016、TASK-018、TASK-024、TASK-025 全部完成
- **优先级**：P2
- **阶段**：第三批（最后执行）
- **涉及文件**：
  - `frontend/src/components/layout/SidebarNav.tsx`（移除菜单项）
  - `frontend/src/pages/Roster.tsx`（确认所有入口已下沉）
  - `frontend/src/App.tsx`（路由保留但菜单移除）
  - `frontend/src/components/HelpModal.tsx`（帮助文案更新）
- **测试要求**：
  - 手工验证：侧边栏无"用工办理" → 花名册操作栏可完成转正/续签/变更/证明 → WorkProcess 页面仍可通过 URL 访问

---

## 第四批：P3 规划（2 项）

### TASK-029：组织架构+简单审批流（问题 27，方案 A）

- **目标**：新增组织架构模块（树形部门+岗位字典+上下级关系），支持三步以内审批流转
- **对应需求**：问题 27（方案 A：保留 position 单字段，岗位独立建表）
- **验收标准**：
  - [x] **组织架构子页**：系统设置新增"组织架构"
    - 树形部门管理（`Department` 自引用 parent，支持增删改查、拖拽排序）
    - 岗位字典（`Position`，含名称/所属部门/编制人数/职级）
    - 员工 `position` 字段关联岗位字典（可选，兼容旧文本数据）
    - 上下级关系（`Employee.supervisorId`）
  - [x] **审批流配置**：
    - 最多 3 步（发起人 → 直属上级 → 部门负责人）
    - 按流程类型（休假/离职/调薪）配置是否启用某步
    - 审批人可指定"直属上级"或"具体人员"
  - [x] **现有流程接入**：
    - `LeaveApproval` 接入审批流引擎
    - 离职/调薪等流程可选启用审批流
  - [x] **数据模型**：
    - `Department`（id/name/parentId/level/sortOrder/orgId）
    - `Position`（id/name/departmentId/headcount/level/orgId）
    - `Employee` 新增 `supervisorId`、`departmentId`（关联 Department，兼容旧 department 字符串）
    - `ApprovalFlow`（id/type/steps/config/orgId）
    - `ApprovalInstance`（id/flowId/status/currentStep/approver/result/createdAt）
- **依赖**：第三批完成
- **优先级**：P3
- **阶段**：第四批
- **涉及文件**：
  - 新增 `frontend/src/pages/OrgChart.tsx`（组织架构可视化）
  - `frontend/src/pages/Settings.tsx`（新增组织架构 Tab）
  - `backend/prisma/schema.prisma`（Department/Position/ApprovalFlow/ApprovalInstance 模型）
  - 新增 `backend/src/services/approval.service.ts`（审批流引擎）
  - 新增 `backend/src/routes/department.routes.ts`、`backend/src/routes/position.routes.ts`、`backend/src/routes/approval.routes.ts`
  - `frontend/src/pages/LeaveApproval.tsx`（接入审批流）
- **DB 变更**：新增 4 个模型 + Employee 2 个字段，migration + 回滚方案 + seed 数据
- **测试要求**：
  - 手工验证：创建部门"技术部" → 创建岗位"前端工程师" → 员工关联部门和岗位 → 配置休假审批流（直属上级→部门负责人）→ 提交休假申请 → 直属上级审批 → 部门负责人审批 → 通过

### TASK-030：客服工作台增强（问题 31 增强全部 6 项）

- **目标**：在平台管理端基础上扩展客服工作台功能
- **对应需求**：问题 31 增强部分
- **验收标准**：
  - [x] **角色与路由**：
    - 新增 `SUPPORT` 角色
    - 独立路由 `/support/*`，独立登录页 `/support/login`
    - 独立侧边栏 `SupportSidebar`
  - [x] **工单管理**：
    - `Ticket` 模型（标题/内容/状态/优先级/归属租户/处理人）
    - `TicketMessage` 模型（工单回复）
    - 工单列表、详情、回复、关闭、转派
    - 客户端（企业端）可提交工单
  - [x] **客户会话**：
    - `ChatSession` 模型（客户会话）
    - 客服与客户企业管理员实时沟通或留言
    - 未读消息提醒
  - [x] **租户数据穿透**：
    - 客服选择租户后，以"只读+代操作"模式访问该租户业务数据
    - 请求头带 `X-Support-Tenant-Id`，后端中间件切换租户上下文
    - 可查看花名册/合同/薪税/风险等数据
  - [x] **协助操作**：
    - 代客户重置密码（已有，复用）
    - 代客户调整套餐（已有，复用）
    - 代客户发起流程（新增）
  - [x] **AI 辅助**：
    - 客服侧 AI 问答，复用现有 AI 接口
    - 独立会话隔离，不影响客户企业 AI 用量
  - [x] **操作日志**：
    - 客服操作留痕审计
    - `AuditLog` 扩展支持客服角色操作记录
- **依赖**：第三批完成
- **优先级**：P3
- **阶段**：第四批
- **涉及文件**：
  - 新增 `frontend/src/pages/support/*`（SupportDashboard/Tickets/Chat/TenantData/AI/Logs）
  - 新增 `frontend/src/components/layout/SupportSidebar.tsx`
  - `backend/prisma/schema.prisma`（Ticket/TicketMessage/ChatSession 模型，User.role 新增 SUPPORT）
  - 新增 `backend/src/routes/support.routes.ts`
  - 新增 `backend/src/middleware/support-tenant.ts`（租户上下文切换）
  - `backend/src/routes/platform.routes.ts`（工单/会话接口复用）
- **DB 变更**：新增 3 个模型 + User.role 枚举新增 SUPPORT，migration + 回滚方案
- **测试要求**：
  - 手工验证：客服登录 → 查看工单列表 → 回复工单 → 选择租户 → 穿透查看花名册 → AI 辅助问答 → 操作日志记录

---

## 第五批：电子签署完整流程 + 线下手签 + 证据链体系（2026-08-16 新增）

> 背景：原系统电子签署模块存在两套并行且互不连通的签署机制、无实际签署流程、无证据链集成、无验证码确认、无线下手签支持等问题。本批次系统性重构电子签署模块，建立完整的法律证据链体系。

### TASK-031：电子签署后端路由重写 + 模板自动渲染（P0）

- **目标**：重写 esign.routes.ts，支持完整的电子签署发起流程，自动从模板渲染文件内容
- **对应需求**：电子签署逻辑审计 P0-1/P1-1
- **验收标准**：
  - [x] 发起签署时校验组织电子签开关（POLICY/PAYSLIP/ONBOARDING）
  - [x] 自动从模板渲染文件内容（CONTRACT→劳动合同模板，RESIGNATION→离职协议模板）
  - [x] 创建签署记录时自动创建证据链（发起签署事件）
  - [x] 新增签署详情接口、证据链查看接口
  - [x] 取消签署追加证据链事件
  - [x] 签署状态查询自动处理过期记录
- **依赖**：无
- **优先级**：P0
- **阶段**：第五批
- **涉及文件**：
  - `backend/src/routes/esign.routes.ts`（重写）
  - `backend/src/services/template.service.ts`（renderTemplate/getTemplateById 集成）
  - `backend/src/services/evidence.service.ts`（createEvidence 集成）
- **测试要求**：
  - 手工验证：发起劳动合同签署 → 自动渲染模板内容 → 创建证据链 → 详情页可查看

### TASK-032：员工端签署验证码确认机制（P0）

- **目标**：员工端签署增加手机验证码确认，确保签署行为真实性
- **对应需求**：电子签署逻辑审计 P0-1
- **验收标准**：
  - [x] 员工端新增验证码发送接口（/esign/:id/send-code）
  - [x] 签署操作增加验证码校验（5次错误限制 + 60秒限流）
  - [x] 签署完成追加证据链（IP/UA/时间戳/验证码/签署人）
  - [x] 签署完成回写合同 signMethod + attachmentName（签署证据）
  - [x] 列表和详情接口自动处理过期记录
- **依赖**：TASK-031
- **优先级**：P0
- **阶段**：第五批
- **涉及文件**：
  - `backend/src/routes/portal.routes.ts`（员工端 esign 重写）
  - `backend/src/services/codeStore.ts`（setCode/getCode/checkRateLimit）
- **测试要求**：
  - 手工验证：员工查看待签文件 → 获取验证码 → 输入验证码 → 签署完成 → 证据链记录

### TASK-033：签署全流程证据链体系（P0）

- **目标**：签署全流程（发起/验证码发送/签署完成/取消）自动记录证据链，确保法律效力
- **对应需求**：电子签署逻辑审计 P0-2
- **验收标准**：
  - [x] 发起签署时创建证据链（事件1：发起签署）
  - [x] 发送验证码时追加证据链（事件2：验证码发送）
  - [x] 签署完成时追加证据链（事件3：签署完成，含IP/UA/时间戳/验证码/签署人）
  - [x] 取消签署时追加证据链（事件4：取消签署）
  - [x] 证据链包含 hash 值用于完整性校验
  - [x] 管理端详情页可查看完整证据链时间线
- **依赖**：TASK-031、TASK-032
- **优先级**：P0
- **阶段**：第五批
- **涉及文件**：
  - `backend/src/routes/esign.routes.ts`（发起/取消证据链）
  - `backend/src/routes/portal.routes.ts`（验证码/签署完成证据链）
  - `backend/src/services/evidence.service.ts`（createEvidence/appendEvidence）
- **测试要求**：
  - 手工验证：完整签署流程 → 详情页证据链显示3-4个事件 → 含时间戳/IP/操作人

### TASK-034：签署完成回写合同 + 生成签署证据（P1）

- **目标**：签署完成后自动回写合同签署方式，生成签署证据文件
- **对应需求**：电子签署逻辑审计 P1-3
- **验收标准**：
  - [x] 签署完成回写合同 signMethod=ELECTRONIC
  - [x] 回写合同 attachmentName（含IP/UA/时间戳证据摘要）
  - [x] 签署证据写入 callbackData
  - [x] 对接易签宝后自动回写 signedPdfUrl（预留接口）
- **依赖**：TASK-032
- **优先级**：P1
- **阶段**：第五批
- **涉及文件**：
  - `backend/src/routes/portal.routes.ts`（签署完成回写逻辑）
- **测试要求**：
  - 手工验证：劳动合同签署完成 → 合同 signMethod 变为 ELECTRONIC → attachmentName 包含证据摘要

### TASK-035：组织电子签开关校验（P1）

- **目标**：发起签署前校验组织级别的电子签开关，未开启的场景不允许发起
- **对应需求**：电子签署逻辑审计 P1-2
- **验收标准**：
  - [x] 发起签署前校验 SCENE_ORG_FLAG_MAP 对应的组织开关
  - [x] CONTRACT/RESIGNATION 场景默认允许（不依赖开关）
  - [x] POLICY/PAYSLIP/ONBOARDING 场景需对应开关开启
  - [x] 开关未开启时返回明确错误提示
- **依赖**：TASK-031
- **优先级**：P1
- **阶段**：第五批
- **涉及文件**：
  - `backend/src/routes/esign.routes.ts`（开关校验逻辑）
- **测试要求**：
  - 手工验证：组织未开启 POLICY 开关 → 发起规章制度签署 → 返回错误提示

### TASK-036：scene 关联模板自动填充 + 过期自动处理（P2）

- **目标**：签署场景与模板自动关联，过期记录自动标记
- **对应需求**：电子签署逻辑审计 P2-1
- **验收标准**：
  - [x] SCENE_TEMPLATE_MAP 映射（CONTRACT→劳动合同，RESIGNATION→离职协议）
  - [x] 前端场景选择后自动填充默认文件标题
  - [x] 列表/详情/状态查询时自动将过期 PENDING 标记为 EXPIRED
  - [x] 过期时间默认30天
- **依赖**：TASK-031
- **优先级**：P2
- **阶段**：第五批
- **涉及文件**：
  - `backend/src/services/esign.service.ts`（SCENE_TEMPLATE_MAP）
  - `backend/src/routes/esign.routes.ts`（过期处理）
  - `backend/src/routes/portal.routes.ts`（员工端过期处理）
  - `frontend/src/pages/ESign.tsx`（场景选择自动填充）
- **测试要求**：
  - 手工验证：选择"劳动合同"场景 → 文件标题自动填充 → 创建记录 → 30天后自动标记过期

### TASK-037：前端管理端发起签署 UI 增强（P2）

- **目标**：管理端 ESign 页面增加场景选择、模板预览、证据链查看
- **对应需求**：电子签署逻辑审计 P2-2
- **验收标准**：
  - [x] 发起签署增加场景选择（5种场景：劳动合同/离职协议/规章制度/工资条/入职文件）
  - [x] 场景选择后自动填充默认文件标题
  - [x] 新增签署详情页（文件内容预览 + 证据链时间线）
  - [x] 签署流程说明（6步流程图）
  - [x] 签署记录列表增加签署方式列
- **依赖**：TASK-031
- **优先级**：P2
- **阶段**：第五批
- **涉及文件**：
  - `frontend/src/pages/ESign.tsx`（重写）
  - `frontend/src/lib/api-services.ts`（esignApi 增加 detail/evidence 接口）
- **测试要求**：
  - 手工验证：发起签署 → 选择场景 → 自动填充标题 → 创建 → 详情页查看文件内容和证据链

### TASK-038：前端员工端签署 UI 增强（P2）

- **目标**：员工端 MyEsign 增加验证码签署流程和文件预览
- **对应需求**：电子签署逻辑审计 P2-3
- **验收标准**：
  - [x] 签署操作增加验证码确认流程
  - [x] 60秒倒计时限制
  - [x] 文件内容预览
  - [x] 签署完成状态展示
  - [x] 开发模式直接显示验证码（便于测试）
- **依赖**：TASK-032
- **优先级**：P2
- **阶段**：第五批
- **涉及文件**：
  - `frontend/src/pages/portal/MyEsign.tsx`（重写）
  - `frontend/src/lib/api-services.ts`（portalApi 增加 esignSendCode 接口）
- **测试要求**：
  - 手工验证：员工端查看待签文件 → 点击获取验证码 → 输入验证码 → 签署完成

### TASK-039：线下手签完整流程 + 证据链（P1）

- **目标**：支持线下手签的完整登记流程，上传扫描件，记录证据链，与电子签署具有同等证据效力
- **对应需求**：线下手签支持
- **验收标准**：
  - [x] ESignRecord 增加 signMethod 字段（ELECTRONIC/PAPER）
  - [x] 增加线下手签专用字段：signedAt、signedLocation、witnessName、witnessPhone、scanFileUrls
  - [x] 后端新增线下手签登记接口（POST /esign/paper-sign）
  - [x] 后端新增扫描件上传接口（POST /esign/paper-upload，multer多文件）
  - [x] 线下手签登记创建 COMPLETED 状态记录 + 证据链 + 回写合同
  - [x] 管理端 ESign 页面增加"线下手签登记"按钮和 Modal
  - [x] 员工端线下手签记录只读展示（含扫描件链接）
- **依赖**：无
- **优先级**：P1
- **阶段**：第五批
- **涉及文件**：
  - `backend/prisma/schema.prisma`（ESignRecord 扩展7个字段）
  - `backend/src/routes/esign.routes.ts`（线下手签接口）
  - `frontend/src/pages/ESign.tsx`（线下手签登记 Modal）
  - `frontend/src/pages/portal/MyEsign.tsx`（线下手签只读展示）
  - `frontend/src/lib/api-services.ts`（uploadPaperSign/paperSign 接口）
- **DB 变更**：ESignRecord 新增 signMethod + 6个线下手签字段，`prisma db push` 已应用
- **测试要求**：
  - 手工验证：HR点击"线下手签登记" → 选择员工 → 填写签署日期/地点/见证人 → 上传扫描件 → 登记 → 证据链记录 → 员工端可查看扫描件

### TASK-040：花名册操作自动创建电子签署（P1）

- **目标**：花名册关键操作（增加员工/主动离职/公司解聘）自动创建电子签署记录
- **对应需求**：花名册与电子签署联动
- **验收标准**：
  - [x] 新增 esign.service.ts 提供 autoCreateEsignRecord 公共方法
  - [x] 主动离职（createDraft type=RESIGNATION）自动创建离职协议签署
  - [x] 公司解聘执行完成（executeTermination type=TERMINATION）自动创建离职协议签署
  - [x] 自动创建失败不阻断主流程（返回 null）
  - [x] 前端操作成功后提示"电子签署已自动发起"
- **依赖**：TASK-031
- **优先级**：P1
- **阶段**：第五批
- **涉及文件**：
  - `backend/src/services/esign.service.ts`（新增）
  - `backend/src/services/termination.service.ts`（createDraft/executeTermination 集成）
- **测试要求**：
  - 手工验证：花名册主动离职 → 创建离职草稿 → 自动创建离职协议签署记录 → 员工端可见

### TASK-041：通用签署方式选择弹窗 + 花名册4项操作联动（P1）

- **目标**：花名册操作（重新入职/合同续签/薪酬变更/调岗调动）成功后弹窗选择签署方式
- **对应需求**：花名册与电子签署联动（用户选择签署方式）
- **验收标准**：
  - [x] 新增 SignMethodChoice 通用组件（电子签/线下手签/稍后处理三选一）
  - [x] 重新入职：操作成功后弹窗（scene=CONTRACT，劳动合同）
  - [x] 合同续签：操作成功后弹窗（scene=CONTRACT，续签劳动合同）
  - [x] 薪酬变更：操作成功后弹窗（scene=POLICY，薪酬调整确认书）
  - [x] 调岗调动：操作成功后弹窗（scene=POLICY，调岗确认书）
  - [x] 选择"电子签"→自动创建签署记录
  - [x] 选择"线下手签"→跳转签署页面，预填信息
  - [x] 选择"稍后处理"→跳过，可后续手动发起
  - [x] ESign 页面支持 URL 参数自动打开线下手签登记
- **依赖**：TASK-039
- **优先级**：P1
- **阶段**：第五批
- **涉及文件**：
  - `frontend/src/components/ui/SignMethodChoice.tsx`（新增）
  - `frontend/src/pages/Roster.tsx`（4个 mutation onSuccess 集成）
  - `frontend/src/pages/ESign.tsx`（URL 参数读取 + PaperSignModal 预填）
- **测试要求**：
  - 手工验证：花名册薪酬变更 → 成功 → 弹窗选择"电子签" → 自动创建签署记录
  - 手工验证：花名册调岗 → 成功 → 弹窗选择"线下手签" → 跳转签署页面 → 信息已预填

### TASK-042：转正弹窗显示原薪资 + 薪资变化联动签署（P1）

- **目标**：转正弹窗显示原薪资，薪资变化时自动发起薪酬调整确认书签署
- **对应需求**：转正流程与电子签署联动
- **验收标准**：
  - [x] ConfirmModal 标签显示原薪资（¥xxx）
  - [x] 转正薪资默认填入原薪资
  - [x] 薪资变化时提示"将发起薪酬调整确认书签署"
  - [x] 转正成功后薪资有变化时弹出签署方式选择
  - [x] 签署文件标题为"转正薪酬调整确认书"
  - [x] 备注记录薪资变化：¥原薪资 → ¥新薪资
  - [x] 薪资未变化时仅显示"转正已提交"，不弹窗
- **依赖**：TASK-041
- **优先级**：P1
- **阶段**：第五批
- **涉及文件**：
  - `frontend/src/pages/roster/modals.tsx`（ConfirmModal 增强）
  - `frontend/src/pages/Roster.tsx`（confirmMutation onSuccess 联动）
- **测试要求**：
  - 手工验证：试用期薪资 ¥8000 → 转正填写 ¥10000 → 提示将发起签署 → 转正成功 → 弹窗选择签署方式
  - 手工验证：试用期薪资 ¥8000 → 转正不修改 → 提交 → 仅显示"转正已提交"

---

## 任务依赖关系图

```
第一批（P0，无依赖）：
TASK-001（草稿保存）─┬─→ TASK-002（补偿金合计）─┬─→ TASK-003（驳回更新）
                    │                         ├─→ TASK-004（违法解除风险）
                    │                         ├─→ TASK-009（补偿月数）→ TASK-010（计算基数）
                    │                         └─→ TASK-006（补偿金批次）
TASK-005（合同日期校验）─→ TASK-013（续签日期推导）

第二批（P1）：
TASK-007（社保联动）     独立
TASK-008（合规软阻断）─→ TASK-011（交接软阻断）
TASK-012（解聘入口）     独立
TASK-014（年龄校验）─→ TASK-022（证件号码）
TASK-015（入职日期联动） 独立
TASK-016（转正入口）─┬─→ TASK-017（薪资回写）
                    └─→ TASK-026（批量转正）
TASK-018（合同选择）     独立
TASK-019（三期性别）     独立

第三批（P2）：
TASK-020（用工关系文案） 独立
TASK-021（年假折算）← TASK-002
TASK-023（手机号查重）   独立
TASK-024（开具证明入口）─→ TASK-027（批量证明）
TASK-025（续签入口）← TASK-013, TASK-018
TASK-028（去掉用工办理）← TASK-016, TASK-018, TASK-024, TASK-025

第四批（P3）：
TASK-029（组织架构+审批流） 独立
TASK-030（客服工作台）     独立

第五批（电子签署，2026-08-16 新增）：
TASK-031（后端路由重写+模板渲染）─┬─→ TASK-032（验证码确认）─→ TASK-033（证据链体系）
                                ├─→ TASK-035（组织开关校验）
                                ├─→ TASK-036（scene模板+过期处理）─→ TASK-037（管理端UI）
                                └─→ TASK-040（花名册自动创建）
TASK-032 ─→ TASK-034（回写合同）─→ TASK-038（员工端UI）
TASK-039（线下手签）─→ TASK-041（签署方式选择弹窗）─→ TASK-042（转正联动）
```

---

## 验收检查清单

### 每个任务完成后必做
- [x] 代码实现完成，lint 通过
- [x] 涉及前端：手工验证通过
- [x] 涉及后端：API 测试通过
- [x] 涉及 DB 变更：migration 已创建，回滚方案已准备
- [x] `run.md` 如有命令变化已同步
- [x] 本文档对应 TASK 已标记 `[x]`

### 批次完成后必做
- [x] 该批次所有 TASK 标记 `[x]`
- [x] 前端 build 通过：`cd frontend && npm run build`
- [x] 后端编译通过：`cd backend && npx tsc --noEmit`
- [x] 更新 `20260815-优化.md` 中对应问题的状态
- [x] 简洁汇报结果、风险和下一步

### 全部完成后必做
- [x] 全部 30 个 TASK 标记 `[x]`
- [x] 全域搜索确认无遗漏（"身份证号"、"劳动合同"等）
- [x] DB migration 全部已应用
- [x] 前后端 build 均通过
- [x] 更新 `run.md`（如有新增模块/路由/端口）
- [x] 更新 `HelpModal.tsx` 帮助文案
- [x] Git commit（按批次提交，前缀 `feat/fix/ux/refactor`）

---

## 风险与注意事项

1. **DB 变更风险**：TASK-007/020/022/029/030 涉及 schema 变更，需先备份 DB，migration 需含回滚方案。
2. **兼容性风险**：TASK-022（证件号码）字段名 `idCardNumber` 保持不变，仅改 label，避免历史数据丢失。
3. **依赖链风险**：TASK-028（去掉用工办理）依赖 4 个前置任务，不可提前执行。
4. **文案替换风险**：TASK-020（用工关系）需区分法定术语和面向用户文案，法律文书模板不可改。
5. **审批流复杂度**：TASK-029 是新模块，建议先做 MVP（部门树+直属上级审批），再逐步扩展。
6. **客服端复杂度**：TASK-030 是新模块，建议先做工单+数据穿透，再做会话和 AI。
7. **历史脏数据**：TASK-005（合同日期倒置）、TASK-019（男职工三期）可能存在历史脏数据，提供查询列表但不自动修复。
8. **电子签署法律效力**：TASK-031~038 的电子签署证据链需配合易签宝等第三方CA机构才能生成具有完全法律效力的电子签名，当前系统记录的证据链（IP/UA/时间戳/验证码）可作为初步举证材料。
9. **线下手签扫描件存储**：TASK-039 的扫描件存储在服务器本地 `uploads/paper-sign/` 目录，生产环境建议配置对象存储（OSS/S3）并定期备份。
10. **验证码发送通道**：TASK-032 的验证码当前为开发模式（直接返回），生产环境需对接短信服务商（阿里云/腾讯云短信）。
11. **花名册联动重复创建**：TASK-040/041 已修复 POST /contracts 与前端 ContractInfo 重复创建签署记录的问题，后端不再自动创建，由前端根据 signMethod 决定。
