@done-coding/admin-core 0.29.0 → 0.29.1-alpha.0

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.
Files changed (86) hide show
  1. package/es/bridge/layout.mjs +31 -2
  2. package/es/components/app-layout/AppAside.vue.mjs +1 -1
  3. package/es/components/app-layout/AppCollapseToggle.vue.mjs +1 -1
  4. package/es/components/app-layout/AppFooter.vue.mjs +1 -1
  5. package/es/components/app-layout/AppHeader.vue.mjs +1 -1
  6. package/es/components/app-layout/AppHeader.vue2.mjs +1 -1
  7. package/es/components/app-layout/AppSidebar.vue.mjs +1 -1
  8. package/es/components/app-layout/AppSidebar.vue2.mjs +60 -34
  9. package/es/components/data-view/DataGridView.vue.mjs +1 -1
  10. package/es/components/data-view/DataGridView.vue2.mjs +30 -6
  11. package/es/components/data-view/DataListView.vue.mjs +1 -1
  12. package/es/components/data-view/DataListView.vue2.mjs +38 -14
  13. package/es/components/data-view/DataListViewItem.vue.mjs +1 -1
  14. package/es/components/data-view/DataListViewItem.vue2.mjs +23 -4
  15. package/es/components/data-view/InfiniteListView.vue.mjs +1 -1
  16. package/es/components/data-view/InfiniteListView.vue2.mjs +9 -3
  17. package/es/components/data-view/use-grid-layout.mjs +46 -0
  18. package/es/components/data-view/use-masonry.mjs +65 -0
  19. package/es/components/display/BadgeMark.vue.mjs +1 -1
  20. package/es/components/display/BadgeMark.vue2.mjs +11 -3
  21. package/es/components/display/HeightProvider.vue.mjs +17 -3
  22. package/es/components/display/use-badge.mjs +22 -13
  23. package/es/components/form/use-upload-state.mjs +33 -11
  24. package/es/components/page-layout/AppPageDetail.vue.mjs +1 -1
  25. package/es/components/page-layout/AppPageDetail.vue2.mjs +12 -2
  26. package/es/components/page-layout/AppPageListDetailLayout.vue.mjs +11 -4
  27. package/es/components/page-layout/AppPageListDetailSheet.vue.mjs +8 -1
  28. package/es/components/page-layout/AppPageListDetailSplit.vue.mjs +1 -1
  29. package/es/components/page-layout/AppPageListDetailSplit.vue2.mjs +8 -1
  30. package/es/components/table/TableMain.vue.mjs +1 -1
  31. package/es/components/table/TableMain.vue2.mjs +8 -5
  32. package/es/components/view-layout/ViewLayout.vue.mjs +1 -1
  33. package/es/components/view-layout/ViewLayout.vue2.mjs +68 -20
  34. package/es/hooks/use-surface.mjs +4 -1
  35. package/es/hooks/use-theme-apply.mjs +78 -0
  36. package/es/index.mjs +118 -120
  37. package/es/store/app.mjs +25 -0
  38. package/es/style.css +120 -95
  39. package/package.json +2 -2
  40. package/src/bridge/docs/README.md +31 -0
  41. package/src/components/app-layout/docs/README-AppAside.md +11 -0
  42. package/src/components/app-layout/docs/README-AppFooter.md +11 -1
  43. package/src/components/app-layout/docs/README-AppHeader.md +16 -0
  44. package/src/components/app-layout/docs/README-AppSidebar.md +18 -0
  45. package/src/components/data-view/README.md +2 -1
  46. package/src/components/data-view/docs/README-DataGridView.md +21 -1
  47. package/src/components/data-view/docs/README-DataListView.md +65 -3
  48. package/src/components/data-view/docs/README-InfiniteListView.md +17 -0
  49. package/src/components/display/README.md +1 -1
  50. package/src/components/display/docs/README-BadgeMark.md +52 -10
  51. package/src/components/display/docs/README-HeightProvider.md +14 -8
  52. package/src/components/form/docs/README-FormUpload.md +79 -0
  53. package/src/components/form/docs/README-FormUploadImage.md +19 -0
  54. package/src/components/form/docs/README-FormUploadVideo.md +19 -0
  55. package/src/components/page-layout/README.md +15 -0
  56. package/src/components/page-layout/docs/README-AppPageDetail.md +3 -0
  57. package/src/components/page-layout/docs/README-AppPageListDetailLayout.md +33 -0
  58. package/src/components/table/docs/README-TableMain.md +17 -0
  59. package/src/components/view-layout/README.md +2 -2
  60. package/src/components/view-layout/docs/README-ViewLayout.md +97 -6
  61. package/types/bridge/badge.d.ts +3 -1
  62. package/types/bridge/layout.d.ts +42 -5
  63. package/types/components/app-layout/AppSidebar.vue.d.ts +286 -2
  64. package/types/components/app-layout/types.d.ts +1 -1
  65. package/types/components/data-view/DataListViewItem.vue.d.ts +12 -7
  66. package/types/components/data-view/types.d.ts +76 -0
  67. package/types/components/data-view/use-grid-layout.d.ts +42 -0
  68. package/types/components/data-view/use-masonry.d.ts +44 -0
  69. package/types/components/display/BadgeMark.vue.d.ts +5 -5
  70. package/types/components/display/HeightProvider.vue.d.ts +1 -0
  71. package/types/components/display/use-badge.d.ts +6 -0
  72. package/types/components/page-layout/AppPageDetail.vue.d.ts +18 -0
  73. package/types/components/page-layout/AppPageListDetailLayout.vue.d.ts +20 -0
  74. package/types/components/page-layout/AppPageListDetailSheet.vue.d.ts +4 -0
  75. package/types/components/page-layout/AppPageListDetailSplit.vue.d.ts +4 -0
  76. package/types/components/table/types.d.ts +8 -0
  77. package/types/components/view-layout/ViewLayout.vue.d.ts +30 -0
  78. package/types/components/view-layout/types.d.ts +12 -0
  79. package/types/hooks/use-surface.d.ts +11 -0
  80. package/types/index.d.ts +0 -1
  81. package/types/injectInfo.json.d.ts +1 -1
  82. package/es/components/icon/IconHammer.vue.mjs +0 -26
  83. package/es/components/icon/IconHammer.vue2.mjs +0 -4
  84. package/src/components/icon/README.md +0 -38
  85. package/types/components/icon/IconHammer.vue.d.ts +0 -2
  86. package/types/components/icon/index.d.ts +0 -7
@@ -1,10 +1,10 @@
1
1
  # view-layout 展示布局族
2
2
 
3
- 展示空间布局壳:`ViewLayout` 消费 `props.api`(内部 `useActivated` 激活拉取)+ toolbar 对齐 `TableToolbar`(左/右 `ActionBtnGroup` extra 按钮 + 右侧 `AutoRefreshGroup` 自动刷新 / 手动刷新)+ 默认插槽自由内容。
3
+ 展示空间布局壳:`ViewLayout` 消费 `props.api`(内部 `useActivated` 激活拉取)+ toolbar 对齐 `TableToolbar`(左/右 `ActionBtnGroup` extra 按钮 + 右侧 `AutoRefreshGroup` 自动刷新 / 手动刷新)+ 默认插槽自由内容 + `#bottom` 底部区(refine 固定在底 / 自然流平铺在后)。
4
4
 
5
5
  ## 组件文档(docs/)
6
6
 
7
- - [ViewLayout](./docs/README-ViewLayout.md) — 展示布局(api 拉取 + 自动刷新 + 自由内容插槽)
7
+ - [ViewLayout](./docs/README-ViewLayout.md) — 展示布局(api 拉取 + 自动刷新 + 自由内容插槽 + `#bottom` 底部区)
8
8
 
9
9
  ## 范式页(apps/reference)
10
10
 
@@ -1,6 +1,6 @@
1
1
  # ViewLayout(展示布局)
2
2
 
3
- > 展示空间布局壳:`props.api` 数据拉取(内部 `useActivated` 激活拉取)+ toolbar 对齐 `TableToolbar`(左/右 `ActionBtnGroup` extra 按钮 + 右侧 `AutoRefreshGroup` 自动刷新 / 手动刷新)+ 默认插槽自由内容 + 精细流高度链(refine 上下文默认:AppPage#default / TabsMain 页签内容内开)。
3
+ > 展示空间布局壳:`props.api` 数据拉取(内部 `useActivated` 激活拉取)+ toolbar 对齐 `TableToolbar`(左/右 `ActionBtnGroup` extra 按钮 + 右侧 `AutoRefreshGroup` 自动刷新 / 手动刷新)+ 默认插槽自由内容 + `#bottom` 底部区 + 精细流高度链(refine 上下文默认:AppPage#default / TabsMain 页签内容内开)。
4
4
  > 范式页:`apps/reference/src/pages/view-layout/guide/`
5
5
 
6
6
  ## 定位
@@ -8,7 +8,7 @@
8
8
  - **空间一等公民**:展示空间布局首选(页级数据展示的布局壳)——承接 PanelMain 废弃的页级展示场景
9
9
  - **何时用**:页级数据展示(详情 / 预览 / 摘要展示)——api 拉数 + 自动刷新 + 内容自由编排
10
10
  - **何时不用**:结构化详情字段面板用 `PanelMain`(仅表单预览 / 就地编辑保留场景);列表用 `ListLayout`
11
- - 内部组合:`ActionBtnGroup`(左/右 extra 按钮,`default-size="small"` 对齐 table-toolbar 视觉惯例)+ `AutoRefreshGroup`(右侧,refreshFn=api 拉取,经 `HeightProvider` #header 槽 WatchSize 量高)+ 默认插槽(`{ data, loading, refresh, viewportHeight, fetchSeq }` 注入)
11
+ - 内部组合:`ActionBtnGroup`(左/右 extra 按钮,`default-size="small"` 对齐 table-toolbar 视觉惯例)+ `AutoRefreshGroup`(右侧,refreshFn=api 拉取,toolbar `HeightProvider` #header 槽 WatchSize 量高)+ 默认插槽(`{ data, loading, refresh, viewportHeight, fetchSeq }` 注入)+ `#bottom` 底部区(精细流进 `HeightProvider` #footer 槽,同样量高扣减)
12
12
 
13
13
  ## 快速上手(最小可用)
14
14
 
@@ -29,7 +29,7 @@
29
29
  - 激活即拉取:首访 mounted / KeepAlive 重新激活自动拉取,失活不拉(数据保留)
30
30
  - 右上角 AutoRefreshGroup 自动接管刷新按钮 / 自动刷新开关(`showAutoRefresh` / `showRefresh` 控制显隐)
31
31
  - toolbar 对齐 `TableToolbar` 结构:`leftExtraButtons` / `rightExtraButtons`(`ActionBtnGroup` 配置,`default-size="small"`)左右分栏;不含表格特有能力(导出 / 批量下载 / 视图切换)
32
- - **refine 上下文默认**:置于 AppPage `#default` / TabsMain 页签内容内默认开(精细流)——内容区可用高 = 视口高 − toolbar 高(`scope.viewportHeight` + 容器 max-height 双出口)——超高内滚;其余容器 / 独立使用回落自然流(按自身尺寸)
32
+ - **refine 上下文默认**:置于 AppPage `#default` / TabsMain 页签内容内默认开(精细流)——内容区可用高 = 视口高 − toolbar 高 − `#bottom` 高 − 内容区自身纵向 padding(`scope.viewportHeight` + 容器 max-height 双出口)——超高内滚;其余容器 / 独立使用回落自然流(按自身尺寸)
33
33
 
34
34
  ## 能力边界 / 按需使用
35
35
 
@@ -39,6 +39,7 @@
39
39
  - `params`:仅当 api 需要拉取参数时传;⚠️ **响应式变化不自动重拉**(需要时调 `scope.refresh()`)。
40
40
  - `showAutoRefresh` / `showRefresh`:仅当不需要自动刷新或手动刷新时关。
41
41
  - `leftExtraButtons` / `rightExtraButtons`:仅当 toolbar 需要业务操作按钮时配——配置为 `ActionBtnGroup` 单项(`key` / `label` / `actionBtnProps` / `render` / `show`),ctx 注入 `{ loading, refresh }`(刷新与右上角同源);按钮默认 `size="small"` 对齐 table-toolbar。
42
+ - **`#bottom`(底部区):不传即完全不存在。** 传了才渲染([MUST NOT] 传空 `<template>` 占位)——精细流下它**固定在底部、不随内容滚**,自然流下**平铺在内容之后**。典型用途:合计行 / 固定操作条 / 状态摘要。
42
43
  - **插槽内容自由编排**:纯展示 [MUST NOT] 套 PanelMain 作页级根(已废弃场景);需要结构化字段面板时在插槽内用 PanelMain,自由内容直接写。
43
44
  - **完整能力演示**:`apps/reference/src/pages/view-layout/guide/`——能力展示,非推荐默认。
44
45
 
@@ -80,10 +81,93 @@
80
81
 
81
82
  **toolbar 是「条」(bar) 不是「卡」(card)**(甲方 2026-09-16 定性):底色取「面与底的中点」
82
83
  (`color-mix(in srgb, --dc-core-surface 50%, --dc-core-ground)`,亮暗自动跟随),
83
- 但守三条纪律 —— **贴边**(零左右呼吸,否则按钮与下方内容区左边界错位,而内容区的面由
84
- 消费方自持、padding 不受本组件控制)· **通栏**(零圆角)· **不加高**(只留既有的 8px 下呼吸)。
84
+ 但守两条纪律 —— **通栏**(零圆角)· **不加高**(零上下呼吸)。
85
85
  此前「工具条成卡」被否的根因不是「有面」,而是面顺带塞进 12px 内呼吸把 32px 的条撑到 56px。
86
86
 
87
+ 横向呼吸**左右不对称**:左 **两份**、右 **一份** —— 左缘那条 3px 主色条已经占住了第一层留白,
88
+ 不补第二份的话文字读起来像贴着色条(实测只剩 5px)。
89
+
90
+ 🔴 **左缘那两份是 toolbar 与内容区\*\*共用\*\*的一个值**(源码 `padLeftPx`),[MUST NOT] 只给 toolbar 加倍:
91
+ 色条标识的是**整个组件的左缘**、不是 toolbar 一个人的,只给它加倍会让**标题比正文右移一份**
92
+ (实测错开 8px,甲方 2026-09-17 排查色条内外侧时撞出)。标题与正文左对齐是排版底线,
93
+ [MUST NOT] 为装饰破坏它。内容区因此左右不对称(左两份 / 右一份),这是**有据的**:
94
+ 左缘有标识、右缘没有。
95
+
96
+ ## 底部区(`#bottom`)
97
+
98
+ ```vue
99
+ <ViewLayout :api="api" title="订单详情">
100
+ <template #default="{ data }">…长内容…</template>
101
+ <!-- refine:固定在底部,内容再长也压不到它;自然流:跟在内容之后 -->
102
+ <template #bottom="{ data, loading }">
103
+ <ElButton type="primary" :loading="loading">保存</ElButton>
104
+ </template>
105
+ </ViewLayout>
106
+ ```
107
+
108
+ | 档 | 行为 |
109
+ | --- | --- |
110
+ | `refine` 开(精细流) | **固定在底部** —— 进 `HeightProvider` 的 `#footer` 槽,经 `WatchSize` 量高并从内容区可用高里扣掉,内容再长也不滚走。要它**贴容器底**(内容稀疏时也不浮在半空)再开 `fillHeight`(见下) |
111
+ | `refine` 关(自然流) | **平铺在底部** —— 跟在内容之后按自身尺寸排布,无固定定位 |
112
+
113
+ - scope:`{ data, loading, fetchSeq }`(底部区常要跟着详情数据走,而这三者都在 setup 里取不到)。
114
+ 比 `#header` 多一个 `fetchSeq` —— 底部区是**放操作条**的地方,提交后常要判「详情真的重拉成功了」
115
+ (失败不递增,[MUST NOT] 用 `loading` 的 `true→false` 代替);也让
116
+ `AppPageListDetailLayout` 的 `#detailBottom` 能原样复用 `#detail` 那份 scope、
117
+ [MUST NOT] 为凑类型编一个恒 0 的假值。
118
+ - **不传 = 不渲染**:[MUST NOT] 留空盒——那会白占一段 reserve(精细流下内容区凭空少一截)。
119
+ - 🔴 **随内容滚的尾部内容 [MUST NOT] 放这里**:凡进 `#bottom` 的都从可用高里扣。要跟着滚就写在默认插槽末尾。
120
+ - 本槽**不自带面 / 不自带呼吸**:它与内容区之间的间隔由内容区自己的下 padding 给出(见下),装什么面由使用方决定。
121
+ - **自然流下它只是「排在内容之后」**,没有底可贴(那一档本就没有高度预算)。
122
+
123
+ ## 间距归属(谁给的呼吸)
124
+
125
+ | 段 | 归属 | 值 |
126
+ | --- | --- | --- |
127
+ | toolbar ↔ 内容 | **内容区的上 padding** | 一份 |
128
+ | 内容区上 / 下 / 右 | 内容区自己的 padding(`box-sizing: border-box`) | 一份 |
129
+ | **组件左缘**(toolbar 与内容区**共用**一个值 `padLeftPx`) | 两者各自的左 padding | **两份**(色条占了第一层) |
130
+ | toolbar 右侧 | toolbar 的右 padding | 一份 |
131
+
132
+ 「一份」= 间距阶梯的**模块档**(`APP_LAYOUT_GAP_CONFIG.size` × 密度系数 × 1,默认 **8px**),
133
+ 随 `bridge.APP_LAYOUT_GAP_CONFIG.size` 与主题密度档自动缩放,[MUST NOT] 在消费侧写死像素补偿。
134
+
135
+ 🔴 **为什么间隔一律做成「各自盒内的 padding」,[MUST NOT] 用根的 flex `gap` / `margin`**:
136
+ 精细流的 reserve 是量 toolbar 的 `clientHeight` 得出的,而 `gap` 跨在两个盒**之间**、
137
+ `margin` 会穿透父盒 —— 两者都不计入 `clientHeight`,量不到 ⇒ **每页恒溢出一段**
138
+ (实测 846 的可用高被占到 854,甲方报障过)。
139
+
140
+ ⚠️ 内容区的纵向 padding **在喂给 `HeightProvider` 之前就先扣掉了**,故 `scope.viewportHeight`
141
+ 与向后代 provide 的可用高**恒等于内容盒真正的内高**——嵌套 `ListLayout` / `TabsMain` 直接吃它即可,
142
+ [MUST NOT] 再自行减一遍 padding(那是双扣)。
143
+
144
+ ## `fillHeight` —— 让 `#bottom` 贴容器底(opt-in)
145
+
146
+ 内容盒默认只有 **`max-height` 上限**:内容多短盒子就多矮,于是内容稀疏时 `#bottom` 会
147
+ **跟在内容屁股后面浮在半空**(它没滚走,只是没贴底)。开 `fillHeight` 额外补一条同值
148
+ `min-height` ⇒ 上下界重合 = 定高,底边恒落在预算下沿(抽屉里就是抽屉底、页面里就是内容视口底)。
149
+
150
+ ```vue
151
+ <!-- 详情页底部要钉一条提交栏 -->
152
+ <ViewLayout :api="api" fill-height>
153
+ <template #default>…可能很短的内容…</template>
154
+ <template #bottom><ElButton type="primary">提交</ElButton></template>
155
+ </ViewLayout>
156
+ ```
157
+
158
+ | | 内容短 | 内容长 |
159
+ | --- | --- | --- |
160
+ | 默认(关) | 盒子矮,`#bottom` 跟在内容后 | 盒内滚,`#bottom` 停在预算下沿 |
161
+ | `fillHeight` 开 | **盒子占满预算,`#bottom` 贴底** | 同左(长内容下两者无差别) |
162
+
163
+ - **默认关,且 [MUST] 保持 opt-in**:定高的一体两面是「内容短时盒内留白」。
164
+ [MUST NOT] 改成默认开、更 [MUST NOT] 把 `max-height` 直接换成 `height` ——
165
+ 那会让**所有** refine 页面一起定高(甲方 2026-09-17:不应波及其他 refine 页面)。
166
+ - 仅 `refine=true` 有意义;自然流没有高度预算,本 prop 无声忽略。
167
+ - 同名同义于 `TableMain.fillHeight`(那边是让分页器被顶到容器底),两处认同一套心智。
168
+ - `AppPageListDetailLayout` 的 `#detailBottom` **自动开**(用了那个槽就是要贴底),
169
+ 仍可经 `viewLayoutProps.fillHeight` 关掉。
170
+
87
171
  ## API
88
172
  > ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
89
173
 
@@ -99,6 +183,7 @@
99
183
  | `channel` | `string?` | — | 作为父时的 scope 标识。⚠️ 与 parentChannel 均 [MUST NOT] 响应式变更(setup 期快照);且仅 refine=true 路径生效 |
100
184
  | `parentChannel` | `string?` | — | 作为子时定向消费的祖先 scope 标识(沿对象链 parent 找匹配) |
101
185
  | `minHeight` | `number?` | `100` | 内容区可用高兜底下限(对齐 ListLayout/TabsMain 惯例) |
186
+ | `fillHeight` | `boolean?` | `false` | 内容盒撑满可用高(额外补同值 `min-height` = 定高)。用途 = 让 `#bottom` **贴容器底**;仅 `refine` 下有意义。同名同义于 `TableMain.fillHeight` |
102
187
  | `showAutoRefresh` | `boolean?` | `true` | 是否显示自动刷新开关(透传 AutoRefreshGroup) |
103
188
  | `showRefresh` | `boolean?` | `true` | 是否显示手动刷新按钮(透传 AutoRefreshGroup) |
104
189
  | `showNavigation` | `boolean?` | `true` | 是否显示内置「上一条 / 下一条」导航。⚠️ **真正的显隐判据是可选 inject 探测**:只有置于 `AppPageListDetailLayout` 内才渲染,单独使用 ViewLayout 时无论本值为何都不渲染(老用法零变化);本 prop 用于在门面内显式关掉 |
@@ -109,7 +194,9 @@
109
194
 
110
195
  | 槽 | scope | 语义 |
111
196
  | --- | --- | --- |
112
- | 默认 | `{ data, loading, refresh, viewportHeight, fetchSeq }`(`ViewLayoutScope<R>`) | 展示内容;PanelMain 或自由编排皆可;viewportHeight refine 时给可用高、自然流 undefined;`fetchSeq` = **成功**拉取次数(失败不递增),供下游懒加载块判「该重拉了」 |
197
+ | 默认 | `{ data, loading, refresh, viewportHeight, fetchSeq }`(`ViewLayoutScope<R>`) | 展示内容;PanelMain 或自由编排皆可;viewportHeight refine 时给可用高(**已扣内容区自身 padding**)、自然流 undefined;`fetchSeq` = **成功**拉取次数(失败不递增),供下游懒加载块判「该重拉了」 |
198
+ | `#header` | `{ data, loading }` | 标题行(见上「标题行」段);不传且无 `title` 时不渲染 |
199
+ | `#bottom` | `{ data, loading, fetchSeq }` | 底部区:refine 固定在底部(计入 reserve)/ 自然流平铺在内容之后;不传不渲染。比 `#header` 多 `fetchSeq`(本槽放操作条,提交后要判「真的重拉成功了」) |
113
200
 
114
201
  ### 内置上/下一条导航(仅列表详情范式内出现)
115
202
 
@@ -133,6 +220,10 @@
133
220
  - **要重拉不要改 `params` 指望它自动生效**:`params` 响应式变化**刻意**不重拉(防请求风暴的既有设计)。「换了参数要重拉」= 改 `params` **并**动 `refreshToken`(或调 `scope.refresh()`)
134
221
  - **[MUST NOT] 把触发值塞进 `params` 当刷新开关**:那会把纯前端的令牌发给后端、污染 API 契约——这正是 `refreshToken` 独立成 prop 的原因
135
222
  - **[MUST NOT] 用 `:key="token"` 重建来实现重拉**:会连 toolbar / 按钮一起重建,连续切换时闪烁,且语义错位(chrome 不该随内容重建)——用 `refreshToken`
223
+ - **把随内容滚的东西塞进 `#bottom`**:[MUST NOT]——它是固定区,凡进此槽的都从内容可用高里扣
224
+ - **指望 `#bottom` 默认就贴容器底**:默认不贴(内容盒只有上限、不定高)——要贴底开 `fillHeight`
225
+ - **为了贴底把 `max-height` 改写成 `height`**:[MUST NOT]——那波及所有 refine 页面,是本 prop 存在的理由掉
226
+ - **在消费侧写死像素补偿 toolbar / 内容区的间距**:[MUST NOT]——间距由 gap 阶梯派生,写死会在改 `gap` / 换密度档时脱钩
136
227
  - **toolbar 不含表格能力全集**:对齐的是 table-toolbar 的**结构与视觉惯例**(左右分栏 + extra 按钮 + AutoRefreshGroup),[MUST NOT] 期待导出 / 批量下载 / 视图切换等表格特有能力出现在 ViewLayout——需要表格能力用 `ListLayout` / `TableMain`
137
228
 
138
229
  ## 关联
@@ -104,6 +104,8 @@ export type BadgeEntry = {
104
104
  kind: "beta";
105
105
  } | {
106
106
  kind: "wip";
107
+ } | {
108
+ kind: "planned";
107
109
  } | {
108
110
  kind: "deprecated";
109
111
  } | {
@@ -134,7 +136,7 @@ export type BadgeEntry = {
134
136
  type?: BadgeProps["type"];
135
137
  });
136
138
  /** 内置标(非 count / custom)的 kind 联合——文案与语义色由 core 统一定,保证跨 app 一致 */
137
- export type BadgeBuiltinKind = "new" | "updated" | "beta" | "wip" | "deprecated" | "locked";
139
+ export type BadgeBuiltinKind = "new" | "updated" | "beta" | "wip" | "planned" | "deprecated" | "locked";
138
140
  /**
139
141
  * 会遮挡宿主交互的 kind——[MUST] 与 `use-badge-mask` 的判据同源,[MUST NOT] 两处各写一份。
140
142
  *
@@ -33,6 +33,24 @@ export interface BridgeLayoutInit {
33
33
  /** aside 折叠初值(业务侧无缓存默认);缺省 false */
34
34
  defaultAsideCollapsed?: boolean;
35
35
  }
36
+ /**
37
+ * 侧栏菜单控制器 —— 由 `AppSidebar` 在挂载时注册进来的**接缝**。
38
+ *
39
+ * 🔴 bridge 是**纯状态**层、拿不到菜单组件实例,而「展开到某路径」必须调 `ElMenu.open()`。
40
+ * 故由持有实例的那一层注册能力进来,bridge 只做编排(同「auth facade 由 app 注册钩子」范式)。
41
+ * [MUST NOT] 反过来让 bridge 去 querySelector 菜单 DOM —— 那会把结构写死进状态层。
42
+ */
43
+ export interface CoreLayoutMenuController {
44
+ /** 展开一级子菜单(ElMenu 的 index = 路由 path) */
45
+ open: (index: string) => void;
46
+ /**
47
+ * 解析目标 path 的**沿途父级 path 链**(自顶向下)。
48
+ * path 不在菜单里 → `undefined`(与「在菜单里但没有父级」的空数组区分开)。
49
+ */
50
+ resolveAncestors: (path: string) => string[] | undefined;
51
+ /** 是否分组形态(`menuGroupMode`)——该形态父级是 section heading、本就全展开 */
52
+ isGroupMode: () => boolean;
53
+ }
36
54
  /**
37
55
  * 布局折叠模块(bridge 公开面 `bridge.layout`)。
38
56
  *
@@ -52,14 +70,33 @@ export interface CoreLayoutModule {
52
70
  setAsideCollapse: (collapsed: boolean) => void;
53
71
  /** 反转 aside 折叠态 */
54
72
  toggleAside: () => void;
73
+ /**
74
+ * 把目标路径**沿途的父级子菜单全部展开**,返回是否成功。
75
+ *
76
+ * 缘起:引导要高亮折叠子菜单里的项 —— 那种元素虽在 DOM 里但 `display:none`、rect 全 0,
77
+ * 引导只能跳过。判据是目标项 `getClientRects().length > 0`,[MUST NOT] 拿「没报错」当成功。
78
+ *
79
+ * 三种形态:
80
+ * - 常规树形 → 逐级 `open()` 沿途父级 → `true`;
81
+ * - 分组形态(`menuGroupMode`)→ 父级本就全展开 ⇒ **no-op 返回 `true`**;
82
+ * - **侧栏折叠态 → 先展开侧栏**(`setSidebarCollapse(false)`)再展开父级 → `true`。
83
+ *
84
+ * 🔴 折叠态自动展开侧栏是**甲方 2026-09-18 的裁决**,且**事后不还原**:折叠态是持久化到
85
+ * localStorage 的用户偏好,本方法等于程序化改写它 —— 依据是「引导是用户主动发起的流程,
86
+ * 为让他看见而展开属正当副作用」。[MUST NOT] 改成「展开后自动还原」:还原时机不可靠
87
+ * (引导弹窗还开着就还原会当场收起菜单),异常路径 / 快速切路由会让状态泄漏。
88
+ *
89
+ * 路径不存在 / 侧栏未注册(无侧栏)→ `false`,且**不动任何状态**。
90
+ */
91
+ openMenuTo: (path: string) => boolean;
92
+ /**
93
+ * 注册 / 注销侧栏菜单控制器(**内部接缝**,由 `AppSidebar` 调用)。
94
+ * 业务 [MUST NOT] 直接调它 —— 注册两份会让后注册的覆盖前一份。
95
+ */
96
+ registerMenuController: (controller: CoreLayoutMenuController | null) => void;
55
97
  }
56
98
  /** bridge 布局折叠 hook 工厂返回(聚合到 `bridge.layout`)。 */
57
99
  export interface BridgeLayoutHook {
58
100
  layout: CoreLayoutModule;
59
101
  }
60
- /**
61
- * bridge 布局折叠 hook 工厂。
62
- *
63
- * init:读持久化恢复 sidebar / aside 折叠态(无持久化值 → 回落初值)。
64
- */
65
102
  export declare function createBridgeLayoutHook(init: BridgeLayoutInit): BridgeLayoutHook;
@@ -13,13 +13,297 @@ declare function __VLS_template(): {
13
13
  top?(_: {}): any;
14
14
  bottom?(_: {}): any;
15
15
  };
16
- refs: {};
16
+ refs: {
17
+ menuTreeRef: import('vue').CreateComponentPublicInstanceWithMixins<Readonly<{
18
+ menus: RouteMetaResolveRaw[];
19
+ menuFlatList: RouteMetaResolveRaw[];
20
+ routerMode?: boolean;
21
+ collapse?: boolean;
22
+ autoClose?: boolean;
23
+ groupMode?: boolean;
24
+ }> & Readonly<{}>, {
25
+ open: (index: string) => void | undefined;
26
+ close: (index: string) => void | undefined;
27
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, import('vue').PublicProps, {}, false, {}, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, {
28
+ elMenu: import('vue').CreateComponentPublicInstanceWithMixins<Readonly<import('vue').ExtractPropTypes<{
29
+ readonly mode: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, "horizontal" | "vertical", unknown, "vertical", boolean>;
30
+ readonly defaultActive: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
31
+ readonly defaultOpeneds: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => string[]) | (() => string[]) | (((new (...args: any[]) => string[]) | (() => string[])) | null)[], unknown, unknown, () => [], boolean>;
32
+ readonly uniqueOpened: BooleanConstructor;
33
+ readonly router: BooleanConstructor;
34
+ readonly menuTrigger: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, "click" | "hover", unknown, "hover", boolean>;
35
+ readonly collapse: BooleanConstructor;
36
+ readonly backgroundColor: StringConstructor;
37
+ readonly textColor: StringConstructor;
38
+ readonly activeTextColor: StringConstructor;
39
+ readonly closeOnClickOutside: BooleanConstructor;
40
+ readonly collapseTransition: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
41
+ readonly ellipsis: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
42
+ readonly popperOffset: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 6, boolean>;
43
+ readonly ellipsisIcon: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component) | (((new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component)) | null)[], unknown, unknown, () => import('vue').DefineComponent<{}, void, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>, boolean>;
44
+ readonly popperEffect: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => string) | (() => import('element-plus').PopperEffect) | (((new (...args: any[]) => string) | (() => import('element-plus').PopperEffect)) | null)[], unknown, unknown, "dark", boolean>;
45
+ readonly popperClass: StringConstructor;
46
+ readonly popperStyle: {
47
+ readonly type: import('vue').PropType<import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => string | import('vue').CSSProperties) | (() => string | import('vue').CSSProperties) | (((new (...args: any[]) => string | import('vue').CSSProperties) | (() => string | import('vue').CSSProperties)) | null)[], unknown, unknown>>;
48
+ readonly required: false;
49
+ readonly validator: ((val: unknown) => boolean) | undefined;
50
+ __epPropKey: true;
51
+ };
52
+ readonly showTimeout: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 300, boolean>;
53
+ readonly hideTimeout: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 300, boolean>;
54
+ readonly persistent: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
55
+ }>> & Readonly<{
56
+ onClose?: ((index: string, indexPath: string[]) => any) | undefined;
57
+ onSelect?: ((index: string, indexPath: string[], item: import('element-plus').MenuItemClicked, routerResult?: Promise<void | import('vue-router').NavigationFailure> | undefined) => any) | undefined;
58
+ onOpen?: ((index: string, indexPath: string[]) => any) | undefined;
59
+ }>, () => import('vue').VNode<import('vue').RendererNode, import('vue').RendererElement, {
60
+ [key: string]: any;
61
+ }>, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
62
+ close: (index: string, indexPath: string[]) => boolean;
63
+ open: (index: string, indexPath: string[]) => boolean;
64
+ select: (index: string, indexPath: string[], item: import('element-plus').MenuItemClicked, routerResult?: Promise<void | import('vue-router').NavigationFailure>) => boolean;
65
+ }, import('vue').PublicProps, {
66
+ readonly collapse: boolean;
67
+ readonly ellipsis: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
68
+ readonly persistent: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
69
+ readonly mode: import('element-plus/es/utils/index.mjs').EpPropMergeType<StringConstructor, "horizontal" | "vertical", unknown>;
70
+ readonly showTimeout: number;
71
+ readonly hideTimeout: number;
72
+ readonly defaultActive: string;
73
+ readonly defaultOpeneds: string[];
74
+ readonly menuTrigger: import('element-plus/es/utils/index.mjs').EpPropMergeType<StringConstructor, "click" | "hover", unknown>;
75
+ readonly collapseTransition: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
76
+ readonly popperOffset: number;
77
+ readonly ellipsisIcon: import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component) | (((new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component)) | null)[], unknown, unknown>;
78
+ readonly popperEffect: import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => string) | (() => import('element-plus').PopperEffect) | (((new (...args: any[]) => string) | (() => import('element-plus').PopperEffect)) | null)[], unknown, unknown>;
79
+ readonly uniqueOpened: boolean;
80
+ readonly router: boolean;
81
+ readonly closeOnClickOutside: boolean;
82
+ }, true, {}, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, {}, any, import('vue').ComponentProvideOptions, {
83
+ P: {};
84
+ B: {};
85
+ D: {};
86
+ C: {};
87
+ M: {};
88
+ Defaults: {};
89
+ }, Readonly<import('vue').ExtractPropTypes<{
90
+ readonly mode: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, "horizontal" | "vertical", unknown, "vertical", boolean>;
91
+ readonly defaultActive: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
92
+ readonly defaultOpeneds: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => string[]) | (() => string[]) | (((new (...args: any[]) => string[]) | (() => string[])) | null)[], unknown, unknown, () => [], boolean>;
93
+ readonly uniqueOpened: BooleanConstructor;
94
+ readonly router: BooleanConstructor;
95
+ readonly menuTrigger: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, "click" | "hover", unknown, "hover", boolean>;
96
+ readonly collapse: BooleanConstructor;
97
+ readonly backgroundColor: StringConstructor;
98
+ readonly textColor: StringConstructor;
99
+ readonly activeTextColor: StringConstructor;
100
+ readonly closeOnClickOutside: BooleanConstructor;
101
+ readonly collapseTransition: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
102
+ readonly ellipsis: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
103
+ readonly popperOffset: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 6, boolean>;
104
+ readonly ellipsisIcon: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component) | (((new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component)) | null)[], unknown, unknown, () => import('vue').DefineComponent<{}, void, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>, boolean>;
105
+ readonly popperEffect: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => string) | (() => import('element-plus').PopperEffect) | (((new (...args: any[]) => string) | (() => import('element-plus').PopperEffect)) | null)[], unknown, unknown, "dark", boolean>;
106
+ readonly popperClass: StringConstructor;
107
+ readonly popperStyle: {
108
+ readonly type: import('vue').PropType<import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => string | import('vue').CSSProperties) | (() => string | import('vue').CSSProperties) | (((new (...args: any[]) => string | import('vue').CSSProperties) | (() => string | import('vue').CSSProperties)) | null)[], unknown, unknown>>;
109
+ readonly required: false;
110
+ readonly validator: ((val: unknown) => boolean) | undefined;
111
+ __epPropKey: true;
112
+ };
113
+ readonly showTimeout: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 300, boolean>;
114
+ readonly hideTimeout: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 300, boolean>;
115
+ readonly persistent: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
116
+ }>> & Readonly<{
117
+ onClose?: ((index: string, indexPath: string[]) => any) | undefined;
118
+ onSelect?: ((index: string, indexPath: string[], item: import('element-plus').MenuItemClicked, routerResult?: Promise<void | import('vue-router').NavigationFailure> | undefined) => any) | undefined;
119
+ onOpen?: ((index: string, indexPath: string[]) => any) | undefined;
120
+ }>, () => import('vue').VNode<import('vue').RendererNode, import('vue').RendererElement, {
121
+ [key: string]: any;
122
+ }>, {}, {}, {}, {
123
+ readonly collapse: boolean;
124
+ readonly ellipsis: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
125
+ readonly persistent: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
126
+ readonly mode: import('element-plus/es/utils/index.mjs').EpPropMergeType<StringConstructor, "horizontal" | "vertical", unknown>;
127
+ readonly showTimeout: number;
128
+ readonly hideTimeout: number;
129
+ readonly defaultActive: string;
130
+ readonly defaultOpeneds: string[];
131
+ readonly menuTrigger: import('element-plus/es/utils/index.mjs').EpPropMergeType<StringConstructor, "click" | "hover", unknown>;
132
+ readonly collapseTransition: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
133
+ readonly popperOffset: number;
134
+ readonly ellipsisIcon: import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component) | (((new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component)) | null)[], unknown, unknown>;
135
+ readonly popperEffect: import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => string) | (() => import('element-plus').PopperEffect) | (((new (...args: any[]) => string) | (() => import('element-plus').PopperEffect)) | null)[], unknown, unknown>;
136
+ readonly uniqueOpened: boolean;
137
+ readonly router: boolean;
138
+ readonly closeOnClickOutside: boolean;
139
+ }> | null;
140
+ }, any, import('vue').ComponentProvideOptions, {
141
+ P: {};
142
+ B: {};
143
+ D: {};
144
+ C: {};
145
+ M: {};
146
+ Defaults: {};
147
+ }, Readonly<{
148
+ menus: RouteMetaResolveRaw[];
149
+ menuFlatList: RouteMetaResolveRaw[];
150
+ routerMode?: boolean;
151
+ collapse?: boolean;
152
+ autoClose?: boolean;
153
+ groupMode?: boolean;
154
+ }> & Readonly<{}>, {
155
+ open: (index: string) => void | undefined;
156
+ close: (index: string) => void | undefined;
157
+ }, {}, {}, {}, {}> | null;
158
+ };
17
159
  rootEl: HTMLDivElement;
18
160
  };
19
161
  type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
20
162
  declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
21
163
  aboveHeader: boolean;
22
- }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
164
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
165
+ menuTreeRef: import('vue').CreateComponentPublicInstanceWithMixins<Readonly<{
166
+ menus: RouteMetaResolveRaw[];
167
+ menuFlatList: RouteMetaResolveRaw[];
168
+ routerMode?: boolean;
169
+ collapse?: boolean;
170
+ autoClose?: boolean;
171
+ groupMode?: boolean;
172
+ }> & Readonly<{}>, {
173
+ open: (index: string) => void | undefined;
174
+ close: (index: string) => void | undefined;
175
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, import('vue').PublicProps, {}, false, {}, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, {
176
+ elMenu: import('vue').CreateComponentPublicInstanceWithMixins<Readonly<import('vue').ExtractPropTypes<{
177
+ readonly mode: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, "horizontal" | "vertical", unknown, "vertical", boolean>;
178
+ readonly defaultActive: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
179
+ readonly defaultOpeneds: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => string[]) | (() => string[]) | (((new (...args: any[]) => string[]) | (() => string[])) | null)[], unknown, unknown, () => [], boolean>;
180
+ readonly uniqueOpened: BooleanConstructor;
181
+ readonly router: BooleanConstructor;
182
+ readonly menuTrigger: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, "click" | "hover", unknown, "hover", boolean>;
183
+ readonly collapse: BooleanConstructor;
184
+ readonly backgroundColor: StringConstructor;
185
+ readonly textColor: StringConstructor;
186
+ readonly activeTextColor: StringConstructor;
187
+ readonly closeOnClickOutside: BooleanConstructor;
188
+ readonly collapseTransition: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
189
+ readonly ellipsis: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
190
+ readonly popperOffset: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 6, boolean>;
191
+ readonly ellipsisIcon: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component) | (((new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component)) | null)[], unknown, unknown, () => import('vue').DefineComponent<{}, void, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>, boolean>;
192
+ readonly popperEffect: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => string) | (() => import('element-plus').PopperEffect) | (((new (...args: any[]) => string) | (() => import('element-plus').PopperEffect)) | null)[], unknown, unknown, "dark", boolean>;
193
+ readonly popperClass: StringConstructor;
194
+ readonly popperStyle: {
195
+ readonly type: import('vue').PropType<import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => string | import('vue').CSSProperties) | (() => string | import('vue').CSSProperties) | (((new (...args: any[]) => string | import('vue').CSSProperties) | (() => string | import('vue').CSSProperties)) | null)[], unknown, unknown>>;
196
+ readonly required: false;
197
+ readonly validator: ((val: unknown) => boolean) | undefined;
198
+ __epPropKey: true;
199
+ };
200
+ readonly showTimeout: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 300, boolean>;
201
+ readonly hideTimeout: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 300, boolean>;
202
+ readonly persistent: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
203
+ }>> & Readonly<{
204
+ onClose?: ((index: string, indexPath: string[]) => any) | undefined;
205
+ onSelect?: ((index: string, indexPath: string[], item: import('element-plus').MenuItemClicked, routerResult?: Promise<void | import('vue-router').NavigationFailure> | undefined) => any) | undefined;
206
+ onOpen?: ((index: string, indexPath: string[]) => any) | undefined;
207
+ }>, () => import('vue').VNode<import('vue').RendererNode, import('vue').RendererElement, {
208
+ [key: string]: any;
209
+ }>, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
210
+ close: (index: string, indexPath: string[]) => boolean;
211
+ open: (index: string, indexPath: string[]) => boolean;
212
+ select: (index: string, indexPath: string[], item: import('element-plus').MenuItemClicked, routerResult?: Promise<void | import('vue-router').NavigationFailure>) => boolean;
213
+ }, import('vue').PublicProps, {
214
+ readonly collapse: boolean;
215
+ readonly ellipsis: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
216
+ readonly persistent: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
217
+ readonly mode: import('element-plus/es/utils/index.mjs').EpPropMergeType<StringConstructor, "horizontal" | "vertical", unknown>;
218
+ readonly showTimeout: number;
219
+ readonly hideTimeout: number;
220
+ readonly defaultActive: string;
221
+ readonly defaultOpeneds: string[];
222
+ readonly menuTrigger: import('element-plus/es/utils/index.mjs').EpPropMergeType<StringConstructor, "click" | "hover", unknown>;
223
+ readonly collapseTransition: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
224
+ readonly popperOffset: number;
225
+ readonly ellipsisIcon: import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component) | (((new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component)) | null)[], unknown, unknown>;
226
+ readonly popperEffect: import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => string) | (() => import('element-plus').PopperEffect) | (((new (...args: any[]) => string) | (() => import('element-plus').PopperEffect)) | null)[], unknown, unknown>;
227
+ readonly uniqueOpened: boolean;
228
+ readonly router: boolean;
229
+ readonly closeOnClickOutside: boolean;
230
+ }, true, {}, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, {}, any, import('vue').ComponentProvideOptions, {
231
+ P: {};
232
+ B: {};
233
+ D: {};
234
+ C: {};
235
+ M: {};
236
+ Defaults: {};
237
+ }, Readonly<import('vue').ExtractPropTypes<{
238
+ readonly mode: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, "horizontal" | "vertical", unknown, "vertical", boolean>;
239
+ readonly defaultActive: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
240
+ readonly defaultOpeneds: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => string[]) | (() => string[]) | (((new (...args: any[]) => string[]) | (() => string[])) | null)[], unknown, unknown, () => [], boolean>;
241
+ readonly uniqueOpened: BooleanConstructor;
242
+ readonly router: BooleanConstructor;
243
+ readonly menuTrigger: import('element-plus/es/utils/index.mjs').EpPropFinalized<StringConstructor, "click" | "hover", unknown, "hover", boolean>;
244
+ readonly collapse: BooleanConstructor;
245
+ readonly backgroundColor: StringConstructor;
246
+ readonly textColor: StringConstructor;
247
+ readonly activeTextColor: StringConstructor;
248
+ readonly closeOnClickOutside: BooleanConstructor;
249
+ readonly collapseTransition: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
250
+ readonly ellipsis: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
251
+ readonly popperOffset: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 6, boolean>;
252
+ readonly ellipsisIcon: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component) | (((new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component)) | null)[], unknown, unknown, () => import('vue').DefineComponent<{}, void, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>, boolean>;
253
+ readonly popperEffect: import('element-plus/es/utils/index.mjs').EpPropFinalized<(new (...args: any[]) => string) | (() => import('element-plus').PopperEffect) | (((new (...args: any[]) => string) | (() => import('element-plus').PopperEffect)) | null)[], unknown, unknown, "dark", boolean>;
254
+ readonly popperClass: StringConstructor;
255
+ readonly popperStyle: {
256
+ readonly type: import('vue').PropType<import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => string | import('vue').CSSProperties) | (() => string | import('vue').CSSProperties) | (((new (...args: any[]) => string | import('vue').CSSProperties) | (() => string | import('vue').CSSProperties)) | null)[], unknown, unknown>>;
257
+ readonly required: false;
258
+ readonly validator: ((val: unknown) => boolean) | undefined;
259
+ __epPropKey: true;
260
+ };
261
+ readonly showTimeout: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 300, boolean>;
262
+ readonly hideTimeout: import('element-plus/es/utils/index.mjs').EpPropFinalized<NumberConstructor, unknown, unknown, 300, boolean>;
263
+ readonly persistent: import('element-plus/es/utils/index.mjs').EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
264
+ }>> & Readonly<{
265
+ onClose?: ((index: string, indexPath: string[]) => any) | undefined;
266
+ onSelect?: ((index: string, indexPath: string[], item: import('element-plus').MenuItemClicked, routerResult?: Promise<void | import('vue-router').NavigationFailure> | undefined) => any) | undefined;
267
+ onOpen?: ((index: string, indexPath: string[]) => any) | undefined;
268
+ }>, () => import('vue').VNode<import('vue').RendererNode, import('vue').RendererElement, {
269
+ [key: string]: any;
270
+ }>, {}, {}, {}, {
271
+ readonly collapse: boolean;
272
+ readonly ellipsis: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
273
+ readonly persistent: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
274
+ readonly mode: import('element-plus/es/utils/index.mjs').EpPropMergeType<StringConstructor, "horizontal" | "vertical", unknown>;
275
+ readonly showTimeout: number;
276
+ readonly hideTimeout: number;
277
+ readonly defaultActive: string;
278
+ readonly defaultOpeneds: string[];
279
+ readonly menuTrigger: import('element-plus/es/utils/index.mjs').EpPropMergeType<StringConstructor, "click" | "hover", unknown>;
280
+ readonly collapseTransition: import('element-plus/es/utils/index.mjs').EpPropMergeType<BooleanConstructor, unknown, unknown>;
281
+ readonly popperOffset: number;
282
+ readonly ellipsisIcon: import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component) | (((new (...args: any[]) => (string | import('vue').Component) & {}) | (() => string | import('vue').Component)) | null)[], unknown, unknown>;
283
+ readonly popperEffect: import('element-plus/es/utils/index.mjs').EpPropMergeType<(new (...args: any[]) => string) | (() => import('element-plus').PopperEffect) | (((new (...args: any[]) => string) | (() => import('element-plus').PopperEffect)) | null)[], unknown, unknown>;
284
+ readonly uniqueOpened: boolean;
285
+ readonly router: boolean;
286
+ readonly closeOnClickOutside: boolean;
287
+ }> | null;
288
+ }, any, import('vue').ComponentProvideOptions, {
289
+ P: {};
290
+ B: {};
291
+ D: {};
292
+ C: {};
293
+ M: {};
294
+ Defaults: {};
295
+ }, Readonly<{
296
+ menus: RouteMetaResolveRaw[];
297
+ menuFlatList: RouteMetaResolveRaw[];
298
+ routerMode?: boolean;
299
+ collapse?: boolean;
300
+ autoClose?: boolean;
301
+ groupMode?: boolean;
302
+ }> & Readonly<{}>, {
303
+ open: (index: string) => void | undefined;
304
+ close: (index: string) => void | undefined;
305
+ }, {}, {}, {}, {}> | null;
306
+ }, HTMLDivElement>;
23
307
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
24
308
  export default _default;
25
309
  type __VLS_WithTemplateSlots<T, S> = T & {
@@ -41,7 +41,7 @@ export type AppLayoutUserStoreSlice<UserInfo = Record<string, any>> = ReturnType
41
41
  * (getRoutes / generateRouteMetaRawTree)。loginApi / refreshToken 等 auth
42
42
  * 面不通过本 slice 暴露(业务侧通过 appBridge 直读)。
43
43
  */
44
- export type AppLayoutBridgeSlice = Pick<CoreBridge, "APP_BASE_INFO" | "APP_ENV_INFO" | "APP_CACHE_CONFIG" | "APP_LAYOUT_HEADER_CONFIG" | "APP_LAYOUT_FOOTER_CONFIG" | "APP_LAYOUT_SIDEBAR_CONFIG" | "APP_LAYOUT_ASIDE_CONFIG" | "APP_LAYOUT_BREADCRUMB_CONFIG" | "APP_LAYOUT_BODY_CONFIG" | "APP_LAYOUT_VIEWPORT_CONFIG" | "APP_LAYOUT_GAP_CONFIG" | "APP_LAYOUT_CONFIG" | "APP_ROUTER_META_DEFAULT_CONFIG" | "APP_ROUTER_CONFIG" | "APP_ROUTER_PATHS_CONFIG" | "APP_THEME_CONFIG" | "theme" | "themeStyle" | "themeMode" | "themeIsDark" | "themeLayout" | "themeDensity" | "themeMotion" | "themeColors" | "showThemeStyleSwitcher" | "getRoutes" | "generateRouteMetaRawTree">;
44
+ export type AppLayoutBridgeSlice = Pick<CoreBridge, "APP_BASE_INFO" | "APP_ENV_INFO" | "APP_CACHE_CONFIG" | "APP_LAYOUT_HEADER_CONFIG" | "APP_LAYOUT_FOOTER_CONFIG" | "APP_LAYOUT_SIDEBAR_CONFIG" | "APP_LAYOUT_ASIDE_CONFIG" | "APP_LAYOUT_BREADCRUMB_CONFIG" | "APP_LAYOUT_BODY_CONFIG" | "APP_LAYOUT_VIEWPORT_CONFIG" | "APP_LAYOUT_GAP_CONFIG" | "APP_LAYOUT_CONFIG" | "APP_ROUTER_META_DEFAULT_CONFIG" | "APP_ROUTER_CONFIG" | "APP_ROUTER_PATHS_CONFIG" | "APP_THEME_CONFIG" | "theme" | "themeStyle" | "themeMode" | "themeIsDark" | "themeLayout" | "themeDensity" | "themeMotion" | "themeColors" | "showThemeStyleSwitcher" | "layout" | "getRoutes" | "generateRouteMetaRawTree">;
45
45
  /**
46
46
  * 内容锚 slot 名集(焊缝契约 ③,纯功能语义;P1' 去布局化重做)。
47
47
  *
@@ -1,15 +1,20 @@
1
- /**
2
- * DataListView 单项容器
3
- * ---
4
- * 仅承载选中(勾选)/ 当前项(active)两个 class 钩子 + 项内容插槽,由 DataListView 内部 v-for 使用。
5
- * [MUST NOT] 写死视觉样式(卡片阴影/圆角等归消费方);
6
- * [MUST NOT] 内置选中状态机(状态机在 DataListView)。
7
- */
8
1
  type __VLS_Props = {
9
2
  /** 当前项是否选中(勾选语义,由 DataListView 传入) */
10
3
  selected: boolean;
11
4
  /** 当前项是否为「当前项」(active = 用户点击/激活的那一条,与勾选无关) */
12
5
  active?: boolean;
6
+ /** 套内置卡壳(border/radius/padding,走 token);由 DataListView 下发 */
7
+ card?: boolean;
8
+ /**
9
+ * 卡壳内呼吸(px)——由 DataListView 按间距阶梯**呼吸档**算好下发。
10
+ * 🔴 [MUST NOT] 在本组件自造 CSS 变量兜这个值(规则 14):自造 var 脱离主题两套注入;
11
+ * 也 [MUST NOT] 写死 12 —— 那样切密度档不跟。
12
+ */
13
+ cardPad?: number;
14
+ /** 瀑布流态(即便本项还没量到跨度,也要吃 `align-self: start`,否则量出来恒等于写进去) */
15
+ masonry?: boolean;
16
+ /** 瀑布流跨度(`grid-row-end: span N`);未测到时不写,退 CSS 兜底跨度 */
17
+ spanRows?: number;
13
18
  };
14
19
  declare function __VLS_template(): {
15
20
  attrs: Partial<{}>;