refactor(client): 前端体系治理——漏斗退役/老卡片标 legacy/fidelity 收阈/文档口径修正
- DsFilterHeader 删除(筛选已全部上移工具栏 chips,屏内零引用) - mobile_list_card 标 LEGACY 禁新用(6 屏迁移 MCard 登记 todo #13) - fidelity 阈值按 2026-07-07 实测收紧:一刀切 8% → 各屏实测最大残差+2pp (4%~7%),新阈下 36 屏×主题全过;proto 基准同步重摄(含库存改版) - CLAUDE.md 修正:表格筛选口径(工具栏 chips+列头仅排序)、响应式导航 (Drawer 退役→底部 5 tab,修文字滞后) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
@@ -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`)
|
||||
|
||||
### 权限中间件(已全局挂载)
|
||||
|
||||
@@ -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 排序。
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
Before Width: | Height: | Size: 393 KiB After Width: | Height: | Size: 394 KiB |
|
Before Width: | Height: | Size: 389 KiB After Width: | Height: | Size: 389 KiB |
|
Before Width: | Height: | Size: 445 KiB After Width: | Height: | Size: 443 KiB |
|
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 438 KiB |
|
Before Width: | Height: | Size: 423 KiB After Width: | Height: | Size: 426 KiB |
|
Before Width: | Height: | Size: 435 KiB After Width: | Height: | Size: 439 KiB |
|
Before Width: | Height: | Size: 383 KiB After Width: | Height: | Size: 384 KiB |
|
Before Width: | Height: | Size: 373 KiB After Width: | Height: | Size: 374 KiB |
|
Before Width: | Height: | Size: 385 KiB After Width: | Height: | Size: 386 KiB |
|
Before Width: | Height: | Size: 277 KiB After Width: | Height: | Size: 276 KiB |
|
Before Width: | Height: | Size: 271 KiB After Width: | Height: | Size: 271 KiB |
|
Before Width: | Height: | Size: 278 KiB After Width: | Height: | Size: 278 KiB |
|
Before Width: | Height: | Size: 438 KiB After Width: | Height: | Size: 438 KiB |
|
Before Width: | Height: | Size: 426 KiB After Width: | Height: | Size: 426 KiB |
|
Before Width: | Height: | Size: 439 KiB After Width: | Height: | Size: 439 KiB |
|
Before Width: | Height: | Size: 383 KiB After Width: | Height: | Size: 388 KiB |
|
Before Width: | Height: | Size: 374 KiB After Width: | Height: | Size: 379 KiB |
|
Before Width: | Height: | Size: 384 KiB After Width: | Height: | Size: 388 KiB |
|
Before Width: | Height: | Size: 362 KiB After Width: | Height: | Size: 362 KiB |
|
Before Width: | Height: | Size: 354 KiB After Width: | Height: | Size: 355 KiB |
|
Before Width: | Height: | Size: 362 KiB After Width: | Height: | Size: 363 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 402 KiB After Width: | Height: | Size: 405 KiB |
|
Before Width: | Height: | Size: 392 KiB After Width: | Height: | Size: 394 KiB |
|
Before Width: | Height: | Size: 404 KiB After Width: | Height: | Size: 407 KiB |
|
Before Width: | Height: | Size: 400 KiB After Width: | Height: | Size: 402 KiB |
|
Before Width: | Height: | Size: 388 KiB After Width: | Height: | Size: 391 KiB |
|
Before Width: | Height: | Size: 401 KiB After Width: | Height: | Size: 404 KiB |
|
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 216 KiB |
|
Before Width: | Height: | Size: 212 KiB After Width: | Height: | Size: 212 KiB |
|
Before Width: | Height: | Size: 218 KiB After Width: | Height: | Size: 218 KiB |
@@ -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)
|
||||
},
|
||||
};
|
||||
|
||||