From bb25e1731c896f05f8cd56cbb9b88edfb9f724c7 Mon Sep 17 00:00:00 2001 From: freedakgmail Date: Fri, 24 Jul 2026 23:37:11 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BD=93=E5=A4=A9?= =?UTF-8?q?=E5=85=A5=E8=81=8C=E5=91=98=E5=B7=A5=E8=A2=AB=E8=AF=AF=E5=88=A4?= =?UTF-8?q?=E4=B8=BA=E9=A2=84=E5=85=A5=E8=81=8C=E7=9A=84=E6=97=B6=E5=8C=BA?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=9B=E6=95=B0=E6=8D=AE=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E4=B8=BA=E8=AE=BE=E7=BD=AETab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/routes/roster.routes.ts | 11 +- docs/业务场景与操作指南.md | 981 ++++++++++++++++++++++++++++ frontend/src/pages/Settings.tsx | 13 +- 3 files changed, 997 insertions(+), 8 deletions(-) create mode 100644 docs/业务场景与操作指南.md diff --git a/backend/src/routes/roster.routes.ts b/backend/src/routes/roster.routes.ts index 9182c6c..dd423ea 100644 --- a/backend/src/routes/roster.routes.ts +++ b/backend/src/routes/roster.routes.ts @@ -28,8 +28,13 @@ router.get('/', authMiddleware, async (req: AuthRequest, res, next) => { const contractStatus = req.query.contractStatus as string // active | expiring | expired | unsigned | etc. const skip = (page - 1) * pageSize + // 使用本地日期午夜,避免时区问题导致当天入职被误判为预入职 const today = new Date() today.setHours(0, 0, 0, 0) + // hireDate 可能以 UTC 午夜存储(如 new Date('2026-07-24')),在 UTC+8 下为 08:00 + // 将 today 前移一天作为比较基准,确保当天入职的员工不被误判为预入职 + const todayEnd = new Date(today) + todayEnd.setDate(todayEnd.getDate() + 1) // 先查询满足 orgId 和搜索条件的员工 const whereBase: any = { orgId: req.user!.orgId } @@ -45,10 +50,10 @@ router.get('/', authMiddleware, async (req: AuthRequest, res, next) => { whereBase.status = 'RESIGNED' } else if (status === 'PRE_HIRE') { whereBase.status = 'ACTIVE' - whereBase.hireDate = { gt: today } + whereBase.hireDate = { gt: todayEnd } } else if (status === 'ACTIVE') { whereBase.status = 'ACTIVE' - whereBase.hireDate = { lte: today } + whereBase.hireDate = { lte: todayEnd } } // unsigned 合同状态可以在 DB 层过滤 @@ -101,7 +106,7 @@ router.get('/', authMiddleware, async (req: AuthRequest, res, next) => { hireDate: e.hireDate, }) const isResigned = e.terminations.some((t) => t.terminationDate <= today) - const isPreHire = !isResigned && e.hireDate > today + const isPreHire = !isResigned && e.hireDate > todayEnd const dynamicStatus = isResigned ? 'RESIGNED' : (isPreHire ? 'PRE_HIRE' : 'ACTIVE') return { id: e.id, diff --git a/docs/业务场景与操作指南.md b/docs/业务场景与操作指南.md new file mode 100644 index 0000000..75a57ad --- /dev/null +++ b/docs/业务场景与操作指南.md @@ -0,0 +1,981 @@ +# AIHR 智能人力资源管理系统 — 业务场景与操作指南 + +> 本文档详细描述系统各功能模块的业务场景、角色权限、操作流程及示例,供产品、开发、测试和用户参考。 + +--- + +## 目录 + +1. [系统概述与角色](#1-系统概述与角色) +2. [注册与登录](#2-注册与登录) +3. [Dashboard 仪表盘](#3-dashboard-仪表盘) +4. [花名册管理](#4-花名册管理) +5. [薪酬管理](#5-薪酬管理) +6. [社保公积金管理](#6-社保公积金管理) +7. [离职解聘管理](#7-离职解聘管理) +8. [AI 智能助手](#8-ai-智能助手) +9. [系统设置](#9-系统设置) +10. [数据导入导出](#10-数据导入导出) +11. [通知管理](#11-通知管理) +12. [员工自助门户](#12-员工自助门户) +13. [安全与权限体系](#13-安全与权限体系) + +--- + +## 1. 系统概述与角色 + +### 1.1 系统简介 + +AIHR 是一套面向中小企业的智能人力资源管理 SaaS 系统,覆盖员工全生命周期管理:入职 → 在职管理(合同、薪酬、社保、考勤、绩效、培训、奖惩)→ 离职/解聘。系统内置 AI 法律助手,提供劳动合同审查、案例匹配和风险预警能力。 + +### 1.2 角色定义 + +| 角色 | 标识 | 权限范围 | +|------|------|----------| +| 管理员 | `ADMIN` | 全部功能,包括用户管理、数据导入导出、系统设置 | +| HR 专员 | `HR` | 花名册、薪酬、社保、离职等日常业务操作 | +| 只读用户 | `VIEWER` | 仅查看数据,不可修改 | +| 员工 | `EMPLOYEE` | 员工自助门户,查看工资条、合同、入职填报 | + +### 1.3 套餐计划 + +| 套餐 | 员工上限 | AI 问答/月 | 合同审查/月 | 案例匹配/月 | +|------|---------|-----------|-----------|-----------| +| FREE | 50 | 10 | 3 | 3 | +| PRO | 500 | 100 | 20 | 20 | +| ENTERPRISE | 无限 | 无限 | 无限 | 无限 | + +--- + +## 2. 注册与登录 + +### 2.1 企业注册 + +**场景**:新企业首次使用系统,HR 负责人注册企业账号。 + +**操作流程**: +1. 访问 `/register` 页面 +2. 填写:企业名称、姓名、手机号、密码(≥8位) +3. 系统自动创建企业组织(默认 FREE 套餐)和 ADMIN 用户 +4. 注册成功后跳转登录页 + +**示例**: +``` +企业名称:北京科技有限公司 +姓名:张三 +手机号:13800138000 +密码:Abc12345 +→ 注册成功,企业 ID 自动生成,套餐为 FREE +``` + +### 2.2 登录 + +**场景**:已注册用户登录管理后台。 + +**操作流程**: +1. 访问 `/login` 页面 +2. 输入手机号 + 密码 +3. 登录成功后获取 JWT accessToken + refreshToken +4. 前端存储 token 到 localStorage,跳转 Dashboard + +**安全机制**: +- 登录限流:每分钟 5 次 +- 认证限流:每分钟 10 次 +- JWT 双 Token 机制,accessToken 过期后用 refreshToken 刷新 + +### 2.3 忘记密码 + +**场景**:用户忘记密码,通过手机验证码重置。 + +**操作流程**: +1. 访问 `/forgot-password` 页面 +2. 输入手机号 → 系统生成 6 位验证码(开发环境直接返回,生产环境发短信) +3. 输入验证码 + 新密码(≥8位) +4. 系统校验验证码有效性(5分钟过期,最多5次错误尝试) +5. 验证通过后重置密码 + +**示例**: +``` +步骤1:输入手机号 13800138000 → 获取验证码 385721 +步骤2:输入验证码 385721 + 新密码 NewPass123 +→ 密码重置成功 +``` + +--- + +## 3. Dashboard 仪表盘 + +### 3.1 数据概览 + +**场景**:HR 登录后查看企业人力资源整体状况。 + +**展示内容**: +- 员工总数、在职人数、离职人数 +- 本月新入职/离职统计 +- 合同即将到期预警(30/60/90天) +- 未签合同员工提醒 +- 社保/公积金基数异常预警 +- 加班时长超标预警 +- 待办风险事项列表 + +**API**:`GET /api/dashboard` + +### 3.2 待办事项管理 + +**场景**:HR 处理系统自动检测到的风险事项(如合同到期、社保断缴等)。 + +**操作示例**: +``` +待办列表显示: +- 「张三的合同将于 2025-08-15 到期,请及时续签」 [处理] [忽略] +- 「李四社保基数低于最低标准」 [处理] [忽略] + +操作:点击「处理」→ 标记为 RESOLVED +操作:勾选多条 → 点击「批量处理」或「批量忽略」 +``` + +**API**: +- `PATCH /api/dashboard/todos/:id/resolve` — 标记完成 +- `PATCH /api/dashboard/todos/:id/ignore` — 忽略 +- `PATCH /api/dashboard/todos/batch-resolve` — 批量完成 +- `PATCH /api/dashboard/todos/batch-ignore` — 批量忽略 + +--- + +## 4. 花名册管理 + +### 4.1 员工列表与筛选 + +**场景**:HR 查看企业所有员工,按状态/合同状态/姓名/部门筛选。 + +**操作流程**: +1. 访问 `/roster` 页面 +2. 搜索框输入姓名或部门(支持模糊搜索,300ms 防抖) +3. 按状态筛选:在职(ACTIVE)、待入职(PRE_HIRE)、已离职(RESIGNED) +4. 按合同状态筛选:生效中、即将到期、已过期、未签订(unsigned)、无固定期限 +5. 分页展示,每页可选 10/20/50 条 + +**分页优化说明**: +- 状态过滤在数据库层完成,减少内存过滤 +- `unsigned`(未签合同)通过 Prisma `contracts: { none: {} }` 在 DB 层过滤 +- 其他合同状态因需计算,仍需内存过滤后分页 + +**API**:`GET /api/roster?page=1&pageSize=20&search=张&status=ACTIVE&contractStatus=expiring` + +### 4.2 新增员工 + +**场景**:新员工入职,HR 录入员工信息并创建初始合同。 + +**操作流程**: +1. 点击「新增员工」按钮 +2. 填写基本信息: + - 姓名、性别、手机号、身份证号(加密存储) + - 入职日期、部门、月薪(加密存储) + - 城市(默认北京) + - 社保基数、公积金基数(默认等于月薪) + - 社保起缴月、公积金起缴月(默认入职月) +3. 填写合同信息(可选): + - 合同类型:固定期限(FIXED)、无固定期限(UNFIXED)、以完成一定工作为期限(PROJECT)、未签订(UNSIGNED) + - 签订日期、起始日期、结束日期 + - 签订方式:纸质(PAPER)、电子(ELECTRONIC) + - 合同年限、试用期月数、试用期工资 +4. 系统在事务中一次性创建: + - 员工基本信息 + - 社保缴费记录(ONBOARDING) + - 公积金缴费记录(ONBOARDING) + - 薪资变更记录(ONBOARDING,旧薪资=0) + - 部门变更记录(ONBOARDING) + - 劳动合同记录 +5. 自动触发风险检测 + +**示例**: +``` +姓名:李四 +性别:男 +手机号:13900139000 +身份证号:110101199001011234 +入职日期:2025-07-01 +部门:技术部 +月薪:15000 +城市:北京 +社保基数:15000 +公积金基数:15000 +合同类型:固定期限 +签订日期:2025-07-01 +起始日期:2025-07-01 +结束日期:2028-06-30 +试用期:6个月 +试用期工资:12000 + +→ 事务创建:员工 + 社保记录 + 公积金记录 + 薪资记录 + 部门记录 + 合同 +→ 自动风险检测:检查试用期是否合法(合同期36个月,试用期6个月 ✓) +``` + +**API**:`POST /api/employees` + +### 4.3 员工详情档案 + +**场景**:查看某员工的完整人事档案。 + +**展示标签页**: +- **基本信息**:姓名、性别、手机、身份证(脱敏)、入职日期、部门、薪资、城市 +- **合同信息**:所有合同列表,合同状态(生效/即将到期/已过期) +- **工资条**:历史工资条记录 +- **加班记录**:月度加班统计 +- **奖惩记录**:违纪处分记录 +- **考勤记录**:最近90天考勤 +- **培训记录**:参加的培训及结果 +- **绩效记录**:考核周期及评分 +- **离职记录**:离职/解聘历史 +- **附件**:上传的文件(合同扫描件、身份证复印件等) +- **证据链**:相关审计日志 + +**API**:`GET /api/roster/:id/profile` + +### 4.4 调整薪资 + +**场景**:员工涨薪/降薪,HR 记录薪资变更。 + +**操作流程**: +1. 在员工详情中点击「调薪」 +2. 输入新薪资、生效日期 +3. 系统创建薪资变更记录,关闭旧记录的 endMonth +4. 更新员工当前月薪(加密存储) + +**示例**: +``` +员工:李四,当前薪资 15000 +新薪资:18000 +生效日期:2025-08-01 +→ 创建薪资变更记录:旧=15000,新=18000,生效月=2025-08 +→ 更新员工 monthlySalary = encrypt(18000) +``` + +### 4.5 调整部门 + +**场景**:员工内部转岗,HR 记录部门变更。 + +**操作流程**: +1. 在员工详情中点击「调岗」 +2. 选择新部门、生效月份 +3. 系统创建部门变更记录,关闭旧记录的 endMonth + +### 4.6 重新雇佣 + +**场景**:已离职员工重新入职。 + +**操作流程**: +1. 在已离职员工列表中点击「重新雇佣」 +2. 输入新入职日期、部门、薪资、新合同信息 +3. 系统更新员工状态为 ACTIVE,创建新的社保/公积金/薪资/部门/合同记录 + +### 4.7 合同续签合规预检 + +**场景**:批量续签合同前,系统自动检查合规风险。 + +**操作流程**: +1. 选择多个即将到期的合同 +2. 点击「批量续签预检」 +3. 系统批量查询所有相关员工的历史固定期限合同(优化:一次查询替代 N 次循环) +4. 对每个合同返回: + - 当前是第几次固定期限续签 + - 是否应签无固定期限(≥2次固定期限续签 或 工作满10年) + - 风险预警信息和建议 + +**示例**: +``` +预检结果: +| 合同ID | 员工 | 续签次数 | 预警 | +|--------|------|---------|------| +| c001 | 张三 | 3 | ⚠️ 第3次续签应订立无固定期限劳动合同 | +| c002 | 李四 | 1 | ✅ 可续签固定期限(第1次续签) | +| c003 | 王五 | 2 | ⚠️ 已工作12年,应订立无固定期限劳动合同 | +``` + +**API**:`POST /api/employees/contracts/preview-renew` + +### 4.8 合同续签 + +**场景**:对单个合同执行续签操作。 + +**操作流程**: +1. 在员工详情的合同标签页中点击「续签」 +2. 选择续签类型(固定期限/无固定期限)、新起止日期 +3. 系统关闭旧合同,创建新合同记录 + +--- + +## 5. 薪酬管理 + +### 5.1 发薪批次 + +**场景**:HR 按月创建发薪批次,录入员工薪资明细。 + +**操作流程**: +1. 访问 `/money` 页面,默认显示「发薪批次」标签 +2. 点击「创建批次」 +3. 选择: + - 批次类型:常规发薪(REGULAR)、离职结算(TERMINATION)、奖金(BONUS)、经济补偿金(SEVERANCE) + - 发薪月份 + - 创建模式: + - `copy_last`:复制上月批次数据 + - `blank_employees`:空白模板但自动带入所有在职员工 + - `blank_all`:完全空白 + - `copy_batch`:复制指定批次 +4. 批次创建后,可逐条编辑员工薪资明细(基本工资、加班费、津贴、扣除、奖金等) +5. 可添加/移除员工 +6. 确认数据无误后点击「归档」→ 批次锁定不可编辑 + +**示例**: +``` +创建批次: + 类型:常规发薪 + 月份:2025-07 + 模式:复制上月 +→ 自动复制 2025-06 批次的所有员工数据和薪资项 + +编辑员工「张三」的薪资: + 基本工资:15000 + 加班费:2000 + 津贴:500 + 奖金:3000 + 扣除:0 + → 系统自动计算:合计 20500,社保个人 1575,公积金 1800,个税 745,实发 16380 + +归档批次 → 状态变为 ARCHIVED,不可再编辑 +``` + +**API**: +- `POST /api/payroll2/batches` — 创建批次 +- `GET /api/payroll2/batches` — 批次列表 +- `GET /api/payroll2/batches/:id` — 批次详情 +- `PUT /api/payroll2/batches/:id/items/:employeeId` — 编辑薪资项 +- `POST /api/payroll2/batches/:id/archive` — 归档 +- `DELETE /api/payroll2/batches/:id` — 删除批次 + +### 5.2 薪酬模版 + +**场景**:自定义工资条的薪酬项目及其计算公式。 + +**操作流程**: +1. 切换到「薪酬模版」标签 +2. 查看预置薪酬项(基本工资、加班费、津贴、扣除、奖金、社保个人、公积金个人、个税、实发工资) +3. 可新增自定义薪酬项: + - 名称、编码、类型(输入项 INPUT / 计算项 CALCULATED) + - 计算公式(如 `baseSalary * 0.1`) + - 排序顺序、是否可编辑 +4. 预置项不可删除,自定义项可删除 + +**示例**: +``` +新增薪酬项: + 名称:交通补贴 + 编码:transport_allowance + 类型:输入项(INPUT) + 排序:6 + 可编辑:是 +→ 创建成功,发薪批次中将出现该列 +``` + +### 5.3 加班费计算 + +**场景**:批量导入加班记录,系统自动计算加班费。 + +**操作流程**: +1. 切换到「加班费计算」标签 +2. 选择月份 +3. 上传 Excel 文件(包含员工姓名、加班日期、加班时长、加班类型) +4. 系统解析并预览数据 +5. 确认后导入,系统按加班类型自动计算: + - 工作日加班:1.5倍 + - 休息日加班:2倍 + - 法定节假日加班:3倍 +6. 计算结果可导入到发薪批次 + +### 5.4 工资条管理 + +**场景**:从已归档批次汇总生成工资条,员工可在自助门户查看。 + +**操作流程**: +1. 切换到「工资条管理」标签 +2. 选择月份 +3. 点击「从批次汇总生成」→ 系统从该月已归档批次汇总数据,生成/覆盖工资条 +4. 工资条包含:基本工资、各项明细、合计、社保、公积金、个税、实发、累计数据 +5. 可查看已确认/未确认数量 +6. 员工在自助门户确认后,系统记录确认时间和 IP + +**示例**: +``` +生成 2025-07 工资条: +→ 查找 2025-07 所有已归档批次 +→ 按员工汇总各项数据 +→ 生成工资条(包含年度累计收入、累计税额等) +→ 员工张三在门户确认 → 记录 confirmedAt + IP +→ HR 端显示:已确认 15/30 人 +``` + +**API**: +- `POST /api/payroll2/payslips/generate-from-batch` — 从批次生成 +- `GET /api/payroll2/payslips` — 工资条列表 +- `POST /api/portal/payslip/:id/confirm` — 员工确认(门户端) + +--- + +## 6. 社保公积金管理 + +### 6.1 社保/公积金政策配置 + +**场景**:HR 设置各城市的社保和公积金缴费比例。 + +**操作流程**: +1. 访问 `/social` 页面 +2. 在「社保」或「公积金」标签下配置: + - 城市(如北京、上海、深圳) + - 缴费比例: + - 养老保险:单位 16% / 个人 8% + - 医疗保险:单位 10% / 个人 2% + - 失业保险:单位 0.5% / 个人 0.5% + - 工伤保险:单位 0.2% + - 生育保险:单位 0.8% + - 住房公积金:单位 12% / 个人 12% + - 缴费基数上下限 +3. 保存后创建新版本,旧版本自动失效 +4. 支持查看历史版本 + +**示例**: +``` +配置北京社保(2025年度): + 养老单位:16% 个人:8% + 医疗单位:10% 个人:2% + 失业单位:0.5% 个人:0.5% + 工伤单位:0.2% + 生育单位:0.8% + 基数下限:6326 上限:33891 + +配置北京公积金: + 单位:12% 个人:12% + 基数下限:2420 上限:33891 +``` + +### 6.2 月度缴费明细 + +**场景**:按月查看社保/公积金缴费明细。 + +**操作流程**: +1. 切换到「月度明细」标签 +2. 选择月份和城市 +3. 系统展示所有在职员工的缴费明细: + - 员工姓名、缴费基数 + - 单位缴纳各项明细、个人缴纳各项明细 + - 合计单位缴纳、合计个人缴纳 +4. 支持导出 Excel + +### 6.3 基数调整 + +**场景**:年度社保基数调整,HR 批量调整员工缴费基数。 + +**操作流程**: +1. 在社保配置页面点击「基数调整」 +2. 系统列出所有员工当前基数 +3. HR 可逐个修改或批量按规则调整(如统一设为新基数下限) +4. 确认后系统: + - 关闭旧的社保/公积金缴费记录(设置 endMonth) + - 创建新的缴费记录(设置新基数) +5. 调整后可「重置」恢复到调整前状态 + +**示例**: +``` +2025年度基数调整: + 张三:旧基数 12000 → 新基数 15000 + 李四:旧基数 8000 → 新基数 9000 + +→ 关闭旧记录 endMonth = 2025-06 +→ 创建新记录 startMonth = 2025-07, base = 新基数 +``` + +**API**: +- `POST /api/social/adjust` — 执行基数调整 +- `POST /api/social/reset-adjust` — 重置调整 +- `GET /api/social/config` — 获取当前配置 +- `POST /api/social/config` — 保存新配置版本 + +--- + +## 7. 离职解聘管理 + +### 7.1 解聘(公司发起) + +**场景**:公司因故解聘员工,需要风险评估和合规检查。 + +**操作流程**: +1. 访问 `/termination` 页面 +2. 点击「解聘」按钮 +3. 选择员工、解聘原因: + - FAULT:员工过错(严重违纪等) + - NONFAULT:非过错解除 + - LAYOFF:经济性裁员 + - EXPIRED:合同到期不续签 +4. 填写解聘日期、经济补偿金 +5. 设置社保/公积金截止月份 +6. 系统自动进行风险评估: + - 检查员工是否在孕期、医疗期、工伤期 + - 检查工作年限和合同类型 + - 生成风险等级(SAFE / WARNING / DANGER)和预警列表 +7. 系统生成解聘清单(checklist),包含: + - 工作交接清单 + - 社保公积金停缴 + - 经济补偿金计算 + - 竞业限制提醒 + - 保密义务提醒 +8. 确认后提交,系统在事务中: + - 创建解聘记录 + - 关闭社保/公积金缴费记录 + - 更新员工状态(如解聘日期≤今天则设为 RESIGNED) + - 关闭待处理风险项 + +**示例**: +``` +解聘员工张三: + 原因:员工过错(FAULT) + 解聘日期:2025-08-01 + 经济补偿金:0 + +风险评估结果: + 风险等级:WARNING + 预警: + - 该员工处于医疗期,非过错解除有法律风险 + - 建议等待医疗期结束后再解除 + +解聘清单: + ☐ 工作交接完成 + ☐ 社保停缴(截止月:2025-08) + ☐ 公积金停缴(截止月:2025-08) + ☐ 竞业限制协议提醒 + ☐ 保密义务提醒 + ☐ 离职证明开具 +``` + +**API**: +- `POST /api/terminations` — 创建解聘 +- `GET /api/terminations/checklist/:reason` — 获取解聘清单 +- `GET /api/terminations/assess/:employeeId` — 风险评估 + +### 7.2 离职(员工主动) + +**场景**:员工主动提出离职。 + +**操作流程**: +1. 在离职管理页面点击「离职」 +2. 选择员工、离职日期 +3. 填写离职原因、备注 +4. 系统在事务中创建离职记录,关闭社保/公积金,更新员工状态 + +### 7.3 撤回离职/解聘 + +**场景**:离职/解聘日期尚未到达,HR 撤回操作。 + +**操作流程**: +1. 在花名册或离职管理页面,对待离职/待解聘员工点击「撤回」 +2. 系统删除离职/解聘记录,恢复员工状态为 ACTIVE +3. 仅在离职日期未到时可撤回 + +### 7.4 批量解聘 + +**场景**:经济性裁员,需批量处理多名员工。 + +**操作流程**: +1. 点击「批量解聘」 +2. 批量预检(系统一次查询所有员工信息和历史离职记录): + - 检查每个员工是否已有离职记录 + - 检查是否存在风险(孕期、医疗期等) +3. 预检通过后,填写批量解聘信息 +4. 系统逐个在事务中执行解聘,返回成功/失败列表 + +**示例**: +``` +批量解聘预检: + 张三:✅ 可解聘 + 李四:⚠️ 处于孕期,有法律风险 + 王五:❌ 已有离职记录 + +执行批量解聘(张三、王五): + 张三:✅ 成功 + 王五:❌ 已有离职记录 + 结果:成功 1,失败 1 +``` + +**API**: +- `POST /api/terminations/batch/preview` — 批量预检 +- `POST /api/terminations/batch` — 批量执行 + +### 7.5 解聘流程状态机 + +**场景**:复杂解聘场景需要多级审批。 + +**状态流转**: +``` +DRAFT → PENDING_APPROVAL → APPROVED → EXECUTING → COMPLETED + ↓ + REJECTED +``` + +**操作流程**: +1. **创建草稿**:HR 创建解聘草稿,填写基本信息 +2. **提交审批**:草稿提交后状态变为 PENDING_APPROVAL +3. **审批通过/驳回**:管理员审批,通过则 APPROVED,驳回则 REJECTED(可修改后重新提交) +4. **执行解聘**:审批通过后执行,状态 EXECUTING → COMPLETED +5. **取消**:任何阶段可取消,状态变为 CANCELLED + +**API**: +- `POST /api/terminations/draft` — 创建草稿 +- `PUT /api/terminations/draft/:id` — 修改草稿 +- `POST /api/terminations/draft/:id/submit` — 提交审批 +- `POST /api/terminations/:id/approve` — 审批通过 +- `POST /api/terminations/:id/reject` — 驳回 +- `POST /api/terminations/:id/execute` — 执行解聘 +- `POST /api/terminations/:id/cancel` — 取消 + +--- + +## 8. AI 智能助手 + +### 8.1 法律问答 + +**场景**:HR 遇到劳动法相关问题,向 AI 助手提问。 + +**操作流程**: +1. 访问 `/ai-assistant` 页面 +2. 在对话框输入问题 +3. 系统通过 RAG(检索增强生成)从知识库中检索相关法律条文 +4. AI 流式返回回答(SSE 实时输出) +5. 支持语音输入 + +**示例**: +``` +用户:员工试用期可以超过6个月吗? +AI:根据《劳动合同法》第十九条,试用期最长不得超过6个月。3年以上固定期限 +合同和无固定期限合同,试用期不得超过6个月。同时,同一用人单位与同一劳动 +者只能约定一次试用期。 +``` + +**API**:`POST /api/ai/chat`(流式 SSE) + +**用量限制**:按套餐计划限制每月次数。 + +### 8.2 合同审查 + +**场景**:HR 上传劳动合同文本,AI 自动审查合规风险。 + +**操作流程**: +1. 在 AI 助手页面切换到「合同审查」 +2. 粘贴或上传合同文本 +3. AI 分析合同条款,输出: + - 合规风险点 + - 缺失条款提醒 + - 修改建议 + +**API**:`POST /api/ai/review` + +### 8.3 案例匹配 + +**场景**:输入案情描述,AI 匹配相似劳动争议案例。 + +**操作流程**: +1. 切换到「案例匹配」 +2. 输入案情描述 +3. AI 返回相似案例列表,包含判决结果和要点 + +**API**:`POST /api/ai/match-case` + +### 8.4 风险预测 + +**场景**:基于企业当前员工数据,AI 预测潜在劳动争议风险。 + +**API**:`POST /api/ai/predict-risks` + +--- + +## 9. 系统设置 + +### 9.1 企业信息 + +**场景**:查看和修改企业基本信息。 + +**操作流程**: +1. 访问 `/settings` 页面 +2. 查看企业名称、套餐计划、员工上限、创建时间 +3. 管理员可修改企业名称 + +**权限**:修改操作需要 ADMIN 角色。 + +### 9.2 用户管理 + +**场景**:管理员添加/管理 HR 用户账号。 + +**操作流程**: +1. 在设置页面查看用户列表 +2. 点击「添加用户」: + - 姓名、手机号、密码、角色(ADMIN/HR/VIEWER) +3. 可编辑用户信息、修改角色 +4. 可删除用户 + +**权限**:全部操作需要 ADMIN 角色(`requireAdmin` 中间件保护)。 + +**API**: +- `GET /api/settings/users` — 用户列表 +- `POST /api/settings/users` — 添加用户 +- `PUT /api/settings/users/:id` — 编辑用户 +- `DELETE /api/settings/users/:id` — 删除用户 + +### 9.3 套餐切换 + +**场景**:企业升级/降级套餐。 + +**操作流程**: +1. 在设置页面查看当前套餐 +2. 管理员可切换套餐:FREE → PRO → ENTERPRISE +3. 切换后立即生效,影响 AI 用量限制和员工上限 + +**权限**:需要 ADMIN 角色。 + +**API**:`POST /api/settings/plan` + +--- + +## 10. 数据导入导出 + +### 10.1 数据导入 + +**场景**:HR 从 Excel 批量导入员工数据。 + +**操作流程**: +1. 在花名册页面点击「导入」 +2. 下载导入模板(Excel) +3. 填写员工数据后上传 +4. 系统解析 Excel 并预览: + - 校验身份证号格式(18位校验位算法,支持15位升级) + - 校验手机号格式 + - 检查重复员工(姓名+手机号) +5. 确认后批量创建员工记录 + +**权限**:需要 ADMIN 角色。 + +**安全**: +- 文件大小限制 10MB +- 身份证号加密存储 +- 支持导入员工、合同、社保、公积金等数据 + +**API**: +- `POST /api/import/employees` — 导入员工 +- `POST /api/import/contracts` — 导入合同 +- `POST /api/import/social` — 导入社保记录 + +### 10.2 数据导出 + +**场景**:HR 导出企业数据用于备份或报表。 + +**操作流程**: +1. 在设置或花名册页面点击「导出」 +2. 选择导出模块:员工、合同、离职记录、薪资批次、工资条、社保记录、公积金记录、风险项 +3. 选择格式:JSON 或 Excel +4. 选择是否脱敏(非 ADMIN 用户强制脱敏): + - 身份证号:显示前3位 + **** + 后4位 + - 银行账号:显示后4位 + - 工资金额:ADMIN 可见明文,其他角色不可见 +5. 系统分页查询数据(每批 500 条),生成文件下载 + +**权限**:需要 ADMIN 角色。 + +**API**:`GET /api/export/all?format=xlsx&mask=true&modules=employees,contracts` + +--- + +## 11. 通知管理 + +### 11.1 通知设置 + +**场景**:HR 配置各类通知的触发规则和推送方式。 + +**可配置项**: +- 合同到期提醒:开关 + 提前天数(1-365天) +- 未签合同提醒:开关 +- 加班超标提醒:开关 +- 工资条就绪通知:开关 + 发薪日(1-28号) +- 社保办理日提醒:开关 + 办理日(1-28号) +- 公积金办理日提醒:开关 + 办理日 +- 个税申报日提醒:开关 + 申报日 +- 推送方式: + - 企微 Webhook:填写 Webhook URL + - 邮件通知:开关 + 邮箱地址 + +**API**: +- `GET /api/notifications/settings` — 获取设置 +- `PUT /api/notifications/settings` — 更新设置 + +### 11.2 通知日志 + +**场景**:查看历史通知记录。 + +**展示内容**: +- 通知标题、内容 +- 通知类型(合同到期、工资条确认等) +- 推送渠道(IN_APP / WECHAT / EMAIL) +- 发送时间、发送状态 + +**API**:`GET /api/notifications/logs?page=1&pageSize=20` + +--- + +## 12. 员工自助门户 + +### 12.1 员工登录 + +**场景**:员工通过手机号登录自助门户。 + +**访问地址**:`/portal/login` + +**登录方式**: +1. **密码登录**:手机号 + 密码(需 HR 预设密码) +2. **验证码登录**:手机号 → 获取验证码 → 输入验证码 + - 验证码 6 位,5 分钟有效 + - 60 秒内不可重复发送 + - 最多 5 次错误尝试 + +**Token 机制**:员工端使用独立的 JWT Token,角色为 `EMPLOYEE`。 + +### 12.2 工资条查看 + +**场景**:员工查看自己的工资条。 + +**操作流程**: +1. 登录后进入 `/portal/payslip` +2. 选择月份查看当月工资条 +3. 可查看最近 6 个月历史工资条 +4. 点击「确认已阅」→ 记录确认时间和 IP +5. HR 端收到确认通知 + +**API**: +- `GET /api/portal/payslip?month=2025-07` — 查看指定月工资条 +- `GET /api/portal/payslip/history` — 最近6个月历史 +- `POST /api/portal/payslip/:id/confirm` — 确认已阅 + +### 12.3 我的合同 + +**场景**:员工查看自己的劳动合同。 + +**操作流程**: +1. 进入 `/portal/contract` +2. 查看最新合同信息:合同类型、起止日期、签订方式、试用期等 + +**API**:`GET /api/portal/contract` + +### 12.4 入职填报 + +**场景**:新员工通过入职链接填写个人信息。 + +**操作流程**: +1. HR 在花名册中创建员工后,生成入职链接(含 token) +2. 将链接发送给新员工 +3. 员工打开链接 `/portal/onboarding?token=xxx` +4. 填写:姓名、手机号、身份证号、紧急联系人、紧急联系电话、地址、银行卡号、开户行 +5. 提交后状态变为 APPROVED,HR 审核后正式入职 + +**API**:`POST /api/portal/onboarding` + +### 12.5 合同签署确认 + +**场景**:电子合同签署,员工通过链接确认签署。 + +**操作流程**: +1. HR 生成合同签署链接(含 token) +2. 员工打开链接 `/portal/contract-confirm?token=xxx` +3. 查看合同内容 +4. 点击「发送验证码」→ 系统向员工手机发送验证码 +5. 输入验证码确认签署 +6. 系统记录签署时间和 IP + +**API**: +- `POST /api/portal/contract-confirm/send-code` — 发送验证码 +- `POST /api/portal/contract-confirm` — 确认签署 + +--- + +## 13. 安全与权限体系 + +### 13.1 认证机制 + +- **JWT 双 Token**:accessToken(短期)+ refreshToken(长期) +- **Token 刷新**:accessToken 过期后自动用 refreshToken 刷新 +- **限流保护**: + - 登录接口:每分钟 5 次 + - 认证接口:每分钟 10 次 + - 验证码发送:60 秒间隔 + +### 13.2 数据加密 + +| 字段 | 加密方式 | 说明 | +|------|---------|------| +| 身份证号 | AES-256 加密 + SHA-256 哈希 | 加密存储原始值,哈希用于查重 | +| 银行账号 | AES-256 加密 | 仅 ADMIN 可解密查看 | +| 月薪金额 | AES-256 加密 | 仅 ADMIN 可解密查看 | +| 密码 | bcrypt(10轮) | 不可逆 | + +### 13.3 RBAC 权限控制 + +| 操作 | ADMIN | HR | VIEWER | +|------|-------|-----|--------| +| 查看所有数据 | ✅ | ✅ | ✅ | +| 员工增删改 | ✅ | ✅ | ❌ | +| 薪酬管理 | ✅ | ✅ | ❌ | +| 社保管理 | ✅ | ✅ | ❌ | +| 离职管理 | ✅ | ✅ | ❌ | +| 数据导入 | ✅ | ❌ | ❌ | +| 数据导出 | ✅ | ❌ | ❌ | +| 用户管理 | ✅ | ❌ | ❌ | +| 套餐切换 | ✅ | ❌ | ❌ | +| 企业信息修改 | ✅ | ❌ | ❌ | + +### 13.4 审计日志 + +系统自动记录关键操作日志: +- 操作人、操作时间、IP 地址 +- 操作类型(CREATE/UPDATE/DELETE/TERMINATE/IMPORT/EXPORT/AI_CHAT 等) +- 操作实体和详情 +- HR 操作和 AI 调用均记录 + +### 13.5 事务保护 + +以下关键多写操作已使用 Prisma `$transaction` 包裹,确保原子性: +- 创建员工(员工 + 社保 + 公积金 + 薪资 + 部门 + 合同) +- 创建解聘/离职(解聘记录 + 社保停缴 + 公积金停缴 + 员工状态更新 + 风险项关闭) +- 执行解聘(同上 + 状态更新为 COMPLETED) +- 批量解聘(逐个事务) + +### 13.6 环境变量校验 + +系统启动时自动校验关键环境变量: +- `JWT_SECRET`:必须设置,不得使用默认值 +- `JWT_REFRESH_SECRET`:必须设置,不得使用默认值 +- `ENCRYPTION_KEY`:必须设置,不得使用默认值 +- 生产环境(`NODE_ENV=production`)未正确配置将拒绝启动 + +--- + +## 附录:API 路由总览 + +| 模块 | 路由前缀 | 主要功能 | +|------|---------|---------| +| 认证 | `/api/auth` | 登录、注册、刷新Token、忘记密码、重置密码 | +| 仪表盘 | `/api/dashboard` | 数据概览、待办管理 | +| 花名册 | `/api/roster` | 员工列表、详情、增删改 | +| 员工 | `/api/employees` | 创建员工、合同续签预检、合同续签 | +| 薪酬 | `/api/payroll2` | 发薪批次、薪酬模版、加班费、工资条 | +| 社保 | `/api/social` | 社保/公积金配置、月度明细、基数调整 | +| 离职 | `/api/terminations` | 解聘/离职/撤回/批量/流程状态机 | +| AI | `/api/ai` | 法律问答、合同审查、案例匹配、风险预测 | +| 设置 | `/api/settings` | 企业信息、用户管理、套餐切换 | +| 导入 | `/api/import` | Excel 导入员工/合同/社保 | +| 导出 | `/api/export` | 数据导出(JSON/Excel) | +| 通知 | `/api/notifications` | 通知设置、通知日志 | +| 附件 | `/api/attachments` | 文件上传/下载 | +| 员工门户 | `/api/portal` | 登录、工资条、合同、入职填报、合同签署 | diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index 4bc0b5e..51b1ee8 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -11,7 +11,7 @@ import Modal from '../components/ui/Modal' export default function Settings() { const queryClient = useQueryClient() - const [activeSection, setActiveSection] = useState<'org' | 'users' | 'plan' | 'notifications' | 'import'>('org') + const [activeSection, setActiveSection] = useState<'org' | 'users' | 'plan' | 'notifications' | 'import' | 'export'>('org') const { data: orgData } = useQuery({ queryKey: ['org-settings'], @@ -40,6 +40,7 @@ export default function Settings() { { key: 'plan' as const, label: '套餐', icon: CreditCard }, { key: 'notifications' as const, label: '通知设置', icon: Bell }, { key: 'import' as const, label: '数据导入', icon: FileSpreadsheet }, + { key: 'export' as const, label: '数据导出', icon: Download }, ] return ( @@ -77,6 +78,12 @@ export default function Settings() { {activeSection === 'plan' && } {activeSection === 'notifications' && } {activeSection === 'import' && } + {activeSection === 'export' && ( + +

数据导出

+ +
+ )} ) } @@ -131,10 +138,6 @@ function OrgSettings({ orgData, onSave, saving }: { orgData: any; onSave: (data: -
-

数据导出

- -
) }