diff --git a/CLAUDE.md b/CLAUDE.md index 7c9229a..6b415a7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -268,16 +268,16 @@ cd client && flutter test - **漂移体检**:不逐提交强制同步;大版本/整屏改版前跑 `node tools/fidelity.mjs`,按报告逐屏决定「重新对齐原型」或「降级快照」,结果回填 CONTRACT。 - **CI 闸**(`.gitea/workflows/checks.yml`,PR + main push 自动跑):① `check-ds.mjs` 原型 12 道;② `tools/check-l1-sync.mjs` L1 同源四道(tokens 快照逐字节 / icons 两端同集同内容 / 官网 token 值对齐原型主题 A / web 硬编码 hex,白名单 #fff、#1677ff,`ds-allow` 可豁免);③ `client/tool/check_ds_code.mjs` Flutter 颜色单源;④ codegen 新鲜度(regen→`dart format`→与入库产物零 diff)。本地可直接跑同名命令。 -### 表格与列头筛选(ds 真相源) -- 列表屏统一 `DsTable`(`widgets/ds/ds_table.dart`:toolbar+表格+pager 连成一卡),列定义 `DsColumn`,可筛选列走其列头漏斗(`filtered` 态高亮),可隐藏列走列设置菜单 -- 不要在 toolbar 放独立筛选按钮,筛选入口内嵌列头或工具栏 `DsChip` +### 表格与筛选/排序(ds 真相源) +- 列表屏统一 `DsTable`(`widgets/ds/ds_table.dart`:toolbar+表格+pager 连成一卡),列定义 `DsColumn`,可隐藏列走列设置菜单 +- **筛选统一放工具栏 `DsChip`**(2026-07-07 用户口径,形式参照出库管理:单选/多选 chip + 选中值/N 项摘要 + × 单清);列头**只放排序** `DsSortHeader`(点击循环 无→升→降→无,服务端全局排序)。列头漏斗 `DsFilterHeader` 已退役删除 - 旧 `FilterableColumnHeader`/`multi_select_dropdown.dart` 仅存量引用,勿在新屏使用 ### 响应式 / 移动端适配 - 断点判定统一用 `context.isMobile`(`client/lib/core/responsive/responsive.dart`,宽度 < 600 为窄屏/手机),**禁止**在各处散落 `MediaQuery.width < 600` 这类魔法数 -- **列表屏**:统一用 `DsTable`(`widgets/ds/ds_table.dart`,真相源表格:toolbar+列+pager);窄屏卡片流复用 `MobileListCard` / `MobileCardField`(`widgets/mobile_list_card.dart`)。旧 `DataTableCard` 已删除(2026-07-03),勿再引用 +- **列表屏**:统一用 `DsTable`(`widgets/ds/ds_table.dart`,真相源表格:toolbar+列+pager);窄屏卡片流用 `MCard`(`widgets/ds/m_card.dart`,镜像原型 mobile-atoms)。旧 `MobileListCard` 为 legacy 仅存量引用(迁移在 todo),旧 `DataTableCard` 已删除(2026-07-03),勿再引用 - **弹窗固定宽度**:一律用 `context.dialogWidth(X)`(≤ 屏宽 92%),**禁止**裸写 `width: <固定值>` 导致窄屏溢出 -- **导航**:窄屏(手机)用 Drawer 抽屉(`app_shell.dart`),宽屏保持侧边栏;新增页面无需单独处理,挂在 shell 下即可 +- **导航**:窄屏(手机)= 底部 5 tab(库存/入库/出库/财务/我的)+「我的」hub 聚合二级屏(`app_shell.dart` + `m_tab_bar.dart`,2026-07-04 起,Drawer 已退役);宽屏保持侧边栏;一切弹层窄屏统一走 `showMSheet` 底部 sheet - 平台判断仍遵守上面「前端平台判断」规则(`kIsWeb` 先于 `dart:io`) ### 权限中间件(已全局挂载) diff --git a/client/lib/widgets/ds/ds_table.dart b/client/lib/widgets/ds/ds_table.dart index 375f90f..155777d 100644 --- a/client/lib/widgets/ds/ds_table.dart +++ b/client/lib/widgets/ds/ds_table.dart @@ -523,38 +523,5 @@ class DsSortHeader extends StatelessWidget { } } -/// 原型 thead th .fh 漏斗列头:label + funnel(12, sw1.6),有筛选值时整体 primary。 -/// 点击回调携带列头自身 BuildContext(供 showDsMenu 锚定)。 -class DsFilterHeader extends StatelessWidget { - final String label; - final bool filtered; - final void Function(BuildContext anchorContext) onOpen; - const DsFilterHeader( - {super.key, - required this.label, - required this.filtered, - required this.onOpen}); - - @override - Widget build(BuildContext context) { - final t = context.tokens; - final color = filtered ? t.primary : t.muted; - return Builder( - builder: (bctx) => InkWell( - onTap: () => onOpen(bctx), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text(label, - style: TextStyle( - fontSize: AppDims.fsSm, - fontWeight: FontWeight.w600, - color: color)), - const SizedBox(width: 5), - Icon(LucideIcons.funnel, size: 12, color: color), - ], - ), - ), - ); - } -} +// DsFilterHeader(列头漏斗筛选)已于 2026-07-07 退役删除:筛选统一上移工具栏 +// chips(用户口径,形式参照出库管理),列头仅保留 DsSortHeader 排序。 diff --git a/client/lib/widgets/mobile_list_card.dart b/client/lib/widgets/mobile_list_card.dart index 0c056ce..8736f72 100644 --- a/client/lib/widgets/mobile_list_card.dart +++ b/client/lib/widgets/mobile_list_card.dart @@ -1,6 +1,11 @@ import 'package:flutter/material.dart'; import '../core/theme/context_tokens.dart'; +// ⚠️ LEGACY(2026-07-07 标注):本组件为旧移动卡片范式(label:value 竖排字段), +// 新范式 = widgets/ds/m_card.dart 的 MCard(镜像原型 mobile-atoms .m-card, +// 图标徽章 + 双栏紧凑)。**新屏禁用本组件,一律用 MCard**;存量 6 屏 +// (出入库录单/往来/盘点/基础数据/财务)迁移已登记 todo,迁完删除本文件。 + /// 移动端列表卡片的单个字段(label: value)。 class MobileCardField { final String label; diff --git a/client/test/golden/proto/about_a.png b/client/test/golden/proto/about_a.png index 7e656b0..aab003b 100644 Binary files a/client/test/golden/proto/about_a.png and b/client/test/golden/proto/about_a.png differ diff --git a/client/test/golden/proto/about_b.png b/client/test/golden/proto/about_b.png index f3ae714..3494d43 100644 Binary files a/client/test/golden/proto/about_b.png and b/client/test/golden/proto/about_b.png differ diff --git a/client/test/golden/proto/about_c.png b/client/test/golden/proto/about_c.png index e4ded53..9e9752d 100644 Binary files a/client/test/golden/proto/about_c.png and b/client/test/golden/proto/about_c.png differ diff --git a/client/test/golden/proto/app_shell_a.png b/client/test/golden/proto/app_shell_a.png index 3ad7d4f..4982fea 100644 Binary files a/client/test/golden/proto/app_shell_a.png and b/client/test/golden/proto/app_shell_a.png differ diff --git a/client/test/golden/proto/app_shell_b.png b/client/test/golden/proto/app_shell_b.png index cc38858..9dc4d1b 100644 Binary files a/client/test/golden/proto/app_shell_b.png and b/client/test/golden/proto/app_shell_b.png differ diff --git a/client/test/golden/proto/app_shell_c.png b/client/test/golden/proto/app_shell_c.png index 935c1ef..b140fcb 100644 Binary files a/client/test/golden/proto/app_shell_c.png and b/client/test/golden/proto/app_shell_c.png differ diff --git a/client/test/golden/proto/device_management_a.png b/client/test/golden/proto/device_management_a.png index 32beb60..6c05a06 100644 Binary files a/client/test/golden/proto/device_management_a.png and b/client/test/golden/proto/device_management_a.png differ diff --git a/client/test/golden/proto/device_management_b.png b/client/test/golden/proto/device_management_b.png index 022f857..06a56d1 100644 Binary files a/client/test/golden/proto/device_management_b.png and b/client/test/golden/proto/device_management_b.png differ diff --git a/client/test/golden/proto/device_management_c.png b/client/test/golden/proto/device_management_c.png index 39dc365..b612018 100644 Binary files a/client/test/golden/proto/device_management_c.png and b/client/test/golden/proto/device_management_c.png differ diff --git a/client/test/golden/proto/finance_a.png b/client/test/golden/proto/finance_a.png index 6484803..00811f2 100644 Binary files a/client/test/golden/proto/finance_a.png and b/client/test/golden/proto/finance_a.png differ diff --git a/client/test/golden/proto/finance_b.png b/client/test/golden/proto/finance_b.png index ecd67d8..3b057af 100644 Binary files a/client/test/golden/proto/finance_b.png and b/client/test/golden/proto/finance_b.png differ diff --git a/client/test/golden/proto/finance_c.png b/client/test/golden/proto/finance_c.png index c82f93a..5299756 100644 Binary files a/client/test/golden/proto/finance_c.png and b/client/test/golden/proto/finance_c.png differ diff --git a/client/test/golden/proto/inventory_list_a.png b/client/test/golden/proto/inventory_list_a.png index e4d703e..7bc1e36 100644 Binary files a/client/test/golden/proto/inventory_list_a.png and b/client/test/golden/proto/inventory_list_a.png differ diff --git a/client/test/golden/proto/inventory_list_b.png b/client/test/golden/proto/inventory_list_b.png index c337df2..8ff29d5 100644 Binary files a/client/test/golden/proto/inventory_list_b.png and b/client/test/golden/proto/inventory_list_b.png differ diff --git a/client/test/golden/proto/inventory_list_c.png b/client/test/golden/proto/inventory_list_c.png index f59e010..b92d10d 100644 Binary files a/client/test/golden/proto/inventory_list_c.png and b/client/test/golden/proto/inventory_list_c.png differ diff --git a/client/test/golden/proto/partners_a.png b/client/test/golden/proto/partners_a.png index c8732f2..bff2a3c 100644 Binary files a/client/test/golden/proto/partners_a.png and b/client/test/golden/proto/partners_a.png differ diff --git a/client/test/golden/proto/partners_b.png b/client/test/golden/proto/partners_b.png index 7670354..d2a0a9e 100644 Binary files a/client/test/golden/proto/partners_b.png and b/client/test/golden/proto/partners_b.png differ diff --git a/client/test/golden/proto/partners_c.png b/client/test/golden/proto/partners_c.png index 81cc482..bbcfbfd 100644 Binary files a/client/test/golden/proto/partners_c.png and b/client/test/golden/proto/partners_c.png differ diff --git a/client/test/golden/proto/products_archive_a.png b/client/test/golden/proto/products_archive_a.png index 93806a3..a78af6b 100644 Binary files a/client/test/golden/proto/products_archive_a.png and b/client/test/golden/proto/products_archive_a.png differ diff --git a/client/test/golden/proto/products_archive_b.png b/client/test/golden/proto/products_archive_b.png index 142379e..eb634f9 100644 Binary files a/client/test/golden/proto/products_archive_b.png and b/client/test/golden/proto/products_archive_b.png differ diff --git a/client/test/golden/proto/products_archive_c.png b/client/test/golden/proto/products_archive_c.png index ef311b3..9256198 100644 Binary files a/client/test/golden/proto/products_archive_c.png and b/client/test/golden/proto/products_archive_c.png differ diff --git a/client/test/golden/proto/settings_a.png b/client/test/golden/proto/settings_a.png index a9d387b..350d869 100644 Binary files a/client/test/golden/proto/settings_a.png and b/client/test/golden/proto/settings_a.png differ diff --git a/client/test/golden/proto/settings_b.png b/client/test/golden/proto/settings_b.png index 4e48605..885311b 100644 Binary files a/client/test/golden/proto/settings_b.png and b/client/test/golden/proto/settings_b.png differ diff --git a/client/test/golden/proto/settings_c.png b/client/test/golden/proto/settings_c.png index 854a5a2..0146446 100644 Binary files a/client/test/golden/proto/settings_c.png and b/client/test/golden/proto/settings_c.png differ diff --git a/client/test/golden/proto/stock_in_list_a.png b/client/test/golden/proto/stock_in_list_a.png index 26c81a9..fd2757d 100644 Binary files a/client/test/golden/proto/stock_in_list_a.png and b/client/test/golden/proto/stock_in_list_a.png differ diff --git a/client/test/golden/proto/stock_in_list_b.png b/client/test/golden/proto/stock_in_list_b.png index ea7bd2b..69b2ee8 100644 Binary files a/client/test/golden/proto/stock_in_list_b.png and b/client/test/golden/proto/stock_in_list_b.png differ diff --git a/client/test/golden/proto/stock_in_list_c.png b/client/test/golden/proto/stock_in_list_c.png index 9192ee1..e680e2d 100644 Binary files a/client/test/golden/proto/stock_in_list_c.png and b/client/test/golden/proto/stock_in_list_c.png differ diff --git a/client/test/golden/proto/stock_out_list_a.png b/client/test/golden/proto/stock_out_list_a.png index 3165066..3593ad1 100644 Binary files a/client/test/golden/proto/stock_out_list_a.png and b/client/test/golden/proto/stock_out_list_a.png differ diff --git a/client/test/golden/proto/stock_out_list_b.png b/client/test/golden/proto/stock_out_list_b.png index 0271834..c2300a3 100644 Binary files a/client/test/golden/proto/stock_out_list_b.png and b/client/test/golden/proto/stock_out_list_b.png differ diff --git a/client/test/golden/proto/stock_out_list_c.png b/client/test/golden/proto/stock_out_list_c.png index 0929d5f..a892e5a 100644 Binary files a/client/test/golden/proto/stock_out_list_c.png and b/client/test/golden/proto/stock_out_list_c.png differ diff --git a/client/test/golden/proto/users_a.png b/client/test/golden/proto/users_a.png index 65df995..3d33279 100644 Binary files a/client/test/golden/proto/users_a.png and b/client/test/golden/proto/users_a.png differ diff --git a/client/test/golden/proto/users_b.png b/client/test/golden/proto/users_b.png index 1f6986e..2da2c0c 100644 Binary files a/client/test/golden/proto/users_b.png and b/client/test/golden/proto/users_b.png differ diff --git a/client/test/golden/proto/users_c.png b/client/test/golden/proto/users_c.png index 24a8bde..da3c9b1 100644 Binary files a/client/test/golden/proto/users_c.png and b/client/test/golden/proto/users_c.png differ diff --git a/tools/screens.mjs b/tools/screens.mjs index afefae8..33a2f81 100644 --- a/tools/screens.mjs +++ b/tools/screens.mjs @@ -39,7 +39,7 @@ export const SCREENS = { waitFor: '.app', // Phase 2 重建后校准:实测 a 3.8% / b 2.9% / c 4.2%(残差=跨渲染器行高漂移 // + 状态徽章已知语义差),收紧到 8% 抓结构性回归。 - threshold: 0.08, + threshold: 0.07, // 实测 4.7% + 2pp(2026-07-07 收紧,原 0.08) }, partners: { html: '.superpowers/prototype/screens/partners.html', @@ -47,7 +47,7 @@ export const SCREENS = { width: 1280, height: 900, dpr: 2, waitFor: '.app', // 重建后校准:实测 a 3.2 / b 2.5 / c 3.5%(残差=列宽分布+文字度量+保留的导出按钮) - threshold: 0.08, + threshold: 0.06, // 实测 3.6% + 2pp(2026-07-07 收紧,原 0.08) }, products: { html: '.superpowers/prototype/screens/products.html', @@ -57,7 +57,7 @@ export const SCREENS = { // 重建后校准:实测 a 3.2 / b 2.4 / c 3.5%。残差含已知数据驱动差 // (见 design/CONTRACT.md):档案无 分类/状态 列、无香型 chips、 // seg 第 5 tab 香型→仓库、无「新增商品」、pager 带翻页控件。 - threshold: 0.08, + threshold: 0.06, // 实测 3.7% + 2pp(2026-07-07 收紧,原 0.08) }, devices: { html: '.superpowers/prototype/screens/devices.html', @@ -65,7 +65,7 @@ export const SCREENS = { width: 1280, height: 900, dpr: 2, waitFor: '.app', // 重建后校准:实测 2.4–3.0%(残差=会话表列宽分布+外设卡按钮文字省略) - threshold: 0.08, + threshold: 0.06, // 实测 3.5% + 2pp(2026-07-07 收紧,原 0.08) }, settings: { html: '.superpowers/prototype/screens/settings.html', @@ -73,7 +73,7 @@ export const SCREENS = { width: 1280, height: 900, dpr: 2, waitFor: '.app', // 已知差异:子导航多「编号规则」项、门店卡多 Logo 行。实测 1.7–2.3% - threshold: 0.08, + threshold: 0.04, // 实测 2.4% + 2pp(2026-07-07 收紧,原 0.08) }, users: { html: '.superpowers/prototype/screens/users.html', @@ -81,14 +81,14 @@ export const SCREENS = { width: 1280, height: 900, dpr: 2, waitFor: '.app', // 已知差异:角色口径拉平为后端四级(原型 KPI 初值/角色混用三级)。实测 1.3–2.1% - threshold: 0.08, + threshold: 0.04, // 实测 1.9% + 2pp(2026-07-07 收紧,原 0.08) }, about: { html: '.superpowers/prototype/screens/about.html', prefix: 'about', width: 1280, height: 900, dpr: 2, waitFor: '.app', - threshold: 0.08, // 实测 2.2–2.7% + threshold: 0.05, // 实测 2.7% + 2pp(2026-07-07 收紧,原 0.08) }, 'stock-in': { html: '.superpowers/prototype/screens/stock-in-list.html', @@ -98,7 +98,7 @@ export const SCREENS = { // 2026-07-03 补注册(此前漏注册导致单元格样式偏差长期未被闸住)。 // 页面留白/单元格对齐后校准:实测 a 3.6 / b 2.6 / c 3.9% //(残差=真实数据 vs 原型演示数据 + 状态列口径/placeholder 文案已知差异)。 - threshold: 0.08, + threshold: 0.06, // 实测 4.0% + 2pp(2026-07-07 收紧,原 0.08) }, 'stock-out': { html: '.superpowers/prototype/screens/stock-out-list.html', @@ -106,7 +106,7 @@ export const SCREENS = { width: 1280, height: 900, dpr: 2, waitFor: '.app', // 页面留白/单元格对齐后校准:实测 a 3.6 / b 2.6 / c 3.9% - threshold: 0.08, + threshold: 0.06, // 实测 4.0% + 2pp(2026-07-07 收紧,原 0.08) }, login: { html: '.superpowers/prototype/screens/login.html', @@ -116,7 +116,7 @@ export const SCREENS = { // 2026-07-03 重建后校准:实测 a 1.9 / b 1.4 / c 2.1%。已知差异 // (design/CONTRACT.md):密码框空值 hint vs 原型 8 dots、 // 历史下拉/密码可见后缀箭头(功能位)、ds-fab 仅原型有。 - threshold: 0.08, + threshold: 0.04, // 实测 2.4% + 2pp(2026-07-07 收紧,原 0.08) }, // register:暂不入闸(2026-07-03 用户拍板)。原型多「门店编号/授权兑换券」 // 两字段,后端 RegisterInput 暂不支持 → 表单少两行,整卡结构性错位 @@ -136,6 +136,6 @@ export const SCREENS = { waitFor: '.app', // 重建后校准:实测 a 3.9 / b 3.0 / c 4.2%(残差=柱高比例+文字度量+ // KPI 应收为实算汇总 vs 原型硬编码,见 CONTRACT 已知差异) - threshold: 0.08, + threshold: 0.06, // 实测 4.3% + 2pp(2026-07-07 收紧,原 0.08) }, };