feat: 线下手签完整流程 + 证据链体系

## 数据库
- ESignRecord 增加 signMethod 字段(ELECTRONIC/PAPER)
- 增加线下手签专用字段:signedAt、signedLocation、witnessName、witnessPhone、scanFileUrls

## 后端
- esign.routes.ts 新增线下手签接口:
  - POST /esign/paper-upload:上传签署扫描件(multer多文件,10MB限制)
  - POST /esign/paper-sign:线下手签登记(创建COMPLETED记录+证据链+回写合同)
- esign.service.ts:autoCreateEsignRecord 设置 signMethod=ELECTRONIC
- 静态文件服务复用 /uploads 统一映射

## 前端管理端
- ESign.tsx 新增"线下手签登记"按钮和 Modal:
  - 选择员工、文件类型、签署日期、地点、见证人
  - 上传签署扫描件(多文件)
  - 登记后自动创建证据链
- 列表增加"签署方式"列(电子签/线下手签标签)
- 详情页增加签署方式标签 + 线下手签信息卡片 + 扫描件列表

## 前端员工端
- MyEsign.tsx 列表增加线下手签标签
- 详情页增加线下手签信息卡片(签署日期/地点/见证人/扫描件)
- 签署操作区域:线下手签记录显示"线下手签已登记",不显示验证码签署

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-15 16:36:46 +08:00
parent 12f1cde7c5
commit 434c63c6d3
6 changed files with 513 additions and 20 deletions
+9 -1
View File
@@ -1528,6 +1528,7 @@ model ESignRecord {
employeeId String
employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
scene String @default("CONTRACT") // CONTRACT | RESIGNATION | POLICY | PAYSLIP | ONBOARDING
signMethod String @default("ELECTRONIC") // ELECTRONIC=电子签署 | PAPER=线下手签
flowId String? // 易签宝流程ID
documentTitle String // 文件标题
documentContent String? // 文件内容(HTML/PDF base64
@@ -1537,12 +1538,19 @@ model ESignRecord {
initiatedBy String // 发起人(HR用户ID
completedAt DateTime?
expiredAt DateTime?
callbackData Json? // 易签宝回调数据
callbackData Json? // 易签宝回调数据 / 线下手签证据
remark String?
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 线下手签专用字段
signedAt DateTime? // 线下签署日期
signedLocation String? // 签署地点
witnessName String? // 见证人姓名
witnessPhone String? // 见证人手机号
scanFileUrls Json? // 线下签署扫描件URL列表 [{name, url}]
@@index([orgId, status])
@@index([employeeId])
@@index([contractId])