# TurboHR 优化方案（20260730）

> 日期：2026-07-30
> 依据：白话用工侠完整运行测试报告对比分析 + 功能缺口梳理
> 优先级：P0（紧急/核心）、P1（重要补全）、P2（增强优化）

---

## 背景

将「白话用工侠完整运行测试报告」中列出的功能与本系统（TurboHR）实际代码逐一对比后，识别出以下功能缺口：

### 已实现功能（14项）

| 功能 | 对应文件 |
|------|---------|
| 登录与全局框架 | `Login.tsx`、`SidebarNav`、`TopNav` |
| 工作台（合规健康度/风险预警/待办） | `Dashboard.tsx` |
| AI 智能问答（流式/历史/语音/转律师） | `AIAssistant.tsx` ChatTab |
| AI 判赔预测（12类争议场景） | `AIAssistant.tsx` PredictTab |
| AI 合同审查（粘贴文本） | `AIAssistant.tsx` ReviewTab |
| AI 案例匹配 | `AIAssistant.tsx` CaseTab |
| 花名册（搜索/筛选/导入/导出/二维码邀请） | `Roster.tsx` |
| 考勤管理（记录/导入/统计/排班/休假） | `Attendance.tsx` |
| 合同管理（列表/查询/查看/下载/删除） | `Contracts.tsx` |
| 规章制度民主程序（四步流程） | `Policies.tsx` |
| 用工体检诊断（6维度评分） | `HealthCheck.tsx` |
| 文本模板库（87模板/下载Word/变量渲染） | `Templates.tsx` |
| 通知管理（发布/目标人群/定时） | `Notifications.tsx` |
| 计算器（五险一金/医疗期） | `SocialInsurance.tsx`、`MedicalPeriodCalculator.tsx` |

### 部分实现功能（3项）

| 功能 | 已有部分 | 缺失部分 |
|------|---------|---------|
| AI 文件审查 | 粘贴合同文本审查、结构化风险报告 | 不支持上传 doc/docx 文件，无文书类型选择 |
| 考勤管理 | 考勤记录导入、查看、统计 | 无"发布考勤表"功能 |
| 工资条管理 | 工资条生成、员工端查看 | 无"发布工资条"和"定时发送"功能 |

### 未实现功能（5项）

| 功能 | 说明 |
|------|------|
| 用工办理工作流（13类流程） | 最大的功能缺口，无统一办理工作流系统 |
| 背景调查 | 完全未实现（本次暂不纳入） |
| 视频中心 | 完全未实现（本次暂不纳入） |
| 企业自建文本库 | 无企业自建文本管理功能 |
| 合同到期处理弹窗 | 有到期提醒但无多选项处理弹窗（本次暂不纳入） |

**本次优化聚焦4项功能**：用工办理工作流、企业自建文本库、考勤/工资条发布、AI文件审查上传。

---

## P0：AI文件审查上传功能

### 问题描述

现有 `AIAssistant.tsx` ReviewTab 仅支持粘贴合同文本进行审查，无法上传 doc/docx 文件。白话用工侠支持上传文件并选择文书类型（劳动合同/协商解除/劳务协议/实习协议/保密协议）。

### 涉及文件

| 文件 | 改动 |
|------|------|
| `backend/src/routes/ai.routes.ts` | 新增 `POST /ai/review/upload` 接口 |
| `frontend/src/pages/AIAssistant.tsx` ReviewTab | 新增文件上传区 + 文书类型选择 |
| `backend/package.json` | 新增 `mammoth` 依赖 |

### 实现方案

#### 后端：文件上传 + 文本提取

```typescript
// ai.routes.ts 新增
import mammoth from 'mammoth'

const upload = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: 100 * 1024 * 1024 }, // 100MB
  fileFilter: (req, file, cb) => {
    const ext = path.extname(file.originalname).toLowerCase()
    if (ext !== '.docx' && ext !== '.doc') {
      return cb(new Error('仅支持 .doc 和 .docx 文件'))
    }
    cb(null, true)
  },
})

router.post('/review/upload', authMiddleware, upload.single('file'), async (req: AuthRequest, res, next) => {
  try {
    if (!req.file) return res.status(400).json({ success: false, error: { code: 'NO_FILE', message: '请上传文件' } })
    const ext = path.extname(req.file.originalname).toLowerCase()
    let text = ''
    if (ext === '.docx') {
      const result = await mammoth.extractRawText({ buffer: req.file.buffer })
      text = result.value
    } else {
      // .doc 旧格式：提示用户转换为 .docx
      return res.status(400).json({ success: false, error: { code: 'UNSUPPORTED', message: '暂不支持 .doc 格式，请将文件另存为 .docx 后上传' } })
    }
    // 截断超长文本
    if (text.length > 50000) {
      text = text.slice(0, 50000) + '\n\n[文本过长，已截断]'
    }
    res.json({ success: true, data: { text } })
  } catch (err) { next(err) }
})
```

#### 前端：ReviewTab 改造

在现有粘贴文本输入框上方新增：

```
合同审查 Tab：
├── 文书类型选择（下拉：劳动合同/协商解除协议/劳务协议/实习协议/保密协议）
├── 文件上传区（拖拽或点击上传 .docx）
│   ├── 上传后调用 /ai/review/upload 提取文本
│   └── 提取成功后自动填入下方输入框
├── 文本输入框（现有，用户可编辑提取后的文本）
├── 开始审查按钮（现有）
└── 审查结果展示（现有）
```

#### 依赖安装

```bash
cd backend && npm install mammoth
```

### 安全考虑

- 文件大小限制：100MB（multer limits）
- 文件类型校验：仅 `.docx`，`.doc` 提示转换
- 提取后不保存原文件，仅返回文本
- 文本长度截断：超过 50000 字符时截断并提示

---

## P0：用工办理工作流系统（13类流程）

### 问题描述

本系统有 `Termination.tsx`（离职管理）和 `Contracts.tsx`（合同管理），但缺少统一的用工办理工作流系统。白话用工侠提供13类办理流程：员工录用、员工入职、自定义合同签署、员工信息提交、员工转正、合同变更、合同续签、合同中止、开具收入证明、合同终止、合同解除、开具离职证明、灵活用工。

### 13类流程定义

| 编号 | 流程名称 | 类型代码 | 核心表单字段 | 关联模块 |
|------|---------|---------|------------|---------|
| 1 | 员工录用 | HIRE | 人员选择、入职时间、公司地址、部门、岗位、直属上级、联系方式、试用期薪酬、转正薪酬、携带材料 | 员工创建+合同起草 |
| 2 | 员工入职 | ONBOARD | 入职日期、岗位确认、合同签署方式、材料提交清单 | 员工状态→ACTIVE |
| 3 | 自定义合同签署 | CUSTOM_CONTRACT | 合同模板选择、变量填充、签署方、期限 | 合同管理 |
| 4 | 员工信息提交 | INFO_SUBMIT | 信息变更字段、证明材料 | 员工档案更新 |
| 5 | 员工转正 | CONFIRM | 转正日期、转正薪资、考核结果 | 员工状态+薪资变更 |
| 6 | 合同变更 | CHANGE | 变更类型、变更内容、生效日期 | 合同管理 |
| 7 | 合同续签 | RENEW | 续签次数、新期限、新薪资 | 合同管理 |
| 8 | 合同中止 | SUSPEND | 中止原因、中止期限、预计恢复日期 | 合同状态 |
| 9 | 开具收入证明 | INCOME_CERT | 用途、收入期间、接收方 | 文本模板渲染 |
| 10 | 合同终止 | TERMINATE | 终止原因、终止日期、经济补偿 | 合同状态+离职 |
| 11 | 合同解除 | RESCIND | 解除原因、解除方式、协商/单方 | 复用 Termination 模块 |
| 12 | 开具离职证明 | LEAVING_CERT | 离职日期、离职原因、接收方 | 文本模板渲染 |
| 13 | 灵活用工 | FLEXIBLE | 人员信息、用工类型、协议期限、计酬方式 | 合同管理(LABOR) |

### 数据模型

```prisma
// 用工办理流程
model WorkProcess {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  type        String   // HIRE/ONBOARD/CUSTOM_CONTRACT/INFO_SUBMIT/CONFIRM/CHANGE/RENEW/SUSPEND/INCOME_CERT/TERMINATE/RESCIND/LEAVING_CERT/FLEXIBLE
  title       String
  employeeId  String?
  employee    Employee? @relation(fields: [employeeId], references: [id])
  status      String   @default("DRAFT") // DRAFT/PENDING_APPROVAL/APPROVED/REJECTED/EXECUTING/COMPLETED/CANCELLED
  formData    Json     // 表单数据 JSON
  documents   Json?    // 生成的文书列表 [{name, content, type}]
  approverId  String?
  approvedAt  DateTime?
  remark      String?
  createdBy   String
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([orgId, status])
  @@index([orgId, type])
  @@index([orgId, createdBy])
}
```

### 后端接口

```
POST   /api/v1/work-processes              # 创建办理（含草稿）
GET    /api/v1/work-processes              # 列表查询（支持type/status筛选）
GET    /api/v1/work-processes/:id          # 详情
PATCH  /api/v1/work-processes/:id          # 更新草稿
POST   /api/v1/work-processes/:id/submit   # 提交办理
POST   /api/v1/work-processes/:id/approve  # 审批通过
POST   /api/v1/work-processes/:id/reject   # 驳回
POST   /api/v1/work-processes/:id/cancel   # 撤销
DELETE /api/v1/work-processes/:id          # 删除草稿
GET    /api/v1/work-processes/:id/preview  # 预览生成的文书
```

### 前端架构

**新增页面**：`frontend/src/pages/WorkProcess.tsx`

```
页面结构：
├── 发起办理（13类流程卡片选择）
├── 办理记录（列表+筛选：类型/状态/日期）
├── 办理草稿（仅 DRAFT 状态）
└── 流程详情（步骤条+表单+预览+操作）
```

**流程详情组件**（通用 Wizard）：
- 步骤条：填写信息 → 预览文书 → 存草稿/提交
- 表单根据 `type` 动态渲染字段
- 预览：调用文本模板渲染接口生成文书
- 提交后根据流程类型执行对应业务逻辑

**复用已有模块**：
- 合同解除（#11）→ 复用 `Termination.tsx` 的 Wizard 逻辑
- 合同续签（#7）→ 复用 `Contracts.tsx` 的合同管理逻辑
- 收入证明（#9）/ 离职证明（#12）→ 复用 `Templates.tsx` 的模板渲染
- 员工录用（#1）→ 复用 `roster/modals.tsx` 的添加员工逻辑

### 提交后业务联动

| 流程类型 | 提交后执行 |
|---------|-----------|
| HIRE | 创建员工记录 + 创建劳动合同 |
| ONBOARD | 更新员工状态为 ACTIVE + 记录入职日期 |
| CUSTOM_CONTRACT | 创建劳动合同 |
| INFO_SUBMIT | 更新员工档案字段 |
| CONFIRM | 更新试用期结束 + 调整薪资 |
| CHANGE | 更新合同字段 + 记录变更历史 |
| RENEW | 关闭旧合同 + 创建新合同 |
| SUSPEND | 合同状态改为 SUSPENDED |
| INCOME_CERT | 生成收入证明文书（不改变业务数据） |
| TERMINATE | 合同状态改为 TERMINATED + 触发离职流程 |
| RESCIND | 调用已有 Termination 逻辑 |
| LEAVING_CERT | 生成离职证明文书 |
| FLEXIBLE | 创建劳务协议合同 |

### 涉及文件

| 文件 | 改动 |
|------|------|
| `backend/prisma/schema.prisma` | 新增 `WorkProcess` 模型 |
| `backend/src/routes/work-process.routes.ts` | **新增**，办理 CRUD + 提交/审批/撤销 |
| `backend/src/services/work-process.service.ts` | **新增**，13类流程的业务联动逻辑 |
| `backend/src/index.ts` | 注册新路由 |
| `frontend/src/pages/WorkProcess.tsx` | **新增**，办理页面 |
| `frontend/src/App.tsx` | 注册路由 |
| `frontend/src/components/layout/SidebarNav.tsx` | 新增菜单项 |

### 实施分阶段

1. **Phase 1**：数据模型 + 基础 CRUD + 列表/草稿页面
2. **Phase 2**：员工录用、员工入职、合同续签、合同终止（4个高频流程）
3. **Phase 3**：剩余9类流程 + 文书预览生成
4. **Phase 4**：审批流程 + 办理记录导出

---

## P1：企业自建文本库

### 问题描述

现有 `Templates.tsx` 仅提供系统预置模板（87个，只读），企业无法创建和管理自己的文本模板。白话用工侠有"企业文本库"功能，支持自建文本。

### 数据模型

```prisma
// 企业自建文本模板
model EnterpriseTemplate {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  name        String
  category    String   // CONTRACT/RULES/NOTICE/AGREEMENT/OTHER
  description String?
  content     String   @db.Text
  variables   String[] // 变量名列表
  status      String   @default("ACTIVE") // ACTIVE/ARCHIVED
  createdBy   String
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([orgId, category])
}
```

### 后端接口

```
# 现有模板路由：/api/v1/templates（系统预置，只读）
# 新增企业模板路由：/api/v1/enterprise-templates

GET    /api/v1/enterprise-templates            # 列表（支持category/search）
POST   /api/v1/enterprise-templates            # 新建
GET    /api/v1/enterprise-templates/:id        # 详情
PUT    /api/v1/enterprise-templates/:id        # 更新
DELETE /api/v1/enterprise-templates/:id        # 删除
POST   /api/v1/enterprise-templates/:id/render # 渲染（复用现有 renderTemplate 逻辑）
GET    /api/v1/enterprise-templates/:id/download # 下载Word
```

### 前端方案

**改造页面**：`frontend/src/pages/Templates.tsx`

在现有模板库页面顶部新增 Tab 切换：
- **系统模板库**（现有功能不变）
- **企业文本库**（新增）

企业文本库 Tab 内容：
```
├── 查询栏（名称搜索 + 分类筛选）
├── 新建/编辑弹窗（名称、分类、变量配置、内容编辑）
├── 模板卡片列表（复用现有卡片样式）
├── 详情弹窗（变量填写 → 渲染 → 下载Word/复制）
└── 操作：编辑、复制、删除、归档
```

### 涉及文件

| 文件 | 改动 |
|------|------|
| `backend/prisma/schema.prisma` | 新增 `EnterpriseTemplate` 模型 |
| `backend/src/routes/enterprise-template.routes.ts` | **新增**，CRUD + 渲染 + 下载 |
| `backend/src/index.ts` | 注册新路由 |
| `frontend/src/pages/Templates.tsx` | 顶部新增 Tab 切换 + 企业文本库面板 |

### 实现要点

- 变量提取：编辑内容时自动扫描 `{{变量名}}` 提取变量列表
- 渲染逻辑：复用 `template.service.ts` 的 `renderTemplate` 函数
- 内容编辑器：使用 textarea + 变量插入按钮（点击插入 `{{变量名}}`）
- 权限：ADMIN/HR 可增删改，VIEWER 只读

---

## P1：考勤发布流程

### 问题描述

现有 `Attendance.tsx` 有考勤记录和统计功能，但缺少"发布考勤表"功能。白话用工侠支持 HR 发布月度考勤表，员工在员工端查看确认。

### 数据模型

```prisma
// 考勤发布记录
model AttendancePublish {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  month       String   // 2026-07
  title       String   // 如"2026年7月考勤表"
  status      String   @default("PUBLISHED") // PUBLISHED/CANCELLED
  publishDate DateTime @default(now())
  createdBy   String
  createdAt   DateTime @default(now())

  @@unique([orgId, month])
  @@index([orgId, month])
}
```

### 后端接口

```
POST   /api/v1/attendance/publish             # 发布考勤表
GET    /api/v1/attendance/publish-records      # 发布记录列表
POST   /api/v1/attendance/publish/:id/cancel   # 取消发布
GET    /api/v1/portal/attendance?month=2026-07 # 员工查看自己的月度考勤
```

### 前端改造

**`Attendance.tsx`** — 在「考勤确认」Tab 工具栏新增：
- **「发布考勤表」按钮**：弹窗确认 → 选择月份 → 发布
- **「发布记录」入口**：查看历史发布记录，可取消发布

**`portal/` 新增考勤查看页面** — `portal/MyAttendance.tsx`：
- 员工登录后查看已发布月份的考勤记录
- 显示每日考勤状态、上下班时间
- 支持月度切换

### 涉及文件

| 文件 | 改动 |
|------|------|
| `backend/prisma/schema.prisma` | 新增 `AttendancePublish` 模型 |
| `backend/src/routes/attendance.routes.ts` | 新增发布/取消/记录接口 |
| `backend/src/routes/portal.routes.ts` | 新增员工端考勤查看接口 |
| `frontend/src/pages/Attendance.tsx` | 新增发布按钮和发布记录弹窗 |
| `frontend/src/pages/portal/MyAttendance.tsx` | **新增**，员工端考勤查看 |
| `frontend/src/App.tsx` | 注册员工端考勤路由 |
| `frontend/src/components/layout/PortalLayout.tsx` | 员工端导航新增考勤入口 |

---

## P1：工资条发布与定时发送

### 问题描述

现有 `Money.tsx` 可生成工资条，员工端 `portal/Payslip.tsx` 可查看，但缺少"发布工资条"和"定时发送"功能。白话用工侠支持 HR 发布工资条后员工才能看到，并支持定时发送。

### 数据模型

复用已有 `Payslip` 模型，新增发布状态字段：

```prisma
// 在 Payslip 模型新增字段
model Payslip {
  // ...已有字段
  publishStatus   String?  // UNPUBLISHED/PUBLISHED/SCHEDULED
  publishedAt     DateTime?
  scheduledAt     DateTime? // 定时发送时间
  // confirmedAt 已有
}
```

### 后端接口

```
POST   /api/v1/payroll/batches/:batchId/publish     # 发布工资条
POST   /api/v1/payroll/batches/:batchId/schedule    # 定时发送
GET    /api/v1/payroll/schedule-records              # 定时发送记录
POST   /api/v1/payroll/schedule/:id/cancel           # 取消定时发送
```

### 前端改造

**`Money.tsx`** — 在批次详情页新增：
- **「发布工资条」按钮**：将批次内所有工资条标记为 PUBLISHED
- **「定时发送」选项**：选择发送时间，到点自动发布
- **「定时发送记录」入口**：查看定时发送列表，可取消

**`portal/Payslip.tsx`** — 调整查询逻辑：
- 发布前：员工端不显示该月工资条
- 发布后：员工端显示工资条，可查看和确认
- 定时发送：到点后状态从 SCHEDULED → PUBLISHED

### 定时发送实现

- 使用 `node-cron` 或现有定时任务机制
- 每分钟检查 `scheduledAt <= now && publishStatus = SCHEDULED` 的记录
- 自动更新为 PUBLISHED 并发送通知

### 涉及文件

| 文件 | 改动 |
|------|------|
| `backend/prisma/schema.prisma` | `Payslip` 模型新增 `publishStatus`/`publishedAt`/`scheduledAt` 字段 |
| `backend/src/routes/payroll.routes.ts` 或 `payroll2.routes.ts` | 新增发布/定时发送/取消接口 |
| `backend/src/index.ts` | 注册定时任务 |
| `frontend/src/pages/Money.tsx` | 批次详情页新增发布/定时发送按钮 |
| `frontend/src/pages/portal/Payslip.tsx` | 查询逻辑增加 publishStatus 过滤 |
| `backend/src/routes/portal.routes.ts` | 员工端 payslip 接口增加 publishStatus 过滤 |

---

## P2：合同到期处理弹窗（增强）

### 问题描述

现有 `Dashboard.tsx` 有合同到期提醒，但仅显示列表。白话用工侠支持到期合同弹窗处理：发送续签通知、已线下续签、终止合同、自定义签署，并可查看合同PDF。

### 前端改造

**`Dashboard.tsx`** — 合同到期待办项增加操作弹窗：

```
合同到期处理弹窗：
├── 员工信息 + 合同信息（类型/期限/到期日）
├── 合同PDF查看链接（如有附件）
└── 操作按钮：
    ├── 发送续签通知 → 调用通知接口
    ├── 已线下续签 → 更新合同状态 + 创建新合同记录
    ├── 终止合同 → 跳转 Termination 模块
    └── 自定义签署 → 跳转 WorkProcess CUSTOM_CONTRACT
```

### 涉及文件

| 文件 | 改动 |
|------|------|
| `frontend/src/pages/Dashboard.tsx` | 合同到期待办增加操作弹窗 |
| `backend/src/routes/dashboard.routes.ts` | 如需新增批量操作接口 |

---

## 实施计划

### 优先级排序

| 优先级 | 功能 | 预估工作量 | 建议时间 |
|--------|------|-----------|---------|
| P0 | AI文件审查上传 | 1-2天 | 立即 |
| P0 | 用工办理工作流 Phase 1-2 | 5-7天 | 本周 |
| P1 | 企业自建文本库 | 2-3天 | 下周 |
| P1 | 考勤发布 | 2天 | 下周 |
| P1 | 工资条发布与定时发送 | 2-3天 | 下周 |
| P0 | 用工办理工作流 Phase 3-4 | 5-7天 | 第三周 |
| P2 | 合同到期处理弹窗 | 1-2天 | 第三周 |

### 分周计划

- **第1周**：AI文件审查上传 + 用工办理 Phase 1-2（数据模型 + CRUD + 4个高频流程）
- **第2周**：企业文本库 + 考勤发布 + 工资条发布
- **第3周**：用工办理 Phase 3-4（剩余9类流程 + 审批） + 合同到期弹窗 + 联调测试

### 总工作量

约 18-26 个工作日

### 数据库迁移

所有新增模型和字段变更需要执行：
```bash
cd backend && npx prisma db push
```

---

## 风险与注意事项

1. **用工办理工作流**是最复杂的功能，建议先实现4个高频流程（录用/入职/续签/终止），验证架构后再扩展剩余9类
2. **企业文本库**的变量提取逻辑需与系统模板保持一致，复用 `renderTemplate` 函数
3. **工资条发布**涉及薪资敏感数据，需确保只有发布后员工端才能看到，发布前 `publishStatus = UNPUBLISHED` 的记录在员工端不可见
4. **AI文件审查**的 .doc 旧格式支持有限，建议仅支持 .docx 并提示用户转换
5. **定时发送**需要确保服务器进程持续运行（PM2 已有保障），定时任务需做幂等处理防止重复发布
6. **用工办理工作流**的13类流程提交后业务联动逻辑较复杂，每类流程需独立编写 `executeWorkProcess(type, formData)` 逻辑
7. **考勤发布**需考虑已取消发布的月份是否允许重新发布（`@@unique([orgId, month])` 约束需处理）
8. **合同到期弹窗**的"发送续签通知"需复用现有通知模块 `Notifications.tsx` 的逻辑
