Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
17 KiB
六项前端体验优化 实现计划
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: 一次性落地 6 个前端小需求:①库存抽屉加供应商 ②库存桌面列批次号/生产日期换位 ③出入库单详情抽屉加「生产日期+批次号」双行列(两端)④出入库列表状态筛选多选+默认草稿/待审核 ⑤新建单默认填充默认仓库 ⑥财务加往来单位筛选+自定义时间换统一组件。
Architecture: 全部为前端(Flutter client/)+ 设计原型(design/prototype/)改动,后端零改动(调研已核实:供应商/批次/生产日期数据链路已通、status 已支持逗号多值、partner_id 过滤已存在、warehouses.is_default 全链路齐备)。按 design-first 铁律:每个任务先改原型、再改真实代码、原型与代码同一提交。
Tech Stack: Flutter/Riverpod + 原型 HTML/JS(tokens/atoms 单源);验收闸 check-ds / check_ds_code / check-l1-sync / fidelity / golden。
Global Constraints
- design-first 铁律(用户 2026-07-14 重申):涉及页面的改动必须先改
design/prototype/原型再开发,原型与代码同一提交;改到的屏必须保持 CONTRACT「同步」态。 - 颜色/间距一律走 token(
context.tokens),禁硬编码 hex;新原子先登记原型index.html。 - 弹窗/抽屉宽度改动属 L1 层(
atoms.css),须原型与 Flutter 常量同提交(过tools/check-l1-sync.mjs)。 - 多租户/权限口径不变:出库成本/利润仅管理员可见的逻辑不受本次改动影响(新增列均为非成本字段)。
- DoD:
flutter analyze --no-fatal-infos --no-fatal-warnings零 error、flutter test全绿、node client/tool/check_ds_code.mjs、node tools/check-l1-sync.mjs过闸、涉及屏 fidelity ≤ 8%;不发版、不打 tag、不部署,完成后停在本地提交态等用户验收。 - 提交规范:每个需求一个提交,
feat(client): ...,原型改动包含在同一提交内。
已定决策(评审时可推翻)
- D1 供应商行两端同显:库存商品抽屉两端共用
product_editor_drawer.dart的_infoBody,加一行两端同时生效、成本为零;桌面端抽屉当前也没有供应商(表格有),一并补齐更一致。行位置:紧跟「生产日期」行之后。 - D2 库存抽屉顺手补「批次号」行(推荐做):与需求③口径一致(出入库抽屉都有生产日期+批次号,库存抽屉只有生产日期不对称);
Inventory.batchNo数据已有,走与供应商相同的入参传递。若你只要最小改动(仅供应商),评审时说一声即去掉。 - D3 状态筛选「重置」回默认:重置按钮把状态恢复为默认
draft,pending(与进入页面初始态一致),不是回「全部」。 - D4 退单伪状态与多选互斥:
ret:partial/ret:full保持与主状态互斥——选退单态清空状态多选,选任一主状态清退单态(沿用现语义,最小改动)。 - D5 移动端 KPI 卡片点击 = 覆盖为单值:点「待审核」卡即只看待审核(覆盖当前多选集合),保持现有心智。
- D6 移动端财务往来单位筛选形态:在时间 chips 行尾追加「往来单位」chip,点开
showMSheet底部可搜索单选列表(与桌面ComboSearchField对应);再点 × 清除。 - D7 出库抽屉加宽 600→660:出库管理员形态 7→8 列太紧,
atoms.css.drawer.wide600→660px 与 Flutterorder_detail_drawer.dart:44常量同提交;入库 5→6 列余量够,只微调列宽不加宽。
执行分组(多 agent 调度)
| 波次 | 组 | 任务 | 关键文件域 | 并行性 |
|---|---|---|---|---|
| 1 | A 库存域 | Task 1 + Task 2 | product_editor_drawer / inventory_list_screen / inventory.html / product-editor.js / m-inventory.html | 与 B、D 并行 |
| 1 | B 出入库抽屉 | Task 3 | order_detail_drawer / 两 list_screen(传参处)/ atoms.css / stock-*-list.html ×4 | 与 A、D 并行 |
| 1 | D 财务域 | Task 6 | finance_screen / finance_provider / finance.html / m-finance.html | 与 A、B 并行 |
| 2 | C 出入库筛选+表单 | Task 4 + Task 5 | 两 provider / 两 list_screen / 两 form_screen / stock-*-list.html ×4 / stock-in.js | 必须等 B 完成(同文件) |
| 3 | 收尾 | Task 7 | CONTRACT.md / fidelity / golden / 手册核查 | 最后 |
Task 1: 库存商品抽屉加「供应商」行(+D2 批次号行)【两端】
Files:
- Modify:
design/prototype/screens/product-editor.js:60-75(infoRows()) - Modify:
design/prototype/screens/m-inventory.html:98(详情 sheet 行序) - Modify:
client/lib/widgets/product_editor_drawer.dart(入参 +_infoBody385-471) - Modify:
client/lib/screens/inventory/inventory_list_screen.dart:123(_openEditor传参)
Interfaces:
-
Produces:
showProductEditorDrawer(..., String? supplier, String? batchNo)两个新可空入参;不传即不显示(条件行机制),其它调用方(products_screen.dart 等)零改动。 -
Step 1(原型先行):
product-editor.jsinfoRows()在「生产日期」行后加「批次号」「供应商」两行(假数据示例B20260701/XX贸易);m-inventory.html详情 sheet 同步行序。本地 5180 预览确认。 -
Step 2(代码):
product_editor_drawer.dart的showProductEditorDrawer加String? supplier, String? batchNo入参并透传;_infoBody在生产日期行后按非空条件渲染「批次号」「供应商」两行(样式照抄现有 info 行)。 -
Step 3(接线):
inventory_list_screen.dart_openEditor传supplier: item.supplierName, batchNo: item.batchNo。 -
Step 4(验证):
cd client && flutter analyze --no-fatal-infos --no-fatal-warnings && flutter test;若库存屏 golden 覆盖抽屉则 regen。 -
Step 5(提交):
feat(client): 库存商品抽屉增加供应商与批次号信息行(两端,原型同步)
Task 2: 库存桌面表格「批次号」「生产日期」列换位【仅桌面】
Files:
- Modify:
design/prototype/screens/inventory.html:128(COLS数组对调) - Modify:
client/lib/screens/inventory/inventory_list_screen.dart:58-73(_colDefs对调)
前提核实(调研已确认):移动端卡片无批次号字段,不涉及;列偏好/排序白名单均按 key 存,换位只动数组顺序不动 key,用户已存配置不受影响。
- Step 1(原型先行):
inventory.htmlCOLS中 batch 与 prodDate 位置对调,5180 预览确认。 - Step 2(代码):
_colDefs同步对调两项顺序(连同对应 cell 构建顺序)。 - Step 3(验证):
flutter analyze && flutter test;库存列表 golden 如有列序断言则 regen。 - Step 4(提交):
feat(client): 库存列表批次号与生产日期列位对调(原型同步)
Task 3: 出入库单详情抽屉明细加「生产日期+批次号」双行列【两端】
Files:
- Modify:
design/prototype/screens/stock-in-list.html:311-312(明细 grid + 假数据 lines 补pdate/batch) - Modify:
design/prototype/screens/stock-out-list.html:306-308(GRID常量 + 假数据) - Modify:
design/prototype/screens/m-stock-in-list.html:145-149、m-stock-out-list.html(openOrderlineRows 插入「生产日期/批次号」双行列) - Modify:
design/prototype/atoms.css:218-220(.drawer.wide600→660,D7) - Modify:
client/lib/widgets/order_detail_drawer.dart(OrderLine:67-92 加字段;_LinesTable:418-618 加列;_mLineRow:331-367 插双行列;:44 宽度 660) - Modify:
client/lib/screens/stock_in/stock_in_list_screen.dart:988-999、client/lib/screens/stock_out/stock_out_list_screen.dart:1064-1080(构造 OrderLine 传两字段) - Modify:
client/lib/models/stock_in.dart:63-64(StockInItem两字段改lineOrProduct兜底,对齐 stock_out 写法) - Test:
client/test/order_detail_drawer_columns_test.dart(列结构断言同步更新)
Interfaces:
-
Produces:
OrderLine(..., String? productionDate, String? batchNo);桌面新列单元格样式 = 上行生产日期(fsSm mono)+ 下行批次号(fsXs faint mono),复用「商品·编码」列先例。 -
Step 1(原型先行): 四个原型文件明细区插入「生产日期/批次号」双行列(桌面:入库 grid 插 ~72px 列并把 124→110、88→78;出库 GRID 插列且抽屉用 wide 660)+ 移动 lineRows 在金额左侧同样插入双行列(上=生产日期 fsSm mono,下=批次号 fsXs faint,与桌面同构;用户 2026-07-14 审阅指定);
atoms.css.drawer.wide600→660。假数据补 pdate/batch。5180 预览两端四屏。 -
Step 2(模型兜底):
stock_in.dartStockInItem.fromJson的 production_date/batch_no 改用lineOrProduct兜底(照stock_out.dart:68-69)。 -
Step 3(抽屉代码):
OrderLine加两字段;_LinesTable入库 5→6 列 / 出库 7→8 列,新列插在「系列·规格」后,列宽按原型定稿值;_mLineRow在金额区左侧插入双行列(上=生产日期 fsSm mono,下=批次号 fsXs faint;两值都空则不渲染该列,避免空占位);:44 桌面宽度min(660, 94%)。 -
Step 4(接线): 两个 list_screen 构造 OrderLine 时传
productionDate: it.productionDate, batchNo: it.batchNo(显示截substring(0,10))。 -
Step 5(测试): 更新
order_detail_drawer_columns_test.dart列数/列头断言;flutter analyze && flutter test;涉及 golden(stock_{in,out}_list*)若开抽屉则 regen。 -
Step 6(L1 闸):
node tools/check-l1-sync.mjs过闸(atoms.css 与 Flutter 常量同源)。 -
Step 7(提交):
feat(client): 出入库单详情抽屉明细增加生产日期+批次号列(两端,抽屉加宽 660,原型同步)
Task 4: 出入库列表状态筛选多选 + 默认「草稿+待审核」【两端】
Files:
- Modify:
design/prototype/screens/stock-in-list.html:67、stock-out-list.html(chipStatus 单选→多选,默认态 draft+pending,摘要「值/N 项」,参照 inventory.html:69,138-139 既有多选形态) - Modify:
design/prototype/screens/m-stock-in-list.html:101-102、m-stock-out-list.html(状态 sheet 单选→多选勾选) - Modify:
client/lib/providers/stock_in_provider.dart:41、stock_out_provider.dart:41(默认_status = 'draft,pending') - Modify:
client/lib/screens/stock_in/stock_in_list_screen.dart(:86-113 归一逻辑重写;:773-790 桌面 chip 改showDsMultiMenu;:678-724 移动 sheet 改多选;:621-630 KPI 点击、_resetFilters) - Modify:
client/lib/screens/stock_out/stock_out_list_screen.dart(:100-128 归一、_MenuChip调用点 ~813、:1973-2020、KPI :548-560/:650-659 同构改法)
Interfaces:
- Consumes: 后端
status IN (逗号分隔)已支持(stock_in.go:44-45 / stock_out.go:55-56),零改动。 - Produces: 屏内状态 =
Set<String>,落 provider 时join(',');空集 = 全部。
关键陷阱(调研确认):两屏 initState 有「归零残留多值」逻辑,会把 'pending,draft' 重置为 ''——必须重写为「按逗号拆分后逐值校验合法性,非法才归默认」,否则默认值刚设就被清掉。
- Step 1(原型先行): 四个原型文件状态筛选改多选(复用 inventory 屏 chip 摘要形态 / m 端 sheet 勾选形态),默认选中 草稿+待审核。5180 预览。
- Step 2(provider): 两个 provider 默认值改
'draft,pending'。 - Step 3(归一重写): 两屏 initState 残留清洗逻辑改为逐值校验(合法集 = draft/pending/approved/rejected),并兼容退单伪状态互斥(D4)。
- Step 4(桌面 chip): 单选 PopupMenu →
_multiChip+showDsMultiMenu(照inventory_list_screen.dart:209-246、widgets/ds/ds_menu.dart:51),摘要:1 项显示值 / 多项「N 项」/ × 清为默认(D3)。 - Step 5(移动 sheet + KPI):
_openStatusSheet改多选勾选(确定时应用);KPI 卡点击 = 覆盖单值(D5);_resetFilters状态回draft,pending(D3)。 - Step 6(验证):
flutter analyze && flutter test;两屏列表 golden regen(默认筛选态变了,golden 基线会变)。 - Step 7(提交):
feat(client): 出入库列表状态筛选改多选并默认草稿+待审核(两端,原型同步)
Task 5: 新建入库/出库单默认填充默认仓库【两端,同一代码路径】
Files:
- Modify:
design/prototype/screens/stock-in.js(state.doc.warehouse新建时默认取默认仓,双模式驱动 in/out 两屏) - Modify:
client/lib/screens/stock_in/stock_in_form_screen.dart(_warehouseId:43,加载仓库后填充) - Modify:
client/lib/screens/stock_out/stock_out_form_screen.dart(:158 同构)
Interfaces:
-
Consumes:
Warehouse.isDefault(client/lib/models/warehouse.dart:5,18,已存在);设置页已可指定默认仓。 -
Step 1(原型先行):
stock-in.js新建单时仓库字段预填默认仓(假数据标记一个默认仓)。5180 预览 in/out 两屏。 -
Step 2(代码): 两张表单新建模式(非编辑回填)在仓库列表加载完成后:
_warehouseId ??= 列表中 isDefault 的仓 ?? (列表仅 1 个仓时取它 : 保持 null)。编辑模式不受影响(仍从单据回填)。 -
Step 3(验证):
flutter analyze && flutter test(两表单已有测试如断言初始空值需同步)。 -
Step 4(提交):
feat(client): 新建出入库单默认填充默认仓库(两端,原型同步)
Task 6: 财务加「往来单位」筛选 + 自定义时间换统一组件【两端】
Files:
- Modify:
design/prototype/screens/finance.html(:82-86 timerow「自定义」接datewheel.js openRange(照 stock-in-list.html:228 写法);流水表 toolbar 加往来单位下拉) - Modify:
design/prototype/screens/m-finance.html(回填真实端已有的时间 chips 行【存量漂移】+ 时间行尾加「往来单位」chip→sheet,D6) - Modify:
client/lib/providers/finance_provider.dart:18-88(加_partnerId+setPartner(),照setType写法约 8 行) - Modify:
client/lib/screens/finance/finance_screen.dart(:89-103_applyRange自定义分支showDateRangePicker→showDateRangeDropdown(anchorCtx, initial:),anchor 用「自定义」chip 的 Builder context,照 stock_in_dateMenu:247-270;:532-557_flowTabletoolbar 加ComboSearchField往来单位(照 stock_out_list_screen.dart:783-797);移动分支时间行尾加往来单位 chip→showMSheet可搜单选)
Interfaces:
-
Consumes: 后端
/finance/records?partner_id=已支持(finance.go:34,51-52);finance_repository.listRecords已有partnerId参数(:16,28);数据源allPartnersProvider(partner_provider.dart:31);showDateRangeDropdown(widgets/wheel_date_picker.dart,组件内部自适应桌面下拉/窄屏 sheet)。 -
Step 1(原型先行):
finance.html自定义时间接 datewheel + toolbar 加往来下拉;m-finance.html回填时间行 + 往来单位 chip/sheet。5180 预览两端。 -
Step 2(provider):
FinanceListNotifier加_partnerId/setPartner()并接入listRecords。 -
Step 3(统一时间):
_applyRange自定义分支换showDateRangeDropdown(一处代码两端生效,删除showDateRangePicker引用)。 -
Step 4(桌面往来筛选):
_flowTabletoolbar 类型 chips 旁加ComboSearchField(可搜单选,清除回全部)。 -
Step 5(移动往来筛选): 时间 chips 行尾加「往来单位」chip → 底部 sheet 可搜单选(D6)。
-
Step 6(验证):
flutter analyze && flutter test;财务屏 golden regen(toolbar 变了)。 -
Step 7(提交):
feat(client): 财务筛选增加往来单位并统一自定义时间组件(两端,原型同步)
Task 7: 收尾——CONTRACT 台账回填 + fidelity 体检 + 手册核查
Files:
-
Modify:
design/CONTRACT.md(块 4:库存 :100-101、出入库列表 :106-107、财务 :108 各行备注回填本次改动,保持「同步」态) -
Check:
web/content/docs.md/docs/manual/user-manual.html(若有「出入库列表默认显示」「财务筛选」相关描述则同步;无则不动) -
Step 1: 跑受影响屏 fidelity:
node tools/fidelity.mjs(库存、入库列表、出库列表、财务,桌面+移动),超 8% 回改对齐。 -
Step 2: CONTRACT.md 对应行回填改动说明与 fidelity 结果。
-
Step 3: 手册核查:默认筛选行为变化(草稿+待审核)如手册有描述则两侧同步(web/content/docs.md + user-manual.html)。
-
Step 4(全量 DoD):
flutter analyze && flutter test、node client/tool/check_ds_code.mjs、node tools/check-l1-sync.mjs全绿。 -
Step 5(提交):
docs(design): 六项前端优化 CONTRACT 台账回填与手册同步