feat: 开发任务时间字段重构 + 双口径耗时 + 搜索 + 性能优化
核心变更: - DevTask 字段重构:startDate/dueDate/estimateHours/actualHours 替换为 expectedStartAt/expectedEndAt/actualStartAt/actualEndAt(含时分),预计/实际工时按工作时段(9:00-12:00 + 13:00-18:00)派生计算 - 状态机自动化:到点自动切开发中、未到可手动开干、超期需填延后原因 - 新建 lib/work-hours.ts:calcWorkHours(工作时段过滤)、formatWorkHours(X h(Y 天))、calcTwoMetrics(日历/人力双口径) - 新建 lib/dev-task-transitions.ts:状态切换守卫 - 三个 Tab 顶部统计:开发任务(预/日历/人力)、测试用例 / Bug(日历 / 人力);版本概览总人天投入改双行(日历总耗时 / 人力总投入) - 三个 Tab 加搜索框:300ms debounce + 标题/编号模糊匹配 - 性能优化:requirementIds/categories/requirements/testCases 转 Map/Set 索引、Row 组件 React.memo - 全局耗时显示统一带天数换算:8h(1天)、11h(1.4天) 新增文件: SearchInput.tsx, useDebouncedValue.ts, work-hours.ts, dev-task-transitions.ts, 设计文档 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
# 版本统计「日历耗时 + 人力投入」双口径设计
|
||||
|
||||
## Context
|
||||
|
||||
当前版本详情下的开发任务/测试用例/Bug 三个 Tab 顶部统计,以及概览页的"总人天投入",都用**单条任务独立累加**计算耗时。问题:
|
||||
|
||||
- 任务 A:09:00–11:00(2h)
|
||||
- 任务 B:10:00–12:00(2h)
|
||||
|
||||
实际只占用了 09:00–12:00 共 3h 工作时段,但当前累加算成 4h。
|
||||
|
||||
任务越多重叠越严重,"总耗时"会显著虚高,无法回答"这个版本实际走了几天"。
|
||||
|
||||
**目标**:顶部统计同时展示两个口径——
|
||||
|
||||
- **日历耗时**:合并区间后的真实工作时段占用(看版本实际走了多久)
|
||||
- **人力投入**:单条独立累加(看总人力成本,原口径)
|
||||
|
||||
## 决策摘要
|
||||
|
||||
| 项 | 决策 |
|
||||
|---|---|
|
||||
| 算法位置 | `apps/web/lib/work-hours.ts` 新增 `mergeWorkHours` + `calcTwoMetrics` |
|
||||
| 区间提取 | 各模块(dev-task / test-case / bug)暴露 `xxxIntervals(items)` 函数 |
|
||||
| 顶部展示 | 三段式:"预 X / 日历 Y / 人力 Z"(开发任务);"日历 Y / 人力 Z"(测试用例 / Bug) |
|
||||
| 概览 总人天 | 两行展示:日历总耗时 / 人力总投入(含调研/产品/UI/开发/测试/Bug 全程) |
|
||||
| 个人耗时排名 | 不动(按人汇总天然是人力维度) |
|
||||
| PlanTab 顶部 | 不动(不在本次范围) |
|
||||
| 老聚合函数 | 保留(向后兼容,仍然是 manhours) |
|
||||
| Bug 区间 end 优先级 | `closedAt > resolvedAt > 终态 updatedAt > now` |
|
||||
|
||||
## 1. 合并区间算法
|
||||
|
||||
`apps/web/lib/work-hours.ts` 新增:
|
||||
|
||||
```ts
|
||||
export interface TimeInterval {
|
||||
start: string;
|
||||
end: string;
|
||||
}
|
||||
|
||||
// 合并所有重叠区间后,对每段独立调 calcWorkHours 求和
|
||||
export function mergeWorkHours(intervals: TimeInterval[]): number;
|
||||
|
||||
// 双口径汇总
|
||||
export function calcTwoMetrics(intervals: TimeInterval[]): {
|
||||
calendarHours: number;
|
||||
manhours: number;
|
||||
};
|
||||
```
|
||||
|
||||
算法:
|
||||
|
||||
1. 过滤掉非法(`!start || !end`)或 `end <= start` 的区间
|
||||
2. 按 `start` 升序排序
|
||||
3. 扫描合并:当前与 prev 重叠(`cur.start <= prev.end`)时合并 `prev.end = max(prev.end, cur.end)`,否则把 prev push 出去
|
||||
4. 对最终的 N 个不重叠区间,逐个调 `calcWorkHours(start, end)` 求和 → `calendarHours`
|
||||
5. `manhours` = 原始 intervals 各自 `calcWorkHours` 之后求和(不合并)
|
||||
|
||||
精度 0.5h,与现有口径一致。未结束任务以 `now` 作为 end 参与合并。
|
||||
|
||||
**验证用例**:
|
||||
- A(9–11) + B(10–12) → 日历 3h,人力 4h
|
||||
- A(9–11) + B(13–15) + C(10–14) → 合并后 9–15 减去午休 12–13 = 5h;人力 6h
|
||||
- 跨周末合并:周五 17–周一 10 + 周二 9–11 → 工作时段过滤后两段独立算
|
||||
|
||||
## 2. 三个模块的 intervals 提取
|
||||
|
||||
**`apps/web/lib/dev-task.ts`** 新增:
|
||||
|
||||
```ts
|
||||
export function devTaskIntervals(tasks: DevTask[], now?: Date): TimeInterval[];
|
||||
// 取 [actualStartAt, actualEndAt ?? now],过滤无 actualStartAt 的
|
||||
```
|
||||
|
||||
**`apps/web/lib/test-case.ts`** 新增:
|
||||
|
||||
```ts
|
||||
export function testCaseIntervals(cases: TestCase[], now?: Date): TimeInterval[];
|
||||
// 取 [startedAt, completedAt ?? now],过滤无 startedAt 的
|
||||
```
|
||||
|
||||
**`apps/web/lib/bug.ts`** 新增:
|
||||
|
||||
```ts
|
||||
export function bugIntervals(bugs: Bug[], now?: Date): TimeInterval[];
|
||||
// 取 [createdAt, closedAt ?? resolvedAt ?? (status 终态时 updatedAt) ?? now]
|
||||
```
|
||||
|
||||
**`apps/web/lib/version-plan.ts`** 新增(仅供概览总人天用):
|
||||
|
||||
```ts
|
||||
export function planIntervals(plans: VersionPlan[], now?: Date): TimeInterval[];
|
||||
// 取 [actualStartAt, completedAt ?? now],过滤无 actualStartAt 的
|
||||
```
|
||||
|
||||
老聚合函数(`aggregateDevTaskHours / aggregateTestCaseActualHours / aggregateBugActualHours`)保留,仍然是 manhours 累加,向后兼容(项目顶部卡片、与我相关页继续用)。
|
||||
|
||||
## 3. 4 个统计点 UI 调整
|
||||
|
||||
**(1) `DevTaskTab` 顶部**:
|
||||
|
||||
```
|
||||
12任务 · 预 96h(12天) · 日历 64h(8天) / 人力 84h(10.5天)
|
||||
```
|
||||
|
||||
- 染色:人力 > 预计 红、< 预计 绿、相等灰
|
||||
- 日历不染色(中性事实)
|
||||
|
||||
**(2) `TestCaseTab` 顶部**:
|
||||
|
||||
```
|
||||
40例 · 通过28 · 失败5 · 通过率85% · 日历 32h(4天) / 人力 56h(7天)
|
||||
```
|
||||
|
||||
**(3) `BugTab` 顶部**:
|
||||
|
||||
```
|
||||
Bug 12 个 · 待修复2 · 修复中3 · ... · 解决率75% · 日历 18h / 人力 24h
|
||||
```
|
||||
|
||||
**(4) 概览-总人天投入**(line 778):当前一行 `总人天投入 96h(12人天)` 改为两行:
|
||||
|
||||
```
|
||||
日历总耗时 104h(13天)
|
||||
人力总投入 176h(22人天)
|
||||
```
|
||||
|
||||
数据源:plans + devTasks + testCases + bugs 的 intervals 全部合并后调 `calcTwoMetrics`。
|
||||
|
||||
## 4. 不动的部分
|
||||
|
||||
- 个人耗时排名(按人累加,本身就是人力维度)
|
||||
- 阶段耗时(项目维度)卡片(已经是日历口径,用 `calcCalendar` 算最早开始/最晚结束/天数差)
|
||||
- PlanTab(调研/产品方案/UI 设计)顶部统计
|
||||
- 项目详情顶部 `HoursStatCard`
|
||||
- 与我相关页 DevTask 工时显示
|
||||
|
||||
## 数据流
|
||||
|
||||
```
|
||||
DevTask + TestCase + Bug + Plan
|
||||
│
|
||||
├── devTaskIntervals(tasks)
|
||||
├── testCaseIntervals(cases)
|
||||
├── bugIntervals(bugs)
|
||||
└── planIntervals(plans)
|
||||
│
|
||||
└── work-hours.calcTwoMetrics(intervals)
|
||||
│
|
||||
├── DevTaskTab 顶部
|
||||
├── TestCaseTab 顶部
|
||||
├── BugTab 顶部
|
||||
└── 概览总人天卡片(4 个 intervals 合并)
|
||||
```
|
||||
|
||||
## 实施清单
|
||||
|
||||
新增/修改:
|
||||
|
||||
1. `apps/web/lib/work-hours.ts` — `TimeInterval` + `mergeWorkHours` + `calcTwoMetrics`
|
||||
2. `apps/web/lib/dev-task.ts` — `devTaskIntervals`
|
||||
3. `apps/web/lib/test-case.ts` — `testCaseIntervals`
|
||||
4. `apps/web/lib/bug.ts` — `bugIntervals`
|
||||
5. `apps/web/lib/version-plan.ts` — `planIntervals`
|
||||
6. `apps/web/components/dev-task/DevTaskTab.tsx` — 三段式
|
||||
7. `apps/web/components/test-case/TestCaseTab.tsx` — 加日历/人力两段
|
||||
8. `apps/web/components/bug/BugTab.tsx` — 加日历/人力两段
|
||||
9. `apps/web/app/versions/[id]/page.tsx` — 概览"总人天"改两行
|
||||
|
||||
## 验证
|
||||
|
||||
1. 单条任务 09:00–11:00:日历=2h,人力=2h
|
||||
2. 两条 A(9–11) + B(10–12):日历=3h,人力=4h
|
||||
3. 三条 A(9–11) + B(13–15) + C(10–14):日历=5h(去午休),人力=6h
|
||||
4. 跨周末合并:周五 17–周一 10 与周二 9–11,分两段算工作时段后再相加
|
||||
5. `pnpm type-check` + `pnpm build` 0 错误
|
||||
6. 浏览器进版本详情:开发/测试/Bug 三个 Tab 顶部三段式正确,概览总人天两行正确
|
||||
Reference in New Issue
Block a user