@done-coding/admin-core 0.23.0 → 0.23.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.
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./AppSidebar.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const AppSidebar = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-8aa015fb"]]);
4
+ const AppSidebar = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6808ecdb"]]);
5
5
  export {
6
6
  AppSidebar as default
7
7
  };
@@ -14,9 +14,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
14
14
  },
15
15
  setup(__props) {
16
16
  useCssVars((_ctx) => ({
17
- "v3ceb1df4": sidebarZIndex.value,
18
- "v2c8b87ee": shimTop.value,
19
- "baa8be1c": shimBottom.value
17
+ "a540a4d0": sidebarZIndex.value,
18
+ "v4433cc00": shimTop.value,
19
+ "v7d77fda0": shimBottom.value
20
20
  }));
21
21
  const props = __props;
22
22
  const appStore = inject(APP_LAYOUT_APP_STORE_KEY);
@@ -38,6 +38,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
38
38
  };
39
39
  const bridge = inject(APP_LAYOUT_BRIDGE_KEY);
40
40
  const themeColors = computed(() => bridge.themeColors.value);
41
+ const menuGroupMode = computed(
42
+ () => bridge.APP_LAYOUT_SIDEBAR_CONFIG.menuGroupMode ?? false
43
+ );
41
44
  return (_ctx, _cache) => {
42
45
  return openBlock(), createElementBlock("div", {
43
46
  class: "app-sidebar",
@@ -61,8 +64,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
61
64
  "text-color": themeColors.value.baseColor,
62
65
  "active-text-color": themeColors.value.primaryColor,
63
66
  menuFlatList: __props.menuFlatList,
67
+ groupMode: menuGroupMode.value,
64
68
  routerMode: ""
65
- }, null, 8, ["collapse", "menus", "background-color", "text-color", "active-text-color", "menuFlatList"])
69
+ }, null, 8, ["collapse", "menus", "background-color", "text-color", "active-text-color", "menuFlatList", "groupMode"])
66
70
  ]),
67
71
  createVNode(unref(_sfc_main$1), {
68
72
  class: "app-sidebar-bottom",
@@ -75,7 +79,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
75
79
  }),
76
80
  createVNode(AppCollapseToggle, {
77
81
  side: "sidebar",
78
- show: __props.show,
82
+ show: __props.show && !menuGroupMode.value,
79
83
  collapse: collapse.value,
80
84
  onToggle: onToggleCollapse
81
85
  }, null, 8, ["show", "collapse"])
@@ -2,7 +2,7 @@ import _sfc_main from "./FormUpload.vue2.mjs";
2
2
  /* empty css */
3
3
  /* empty css */
4
4
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
5
- const FormUpload = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-158fc67d"]]);
5
+ const FormUpload = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9f186e75"]]);
6
6
  export {
7
7
  FormUpload as default
8
8
  };
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./FormUploadCard.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const FormUploadCard = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-48323f64"]]);
4
+ const FormUploadCard = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-3989639c"]]);
5
5
  export {
6
6
  FormUploadCard as default
7
7
  };
@@ -1,7 +1,7 @@
1
1
  import { defineComponent, ref, useAttrs, computed, openBlock, createBlock, unref, mergeProps, withCtx, createElementBlock, Fragment, renderList, resolveDynamicComponent, createCommentVNode, createElementVNode, toDisplayString } from "vue";
2
2
  import _sfc_main$1 from "./MenuItemSub.vue.mjs";
3
3
  import { useRoute } from "vue-router";
4
- import { ElMenu, ElMenuItem, ElIcon } from "element-plus";
4
+ import { ElMenu, ElMenuItemGroup, ElMenuItem, ElIcon } from "element-plus";
5
5
  const _sfc_main = /* @__PURE__ */ defineComponent({
6
6
  __name: "MenuTree",
7
7
  props: {
@@ -9,7 +9,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
9
9
  menuFlatList: {},
10
10
  routerMode: { type: Boolean },
11
11
  collapse: { type: Boolean },
12
- autoClose: { type: Boolean }
12
+ autoClose: { type: Boolean },
13
+ groupMode: { type: Boolean }
13
14
  },
14
15
  setup(__props, { expose: __expose }) {
15
16
  const props = __props;
@@ -72,12 +73,44 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
72
73
  return openBlock(), createElementBlock(Fragment, {
73
74
  key: menu.path
74
75
  }, [
75
- menu.children.length ? (openBlock(), createBlock(_sfc_main$1, {
76
+ __props.groupMode && menu.children.length ? (openBlock(), createBlock(unref(ElMenuItemGroup), {
76
77
  key: 0,
78
+ title: menu.title
79
+ }, {
80
+ default: withCtx(() => [
81
+ (openBlock(true), createElementBlock(Fragment, null, renderList(menu.children, (item) => {
82
+ return openBlock(), createElementBlock(Fragment, {
83
+ key: item.path
84
+ }, [
85
+ item.children.length ? (openBlock(), createBlock(_sfc_main$1, {
86
+ key: 0,
87
+ menu: item,
88
+ MenuItemSub: _sfc_main$1
89
+ }, null, 8, ["menu"])) : (openBlock(), createBlock(unref(ElMenuItem), {
90
+ key: 1,
91
+ index: item.path
92
+ }, {
93
+ default: withCtx(() => [
94
+ item.menuIcon ? (openBlock(), createBlock(unref(ElIcon), { key: 0 }, {
95
+ default: withCtx(() => [
96
+ (openBlock(), createBlock(resolveDynamicComponent(item.menuIcon)))
97
+ ]),
98
+ _: 2
99
+ }, 1024)) : createCommentVNode("", true),
100
+ createElementVNode("span", null, toDisplayString(item.title), 1)
101
+ ]),
102
+ _: 2
103
+ }, 1032, ["index"]))
104
+ ], 64);
105
+ }), 128))
106
+ ]),
107
+ _: 2
108
+ }, 1032, ["title"])) : menu.children.length ? (openBlock(), createBlock(_sfc_main$1, {
109
+ key: 1,
77
110
  menu,
78
111
  MenuItemSub: _sfc_main$1
79
112
  }, null, 8, ["menu"])) : (openBlock(), createBlock(unref(ElMenuItem), {
80
- key: 1,
113
+ key: 2,
81
114
  index: menu.path
82
115
  }, {
83
116
  default: withCtx(() => [
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./ViewLayout.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const ViewLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f0ed342f"]]);
4
+ const ViewLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-c8a1cb2d"]]);
5
5
  export {
6
6
  ViewLayout as default
7
7
  };
@@ -1,4 +1,5 @@
1
- import { defineComponent, shallowRef, ref, computed, provide, watch, openBlock, createElementBlock, unref, createBlock, withCtx, createElementVNode, normalizeStyle, renderSlot, withDirectives, createVNode, vShow, Fragment } from "vue";
1
+ import { defineComponent, shallowRef, ref, useModel, computed, provide, watch, withDirectives, openBlock, createElementBlock, unref, createBlock, withCtx, createElementVNode, normalizeStyle, renderSlot, createVNode, vShow, Fragment, mergeModels } from "vue";
2
+ import { vLoading } from "element-plus";
2
3
  import AutoRefreshGroup from "../misc/AutoRefreshGroup.vue.mjs";
3
4
  import _sfc_main$1 from "../display/HeightProvider.vue.mjs";
4
5
  import _sfc_main$2 from "../display/ActionBtnGroup.vue.mjs";
@@ -17,7 +18,7 @@ const _hoisted_7 = { class: "view-layout-toolbar__right" };
17
18
  const _hoisted_8 = { class: "view-layout-content" };
18
19
  const _sfc_main = /* @__PURE__ */ defineComponent({
19
20
  __name: "ViewLayout",
20
- props: {
21
+ props: /* @__PURE__ */ mergeModels({
21
22
  api: {},
22
23
  params: {},
23
24
  refine: { type: Boolean, default: void 0 },
@@ -29,7 +30,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
29
30
  showRefresh: { type: Boolean, default: true },
30
31
  leftExtraButtons: { default: () => [] },
31
32
  rightExtraButtons: { default: () => [] }
32
- },
33
+ }, {
34
+ "isAutoRefresh": { type: Boolean },
35
+ "isAutoRefreshModifiers": {}
36
+ }),
37
+ emits: ["update:isAutoRefresh"],
33
38
  setup(__props) {
34
39
  const props = __props;
35
40
  const { ctxRefine } = useContextDefaults({
@@ -41,6 +46,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
41
46
  const { viewportHeightFinal, nearestScope } = useChannelViewportHeight(props);
42
47
  const data = shallowRef(void 0);
43
48
  const loading = ref(false);
49
+ const isAutoRefresh = useModel(__props, "isAutoRefresh");
44
50
  const fetch = async () => {
45
51
  loading.value = true;
46
52
  try {
@@ -50,6 +56,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
50
56
  }
51
57
  };
52
58
  const refresh = fetch;
59
+ const showLoadingMask = computed(() => !isAutoRefresh.value && loading.value);
53
60
  const toolbarCtx = computed(() => ({
54
61
  loading: loading.value,
55
62
  refresh
@@ -84,7 +91,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
84
91
  () => console.error("[ViewLayout] channel 不支持响应式变更,当前值已忽略。")
85
92
  );
86
93
  return (_ctx, _cache) => {
87
- return openBlock(), createElementBlock("div", _hoisted_1, [
94
+ return withDirectives((openBlock(), createElementBlock("div", _hoisted_1, [
88
95
  unref(ctxRefine) ? (openBlock(), createBlock(unref(_sfc_main$1), {
89
96
  key: 0,
90
97
  viewportHeight: heightProviderViewportHeight.value,
@@ -107,11 +114,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
107
114
  "default-size": "small"
108
115
  }, null, 8, ["configs", "ctx"]),
109
116
  createVNode(unref(AutoRefreshGroup), {
117
+ isAutoRefresh: isAutoRefresh.value,
118
+ "onUpdate:isAutoRefresh": _cache[0] || (_cache[0] = ($event) => isAutoRefresh.value = $event),
110
119
  refreshFn: fetch,
111
120
  loading: loading.value,
112
121
  showAutoRefresh: __props.showAutoRefresh,
113
122
  showRefresh: __props.showRefresh
114
- }, null, 8, ["loading", "showAutoRefresh", "showRefresh"])
123
+ }, null, 8, ["isAutoRefresh", "loading", "showAutoRefresh", "showRefresh"])
115
124
  ])
116
125
  ], 512), [
117
126
  [vShow, hasToolbarContent.value]
@@ -147,11 +156,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
147
156
  "default-size": "small"
148
157
  }, null, 8, ["configs", "ctx"]),
149
158
  createVNode(unref(AutoRefreshGroup), {
159
+ isAutoRefresh: isAutoRefresh.value,
160
+ "onUpdate:isAutoRefresh": _cache[1] || (_cache[1] = ($event) => isAutoRefresh.value = $event),
150
161
  refreshFn: fetch,
151
162
  loading: loading.value,
152
163
  showAutoRefresh: __props.showAutoRefresh,
153
164
  showRefresh: __props.showRefresh
154
- }, null, 8, ["loading", "showAutoRefresh", "showRefresh"])
165
+ }, null, 8, ["isAutoRefresh", "loading", "showAutoRefresh", "showRefresh"])
155
166
  ])
156
167
  ], 512), [
157
168
  [vShow, hasToolbarContent.value]
@@ -165,6 +176,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
165
176
  }, void 0, true)
166
177
  ])
167
178
  ], 64))
179
+ ])), [
180
+ [unref(vLoading), showLoadingMask.value]
168
181
  ]);
169
182
  };
170
183
  }
package/es/store/app.mjs CHANGED
@@ -8,8 +8,12 @@ function createAppStore(deps) {
8
8
  const footerHeight = computed(() => bridge.APP_LAYOUT_FOOTER_CONFIG.height);
9
9
  const name = computed(() => bridge.APP_BASE_INFO.name);
10
10
  const sidebarHasMenus = ref(false);
11
+ const sidebarCollapsedEffective = computed(() => {
12
+ if (bridge.APP_LAYOUT_SIDEBAR_CONFIG.menuGroupMode) return false;
13
+ return bridge.layout.sidebarCollapsed.value;
14
+ });
11
15
  const sidebarWidth = computed(() => {
12
- return bridge.layout.sidebarCollapsed.value ? bridge.APP_LAYOUT_SIDEBAR_CONFIG.collapseWidth : bridge.APP_LAYOUT_SIDEBAR_CONFIG.width;
16
+ return sidebarCollapsedEffective.value ? bridge.APP_LAYOUT_SIDEBAR_CONFIG.collapseWidth : bridge.APP_LAYOUT_SIDEBAR_CONFIG.width;
13
17
  });
14
18
  const route = useRoute();
15
19
  const theme = computed(() => bridge.themeColors.value);
@@ -191,7 +195,8 @@ function createAppStore(deps) {
191
195
  bodyShimStyle,
192
196
  viewportPadding,
193
197
  // 折叠态读 bridge 真相(架构反转,名字保留向后兼容);aside 对称新增。
194
- sidebarIsCollapse: computed(() => bridge.layout.sidebarCollapsed.value),
198
+ // sidebar 侧经 sidebarCollapsedEffective 单点(分组形态闸为 false,见其注释)。
199
+ sidebarIsCollapse: sidebarCollapsedEffective,
195
200
  asideIsCollapse: computed(() => bridge.layout.asideCollapsed.value),
196
201
  changeSidebarCollapseStatus,
197
202
  changeAsideCollapseStatus,
package/es/style.css CHANGED
@@ -499,34 +499,34 @@
499
499
  display: flex;
500
500
  align-items: center;
501
501
  }
502
- .app-sidebar[data-v-8aa015fb] {
502
+ .app-sidebar[data-v-6808ecdb] {
503
503
  transition-duration: 0.3s;
504
504
  transition-property: width;
505
505
  transition-timing-function: linear;
506
506
  box-shadow: var(--dc-core-shadow, var(--el-box-shadow));
507
507
  overflow: visible;
508
- z-index: var(--v3ceb1df4);
508
+ z-index: var(--a540a4d0);
509
509
  }
510
- .app-sidebar-top[data-v-8aa015fb] {
510
+ .app-sidebar-top[data-v-6808ecdb] {
511
511
  position: absolute;
512
512
  left: 0;
513
513
  right: 0;
514
514
  top: 0;
515
515
  overflow: hidden;
516
516
  }
517
- .app-sidebar-bottom[data-v-8aa015fb] {
517
+ .app-sidebar-bottom[data-v-6808ecdb] {
518
518
  position: absolute;
519
519
  left: 0;
520
520
  right: 0;
521
521
  bottom: 0;
522
522
  overflow: hidden;
523
523
  }
524
- .app-sidebar-shim[data-v-8aa015fb] {
524
+ .app-sidebar-shim[data-v-6808ecdb] {
525
525
  position: absolute;
526
526
  left: 0;
527
527
  right: 0;
528
- top: var(--v2c8b87ee);
529
- bottom: var(--baa8be1c);
528
+ top: var(--v4433cc00);
529
+ bottom: var(--v7d77fda0);
530
530
  overflow-x: hidden;
531
531
  overflow-y: auto;
532
532
  --el-menu-border-color: transparent;
@@ -964,7 +964,7 @@ to {
964
964
  padding: 0;
965
965
  color: var(--el-text-color-secondary);
966
966
  }
967
- .dc-form-upload__placeholder[data-v-158fc67d] {
967
+ .dc-form-upload__placeholder[data-v-9f186e75] {
968
968
  margin-top: 4px;
969
969
  font-size: 12px;
970
970
  line-height: 1.5;
@@ -1035,14 +1035,16 @@ to {
1035
1035
  .dc-form-upload-audio__item:hover .dc-form-upload-audio__remove[data-v-3884f0f6] {
1036
1036
  opacity: 1;
1037
1037
  }
1038
- .dc-form-upload-card[data-v-48323f64] {
1038
+ .dc-form-upload-card[data-v-3989639c] {
1039
1039
  position: relative;
1040
1040
  width: 100%;
1041
1041
  height: 100%;
1042
1042
  overflow: hidden;
1043
+ display: flex;
1044
+ align-items: center;
1043
1045
  background: var(--el-fill-color-light);
1044
1046
  }
1045
- .dc-form-upload-card__mask[data-v-48323f64] {
1047
+ .dc-form-upload-card__mask[data-v-3989639c] {
1046
1048
  position: absolute;
1047
1049
  inset: 0;
1048
1050
  display: flex;
@@ -1055,17 +1057,17 @@ to {
1055
1057
  color: var(--el-color-white);
1056
1058
  font-size: 12px;
1057
1059
  }
1058
- .dc-form-upload-card__mask-name[data-v-48323f64] {
1060
+ .dc-form-upload-card__mask-name[data-v-3989639c] {
1059
1061
  max-width: 100%;
1060
1062
  overflow: hidden;
1061
1063
  text-overflow: ellipsis;
1062
1064
  white-space: nowrap;
1063
1065
  }
1064
- .dc-form-upload-card__mask-percent[data-v-48323f64] {
1066
+ .dc-form-upload-card__mask-percent[data-v-3989639c] {
1065
1067
  font-size: 13px;
1066
1068
  font-weight: 600;
1067
1069
  }
1068
- .dc-form-upload-card__mask-bar[data-v-48323f64] {
1070
+ .dc-form-upload-card__mask-bar[data-v-3989639c] {
1069
1071
  position: absolute;
1070
1072
  left: 0;
1071
1073
  bottom: 0;
@@ -1073,7 +1075,7 @@ to {
1073
1075
  background: var(--el-color-primary);
1074
1076
  transition: width 0.2s;
1075
1077
  }
1076
- .dc-form-upload-card__remove[data-v-48323f64] {
1078
+ .dc-form-upload-card__remove[data-v-3989639c] {
1077
1079
  position: absolute;
1078
1080
  top: 4px;
1079
1081
  right: 4px;
@@ -1091,7 +1093,7 @@ to {
1091
1093
  opacity: 0;
1092
1094
  transition: opacity 0.2s;
1093
1095
  }
1094
- .dc-form-upload-card:hover .dc-form-upload-card__remove[data-v-48323f64] {
1096
+ .dc-form-upload-card:hover .dc-form-upload-card__remove[data-v-3989639c] {
1095
1097
  opacity: 1;
1096
1098
  }
1097
1099
  .dc-form-upload-image__thumb[data-v-9d62114a] {
@@ -1269,24 +1271,24 @@ to {
1269
1271
  gap: 8px;
1270
1272
  margin-top: 8px;
1271
1273
  }
1272
- .view-layout[data-v-f0ed342f] {
1274
+ .view-layout[data-v-c8a1cb2d] {
1273
1275
  display: flex;
1274
1276
  flex-direction: column;
1275
1277
  gap: 8px;
1276
1278
  }
1277
- .view-layout-toolbar[data-v-f0ed342f] {
1279
+ .view-layout-toolbar[data-v-c8a1cb2d] {
1278
1280
  display: flex;
1279
1281
  justify-content: space-between;
1280
1282
  align-items: center;
1281
1283
  padding-bottom: 8px;
1282
1284
  gap: 20px;
1283
1285
  }
1284
- .view-layout-toolbar__left[data-v-f0ed342f],
1285
- .view-layout-toolbar__right[data-v-f0ed342f] {
1286
+ .view-layout-toolbar__left[data-v-c8a1cb2d],
1287
+ .view-layout-toolbar__right[data-v-c8a1cb2d] {
1286
1288
  display: flex;
1287
1289
  align-items: center;
1288
1290
  gap: 10px;
1289
1291
  }
1290
- .view-layout-content[data-v-f0ed342f] {
1292
+ .view-layout-content[data-v-c8a1cb2d] {
1291
1293
  overflow: auto;
1292
1294
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@done-coding/admin-core",
3
- "version": "0.23.0",
3
+ "version": "0.23.1-alpha.0",
4
4
  "description": "内部前端库",
5
5
  "private": false,
6
6
  "main": "es/index.mjs",
@@ -83,5 +83,5 @@
83
83
  "dependencies": {
84
84
  "@tanstack/vue-virtual": "^3.13.35"
85
85
  },
86
- "gitHead": "345849870494584a62144db4e7bc983d49ed38fa"
86
+ "gitHead": "1112339ffe6bdb4569c9f1c9f3a2e3b7da9c15dd"
87
87
  }
@@ -44,11 +44,38 @@ app.use(appCoreBridge); // opt-in:CORE_BRIDGE_KEY 注入
44
44
  响应式更新(`update` 改配置视图,全链路即时生效):
45
45
 
46
46
  ```ts
47
- appCoreBridge.update({ APP_LAYOUT_VIEWPORT_CONFIG: { ... } });
47
+ appCoreBridge.update("APP_LAYOUT_VIEWPORT_CONFIG", { ... }); // 单 key + 一级浅合并
48
48
  appCoreBridge.theme.setStyle("studio-stage");
49
49
  appCoreBridge.theme.setDark(true);
50
50
  ```
51
51
 
52
+ ## 布局配置里的行为开关
53
+
54
+ 布局 8 组配置多为几何数值(宽高 / 间距 / 配色),少数是**行为开关**——需要单独知道语义:
55
+
56
+ | 配置键 | 字段 | 默认 | 语义 |
57
+ | --- | --- | --- | --- |
58
+ | `APP_LAYOUT_SIDEBAR_CONFIG` | `menuGroupMode?: boolean` | `false` | 侧栏菜单渲染形态:`false` = 树形(父级手风琴,默认收起);`true` = 分组(父级降格为小字号弱色的 section heading,不可点不可折叠,子项常驻全展开) |
59
+
60
+ ```ts
61
+ // 初始化时定形态
62
+ createCoreBridge({
63
+ APP_LAYOUT_SIDEBAR_CONFIG: { width: 220, collapseWidth: 64, menuGroupMode: true },
64
+ // ...
65
+ });
66
+
67
+ // 或运行时切(本键在 UpdatableConfigKey 联合内,reactive 全链路即时生效)
68
+ appCoreBridge.update("APP_LAYOUT_SIDEBAR_CONFIG", { menuGroupMode: true });
69
+ ```
70
+
71
+ **连带影响(开启 `menuGroupMode` 后)**:
72
+
73
+ - `AppSidebar` 不渲染折叠把手,侧栏宽度恒取 `width`——`collapseWidth` 在该形态下不生效;
74
+ - `bridge.layout.sidebarCollapsed` 的**读取被屏蔽**(避免历史持久化的 `true` 把无把手的侧栏锁死在窄条),但**持久化值原样保留**,关掉该形态即恢复;
75
+ - 因此该形态下调 `bridge.layout.setSidebarCollapse` / `toggleSidebar` 不报错但视觉无效。
76
+
77
+ 适用判据与三级菜单的混合渲染规则见 [menu 族文档](../../components/menu/README.md) 与 [AppSidebar 文档](../../components/app-layout/docs/README-AppSidebar.md)。
78
+
52
79
  ## 认证与请求接线
53
80
 
54
81
  ### 认证 facade(bridge 4 钩子 + userInfoAccess)
@@ -11,7 +11,7 @@
11
11
  | `AppPage` | 页面主体容器:撑满视口 + 四向悬浮 fixed 插槽 | `fullViewport` `fullMode` `gap` `topBg`/`bottomBg`/`leftBg`/`rightBg` `nextViewportMaxHeight` | [README-AppPage.md](./docs/README-AppPage.md) |
12
12
  | `AppBody` | 内容主体:内置 RouterView + KeepAlive + 面包屑 affix + #footer 槽 | `menuFlatList` | [README-AppBody.md](./docs/README-AppBody.md) |
13
13
  | `AppHeader` | 顶栏积木:#left 品牌 + 路由模块菜单 + #right 操作区 | `menus` `menuFlatList`(必填)`show`(未消费) | [README-AppHeader.md](./docs/README-AppHeader.md) |
14
- | `AppSidebar` | 侧边栏积木:折叠把手 + MenuTree 菜单 + #top/#bottom 高度自撑 | `show` `menus`(必填)`menuFlatList`(必填)`aboveHeader` | [README-AppSidebar.md](./docs/README-AppSidebar.md) |
14
+ | `AppSidebar` | 侧边栏积木:折叠把手 + MenuTree 菜单(树形/分组双形态)+ #top/#bottom 高度自撑 | `show` `menus`(必填)`menuFlatList`(必填)`aboveHeader`;菜单形态读 bridge `APP_LAYOUT_SIDEBAR_CONFIG.menuGroupMode`(分组态无折叠把手) | [README-AppSidebar.md](./docs/README-AppSidebar.md) |
15
15
  | `AppAside` | 右侧补充区积木(对称 AppSidebar),无内置内容 | `show` | [README-AppAside.md](./docs/README-AppAside.md) |
16
16
  | `AppBreadcrumb` | 面包屑积木:menuFlatList 匹配 route.matched 出链 | `height`(必填)`menuFlatList`(必填) | [README-AppBreadcrumb.md](./docs/README-AppBreadcrumb.md) |
17
17
  | `AppFooter` | 底部状态条积木:高度/样式随 appStore.footerStyle 驱动,零 props | 无 | [README-AppFooter.md](./docs/README-AppFooter.md) |
@@ -1,6 +1,6 @@
1
1
  # AppSidebar(侧边栏积木)
2
2
 
3
- > 左侧栏积木:折叠把手 + MenuTree 菜单渲染 + #top/#bottom 高度自撑插槽;可 aboveHeader 悬浮盖顶。
3
+ > 左侧栏积木:折叠把手 + MenuTree 菜单渲染(树形 / 分组双形态)+ #top/#bottom 高度自撑插槽;可 aboveHeader 悬浮盖顶。
4
4
  > 范式页:`apps/reference/src/pages/app-layout/shell/`(DemoCustomShell 自供 shell 积木直引)、`apps/reference/src/pages/app-layout/layout/`(NoSidebar 显隐变体)
5
5
 
6
6
  ## 定位
@@ -9,6 +9,22 @@
9
9
  - `show` 控制显隐(含折叠把手渲染开关)——false 即不渲染整栏
10
10
  - `aboveHeader` 时 z-index 2 盖 header(AppLayout 另有 `sidebarAboveHeader` prop 同源传递)
11
11
  - #top/#bottom 高度自撑(WatchSize 反推 shim 边界)——品牌区/挂件放 #top,底部操作放 #bottom
12
+ - 菜单形态由 **bridge 配置**驱动(非 prop):`bridge.APP_LAYOUT_SIDEBAR_CONFIG.menuGroupMode`(缺省 `false`)
13
+
14
+ ## 菜单形态:树形(默认)/ 分组
15
+
16
+ `menuGroupMode` 落在 `APP_LAYOUT_SIDEBAR_CONFIG`(`createCoreBridge` 初始化传入,缺省 `false`;因在 `UpdatableConfigKey` 联合内,亦可 `bridge.update("APP_LAYOUT_SIDEBAR_CONFIG", { menuGroupMode: true })` 运行时切换)。AppSidebar 内部读它,**不开放同名 prop**——与 `collapse` 读 `appStore.sidebarIsCollapse` 同范式,业务侧统一在 bridge 一处配置。
17
+
18
+ | | `menuGroupMode: false`(默认) | `menuGroupMode: true` |
19
+ | --- | --- | --- |
20
+ | 菜单渲染 | MenuTree 树形(父级手风琴,默认收起) | MenuTree 分组(父级 = 小字号弱色分组标题,子项常驻全展开) |
21
+ | 折叠把手 `AppCollapseToggle` | 渲染 | **不渲染**(`show=false`) |
22
+ | 侧栏宽度 | 随折叠态在 `width` / `collapseWidth` 间切换 | 恒取 `width`(展开态) |
23
+ | `bridge.layout.sidebarCollapsed` | 生效 | **读取被屏蔽**,但持久化值原样保留 |
24
+
25
+ **为什么分组形态没有折叠把手**:分组形态的前提是「全展开常驻」,与折叠成图标栏语义互斥;且 EP 的 `--collapse` 规则对 `el-menu-item-group` 支持不全(标题不隐藏、组内叶子不居中),窄栏必然错乱。故直接关掉该形态下的折叠能力,而非去打 EP 补丁。
26
+
27
+ **⚠️ 折叠持久化的锁死风险与规避**(实现约束,[MUST] 守):`bridge.layout` 把 `sidebarCollapsed` 持久化进 localStorage。若用户上次折叠过(落盘 `true`),开发者随后打开 `menuGroupMode`,侧栏会以 `collapseWidth` 窄条渲染却**没有把手可展开 → 永久锁死**。规避方式:`menuGroupMode` 为真时在 `store/app.ts` 单点把折叠态**读取**强制为 `false`(`sidebarWidth` 与 `sidebarIsCollapse` 两处共用同一 computed),**[MUST NOT] 写回** `bridge.layout.setSidebarCollapse`——用户的折叠偏好原样留在存储里,关掉分组形态后照常恢复。
12
28
 
13
29
  ## 快速上手(最小可用)
14
30
 
@@ -27,6 +43,7 @@
27
43
 
28
44
  - **`#top` / `#bottom` 高度自撑插槽按需**:默认零配置即菜单栏可用;仅当需要品牌区/挂件(`#top`)或底部操作区(`#bottom`)才填——高度自撑(WatchSize 反推 shim 边界),放多少内容撑多高。
29
45
  - **`aboveHeader` 默认关**:仅当 sidebar 需要 z-index 2 盖住 header 悬浮时开(与 AppLayout `sidebarAboveHeader` 同源传递,自供 shell 时对齐)。
46
+ - **`menuGroupMode` 默认关(树形)即够用**:仅当菜单量小(经验值 ≤ 25 叶子)/ 层级浅、要求零点击看见全部导航才开;量大或层级深仍用树形,否则全展开会变成长滚动条。开启后自动失去折叠能力(见上表)。
30
47
  - `show=false` 整栏不渲染(含折叠把手)——「收起但保留把手」场景走折叠态而非 `show=false`。
31
48
  - **完整能力演示**(DemoCustomShell 槽转发范式 + NoSidebar 变体):`apps/reference/src/pages/app-layout/shell/`、`apps/reference/src/pages/app-layout/layout/`
32
49
 
@@ -59,12 +76,17 @@
59
76
  ## 反模式 / 注意
60
77
 
61
78
  - `show=false` 时折叠把手也随整栏不渲染(把手渲染开关即 show)——「收起但保留把手」场景应走折叠态而非 show=false
79
+ - **`menuGroupMode` 下还想保留折叠把手**:两者语义互斥且 EP 折叠态不支持分组,[MUST NOT] 强开
80
+ - **`menuGroupMode` 下调 `bridge.layout.setSidebarCollapse` / `appStore.changeSidebarCollapseStatus`**:调用不报错但视觉无效(读取被屏蔽),属无效操作
81
+ - **给 AppSidebar 加同名 `menuGroupMode` prop 覆盖 bridge**:[MUST NOT]——形态是全 app 一致的布局配置,双真相源会让自供 shell 与内置 shell 表现分叉
62
82
  - `aboveHeader` 与 AppLayout `sidebarAboveHeader` 语义一致,自供 shell 时两者对齐(DemoCustomShell 透传范式)
63
83
  - 折叠/展开动画由族内积木承担,[MUST NOT] 自造折叠逻辑
64
84
 
65
85
  ## 关联
66
86
 
67
87
  - 折叠积木:`AppCollapseToggle`(族内共享,AppSidebar/AppAside 内部使用,未导出)
88
+ - 菜单积木:`MenuTree`(menu 族,`groupMode` 双形态详见 [menu 族文档](../../menu/README.md))
89
+ - 配置真源:`APP_LAYOUT_SIDEBAR_CONFIG`(bridge,见 [bridge 文档](../../../bridge/docs/README.md))
68
90
  - 右侧对称积木:`AppAside`
69
91
  - 内容锚:`#brand` 等(落位见 AppLayout 文档)
70
92
  - 范式页:`apps/reference/src/pages/app-layout/shell/`、`apps/reference/src/pages/app-layout/layout/`
@@ -1,11 +1,24 @@
1
1
  # menu 菜单族
2
2
 
3
- 配置化菜单族:`MenuTree`(基于 ElMenu 的树形菜单)+ `MenuItemSub`(递归子菜单分组件,MenuTree 内部递归用)。
3
+ 配置化菜单族:`MenuTree`(基于 ElMenu 的菜单,含**树形 / 分组**双渲染形态)+ `MenuItemSub`(递归子菜单分组件,MenuTree 内部递归用)。
4
+
5
+ ## 两种渲染形态(`MenuTree` 的 `groupMode`)
6
+
7
+ | 形态 | `groupMode` | 父级节点渲染成 | 交互 | 适用 |
8
+ | --- | --- | --- | --- | --- |
9
+ | **树形**(默认) | `false` | `ElSubMenu`(手风琴) | 点击展开 / 收起,默认收起 | 菜单量大 / 层级深,靠折叠控制列表长度 |
10
+ | **分组** | `true` | `ElMenuItemGroup`(分组标题:小字号 + 弱色,**不可点、不可折叠、不导航**) | 无——子项常驻全展开 | 菜单量小(经验值 ≤ 25 叶子)/ 层级浅,要求零点击看见全部导航 |
11
+
12
+ 分组形态即业界通称的 **grouped / sectioned navigation**(父级叫 section heading / group label):shadcn/ui `SidebarGroupLabel`、Ant Design `Menu type:"group"`、Element Plus `el-menu-item-group`、Material 3 / Fluent 2 的 navigation section header 都是同一范式;Linear / Stripe / Vercel / Supabase / GitHub Settings 等产品的侧栏走的都是它而非手风琴。
13
+
14
+ 本族**不自造分组组件**——EP 的 `el-menu-item-group__title` 原生就是 `font-size: 12px` + `--el-text-color-secondary`,正是「字号偏小、颜色偏弱」,直接复用。
15
+
16
+ > ⚠️ 分组形态**只吃掉一层**父级:三级及以上菜单中 L1 → 分组标题,L2 若仍有 `children` → 继续走 `ElSubMenu` 手风琴(混合渲染)。详见 [README-MenuTree.md](./docs/README-MenuTree.md)。
4
17
 
5
18
  ## 组件文档(docs/)
6
19
 
7
- - [MenuTree](./docs/README-MenuTree.md) — 树形菜单(menus 递归出 ElSubMenu + routerMode / autoClose / collapse + open/close expose)
8
- - [MenuItemSub](./docs/README-MenuItemSub.md) — 递归子菜单分组件(ElSubMenu 递归节点,一般由 MenuTree 自用)
20
+ - [MenuTree](./docs/README-MenuTree.md) — 菜单主体(menus 递归 + `groupMode` 树形 / 分组双形态 + routerMode / autoClose / collapse + open/close expose)
21
+ - [MenuItemSub](./docs/README-MenuItemSub.md) — 递归子菜单分组件(ElSubMenu 递归节点,一般由 MenuTree 自用;分组形态下承接 L2 及更深层级)
9
22
 
10
23
  ## 关键类型
11
24
 
@@ -14,6 +27,6 @@
14
27
 
15
28
  ## 范式页(apps/reference)
16
29
 
17
- - 真实消费方:`AppSidebar`(packages/core/src/components/app-layout/AppSidebar.vue)——生产级驱动点
30
+ - 真实消费方:`AppSidebar`(packages/core/src/components/app-layout/AppSidebar.vue)——生产级驱动点;其 `groupMode` 由 `bridge.APP_LAYOUT_SIDEBAR_CONFIG.menuGroupMode` 驱动,业务侧不直传
18
31
  - 菜单数据契约范式:`apps/reference/src/router/modules/test.ts`(meta.menu 的 show / icon / sort 驱动渲染与排序)
19
32
  - 注意:`/menu/showcase/Page1/2/3` 是菜单渲染出的叶子路由页,不是 MenuTree 的用法示范
@@ -8,6 +8,9 @@
8
8
  - 递归子菜单分组件:节点含 `children` → `ElSubMenu` + 递归子级;叶子 → `ElMenuItem`
9
9
  - 组件自引用:`MenuItemSub` prop 传入组件自身,供 children 递归再实例化
10
10
  - 一般由 `MenuTree` 内部使用,独立消费场景少见
11
+ - **两种形态下的角色**:
12
+ - MenuTree `groupMode=false`(树形)→ 承接 **L1 及以下**全部有子项的节点
13
+ - MenuTree `groupMode=true`(分组)→ L1 已被 `ElMenuItemGroup` 分组标题接管,本组件**只承接 L2 及更深**层级(即「分组标题内的手风琴」)。分组标题只吃掉一层,深层级仍归本组件——这是分组形态下三级菜单混合渲染的实现落点
11
14
 
12
15
  ## 快速上手(最小可用)
13
16
 
@@ -46,6 +49,7 @@ MenuTree 内部驱动(menu/MenuTree.vue 片段):
46
49
  ## 反模式 / 注意
47
50
 
48
51
  - **缺自引用 prop**:children 递归靠 `MenuItemSub` prop 再实例化,缺它无法递归展开子级
52
+ - **想在分组形态下把本组件也换成分组标题**:分组标题是视觉聚类不是层级实体,[MUST NOT] 嵌套分组(EP / AntD / shadcn 皆不支持);L2+ 保持 ElSubMenu 是设计内行为
49
53
 
50
54
  ## 关联
51
55
 
@@ -1,15 +1,31 @@
1
1
  # MenuTree(树形菜单)
2
2
 
3
- > 基于 ElMenu 的配置化树形菜单:menus 树形数据递归出 ElSubMenu,叶子渲染 ElMenuItem;routerMode 路由联动、autoClose 选中收合、collapse 折叠透传。
3
+ > 基于 ElMenu 的配置化菜单:menus 树形数据递归渲染,含**树形(手风琴)/ 分组(section heading)**双形态;routerMode 路由联动、autoClose 选中收合、collapse 折叠透传。
4
4
  > 范式页:真实消费方为 `AppSidebar`(packages/core/src/components/app-layout/AppSidebar.vue);菜单数据契约范式见 `apps/reference/src/router/modules/test.ts`
5
5
 
6
6
  ## 定位
7
7
 
8
- - **何时用**:侧栏 / 导航需要配置驱动的树形菜单(递归子菜单、路由联动、折叠态)
8
+ - **何时用**:侧栏 / 导航需要配置驱动的菜单(递归子菜单、路由联动、折叠态、分组标题)
9
9
  - **何时不用**:单层 / 少量菜单直接用 ElMenu;菜单数据不来自路由配置时自行组装数据再接入
10
- - 数据驱动:`menus` 树形节点含 `children` 递归出 `ElSubMenu`,叶子渲染 `ElMenuItem`;`menuFlatList` 拍平列表供 autoClose 沿 `parentPath` 递归算父链
10
+ - 数据驱动:`menus` 树形节点含 `children` 递归出父级容器,叶子渲染 `ElMenuItem`;`menuFlatList` 拍平列表供 autoClose 沿 `parentPath` 递归算父链
11
+ - **双形态**:`groupMode=false`(默认)父级 → `ElSubMenu` 手风琴;`groupMode=true` 父级 → `ElMenuItemGroup` 分组标题(详见下节)
11
12
  - 增强点:routerMode(defaultActive 取 route.path + ElMenu :router)、autoClose(选中一项收合其它展开子菜单)、collapse 透传、ElMenu 其余 attrs 整包透传、open / close expose
12
13
 
14
+ ## 树形 / 分组双形态(`groupMode`)
15
+
16
+ | | `groupMode=false`(默认,树形) | `groupMode=true`(分组) |
17
+ | --- | --- | --- |
18
+ | L1 有子项 | `ElSubMenu`,可点击展开 / 收起,**默认收起** | `ElMenuItemGroup :title`,小字号 + 弱色,**不可点、不导航、不折叠** |
19
+ | L1 叶子 | `ElMenuItem` | `ElMenuItem`(同左) |
20
+ | L2 及更深有子项 | `MenuItemSub` 递归 `ElSubMenu` | **仍是** `MenuItemSub` 递归 `ElSubMenu`(分组只吃掉一层,见下) |
21
+ | 子项可见性 | 需点击父级才展开 | 常驻全展开 |
22
+
23
+ **分组只吃掉一层——三级菜单是混合渲染。** 分组标题是「视觉聚类」而非「层级实体」,一层标题下不能再嵌一层标题(EP / AntD / shadcn 皆如此)。因此 L1 降格为分组标题后,L2 若仍有 `children`,只能继续用 `ElSubMenu` 手风琴。`apps/reference/src/router/modules/test.ts` 实测存在三级嵌套,分组形态下就会呈现「分组标题 + 组内手风琴」的混合形态,这是设计内行为,非缺陷。
24
+
25
+ **选型判据**:叶子总量小(经验值 ≤ 25)且层级浅 → 分组(零点击可见全部导航,无手风琴的「东西藏哪了」认知负担);量大或层级深 → 树形(否则全展开变成长滚动条)。
26
+
27
+ **视觉不自造**:分组标题吃 EP 原生皮肤(`el-menu-item-group__title` = `font-size:12px` + `--el-text-color-secondary`);需微调只走主题 var(规则 14),[MUST NOT] 写死颜色。
28
+
13
29
  ## 快速上手(最小可用)
14
30
 
15
31
  必填只有 `menus` + `menuFlatList`——默认 ElMenu 主题、无路由联动、无选中收合:
@@ -29,6 +45,7 @@
29
45
  - **`routerMode`:默认关即够用。** 仅当菜单项与路由 path 联动高亮才开——开启后 `defaultActive` 自动取 `route.path`(useRoute)+ ElMenu `:router` 同步开启;注意依赖 vue-router 上下文。
30
46
  - **`autoClose`:默认关即够用。** 仅当「选中一项后收合其它展开子菜单」才开——父链沿 `menuFlatList` 的 `parentPath` 递归计算,数据缺失时路径链断裂、收合不全。
31
47
  - **`collapse`:默认不折叠即够用。** 仅当侧栏折叠态需要同步收起菜单才传(透传 ElMenu)。
48
+ - **`groupMode`:默认关(树形)即够用。** 仅当菜单量小 / 层级浅、要求全展开常驻导航才开。⚠️ **与 `collapse` 互斥**:分组形态的前提就是「常驻全展开」,两者同时为 true 无意义且 EP 折叠态对 `el-menu-item-group` 支持不全(EP 的 `--collapse` 规则既没隐藏 `el-menu-item-group__title`,也漏掉了 `> .el-menu-item-group > ul > .el-menu-item` 的「藏文字 + 图标居中」,会溢出窄栏)。消费方 [MUST NOT] 同开两者;`AppSidebar` 已在内部保证互斥(见其文档)。
32
49
  - **颜色 attrs(`background-color` / `text-color` / `active-text-color` 等):默认 ElMenu 主题即够用。** 仅当需贴合页面主题配色才显式传。
33
50
  - **完整能力演示**(生产级驱动点 = AppSidebar 内部接线,含折叠 + 路由联动 + 主题配色):`packages/core/src/components/app-layout/AppSidebar.vue`——能力展示,非推荐默认。
34
51
 
@@ -44,6 +61,7 @@
44
61
  | `routerMode?` | `boolean` | 未设 | 路由模式:true 时 defaultActive 取 route.path(useRoute)+ ElMenu :router 开启 |
45
62
  | `collapse?` | `boolean` | 未设 | 折叠态透传 ElMenu |
46
63
  | `autoClose?` | `boolean` | 未设 | 选中一项后关闭其它展开的 ElSubMenu |
64
+ | `groupMode?` | `boolean` | `false` | 分组形态:L1 有子项时渲染 `ElMenuItemGroup` 分组标题(不可点 / 不折叠)替代 `ElSubMenu`;L2+ 仍走 ElSubMenu。与 `collapse` 互斥 |
47
65
 
48
66
  其余 attrs(`background-color` / `text-color` / `active-text-color` 等 ElMenu props)整包透传。
49
67
 
@@ -68,6 +86,9 @@
68
86
  - **autoClose 缺 parentPath 数据**:父链沿 `parentPath` 递归计算,数据缺失时路径链断裂、收合不全
69
87
  - **想覆盖内部 @select**:`v-bind="attrs"` 展开在前、`@select` 声明在后,外部 `onSelect` 无法覆盖内部 autoClose 逻辑(推断标注)
70
88
  - **依赖 vue-router 上下文**:routerMode 使用 `useRoute`,组件须在安装 vue-router 的上下文中使用
89
+ - **`groupMode` + `collapse` 同开**:EP 折叠态不支持 `el-menu-item-group`(标题不隐藏 + 组内叶子不居中),窄栏会溢出错乱;两者语义本身也互斥
90
+ - **指望 `groupMode` 把整棵树拍平**:它只把 L1 降为分组标题,L2+ 仍是手风琴;要全平请先把菜单数据本身收敛到两层
91
+ - **`open` / `close` expose 在分组形态下对 L1 无效**:L1 已不是 `ElSubMenu`(无 index、无展开态),expose 仅对组内仍为 ElSubMenu 的 L2+ 节点有效
71
92
 
72
93
  ## 关联
73
94
 
@@ -157,12 +157,22 @@ export interface AppConfig {
157
157
  /** 装饰逃生舱(见 {@link AppLayoutModuleStyle}) */
158
158
  style?: AppLayoutModuleStyle;
159
159
  };
160
- /** 应用布局-sidebar 配置(store/app 取 collapseWidth / width) */
160
+ /** 应用布局-sidebar 配置(store/app 取 collapseWidth / width / menuGroupMode) */
161
161
  APP_LAYOUT_SIDEBAR_CONFIG: {
162
162
  /** [展开的]宽度(px) */
163
163
  width: number;
164
164
  /** 折叠起来的宽度(px) */
165
165
  collapseWidth: number;
166
+ /**
167
+ * 侧栏菜单渲染形态:`false`(缺省) = 树形(父级 ElSubMenu 手风琴,默认收起);
168
+ * `true` = 分组(父级降格为 ElMenuItemGroup 分组标题——小字号弱色、不可点不可折叠,
169
+ * 子项常驻全展开,即业界 grouped / sectioned navigation 范式)。
170
+ *
171
+ * 开启后:AppSidebar 不渲染折叠把手、宽度恒取 `width`(`collapseWidth` 失效),
172
+ * 且 store 侧把 `bridge.layout.sidebarCollapsed` 的**读取**闸为 false
173
+ * (避免历史持久化的 true 把无把手的侧栏锁死在窄条);持久化值原样保留。
174
+ */
175
+ menuGroupMode?: boolean;
166
176
  /** 字体色;缺省 → 继承 :root color(baseColor) */
167
177
  color?: string;
168
178
  /** 背景(color / image / gradient 等 CSS background);缺省 → bodyColor */
@@ -5,6 +5,15 @@ type __VLS_Props = {
5
5
  routerMode?: boolean;
6
6
  collapse?: boolean;
7
7
  autoClose?: boolean;
8
+ /**
9
+ * 分组形态:L1 有子项时渲染 ElMenuItemGroup 分组标题替代 ElSubMenu 手风琴,
10
+ * 子项常驻全展开(业界 grouped / sectioned navigation 范式);L2+ 仍走 ElSubMenu。
11
+ *
12
+ * ⚠️ 与 `collapse` 互斥——分组形态前提即「常驻全展开」,且 EP 的 `--collapse` 规则
13
+ * 对 `el-menu-item-group` 支持不全(标题不隐藏 + 组内叶子不居中)会撑坏窄栏。
14
+ * 缺省 false = 树形形态,零回归。
15
+ */
16
+ groupMode?: boolean;
8
17
  };
9
18
  declare const _default: import('vue').DefineComponent<__VLS_Props, {
10
19
  open: (index: string) => void | undefined;
@@ -1,7 +1,11 @@
1
1
  import { VNode } from 'vue';
2
2
  import { ViewLayoutProps, ViewLayoutScope } from './types';
3
3
  declare const _default: <P extends Record<string, any> = Record<string, any>, R = any>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
4
- props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{} & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, never>, never> & ViewLayoutProps<P, R> & Partial<{}>> & import('vue').PublicProps;
4
+ props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{
5
+ readonly "onUpdate:isAutoRefresh"?: ((value: boolean) => any) | undefined;
6
+ } & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, never>, "onUpdate:isAutoRefresh"> & ({
7
+ isAutoRefresh?: boolean;
8
+ } & ViewLayoutProps<P, R>) & Partial<{}>> & import('vue').PublicProps;
5
9
  expose(exposed: import('vue').ShallowUnwrapRef<{}>): void;
6
10
  attrs: any;
7
11
  slots: Readonly<{
@@ -9,7 +13,7 @@ declare const _default: <P extends Record<string, any> = Record<string, any>, R
9
13
  }> & {
10
14
  default: (scope: ViewLayoutScope<R>) => VNode[];
11
15
  };
12
- emit: {};
16
+ emit: (evt: "update:isAutoRefresh", value: boolean) => void;
13
17
  }>) => import('vue').VNode & {
14
18
  __ctx?: Awaited<typeof __VLS_setup>;
15
19
  };
@@ -1,6 +1,6 @@
1
1
  declare const _default: {
2
2
  "name": "@done-coding/admin-core",
3
- "version": "0.23.0",
3
+ "version": "0.23.1-alpha.0",
4
4
  "description": "内部前端库"
5
5
  };
6
6