Files
TurboHR/20260815-优化计划.md
T
selfrelease fa0dc82d38 docs: 优化计划补充第五批电子签署任务(TASK-031~042)
新增12项电子签署优化任务:
- P0:后端路由重写+模板渲染、验证码确认、证据链体系
- P1:回写合同、组织开关校验、线下手签、花名册联动、转正联动
- P2:scene模板填充、管理端UI、员工端UI

更新执行状态总览(31→43条)、批次总览、依赖关系图、风险注意事项

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-15 16:56:24 +08:00

1039 lines
55 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 20260815 优化执行计划
> 基于 `20260815-优化.md`(31 条优化项)制定的可执行任务清单。
> 覆盖范围:P0(6 条)+ P1(14 条)+ P29 条)+ 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-1010 日 < 15 日)→ 社保截止 2026-07 → 公积金截止 2026-07
- 手工验证:离职日期 2026-08-2020 日 > 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)→ 折算 ¥69005×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 枚举新增 SUPPORTmigration + 回滚方案
- **测试要求**
- 手工验证:客服登录 → 查看工单列表 → 回复工单 → 选择租户 → 穿透查看花名册 → 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-036scene 关联模板自动填充 + 过期自动处理(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-uploadmulter多文件)
- [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-036scene模板+过期处理)─→ 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 变更,需先备份 DBmigration 需含回滚方案。
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 决定。