From 2d3f56b00c74c558fdd4cb0b8b330c23ced0e4cd Mon Sep 17 00:00:00 2001 From: Script Generator Date: Mon, 15 Jun 2026 15:39:38 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=83=B6=E5=9B=8A=E8=BF=9B=E5=BA=A6?= =?UTF-8?q?=E6=8C=89=E5=AD=90=E4=BB=BB=E5=8A=A1=E5=8A=A0=E6=9D=83=20+=20?= =?UTF-8?q?=E8=B0=83=E7=A0=94=E4=BB=BB=E5=8A=A1=E6=B8=85=E5=8D=95=E5=BF=85?= =?UTF-8?q?=E5=A1=AB+=E9=A2=84=E8=AE=BE=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 胶囊进度计算改为子任务加权: - 分子 = 所有plan中已完成的子任务数 - 分母 = 所有plan的子任务总数 - completed的plan视为其子任务全部完成 - 没有子任务的plan按1项计算(不会导致分母为0) - 例:4个completed(共8子任务) + 1个pending(2子任务) = 8/(8+2) = 80% 2. 调研任务清单必须至少1项: - handleSubmit 加校验:tasks.length === 0 时 return - 红色提示:"请至少添加一项任务" 3. 预设可选任务选项(空列表时显示): - 竞品分析、用户访谈、数据调研 - 技术可行性分析、市场调研、需求分析 - 点击即添加,也可自定义输入 Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/web/app/versions/[id]/page.tsx | 36 ++++++++++++++----------- apps/web/components/version/PlanTab.tsx | 26 ++++++++++++++++-- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/apps/web/app/versions/[id]/page.tsx b/apps/web/app/versions/[id]/page.tsx index b51e332..c8dcbcb 100644 --- a/apps/web/app/versions/[id]/page.tsx +++ b/apps/web/app/versions/[id]/page.tsx @@ -303,27 +303,33 @@ export default function VersionDetailPage() { const calcGroupProgress = (group: typeof vPlans, type: 'research' | 'product' | 'ui') => { if (group.length === 0) return 0; - // 每个 plan 按权重贡献进度:completed=1, in_progress=子任务完成率, pending=0 - let totalWeight = 0; + // 分子=已完成子任务数,分母=所有plan的子任务总数 + // completed 的 plan:其子任务全算已完成 + let totalItems = 0; + let doneItems = 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; - } + if (type === 'research') { + const tasks = p.tasks || []; + const count = Math.max(tasks.length, 1); + totalItems += count; + if (p.status === 'completed') { + doneItems += count; + } else { + doneItems += tasks.filter((t) => t.status === 'completed').length; + } + } else { + const linked = p.linkedRequirementIds || []; + const count = Math.max(linked.length, 1); + totalItems += count; + if (p.status === 'completed') { + doneItems += count; } else { - const linked = p.linkedRequirementIds || []; const completed = p.completedRequirementIds || []; - if (linked.length > 0) { - totalWeight += completed.filter((id) => linked.includes(id)).length / linked.length; - } + doneItems += completed.filter((id) => linked.includes(id)).length; } } } - return Math.round((totalWeight / group.length) * 100); + return totalItems > 0 ? Math.round((doneItems / totalItems) * 100) : 0; }; 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 9a9ad2b..17c3d62 100644 --- a/apps/web/components/version/PlanTab.tsx +++ b/apps/web/components/version/PlanTab.tsx @@ -252,6 +252,7 @@ function PlanFormModal({ initial, planType, versionId, versionDeadline, currentU e.preventDefault(); if (!title.trim() || !endTime) return; if (isOverdue && !overdueReason.trim()) return; + if (planType === 'research' && tasks.length === 0) return; onSubmit({ versionId, type: planType, @@ -326,7 +327,25 @@ function PlanFormModal({ initial, planType, versionId, versionDeadline, currentU )} {planType === 'research' && (
- + + {/* 预设选项 */} + {tasks.length === 0 && ( +
+ {['竞品分析', '用户访谈', '数据调研', '技术可行性分析', '市场调研', '需求分析'].map((preset) => ( + + ))} +
+ )}
{tasks.map((task, i) => (
@@ -340,11 +359,14 @@ function PlanFormModal({ initial, planType, versionId, versionDeadline, currentU value={newTaskTitle} onChange={(e) => setNewTaskTitle(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); if (newTaskTitle.trim()) { setTasks([...tasks, { id: `task-${Date.now()}`, title: newTaskTitle.trim(), status: 'pending' }]); setNewTaskTitle(''); } } }} - placeholder="输入任务名称,回车添加" + placeholder="自定义任务名称,回车添加" className="flex-1 h-8 rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[12px] focus:border-[var(--accent)] focus:outline-none" />
+ {tasks.length === 0 && ( +
请至少添加一项任务
+ )}
)}