feat(工作台): 细化计划进展工时证据

关键改动:

- 支持需求覆盖和调研方向开始工作记录

- 日报按计划记录开始时间和进度下次开始时间计算证据

- 更新版本编辑校验、项目展示和 workflow 说明

Co-Authored-By: Codex GPT-5 <codex@openai.com>
This commit is contained in:
Script Generator
2026-07-01 11:02:38 +08:00
parent e5ce2d221e
commit 8947aeaac7
18 changed files with 1125 additions and 94 deletions

View File

@@ -146,6 +146,15 @@ test('updates requirement coverage, syncs legacy completed ids, and creates a pl
const next = updateRequirementCoverage!(plan({
linkedRequirementIds: ['r1'],
completedRequirementIds: ['r1'],
requirementCoverage: [
{
requirementId: 'r1',
status: 'completed',
currentWorkStartedAt: '2026-06-29T09:30:00.000Z',
updatedAt: '2026-06-28T12:00:00.000Z',
updatedBy: 'PM',
},
],
}), {
requirementId: 'r1',
status: 'partial',
@@ -159,26 +168,63 @@ test('updates requirement coverage, syncs legacy completed ids, and creates a pl
assert.deepEqual(next.completedRequirementIds, []);
assert.equal(next.requirementCoverage?.[0]?.status, 'partial');
assert.equal(next.requirementCoverage?.[0]?.currentWorkStartedAt, undefined);
assert.equal(next.logs?.length, 1);
assert.equal(next.logs?.[0]?.type, 'requirement_progress');
assert.equal(next.logs?.[0]?.actor, 'PM');
assert.equal(next.logs?.[0]?.requirementCode, 'QY0001');
assert.equal(next.logs?.[0]?.completedContent, '完成移动端主流程');
assert.equal(next.logs?.[0]?.remainingContent, 'PC 端筛选规则未完成');
assert.equal(next.logs?.[0]?.workStartedAt, '2026-06-29T09:30:00.000Z');
});
test('validates requirement coverage record drafts by status', () => {
test('starts requirement coverage work while preserving existing progress', () => {
const startRequirementCoverageWork = (versionPlan as any).startRequirementCoverageWork as undefined | ((item: VersionPlan, input: {
requirementId: string;
startedAt: string;
updatedBy: string;
}) => any);
assert.equal(typeof startRequirementCoverageWork, 'function');
const next = startRequirementCoverageWork!(plan({
requirementCoverage: [
{
requirementId: 'r1',
status: 'partial',
completedContent: '完成主流程',
remainingContent: '补充异常状态',
updatedAt: '2026-06-28T12:00:00.000Z',
updatedBy: 'PM',
},
],
}), {
requirementId: 'r1',
startedAt: '2026-06-29T09:30:00.000Z',
updatedBy: 'PM',
});
assert.equal(next.requirementCoverage?.[0]?.status, 'partial');
assert.equal(next.requirementCoverage?.[0]?.completedContent, '完成主流程');
assert.equal(next.requirementCoverage?.[0]?.remainingContent, '补充异常状态');
assert.equal(next.requirementCoverage?.[0]?.currentWorkStartedAt, '2026-06-29T09:30:00.000Z');
assert.equal(next.requirementCoverage?.[0]?.updatedBy, 'PM');
});
test('validates requirement coverage record drafts by started work session', () => {
const canSaveRequirementCoverageDraft = (versionPlan as any).canSaveRequirementCoverageDraft as undefined | ((
status: string,
completedContent?: string,
remainingContent?: string,
workStartedAt?: string,
) => boolean);
assert.equal(typeof canSaveRequirementCoverageDraft, 'function');
assert.equal(canSaveRequirementCoverageDraft!('completed'), true);
assert.equal(canSaveRequirementCoverageDraft!('partial', '完成主流程', ''), false);
assert.equal(canSaveRequirementCoverageDraft!('partial', '完成主流程', '补充异常状态'), true);
assert.equal(canSaveRequirementCoverageDraft!('not_started'), false);
assert.equal(canSaveRequirementCoverageDraft!('completed'), false);
assert.equal(canSaveRequirementCoverageDraft!('completed', undefined, undefined, '2026-06-29T09:30:00.000Z'), true);
assert.equal(canSaveRequirementCoverageDraft!('partial', '完成主流程', '', '2026-06-29T09:30:00.000Z'), false);
assert.equal(canSaveRequirementCoverageDraft!('partial', '完成主流程', '补充异常状态'), false);
assert.equal(canSaveRequirementCoverageDraft!('partial', '完成主流程', '补充异常状态', '2026-06-29T09:30:00.000Z'), true);
assert.equal(canSaveRequirementCoverageDraft!('not_started', undefined, undefined, '2026-06-29T09:30:00.000Z'), false);
});
test('hides coverage record action after a requirement is completed', () => {