ソースを参照

docs: 添加原始问题截图引用到技术规格文档

为所有 9 个系统故障问题添加对应的原始截图路径引用:
- 问题1-8: docs/系统故障20260306_images/image1-8.png
- 问题9: docs/系统故障20260306_images/image9.jpeg

便于开发时追溯问题源头和对比修复效果。

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 23 時間 前
コミット
c657a409a6

+ 504 - 0
_bmad-output/implementation-artifacts/tech-spec-system-faults-high-priority-fix.md

@@ -0,0 +1,504 @@
+---
+title: '系统故障高优先级修复 - 数据统计与考勤模块'
+slug: 'system-faults-high-priority-fix'
+created: '2026-03-06T12:30:00Z'
+status: 'ready-for-dev'
+stepsCompleted: [1, 2, 3, 4]
+adversarialReviewCompleted: true
+adversarialReviewFindings: 18
+adversarialReviewApplied: true
+tech_stack: ['React', 'TypeScript', 'Taro', 'React Query', 'RPC Client']
+files_to_modify: [
+  'mini-ui-packages/yongren-statistics-ui/src/pages/Statistics/Statistics.tsx',
+  'mini-ui-packages/rencai-attendance-ui/src/pages/AttendancePage/AttendancePage.tsx',
+  'mini-ui-packages/rencai-attendance-ui/src/utils/mockAttendanceData.ts',
+  'mini-ui-packages/yongren-dashboard-ui/src/pages/Dashboard/Dashboard.tsx'
+]
+code_patterns: ['桥接文件模式', 'React Query hooks', 'RPC 客户端', 'Mock 数据']
+test_patterns: ['Vitest', 'React Testing Library']
+---
+
+# Tech-Spec: 系统故障高优先级修复 - 数据统计与考勤模块
+
+**Created:** 2026-03-06
+
+## Overview
+
+### Problem Statement
+
+根据 2026-03-06 系统故障文档,共有 9 个故障问题,涉及网页端、企业端和人才端:
+
+#### 高优先级问题(需立即修复):
+
+**问题2:企业端-数据统计模块无数据展示**
+- 在职人数:0
+- 平均薪资:¥0
+- 在职率:0%
+- 所有分类分布(残疾类型、性别、年龄、户籍省份)显示"暂无数据"
+- 📸 原始截图:`docs/系统故障20260306_images/image2.png`
+
+**问题6:人才端-本月出勤与考勤数据不一致**
+- 本月出勤:0
+- 累计出勤:0
+- 本月薪资:¥0
+- 📸 原始截图:`docs/系统故障20260306_images/image6.png`
+
+**问题9:人才端-出勤率计算异常**
+- 正常出勤:30天
+- 出勤率:136%(超出100%不合理)
+- 需求:修改为正常出勤22天,出勤率100%
+- 📸 原始截图:`docs/系统故障20260306_images/image9.jpeg`
+
+#### 中优先级问题:
+
+**问题1:网页端-订单管理薪资改为可手动输入修改项**
+- 📸 原始截图:`docs/系统故障20260306_images/image1.png`
+
+**问题3:企业端-订单详情打卡数据需修改为固定内容**
+- 打卡完成率:100%
+- 工资视频:100%
+- 个税视频:100%
+- 📸 原始截图:`docs/系统故障20260306_images/image3.png`
+
+**问题5:人才端-小程序远程打卡提示修改**
+- 当前提示:"该功能开发中"
+- 需求:改为"已打卡成功"
+- 📸 原始截图:`docs/系统故障20260306_images/image5.png`
+
+#### 低优先级问题:
+
+**问题4:企业端-首页人才库点击无跳转**
+- 📸 原始截图:`docs/系统故障20260306_images/image4.png`
+
+**问题7:人才端-薪资记录显示范围修改**
+- 需求:显示当前月上一个月的薪资
+- 📸 原始截图:`docs/系统故障20260306_images/image7.png`
+
+**问题8:企业端-首页去掉最新通知模块**
+- 需求:修复在职人员数量显示不匹配
+- 需求:去掉"最新通知"模块
+- 📸 原始截图:`docs/系统故障20260306_images/image8.png`
+
+### Solution
+
+按优先级修复各类问题:
+
+**高优先级(数据类):**
+1. 修复数据统计模块数据加载逻辑
+2. 修复人才端考勤数据获取和显示
+3. 修正出勤率计算公式
+
+**中优先级(功能完善):**
+4. 订单管理薪资字段支持手动输入
+5. 订单详情打卡数据改为固定值
+6. 远程打卡提示文案修改
+
+**低优先级(优化类):**
+7. 人才库跳转功能修复
+8. 薪资记录时间范围调整
+9. 首页最新通知模块移除
+
+### Scope
+
+**In Scope:**
+全部 9 个故障问题的修复:
+
+**高优先级(3个):**
+- 问题2:企业端-数据统计模块数据加载修复
+- 问题6:人才端-本月出勤数据加载修复
+- 问题9:人才端-出勤率计算逻辑修复(22天,100%)
+
+**中优先级(3个):**
+- 问题1:网页端-订单管理薪资改为手动输入
+- 问题3:企业端-订单详情打卡数据改为固定内容
+- 问题5:人才端-小程序远程打卡提示修改
+
+**低优先级(3个):**
+- 问题4:企业端-首页人才库点击跳转修复
+- 问题7:人才端-薪资记录显示范围修改
+- 问题8:企业端-首页去掉最新通知模块
+
+**Out of Scope:**
+- 重构整个数据统计模块架构
+- 修改数据库表结构(但允许添加测试数据)
+- 实现全新的考勤系统
+- 与其他模块联调(除非直接影响本修复)
+
+**Gray Area(需要判断)**:
+- 如果问题2根源是数据库无数据:允许添加测试数据进行验证
+- 如果需要微调API响应格式:允许调整前端数据处理逻辑
+
+## Context for Development
+
+### Codebase Patterns
+
+**项目架构:**
+- **小程序框架**:Taro (React + TypeScript)
+- **UI 包分离**:页面组件从独立 npm 包导入
+- **数据获取**:React Query (@tanstack/react-query) + RPC 客户端
+- **状态管理**:React hooks (useState, useEffect)
+
+**代码模式:**
+- **桥接文件模式**:小程序页面作为桥接,从 UI 包导入实际组件
+  ```typescript
+  // mini/src/pages/yongren/statistics/index.tsx
+  import Statistics from '@d8d/yongren-statistics-ui/pages/Statistics/Statistics'
+  export default Statistics
+  ```
+- **API 客户端模式**:使用 Hono RPC 客户端调用后端接口
+  ```typescript
+  export const enterpriseStatisticsClient = rpcClient<typeof statisticsRoutes>('/api/v1/yongren/statistics')
+  ```
+- **React Query 模式**:使用 useQuery hook 进行数据获取和缓存
+  ```typescript
+  const { data, isLoading } = useQuery({
+    queryKey: ['statistics', 'employment-count'],
+    queryFn: async () => { ... }
+  })
+  ```
+
+### Files to Reference
+
+| 文件 | 用途 | 关键问题 |
+| ---- | ---- | -------- |
+| `mini-ui-packages/yongren-statistics-ui/src/pages/Statistics/Statistics.tsx` | 企业端数据统计页面 | API 返回数据为 0 |
+| `mini-ui-packages/yongren-statistics-ui/src/api/enterpriseStatisticsClient.ts` | 统计 API 客户端 | 调用 `/api/v1/yongren/statistics/*` |
+| `mini-ui-packages/rencai-attendance-ui/src/pages/AttendancePage/AttendancePage.tsx` | 人才端考勤记录页面 | 使用 Mock 数据,未连接真实 API |
+| `mini-ui-packages/rencai-attendance-ui/src/utils/mockAttendanceData.ts` | Mock 数据生成工具 | 出勤率计算逻辑错误 |
+| `mini-ui-packages/yongren-dashboard-ui/src/pages/Dashboard/Dashboard.tsx` | 企业端首页仪表板 | 人才库跳转、通知模块 |
+
+### Technical Decisions
+
+**问题根源分析:**
+
+**问题2(企业端数据统计为0):**
+- 组件正常,使用 `enterpriseStatisticsClient` 调用 API
+- API 端点:`/api/v1/yongren/statistics/*`
+- 可能原因:
+  1. 后端 API 返回空数据(数据库无数据)
+  2. JWT token 中的 companyId 无效
+  3. 企业用户没有关联的人才数据
+- **修复方向**:检查后端 API 响应,确保数据正确返回
+
+**问题6(人才端考勤数据为0):**
+- 当前使用 **Mock 数据** (`generateMockAttendanceData`)
+- **未连接真实 API**
+- 初始状态 `normalDays: 0` 可能导致显示问题
+- **修复方向**:连接真实 API 或修复 Mock 数据初始化
+
+**问题9(人才端出勤率计算136%):**
+- 计算逻辑在 `calculateAttendanceStats` 函数:
+  ```typescript
+  const attendanceRate = workDays.length > 0
+    ? Math.round((normalDays / workDays.length) * 100)
+    : 0
+  ```
+- 问题:`normalDays` 包含周末,但 `workDays` 应排除周末
+- **修复方向**:修正计算公式,确保出勤率不超过 100%
+- **需求**:改为固定值(22天,100%)
+
+## Implementation Plan
+
+### Pre-Development Tasks(开始前的准备)
+
+在开始修复前,必须先完成以下调查任务:
+
+- [ ] **前置任务 0.1:解决测试账号 401 认证问题**
+  - 动作:使用测试账号 13800138005/13800138004 登录企业端/人才端小程序
+  - 动作:或创建新的测试账号
+  - 验证:账号可正常登录并访问相关页面
+  - 备注:如果 401 无法解决,使用 Mock Service Worker 模拟 API 响应
+
+- [ ] **前置任务 0.2:API 发现**
+  - 动作:确认人才端考勤 API 的完整路径和请求/响应格式
+  - 动作:确认订单管理 API 的完整路径和请求/响应格式
+  - 动作:确认薪资记录 API 的完整路径和请求/响应格式
+  - 备注:使用 curl 或 Postman 测试,记录端点信息
+
+- [ ] **前置任务 0.3:代码调查**
+  - 动作:调查并记录订单管理页面的完整文件路径
+  - 动作:调查并记录订单详情页面的完整文件路径
+  - 动作:调查并记录远程打卡组件的完整文件路径和位置
+  - 动作:调查并记录薪资记录页面的完整文件路径
+  - 备注:使用 Grep/Glob 工具搜索相关代码
+
+### Implementation Strategy(实施方案选择)
+
+**针对问题6和问题9的矛盾,明确选择:**
+
+本次修复采用 **方案 A(短期修复)**:
+- **问题6(考勤数据)**:继续使用 Mock 数据,修正返回值确保不为 0
+- **问题9(出勤率)**:修改 Mock 数据生成函数,返回固定值(22天,100%)
+
+**理由**:真实 API 端点未知,连接成本高。先用 Mock 修复前端显示问题,后续再连接真实 API。
+
+**长期计划(可选,非本次范围)**:
+- 任务 X.1:设计并实现考勤数据 API
+- 任务 X.2:前端连接真实 API,替换 Mock 数据
+- 任务 X.3:移除 Mock 数据相关代码
+
+---
+
+#### 高优先级任务(数据类)
+
+**问题2:企业端-数据统计模块无数据展示**
+
+- [ ] **任务 2.1:检查后端 API 响应**
+  - 文件:使用 curl/Postman 测试 API 端点
+  - 动作:测试 `/api/v1/yongren/statistics/employment-count` 等端点
+  - 验证:确认 API 返回数据还是空数组
+  - 备注:如果 API 返回数据,问题在前端;如果返回空,问题在后端/数据库
+
+- [ ] **任务 2.2:添加调试日志和错误处理**
+  - 文件:`mini-ui-packages/yongren-statistics-ui/src/pages/Statistics/Statistics.tsx`
+  - 动作:在 React Query 的 queryFn 中添加 console.log,打印 API 响应
+  - 动作:添加错误处理逻辑,显示友好的错误提示
+  - 验证:使用浏览器 DevTools 查看 console.log 输出
+  - 备注:帮助定位数据为 0 的具体原因
+
+- [ ] **任务 2.3:根据诊断结果执行修复**
+  - 如果 API 返回空数据:创建测试数据或修复数据查询逻辑
+  - 如果 JWT token 无效:修复 token 获取/传递逻辑
+  - 如果前端显示问题:修复数据绑定逻辑
+  - 添加回退方案:显示"暂无数据"而非"0"
+
+**问题6:人才端-本月出勤数据为0**
+
+- [ ] **任务 6.1:连接真实考勤 API**
+  - 文件:`mini-ui-packages/rencai-attendance-ui/src/pages/AttendancePage/AttendancePage.tsx`
+  - 动作:替换 `generateMockAttendanceData` 为真实 API 调用
+  - 动作:使用 React Query 的 useQuery hook 获取考勤数据
+  - 备注:需要先确认后端考勤 API 端点是否存在
+
+- [ ] **任务 6.2:修复初始状态显示**
+  - 文件:`mini-ui-packages/rencai-attendance-ui/src/pages/AttendancePage/AttendancePage.tsx`
+  - 动作:将初始状态 `normalDays: 0` 改为 `normalDays: 22`(或从 API 获取)
+  - 动作:添加 loading 状态,避免数据为 0 时显示异常
+  - 备注:确保数据加载前显示友好提示
+
+**问题9:人才端-出勤率计算异常**
+
+- [ ] **任务 9.1:调查并修复分子分母计算逻辑**
+  - 文件:`mini-ui-packages/rencai-attendance-ui/src/utils/mockAttendanceData.ts`
+  - 动作:检查 `normalDays` 是否错误地包含了非工作日
+  - 动作:检查 `workDays.length` 计算是否正确
+  - 动作:修复计算逻辑,确保数学上正确
+  - 动作:添加单元测试覆盖边界情况
+  - 最后才添加 `Math.min(100, ...)` 作为防御性编程
+  - 备注:这是根本修复,但需求要求固定值,见任务 9.2
+
+- [ ] **任务 9.2:改为固定值(展示层修复)**
+  - 文件:`mini-ui-packages/rencai-attendance-ui/src/utils/mockAttendanceData.ts`
+  - 动作:修改 `generateMockAttendanceData` 函数,返回固定的统计值
+  - 修改:`attendanceRate: 100, normalDays: 22`
+  - 备注:根据业务需求,这是展示层的固定值,不反映真实计算结果
+
+#### 中优先级任务(功能完善)
+
+**问题1:网页端-订单管理薪资改为可手动输入**
+
+- [ ] **任务 1.1:添加薪资编辑功能**
+  - 文件:待调查(需要找到订单管理页面)
+  - 动作:将薪资显示字段改为可编辑的 Input 组件
+  - 动作:添加保存按钮和 API 调用逻辑
+  - 备注:需要确认薪资字段的数据结构和 API
+
+- [ ] **任务 1.2:实现数据持久化**
+  - 文件:待确认(需要确认订单更新API端点)
+  - 动作:确认订单更新 API 端点:`___`
+  - 动作:实现 API 调用逻辑,将修改后的薪资值保存到后端
+  - 动作:添加权限检查和成功/失败提示
+  - 备注:确保数据修改被正确保存
+
+**问题3:企业端-订单详情打卡数据改为固定内容**
+
+- [ ] **任务 3.1:修改打卡数据显示逻辑**
+  - 文件:待调查(需要找到订单详情页面)
+  - 动作:将动态获取的打卡数据改为固定值
+  - 修改:打卡完成率 100%,工资视频 100%,个税视频 100%
+  - 备注:这是临时修复,后续可能需要恢复动态数据
+
+**问题5:人才端-小程序远程打卡提示修改**
+
+- [ ] **任务 5.1:修改远程打卡提示文案**
+  - 文件:待调查(需要找到远程打卡按钮组件)
+  - 动作:将"该功能开发中"改为"已打卡成功"
+  - 动作:可能需要移除功能禁用状态或弹窗
+  - 备注:这是文案修改,不涉及功能逻辑
+
+#### 低优先级任务(优化类)
+
+**问题4:企业端-首页人才库点击无跳转**
+
+- [ ] **任务 4.1:修复人才库跳转功能**
+  - 文件:`mini-ui-packages/yongren-dashboard-ui/src/pages/Dashboard/Dashboard.tsx`
+  - 动作:检查人才库按钮的 onClick 事件
+  - 动作:添加正确的跳转逻辑(使用 Taro.navigateTo)
+  - 备注:需要确认目标页面路径
+
+**问题7:人才端-薪资记录显示范围修改**
+
+- [ ] **任务 7.1:修改薪资查询时间范围**
+  - 文件:待调查(需要找到薪资记录页面)
+  - 动作:修改查询参数,从"当前月"改为"当前月上一个月"
+  - 备注:需要确认薪资 API 的时间参数格式
+
+**问题8:企业端-首页去掉最新通知模块**
+
+- [ ] **任务 8.1:移除最新通知模块**
+  - 文件:`mini-ui-packages/yongren-dashboard-ui/src/pages/Dashboard/Dashboard.tsx`
+  - 动作:注释或删除最新通知组件的渲染逻辑
+  - 动作:调整页面布局,填补移除后的空白
+  - 备注:确保移除后页面布局正常
+
+- [ ] **任务 8.2:修复在职人员数量显示不匹配**
+  - 文件:`mini-ui-packages/yongren-dashboard-ui/src/pages/Dashboard/Dashboard.tsx`
+  - 动作:检查在职人员数量的数据来源
+  - 动作:与数据统计页面的数量进行对比
+  - 动作:统一数据源或修复显示逻辑
+  - 备注:确保顶部显示的"在职人员3人"与列表中的数量一致
+
+### Acceptance Criteria
+
+#### 高优先级 AC
+
+**问题2:企业端-数据统计模块**
+- [ ] **AC 2.1:** Given 企业用户已登录,when 访问数据统计页面,then 显示正确的在职人数、平均薪资、在职率(非 0)
+- [ ] **AC 2.2:** Given API 返回空数据,when 显示统计卡片,then 显示"暂无数据"而非"0"
+- [ ] **AC 2.3:** Given 数据加载失败,when 发生错误,then 显示友好的错误提示
+
+**问题6:人才端-本月出勤数据**
+- [ ] **AC 6.1:** Given 人才用户已登录,when 访问考勤记录页面,then 显示正确的本月出勤天数(非 0)
+- [ ] **AC 6.2:** Given 数据加载中,when 首次访问页面,then 显示 loading 状态而非"0"
+- [ ] **AC 6.3:** Given 无考勤数据,when 用户没有打卡记录,then 显示"暂无数据"提示
+
+**问题9:人才端-出勤率计算**
+- [ ] **AC 9.1:** Given 计算出勤率,when 正常出勤天数超过工作日,then 出勤率不超过 100%(计算层要求)
+- [ ] **AC 9.2:** Given 需求要求(展示层),when 用户访问考勤记录页面,then 显示固定值(22天,100%)
+  - 注:这是展示层的固定值,不代表实际计算结果
+- [ ] **AC 9.3:** Given 计算逻辑修正,when 任何输入情况,then 出勤率始终 ≤ 100%(计算层要求)
+
+#### 中优先级 AC
+
+**问题1:订单管理薪资输入**
+- [ ] **AC 1.1:** Given 订单详情页,when 点击薪资字段,then 可以手动输入/修改薪资值
+- [ ] **AC 1.2:** Given 修改薪资后,when 点击保存,then 数据成功提交到后端
+
+**问题3:订单详情打卡数据**
+- [ ] **AC 3.1:** Given 订单详情页,when 查看打卡数据统计,then 显示固定值(100%, 100%, 100%)
+- [ ] **AC 3.2:** Given 固定值显示,when 刷新页面,then 值保持不变
+
+**问题5:远程打卡提示**
+- [ ] **AC 5.1:** Given 远程打卡按钮,when 点击按钮,then 显示"已打卡成功"提示
+- [ ] **AC 5.2:** Given 提示修改,when 用户看到提示,then 不再显示"该功能开发中"
+
+#### 低优先级 AC
+
+**问题4:人才库跳转**
+- [ ] **AC 4.1:** Given 首页人才库按钮,when 点击,then 正确跳转到人才列表页面
+
+**问题7:薪资记录范围**
+- [ ] **AC 7.1:** Given 薪资记录页面,when 查询数据,then 显示上个月完整月份的薪资记录
+  - 例如:2026年3月查询时,显示2026年2月1日-2月28日的薪资
+  - 边界情况:如果上个月无数据,then 显示"暂无数据"提示
+
+**问题8:首页通知模块**
+- [ ] **AC 8.1:** Given 首页,when 页面加载,then 不显示"最新通知"模块
+- [ ] **AC 8.2:** Given 移除通知模块,when 页面渲染,then 布局正常无空白
+
+## Additional Context
+
+### Dependencies
+
+**前端依赖:**
+- `@tanstack/react-query` - 数据获取和缓存
+- `@tarojs/components` - Taro 小程序组件库
+- `@d8d/mini-shared-ui-components` - 共享 UI 组件
+- `@d8d/yongren-shared-ui` - 企业端共享组件
+- `@d8d/rencai-shared-ui` - 人才端共享组件
+
+**后端依赖:**
+- `/api/v1/yongren/statistics/*` - 企业端统计 API
+- 待确认:人才端考勤 API 端点
+- 待确认:订单管理 API 端点
+
+**其他依赖:**
+- JWT token 中的 companyId(用于企业端数据隔离)
+- 数据库中的考勤数据和统计数据
+
+### Testing Strategy
+
+**E2E 测试:**
+- 使用 Playwright 验证数据统计页面正确显示数据
+- 使用 Playwright 验证考勤记录页面正确显示出勤数据
+- 验证出勤率计算不超过 100%
+
+**单元测试:**
+- 测试 `calculateAttendanceStats` 函数的各种边界情况
+- 测试出勤率计算逻辑(正常、全勤、缺勤、迟到等)
+- 测试固定值返回逻辑
+
+**单元测试用例(出勤率计算):**
+```typescript
+describe('calculateAttendanceStats', () => {
+  it('正常情况:20天工作日,出勤20天 → 100%', () => {
+    const result = calculateAttendanceStats(/* 20 work days, 20 present */)
+    expect(result.attendanceRate).toBe(100)
+    expect(result.normalDays).toBe(20)
+  })
+
+  it('全勤:22天工作日,出勤22天 → 100%', () => {
+    const result = calculateAttendanceStats(/* 22 work days, 22 present */)
+    expect(result.attendanceRate).toBe(100)
+  })
+
+  it('缺勤:22天工作日,出勤15天 → 68%', () => {
+    const result = calculateAttendanceStats(/* 22 work days, 15 present */)
+    expect(result.attendanceRate).toBe(68)
+  })
+
+  it('边界:22天工作日,出勤0天 → 0%', () => {
+    const result = calculateAttendanceStats(/* 22 work days, 0 present */)
+    expect(result.attendanceRate).toBe(0)
+  })
+
+  it('边界:22天工作日,出勤30天 → 100%(上限)', () => {
+    const result = calculateAttendanceStats(/* 22 work days, 30 present */)
+    expect(result.attendanceRate).toBe(100) // 不超过100
+  })
+})
+```
+
+**固定值验证测试:**
+```typescript
+describe('generateMockAttendanceData - 固定值模式', () => {
+  it('应返回固定的出勤率100%和22天', () => {
+    const { stats } = generateMockAttendanceData(2026, 3)
+    expect(stats.attendanceRate).toBe(100)
+    expect(stats.normalDays).toBe(22)
+  })
+})
+
+**手动测试:**
+- 企业端登录后查看数据统计页面
+- 人才端登录后查看考勤记录页面
+- 验证远程打卡提示文案
+- 验证人才库跳转功能
+
+### Notes
+
+**高风险项目:**
+- 问题2(数据统计为0)可能涉及后端数据问题,需要跨端协作
+- 问题6(考勤数据)需要连接真实 API,可能需要后端支持
+- 问题9(出勤率计算)计算逻辑需要仔细测试各种边界情况
+
+**已知限制:**
+- 当前测试账号返回 401 错误,无法直接登录验证
+- 部分 API 端点路径需要进一步确认
+- 某些页面组件路径需要调查(订单管理、薪资记录等)
+
+**后续考虑:**
+- 问题3(打卡数据固定值)是临时修复,后续可能需要恢复动态数据
+- 建议为所有关键数据添加 loading 和错误状态
+- 建议添加数据刷新功能(下拉刷新)
+- 考虑添加离线缓存功能