fix: 计划任务勾选逻辑 + 胶囊进度计算修正

1. 必须点击"开始"后才能勾选任务:
   - 调研/产品方案/UI设计的 checkbox 加 disabled 判断
   - plan.status !== 'in_progress' 时不可交互

2. 调研勾选改为二态(与产品/UI一致):
   - 去掉三态循环(pending→in_progress→completed)
   - 改为 toggle:未完成 ↔ 已完成
   - 显示文字也简化为"已完成"/"未完成"

3. 胶囊进度百分比计算修正:
   - 旧逻辑:所有子任务合并计算(新建空任务导致分母为0返回0%)
   - 新逻辑:以 plan 为单位加权计算
     - completed 的 plan = 权重 1
     - in_progress 的 plan = 子任务完成率
     - pending 的 plan = 权重 0
   - 公式:sum(weights) / plan_count * 100
   - 新建一个 pending 的 plan 不会把已完成的 100% 打回 0%

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Script Generator
2026-06-15 15:31:21 +08:00
parent 0a83ab8816
commit 5bbcf02962
2 changed files with 29 additions and 22 deletions

View File

@@ -106,19 +106,20 @@ export function PlanTab({ plans, versionId, versionDeadline, currentUserName, pl
{plan.tasks.map((task) => (
<div key={task.id} className="flex items-center gap-2">
<button
disabled={plan.status !== 'in_progress'}
onClick={() => {
const nextStatus = task.status === 'pending' ? 'in_progress' : task.status === 'in_progress' ? 'completed' : 'pending';
if (plan.status !== 'in_progress') return;
const nextStatus = task.status === 'completed' ? 'pending' : 'completed';
const updatedTasks = plan.tasks!.map((t) => t.id === task.id ? { ...t, status: nextStatus as PlanTask['status'] } : t);
onUpdate(plan.id, { tasks: updatedTasks });
}}
className={`h-4 w-4 rounded border flex items-center justify-center shrink-0 transition-colors ${task.status === 'completed' ? 'bg-[var(--accent)] border-[var(--accent)]' : task.status === 'in_progress' ? 'border-blue-400 bg-blue-50' : 'border-[var(--line)]'}`}
className={`h-4 w-4 rounded border flex items-center justify-center shrink-0 transition-colors ${plan.status !== 'in_progress' ? 'opacity-40 cursor-not-allowed' : ''} ${task.status === 'completed' ? 'bg-[var(--accent)] border-[var(--accent)]' : 'border-[var(--line)]'}`}
>
{task.status === 'completed' && <Check className="h-2.5 w-2.5 text-white" strokeWidth={3} />}
{task.status === 'in_progress' && <div className="h-1.5 w-1.5 rounded-full bg-blue-500" />}
</button>
<span className={`text-[12px] ${task.status === 'completed' ? 'line-through text-[var(--ink-muted)]' : 'text-[var(--ink)]'}`}>{task.title}</span>
<span className={`text-[10px] ${task.status === 'completed' ? 'text-green-600' : task.status === 'in_progress' ? 'text-blue-600' : 'text-[var(--ink-muted)]'}`}>
{task.status === 'completed' ? '已完成' : task.status === 'in_progress' ? '进行中' : '未开始'}
<span className={`text-[10px] ${task.status === 'completed' ? 'text-green-600' : 'text-[var(--ink-muted)]'}`}>
{task.status === 'completed' ? '已完成' : '未完成'}
</span>
</div>
))}
@@ -141,12 +142,14 @@ export function PlanTab({ plans, versionId, versionDeadline, currentUserName, pl
return req ? (
<div key={rid} className="flex items-center gap-2">
<button
disabled={plan.status !== 'in_progress'}
onClick={() => {
if (plan.status !== 'in_progress') return;
const current = plan.completedRequirementIds || [];
const next = isDone ? current.filter((id) => id !== rid) : [...current, rid];
onUpdate(plan.id, { completedRequirementIds: next });
}}
className={`h-4 w-4 rounded border flex items-center justify-center shrink-0 transition-colors ${isDone ? 'bg-[var(--accent)] border-[var(--accent)]' : 'border-[var(--line)]'}`}
className={`h-4 w-4 rounded border flex items-center justify-center shrink-0 transition-colors ${plan.status !== 'in_progress' ? 'opacity-40 cursor-not-allowed' : ''} ${isDone ? 'bg-[var(--accent)] border-[var(--accent)]' : 'border-[var(--line)]'}`}
>
{isDone && <Check className="h-2.5 w-2.5 text-white" strokeWidth={3} />}
</button>