@jc-times/business-ui 0.2.53 → 0.2.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/mrt-poc.md CHANGED
@@ -1,205 +1,205 @@
1
- # 表格能力与 MRT 验证样例
2
-
3
- 更新日期:2026-09-12。已决定采用MRT,当前工作树已替代公共DataTable渲染内核并提供独立入口;对应0.2.31;其他服务需单独升级。当前公共API见 [DataTable迁移](data-table.md)。以下合同包装仍是业务验证样例。本文区分现有公共 `DataTable` 与样例能力,不把工作树功能视为已发布 API。
4
-
5
- ## 选用入口
6
-
7
- | 场景 | 当前实现 | 调用边界 |
8
- | --- | --- | --- |
9
- | 普通列表、排序、选择、加载/空态 | 公共 `DataTable` | 从实际安装版本导入,完整参数以类型声明为准 |
10
- | 列筛选、列设置、拖动/固定/缩放 | MRT 本地样例 | 仅 `examples/mrt-poc`,无 npm 导出 |
11
- | 一条主记录包含多条明细,主字段跨行合并 | MRT 样例 `productDisplay="inline"` | 原生 `rowSpan`,按主记录分页 |
12
- | 点击主记录箭头展开明细 | MRT 样例 `productDisplay="expanded"` | MRT 详情面板,默认收起 |
13
-
14
- 公共 `DataTable` 的旧参数兼容层保留原生行渲染,表格外壳已使用MRT,支持 `hiddenColumnIds`、客户端/服务端排序、受控行选择和行级 memo。列顺序由传入 `columns` 决定;筛选、分页取数及切片由调用方组合。旧参数不自动启用高级能力;完整配置及合并渲染器见DataTable迁移文档。参见 [公共 API](api.md#数据表移动端契约) 和 [成熟度迁移](maturity-migration.md)。
15
-
16
- 现有 `DataTable` 的移动布局可以选择 `scroll` / `cards`;MRT 样例仅使用表格容器内横向滚动,没有卡片模式。
17
-
18
- ## 本地启动
19
-
20
- ```powershell
21
- pnpm dev:mrt
22
- # http://127.0.0.1:4186/
23
- pnpm test:mrt
24
- pnpm build:mrt
25
- # 仅用于与简表做构建体积对照
26
- pnpm exec vite build --config examples/mrt-poc/vite.config.ts --mode baseline
27
- ```
28
-
29
- 样例提供 120 份模拟合同和 5,000 份规模体验,每份合同默认三条模拟产品。没有生产接口或真实客户/员工数据。MRT 3.2.1、MUI material/icons 7.3.11、x-date-pickers 9.13.0、Emotion react 11.14.0 / styled 11.14.1 已迁为正式依赖;公共data-table入口使用这些依赖。
30
-
31
- ## 表格交互
32
-
33
- | 能力 | 当前行为 |
34
- | --- | --- |
35
- | 搜索 | 按合同字段做本地全局搜索,不搜索产品明细 |
36
- | 列筛选 | 文本、金额区间、状态下拉;筛选结果按合同计数 |
37
- | 排序 | 单击表头;产品字段没有独立排序语义,已关闭排序 |
38
- | 表头拖动 | 按住表头文字拖动,无独立手柄;有效放下才更新顺序,拖后不触发排序 |
39
- | 列设置 | 字段勾选、左侧轻量手柄排序、左/右固定;与表头共用顺序状态 |
40
- | 列显隐 | 合同编号必选;部门默认隐藏;显示字段不是业务权限控制 |
41
- | 列宽 | 拖动列边缘;金额默认180px、最小140px |
42
- | 选择/分页 | 以合同为单位,跨页保留选择;一份合同的产品不拆到不同页 |
43
- | 默认视图 | 表格底部重置搜索、筛选、排序、列顺序、显隐和选择,不重置全部表格状态 |
44
- | 列设置恢复默认 | 重置列顺序、显隐、固定位置及列宽,不清空业务筛选和选择 |
45
-
46
- 输入框、列菜单及缩放边缘保留各自交互,不触发表头拖列。表头拖动用原生 HTML drag 事件;列设置复用公共 `SortableList`。已验证桌面鼠标拖动,不能据此宣称本样例的真实手机/键盘列排序已验收。
47
-
48
- ## 产品展示配置
49
-
50
- ### 参数
51
-
52
- 独立样例组件为 `examples/mrt-poc/ContractTable.tsx`,参数如下。它依赖示例的 `TableTheme` 和样式环境,不能从已发布 `@jc-times/business-ui` 直接导入。
53
-
54
- | 参数 | 类型 | 默认值 | 说明 |
55
- | --- | --- | --- | --- |
56
- | `rows` | `Contract[]` | 必填 | 调用方提供合同及产品数据 |
57
- | `productDisplay` | `'none' \| 'inline' \| 'expanded'` | `'none'` | 调用服务按页面需求固定选择 |
58
- | `inModal` | `boolean` | `false` | 使用弹窗内表格高度;自身不创建弹窗 |
59
- | `searchMemoryKey` | `string` | 不启用 | 按服务/租户/用户/列表提供稳定标识,启用本地搜索记忆;变更标识时重建组件 |
60
- | `virtual` | `boolean` | `false` | 常规/展开模式可启用行虚拟化;合并模式始终分页 |
61
-
62
- 在当前示例的主题和样式上下文内:
63
-
64
- ```tsx
65
- // 三个真实产品行,合同字段跨行合并
66
- <ContractTable rows={contracts} productDisplay="inline" />
67
-
68
- // 主行默认收起,点击箭头查看产品
69
- <ContractTable rows={contracts} productDisplay="expanded" />
70
-
71
- // 普通合同列表
72
- <ContractTable rows={contracts} productDisplay="none" />
73
- ```
74
-
75
- 模式由调用方选择,不要求最终用户必须看到切换器。演示页面的“产品展示”选择器仅便于体验,切换时通过 React key 重建表格,选择等未持久化状态会重置,配置相同searchMemoryKey时恢复搜索和列筛选;弹窗沿用页面选择的模式。其他调用场景动态切换时应同样重建,或显式协调列顺序等受控状态。
76
-
77
- ### 数据契约
78
-
79
- ```ts
80
- type ContractProduct = {
81
- id: string; // 同一合同内稳定唯一
82
- name: string;
83
- specification: string;
84
- quantity: number;
85
- unit: string;
86
- };
87
-
88
- type Contract = {
89
- id: string; // 合同稳定唯一,作为选择和行标识
90
- name: string;
91
- customer: string;
92
- amount: number; // 样例以元表示,用 Intl.NumberFormat 格式化
93
- owner: string;
94
- status: string;
95
- signedAt: string;
96
- department: string;
97
- products: ContractProduct[];
98
- };
99
- ```
100
-
101
- 产品数组长度不限于三条;调用方没有产品时传 `[]`。当前状态徽标映射仍是样例业务逻辑。正式通用化需要明细数据/渲染插槽和调用方状态映射,不应把合同字段或产品模型固化为公共库契约。
102
-
103
- ### 同行模式:原生行合并
104
-
105
- 每个产品渲染为主表 `tbody` 中的一个真实 `tr`,产品名称、规格、数量各占独立列。合同信息和选择框使用 `rowSpan=产品数` 跨行显示、纵向居中;没有嵌套表格。
106
-
107
- 实现使用 MRT 的 `semantic` 布局与 `muiTableBodyProps.children`,自定义 `MergedProductRows` 复用 MRT 单元格渲染和列状态。这是样例适配,不是 MRT 开箱提供的自动合并能力。
108
-
109
- - 根据每份合同的产品数合并,不把不同合同中相同文本自动合并。
110
- - 无产品时保留一个主行,产品位置显示“暂无产品”和占位符。
111
- - 隐藏全部产品列时,每份合同恢复为一行。
112
- - 产品列可以调整顺序、显隐和宽度;合同仍是选择、搜索、排序与分页单位。
113
- - 尚未提供任意单元格 `rowSpan` / `colSpan` 配置,也未做跨合同合并。
114
- - 合并模式关闭行虚拟化,以免截断跨行单元格;5,000份数据也按合同分页。
115
-
116
- ### 展开模式
117
-
118
- 通过行首按钮展开/收起产品,使用 `renderDetailPanel`,默认收起且未提供展开全部。详情内使用独立产品小表,合同主列表行高保持紧凑。展开模式保留虚拟化选项,但带产品详情的5,000行场景尚无专项性能结论。
119
-
120
- 两种模式都没有产品独立筛选、排序、编辑或选择功能。
121
-
122
- ## 样式与弹窗约定
123
-
124
- 颜色、边框、圆角和焦点使用 `--ui-*`;复用 Button、Checkbox、Badge、Pagination、SortableList、ModalShell,图标采用 Lucide 适配。公共组件源码不因 POC 而改变。
125
-
126
- - 文本默认左对齐,金额和数量右对齐,金额采用等宽数字。
127
- - 表头完全不透明;排序/列菜单图标保持清晰,菜单无边框透明底,仅悬停或键盘聚焦显示浅色背景。
128
- - 表头筛选桌面32px、粗指针44px,缩短占位符并保留完整无障碍字段名。
129
- - 金额列保留单行“金额范围”入口,点击弹出最小/最大金额输入;已设置时显示范围摘要。不再上下堆叠输入撑高整行表头,列仍可缩至140px。
130
- - 窄屏在表格内部横向滚动,列设置内部纵向滚动。
131
-
132
- MUI Popover/Popper 通过 `useOverlayContainer` 进入现有 ModalShell 边界,避免浮层落到模态外。嵌套 Popover 关闭自己的 enforceFocus,保留外层焦点约束。示例包装层捕获 Escape:有内层 Popover 时先由内层处理,否则关闭外层并恢复触发器焦点。此包装在 `main.tsx`,`ContractTable` 本身不负责创建主题或模态焦点边界。
133
-
134
- ## 性能与验证
135
-
136
- 现有公共 `DataTable` 会渲染所有传入行,单元格规模约为行数乘可见列数。稳定的列定义、行对象和回调有助于行级 memo;大数据应由调用方分页,不能把行缓存视为虚拟化。
137
-
138
- 截至2026-09-12,MRT样例类型检查、14项浏览器回归和样例构建通过。覆盖搜索/筛选、跨页选择、表头及列设置拖动、列显隐、金额缩列、页面/弹窗、Escape、合并行结构、展开收起和常规5,000行虚拟DOM控制。五档视口为1440×900、768×1024、390×844、320×480、844×390;产品模式还检查了390px弹窗显示。
139
-
140
- 初版生产构建测量:常规5,000行虚拟模式首尾仅渲染21/22个DOM行、可达末条且无控制台error。这是初版普通模式的测量,不能套用到新增合并/展开产品模式;不代表首屏耗时、帧率、内存或真实低端机性能。
141
-
142
- | 构建 | JS gzip | 说明 |
143
- | --- | ---: | --- |
144
- | 当前完整样例(2026-09-12) | 约380.8KB | 包含MRT/MUI、SortableList、弹窗及产品展示;CSS gzip约11.0KB |
145
- | 初版简表基线(2026-09-11) | 约50KB | 现有DataTable最小页面,未在本次文档整理中重测 |
146
-
147
- 两者功能不等价,不能据此计算MRT单包成本或推断运行速度。样例当前单入口打包,正式接入应评估页面懒加载。公共包没有导出这些MRT示例。
148
-
149
- 生产测量入口(需先构建,端口占用时另选并同步测量脚本):
150
-
151
- ```powershell
152
- pnpm exec vite preview --config examples/mrt-poc/vite.config.ts --host 127.0.0.1 --port 4187 --strictPort
153
- node examples/mrt-poc/measure.mjs
154
- ```
155
-
156
- 截图/测量输出在 `artifacts/mrt-qa/`,失败trace在 `artifacts/mrt-test-results/`,均为忽略产物。性能结论应注明模式、记录数、视口、构建和测量环境。
157
-
158
- ## 文件与后续接入
159
-
160
- | 文件 | 职责 |
161
- | --- | --- |
162
- | `examples/mrt-poc/main.tsx` | 页面、模式选择、主题和现有弹窗适配 |
163
- | `examples/mrt-poc/ContractTable.tsx` | MRT配置、合同列、筛选/排序/拖动/分页 |
164
- | `examples/mrt-poc/MergedProductRows.tsx` | 主表真实产品行及合同rowSpan |
165
- | `examples/mrt-poc/ProductRows.tsx` | 展开详情小表及模式类型 |
166
- | `examples/mrt-poc/ColumnSettings.tsx` | 显隐、排序、固定及列恢复默认 |
167
- | `examples/mrt-poc/data.ts` | 模拟数据与样例类型 |
168
- | `examples/mrt-poc/styles.css`、`icons.tsx`、`tokens.ts` | 局部视觉适配 |
169
- | `examples/mrt-poc/mrt.browser.ts` | 可重复的浏览器回归 |
170
-
1
+ # 表格能力与 MRT 验证样例
2
+
3
+ 更新日期:2026-09-12。已决定采用MRT,当前工作树已替代公共DataTable渲染内核并提供独立入口;对应0.2.31;其他服务需单独升级。当前公共API见 [DataTable迁移](data-table.md)。以下合同包装仍是业务验证样例。本文区分现有公共 `DataTable` 与样例能力,不把工作树功能视为已发布 API。
4
+
5
+ ## 选用入口
6
+
7
+ | 场景 | 当前实现 | 调用边界 |
8
+ | --- | --- | --- |
9
+ | 普通列表、排序、选择、加载/空态 | 公共 `DataTable` | 从实际安装版本导入,完整参数以类型声明为准 |
10
+ | 列筛选、列设置、拖动/固定/缩放 | MRT 本地样例 | 仅 `examples/mrt-poc`,无 npm 导出 |
11
+ | 一条主记录包含多条明细,主字段跨行合并 | MRT 样例 `productDisplay="inline"` | 原生 `rowSpan`,按主记录分页 |
12
+ | 点击主记录箭头展开明细 | MRT 样例 `productDisplay="expanded"` | MRT 详情面板,默认收起 |
13
+
14
+ 公共 `DataTable` 的旧参数兼容层保留原生行渲染,表格外壳已使用MRT,支持 `hiddenColumnIds`、客户端/服务端排序、受控行选择和行级 memo。列顺序由传入 `columns` 决定;筛选、分页取数及切片由调用方组合。旧参数不自动启用高级能力;完整配置及合并渲染器见DataTable迁移文档。参见 [公共 API](api.md#数据表移动端契约) 和 [成熟度迁移](maturity-migration.md)。
15
+
16
+ 现有 `DataTable` 的移动布局可以选择 `scroll` / `cards`;MRT 样例仅使用表格容器内横向滚动,没有卡片模式。
17
+
18
+ ## 本地启动
19
+
20
+ ```powershell
21
+ pnpm dev:mrt
22
+ # http://127.0.0.1:4186/
23
+ pnpm test:mrt
24
+ pnpm build:mrt
25
+ # 仅用于与简表做构建体积对照
26
+ pnpm exec vite build --config examples/mrt-poc/vite.config.ts --mode baseline
27
+ ```
28
+
29
+ 样例提供 120 份模拟合同和 5,000 份规模体验,每份合同默认三条模拟产品。没有生产接口或真实客户/员工数据。MRT 3.2.1、MUI material/icons 7.3.11、x-date-pickers 9.13.0、Emotion react 11.14.0 / styled 11.14.1 已迁为正式依赖;公共data-table入口使用这些依赖。
30
+
31
+ ## 表格交互
32
+
33
+ | 能力 | 当前行为 |
34
+ | --- | --- |
35
+ | 搜索 | 按合同字段做本地全局搜索,不搜索产品明细 |
36
+ | 列筛选 | 文本、金额区间、状态下拉;筛选结果按合同计数 |
37
+ | 排序 | 单击表头;产品字段没有独立排序语义,已关闭排序 |
38
+ | 表头拖动 | 按住表头文字拖动,无独立手柄;有效放下才更新顺序,拖后不触发排序 |
39
+ | 列设置 | 字段勾选、左侧轻量手柄排序、左/右固定;与表头共用顺序状态 |
40
+ | 列显隐 | 合同编号必选;部门默认隐藏;显示字段不是业务权限控制 |
41
+ | 列宽 | 拖动列边缘;金额默认180px、最小140px |
42
+ | 选择/分页 | 以合同为单位,跨页保留选择;一份合同的产品不拆到不同页 |
43
+ | 默认视图 | 表格底部重置搜索、筛选、排序、列顺序、显隐和选择,不重置全部表格状态 |
44
+ | 列设置恢复默认 | 重置列顺序、显隐、固定位置及列宽,不清空业务筛选和选择 |
45
+
46
+ 输入框、列菜单及缩放边缘保留各自交互,不触发表头拖列。表头拖动用原生 HTML drag 事件;列设置复用公共 `SortableList`。已验证桌面鼠标拖动,不能据此宣称本样例的真实手机/键盘列排序已验收。
47
+
48
+ ## 产品展示配置
49
+
50
+ ### 参数
51
+
52
+ 独立样例组件为 `examples/mrt-poc/ContractTable.tsx`,参数如下。它依赖示例的 `TableTheme` 和样式环境,不能从已发布 `@jc-times/business-ui` 直接导入。
53
+
54
+ | 参数 | 类型 | 默认值 | 说明 |
55
+ | --- | --- | --- | --- |
56
+ | `rows` | `Contract[]` | 必填 | 调用方提供合同及产品数据 |
57
+ | `productDisplay` | `'none' \| 'inline' \| 'expanded'` | `'none'` | 调用服务按页面需求固定选择 |
58
+ | `inModal` | `boolean` | `false` | 使用弹窗内表格高度;自身不创建弹窗 |
59
+ | `searchMemoryKey` | `string` | 不启用 | 按服务/租户/用户/列表提供稳定标识,启用本地搜索记忆;变更标识时重建组件 |
60
+ | `virtual` | `boolean` | `false` | 常规/展开模式可启用行虚拟化;合并模式始终分页 |
61
+
62
+ 在当前示例的主题和样式上下文内:
63
+
64
+ ```tsx
65
+ // 三个真实产品行,合同字段跨行合并
66
+ <ContractTable rows={contracts} productDisplay="inline" />
67
+
68
+ // 主行默认收起,点击箭头查看产品
69
+ <ContractTable rows={contracts} productDisplay="expanded" />
70
+
71
+ // 普通合同列表
72
+ <ContractTable rows={contracts} productDisplay="none" />
73
+ ```
74
+
75
+ 模式由调用方选择,不要求最终用户必须看到切换器。演示页面的“产品展示”选择器仅便于体验,切换时通过 React key 重建表格,选择等未持久化状态会重置,配置相同searchMemoryKey时恢复搜索和列筛选;弹窗沿用页面选择的模式。其他调用场景动态切换时应同样重建,或显式协调列顺序等受控状态。
76
+
77
+ ### 数据契约
78
+
79
+ ```ts
80
+ type ContractProduct = {
81
+ id: string; // 同一合同内稳定唯一
82
+ name: string;
83
+ specification: string;
84
+ quantity: number;
85
+ unit: string;
86
+ };
87
+
88
+ type Contract = {
89
+ id: string; // 合同稳定唯一,作为选择和行标识
90
+ name: string;
91
+ customer: string;
92
+ amount: number; // 样例以元表示,用 Intl.NumberFormat 格式化
93
+ owner: string;
94
+ status: string;
95
+ signedAt: string;
96
+ department: string;
97
+ products: ContractProduct[];
98
+ };
99
+ ```
100
+
101
+ 产品数组长度不限于三条;调用方没有产品时传 `[]`。当前状态徽标映射仍是样例业务逻辑。正式通用化需要明细数据/渲染插槽和调用方状态映射,不应把合同字段或产品模型固化为公共库契约。
102
+
103
+ ### 同行模式:原生行合并
104
+
105
+ 每个产品渲染为主表 `tbody` 中的一个真实 `tr`,产品名称、规格、数量各占独立列。合同信息和选择框使用 `rowSpan=产品数` 跨行显示、纵向居中;没有嵌套表格。
106
+
107
+ 实现使用 MRT 的 `semantic` 布局与 `muiTableBodyProps.children`,自定义 `MergedProductRows` 复用 MRT 单元格渲染和列状态。这是样例适配,不是 MRT 开箱提供的自动合并能力。
108
+
109
+ - 根据每份合同的产品数合并,不把不同合同中相同文本自动合并。
110
+ - 无产品时保留一个主行,产品位置显示“暂无产品”和占位符。
111
+ - 隐藏全部产品列时,每份合同恢复为一行。
112
+ - 产品列可以调整顺序、显隐和宽度;合同仍是选择、搜索、排序与分页单位。
113
+ - 尚未提供任意单元格 `rowSpan` / `colSpan` 配置,也未做跨合同合并。
114
+ - 合并模式关闭行虚拟化,以免截断跨行单元格;5,000份数据也按合同分页。
115
+
116
+ ### 展开模式
117
+
118
+ 通过行首按钮展开/收起产品,使用 `renderDetailPanel`,默认收起且未提供展开全部。详情内使用独立产品小表,合同主列表行高保持紧凑。展开模式保留虚拟化选项,但带产品详情的5,000行场景尚无专项性能结论。
119
+
120
+ 两种模式都没有产品独立筛选、排序、编辑或选择功能。
121
+
122
+ ## 样式与弹窗约定
123
+
124
+ 颜色、边框、圆角和焦点使用 `--ui-*`;复用 Button、Checkbox、Badge、Pagination、SortableList、ModalShell,图标采用 Lucide 适配。公共组件源码不因 POC 而改变。
125
+
126
+ - 文本默认左对齐,金额和数量右对齐,金额采用等宽数字。
127
+ - 表头完全不透明;排序/列菜单图标保持清晰,菜单无边框透明底,仅悬停或键盘聚焦显示浅色背景。
128
+ - 表头筛选桌面32px、粗指针44px,缩短占位符并保留完整无障碍字段名。
129
+ - 金额列保留单行“金额范围”入口,点击弹出最小/最大金额输入;已设置时显示范围摘要。不再上下堆叠输入撑高整行表头,列仍可缩至140px。
130
+ - 窄屏在表格内部横向滚动,列设置内部纵向滚动。
131
+
132
+ MUI Popover/Popper 通过 `useOverlayContainer` 进入现有 ModalShell 边界,避免浮层落到模态外。嵌套 Popover 关闭自己的 enforceFocus,保留外层焦点约束。示例包装层捕获 Escape:有内层 Popover 时先由内层处理,否则关闭外层并恢复触发器焦点。此包装在 `main.tsx`,`ContractTable` 本身不负责创建主题或模态焦点边界。
133
+
134
+ ## 性能与验证
135
+
136
+ 现有公共 `DataTable` 会渲染所有传入行,单元格规模约为行数乘可见列数。稳定的列定义、行对象和回调有助于行级 memo;大数据应由调用方分页,不能把行缓存视为虚拟化。
137
+
138
+ 截至2026-09-12,MRT样例类型检查、14项浏览器回归和样例构建通过。覆盖搜索/筛选、跨页选择、表头及列设置拖动、列显隐、金额缩列、页面/弹窗、Escape、合并行结构、展开收起和常规5,000行虚拟DOM控制。五档视口为1440×900、768×1024、390×844、320×480、844×390;产品模式还检查了390px弹窗显示。
139
+
140
+ 初版生产构建测量:常规5,000行虚拟模式首尾仅渲染21/22个DOM行、可达末条且无控制台error。这是初版普通模式的测量,不能套用到新增合并/展开产品模式;不代表首屏耗时、帧率、内存或真实低端机性能。
141
+
142
+ | 构建 | JS gzip | 说明 |
143
+ | --- | ---: | --- |
144
+ | 当前完整样例(2026-09-12) | 约380.8KB | 包含MRT/MUI、SortableList、弹窗及产品展示;CSS gzip约11.0KB |
145
+ | 初版简表基线(2026-09-11) | 约50KB | 现有DataTable最小页面,未在本次文档整理中重测 |
146
+
147
+ 两者功能不等价,不能据此计算MRT单包成本或推断运行速度。样例当前单入口打包,正式接入应评估页面懒加载。公共包没有导出这些MRT示例。
148
+
149
+ 生产测量入口(需先构建,端口占用时另选并同步测量脚本):
150
+
151
+ ```powershell
152
+ pnpm exec vite preview --config examples/mrt-poc/vite.config.ts --host 127.0.0.1 --port 4187 --strictPort
153
+ node examples/mrt-poc/measure.mjs
154
+ ```
155
+
156
+ 截图/测量输出在 `artifacts/mrt-qa/`,失败trace在 `artifacts/mrt-test-results/`,均为忽略产物。性能结论应注明模式、记录数、视口、构建和测量环境。
157
+
158
+ ## 文件与后续接入
159
+
160
+ | 文件 | 职责 |
161
+ | --- | --- |
162
+ | `examples/mrt-poc/main.tsx` | 页面、模式选择、主题和现有弹窗适配 |
163
+ | `examples/mrt-poc/ContractTable.tsx` | MRT配置、合同列、筛选/排序/拖动/分页 |
164
+ | `examples/mrt-poc/MergedProductRows.tsx` | 主表真实产品行及合同rowSpan |
165
+ | `examples/mrt-poc/ProductRows.tsx` | 展开详情小表及模式类型 |
166
+ | `examples/mrt-poc/ColumnSettings.tsx` | 显隐、排序、固定及列恢复默认 |
167
+ | `examples/mrt-poc/data.ts` | 模拟数据与样例类型 |
168
+ | `examples/mrt-poc/styles.css`、`icons.tsx`、`tokens.ts` | 局部视觉适配 |
169
+ | `examples/mrt-poc/mrt.browser.ts` | 可重复的浏览器回归 |
170
+
171
171
  已决定采用MRT;其他服务接入前,需确定通用列/明细插槽、模式选择、受控选择与查询状态、列偏好持久化、服务端契约和权限边界,再完成公共导出、版本发布及实际消费验证。当前样例未连接接口;仅搜索条件可本地记忆,列顺序/显隐/宽度等偏好尚未持久化,未验证React 19组合或真实手机/键盘拖列。不要跨仓库复制样例冒充已发布能力。
172
-
173
- ## 搜索条件记忆
174
-
175
- `searchMemoryKey` 启用后,将生效的全局关键词、列筛选(含金额范围)及筛选栏状态保存到当前浏览器localStorage,刷新或重建时恢复。页面日常列表、5,000条体验与选择弹窗使用不同标识,产品显示模式共用所属列表的搜索记忆。
176
-
177
- ```tsx
178
- <ContractTable rows={contracts} searchMemoryKey={`${serviceId}:${tenantId}:${userId}:contracts`} />
179
- ```
180
-
181
- 存储键前缀为 `business-ui:mrt-search:v1:`。不传参数即不持久化;调用方切换用户或列表标识时,应以key重建组件。损坏数据、未知字段或浏览器存储不可用时回退,搜索仍可用。“恢复默认视图”强制清空筛选而非回到挂载时的已恢复条件,同时删除该列表的搜索记忆。列设置中的恢复默认不清除搜索。仅限当前浏览器,不同步到账号或其他设备;分页、选择、排序及列布局没有在此保存。
182
-
183
- ## 2026-09-12 性能专项复核
184
-
185
- Material/MRT提供基础能力,不免除调用侧性能设计。现有公共DataTable并不基于Material;MRT样例的UI由MUI提供,行模型由TanStack处理。
186
-
187
- 生产构建、Chromium、1440×900、本机无CPU节流,3次“搜索唯一合同并等待匹配数更新”观测:
188
-
189
- | 模式 | 合同数 | 初始实际tbody行 | 搜索端到端观测(ms) |
190
- | --- | ---: | ---: | --- |
191
- | 普通分页 | 120 | 20 | 314 / 340 / 310 |
192
- | 普通虚拟 | 5,000 | 19 | 321 / 311 / 313 |
193
- | 合并、每合同3产品、每页20合同 | 5,000 | 60 | 315 / 337 / 343 |
194
-
195
- 这些时间包含MRT输入的250ms防抖、自动化操作及等待,不能当作纯筛选CPU时间或正式基准。记录位于忽略产物 `artifacts/mrt-qa/performance-review.json`。未测真实网络、低端机、内存峰值及滚动帧率;本次没有足够证据宣称已出现计算瓶颈。
196
-
197
- 优先级判断:
198
-
199
- 1. 正式接入优先页面懒加载:当前完整样例JS gzip约381KB,不能让所有业务页面首屏都承担此成本。
200
- 2. 更大数据量优先服务端筛选/排序/分页:虚拟化只减少DOM,5,000条仍在浏览器内参与过滤。没有测量依据时不规定统一行数阈值。
201
- 3. 合并模式的DOM规模为当前页产品数之和。每合同3产品时受控,但单份合同数百产品会放大渲染,届时优先展开详情并对明细分页。
202
- 4. 公共DataTable已有行级memo、稳定选择回调和排序结果缓存,排序键每行预取一次;不能用“全部重写”代替分页。调用方应保持rows/columns引用稳定,重型单元格需单独分析。
203
- 5. MRT样例的自定义合并body会在表格状态更新时遍历当前页,尚未做逐合同渲染隔离;当前60行没有测出明显恶化,不宜直接打开全表memo以牺牲列拖动/缩放等响应。后续复杂产品单元格先用Profiler定位再优化。
204
-
205
- 公共DataTable相关三个测试文件共24项通过,MRT样例14项浏览器回归、类型和构建通过。本轮未改公共DataTable的性能实现;搜索记忆仅在搜索状态改变时写入小对象,不随单纯勾选触发写入。
172
+
173
+ ## 搜索条件记忆
174
+
175
+ `searchMemoryKey` 启用后,将生效的全局关键词、列筛选(含金额范围)及筛选栏状态保存到当前浏览器localStorage,刷新或重建时恢复。页面日常列表、5,000条体验与选择弹窗使用不同标识,产品显示模式共用所属列表的搜索记忆。
176
+
177
+ ```tsx
178
+ <ContractTable rows={contracts} searchMemoryKey={`${serviceId}:${tenantId}:${userId}:contracts`} />
179
+ ```
180
+
181
+ 存储键前缀为 `business-ui:mrt-search:v1:`。不传参数即不持久化;调用方切换用户或列表标识时,应以key重建组件。损坏数据、未知字段或浏览器存储不可用时回退,搜索仍可用。“恢复默认视图”强制清空筛选而非回到挂载时的已恢复条件,同时删除该列表的搜索记忆。列设置中的恢复默认不清除搜索。仅限当前浏览器,不同步到账号或其他设备;分页、选择、排序及列布局没有在此保存。
182
+
183
+ ## 2026-09-12 性能专项复核
184
+
185
+ Material/MRT提供基础能力,不免除调用侧性能设计。现有公共DataTable并不基于Material;MRT样例的UI由MUI提供,行模型由TanStack处理。
186
+
187
+ 生产构建、Chromium、1440×900、本机无CPU节流,3次“搜索唯一合同并等待匹配数更新”观测:
188
+
189
+ | 模式 | 合同数 | 初始实际tbody行 | 搜索端到端观测(ms) |
190
+ | --- | ---: | ---: | --- |
191
+ | 普通分页 | 120 | 20 | 314 / 340 / 310 |
192
+ | 普通虚拟 | 5,000 | 19 | 321 / 311 / 313 |
193
+ | 合并、每合同3产品、每页20合同 | 5,000 | 60 | 315 / 337 / 343 |
194
+
195
+ 这些时间包含MRT输入的250ms防抖、自动化操作及等待,不能当作纯筛选CPU时间或正式基准。记录位于忽略产物 `artifacts/mrt-qa/performance-review.json`。未测真实网络、低端机、内存峰值及滚动帧率;本次没有足够证据宣称已出现计算瓶颈。
196
+
197
+ 优先级判断:
198
+
199
+ 1. 正式接入优先页面懒加载:当前完整样例JS gzip约381KB,不能让所有业务页面首屏都承担此成本。
200
+ 2. 更大数据量优先服务端筛选/排序/分页:虚拟化只减少DOM,5,000条仍在浏览器内参与过滤。没有测量依据时不规定统一行数阈值。
201
+ 3. 合并模式的DOM规模为当前页产品数之和。每合同3产品时受控,但单份合同数百产品会放大渲染,届时优先展开详情并对明细分页。
202
+ 4. 公共DataTable已有行级memo、稳定选择回调和排序结果缓存,排序键每行预取一次;不能用“全部重写”代替分页。调用方应保持rows/columns引用稳定,重型单元格需单独分析。
203
+ 5. MRT样例的自定义合并body会在表格状态更新时遍历当前页,尚未做逐合同渲染隔离;当前60行没有测出明显恶化,不宜直接打开全表memo以牺牲列拖动/缩放等响应。后续复杂产品单元格先用Profiler定位再优化。
204
+
205
+ 公共DataTable相关三个测试文件共24项通过,MRT样例14项浏览器回归、类型和构建通过。本轮未改公共DataTable的性能实现;搜索记忆仅在搜索状态改变时写入小对象,不随单纯勾选触发写入。
package/docs/release.md CHANGED
@@ -1,32 +1,33 @@
1
- # 内部发布流程
2
-
3
- ## 发布位置与权限
4
-
5
- - Git 仓库:`https://github.com/jc-times/business-ui`
6
- - npm registry:GitHub Packages,`https://npm.pkg.github.com`
7
- - npm 包:`@jc-times/business-ui`
8
- - Release workflow 仅授予 `contents: read` 和 `packages: write`。
9
- - 发布使用 GitHub Actions 自动提供的仓库级 `GITHUB_TOKEN`,无需创建或保存长期 `NPM_TOKEN`。
10
-
11
- 仓库不会保存令牌或带令牌的 `.npmrc`。发布脚本只在执行期间创建临时配置,并在成功或失败后删除。消费私有包所需的 `read:packages` 凭据由各消费仓库或开发者环境分别管理。
12
-
13
- ## 发布规则
14
-
15
- 1. 更新 `package.json` 版本和 `CHANGELOG.md`。
16
- 2. 合并到 `main`,等待 CI 的类型检查、测试、构建和打包全部通过。
17
- 3. 在已验证的提交上创建并推送注释标签 `v<package.version>`。
18
- 4. Release workflow 再次执行完整验证,校验标签与包版本完全一致后发布。
19
- 5. 消费项目以精确版本安装,并在各自仓库提交 lockfile;不使用 `latest`、范围版本或源码路径。
20
-
21
- `workflow_dispatch` 只用于重试同一标签的失败任务;普通分支或无匹配标签的提交会被发布脚本拒绝。
22
-
23
- ## 本地安全演练
24
-
25
- 不设置真实令牌时,可验证拒绝路径:
26
-
27
- ```powershell
28
- $env:NPM_REGISTRY_URL = "https://npm.pkg.github.com"
29
- pnpm publish:release
30
- ```
31
-
32
- 脚本应在发布前因缺少 `NPM_TOKEN` 或标签不匹配而退出。不要把真实令牌写入命令历史、仓库文件或文档。
1
+ # npm 公共发布流程
2
+
3
+ ## 发布位置与权限
4
+
5
+ - Git 仓库:`https://github.com/jc-times/business-ui`
6
+ - npm registry:npmjs,`https://registry.npmjs.org`
7
+ - npm 包:`@jc-times/business-ui`
8
+ - Release workflow 仅授予 `contents: read`。
9
+ - 发布使用仓库 Actions secret `NPM_TOKEN`;令牌限定为 `@jc-times/business-ui` 的发布权限,并由 npm 侧管理有效期与 2FA 绕过策略。
10
+ - 标签发布会先安装 Chromium 并运行完整浏览器回归,再由发布脚本执行类型、单测、构建和打包门禁。
11
+
12
+ 仓库不会保存令牌或带令牌的 `.npmrc`。发布脚本只在执行期间创建临时配置,并在成功或失败后删除。
13
+
14
+ ## 发布规则
15
+
16
+ 1. 更新 `package.json` 版本和 `CHANGELOG.md`。
17
+ 2. 合并到 `main`,等待 CI 的类型检查、测试、构建和打包全部通过。
18
+ 3. 在已验证的提交上创建并推送注释标签 `v<package.version>`。
19
+ 4. Release workflow 再次执行完整验证,校验标签与包版本完全一致后发布。
20
+ 5. 消费项目以精确版本安装,并在各自仓库提交 lockfile;不使用 `latest`、范围版本或源码路径。
21
+
22
+ `workflow_dispatch` 只用于重试同一标签的失败任务;普通分支或无匹配标签的提交会被发布脚本拒绝。
23
+
24
+ ## 本地安全演练
25
+
26
+ 不设置真实令牌时,可验证拒绝路径:
27
+
28
+ ```powershell
29
+ $env:NPM_REGISTRY_URL = "https://registry.npmjs.org"
30
+ pnpm publish:release
31
+ ```
32
+
33
+ 脚本应在发布前因缺少 `NPM_TOKEN` 或标签不匹配而退出。不要把真实令牌写入命令历史、仓库文件或文档。
@@ -0,0 +1,43 @@
1
+ # 拖动排序与跨区块移动
2
+
3
+ 空列表与移动上下文从 0.2.54 起提供;0.2.55 补齐空列表接收区和高亮样式。消费方仍应核对实际安装版本的类型声明。
4
+
5
+ ## 场景与接口
6
+
7
+ - 同列表排序沿用 `onReorder(items)`。
8
+ - 同一编辑范围共享 `useSortableTransferScope<T>(ownerKey)`;不同范围不接收彼此的拖动。ownerKey 使用稳定的业务身份。
9
+ - 各列表可传稳定的 `listId: string | number`。它用于回调上下文,不代替 scope 隔离;省略时对应上下文字段为 undefined。
10
+ - `onDropOnItem(moving, target, context)`:放到目标项上。
11
+ - `onDropBetweenItems(moving, target, position, context)`:跨列表插入,position 为 before/after。
12
+ - `onDropOnList(moving, context)`:放到集合本身,包括空列表;配合 `canDropOnList(moving)` 限制接收。
13
+ - `context: SortableMoveContext` 包含 `sourceListId`、`targetListId`。原有少参数回调无需修改。
14
+ - `renderEmptyState()` 自定义空状态;默认根据是否可接收显示提示。插入位置、来源占位和目标高亮沿用公共主题。
15
+
16
+ 根区域落点不承诺插入位置,由消费方选择追加或其他规则。需要精确位置时用 before/after。未配置回调的落点不接收拖动。
17
+
18
+ ```tsx
19
+ const scope = useSortableTransferScope<Row>(documentId);
20
+ // 来源列表也传同一 scope,以及自己的 listId。
21
+ <SortableList
22
+ aria-label="待办区" listId="todo" transferScope={scope}
23
+ items={rows} getKey={row => row.id} getTextValue={row => row.title}
24
+ renderItem={row => <Card row={row} />} onReorder={setRows}
25
+ onDropOnList={(moving, { sourceListId, targetListId }) => {
26
+ // 通过一次状态更新同时移除来源并添加到目标,持久化由应用处理。
27
+ moveRows(moving, sourceListId, targetListId);
28
+ }}
29
+ />
30
+ ```
31
+
32
+ ## 状态与约束
33
+
34
+ - `disabled` 仅禁用拖放,不卸载列表和卡片,也不禁用卡片中的业务表单。手柄隐藏,但保持拖放 hooks 结构稳定,避免 hook 数量变化和草稿丢失。
35
+ - 同一 scope 内 key 必须唯一,items 更新必须提供新数组;移动项沿来源顺序返回。
36
+ - 拖动过程中保留来源数据;来源删除、禁用、卸载或 ownerKey 改变后不提交旧拖动。目标卸载、目标禁用、键歧义和取消均不提交;一次跨列表拖动只消费一次。
37
+ - 卡片在跨列表移动时的局部状态保留不在本组件承诺内;需跨容器保留的草稿由消费方受控保存。
38
+ - 建立每列表 key 索引供拖动判定使用,避免每次 hover 遍历全部行;scope 歧义检查仍随列表数量增长,不等于已支持虚拟化。
39
+
40
+ ## 验证
41
+
42
+ `src/SortableList.transfer.test.tsx` 覆盖失效来源/目标、重复键、scope 更换、取消、上下文与 2000 行/500 次 hover 的 key 访问计数。
43
+ `e2e/sortable-drop.spec.ts` 覆盖真实浏览器键盘/鼠标投放、空列表、禁用切换时输入节点/草稿/焦点保留及五档视口;手机项目为模拟视口,不替代实机触屏。
@@ -1,6 +1,12 @@
1
- # 发布前多视口验收
2
-
3
- ## 2026-09-18 — 人员资料卡
1
+ # 发布前多视口验收
2
+
3
+ ## 2026-09-19 — 0.2.55 修复候选
4
+
5
+ - 30 个测试文件、158 项单测、TypeScript、组件库构建、按需门禁和视觉矩阵构建通过。
6
+ - Chromium Desktop 与 Pixel 7 项目共 6 项针对性回归通过:PDF 连续阅读的搜索后收起/重开会清除旧结果,隐藏内置工具栏时搜索保持可用;SortableList 空列表在五档视口保持至少 80px 接收区并可完成指针投放。
7
+ - 移动端结果为浏览器模拟;真实触屏惯性滚动和双指缩放仍需真机验收。
8
+
9
+ ## 2026-09-18 — 人员资料卡
4
10
 
5
11
  - Chromium Desktop Chrome 与 Pixel 7 模拟共 4 项:人员标签打开只读资料卡,长部门路径可见,弹层位于视口内、页面无横向溢出;Escape 关闭后焦点返回标签。包含 320px 窄屏检查;默认宽度随视口按 300–560px 缩放。
6
12
 
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 CloudPDF
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 CloudPDF
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.