Files
ftb-project-management/apps/web/lib/work-activity-factory.ts
Script Generator 04520bd8c5 feat(版本): 记录计划需求进展活动
关键改动:

- 记录产品/UI 计划需求覆盖进展,并写入工作活动与实体日志

- 日报和小宝预警补充需求进展活动证据

- 调整版本列表与需求覆盖面板展示,并补充测试

Co-Authored-By: Codex GPT-5 <codex@openai.com>
2026-06-30 15:35:36 +08:00

298 lines
7.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { Bug, BugStatus } from './bug';
import type { DevTask, DevTaskStatus } from './dev-task';
import type { TestCase, TestCaseStatus } from './test-case';
import { REQUIREMENT_COVERAGE_LABEL, type VersionPlan, type VersionPlanLog } from './version-plan';
import type { WorkActivityDraft } from './work-activity';
const PLAN_TYPE_LABEL: Record<VersionPlan['type'], string> = {
research: '调研',
product: '产品方案',
ui: 'UI设计',
};
export function makeVersionPlanCreatedActivity(plan: VersionPlan, actorId: string): WorkActivityDraft {
return {
actorId,
sourceType: 'version_plan',
sourceId: plan.id,
action: 'version_plan_created',
category: 'creation',
title: plan.title,
summary: `新建${PLAN_TYPE_LABEL[plan.type]}${plan.title}`,
};
}
export function makeVersionPlanStartedActivity(plan: VersionPlan, actorId: string): WorkActivityDraft {
return {
actorId,
sourceType: 'version_plan',
sourceId: plan.id,
action: 'version_plan_started',
category: 'progress',
title: plan.title,
summary: `开始${PLAN_TYPE_LABEL[plan.type]}${plan.title}`,
};
}
export function makeVersionPlanCompletedActivity(plan: VersionPlan, actorId: string): WorkActivityDraft {
return {
actorId,
sourceType: 'version_plan',
sourceId: plan.id,
action: 'version_plan_completed',
category: 'delivery',
title: plan.title,
summary: `完成${PLAN_TYPE_LABEL[plan.type]}${plan.title}`,
};
}
export function makeVersionPlanRequirementProgressActivity(plan: VersionPlan, log: VersionPlanLog): WorkActivityDraft | undefined {
if (log.type !== 'requirement_progress') return undefined;
if (plan.type !== 'product' && plan.type !== 'ui') return undefined;
const requirementLabel = [log.requirementCode, log.requirementTitle].filter(Boolean).join(' ') || '需求';
const statusLabel = log.coverageStatus ? REQUIREMENT_COVERAGE_LABEL[log.coverageStatus] : '进度更新';
return {
actorId: log.actor,
sourceType: 'version_plan',
sourceId: plan.id,
action: 'version_plan_requirement_progress',
category: 'progress',
title: plan.title,
summary: `推进${PLAN_TYPE_LABEL[plan.type]}需求:${requirementLabel}${statusLabel}`,
occurredAt: log.createdAt,
metadata: {
requirementId: log.requirementId,
requirementCode: log.requirementCode,
requirementTitle: log.requirementTitle,
coverageStatus: log.coverageStatus,
completedContent: log.completedContent,
remainingContent: log.remainingContent,
},
};
}
export function makeDevTaskCreatedActivity(task: DevTask, actorId: string): WorkActivityDraft {
return {
actorId,
sourceType: 'dev_task',
sourceId: task.id,
action: 'dev_task_created',
category: 'creation',
title: task.title,
summary: `新建开发任务:${task.title}`,
};
}
export function makeDevTaskStatusActivity(
task: DevTask,
fromStatus: DevTaskStatus,
toStatus: DevTaskStatus,
actorId: string,
): WorkActivityDraft | undefined {
const base = {
actorId,
sourceType: 'dev_task' as const,
sourceId: task.id,
title: task.title,
metadata: { fromStatus, toStatus },
};
if (toStatus === 'in_progress') {
return {
...base,
action: 'dev_task_started',
category: 'progress',
summary: `开始开发:${task.title}`,
};
}
if (toStatus === 'testing') {
return {
...base,
action: 'dev_task_self_testing',
category: 'progress',
summary: `进入自测:${task.title}`,
};
}
if (toStatus === 'submitted') {
return {
...base,
action: 'dev_task_submitted',
category: 'delivery',
summary: `已提测开发任务:${task.title}`,
};
}
return undefined;
}
export function makeDevTaskBlockedActivity(
task: DevTask,
actorId: string,
reason?: string,
helperId?: string,
): WorkActivityDraft {
return {
actorId,
sourceType: 'dev_task',
sourceId: task.id,
action: 'dev_task_blocked',
category: 'risk',
title: task.title,
summary: `标记阻塞:${reason?.trim() || task.title}`,
metadata: {
blocker: reason?.trim() || undefined,
helperId: helperId?.trim() || undefined,
},
};
}
export function makeDevTaskUnblockedActivity(task: DevTask, actorId: string): WorkActivityDraft {
return {
actorId,
sourceType: 'dev_task',
sourceId: task.id,
action: 'dev_task_unblocked',
category: 'progress',
title: task.title,
summary: `解除阻塞:${task.title}`,
};
}
export function makeBugCreatedActivity(bug: Bug, actorId: string): WorkActivityDraft {
return {
actorId,
sourceType: 'bug',
sourceId: bug.id,
action: 'bug_created',
category: 'creation',
title: bug.title,
summary: `新建 Bug${bug.title}`,
};
}
export function makeTestCaseCreatedActivity(testCase: TestCase, actorId: string): WorkActivityDraft {
return {
actorId,
sourceType: 'test_case',
sourceId: testCase.id,
action: 'test_case_created',
category: 'creation',
title: testCase.title,
summary: `新建测试用例:${testCase.title}`,
};
}
export function makeTestCaseStatusActivity(
testCase: TestCase,
fromStatus: TestCaseStatus,
toStatus: TestCaseStatus,
actorId: string,
): WorkActivityDraft | undefined {
const base = {
actorId,
sourceType: 'test_case' as const,
sourceId: testCase.id,
title: testCase.title,
metadata: { fromStatus, toStatus },
};
if (toStatus === 'running') {
return {
...base,
action: 'test_case_started',
category: 'progress',
summary: `开始测试:${testCase.title}`,
};
}
if (toStatus === 'passed') {
return {
...base,
action: 'test_case_passed',
category: 'delivery',
summary: `测试通过:${testCase.title}`,
};
}
if (toStatus === 'failed') {
return {
...base,
action: 'test_case_failed',
category: 'risk',
summary: `测试不通过:${testCase.title}`,
};
}
if (toStatus === 'blocked') {
return {
...base,
action: 'test_case_blocked',
category: 'risk',
summary: `测试阻塞:${testCase.title}`,
};
}
return undefined;
}
export function makeBugStatusActivity(
bug: Bug,
fromStatus: BugStatus,
toStatus: BugStatus,
actorId: string,
): WorkActivityDraft | undefined {
const base = {
actorId,
sourceType: 'bug' as const,
sourceId: bug.id,
title: bug.title,
metadata: { fromStatus, toStatus },
};
if (toStatus === 'fixing') {
return {
...base,
action: 'bug_fixing',
category: 'progress',
summary: `开始修复 Bug${bug.title}`,
};
}
if (toStatus === 'fixed') {
return {
...base,
action: 'bug_fixed',
category: 'delivery',
summary: `已修复 Bug${bug.title}`,
};
}
if (toStatus === 'closed') {
return {
...base,
action: 'bug_closed',
category: 'delivery',
summary: `已关闭 Bug${bug.title}`,
};
}
return undefined;
}
export function makeBugTransferredActivity(bug: Bug, actorId: string, toAssigneeId: string): WorkActivityDraft {
return {
actorId,
sourceType: 'bug',
sourceId: bug.id,
action: 'bug_transferred',
category: 'progress',
title: bug.title,
summary: `转交 Bug${bug.title}${toAssigneeId}`,
metadata: { toAssigneeId },
};
}