For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [x]) syntax for tracking.
Goal: 在运输计划列表「待安排」之后增加「已安排」Tab,筛选跟进状态为 arranged 的计划。
Architecture: 沿用「待安排 / 草稿中」跟进状态 Tab 模式:扩展 PL_PLAN_LIST_TABS 与 plPlanListTabToFilters,列表页切换 Tab 时同步 searchForm.followStatus。后端已支持 followStatus=arranged,无需改接口。
Tech Stack: Vue 3 + TypeScript;node:test + pnpm exec tsx --test
Spec: docs/superpowers/specs/2026-09-04-pl-plan-arranged-tab-design.md
注意: 工作区可能有无关未提交改动。只改本计划列出的文件,提交时勿夹带无关 diff。
| 操作 | 文件 | 职责 |
|---|---|---|
| Create | web-admin/src/utils/pl-plan-list-tabs.test.ts |
Tab 顺序 / filter / 跟进状态 Tab 判定单测 |
| Modify | web-admin/src/utils/pl-display.ts |
PlPlanListTab、PL_PLAN_LIST_TABS、isPlPlanFollowStatusListTab、plPlanListTabToFilters |
| Modify | web-admin/src/views/pl/plan/index.vue |
handlePlanTypeTabChange 切到 arranged 时同步筛选 |
Files:
web-admin/src/utils/pl-plan-list-tabs.test.tsModify: web-admin/src/utils/pl-display.ts
[x] Step 1: 写失败单测
创建 web-admin/src/utils/pl-plan-list-tabs.test.ts:
import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import {
PL_PLAN_LIST_TABS,
isPlPlanFollowStatusListTab,
plPlanListTabToFilters
} from './pl-display'
describe('PL_PLAN_LIST_TABS', () => {
it('places arranged immediately after pending_arrange', () => {
const names = PL_PLAN_LIST_TABS.map((t) => t.name)
assert.deepEqual(names.slice(0, 3), ['pending_arrange', 'arranged', 'drafting'])
assert.equal(
PL_PLAN_LIST_TABS.find((t) => t.name === 'arranged')?.label,
'已安排'
)
})
})
describe('isPlPlanFollowStatusListTab', () => {
it('recognizes pending_arrange, arranged, drafting', () => {
assert.equal(isPlPlanFollowStatusListTab('pending_arrange'), true)
assert.equal(isPlPlanFollowStatusListTab('arranged'), true)
assert.equal(isPlPlanFollowStatusListTab('drafting'), true)
assert.equal(isPlPlanFollowStatusListTab('all'), false)
assert.equal(isPlPlanFollowStatusListTab('inbound'), false)
})
})
describe('plPlanListTabToFilters', () => {
it('maps arranged to followStatus arranged with empty planType', () => {
assert.deepEqual(plPlanListTabToFilters('arranged'), {
planType: '',
followStatus: 'arranged'
})
})
it('keeps pending_arrange and drafting behavior', () => {
assert.deepEqual(plPlanListTabToFilters('pending_arrange'), {
planType: '',
followStatus: 'pending_arrange'
})
assert.deepEqual(plPlanListTabToFilters('drafting'), {
planType: '',
followStatus: 'drafting'
})
})
it('maps type tabs without followStatus', () => {
assert.deepEqual(plPlanListTabToFilters('all'), { planType: '' })
assert.deepEqual(plPlanListTabToFilters('inbound'), { planType: 'inbound' })
})
})
cd web-admin && pnpm exec tsx --test src/utils/pl-plan-list-tabs.test.ts
Expected: FAIL(arranged 尚未进入 PL_PLAN_LIST_TABS / filter)
在 web-admin/src/utils/pl-display.ts 中:
/** 运输计划列表 Tab(单据类型前增加「待安排」「已安排」「草稿中」) */
export type PlPlanListTab = PlPlanTypeTab | 'pending_arrange' | 'arranged' | 'drafting'
export const PL_PLAN_LIST_TABS: { label: string; name: PlPlanListTab }[] = [
{ label: '待安排', name: 'pending_arrange' },
{ label: '已安排', name: 'arranged' },
{ label: '草稿中', name: 'drafting' },
...PL_PLAN_TYPE_TABS
]
export function isPlPlanFollowStatusListTab(
tab: PlPlanListTab | string
): tab is 'pending_arrange' | 'arranged' | 'drafting' {
return tab === 'pending_arrange' || tab === 'arranged' || tab === 'drafting'
}
plPlanListTabToFilters 中增加 arranged 分支(放在 pending_arrange 之后、drafting 之前):export function plPlanListTabToFilters(tab: PlPlanListTab): {
planType: string
followStatus?: string
} {
if (tab === 'pending_arrange') {
return { planType: '', followStatus: 'pending_arrange' }
}
if (tab === 'arranged') {
return { planType: '', followStatus: 'arranged' }
}
if (tab === 'drafting') {
return { planType: '', followStatus: 'drafting' }
}
return { planType: plPlanTypeTabToFilter(tab) }
}
cd web-admin && pnpm exec tsx --test src/utils/pl-plan-list-tabs.test.ts
Expected: PASS(全部用例通过)
git add web-admin/src/utils/pl-display.ts web-admin/src/utils/pl-plan-list-tabs.test.ts
git commit -m "$(cat <<'EOF'
feat(web-admin): add arranged tab to transport plan list filters
Insert「已安排」after「待安排」in PL_PLAN_LIST_TABS and map it to followStatus=arranged.
EOF
)"
Files:
Modify: web-admin/src/views/pl/plan/index.vue
[x] Step 1: 更新 handlePlanTypeTabChange
在 handlePlanTypeTabChange 中,于 pending_arrange 分支后增加 arranged 分支(isPlPlanFollowStatusListTab 已含 arranged,从跟进状态 Tab 切回类型 Tab 时会自动恢复默认筛选,无需额外改动):
function handlePlanTypeTabChange(tab: PlPlanListTab | string) {
const nextTab = tab as PlPlanListTab
const prevTab = activePlanTypeTab.value
activePlanTypeTab.value = nextTab
const filters = plPlanListTabToFilters(nextTab)
searchForm.planType = filters.planType
if (nextTab === 'pending_arrange') {
searchForm.followStatus = ['pending_arrange']
} else if (nextTab === 'arranged') {
searchForm.followStatus = ['arranged']
} else if (nextTab === 'drafting') {
searchForm.followStatus = ['drafting']
} else if (isPlPlanFollowStatusListTab(prevTab) && !isPlPlanFollowStatusListTab(nextTab)) {
searchForm.followStatus = [...PL_PLAN_DEFAULT_FOLLOW_STATUSES]
}
pagination.page = 1
fetchData()
}
说明:
fetchData / 导出已通过 plPlanListTabToFilters(activePlanTypeTab.value) 取 followStatus,无需再改handleReset 仍默认「待安排」,保持不变工具栏与行操作不改
[x] Step 2: 手动验收清单(开发机)
打开 http://localhost:3006/#/pl/plan-module/plan:
git add web-admin/src/views/pl/plan/index.vue
git commit -m "$(cat <<'EOF'
feat(web-admin): sync followStatus when switching to arranged plan tab
Mirror pending_arrange behavior so the arranged tab forces followStatus filter to arranged.
EOF
)"
./scripts/update-graph.sh frontend
或:
cd web-admin && graphify update .
| Spec 要求 | Task |
|---|---|
| Tab 顺序:待安排 → 已安排 → 草稿中 → … | Task 1 |
筛选 followStatus=arranged |
Task 1 + Task 2 |
| 切回类型 Tab 恢复默认跟进状态 | Task 1(isPlPlanFollowStatusListTab)+ Task 2 |
| 列表/工具栏不改 | Task 2(刻意不改) |
| 默认落地仍为待安排 | Task 2(handleReset 不动) |
| 后端不改 | 无对应 Task |
无 TBD / 占位;类型名 arranged 前后一致。