|
@@ -0,0 +1,241 @@
|
|
|
|
|
+---
|
|
|
|
|
+title: '修复人才端本月出勤数据不一致'
|
|
|
|
|
+slug: 'talent-attendance-data-fix'
|
|
|
|
|
+created: '2026-03-08T23:05:14+00:00'
|
|
|
|
|
+status: 'ready-for-dev'
|
|
|
|
|
+stepsCompleted: [1, 2, 3, 4]
|
|
|
|
|
+tech_stack: ['React', 'TypeScript', 'Taro 4.1', 'React Query', 'Hono RPC Client']
|
|
|
|
|
+files_to_modify: [
|
|
|
|
|
+ 'mini-talent/src/pages/index/index.tsx',
|
|
|
|
|
+ 'mini-talent/src/pages/settings/index.tsx'
|
|
|
|
|
+]
|
|
|
|
|
+code_patterns: ['Mock数据函数', 'React hooks', 'useState初始化模式', '同步函数调用']
|
|
|
|
|
+test_patterns: ['Vitest', 'React Testing Library', 'Jest']
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+# Tech-Spec: 修复人才端本月出勤数据不一致
|
|
|
|
|
+
|
|
|
|
|
+**Created:** 2026-03-08T23:05:14+00:00
|
|
|
|
|
+
|
|
|
|
|
+## Overview
|
|
|
|
|
+
|
|
|
|
|
+### Problem Statement
|
|
|
|
|
+
|
|
|
|
|
+人才端首页、更多页面、考勤记录页的"本月出勤"数据来源不同,显示值不一致:
|
|
|
|
|
+
|
|
|
|
|
+| 位置 | 当前值 | 数据来源 |
|
|
|
|
|
+|------|--------|----------|
|
|
|
|
|
+| 首页 (`pages/index/index.tsx`) | 29天 | 硬编码 |
|
|
|
|
|
+| 更多页面 (`pages/settings/index.tsx`) | 28天 (mock) / 0天 (API) | 各自的 mock 数据 |
|
|
|
|
|
+| 考勤记录页 (`pages/attendance/index.tsx`) | 22天 | `generateMockAttendanceData` |
|
|
|
|
|
+
|
|
|
|
|
+这种不一致会导致用户体验混乱,不同页面显示的出勤天数不同。
|
|
|
|
|
+
|
|
|
|
|
+### Solution
|
|
|
|
|
+
|
|
|
|
|
+统一使用 `generateMockAttendanceData` 函数作为所有页面的统计数据源:
|
|
|
|
|
+
|
|
|
|
|
+1. 首页:移除硬编码值 `29`,改为调用 `generateMockAttendanceData` 获取 `normalDays`
|
|
|
|
|
+2. 更多页面:移除本地 mock 数据,改为调用 `generateMockAttendanceData` 获取 `normalDays`
|
|
|
|
|
+3. 保持考勤记录页不变(已正确使用 `generateMockAttendanceData`)
|
|
|
|
|
+
|
|
|
|
|
+### Scope
|
|
|
|
|
+
|
|
|
|
|
+**In Scope:**
|
|
|
|
|
+- 修复首页 (`mini-talent/src/pages/index/index.tsx`) 的本月出勤硬编码值
|
|
|
|
|
+- 修复更多页面 (`mini-talent/src/pages/settings/index.tsx`) 的 mock 数据
|
|
|
|
|
+- 统一使用 `generateMockAttendanceData` 函数获取统计数据
|
|
|
|
|
+
|
|
|
|
|
+**Out of Scope:**
|
|
|
|
|
+- 连接真实 API(继续使用 Mock 数据)
|
|
|
|
|
+- 修改其他统计数据(薪资、累计出勤等)
|
|
|
|
|
+- 修改考勤记录页(已正确实现)
|
|
|
|
|
+
|
|
|
|
|
+## Context for Development
|
|
|
|
|
+
|
|
|
|
|
+### Codebase Patterns
|
|
|
|
|
+
|
|
|
|
|
+**Mock 数据函数 (`generateMockAttendanceData`):**
|
|
|
|
|
+- 位置:`mini-talent/src/utils/mockAttendanceData.ts`
|
|
|
|
|
+- 签名:`function generateMockAttendanceData(year: number, month: number): { stats: AttendanceStats, records: AttendanceRecord[] }`
|
|
|
|
|
+- 返回值:`{ stats: { normalDays: 22, attendanceRate: 100, lateCount: 0, earlyLeaveCount: 0, absentCount: 0 }, records: [...] }`
|
|
|
|
|
+- 使用方式:直接同步调用,无需 React Query
|
|
|
|
|
+
|
|
|
|
|
+**首页当前模式:**
|
|
|
|
|
+- 位置:`mini-talent/src/pages/index/index.tsx` 第 223 行
|
|
|
|
|
+- 当前代码:`<Text className="text-white text-2xl font-bold">29</Text>`
|
|
|
|
|
+- 需要修改:导入 `generateMockAttendanceData` 并调用获取 `normalDays`
|
|
|
|
|
+
|
|
|
|
|
+**更多页面当前模式:**
|
|
|
|
|
+- 位置:`mini-talent/src/pages/settings/index.tsx` 第 185-217 行
|
|
|
|
|
+- 当前代码:使用本地 mock 数据 `thisMonthAttendance: 28`
|
|
|
|
|
+- 需要修改:调用 `generateMockAttendanceData` 获取 `normalDays`
|
|
|
|
|
+
|
|
|
|
|
+**考勤记录页正确模式:**
|
|
|
|
|
+- 位置:`mini-talent/src/pages/attendance/index.tsx` 第 19-25 行
|
|
|
|
|
+- 导入:`import { generateMockAttendanceData, getCurrentYearMonth } from '../../utils/mockAttendanceData'`
|
|
|
|
|
+- 使用:`const { stats } = generateMockAttendanceData(year, month).stats`
|
|
|
|
|
+
|
|
|
|
|
+### Files to Reference
|
|
|
|
|
+
|
|
|
|
|
+| File | 行号 | 用途 |
|
|
|
|
|
+| ---- | ---- | ---- |
|
|
|
|
|
+| `mini-talent/src/utils/mockAttendanceData.ts` | 全部 | Mock 数据生成函数,统一的统计数据源 |
|
|
|
|
|
+| `mini-talent/src/types/attendance.ts` | 全部 | 考勤相关类型定义 (`AttendanceStats`, `AttendanceRecord`) |
|
|
|
|
|
+| `mini-talent/src/pages/index/index.tsx` | 223 | 首页,硬编码显示 29 天(需修改) |
|
|
|
|
|
+| `mini-talent/src/pages/settings/index.tsx` | 185-217 | 更多页面,本地 mock 数据(需修改) |
|
|
|
|
|
+| `mini-talent/src/pages/attendance/index.tsx` | 19-47 | 考勤记录页,正确实现示例(参考) |
|
|
|
|
|
+
|
|
|
|
|
+### Technical Decisions
|
|
|
|
|
+
|
|
|
|
|
+**实现策略:**
|
|
|
|
|
+1. 首页:在组件内直接调用 `generateMockAttendanceData`,不使用 useState(因为是纯函数)
|
|
|
|
|
+2. 更多页面:在组件内直接调用 `generateMockAttendanceData`,替换本地 mock 数据
|
|
|
|
|
+3. 使用 `getCurrentYearMonth()` 获取当前年月,传入 `generateMockAttendanceData`
|
|
|
|
|
+
|
|
|
|
|
+**代码模式:**
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 导入
|
|
|
|
|
+import { generateMockAttendanceData, getCurrentYearMonth } from '../../utils/mockAttendanceData'
|
|
|
|
|
+
|
|
|
|
|
+// 在组件内调用
|
|
|
|
|
+const { year, month } = getCurrentYearMonth()
|
|
|
|
|
+const { stats } = generateMockAttendanceData(year, month)
|
|
|
|
|
+
|
|
|
|
|
+// 使用 stats.normalDays 显示出勤天数
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## Implementation Plan
|
|
|
|
|
+
|
|
|
|
|
+### Tasks
|
|
|
|
|
+
|
|
|
|
|
+#### Task 1: 修复首页本月出勤硬编码值
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Task 1.1:** 在首页添加 `generateMockAttendanceData` 导入
|
|
|
|
|
+ - File: `mini-talent/src/pages/index/index.tsx`
|
|
|
|
|
+ - Action: 在文件顶部导入区域添加:
|
|
|
|
|
+ ```typescript
|
|
|
|
|
+ import { generateMockAttendanceData, getCurrentYearMonth } from '../../utils/mockAttendanceData'
|
|
|
|
|
+ ```
|
|
|
|
|
+ - Notes: 参考考勤记录页的导入方式(第 19-25 行)
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Task 1.2:** 在首页组件中调用 Mock 数据函数
|
|
|
|
|
+ - File: `mini-talent/src/pages/index/index.tsx`
|
|
|
|
|
+ - Action: 在 `Dashboard` 组件内部,添加以下代码:
|
|
|
|
|
+ ```typescript
|
|
|
|
|
+ // 获取当前月份考勤统计数据
|
|
|
|
|
+ const { stats: attendanceStats } = (() => {
|
|
|
|
|
+ const { year, month } = getCurrentYearMonth()
|
|
|
|
|
+ return generateMockAttendanceData(year, month)
|
|
|
|
|
+ })()
|
|
|
|
|
+ ```
|
|
|
|
|
+ - Notes: 使用 `attendanceStats` 变量名避免类型冲突,IIFE 确保只在组件渲染时计算一次
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Task 1.3:** 替换首页所有硬编码的统计数据
|
|
|
|
|
+ - File: `mini-talent/src/pages/index/index.tsx`
|
|
|
|
|
+ - Action: 找到第 223-232 行的硬编码值,将:
|
|
|
|
|
+ ```typescript
|
|
|
|
|
+ <Text className="text-white text-2xl font-bold">29</Text> {/* 本月出勤 */}
|
|
|
|
|
+ <Text className="text-white text-2xl font-bold">0</Text> {/* 异常记录 */}
|
|
|
|
|
+ <Text className="text-white text-2xl font-bold">¥4,800</Text> {/* 本月薪资 */}
|
|
|
|
|
+ ```
|
|
|
|
|
+ 替换为:
|
|
|
|
|
+ ```typescript
|
|
|
|
|
+ <Text className="text-white text-2xl font-bold">{stats.normalDays}</Text> {/* 本月出勤 */}
|
|
|
|
|
+ <Text className="text-white text-2xl font-bold">{stats.lateCount + stats.earlyLeaveCount + stats.absentCount}</Text> {/* 异常记录 */}
|
|
|
|
|
+ <Text className="text-white text-2xl font-bold">¥4,800</Text> {/* 本月薪资保持不变 */}
|
|
|
|
|
+ ```
|
|
|
|
|
+ - Notes: 使用 `attendanceStats` 变量名避免与 `stats` 类型冲突
|
|
|
|
|
+
|
|
|
|
|
+#### Task 2: 修复更多页面本地 Mock 数据
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Task 2.1:** 在更多页面添加 `generateMockAttendanceData` 导入
|
|
|
|
|
+ - File: `mini-talent/src/pages/settings/index.tsx`
|
|
|
|
|
+ - Action: 在文件顶部导入区域添加:
|
|
|
|
|
+ ```typescript
|
|
|
|
|
+ import { generateMockAttendanceData, getCurrentYearMonth } from '../../utils/mockAttendanceData'
|
|
|
|
|
+ ```
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Task 2.2:** 替换更多页面的本地 Mock 数据
|
|
|
|
|
+ - File: `mini-talent/src/pages/settings/index.tsx`
|
|
|
|
|
+ - Action: 修改 `displayProfile` 的计算逻辑,将:
|
|
|
|
|
+ ```typescript
|
|
|
|
|
+ stats: {
|
|
|
|
|
+ thisMonthAttendance: 0,
|
|
|
|
|
+ totalAttendance: 0,
|
|
|
|
|
+ thisMonthSalary: 0
|
|
|
|
|
+ }
|
|
|
|
|
+ ```
|
|
|
|
|
+ 替换为:
|
|
|
|
|
+ ```typescript
|
|
|
|
|
+ stats: (() => {
|
|
|
|
|
+ const { year, month } = getCurrentYearMonth()
|
|
|
|
|
+ const { stats } = generateMockAttendanceData(year, month)
|
|
|
|
|
+ return {
|
|
|
|
|
+ thisMonthAttendance: stats.normalDays,
|
|
|
|
|
+ totalAttendance: stats.normalDays, // 累计出勤暂时显示本月值
|
|
|
|
|
+ thisMonthSalary: 4800 // 薪资保持不变
|
|
|
|
|
+ }
|
|
|
|
|
+ })()
|
|
|
|
|
+ ```
|
|
|
|
|
+ - Notes: 累计出勤与本月保持一致,后续可从 API 获取真实累计数据
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Task 2.3:** 保留 mockProfile 作为后备数据源
|
|
|
|
|
+ - File: `mini-talent/src/pages/settings/index.tsx`
|
|
|
|
|
+ - Action: 保留 `mockProfile` 定义作为 API 返回空数据时的后备选项
|
|
|
|
|
+ - Notes: 确保 API 失败时页面仍有数据显示
|
|
|
|
|
+
|
|
|
|
|
+### Acceptance Criteria
|
|
|
|
|
+
|
|
|
|
|
+#### AC 1: 首页显示正确的出勤天数
|
|
|
|
|
+
|
|
|
|
|
+- **Given** 用户已登录人才小程序首页,且 `generateMockAttendanceData` 返回正常数据
|
|
|
|
|
+- **When** 页面加载完成
|
|
|
|
|
+- **Then** 首页"本月出勤"显示 `attendanceStats.normalDays`(当前为 22 天)
|
|
|
|
|
+- **And** "异常记录"显示 `attendanceStats.lateCount + attendanceStats.earlyLeaveCount + attendanceStats.absentCount`(当前为 0)
|
|
|
|
|
+- **And** "本月薪资"显示 ¥4,800(保持不变)
|
|
|
|
|
+
|
|
|
|
|
+#### AC 2: 更多页面显示正确的出勤天数
|
|
|
|
|
+
|
|
|
|
|
+- **Given** 用户已登录人才小程序并点击底部"更多"标签
|
|
|
|
|
+- **When** 更多页面加载完成
|
|
|
|
|
+- **Then** 更多页面"本月出勤"显示 `stats.normalDays`(当前为 22 天)
|
|
|
|
|
+- **And** "累计出勤"显示 `stats.normalDays`(与本月一致,非 *6 计算)
|
|
|
|
|
+- **And** "本月薪资"显示 ¥4,800(保持不变)
|
|
|
|
|
+
|
|
|
|
|
+#### AC 3: 所有页面出勤数据一致
|
|
|
|
|
+
|
|
|
|
|
+- **Given** 用户在人才小程序的首页、更多页面、考勤记录页之间切换
|
|
|
|
|
+- **When** 查看所有页面的出勤天数
|
|
|
|
|
+- **Then** 三个页面显示的"本月出勤"均为 22 天
|
|
|
|
|
+- **And** 数据来源统一为 `generateMockAttendanceData` 函数
|
|
|
|
|
+
|
|
|
|
|
+## Additional Context
|
|
|
|
|
+
|
|
|
|
|
+### Dependencies
|
|
|
|
|
+
|
|
|
|
|
+- 无新增依赖
|
|
|
|
|
+- 依赖现有的 `generateMockAttendanceData` 函数
|
|
|
|
|
+
|
|
|
|
|
+### Testing Strategy
|
|
|
|
|
+
|
|
|
|
|
+1. 首页验证:打开人才小程序首页,确认"本月出勤"显示 22 天
|
|
|
|
|
+2. 更多页面验证:点击底部"更多"标签,确认"本月出勤"显示 22 天
|
|
|
|
|
+3. 一致性验证:首页、更多页面、考勤记录页的出勤天数均为 22 天
|
|
|
|
|
+
|
|
|
|
|
+### Notes
|
|
|
|
|
+
|
|
|
|
|
+- 当前 mock 数据固定返回 `normalDays: 22`, `lateCount: 0`, `earlyLeaveCount: 0`, `absentCount: 0`
|
|
|
|
|
+- 如后续需要动态计算,可修改 `generateMockAttendanceData` 函数
|
|
|
|
|
+- `getCurrentYearMonth()` 使用本地时区,与考勤记录页保持一致
|
|
|
|
|
+
|
|
|
|
|
+### 回滚计划
|
|
|
|
|
+
|
|
|
|
|
+如果修改导致页面显示异常或错误:
|
|
|
|
|
+1. 使用 `git checkout` 恢复修改的文件:
|
|
|
|
|
+ ```bash
|
|
|
|
|
+ git checkout mini-talent/src/pages/index/index.tsx
|
|
|
|
|
+ git checkout mini-talent/src/pages/settings/index.tsx
|
|
|
|
|
+ ```
|
|
|
|
|
+2. 重启开发服务器:`pnpm run dev`
|
|
|
|
|
+3. 刷新页面验证恢复正常
|