@done-coding/admin-core 0.23.1-alpha.0 → 0.24.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.
- package/es/bridge/badge.mjs +27 -0
- package/es/bridge/index.mjs +4 -0
- package/es/components/app-layout/AppHeader.vue.mjs +1 -1
- package/es/components/app-layout/AppHeader.vue2.mjs +13 -3
- package/es/components/app-layout/AppLayout.vue.mjs +1 -1
- package/es/components/app-layout/AppLayout.vue2.mjs +6 -2
- package/es/components/display/ActionBtn.vue.mjs +21 -3
- package/es/components/display/BadgeMark.vue.mjs +7 -0
- package/es/components/display/BadgeMark.vue2.mjs +31 -0
- package/es/components/display/TabsHeader.vue.mjs +1 -1
- package/es/components/display/TabsHeader.vue2.mjs +16 -7
- package/es/components/display/TabsTile.vue.mjs +1 -1
- package/es/components/display/TabsTile.vue2.mjs +27 -7
- package/es/components/display/use-badge.mjs +62 -0
- package/es/components/menu/MenuItemSub.vue.mjs +22 -3
- package/es/components/menu/MenuTree.vue.mjs +34 -8
- package/es/index.mjs +62 -60
- package/es/store/app.mjs +16 -4
- package/es/style.css +61 -46
- package/package.json +2 -2
- package/src/bridge/README.md +1 -1
- package/src/bridge/docs/README.md +98 -2
- package/src/components/app-layout/README.md +1 -1
- package/src/components/app-layout/docs/README-AppHeader.md +8 -0
- package/src/components/app-layout/docs/README-AppLayout.md +24 -0
- package/src/components/display/README.md +7 -4
- package/src/components/display/docs/README-ActionBtn.md +1 -0
- package/src/components/display/docs/README-BadgeMark.md +125 -0
- package/src/components/display/docs/README-TabsMain.md +20 -1
- package/src/components/menu/README.md +8 -0
- package/src/components/menu/docs/README-MenuItemSub.md +4 -0
- package/src/components/menu/docs/README-MenuTree.md +10 -0
- package/types/bridge/badge.d.ts +112 -0
- package/types/bridge/index.d.ts +18 -0
- package/types/components/display/BadgeMark.vue.d.ts +57 -0
- package/types/components/display/index.d.ts +7 -0
- package/types/components/display/types.d.ts +18 -0
- package/types/components/display/use-badge.d.ts +19 -0
- package/types/injectInfo.json.d.ts +1 -1
- package/types/store/app.d.ts +22 -1
- package/types/types/route.d.ts +20 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { shallowRef, readonly } from "vue";
|
|
2
|
+
function createBridgeBadgeHook(init = {}) {
|
|
3
|
+
const marks = shallowRef({ ...init.marks ?? {} });
|
|
4
|
+
const setAll = (next) => {
|
|
5
|
+
marks.value = { ...next };
|
|
6
|
+
};
|
|
7
|
+
const set = (key, entry) => {
|
|
8
|
+
marks.value = { ...marks.value, [key]: entry };
|
|
9
|
+
};
|
|
10
|
+
const remove = (key) => {
|
|
11
|
+
if (!(key in marks.value)) return;
|
|
12
|
+
const next = { ...marks.value };
|
|
13
|
+
delete next[key];
|
|
14
|
+
marks.value = next;
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
badge: {
|
|
18
|
+
marks: readonly(marks),
|
|
19
|
+
setAll,
|
|
20
|
+
set,
|
|
21
|
+
remove
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
createBridgeBadgeHook
|
|
27
|
+
};
|
package/es/bridge/index.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { createBridgeConfigHook } from "./config-hook.mjs";
|
|
|
6
6
|
import { createBridgePluginHost } from "./plugin.mjs";
|
|
7
7
|
import { createBridgeThemeHook } from "./theme/index.mjs";
|
|
8
8
|
import { createBridgeLayoutHook } from "./layout.mjs";
|
|
9
|
+
import { createBridgeBadgeHook } from "./badge.mjs";
|
|
9
10
|
import { CORE_BRIDGE_KEY } from "../inject/key.mjs";
|
|
10
11
|
function createCoreBridge(options) {
|
|
11
12
|
const rawNs = options.APP_CACHE_CONFIG.namespace;
|
|
@@ -81,6 +82,7 @@ function createCoreBridge(options) {
|
|
|
81
82
|
defaultMode: options.defaultThemeMode
|
|
82
83
|
});
|
|
83
84
|
const layoutHook = createBridgeLayoutHook({ storage });
|
|
85
|
+
const badgeHook = createBridgeBadgeHook({ marks: options.badgeMarks });
|
|
84
86
|
const themeColors = computed(
|
|
85
87
|
() => themeHook.themeIsDark.value ? configHook.roTheme.dark : configHook.roTheme.light
|
|
86
88
|
);
|
|
@@ -251,6 +253,8 @@ function createCoreBridge(options) {
|
|
|
251
253
|
showThemeStyleSwitcher: options.showThemeStyleSwitcher ?? true,
|
|
252
254
|
/** 布局折叠模块(折叠真相源在 bridge;appStore 转发,AppSidebar / AppAside 驱动) */
|
|
253
255
|
layout: layoutHook.layout,
|
|
256
|
+
/** 徽标注册表(key→标记;菜单按 path、ActionBtn 按 badgeKey 查表渲染角标) */
|
|
257
|
+
badge: badgeHook.badge,
|
|
254
258
|
/** 用户信息字段访问器集(第一宪法:业务注入 get/set 读写 token/refreshToken/permission) */
|
|
255
259
|
userInfoAccess,
|
|
256
260
|
// 插件系统一期:update(REQ-1)+ install(REQ-9)挂载。
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _sfc_main from "./AppHeader.vue2.mjs";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
|
|
4
|
-
const AppHeader = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
4
|
+
const AppHeader = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-40b13903"]]);
|
|
5
5
|
export {
|
|
6
6
|
AppHeader as default
|
|
7
7
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { defineComponent, useCssVars, inject, computed, watch, nextTick, openBlock, createElementBlock, normalizeStyle, createElementVNode, renderSlot, normalizeClass, Fragment, renderList, createBlock, unref, withCtx, resolveDynamicComponent, createCommentVNode, toDisplayString } from "vue";
|
|
1
|
+
import { defineComponent, useCssVars, inject, computed, watch, nextTick, openBlock, createElementBlock, normalizeStyle, createElementVNode, renderSlot, normalizeClass, Fragment, renderList, createBlock, unref, withCtx, resolveDynamicComponent, createCommentVNode, createVNode, createTextVNode, toDisplayString } from "vue";
|
|
2
2
|
import { useRouter } from "vue-router";
|
|
3
3
|
import { ElIcon } from "element-plus";
|
|
4
|
+
import BadgeMark from "../display/BadgeMark.vue.mjs";
|
|
4
5
|
import { APP_LAYOUT_APP_STORE_KEY, APP_LAYOUT_BRIDGE_KEY } from "../../inject/key.mjs";
|
|
5
6
|
const _hoisted_1 = { class: "app-header-shim" };
|
|
6
7
|
const _hoisted_2 = ["name", "onClick"];
|
|
@@ -16,7 +17,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
16
17
|
},
|
|
17
18
|
setup(__props) {
|
|
18
19
|
useCssVars((_ctx) => ({
|
|
19
|
-
"
|
|
20
|
+
"v05959ac0": themeColors.value.primaryColor
|
|
20
21
|
}));
|
|
21
22
|
const props = __props;
|
|
22
23
|
const appStore = inject(APP_LAYOUT_APP_STORE_KEY);
|
|
@@ -87,7 +88,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
87
88
|
]),
|
|
88
89
|
_: 2
|
|
89
90
|
}, 1024)) : createCommentVNode("", true),
|
|
90
|
-
createElementVNode("span", null,
|
|
91
|
+
createElementVNode("span", null, [
|
|
92
|
+
createVNode(unref(BadgeMark), {
|
|
93
|
+
badgeKey: menu.path
|
|
94
|
+
}, {
|
|
95
|
+
default: withCtx(() => [
|
|
96
|
+
createTextVNode(toDisplayString(menu.title), 1)
|
|
97
|
+
]),
|
|
98
|
+
_: 2
|
|
99
|
+
}, 1032, ["badgeKey"])
|
|
100
|
+
])
|
|
91
101
|
], 10, _hoisted_2);
|
|
92
102
|
}), 128))
|
|
93
103
|
])) : createCommentVNode("", true),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _sfc_main from "./AppLayout.vue2.mjs";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
|
|
4
|
-
const AppLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
4
|
+
const AppLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-b68520cd"]]);
|
|
5
5
|
export {
|
|
6
6
|
AppLayout as default
|
|
7
7
|
};
|
|
@@ -72,7 +72,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
72
72
|
getThemeMotion: () => props.bridge.themeMotion.value
|
|
73
73
|
});
|
|
74
74
|
useCoreViewportApply({
|
|
75
|
-
|
|
75
|
+
// [MUST] 读 store 的**有效值**而非 bridge 原值:路由 `meta.layout.noViewportPadding`
|
|
76
|
+
// 要同时归零 core 内部几何与这套对外 CSS var,两条链必须同源
|
|
77
|
+
// (只归零一边 → 内容区贴边了,而读 var 的浮层仍按套框内缘定位)。
|
|
78
|
+
getViewportConfig: () => props.appStore.viewportConfigEffective,
|
|
76
79
|
getGapConfig: () => props.bridge.APP_LAYOUT_GAP_CONFIG
|
|
77
80
|
});
|
|
78
81
|
const menus = computed(() => {
|
|
@@ -158,7 +161,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
158
161
|
return (_ctx, _cache) => {
|
|
159
162
|
return openBlock(), createElementBlock("div", {
|
|
160
163
|
class: normalizeClass(["app-layout", {
|
|
161
|
-
"app-layout_noLogin": !isLogin.value
|
|
164
|
+
"app-layout_noLogin": !isLogin.value,
|
|
165
|
+
"app-layout_noAnimation": __props.appStore.noAnimation
|
|
162
166
|
}])
|
|
163
167
|
}, [
|
|
164
168
|
createVNode(unref(ElWatermark), {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineComponent, toRefs, getCurrentInstance, ref, computed, openBlock, createBlock, unref, withCtx, createVNode, mergeProps, renderSlot } from "vue";
|
|
2
2
|
import { ElButton } from "element-plus";
|
|
3
3
|
import ActionConfirm from "./ActionConfirm.vue.mjs";
|
|
4
|
+
import BadgeMark from "./BadgeMark.vue.mjs";
|
|
4
5
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
5
6
|
...{ inheritAttrs: false },
|
|
6
7
|
__name: "ActionBtn",
|
|
@@ -25,7 +26,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
25
26
|
tag: {},
|
|
26
27
|
confirmMode: {},
|
|
27
28
|
confirmConfig: {},
|
|
28
|
-
beforeOpen: {}
|
|
29
|
+
beforeOpen: {},
|
|
30
|
+
badgeKey: {}
|
|
29
31
|
},
|
|
30
32
|
emits: ["click"],
|
|
31
33
|
setup(__props) {
|
|
@@ -137,7 +139,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
137
139
|
onClick: onInnerClick
|
|
138
140
|
}), {
|
|
139
141
|
default: withCtx(() => [
|
|
140
|
-
|
|
142
|
+
createVNode(BadgeMark, {
|
|
143
|
+
align: "corner",
|
|
144
|
+
badgeKey: __props.badgeKey
|
|
145
|
+
}, {
|
|
146
|
+
default: withCtx(() => [
|
|
147
|
+
renderSlot(_ctx.$slots, "default")
|
|
148
|
+
]),
|
|
149
|
+
_: 3
|
|
150
|
+
}, 8, ["badgeKey"])
|
|
141
151
|
]),
|
|
142
152
|
_: 3
|
|
143
153
|
}, 16, ["loading"])
|
|
@@ -151,7 +161,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
151
161
|
onClick: onInnerClick
|
|
152
162
|
}), {
|
|
153
163
|
default: withCtx(() => [
|
|
154
|
-
|
|
164
|
+
createVNode(BadgeMark, {
|
|
165
|
+
align: "corner",
|
|
166
|
+
badgeKey: __props.badgeKey
|
|
167
|
+
}, {
|
|
168
|
+
default: withCtx(() => [
|
|
169
|
+
renderSlot(_ctx.$slots, "default")
|
|
170
|
+
]),
|
|
171
|
+
_: 3
|
|
172
|
+
}, 8, ["badgeKey"])
|
|
155
173
|
]),
|
|
156
174
|
_: 3
|
|
157
175
|
}, 16, ["loading"]));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import _sfc_main from "./BadgeMark.vue2.mjs";
|
|
2
|
+
/* empty css */
|
|
3
|
+
import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
|
|
4
|
+
const BadgeMark = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-12868883"]]);
|
|
5
|
+
export {
|
|
6
|
+
BadgeMark as default
|
|
7
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { defineComponent, unref, openBlock, createBlock, normalizeClass, withCtx, renderSlot } from "vue";
|
|
2
|
+
import { ElBadge } from "element-plus";
|
|
3
|
+
import { useBadgeResolved } from "./use-badge.mjs";
|
|
4
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
5
|
+
__name: "BadgeMark",
|
|
6
|
+
props: {
|
|
7
|
+
badgeKey: {},
|
|
8
|
+
align: {}
|
|
9
|
+
},
|
|
10
|
+
setup(__props) {
|
|
11
|
+
const props = __props;
|
|
12
|
+
const resolved = useBadgeResolved(() => props.badgeKey);
|
|
13
|
+
return (_ctx, _cache) => {
|
|
14
|
+
return unref(resolved) ? (openBlock(), createBlock(unref(ElBadge), {
|
|
15
|
+
key: 0,
|
|
16
|
+
class: normalizeClass(["dc-badge-mark badge-mark", `badge-mark_${__props.align ?? "middle"}`]),
|
|
17
|
+
value: unref(resolved).value,
|
|
18
|
+
max: unref(resolved).max,
|
|
19
|
+
type: unref(resolved).type
|
|
20
|
+
}, {
|
|
21
|
+
default: withCtx(() => [
|
|
22
|
+
renderSlot(_ctx.$slots, "default", {}, void 0, true)
|
|
23
|
+
]),
|
|
24
|
+
_: 3
|
|
25
|
+
}, 8, ["class", "value", "max", "type"])) : renderSlot(_ctx.$slots, "default", { key: 1 }, void 0, true);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
export {
|
|
30
|
+
_sfc_main as default
|
|
31
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _sfc_main from "./TabsHeader.vue2.mjs";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
|
|
4
|
-
const TabsHeader = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
4
|
+
const TabsHeader = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-1f3b9f99"]]);
|
|
5
5
|
export {
|
|
6
6
|
TabsHeader as default
|
|
7
7
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { defineComponent, toRefs, useModel, ref, computed, watch, openBlock, createElementBlock, normalizeClass, Fragment, renderList, unref, renderSlot, createTextVNode, toDisplayString, normalizeStyle, createCommentVNode, mergeModels, nextTick } from "vue";
|
|
1
|
+
import { defineComponent, toRefs, useModel, ref, computed, watch, openBlock, createElementBlock, normalizeClass, Fragment, renderList, unref, createVNode, withCtx, renderSlot, createTextVNode, toDisplayString, normalizeStyle, createCommentVNode, mergeModels, nextTick } from "vue";
|
|
2
|
+
import BadgeMark from "./BadgeMark.vue.mjs";
|
|
2
3
|
import { useActivated } from "../../hooks/activated.mjs";
|
|
3
4
|
const _hoisted_1 = ["onClick"];
|
|
4
5
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
@@ -82,12 +83,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
82
83
|
class: normalizeClass(["tabs-main-bar-item", { "tabs-main-bar-item_active": tab.key === activeKey.value }]),
|
|
83
84
|
onClick: ($event) => activeKey.value = tab.key
|
|
84
85
|
}, [
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
createVNode(BadgeMark, {
|
|
87
|
+
align: "corner",
|
|
88
|
+
badgeKey: tab.badgeKey
|
|
89
|
+
}, {
|
|
90
|
+
default: withCtx(() => [
|
|
91
|
+
renderSlot(_ctx.$slots, tab.key, {
|
|
92
|
+
tab,
|
|
93
|
+
active: tab.key === activeKey.value
|
|
94
|
+
}, () => [
|
|
95
|
+
createTextVNode(toDisplayString(tab.title), 1)
|
|
96
|
+
], true)
|
|
97
|
+
]),
|
|
98
|
+
_: 2
|
|
99
|
+
}, 1032, ["badgeKey"])
|
|
91
100
|
], 10, _hoisted_1);
|
|
92
101
|
}), 128)),
|
|
93
102
|
showIndicator.value ? (openBlock(), createElementBlock("div", {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _sfc_main from "./TabsTile.vue2.mjs";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
|
|
4
|
-
const TabsTile = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
4
|
+
const TabsTile = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-acb4bb13"]]);
|
|
5
5
|
export {
|
|
6
6
|
TabsTile as default
|
|
7
7
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineComponent, toRefs, useModel, ref, computed, inject, watch, onMounted, nextTick, openBlock, createElementBlock, normalizeClass, createElementVNode, normalizeStyle, Fragment, renderList, unref, createVNode, withCtx, renderSlot, createBlock, resolveDynamicComponent, createCommentVNode, createTextVNode, toDisplayString, withModifiers, mergeModels } from "vue";
|
|
2
2
|
import { ElCard, ElAnchor, ElAnchorLink } from "element-plus";
|
|
3
|
+
import BadgeMark from "./BadgeMark.vue.mjs";
|
|
3
4
|
import _sfc_main$1 from "../slot-layout/SlotLayoutTemplate.vue.mjs";
|
|
4
5
|
import { getId } from "../../utils/id.mjs";
|
|
5
6
|
import { APP_PAGE_CONTENT_INSET } from "../../inject/key.mjs";
|
|
@@ -189,12 +190,19 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
189
190
|
class: "dc-tabs-tile__card"
|
|
190
191
|
}, {
|
|
191
192
|
header: withCtx(() => [
|
|
192
|
-
|
|
193
|
-
tab
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
193
|
+
createVNode(BadgeMark, {
|
|
194
|
+
badgeKey: tab.badgeKey
|
|
195
|
+
}, {
|
|
196
|
+
default: withCtx(() => [
|
|
197
|
+
renderSlot(_ctx.$slots, `header-${tab.key}`, {
|
|
198
|
+
tab,
|
|
199
|
+
active: tab.key === model.value
|
|
200
|
+
}, () => [
|
|
201
|
+
createTextVNode(toDisplayString(tab.title), 1)
|
|
202
|
+
], true)
|
|
203
|
+
]),
|
|
204
|
+
_: 2
|
|
205
|
+
}, 1032, ["badgeKey"])
|
|
198
206
|
]),
|
|
199
207
|
default: withCtx(() => [
|
|
200
208
|
renderSlot(_ctx.$slots, tab.key, {
|
|
@@ -230,7 +238,19 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
230
238
|
key: tab.key,
|
|
231
239
|
href: `#${paneId(index)}`,
|
|
232
240
|
title: tab.title
|
|
233
|
-
},
|
|
241
|
+
}, {
|
|
242
|
+
default: withCtx(() => [
|
|
243
|
+
createVNode(BadgeMark, {
|
|
244
|
+
badgeKey: tab.badgeKey
|
|
245
|
+
}, {
|
|
246
|
+
default: withCtx(() => [
|
|
247
|
+
createTextVNode(toDisplayString(tab.title), 1)
|
|
248
|
+
]),
|
|
249
|
+
_: 2
|
|
250
|
+
}, 1032, ["badgeKey"])
|
|
251
|
+
]),
|
|
252
|
+
_: 2
|
|
253
|
+
}, 1032, ["href", "title"]);
|
|
234
254
|
}), 128))
|
|
235
255
|
]),
|
|
236
256
|
_: 1
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { inject, computed, onScopeDispose, ref } from "vue";
|
|
2
|
+
import { CORE_BRIDGE_KEY } from "../../inject/key.mjs";
|
|
3
|
+
const BADGE_BUILTIN_PRESET = {
|
|
4
|
+
new: { text: "新", type: "success" },
|
|
5
|
+
updated: { text: "更新", type: "primary" },
|
|
6
|
+
beta: { text: "内测", type: "warning" },
|
|
7
|
+
// [MUST] ≤2 汉字:绝对定位下角标必然逃逸出宿主,逃逸量=角标宽−13px;
|
|
8
|
+
// 3 字的「开发中」宽 50px、逃逸 36px 会顶到下一个按钮,2 字「开发」宽 38px、逃逸 24px 安全。
|
|
9
|
+
wip: { text: "开发", type: "info" }
|
|
10
|
+
};
|
|
11
|
+
const BADGE_TICK_INTERVAL = 6e4;
|
|
12
|
+
const badgeNow = ref(Date.now());
|
|
13
|
+
let badgeTickTimer;
|
|
14
|
+
let badgeTickRefCount = 0;
|
|
15
|
+
function useBadgeNow() {
|
|
16
|
+
badgeTickRefCount += 1;
|
|
17
|
+
if (!badgeTickTimer) {
|
|
18
|
+
badgeNow.value = Date.now();
|
|
19
|
+
badgeTickTimer = setInterval(() => {
|
|
20
|
+
badgeNow.value = Date.now();
|
|
21
|
+
}, BADGE_TICK_INTERVAL);
|
|
22
|
+
}
|
|
23
|
+
onScopeDispose(() => {
|
|
24
|
+
badgeTickRefCount -= 1;
|
|
25
|
+
if (badgeTickRefCount <= 0) {
|
|
26
|
+
badgeTickRefCount = 0;
|
|
27
|
+
if (badgeTickTimer) {
|
|
28
|
+
clearInterval(badgeTickTimer);
|
|
29
|
+
badgeTickTimer = void 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return badgeNow;
|
|
34
|
+
}
|
|
35
|
+
function useBadgeResolved(getKey) {
|
|
36
|
+
const bridge = inject(CORE_BRIDGE_KEY, void 0);
|
|
37
|
+
const now = useBadgeNow();
|
|
38
|
+
const entry = computed(() => {
|
|
39
|
+
const key = getKey();
|
|
40
|
+
if (!key || !bridge) return void 0;
|
|
41
|
+
const hit = bridge.badge.marks.value[key];
|
|
42
|
+
if (!hit) return void 0;
|
|
43
|
+
if (!hit.expireAt) return hit;
|
|
44
|
+
if (hit.expireAt <= Math.max(now.value, Date.now())) return void 0;
|
|
45
|
+
return hit;
|
|
46
|
+
});
|
|
47
|
+
return computed(() => {
|
|
48
|
+
const hit = entry.value;
|
|
49
|
+
if (!hit) return void 0;
|
|
50
|
+
if (hit.kind === "count") {
|
|
51
|
+
return { value: hit.value, max: hit.max, type: "danger" };
|
|
52
|
+
}
|
|
53
|
+
if (hit.kind === "custom") {
|
|
54
|
+
return { value: hit.text, type: hit.type ?? "primary" };
|
|
55
|
+
}
|
|
56
|
+
const preset = BADGE_BUILTIN_PRESET[hit.kind];
|
|
57
|
+
return { value: preset.text, type: preset.type };
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
useBadgeResolved
|
|
62
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { defineComponent, openBlock, createBlock, unref, withCtx, createElementBlock, Fragment, renderList, resolveDynamicComponent, createCommentVNode, createElementVNode, toDisplayString } from "vue";
|
|
1
|
+
import { defineComponent, openBlock, createBlock, unref, withCtx, createElementBlock, Fragment, renderList, resolveDynamicComponent, createCommentVNode, createElementVNode, createVNode, createTextVNode, toDisplayString } from "vue";
|
|
2
2
|
import { ElSubMenu, ElMenuItem, ElIcon } from "element-plus";
|
|
3
|
+
import BadgeMark from "../display/BadgeMark.vue.mjs";
|
|
3
4
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
4
5
|
__name: "MenuItemSub",
|
|
5
6
|
props: {
|
|
@@ -19,7 +20,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
19
20
|
]),
|
|
20
21
|
_: 1
|
|
21
22
|
})) : createCommentVNode("", true),
|
|
22
|
-
createElementVNode("span", null,
|
|
23
|
+
createElementVNode("span", null, [
|
|
24
|
+
createVNode(unref(BadgeMark), {
|
|
25
|
+
badgeKey: __props.menu.path
|
|
26
|
+
}, {
|
|
27
|
+
default: withCtx(() => [
|
|
28
|
+
createTextVNode(toDisplayString(__props.menu.title), 1)
|
|
29
|
+
]),
|
|
30
|
+
_: 1
|
|
31
|
+
}, 8, ["badgeKey"])
|
|
32
|
+
])
|
|
23
33
|
]),
|
|
24
34
|
default: withCtx(() => [
|
|
25
35
|
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.menu.children, (item) => {
|
|
@@ -41,7 +51,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
41
51
|
]),
|
|
42
52
|
_: 2
|
|
43
53
|
}, 1024)) : createCommentVNode("", true),
|
|
44
|
-
createElementVNode("span", null,
|
|
54
|
+
createElementVNode("span", null, [
|
|
55
|
+
createVNode(unref(BadgeMark), {
|
|
56
|
+
badgeKey: item.path
|
|
57
|
+
}, {
|
|
58
|
+
default: withCtx(() => [
|
|
59
|
+
createTextVNode(toDisplayString(item.title), 1)
|
|
60
|
+
]),
|
|
61
|
+
_: 2
|
|
62
|
+
}, 1032, ["badgeKey"])
|
|
63
|
+
])
|
|
45
64
|
]),
|
|
46
65
|
_: 2
|
|
47
66
|
}, 1032, ["index"]))
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { defineComponent, ref, useAttrs, computed, openBlock, createBlock, unref, mergeProps, withCtx, createElementBlock, Fragment, renderList, resolveDynamicComponent, createCommentVNode, createElementVNode, toDisplayString } from "vue";
|
|
1
|
+
import { defineComponent, ref, useAttrs, computed, openBlock, createBlock, unref, mergeProps, withCtx, createElementBlock, Fragment, renderList, resolveDynamicComponent, createCommentVNode, createElementVNode, createVNode, createTextVNode, toDisplayString } from "vue";
|
|
2
2
|
import _sfc_main$1 from "./MenuItemSub.vue.mjs";
|
|
3
|
+
import BadgeMark from "../display/BadgeMark.vue.mjs";
|
|
3
4
|
import { useRoute } from "vue-router";
|
|
4
5
|
import { ElMenu, ElMenuItemGroup, ElMenuItem, ElIcon } from "element-plus";
|
|
5
6
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
@@ -73,10 +74,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
73
74
|
return openBlock(), createElementBlock(Fragment, {
|
|
74
75
|
key: menu.path
|
|
75
76
|
}, [
|
|
76
|
-
__props.groupMode && menu.children.length ? (openBlock(), createBlock(unref(ElMenuItemGroup), {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
__props.groupMode && menu.children.length ? (openBlock(), createBlock(unref(ElMenuItemGroup), { key: 0 }, {
|
|
78
|
+
title: withCtx(() => [
|
|
79
|
+
createVNode(unref(BadgeMark), {
|
|
80
|
+
badgeKey: menu.path
|
|
81
|
+
}, {
|
|
82
|
+
default: withCtx(() => [
|
|
83
|
+
createTextVNode(toDisplayString(menu.title), 1)
|
|
84
|
+
]),
|
|
85
|
+
_: 2
|
|
86
|
+
}, 1032, ["badgeKey"])
|
|
87
|
+
]),
|
|
80
88
|
default: withCtx(() => [
|
|
81
89
|
(openBlock(true), createElementBlock(Fragment, null, renderList(menu.children, (item) => {
|
|
82
90
|
return openBlock(), createElementBlock(Fragment, {
|
|
@@ -97,7 +105,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
97
105
|
]),
|
|
98
106
|
_: 2
|
|
99
107
|
}, 1024)) : createCommentVNode("", true),
|
|
100
|
-
createElementVNode("span", null,
|
|
108
|
+
createElementVNode("span", null, [
|
|
109
|
+
createVNode(unref(BadgeMark), {
|
|
110
|
+
badgeKey: item.path
|
|
111
|
+
}, {
|
|
112
|
+
default: withCtx(() => [
|
|
113
|
+
createTextVNode(toDisplayString(item.title), 1)
|
|
114
|
+
]),
|
|
115
|
+
_: 2
|
|
116
|
+
}, 1032, ["badgeKey"])
|
|
117
|
+
])
|
|
101
118
|
]),
|
|
102
119
|
_: 2
|
|
103
120
|
}, 1032, ["index"]))
|
|
@@ -105,7 +122,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
105
122
|
}), 128))
|
|
106
123
|
]),
|
|
107
124
|
_: 2
|
|
108
|
-
},
|
|
125
|
+
}, 1024)) : menu.children.length ? (openBlock(), createBlock(_sfc_main$1, {
|
|
109
126
|
key: 1,
|
|
110
127
|
menu,
|
|
111
128
|
MenuItemSub: _sfc_main$1
|
|
@@ -120,7 +137,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
120
137
|
]),
|
|
121
138
|
_: 2
|
|
122
139
|
}, 1024)) : createCommentVNode("", true),
|
|
123
|
-
createElementVNode("span", null,
|
|
140
|
+
createElementVNode("span", null, [
|
|
141
|
+
createVNode(unref(BadgeMark), {
|
|
142
|
+
badgeKey: menu.path
|
|
143
|
+
}, {
|
|
144
|
+
default: withCtx(() => [
|
|
145
|
+
createTextVNode(toDisplayString(menu.title), 1)
|
|
146
|
+
]),
|
|
147
|
+
_: 2
|
|
148
|
+
}, 1032, ["badgeKey"])
|
|
149
|
+
])
|
|
124
150
|
]),
|
|
125
151
|
_: 2
|
|
126
152
|
}, 1032, ["index"]))
|