From 87374f3976b40f91292d0a6ace0390132547339a Mon Sep 17 00:00:00 2001 From: zlwu Date: Fri, 4 Sep 2026 17:33:11 +0800 Subject: [PATCH] docs: add implementation plan for transport plan arranged tab Break the arranged-tab design into TDD utility steps and list-page filter sync. Co-authored-by: Cursor --- .../plans/2026-09-04-pl-plan-arranged-tab.md | 258 ++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 docs/superpowers/plans/2026-09-04-pl-plan-arranged-tab.md diff --git a/docs/superpowers/plans/2026-09-04-pl-plan-arranged-tab.md b/docs/superpowers/plans/2026-09-04-pl-plan-arranged-tab.md new file mode 100644 index 000000000..f78081a6b --- /dev/null +++ b/docs/superpowers/plans/2026-09-04-pl-plan-arranged-tab.md @@ -0,0 +1,258 @@ +# 运输计划列表「已安排」Tab Implementation Plan + +> **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 (`- [ ]`) 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` 时同步筛选 | + +--- + +### Task 1: Tab 工具函数单测 + 实现 + +**Files:** +- Create: `web-admin/src/utils/pl-plan-list-tabs.test.ts` +- Modify: `web-admin/src/utils/pl-display.ts` + +- [ ] **Step 1: 写失败单测** + +创建 `web-admin/src/utils/pl-plan-list-tabs.test.ts`: + +```typescript +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' }) + }) +}) +``` + +- [ ] **Step 2: 跑测确认失败** + +```bash +cd web-admin && pnpm exec tsx --test src/utils/pl-plan-list-tabs.test.ts +``` + +Expected: FAIL(`arranged` 尚未进入 `PL_PLAN_LIST_TABS` / filter) + +- [ ] **Step 3: 最小实现** + +在 `web-admin/src/utils/pl-display.ts` 中: + +1. 更新类型与注释: + +```typescript +/** 运输计划列表 Tab(单据类型前增加「待安排」「已安排」「草稿中」) */ +export type PlPlanListTab = PlPlanTypeTab | 'pending_arrange' | 'arranged' | 'drafting' +``` + +2. 更新 Tab 列表(「待安排」后插入「已安排」): + +```typescript +export const PL_PLAN_LIST_TABS: { label: string; name: PlPlanListTab }[] = [ + { label: '待安排', name: 'pending_arrange' }, + { label: '已安排', name: 'arranged' }, + { label: '草稿中', name: 'drafting' }, + ...PL_PLAN_TYPE_TABS +] +``` + +3. 更新跟进状态 Tab 判定: + +```typescript +export function isPlPlanFollowStatusListTab( + tab: PlPlanListTab | string +): tab is 'pending_arrange' | 'arranged' | 'drafting' { + return tab === 'pending_arrange' || tab === 'arranged' || tab === 'drafting' +} +``` + +4. 在 `plPlanListTabToFilters` 中增加 `arranged` 分支(放在 `pending_arrange` 之后、`drafting` 之前): + +```typescript +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) } +} +``` + +- [ ] **Step 4: 跑测确认通过** + +```bash +cd web-admin && pnpm exec tsx --test src/utils/pl-plan-list-tabs.test.ts +``` + +Expected: PASS(全部用例通过) + +- [ ] **Step 5: Commit** + +```bash +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 +)" +``` + +--- + +### Task 2: 列表页 Tab 切换同步筛选 + +**Files:** +- Modify: `web-admin/src/views/pl/plan/index.vue` + +- [ ] **Step 1: 更新 `handlePlanTypeTabChange`** + +在 `handlePlanTypeTabChange` 中,于 `pending_arrange` 分支后增加 `arranged` 分支(`isPlPlanFollowStatusListTab` 已含 `arranged`,从跟进状态 Tab 切回类型 Tab 时会自动恢复默认筛选,无需额外改动): + +```typescript +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` 仍默认「待安排」,保持不变 +- 工具栏与行操作不改 + +- [ ] **Step 2: 手动验收清单(开发机)** + +打开 `http://localhost:3006/#/pl/plan-module/plan`: + +1. Tab 顺序为:待安排 → **已安排** → 草稿中 → 全部 → 入库单 → 出库单 → 直销单 +2. 点「已安排」:列表仅跟进状态为「已安排」;筛选区跟进状态仅勾选「已安排」 +3. 点「全部」:跟进状态恢复默认勾选(不含已取消) +4. 点「重置」:回到「待安排」 +5. 工具栏/行操作与其他 Tab 一致(无额外隐藏) + +- [ ] **Step 3: Commit** + +```bash +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 +)" +``` + +- [ ] **Step 4: 更新知识图谱(若本会话改过代码)** + +```bash +./scripts/update-graph.sh frontend +``` + +或: + +```bash +cd web-admin && graphify update . +``` + +--- + +## Spec 覆盖自检 + +| 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` 前后一致。