From 4d0f9aa77612ae53b04e7353ae2a55484d6495d1 Mon Sep 17 00:00:00 2001 From: matevip Date: Mon, 29 Jun 2026 11:07:36 +0800 Subject: [PATCH] fix(agents): show a running plan's queued steps in the To Do column --- .../src/components/agents/PlanBoard.vue | 78 ++++++++++++++----- mateclaw-ui/src/i18n/locales/en-US.ts | 1 + mateclaw-ui/src/i18n/locales/zh-CN.ts | 1 + 3 files changed, 62 insertions(+), 18 deletions(-) diff --git a/mateclaw-ui/src/components/agents/PlanBoard.vue b/mateclaw-ui/src/components/agents/PlanBoard.vue index 3a64e4ec..f14be5ba 100644 --- a/mateclaw-ui/src/components/agents/PlanBoard.vue +++ b/mateclaw-ui/src/components/agents/PlanBoard.vue @@ -73,28 +73,29 @@ v-for="group in visibleGroups(lane, col.key)" :key="group.key" class="pb-card" + :class="{ 'is-spill': isSpill(group.latest, col.key) }" + :title="isSpill(group.latest, col.key) ? t('plans.queuedSpillHint') : undefined" @click="openDetail(group.latest)" >
{{ group.goal }}
-
+
{{ group.latest.completedSteps }}/{{ group.latest.totalSteps }} ×{{ group.plans.length }}
- -
- - {{ stepDist(group.latest).running }} {{ t('plans.col.running') }} - - - {{ stepDist(group.latest).pending }} {{ t('plans.col.pending') }} - - - {{ stepDist(group.latest).completed }} {{ t('plans.col.completed') }} - + +
+ {{ chip.n }} {{ chip.label }}
@@ -243,7 +244,7 @@ function cleanGoal(goal?: string): string { function groupsIn(lane: Lane, status: PlanStatus): PlanGroup[] { const map = new Map() for (const p of lane.plans) { - if (p.status !== status) continue + if (!belongsToColumn(p, status)) continue const key = cleanGoal(p.goal) || String(p.id) const arr = map.get(key) if (arr) arr.push(p) @@ -294,10 +295,44 @@ function stepDist(plan: Plan): { pending: number; running: number; completed: nu return { pending, running, completed } } -// Only worth showing for multi-step plans that are still active; a finished or -// single-step plan is already fully described by the progress bar. -function showDist(plan: Plan): boolean { - return (plan.totalSteps ?? 0) > 1 && (plan.status === 'running' || plan.status === 'pending') +// A multi-step plan spans columns: its one running step belongs in 执行中 while +// its queued steps belong in 待执行. So a running plan that still has queued +// steps also surfaces in the pending column — otherwise that column sits empty +// next to a card whose badge claims "N pending", which reads as a bug. +function belongsToColumn(plan: Plan, status: PlanStatus): boolean { + if (status === 'pending') { + return plan.status === 'pending' || (plan.status === 'running' && stepDist(plan).pending > 0) + } + return plan.status === status +} + +// True when this card is the queued-steps mirror of an in-progress plan shown in +// the pending column (vs. the plan's primary card in 执行中). +function isSpill(plan: Plan, colKey: PlanStatus): boolean { + return colKey === 'pending' && plan.status === 'running' +} + +// The progress bar follows the plan's real status, except the queued mirror in +// the pending column uses the muted pending tone so it doesn't look "running" +// while sitting in 待执行. +function barStatus(plan: Plan, colKey: PlanStatus): PlanStatus { + return isSpill(plan, colKey) ? 'pending' : (plan.status as PlanStatus) +} + +// Distribution chips scoped to the column the card is rendered in: the pending +// column shows only the queued count, the running column shows the active step +// (and any completed steps). Only multi-step, still-active plans get chips. +function columnChips(plan: Plan, colKey: PlanStatus): { cls: string; n: number; label: string }[] { + if ((plan.totalSteps ?? 0) <= 1) return [] + if (plan.status !== 'running' && plan.status !== 'pending') return [] + const d = stepDist(plan) + if (colKey === 'pending') { + return d.pending ? [{ cls: 'is-pending', n: d.pending, label: t('plans.col.pending') }] : [] + } + const chips: { cls: string; n: number; label: string }[] = [] + if (d.running) chips.push({ cls: 'is-running', n: d.running, label: t('plans.col.running') }) + if (d.completed) chips.push({ cls: 'is-completed', n: d.completed, label: t('plans.col.completed') }) + return chips } function laneLetter(name: string): string { @@ -554,6 +589,13 @@ onMounted(reload) border-color: var(--mc-border-strong); box-shadow: var(--mc-shadow-soft); } +/* Queued-steps mirror of an in-progress plan (shown in the pending column): + dashed + sunken so it reads as a secondary view of a card that also lives in + 执行中, not a duplicate. */ +.pb-card.is-spill { + border-style: dashed; + background: var(--mc-bg-sunken); +} .pb-card__goal { font-size: 12.5px; line-height: 1.45; diff --git a/mateclaw-ui/src/i18n/locales/en-US.ts b/mateclaw-ui/src/i18n/locales/en-US.ts index 8d8e578e..dfd74580 100644 --- a/mateclaw-ui/src/i18n/locales/en-US.ts +++ b/mateclaw-ui/src/i18n/locales/en-US.ts @@ -459,6 +459,7 @@ export default { steps: 'steps', viewResult: 'Click to view result', delegatedTo: 'Delegated to', + queuedSpillHint: 'Queued steps of an in-progress plan — the same plan also shows in In Progress', col: { pending: 'To Do', running: 'In Progress', diff --git a/mateclaw-ui/src/i18n/locales/zh-CN.ts b/mateclaw-ui/src/i18n/locales/zh-CN.ts index a37da88b..3dc8fba1 100644 --- a/mateclaw-ui/src/i18n/locales/zh-CN.ts +++ b/mateclaw-ui/src/i18n/locales/zh-CN.ts @@ -459,6 +459,7 @@ export default { steps: '步骤', viewResult: '点击查看结果', delegatedTo: '委派给', + queuedSpillHint: '进行中计划的待执行步骤——同一计划也显示在「执行中」列', col: { pending: '待执行', running: '执行中',