diff --git a/apps/web/app/versions/[id]/page.tsx b/apps/web/app/versions/[id]/page.tsx index 07dde5e..b51e332 100644 --- a/apps/web/app/versions/[id]/page.tsx +++ b/apps/web/app/versions/[id]/page.tsx @@ -303,23 +303,27 @@ export default function VersionDetailPage() { const calcGroupProgress = (group: typeof vPlans, type: 'research' | 'product' | 'ui') => { if (group.length === 0) return 0; - if (type === 'research') { - const totals = group.reduce((acc, p) => { - const tasks = p.tasks || []; - acc.total += tasks.length; - acc.done += tasks.filter((t) => t.status === 'completed').length; - return acc; - }, { total: 0, done: 0 }); - return totals.total > 0 ? Math.round((totals.done / totals.total) * 100) : 0; + // 每个 plan 按权重贡献进度:completed=1, in_progress=子任务完成率, pending=0 + let totalWeight = 0; + for (const p of group) { + if (p.status === 'completed') { + totalWeight += 1; + } else if (p.status === 'in_progress') { + if (type === 'research') { + const tasks = p.tasks || []; + if (tasks.length > 0) { + totalWeight += tasks.filter((t) => t.status === 'completed').length / tasks.length; + } + } else { + const linked = p.linkedRequirementIds || []; + const completed = p.completedRequirementIds || []; + if (linked.length > 0) { + totalWeight += completed.filter((id) => linked.includes(id)).length / linked.length; + } + } + } } - const totals = group.reduce((acc, p) => { - const linked = p.linkedRequirementIds || []; - const completed = p.completedRequirementIds || []; - acc.total += linked.length; - acc.done += completed.filter((id) => linked.includes(id)).length; - return acc; - }, { total: 0, done: 0 }); - return totals.total > 0 ? Math.round((totals.done / totals.total) * 100) : 0; + return Math.round((totalWeight / group.length) * 100); }; const getPlanStatus = (group: typeof vPlans): 'idle' | 'active' | 'done' => { diff --git a/apps/web/components/version/PlanTab.tsx b/apps/web/components/version/PlanTab.tsx index 2dd4e99..9a9ad2b 100644 --- a/apps/web/components/version/PlanTab.tsx +++ b/apps/web/components/version/PlanTab.tsx @@ -106,19 +106,20 @@ export function PlanTab({ plans, versionId, versionDeadline, currentUserName, pl {plan.tasks.map((task) => (
{task.title} - - {task.status === 'completed' ? '已完成' : task.status === 'in_progress' ? '进行中' : '未开始'} + + {task.status === 'completed' ? '已完成' : '未完成'}
))} @@ -141,12 +142,14 @@ export function PlanTab({ plans, versionId, versionDeadline, currentUserName, pl return req ? (