Files
TurboHR/docs/20260805-优化.md

18 KiB
Raw Permalink Blame History

20260805 优化需求清单

基于用户反馈整理,对照系统代码逐一分析问题根因及优化方案。


问题1:花名册身份证号复制后粘贴为乱码

模块:花名册
优先级P0
状态:待修复

现状描述: 花名册列表和员工详情页均支持点击身份证号复制,但用户反馈复制后粘贴出来是乱码。

问题分析

  • 列表页 Roster.tsx:522-526:点击脱敏身份证号时调用 navigator.clipboard.writeText(e.idCardNumber) 复制完整身份证号
  • 详情页 BasicInfo.tsx:200-213:同样使用 navigator.clipboard.writeText(profile.idCardNumber) 复制
  • navigator.clipboard.writeText 在非 HTTPS 环境或部分浏览器下可能静默失败,clipboard API 返回的 Promise 可能被 reject
  • 当前 .catch(() => toast.error('复制失败')) 仅提示失败,但用户可能看到"已复制"提示后实际粘贴为空或乱码
  • 可能原因:idCardNumber 字段经过加密存储,解密后的值可能包含不可见字符或编码问题

涉及文件

  • frontend/src/pages/Roster.tsx:522-526
  • frontend/src/pages/roster/BasicInfo.tsx:200-213

优化方案

  1. 检查 idCardNumber 字段是否经过 decrypt() 解密,确认复制的是明文而非加密后的乱码
  2. 增加 fallback 方案:当 navigator.clipboard 不可用时,使用 document.execCommand('copy') + 隐藏 textarea 兜底
  3. 复制后增加验证:读取 clipboard 内容验证是否与原始值一致
  4. 确认后端返回的 idCardNumber 已正确解密为明文

问题2:薪税管理筛选条件需精确到年月日,且每笔工资需有创建时间

模块:薪税管理
优先级P1
状态:待优化

现状描述: 薪税管理中筛选条件仅支持按月(YYYY-MM)筛选,无法精确到具体日期。同时发薪批次列表未显示创建时间,难以区分同月多笔工资。

问题分析

  • BatchTab.tsx:101-103:筛选条件为 monthYYYY-MM)、monthFrommonthTo,均为月份级别
  • 后端 payroll2.routes.ts:151-168:查询参数 monthmonthFrommonthTo 也只支持月份级别
  • PayrollBatch schema 有 createdAt 字段(schema.prisma:710),但前端列表未展示
  • 同月可创建多个批次(batchNo 区分),但用户无法直观看出创建先后顺序

涉及文件

  • frontend/src/pages/money/BatchTab.tsx:101-103, 220-240
  • backend/src/routes/payroll2.routes.ts:151-168
  • backend/prisma/schema.prisma:691-719PayrollBatch model

优化方案

  1. 批次列表增加「创建时间」列,显示 createdAt(格式:YYYY-MM-DD HH:mm
  2. 筛选条件增加日期范围选择器(dateFrom / dateTo),后端按 createdAt 过滤
  3. 列表默认按 createdAt desc 排序(当前按 month desc, batchNo asc
  4. 批次详情中每条工资条目也可展示创建/修改时间

问题3:社保公积金无法创建和保存新的政策比例

模块:社保公积金
优先级P0
状态:待修复

现状描述: 用户在社保公积金页面创建新版本政策比例时无法保存成功。

问题分析

  • 前端 SocialInsurance.tsx:183-201createVersionMutationcreateHousingVersionMutation 调用后端 API
  • 后端 social.routes.ts:126-168:创建社保配置版本时,检查同一城市同一生效月份是否已有版本,如有则返回 400 错误
  • 后端 social.routes.ts:509-549:创建公积金配置版本同样检查重复
  • 可能原因:
    1. 前端 newVersion.city 默认为 '北京',但后端 socialConfigFieldscityoptional,若前端未传或传空可能导致 where 条件匹配到 city: null 的已有记录
    2. 后端 prevCurrent 查询 where: { orgId, isCurrent: true } 未按城市过滤(社保),可能将其他城市的当前版本也标记为失效
    3. 前端 createVersionMutationonSuccess 未显示错误详情,onError 未定义,用户可能看不到错误信息
    4. z.object 校验可能因前端传入的字段类型不匹配(如 number 传为 string)而静默失败

涉及文件

  • frontend/src/pages/SocialInsurance.tsx:183-201, 786-789
  • backend/src/routes/social.routes.ts:11-26, 120-168, 503-549
  • backend/prisma/schema.prisma:430-445SocialInsuranceConfig model

优化方案

  1. 后端 prevCurrent 查询增加 city 过滤条件,避免误将其他城市的版本标记失效
  2. 前端 createVersionMutationcreateHousingVersionMutation 增加 onError 回调,显示后端返回的错误信息
  3. 前端提交前校验必填字段(城市、生效月份、各比例),确保类型正确
  4. 后端 createVersionSchemacity 字段改为 z.string().min(1) 必填,避免 null 匹配问题
  5. 增加 try-catch 日志输出,方便排查具体失败原因

问题4:证据链无法导出,导出证据链显示导出失败

模块:证据链
优先级P0
状态:待修复

现状描述: 员工档案 → 证据链页面,点击「导出证据链」按钮提示"导出失败"。

问题分析

  • 前端 EvidenceChain.tsx:47-63handleExport 使用 fetch 请求 /api/v1/roster/${employeeId}/evidence-chain/export,获取 blob 后下载
  • 后端 roster.routes.ts:582-747:使用 ExcelJS 生成 xlsx 文件并返回
  • 可能原因:
    1. 后端 ExcelJS 依赖未在服务器安装(package.json 中有 exceljs: ^4.4.0,但服务器可能未执行 npm install
    2. workbook.xlsx.write(res) 写入流可能因 res 已设置 header 但写入失败而报错
    3. 前端 fetch 请求未携带 Content-Type: application/json,但后端返回的是二进制流,res.blob() 可能解析失败
    4. 服务器内存不足导致 ExcelJS 生成大文件失败
    5. Nginx 代理可能对大响应体有超时或大小限制

涉及文件

  • frontend/src/pages/roster/EvidenceChain.tsx:47-63
  • backend/src/routes/roster.routes.ts:582-747
  • backend/package.json:22exceljs 依赖)

优化方案

  1. 确认服务器已安装 exceljs 依赖(npm ls exceljs
  2. 后端增加错误日志:catch (err) { console.error('证据链导出失败:', err); next(err) }
  3. 前端 handleExport 增加详细错误处理:读取 res.text() 获取后端错误信息
  4. 后端 workbook.xlsx.write(res) 改为 workbook.xlsx.writeBuffer() 然后 res.send(buffer),避免流写入问题
  5. 检查 Nginx proxy_buffer_sizeproxy_read_timeout 配置

问题5:用工办理中离职证明无法自主选择模板,导出为txt格式且格式混乱

模块:用工办理
优先级P0
状态:待优化

现状描述: 用工办理中开具离职证明时只能使用系统默认模板,导出的证明是 txt 文档格式混乱,希望能自主选择模板且能直接电子签章后提供给员工。

问题分析

  • 前端 WorkProcess.tsx:129-135LEAVING_CERT 表单已有 enterpriseTemplateId 字段(enterprise-template 类型),支持选择企业自定义模板
  • 后端 work-process.service.ts:246-261generateDocument 函数已支持企业模板渲染(formData.enterpriseTemplateId
  • 但生成文件扩展名为 .docwork-process.service.ts:259, 289),实际内容为纯文本,非真正的 Word 文档
  • EnterpriseTemplateSelect 组件(WorkProcess.tsx:722-744)已实现模板选择下拉框,但用户可能未创建企业模板
  • 导出的文书存储在 workProcess.documents 字段(JSON 数组),未关联电子签章流程

涉及文件

  • frontend/src/pages/WorkProcess.tsx:129-135, 722-744
  • backend/src/services/work-process.service.ts:245-290
  • backend/src/routes/work-process.routes.ts:136-192
  • backend/src/routes/enterprise-template.routes.ts

优化方案

  1. 导出格式优化:将纯文本 .doc 改为生成真正的 Word 文档(使用 docx 库)或 PDF 格式
  2. 模板选择增强:在离职证明表单中增加模板预览功能,选择模板后可实时预览渲染效果
  3. 电子签章集成:审批通过后自动创建电子签署记录(类似入职流程 work-process.routes.ts:168-186),场景为 RESIGNATION
  4. 文书下载优化:前端增加文书下载按钮,支持直接下载 PDF/Word 格式
  5. 模板提示:当无企业模板时,增加快捷跳转链接到「模板库 → 企业文本库」创建

问题6:用工办理中多个模块功能重复

模块:用工办理
优先级P2
状态:待优化

现状描述: 用工办理中多个流程类型功能重复,都是录入员工信息和合同时间,希望合并精简。

问题分析

  • work-process.service.ts:8-22:共定义 13 类流程
  • 功能重复的流程:
    • HIRE(员工录用)和 ONBOARD(员工入职):都涉及录入员工信息和创建合同
    • CUSTOM_CONTRACT(自定义合同签署)和 CHANGE(合同变更)和 RENEW(合同续签):都是合同相关操作
    • TERMINATE(合同终止)和 RESCIND(合同解除):都是结束劳动关系
    • INCOME_CERT(收入证明)和 LEAVING_CERT(离职证明):都是开具证明文书
  • 前端 WorkProcess.tsxFORM_FIELDS 配置中多个流程字段高度重叠(employeeName、idCardNumber、startDate、endDate 等)

涉及文件

  • backend/src/services/work-process.service.ts:8-22
  • frontend/src/pages/WorkProcess.tsxFORM_FIELDS 配置)

优化方案

  1. 合并入离职类:将 HIREONBOARD 合并为「入职办理」,区分"新员工入职"和"录用+入职一步完成"两种模式
  2. 合并合同类:将 CUSTOM_CONTRACTCHANGERENEW 合并为「合同签署/变更」,通过子类型区分
  3. 合并解聘类:将 TERMINATERESCIND 合并为「解除/终止合同」,通过原因字段区分
  4. 合并证明类:将 INCOME_CERTLEAVING_CERT 合并为「开具证明」,通过证明类型切换模板
  5. 保留独立流程CONFIRM(转正)、SUSPEND(中止)、FLEXIBLE(灵活用工)、INFO_SUBMIT(信息变更)保持独立
  6. 合并后流程类型从 13 个精简为约 8 个,减少用户选择困难

问题7:违纪记录员工签字确认后企业端需可下载违纪确认证明

模块:违纪记录
优先级P0
状态:待新增

现状描述: 员工在员工端签字确认违纪记录后,企业端没有可下载的违纪确认证明文件。

问题分析

  • 前端 DisciplinaryInfo.tsx:仅展示违纪记录列表和新增表单,无下载/导出功能
  • 后端 roster.routes.ts:478-490:证据链中包含违纪记录信息,但无单独的违纪确认证明导出接口
  • DisciplinaryRecord schemaschema.prisma:565-577)有 employeeAckackDateackMethodwitnessattachmentUrl 字段,但无独立的证明生成功能
  • 培训记录已有签收单导出的先例可参考

涉及文件

  • frontend/src/pages/roster/DisciplinaryInfo.tsx
  • frontend/src/pages/roster/PerformanceRecords.tsx(同样需要下载功能)
  • backend/src/routes/roster.routes.ts(需新增导出接口)
  • backend/prisma/schema.prisma:565-577DisciplinaryRecord model

优化方案

  1. 后端新增 GET /roster/:employeeId/disciplinary/:recordId/certificate 接口,生成违纪确认证明 PDF
  2. 证明内容包含:企业名称、员工姓名、身份证号、违纪事实、处理结果、签字确认状态、确认日期、见证人
  3. 前端 DisciplinaryInfo.tsx 在已签字的记录上增加「下载确认证明」按钮
  4. 同步为绩效考核记录增加类似的确认证明下载功能
  5. 证明格式使用 PDF(使用 pdfkitpuppeteer 生成)

问题8:医疗期计算只有全国和上海两个地区政策

模块:医疗期计算器
优先级P2
状态:待优化

现状描述: 医疗期计算器仅支持"全国(通用规定)"和"上海(特殊规定)"两个地区选项,其他有特殊政策的地区无法选择。

问题分析

  • 前端 MedicalPeriodCalculator.tsx:42-86calculateMedicalPeriod 函数硬编码了 region: 'shanghai' | 'national' 两种逻辑
  • 地区选择为固定下拉框(MedicalPeriodCalculator.tsx:146-153),只有两个选项
  • 后端 special-status.service.ts:68-76calculateMedicalMonths 函数也仅按全国通用标准计算,未区分地区
  • 各地特殊政策举例:
    • 广东:按实际工作年限和本单位工作年限分档
    • 北京:与全国规定一致但有补充细则
    • 江苏、浙江等省份有各自的地方规定

涉及文件

  • frontend/src/pages/tools/MedicalPeriodCalculator.tsx:29-107, 146-153
  • backend/src/services/special-status.service.ts:68-76

优化方案

  1. 将地区政策配置改为数据驱动,支持动态添加地区规则
  2. 新增 medicalPeriodPolicy 配置表或 JSON 配置,存储各地政策分档规则
  3. 前端地区选择改为可搜索下拉框,支持从配置中动态加载
  4. 管理员可在系统设置中添加自定义地区政策(工龄分档 → 医疗期月数 → 累计周期月数)
  5. 预置全国通用、上海、广东、北京等常见地区政策
  6. 后端 calculateMedicalMonths 函数同步支持按地区查询配置

问题9:绩效考核需区分月度/年度考核,得分与等级应关联

模块:绩效考核
优先级P0
状态:待优化

现状描述

  1. 绩效考核无法区分月度考核与年度考核
  2. 录入的得分和等级二者无关联,应按得分自动分等级

问题分析

  • PerformanceRecord schemaschema.prisma:624-643):period 字段为自由文本(YYYY-MMYYYY-Q1),无考核类型字段
  • scoreFloat)和 gradeString,A/B/C/D)是独立字段,前端表单分别输入,无联动逻辑
  • resultEXCELLENT/QUALIFIED/NEED_IMPROVE/UNQUALIFIED)也与 scoregrade 无关联
  • 前端 PerformanceInfo.tsx:38-48:考核周期为自由输入框,得分和等级分别独立选择
  • 前端 PerformanceRecords.tsx:212-228:考核周期使用 type="month" 选择器,仅支持月度

涉及文件

  • frontend/src/pages/roster/PerformanceInfo.tsx:14, 38-48
  • frontend/src/pages/roster/PerformanceRecords.tsx:181-270
  • backend/prisma/schema.prisma:624-643PerformanceRecord model
  • backend/src/routes/roster.routes.ts:1064-1097

优化方案

  1. 新增考核类型字段PerformanceRecord 增加 periodType 字段(MONTHLY/QUARTERLY/YEARLY),前端表单增加类型选择
  2. 考核周期选择优化:根据 periodType 动态切换输入方式(月度→ month 选择器,季度→ Q1/Q2/Q3/Q4 选择,年度→ year 选择器)
  3. 得分等级自动关联
    • 前端输入得分后自动计算等级和结果:
      • 90-100 → A(优秀 EXCELLENT
      • 80-89 → B(合格 QUALIFIED
      • 60-79 → C(需改进 NEED_IMPROVE
      • 0-59 → D(不胜任 UNQUALIFIED
    • 等级和结果字段变为只读,由得分自动填充(可手动覆盖,覆盖后标记为"手动调整")
  4. 后端校验:保存时校验得分与等级的匹配性,若不一致记录日志
  5. 列表展示:绩效考核列表页增加考核类型筛选(月度/季度/年度)

问题10:花名册劳动合同无法下载,且不应能删除

模块:花名册 → 劳动合同
优先级P0
状态:待修复

现状描述

  1. 员工花名册中的劳动合同附件无法下载,点击附件和下载按钮都无反应
  2. 劳动合同作为重要资料可以修改或覆盖,但不应该能删除

问题分析

  • 前端 ContractInfo.tsx:258-289:合同附件展示区域尝试解析 c.attachmentUrlJSON 或 data URL),使用 <a href={att.url} download={att.name}> 下载
  • 附件以 base64 data URL 形式存储在数据库中,<a> 标签的 download 属性对 data URL 在某些浏览器下不生效
  • 下载无反应的可能原因:
    1. data URL 过长,浏览器阻止下载
    2. attachmentUrl 字段存储的是 JSON 字符串,解析失败时回退逻辑可能未正确处理
    3. <a> 标签点击事件被外层 <button> 或其他事件拦截
  • 删除问题:
    • 前端 ContractInfo.tsx:300-306:有删除按钮,调用 deleteContractMutation
    • 后端 employee.routes.ts:279-294DELETE /contracts/:contractId 直接物理删除合同记录
    • 合同作为重要法律文件,应禁止删除,仅允许新增或修改(覆盖)

涉及文件

  • frontend/src/pages/roster/ContractInfo.tsx:258-289, 300-306
  • backend/src/routes/employee.routes.ts:279-294
  • backend/src/services/contract.service.ts:713-764

优化方案

  1. 下载修复
    • 将 data URL 转为 Blob URL 后再触发下载(已有 dataToBlobUrl 函数用于预览,下载也应用相同逻辑)
    • 下载按钮改为 onClick 事件主动创建 <a> 元素并 click,而非依赖 <a> 标签的 download 属性
    • 或改为调用后端接口下载(后端返回文件流),避免前端处理大 data URL
  2. 禁止删除
    • 移除前端删除按钮,改为「作废」按钮(将合同标记为 VOID 状态而非物理删除)
    • 后端 DELETE /contracts/:contractId 改为 PATCH /contracts/:contractId/void,仅更新状态
    • schema 中 LaborContract 增加 status 字段(ACTIVE/VOID),作废后不在正常列表展示但保留记录
    • 证据链中保留作废合同记录,标注"已作废"
  3. 允许覆盖:新增合同时若日期完全相同则提示"已存在相同日期合同,确认覆盖?"(当前是直接报错拒绝)

优先级汇总

编号 问题 优先级 模块
1 花名册身份证号复制乱码 P0 花名册
2 薪税管理筛选精确到日+创建时间 P1 薪税管理
3 社保公积金无法创建保存新政策 P0 社保公积金
4 证据链导出失败 P0 证据链
5 离职证明模板选择+格式+电子签章 P0 用工办理
6 用工办理模块功能重复 P2 用工办理
7 违纪记录签字后下载确认证明 P0 违纪记录
8 医疗期计算增加其他地区政策 P2 医疗期计算器
9 绩效考核月度/年度区分+得分等级关联 P0 绩效考核
10 劳动合同无法下载+不应能删除 P0 花名册

已确认无需修改

(暂无)