fix: 登记线下签署日期时同步创建 EsignRecord

登记签署日期后,签署记录 Tab 中也能看到这条记录。
创建一条 status=COMPLETED 的线下手签 EsignRecord,
避免已签合同在签署记录中无痕可查。

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-16 12:17:39 +08:00
parent 040c5a3ab9
commit ef6d4591be
5 changed files with 174 additions and 34 deletions
+74
View File
@@ -272,3 +272,77 @@
- `frontend/src/pages/ESign.tsx`Tab 切换 + PendingTab 组件 + 催办弹窗)
- `frontend/src/lib/api-services.ts`pending / remind 接口调用)
### ✅ 已完成 5:风险提醒反向引导修正(问题 10A)
- **问题**:三期/医疗期/工伤员工的风险提醒文案是"解聘受限",但 `actionUrl` 却指向 `/termination`(解聘向导),等于提示"不能解聘,点这里去解聘她"——反向引导,可能诱导违法解除。
- **修复**3 处 `actionUrl` 从 `/termination?employee=xxx` 改为 `/special-status?employee=xxx&type=PREGNANCY|MEDICAL_PERIOD|WORK_INJURY`,让 HR 确认员工状态而非跳去解聘。文案补充"此为合规提示,请勿发起解聘"。
- **涉及文件**`backend/src/services/risk.service.ts``detectTerminationRisks` 309-342 行)
### ✅ 已完成 6:试用期工资判定修正(问题 11)
- **问题**:3 处获取工资逻辑用错误的试用期判定 `startDate > now - 365d`(入职不到1年),转正后仍用 `probationSalary`。正确逻辑应是 `startDate + probationMonths > now`(试用期未结束)。
- **修复**
1. 抽取统一工具函数 `isInProbation(contract, referenceDate?)` 到 `contract.service.ts`。
2. 修正 3 处错误逻辑,统一调用 `isInProbation`,按批次月份月末判定。
3. `probationSalary` 为 0 时回退用 `monthlySalary`(兼容旧数据)。
- **涉及文件**
- `backend/src/services/contract.service.ts`(新增 `isInProbation`
- `backend/src/routes/payroll2.routes.ts`copy_last 模式 355 行、添加人员 614 行)
- `backend/src/routes/payroll.routes.ts`(旧版批量生成 380 行)
### ✅ 已完成 7:证件号码有效性校验(问题 6)
- **问题**:添加雇员仅校验证件号码长度 ≥18,未做校验位、出生日期合法性验证。
- **修复**
1. 前端 `handleIdCardChange` 增加校验位算法(GB 11643-1999)、出生日期合法性(月份/日期范围、是否存在如2月30日、是否晚于今天),校验失败阻断保存。
2. 后端新增 `validateIdCard`/`getAgeFromIdCard`/`isOverageEmployee` 工具函数,`createEmployee` 增加双保险校验。
- **涉及文件**
- `frontend/src/pages/roster/modals.tsx``handleIdCardChange`、`canSubmit`
- `backend/src/services/contract.service.ts`(新增 3 个工具函数 + `createEmployee` 校验)
### ✅ 已完成 8:超龄人员合同类型限制(问题 7)
- **问题**:超龄人员仅 WARN 提示,仍可选劳动合同(FIXED/UNFIXED),违反合规要求。
- **修复**
1. 前端派生 `isOverage`(男≥60、女干部≥55、女工人≥50),合同类型下拉过滤掉 FIXED/UNFIXED,仅保留 LABOR/INTERNSHIP/UNSIGNED。
2. 草稿恢复时若当前合同类型非法,useEffect 自动切到 UNSIGNED。
3. 后端 `createEmployee` 增加校验:超龄 + FIXED/UNFIXED 拒绝并返回 400。
- **涉及文件**
- `frontend/src/pages/roster/modals.tsx``isOverage` 派生、合同类型下拉过滤、useEffect 自动修正)
- `backend/src/services/contract.service.ts``createEmployee` 超龄校验)
### ✅ 已完成 9:劳务协议社保联动(问题 8)
- **问题**:选劳务协议(LABOR)时社保基数未置 0 且仍可缴纳,违反合规要求。
- **修复**
1. 前端选 LABOR/INTERNSHIP 时,社保/公积金基数自动置 0、起始月清空、字段禁用,提示"劳务协议/实习协议人员不缴纳社保公积金"。
2. 后端 `createEmployee` 强制:LABOR/INTERNSHIP 时 `socialInsBase`/`housingFundBase` = 0,起始月清空。
- **涉及文件**
- `frontend/src/pages/roster/modals.tsx`(合同类型 onChange 联动、社保区 disabled
- `backend/src/services/contract.service.ts``createEmployee` 社保强制 0
### ✅ 已完成 10:合同状态增加待签署判定(问题 4)
- **问题**:有合同记录但 `signDate` 为空时仍显示"正常",应显示"待签署"。
- **修复**`getContractStatus` 增加判定:有合同记录但 `signDate` 为空 → `status: 'pending_sign'``statusText: '待签署'``riskLevel: 'medium'`。电子签署完成后会回写 `signDate`,故 `signDate` 为空即未签署。前端花名册列表 `statusTextMap` 增加 `pending_sign: '待签署'`。
- **涉及文件**
- `backend/src/services/contract.service.ts``getContractStatus` 74-91 行重写)
- `frontend/src/pages/Roster.tsx``tagStyles`/`statusTextMap` 增加 `pending_sign`
### ✅ 已完成 11:社保状态派生字段(问题 5)
- **问题**:社保状态无"待办"判定,未办理社保的在职员工显示"—"而非"待办理"。
- **修复**:后端 `socialInsuranceStatus` 派生逻辑:
- 劳务协议/实习协议 → null(不缴社保,显示"—"
- 在职 + 应缴社保 + 无社保记录 → `PENDING`(待办理)
- 有社保记录 + endMonth 为 null → `ACTIVE`(在保)
- 有社保记录 + endMonth 不为 null → `SUSPENDED`(停保)
- 前端已有 PENDING/UNINSURED 的标签映射,无需改前端。
- **涉及文件**`backend/src/routes/roster.routes.ts``socialInsuranceStatus` 派生 243-249 行)
### ✅ 已完成 12:待办跳转 actionUrl 空值降级(问题 9
- **问题**:待办事项的"立刻办理"链接在 `actionUrl` 为空或 '/' 时仍渲染为 Link,点击跳首页无意义。
- **修复**Dashboard 待办列表渲染时,`actionUrl` 为空或 '/' 时不渲染 Link 和"立刻办理"按钮,改为纯展示 div;有有效 URL 时才渲染可跳转链接。问题 10A 已修正三期/医疗期/工伤的反向引导 URL,其余 actionUrl`/roster?employee=xxx`、`/special-status`、`/money`)均指向有效路由,Roster 已处理 `?employee` 参数自动定位。
- **涉及文件**`frontend/src/pages/Dashboard.tsx`(待办列表渲染 1136-1233 行)