Files
TurboHR/20260730-优化.md
T
freedakgmail 42e0c650a4 feat: 实现20260730优化方案全部功能
- AI文件审查:.docx上传提取文本,支持多种文档类型
- 用工办理工作流:WorkProcess页面+后端API,支持入职/续签/终止等流程
- 企业自建文本库:Templates页面Tab切换,企业模板CRUD+渲染+下载Word
- 考勤发布:Attendance发布/取消发布按钮,员工端MyAttendance页面
- 工资条发布:Money发布/定时发送按钮+弹窗,portal端publishStatus过滤
- 合同到期弹窗:Dashboard合同到期预警可点击打开弹窗,支持续签/终止操作
- Prisma schema新增WorkProcess/EnterpriseTemplate/AttendancePublish模型
- 前后端编译验证全部通过
2026-07-30 10:21:22 +08:00

541 lines
21 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.
# 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文件审查上传。
---
## P0AI文件审查上传功能
### 问题描述
现有 `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
```
### 安全考虑
- 文件大小限制:100MBmulter 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` 的逻辑