yd-admin 0.1.5 → 0.1.7
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/README.md +327 -297
- package/dist/chunk-pbuEa-1d.js +13 -0
- package/dist/index.d.ts +1006 -454
- package/dist/index.js +848 -48
- package/dist/style.css +1054 -1012
- package/package.json +81 -78
package/dist/index.js
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-pbuEa-1d.js";
|
|
1
2
|
import { Fragment, Teleport, Transition, computed, createApp, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, getCurrentInstance, h, inject, isRef, mergeProps, nextTick, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, provide, reactive, ref, renderList, renderSlot, resolveComponent, resolveDynamicComponent, toDisplayString, unref, useCssVars, useSlots, vModelCheckbox, vModelDynamic, vModelText, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
|
|
2
3
|
import AsyncValidator from "async-validator";
|
|
3
4
|
import { createI18n } from "vue-i18n";
|
|
4
|
-
|
|
5
|
-
var __defProp = Object.defineProperty;
|
|
6
|
-
var __exportAll = (all, no_symbols) => {
|
|
7
|
-
let target = {};
|
|
8
|
-
for (var name in all) __defProp(target, name, {
|
|
9
|
-
get: all[name],
|
|
10
|
-
enumerable: true
|
|
11
|
-
});
|
|
12
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
-
return target;
|
|
14
|
-
};
|
|
15
|
-
//#endregion
|
|
5
|
+
import { createMemoryHistory, createRouter as createVueRouter, createWebHashHistory, createWebHistory } from "vue-router";
|
|
16
6
|
//#region src/utils/crypto.ts
|
|
17
7
|
/**
|
|
18
8
|
* Web Crypto API 加密工具
|
|
@@ -83,26 +73,99 @@ async function decrypt(base64Data, key) {
|
|
|
83
73
|
return null;
|
|
84
74
|
}
|
|
85
75
|
}
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region src/utils/secure-storage.ts
|
|
88
76
|
/**
|
|
89
|
-
*
|
|
90
|
-
* 混合加密策略:
|
|
91
|
-
* - sessionStorage: 使用动态会话密钥 (内存中,刷新即焚)
|
|
92
|
-
* - localStorage: 使用 Vite 环境变量密钥 (防普通篡改)
|
|
77
|
+
* 配置文件中的密钥缓存
|
|
93
78
|
*/
|
|
79
|
+
let configLocalStorageKey;
|
|
80
|
+
let configSessionStorageKey;
|
|
94
81
|
let sessionKey = null;
|
|
95
82
|
let storageReadyResolve = null;
|
|
96
83
|
const storageReady = new Promise((resolve) => {
|
|
97
84
|
storageReadyResolve = resolve;
|
|
98
85
|
});
|
|
86
|
+
let localStorageKey = null;
|
|
99
87
|
const ENV_KEY = import.meta.env.VITE_STORAGE_KEY || "yd-admin-default-key";
|
|
88
|
+
const ENV_SESSION_KEY = import.meta.env.VITE_SESSION_STORAGE_KEY || "yd-admin-session-key";
|
|
89
|
+
/**
|
|
90
|
+
* 从配置文件加载密钥
|
|
91
|
+
* @param filePath 配置文件路径,默认 config/storage.json
|
|
92
|
+
*/
|
|
93
|
+
async function loadKeyFromConfig(filePath) {
|
|
94
|
+
if (configLocalStorageKey) return {
|
|
95
|
+
local: configLocalStorageKey,
|
|
96
|
+
session: configSessionStorageKey || void 0
|
|
97
|
+
};
|
|
98
|
+
try {
|
|
99
|
+
const response = await fetch(filePath || "config/storage.json", { cache: "no-store" });
|
|
100
|
+
if (response.ok) {
|
|
101
|
+
const config = await response.json();
|
|
102
|
+
if (config.localStorageKey || config.sessionStorageKey || config.storageKey) {
|
|
103
|
+
configLocalStorageKey = config.storageKey || config.localStorageKey || void 0;
|
|
104
|
+
configSessionStorageKey = config.sessionStorageKey || config.storageKey || void 0;
|
|
105
|
+
return {
|
|
106
|
+
local: configLocalStorageKey,
|
|
107
|
+
session: configSessionStorageKey
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch {}
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 解析 localStorage 密钥(按优先级)
|
|
116
|
+
*/
|
|
117
|
+
async function resolveLocalKey(config) {
|
|
118
|
+
if (config?.localStorageKey || config?.storageKey) return {
|
|
119
|
+
key: config.localStorageKey || config.storageKey,
|
|
120
|
+
source: "init"
|
|
121
|
+
};
|
|
122
|
+
const configFilePath = config?.configFile;
|
|
123
|
+
const configKeys = await loadKeyFromConfig(configFilePath);
|
|
124
|
+
if (configKeys.local) return {
|
|
125
|
+
key: configKeys.local,
|
|
126
|
+
source: "config"
|
|
127
|
+
};
|
|
128
|
+
if (import.meta.env.VITE_STORAGE_KEY) return {
|
|
129
|
+
key: import.meta.env.VITE_STORAGE_KEY,
|
|
130
|
+
source: "env"
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
key: ENV_KEY,
|
|
134
|
+
source: "default"
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 解析 sessionStorage 密钥(按优先级)
|
|
139
|
+
*/
|
|
140
|
+
async function resolveSessionKey(config) {
|
|
141
|
+
if (config?.sessionStorageKey || config?.storageKey) return {
|
|
142
|
+
key: config.sessionStorageKey || config.storageKey,
|
|
143
|
+
source: "init"
|
|
144
|
+
};
|
|
145
|
+
const configFilePath = config?.configFile;
|
|
146
|
+
const configKeys = await loadKeyFromConfig(configFilePath);
|
|
147
|
+
if (configKeys.session) return {
|
|
148
|
+
key: configKeys.session,
|
|
149
|
+
source: "config"
|
|
150
|
+
};
|
|
151
|
+
if (import.meta.env.VITE_SESSION_STORAGE_KEY) return {
|
|
152
|
+
key: import.meta.env.VITE_SESSION_STORAGE_KEY,
|
|
153
|
+
source: "env"
|
|
154
|
+
};
|
|
155
|
+
return {
|
|
156
|
+
key: ENV_SESSION_KEY,
|
|
157
|
+
source: "dynamic"
|
|
158
|
+
};
|
|
159
|
+
}
|
|
100
160
|
/**
|
|
101
161
|
* 初始化安全存储
|
|
102
162
|
* 必须在应用启动时调用
|
|
163
|
+
* @param config 可选的初始化配置
|
|
103
164
|
*/
|
|
104
|
-
async function initSecureStorage() {
|
|
105
|
-
|
|
165
|
+
async function initSecureStorage(config) {
|
|
166
|
+
localStorageKey = (await resolveLocalKey(config)).key;
|
|
167
|
+
if ((await resolveSessionKey(config)).source === "dynamic") sessionKey = await generateSessionKey();
|
|
168
|
+
else sessionKey = null;
|
|
106
169
|
if (storageReadyResolve) {
|
|
107
170
|
storageReadyResolve();
|
|
108
171
|
storageReadyResolve = null;
|
|
@@ -113,32 +176,119 @@ async function initSecureStorage() {
|
|
|
113
176
|
*/
|
|
114
177
|
var SecureStorage = class {
|
|
115
178
|
storage;
|
|
116
|
-
|
|
179
|
+
storageType;
|
|
117
180
|
constructor(type) {
|
|
181
|
+
this.storageType = type;
|
|
118
182
|
this.storage = type === "local" ? localStorage : sessionStorage;
|
|
119
|
-
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* 获取存储类型
|
|
186
|
+
*/
|
|
187
|
+
get type() {
|
|
188
|
+
return this.storageType;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* 是否就绪
|
|
192
|
+
*/
|
|
193
|
+
get ready() {
|
|
194
|
+
return this.storageType === "session" ? !!sessionKey || !!ENV_SESSION_KEY : !!localStorageKey || !!ENV_KEY;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* 获取密钥(根据存储类型)
|
|
198
|
+
*/
|
|
199
|
+
getCurrentKey() {
|
|
200
|
+
if (this.storageType === "session") {
|
|
201
|
+
if (sessionKey) return sessionKey;
|
|
202
|
+
return ENV_SESSION_KEY;
|
|
203
|
+
}
|
|
204
|
+
return localStorageKey || ENV_KEY;
|
|
120
205
|
}
|
|
121
206
|
/**
|
|
122
207
|
* 异步写入
|
|
208
|
+
* @param key 存储键名
|
|
209
|
+
* @param value 存储值
|
|
210
|
+
* @param options 写入选项(可选)
|
|
123
211
|
*/
|
|
124
|
-
async setItem(key, value) {
|
|
125
|
-
|
|
212
|
+
async setItem(key, value, options) {
|
|
213
|
+
const currentKey = this.getCurrentKey();
|
|
214
|
+
if (this.storageType === "session" && !sessionKey && true) {
|
|
215
|
+
console.warn(`[secureStorage] sessionStorage key not ready, write "${key}" skipped`);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
126
218
|
try {
|
|
127
|
-
const
|
|
219
|
+
const now = Date.now();
|
|
220
|
+
const stored = {
|
|
221
|
+
data: value,
|
|
222
|
+
createdAt: now,
|
|
223
|
+
expiresAt: options?.expiresIn ? now + options.expiresIn * 1e3 : void 0
|
|
224
|
+
};
|
|
225
|
+
let json = JSON.stringify(stored);
|
|
226
|
+
if (options?.compress) {
|
|
227
|
+
const encoder = new TextEncoder();
|
|
228
|
+
const reader = new ReadableStream({ start(controller) {
|
|
229
|
+
controller.enqueue(encoder.encode(json));
|
|
230
|
+
controller.close();
|
|
231
|
+
} }).pipeThrough(new CompressionStream("gzip")).getReader();
|
|
232
|
+
const chunks = [];
|
|
233
|
+
while (true) {
|
|
234
|
+
const { done, value } = await reader.read();
|
|
235
|
+
if (done) break;
|
|
236
|
+
chunks.push(value);
|
|
237
|
+
}
|
|
238
|
+
const merged = new Uint8Array(chunks.reduce((a, c) => a + c.length, 0));
|
|
239
|
+
let off = 0;
|
|
240
|
+
for (const chunk of chunks) {
|
|
241
|
+
merged.set(chunk, off);
|
|
242
|
+
off += chunk.length;
|
|
243
|
+
}
|
|
244
|
+
json = btoa(String.fromCharCode(...merged));
|
|
245
|
+
}
|
|
246
|
+
const encrypted = await encrypt(json, currentKey);
|
|
128
247
|
this.storage.setItem(key, encrypted);
|
|
129
|
-
} catch {
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.warn(`[secureStorage] failed to encrypt "${key}":`, error);
|
|
250
|
+
}
|
|
130
251
|
}
|
|
131
252
|
/**
|
|
132
253
|
* 异步读取
|
|
133
254
|
*/
|
|
134
255
|
async getItem(key) {
|
|
135
|
-
|
|
256
|
+
const currentKey = this.getCurrentKey();
|
|
136
257
|
try {
|
|
137
258
|
const encrypted = this.storage.getItem(key);
|
|
138
259
|
if (!encrypted) return null;
|
|
139
|
-
|
|
140
|
-
if (!json)
|
|
141
|
-
|
|
260
|
+
let json = await decrypt(encrypted, currentKey);
|
|
261
|
+
if (!json) {
|
|
262
|
+
this.storage.removeItem(key);
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const decoded = atob(json);
|
|
267
|
+
const bytes = Uint8Array.from(decoded, (c) => c.charCodeAt(0));
|
|
268
|
+
const reader = new ReadableStream({ start(controller) {
|
|
269
|
+
controller.enqueue(bytes);
|
|
270
|
+
controller.close();
|
|
271
|
+
} }).pipeThrough(new DecompressionStream("gzip")).getReader();
|
|
272
|
+
const chunks = [];
|
|
273
|
+
while (true) {
|
|
274
|
+
const { done, value } = await reader.read();
|
|
275
|
+
if (done) break;
|
|
276
|
+
chunks.push(value);
|
|
277
|
+
}
|
|
278
|
+
const merged = new Uint8Array(chunks.reduce((a, c) => a + c.length, 0));
|
|
279
|
+
let off = 0;
|
|
280
|
+
for (const chunk of chunks) {
|
|
281
|
+
merged.set(chunk, off);
|
|
282
|
+
off += chunk.length;
|
|
283
|
+
}
|
|
284
|
+
json = new TextDecoder().decode(merged);
|
|
285
|
+
} catch {}
|
|
286
|
+
const stored = JSON.parse(json);
|
|
287
|
+
if (stored.expiresAt && Date.now() > stored.expiresAt) {
|
|
288
|
+
this.storage.removeItem(key);
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
return stored.data;
|
|
142
292
|
} catch {
|
|
143
293
|
this.storage.removeItem(key);
|
|
144
294
|
return null;
|
|
@@ -464,7 +614,7 @@ var export_helper_default = (sfc, props) => {
|
|
|
464
614
|
};
|
|
465
615
|
//#endregion
|
|
466
616
|
//#region src/components/base/button/button.vue
|
|
467
|
-
const _hoisted_1$
|
|
617
|
+
const _hoisted_1$45 = ["disabled", "type"];
|
|
468
618
|
const _hoisted_2$26 = {
|
|
469
619
|
key: 0,
|
|
470
620
|
class: "yd-button__loading"
|
|
@@ -526,10 +676,89 @@ var button_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ defin
|
|
|
526
676
|
"stroke-width": "3",
|
|
527
677
|
"stroke-dasharray": "31.4 31.4",
|
|
528
678
|
"stroke-linecap": "round"
|
|
529
|
-
})], -1)])])) : createCommentVNode("v-if", true), createElementVNode("span", _hoisted_3$17, [renderSlot(_ctx.$slots, "default", {}, void 0, true)])], 10, _hoisted_1$
|
|
679
|
+
})], -1)])])) : createCommentVNode("v-if", true), createElementVNode("span", _hoisted_3$17, [renderSlot(_ctx.$slots, "default", {}, void 0, true)])], 10, _hoisted_1$45);
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
}), [["__scopeId", "data-v-8a9a80ea"]]);
|
|
683
|
+
//#endregion
|
|
684
|
+
//#region src/components/base/icon/registry.ts
|
|
685
|
+
const iconRegistry = ref({
|
|
686
|
+
check: "<path d=\"M20 6L9 17l-5-5\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
|
|
687
|
+
close: "<path d=\"M18 6L6 18M6 6l12 12\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
|
|
688
|
+
arrowLeft: "<path d=\"M19 12H5m0 0l7 7m-7-7l7-7\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
|
|
689
|
+
arrowRight: "<path d=\"M5 12h14m0 0l-7-7m7 7l-7 7\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
|
|
690
|
+
chevronDown: "<path d=\"M6 9l6 6 6-6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
|
|
691
|
+
chevronUp: "<path d=\"M18 15l-6-6-6 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
|
|
692
|
+
search: "<path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
|
|
693
|
+
menu: "<path d=\"M4 6h16M4 12h16M4 18h16\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
|
|
694
|
+
user: "<path d=\"M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><circle cx=\"12\" cy=\"7\" r=\"4\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
|
|
695
|
+
settings: "<path d=\"M12 15a3 3 0 100-6 3 3 0 000 6z\" stroke=\"currentColor\" stroke-width=\"2\"/><path d=\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z\" stroke=\"currentColor\" stroke-width=\"2\"/>"
|
|
696
|
+
});
|
|
697
|
+
function registerIcon(name, svg) {
|
|
698
|
+
iconRegistry.value[name] = svg;
|
|
699
|
+
}
|
|
700
|
+
function getIcon(name) {
|
|
701
|
+
return iconRegistry.value[name] || "";
|
|
702
|
+
}
|
|
703
|
+
function getIconRegistry() {
|
|
704
|
+
return iconRegistry.value;
|
|
705
|
+
}
|
|
706
|
+
//#endregion
|
|
707
|
+
//#region src/components/base/icon/icon.vue
|
|
708
|
+
const _hoisted_1$44 = ["innerHTML"];
|
|
709
|
+
var icon_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ defineComponent({
|
|
710
|
+
name: "YdIcon",
|
|
711
|
+
inheritAttrs: false,
|
|
712
|
+
__name: "icon",
|
|
713
|
+
props: {
|
|
714
|
+
name: { default: "" },
|
|
715
|
+
size: { default: 16 },
|
|
716
|
+
color: { default: "currentColor" },
|
|
717
|
+
rotate: { default: 0 },
|
|
718
|
+
spin: {
|
|
719
|
+
type: Boolean,
|
|
720
|
+
default: false
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
emits: ["click"],
|
|
724
|
+
setup(__props, { emit: __emit }) {
|
|
725
|
+
const props = __props;
|
|
726
|
+
const emit = __emit;
|
|
727
|
+
function e(element) {
|
|
728
|
+
return `yd-icon__${element}`;
|
|
729
|
+
}
|
|
730
|
+
const svgContent = computed(() => {
|
|
731
|
+
if (!props.name) return "";
|
|
732
|
+
if (props.name.includes("<svg") || props.name.includes("<path")) return props.name;
|
|
733
|
+
return getIcon(props.name) || "";
|
|
734
|
+
});
|
|
735
|
+
const iconStyle = computed(() => {
|
|
736
|
+
const size = typeof props.size === "number" ? `${props.size}px` : props.size;
|
|
737
|
+
return {
|
|
738
|
+
width: size,
|
|
739
|
+
height: size,
|
|
740
|
+
color: props.color,
|
|
741
|
+
transform: props.rotate ? `rotate(${props.rotate}deg)` : void 0
|
|
742
|
+
};
|
|
743
|
+
});
|
|
744
|
+
function handleClick(event) {
|
|
745
|
+
emit("click", event);
|
|
746
|
+
}
|
|
747
|
+
return (_ctx, _cache) => {
|
|
748
|
+
return openBlock(), createElementBlock("span", mergeProps({
|
|
749
|
+
class: unref(cn)("yd-icon"),
|
|
750
|
+
style: iconStyle.value
|
|
751
|
+
}, _ctx.$attrs, { onClick: handleClick }), [createCommentVNode(" SVG Content "), svgContent.value ? (openBlock(), createElementBlock("svg", {
|
|
752
|
+
key: 0,
|
|
753
|
+
class: normalizeClass(e("svg")),
|
|
754
|
+
viewBox: "0 0 24 24",
|
|
755
|
+
fill: "none",
|
|
756
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
757
|
+
innerHTML: svgContent.value
|
|
758
|
+
}, null, 10, _hoisted_1$44)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" Slot Fallback "), renderSlot(_ctx.$slots, "default", {}, void 0, true)], 2112))], 16);
|
|
530
759
|
};
|
|
531
760
|
}
|
|
532
|
-
}), [["__scopeId", "data-v-
|
|
761
|
+
}), [["__scopeId", "data-v-20774ae9"]]);
|
|
533
762
|
//#endregion
|
|
534
763
|
//#region src/components/base/input/input.vue
|
|
535
764
|
const _hoisted_1$43 = [
|
|
@@ -3773,7 +4002,7 @@ var login_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ define
|
|
|
3773
4002
|
], 2)], 2)], 2)], 2);
|
|
3774
4003
|
};
|
|
3775
4004
|
}
|
|
3776
|
-
}), [["__scopeId", "data-v-
|
|
4005
|
+
}), [["__scopeId", "data-v-a965dc29"]]);
|
|
3777
4006
|
//#endregion
|
|
3778
4007
|
//#region src/components/base/login/login-centered.vue
|
|
3779
4008
|
const _hoisted_1$24 = ["fill"];
|
|
@@ -4243,7 +4472,7 @@ var login_centered_default = /* @__PURE__ */ export_helper_default(/* @__PURE__
|
|
|
4243
4472
|
], 2)], 2);
|
|
4244
4473
|
};
|
|
4245
4474
|
}
|
|
4246
|
-
}), [["__scopeId", "data-v-
|
|
4475
|
+
}), [["__scopeId", "data-v-be643e6b"]]);
|
|
4247
4476
|
//#endregion
|
|
4248
4477
|
//#region src/components/base/pin-input/pin-input.vue
|
|
4249
4478
|
const _hoisted_1$23 = [
|
|
@@ -6023,7 +6252,7 @@ var SchemaForm_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ d
|
|
|
6023
6252
|
]);
|
|
6024
6253
|
};
|
|
6025
6254
|
}
|
|
6026
|
-
}), [["__scopeId", "data-v-
|
|
6255
|
+
}), [["__scopeId", "data-v-624e5d24"]]);
|
|
6027
6256
|
var space_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ defineComponent({
|
|
6028
6257
|
name: "YdSpace",
|
|
6029
6258
|
__name: "space",
|
|
@@ -6039,11 +6268,11 @@ var space_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ define
|
|
|
6039
6268
|
setup(__props) {
|
|
6040
6269
|
const props = __props;
|
|
6041
6270
|
const sizeMap = {
|
|
6042
|
-
xs: "
|
|
6043
|
-
sm: "
|
|
6044
|
-
md: "
|
|
6045
|
-
lg: "
|
|
6046
|
-
xl: "
|
|
6271
|
+
xs: "var(--yd-spacing-xs)",
|
|
6272
|
+
sm: "var(--yd-spacing-sm)",
|
|
6273
|
+
md: "var(--yd-spacing-md)",
|
|
6274
|
+
lg: "var(--yd-spacing-base)",
|
|
6275
|
+
xl: "var(--yd-spacing-xl)"
|
|
6047
6276
|
};
|
|
6048
6277
|
const spaceClasses = computed(() => cn("yd-space", `yd-space--${props.direction}`, props.wrap && "yd-space--wrap", props.align && `yd-space--align-${props.align}`));
|
|
6049
6278
|
const spaceStyle = computed(() => {
|
|
@@ -6061,7 +6290,7 @@ var space_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ define
|
|
|
6061
6290
|
}, [renderSlot(_ctx.$slots, "default", {}, void 0, true)], 6);
|
|
6062
6291
|
};
|
|
6063
6292
|
}
|
|
6064
|
-
}), [["__scopeId", "data-v-
|
|
6293
|
+
}), [["__scopeId", "data-v-e6e2e015"]]);
|
|
6065
6294
|
var divider_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ defineComponent({
|
|
6066
6295
|
name: "YdDivider",
|
|
6067
6296
|
__name: "divider",
|
|
@@ -6572,7 +6801,7 @@ var menu_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ defineC
|
|
|
6572
6801
|
/**
|
|
6573
6802
|
* 检查用户是否有权限访问菜单项
|
|
6574
6803
|
*/
|
|
6575
|
-
function hasPermission(menuPermission, userPermissions) {
|
|
6804
|
+
function hasPermission$1(menuPermission, userPermissions) {
|
|
6576
6805
|
if (!menuPermission) return true;
|
|
6577
6806
|
const perms = Array.isArray(menuPermission) ? menuPermission : [menuPermission];
|
|
6578
6807
|
const userPerms = userPermissions.permissions || [];
|
|
@@ -6596,7 +6825,7 @@ function filterMenuItems(items, userPermissions) {
|
|
|
6596
6825
|
for (const item of items) {
|
|
6597
6826
|
if (item.hidden) continue;
|
|
6598
6827
|
if (userPermissions) {
|
|
6599
|
-
if (!hasPermission(item.permission, userPermissions)) continue;
|
|
6828
|
+
if (!hasPermission$1(item.permission, userPermissions)) continue;
|
|
6600
6829
|
if (!hasRole(item.roles, userPermissions)) continue;
|
|
6601
6830
|
}
|
|
6602
6831
|
const filteredChildren = item.children ? filterMenuItems(item.children, userPermissions) : void 0;
|
|
@@ -6679,7 +6908,7 @@ function searchMenuItems(items, query, userPermissions) {
|
|
|
6679
6908
|
for (const item of items) {
|
|
6680
6909
|
if (item.hidden) continue;
|
|
6681
6910
|
if (userPermissions) {
|
|
6682
|
-
if (!hasPermission(item.permission, userPermissions)) continue;
|
|
6911
|
+
if (!hasPermission$1(item.permission, userPermissions)) continue;
|
|
6683
6912
|
if (!hasRole(item.roles, userPermissions)) continue;
|
|
6684
6913
|
}
|
|
6685
6914
|
const labelMatch = item.label.toLowerCase().includes(searchTerm);
|
|
@@ -7558,7 +7787,7 @@ var tabs_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ defineC
|
|
|
7558
7787
|
], 2);
|
|
7559
7788
|
};
|
|
7560
7789
|
}
|
|
7561
|
-
}), [["__scopeId", "data-v-
|
|
7790
|
+
}), [["__scopeId", "data-v-65b74196"]]);
|
|
7562
7791
|
//#endregion
|
|
7563
7792
|
//#region src/components/navigation/dropdown/dropdown.vue
|
|
7564
7793
|
const _hoisted_1$17 = [
|
|
@@ -8771,7 +9000,7 @@ var card_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ defineC
|
|
|
8771
9000
|
], 16);
|
|
8772
9001
|
};
|
|
8773
9002
|
}
|
|
8774
|
-
}), [["__scopeId", "data-v-
|
|
9003
|
+
}), [["__scopeId", "data-v-264319fe"]]);
|
|
8775
9004
|
var tooltip_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ defineComponent({
|
|
8776
9005
|
name: "YdTooltip",
|
|
8777
9006
|
__name: "tooltip",
|
|
@@ -11877,6 +12106,78 @@ var context_menu_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */
|
|
|
11877
12106
|
};
|
|
11878
12107
|
}
|
|
11879
12108
|
}), [["__scopeId", "data-v-5a5029b0"]]);
|
|
12109
|
+
var loading_bar_default = /* @__PURE__ */ export_helper_default(/* @__PURE__ */ defineComponent({
|
|
12110
|
+
name: "YdLoadingBar",
|
|
12111
|
+
__name: "loading-bar",
|
|
12112
|
+
props: {
|
|
12113
|
+
percent: { default: 0 },
|
|
12114
|
+
status: { default: "normal" },
|
|
12115
|
+
size: { default: "md" },
|
|
12116
|
+
duration: { default: 200 },
|
|
12117
|
+
color: { default: "" }
|
|
12118
|
+
},
|
|
12119
|
+
setup(__props, { expose: __expose }) {
|
|
12120
|
+
const props = __props;
|
|
12121
|
+
const visible = ref(false);
|
|
12122
|
+
const currentPercent = ref(0);
|
|
12123
|
+
const loadingBarClasses = computed(() => cn("yd-loading-bar", `yd-loading-bar--${props.status}`, `yd-loading-bar--${props.size}`));
|
|
12124
|
+
const loadingBarStyle = computed(() => ({ "--yd-loading-bar-duration": `${props.duration}ms` }));
|
|
12125
|
+
const innerStyle = computed(() => {
|
|
12126
|
+
const width = `${currentPercent.value}%`;
|
|
12127
|
+
let background = props.color;
|
|
12128
|
+
if (!background) if (props.status === "success") background = "var(--yd-color-success)";
|
|
12129
|
+
else if (props.status === "error") background = "var(--yd-color-error)";
|
|
12130
|
+
else background = "var(--yd-color-primary-500)";
|
|
12131
|
+
return {
|
|
12132
|
+
width,
|
|
12133
|
+
background
|
|
12134
|
+
};
|
|
12135
|
+
});
|
|
12136
|
+
watch(() => props.percent, (newPercent) => {
|
|
12137
|
+
currentPercent.value = Math.min(100, Math.max(0, newPercent));
|
|
12138
|
+
});
|
|
12139
|
+
function start() {
|
|
12140
|
+
visible.value = true;
|
|
12141
|
+
currentPercent.value = 0;
|
|
12142
|
+
}
|
|
12143
|
+
function finish() {
|
|
12144
|
+
currentPercent.value = 100;
|
|
12145
|
+
setTimeout(() => {
|
|
12146
|
+
visible.value = false;
|
|
12147
|
+
setTimeout(() => {
|
|
12148
|
+
currentPercent.value = 0;
|
|
12149
|
+
}, props.duration);
|
|
12150
|
+
}, props.duration);
|
|
12151
|
+
}
|
|
12152
|
+
function setPercent(value) {
|
|
12153
|
+
visible.value = true;
|
|
12154
|
+
currentPercent.value = Math.min(100, Math.max(0, value));
|
|
12155
|
+
}
|
|
12156
|
+
function error() {
|
|
12157
|
+
visible.value = true;
|
|
12158
|
+
currentPercent.value = 100;
|
|
12159
|
+
}
|
|
12160
|
+
__expose({
|
|
12161
|
+
start,
|
|
12162
|
+
finish,
|
|
12163
|
+
setPercent,
|
|
12164
|
+
error
|
|
12165
|
+
});
|
|
12166
|
+
return (_ctx, _cache) => {
|
|
12167
|
+
return openBlock(), createBlock(Teleport, { to: "body" }, [createVNode(Transition, { name: "yd-loading-bar" }, {
|
|
12168
|
+
default: withCtx(() => [visible.value ? (openBlock(), createElementBlock("div", {
|
|
12169
|
+
key: 0,
|
|
12170
|
+
class: normalizeClass(loadingBarClasses.value),
|
|
12171
|
+
style: normalizeStyle(loadingBarStyle.value)
|
|
12172
|
+
}, [createElementVNode("div", {
|
|
12173
|
+
class: normalizeClass(_ctx.e("inner")),
|
|
12174
|
+
style: normalizeStyle(innerStyle.value)
|
|
12175
|
+
}, null, 6)], 6)) : createCommentVNode("v-if", true)]),
|
|
12176
|
+
_: 1
|
|
12177
|
+
})]);
|
|
12178
|
+
};
|
|
12179
|
+
}
|
|
12180
|
+
}), [["__scopeId", "data-v-a2e1e011"]]);
|
|
11880
12181
|
//#endregion
|
|
11881
12182
|
//#region src/components/config-provider/config-provider.vue
|
|
11882
12183
|
const _hoisted_1 = ["data-theme"];
|
|
@@ -12081,6 +12382,92 @@ function useLoginForm(options = {}) {
|
|
|
12081
12382
|
};
|
|
12082
12383
|
}
|
|
12083
12384
|
//#endregion
|
|
12385
|
+
//#region src/composables/use-loading-bar.ts
|
|
12386
|
+
let loadingBarApp = null;
|
|
12387
|
+
let loadingBarInstance = null;
|
|
12388
|
+
const mountingContainer = ref(null);
|
|
12389
|
+
/**
|
|
12390
|
+
* 创建 LoadingBar 实例
|
|
12391
|
+
*/
|
|
12392
|
+
function createLoadingBarInstance() {
|
|
12393
|
+
if (loadingBarApp) return loadingBarInstance;
|
|
12394
|
+
const container = document.createElement("div");
|
|
12395
|
+
container.id = "yd-loading-bar-container";
|
|
12396
|
+
document.body.appendChild(container);
|
|
12397
|
+
mountingContainer.value = container;
|
|
12398
|
+
loadingBarApp = createApp({ render() {
|
|
12399
|
+
return h(loading_bar_default);
|
|
12400
|
+
} });
|
|
12401
|
+
loadingBarInstance = loadingBarApp.mount(container);
|
|
12402
|
+
return loadingBarInstance;
|
|
12403
|
+
}
|
|
12404
|
+
/**
|
|
12405
|
+
* LoadingBar 组合式函数
|
|
12406
|
+
* 提供全局加载进度条控制方法
|
|
12407
|
+
* @returns LoadingBar 控制函数
|
|
12408
|
+
*/
|
|
12409
|
+
function useLoadingBar() {
|
|
12410
|
+
/**
|
|
12411
|
+
* 开始加载
|
|
12412
|
+
* @param options - 配置选项
|
|
12413
|
+
*/
|
|
12414
|
+
const start = (options) => {
|
|
12415
|
+
const instance = createLoadingBarInstance();
|
|
12416
|
+
if (instance) {
|
|
12417
|
+
instance.start();
|
|
12418
|
+
if (options?.size) instance.size = options.size;
|
|
12419
|
+
if (options?.color) instance.color = options.color;
|
|
12420
|
+
}
|
|
12421
|
+
};
|
|
12422
|
+
/**
|
|
12423
|
+
* 完成加载
|
|
12424
|
+
*/
|
|
12425
|
+
const finish = () => {
|
|
12426
|
+
if (loadingBarInstance) loadingBarInstance.finish();
|
|
12427
|
+
};
|
|
12428
|
+
/**
|
|
12429
|
+
* 设置进度百分比
|
|
12430
|
+
* @param percent - 进度百分比 (0-100)
|
|
12431
|
+
*/
|
|
12432
|
+
const setPercent = (percent) => {
|
|
12433
|
+
if (loadingBarInstance) loadingBarInstance.setPercent(percent);
|
|
12434
|
+
};
|
|
12435
|
+
/**
|
|
12436
|
+
* 显示错误状态
|
|
12437
|
+
*/
|
|
12438
|
+
const error = () => {
|
|
12439
|
+
if (loadingBarInstance) loadingBarInstance.error();
|
|
12440
|
+
};
|
|
12441
|
+
return {
|
|
12442
|
+
start,
|
|
12443
|
+
finish,
|
|
12444
|
+
setPercent,
|
|
12445
|
+
error
|
|
12446
|
+
};
|
|
12447
|
+
}
|
|
12448
|
+
const loadingBar = {
|
|
12449
|
+
start: (options) => {
|
|
12450
|
+
const instance = createLoadingBarInstance();
|
|
12451
|
+
if (instance) {
|
|
12452
|
+
instance.start();
|
|
12453
|
+
if (options?.size) instance.size = options.size;
|
|
12454
|
+
if (options?.color) instance.color = options.color;
|
|
12455
|
+
}
|
|
12456
|
+
},
|
|
12457
|
+
finish: () => {
|
|
12458
|
+
const instance = createLoadingBarInstance();
|
|
12459
|
+
if (instance) instance.finish();
|
|
12460
|
+
},
|
|
12461
|
+
setPercent: (percent) => {
|
|
12462
|
+
const instance = createLoadingBarInstance();
|
|
12463
|
+
if (instance) instance.setPercent(percent);
|
|
12464
|
+
},
|
|
12465
|
+
error: () => {
|
|
12466
|
+
const instance = createLoadingBarInstance();
|
|
12467
|
+
if (instance) instance.error();
|
|
12468
|
+
}
|
|
12469
|
+
};
|
|
12470
|
+
//#endregion
|
|
12084
12471
|
//#region src/hooks/use-loading.ts
|
|
12085
12472
|
/**
|
|
12086
12473
|
* Loading 状态管理 hook
|
|
@@ -12785,4 +13172,417 @@ function YdAdminResolver() {
|
|
|
12785
13172
|
};
|
|
12786
13173
|
}
|
|
12787
13174
|
//#endregion
|
|
12788
|
-
|
|
13175
|
+
//#region src/router/create-router.ts
|
|
13176
|
+
/**
|
|
13177
|
+
* Create Router - 路由工厂
|
|
13178
|
+
* 创建配置化的 Vue Router 实例
|
|
13179
|
+
*/
|
|
13180
|
+
/**
|
|
13181
|
+
* 安装路由守卫
|
|
13182
|
+
*/
|
|
13183
|
+
function setupGuards(router, guards) {
|
|
13184
|
+
const toGuardArray = (guard) => {
|
|
13185
|
+
return Array.isArray(guard) ? guard : [guard];
|
|
13186
|
+
};
|
|
13187
|
+
if (guards.beforeEach) {
|
|
13188
|
+
const guardArray = toGuardArray(guards.beforeEach);
|
|
13189
|
+
router.beforeEach(async (to, from, next) => {
|
|
13190
|
+
for (const guard of guardArray) await guard(to, from, next);
|
|
13191
|
+
});
|
|
13192
|
+
}
|
|
13193
|
+
if (guards.afterEach) {
|
|
13194
|
+
const guardArray = toGuardArray(guards.afterEach);
|
|
13195
|
+
router.afterEach((to, from) => {
|
|
13196
|
+
for (const guard of guardArray) guard(to, from, () => {});
|
|
13197
|
+
});
|
|
13198
|
+
}
|
|
13199
|
+
if (guards.beforeResolve) {
|
|
13200
|
+
const guardArray = toGuardArray(guards.beforeResolve);
|
|
13201
|
+
router.beforeResolve(async (to, from, next) => {
|
|
13202
|
+
for (const guard of guardArray) await guard(to, from, next);
|
|
13203
|
+
});
|
|
13204
|
+
}
|
|
13205
|
+
}
|
|
13206
|
+
/**
|
|
13207
|
+
* 创建路由历史
|
|
13208
|
+
*/
|
|
13209
|
+
function createRouterHistory(mode, base) {
|
|
13210
|
+
switch (mode) {
|
|
13211
|
+
case "hash": return createWebHashHistory(base);
|
|
13212
|
+
case "memory": return createMemoryHistory(base);
|
|
13213
|
+
default: return createWebHistory(base);
|
|
13214
|
+
}
|
|
13215
|
+
}
|
|
13216
|
+
/**
|
|
13217
|
+
* 创建路由实例
|
|
13218
|
+
* @param options 路由选项
|
|
13219
|
+
* @returns Vue Router 实例
|
|
13220
|
+
*/
|
|
13221
|
+
function createAppRouter(options = {}) {
|
|
13222
|
+
const { history = "html5", base, routes = [], guards = {}, strict = false, sensitive = false } = options;
|
|
13223
|
+
const router = createVueRouter({
|
|
13224
|
+
history: createRouterHistory(history, base),
|
|
13225
|
+
routes,
|
|
13226
|
+
strict,
|
|
13227
|
+
sensitive
|
|
13228
|
+
});
|
|
13229
|
+
setupGuards(router, guards);
|
|
13230
|
+
return router;
|
|
13231
|
+
}
|
|
13232
|
+
/**
|
|
13233
|
+
* 获取默认路由配置
|
|
13234
|
+
* @returns 默认路由数组
|
|
13235
|
+
*/
|
|
13236
|
+
function getDefaultRoutes() {
|
|
13237
|
+
return [{
|
|
13238
|
+
path: "/",
|
|
13239
|
+
redirect: "/dashboard",
|
|
13240
|
+
meta: { ignoreAuth: true }
|
|
13241
|
+
}];
|
|
13242
|
+
}
|
|
13243
|
+
/**
|
|
13244
|
+
* 获取 404 路由
|
|
13245
|
+
* @param path 404 页面路径
|
|
13246
|
+
* @returns 404 路由配置
|
|
13247
|
+
*/
|
|
13248
|
+
function getNotFoundRoute(path = "/404") {
|
|
13249
|
+
return {
|
|
13250
|
+
path: "/:pathMatch(.*)*",
|
|
13251
|
+
redirect: path,
|
|
13252
|
+
meta: { ignoreAuth: true }
|
|
13253
|
+
};
|
|
13254
|
+
}
|
|
13255
|
+
//#endregion
|
|
13256
|
+
//#region src/router/guards/auth.ts
|
|
13257
|
+
/**
|
|
13258
|
+
* 创建认证守卫
|
|
13259
|
+
* @param options 认证守卫选项
|
|
13260
|
+
* @returns 认证守卫函数
|
|
13261
|
+
*/
|
|
13262
|
+
function createAuthGuard(options) {
|
|
13263
|
+
const { checker, loginName = "Login", ignore } = options;
|
|
13264
|
+
return async (to, _from, next) => {
|
|
13265
|
+
if (ignore?.(to)) {
|
|
13266
|
+
next();
|
|
13267
|
+
return;
|
|
13268
|
+
}
|
|
13269
|
+
if (to.meta?.requiresAuth === false || to.meta?.ignoreAuth === true) {
|
|
13270
|
+
next();
|
|
13271
|
+
return;
|
|
13272
|
+
}
|
|
13273
|
+
if (!await checker()) {
|
|
13274
|
+
const redirect = to.fullPath;
|
|
13275
|
+
next({
|
|
13276
|
+
name: loginName,
|
|
13277
|
+
query: { redirect }
|
|
13278
|
+
});
|
|
13279
|
+
return;
|
|
13280
|
+
}
|
|
13281
|
+
next();
|
|
13282
|
+
};
|
|
13283
|
+
}
|
|
13284
|
+
/**
|
|
13285
|
+
* 默认认证守卫选项
|
|
13286
|
+
*/
|
|
13287
|
+
const defaultAuthGuardOptions = {
|
|
13288
|
+
loginPath: "/login",
|
|
13289
|
+
loginName: "Login",
|
|
13290
|
+
ignore: (to) => Boolean(to.meta?.ignoreAuth)
|
|
13291
|
+
};
|
|
13292
|
+
//#endregion
|
|
13293
|
+
//#region src/router/guards/permission.ts
|
|
13294
|
+
/**
|
|
13295
|
+
* 创建权限守卫
|
|
13296
|
+
* @param options 权限守卫选项
|
|
13297
|
+
* @returns 权限守卫函数
|
|
13298
|
+
*/
|
|
13299
|
+
function createPermissionGuard(options) {
|
|
13300
|
+
const { checker, forbiddenName = "Forbidden" } = options;
|
|
13301
|
+
return async (to, _from, next) => {
|
|
13302
|
+
const requiredPermission = to.meta?.permission;
|
|
13303
|
+
if (!requiredPermission) {
|
|
13304
|
+
next();
|
|
13305
|
+
return;
|
|
13306
|
+
}
|
|
13307
|
+
const userPermissions = {
|
|
13308
|
+
roles: [],
|
|
13309
|
+
permissions: []
|
|
13310
|
+
};
|
|
13311
|
+
if (requiredPermission) {
|
|
13312
|
+
if (!await checker(requiredPermission, userPermissions)) {
|
|
13313
|
+
next({ name: forbiddenName });
|
|
13314
|
+
return;
|
|
13315
|
+
}
|
|
13316
|
+
}
|
|
13317
|
+
next();
|
|
13318
|
+
};
|
|
13319
|
+
}
|
|
13320
|
+
/**
|
|
13321
|
+
* 创建角色守卫
|
|
13322
|
+
* @param options 角色守卫选项
|
|
13323
|
+
* @returns 角色守卫函数
|
|
13324
|
+
*/
|
|
13325
|
+
function createRoleGuard(options) {
|
|
13326
|
+
const { checker, forbiddenPath = "/403" } = options;
|
|
13327
|
+
return async (to, _from, next) => {
|
|
13328
|
+
const requiredRoles = to.meta?.roles;
|
|
13329
|
+
if (!requiredRoles || requiredRoles.length === 0) {
|
|
13330
|
+
next();
|
|
13331
|
+
return;
|
|
13332
|
+
}
|
|
13333
|
+
if (!await checker(requiredRoles, {
|
|
13334
|
+
roles: [],
|
|
13335
|
+
permissions: []
|
|
13336
|
+
})) {
|
|
13337
|
+
next({ path: forbiddenPath });
|
|
13338
|
+
return;
|
|
13339
|
+
}
|
|
13340
|
+
next();
|
|
13341
|
+
};
|
|
13342
|
+
}
|
|
13343
|
+
//#endregion
|
|
13344
|
+
//#region src/router/composables/use-dynamic-route.ts
|
|
13345
|
+
/**
|
|
13346
|
+
* Use Dynamic Route - 动态路由管理组合式函数
|
|
13347
|
+
* 提供动态添加/移除路由的能力
|
|
13348
|
+
*/
|
|
13349
|
+
/** 路由实例 ref - 使用 any 类型避免 Vue Router 5 类型不兼容问题 */
|
|
13350
|
+
const routerInstance = ref(null);
|
|
13351
|
+
/**
|
|
13352
|
+
* 设置路由实例
|
|
13353
|
+
* @param router Vue Router 实例
|
|
13354
|
+
*/
|
|
13355
|
+
function setRouter(router) {
|
|
13356
|
+
routerInstance.value = router;
|
|
13357
|
+
}
|
|
13358
|
+
/**
|
|
13359
|
+
* 获取当前路由实例
|
|
13360
|
+
*/
|
|
13361
|
+
function getRouterInstance() {
|
|
13362
|
+
return routerInstance.value;
|
|
13363
|
+
}
|
|
13364
|
+
/**
|
|
13365
|
+
* 添加单条路由
|
|
13366
|
+
* @param route 路由配置
|
|
13367
|
+
* @param options 添加选项
|
|
13368
|
+
* @returns 是否成功
|
|
13369
|
+
*/
|
|
13370
|
+
function addRoute(route, options = {}) {
|
|
13371
|
+
const router = routerInstance.value;
|
|
13372
|
+
if (!router) {
|
|
13373
|
+
console.warn("[useDynamicRoute] Router not initialized");
|
|
13374
|
+
return false;
|
|
13375
|
+
}
|
|
13376
|
+
const { parentName, overwrite = false } = options;
|
|
13377
|
+
try {
|
|
13378
|
+
if (parentName) router.addRoute(parentName, route);
|
|
13379
|
+
else if (overwrite) router.addRoute(route);
|
|
13380
|
+
else if (!router.getRoutes().find((r) => r.name === route.name)) router.addRoute(route);
|
|
13381
|
+
return true;
|
|
13382
|
+
} catch (error) {
|
|
13383
|
+
console.error("[useDynamicRoute] Failed to add route:", error);
|
|
13384
|
+
return false;
|
|
13385
|
+
}
|
|
13386
|
+
}
|
|
13387
|
+
/**
|
|
13388
|
+
* 批量添加路由
|
|
13389
|
+
* @param routes 路由数组
|
|
13390
|
+
* @param options 添加选项
|
|
13391
|
+
* @returns 成功数量
|
|
13392
|
+
*/
|
|
13393
|
+
function addRoutes(routes, options = {}) {
|
|
13394
|
+
let successCount = 0;
|
|
13395
|
+
for (const route of routes) if (addRoute(route, options)) successCount++;
|
|
13396
|
+
return successCount;
|
|
13397
|
+
}
|
|
13398
|
+
/**
|
|
13399
|
+
* 移除路由
|
|
13400
|
+
* @param name 路由名称
|
|
13401
|
+
* @returns 是否成功
|
|
13402
|
+
*/
|
|
13403
|
+
function removeRoute(name) {
|
|
13404
|
+
const router = routerInstance.value;
|
|
13405
|
+
if (!router) return false;
|
|
13406
|
+
try {
|
|
13407
|
+
router.removeRoute(name);
|
|
13408
|
+
return true;
|
|
13409
|
+
} catch {
|
|
13410
|
+
return false;
|
|
13411
|
+
}
|
|
13412
|
+
}
|
|
13413
|
+
/**
|
|
13414
|
+
* 获取所有路由
|
|
13415
|
+
*/
|
|
13416
|
+
function getRoutes() {
|
|
13417
|
+
return routerInstance.value?.getRoutes() ?? [];
|
|
13418
|
+
}
|
|
13419
|
+
/**
|
|
13420
|
+
* 获取当前路由信息
|
|
13421
|
+
*/
|
|
13422
|
+
function getCurrentRoute() {
|
|
13423
|
+
return routerInstance.value?.currentRoute;
|
|
13424
|
+
}
|
|
13425
|
+
/**
|
|
13426
|
+
* 获取当前路径
|
|
13427
|
+
*/
|
|
13428
|
+
function getCurrentPath() {
|
|
13429
|
+
return routerInstance.value?.currentRoute?.fullPath;
|
|
13430
|
+
}
|
|
13431
|
+
/**
|
|
13432
|
+
* 获取当前路由名称
|
|
13433
|
+
*/
|
|
13434
|
+
function getCurrentName() {
|
|
13435
|
+
const name = routerInstance.value?.currentRoute.name;
|
|
13436
|
+
return typeof name === "string" ? name : void 0;
|
|
13437
|
+
}
|
|
13438
|
+
/**
|
|
13439
|
+
* 导航到指定路径
|
|
13440
|
+
* @param path 路径
|
|
13441
|
+
* @param query 查询参数
|
|
13442
|
+
*/
|
|
13443
|
+
function push(path, query) {
|
|
13444
|
+
return routerInstance.value?.push({
|
|
13445
|
+
path,
|
|
13446
|
+
query
|
|
13447
|
+
});
|
|
13448
|
+
}
|
|
13449
|
+
/**
|
|
13450
|
+
* 替换当前路径
|
|
13451
|
+
* @param path 路径
|
|
13452
|
+
*/
|
|
13453
|
+
function replace(path) {
|
|
13454
|
+
return routerInstance.value?.replace({ path });
|
|
13455
|
+
}
|
|
13456
|
+
//#endregion
|
|
13457
|
+
//#region src/router/utils/route-helpers.ts
|
|
13458
|
+
/**
|
|
13459
|
+
* 过滤菜单项(根据权限)
|
|
13460
|
+
* @param items 菜单项数组
|
|
13461
|
+
* @param permissions 用户权限
|
|
13462
|
+
* @returns 过滤后的菜单项
|
|
13463
|
+
*/
|
|
13464
|
+
function filterMenuItems$1(items, permissions) {
|
|
13465
|
+
if (!permissions) return items;
|
|
13466
|
+
const { roles = [], permissions: perms = [] } = permissions;
|
|
13467
|
+
return items.filter((item) => {
|
|
13468
|
+
if (item.roles && item.roles.length > 0) {
|
|
13469
|
+
if (!item.roles.some((role) => roles.includes(role))) return false;
|
|
13470
|
+
}
|
|
13471
|
+
if (item.permission) {
|
|
13472
|
+
if (!(Array.isArray(item.permission) ? item.permission : [item.permission]).some((p) => perms.includes(p))) return false;
|
|
13473
|
+
}
|
|
13474
|
+
if (item.children && item.children.length > 0) item.children = filterMenuItems$1(item.children, permissions);
|
|
13475
|
+
return true;
|
|
13476
|
+
});
|
|
13477
|
+
}
|
|
13478
|
+
/**
|
|
13479
|
+
* 将 MenuItem 数组转换为路由记录
|
|
13480
|
+
* @param items 菜单项数组
|
|
13481
|
+
* @param options 选项
|
|
13482
|
+
* @returns 路由记录数组
|
|
13483
|
+
*/
|
|
13484
|
+
function menuToRoutes$1(items, options = {}) {
|
|
13485
|
+
const { basePath = "", userPermissions } = options;
|
|
13486
|
+
return (userPermissions ? filterMenuItems$1(items, userPermissions) : items).map((item) => {
|
|
13487
|
+
const route = {
|
|
13488
|
+
path: item.path || item.key,
|
|
13489
|
+
name: item.key,
|
|
13490
|
+
meta: {
|
|
13491
|
+
title: item.label,
|
|
13492
|
+
icon: item.icon,
|
|
13493
|
+
permission: item.permission,
|
|
13494
|
+
roles: item.roles,
|
|
13495
|
+
keepAlive: true
|
|
13496
|
+
}
|
|
13497
|
+
};
|
|
13498
|
+
if (item.children && item.children.length > 0) route.children = menuToRoutes$1(item.children, {
|
|
13499
|
+
basePath: `${basePath}/${route.path}`,
|
|
13500
|
+
userPermissions
|
|
13501
|
+
});
|
|
13502
|
+
return route;
|
|
13503
|
+
});
|
|
13504
|
+
}
|
|
13505
|
+
/**
|
|
13506
|
+
* 检查路由是否需要认证
|
|
13507
|
+
* @param route 路由记录
|
|
13508
|
+
* @returns 是否需要认证
|
|
13509
|
+
*/
|
|
13510
|
+
function requiresAuth(route) {
|
|
13511
|
+
return route.meta?.requiresAuth !== false;
|
|
13512
|
+
}
|
|
13513
|
+
/**
|
|
13514
|
+
* 检查路由是否有权限
|
|
13515
|
+
* @param route 路由记录
|
|
13516
|
+
* @param permissions 用户权限
|
|
13517
|
+
* @returns 是否有权限
|
|
13518
|
+
*/
|
|
13519
|
+
function hasPermission(route, permissions) {
|
|
13520
|
+
const meta = route.meta;
|
|
13521
|
+
if (meta?.permission) {
|
|
13522
|
+
const required = Array.isArray(meta.permission) ? meta.permission : [meta.permission];
|
|
13523
|
+
const userPerms = permissions?.permissions || [];
|
|
13524
|
+
return required.some((p) => userPerms.includes(p));
|
|
13525
|
+
}
|
|
13526
|
+
if (meta?.roles) {
|
|
13527
|
+
const required = meta.roles;
|
|
13528
|
+
const userRoles = permissions?.roles || [];
|
|
13529
|
+
return required.some((r) => userRoles.includes(r));
|
|
13530
|
+
}
|
|
13531
|
+
return true;
|
|
13532
|
+
}
|
|
13533
|
+
/**
|
|
13534
|
+
* 生成面包屑
|
|
13535
|
+
* @param routes 路由数组
|
|
13536
|
+
* @param currentPath 当前路径
|
|
13537
|
+
* @returns 面包屑数组
|
|
13538
|
+
*/
|
|
13539
|
+
function generateBreadcrumbs(routes, currentPath) {
|
|
13540
|
+
const breadcrumbs = [];
|
|
13541
|
+
const findRoute = (routeList, path) => {
|
|
13542
|
+
for (const route of routeList) {
|
|
13543
|
+
if (route.path === path) return route;
|
|
13544
|
+
if (route.children) {
|
|
13545
|
+
const found = findRoute(route.children, path);
|
|
13546
|
+
if (found) return found;
|
|
13547
|
+
}
|
|
13548
|
+
}
|
|
13549
|
+
};
|
|
13550
|
+
const route = findRoute(routes, currentPath);
|
|
13551
|
+
if (route) breadcrumbs.push({
|
|
13552
|
+
label: route.meta?.title || route.name || "",
|
|
13553
|
+
path: route.path
|
|
13554
|
+
});
|
|
13555
|
+
return breadcrumbs;
|
|
13556
|
+
}
|
|
13557
|
+
//#endregion
|
|
13558
|
+
//#region src/router/index.ts
|
|
13559
|
+
var router_exports = /* @__PURE__ */ __exportAll({
|
|
13560
|
+
addRoute: () => addRoute,
|
|
13561
|
+
addRoutes: () => addRoutes,
|
|
13562
|
+
createAppRouter: () => createAppRouter,
|
|
13563
|
+
createAuthGuard: () => createAuthGuard,
|
|
13564
|
+
createMemoryHistory: () => createMemoryHistory,
|
|
13565
|
+
createPermissionGuard: () => createPermissionGuard,
|
|
13566
|
+
createRoleGuard: () => createRoleGuard,
|
|
13567
|
+
createWebHashHistory: () => createWebHashHistory,
|
|
13568
|
+
createWebHistory: () => createWebHistory,
|
|
13569
|
+
defaultAuthGuardOptions: () => defaultAuthGuardOptions,
|
|
13570
|
+
filterMenuItems: () => filterMenuItems$1,
|
|
13571
|
+
generateBreadcrumbs: () => generateBreadcrumbs,
|
|
13572
|
+
getCurrentName: () => getCurrentName,
|
|
13573
|
+
getCurrentPath: () => getCurrentPath,
|
|
13574
|
+
getCurrentRoute: () => getCurrentRoute,
|
|
13575
|
+
getDefaultRoutes: () => getDefaultRoutes,
|
|
13576
|
+
getNotFoundRoute: () => getNotFoundRoute,
|
|
13577
|
+
getRouterInstance: () => getRouterInstance,
|
|
13578
|
+
getRoutes: () => getRoutes,
|
|
13579
|
+
hasPermission: () => hasPermission,
|
|
13580
|
+
menuToRoutes: () => menuToRoutes$1,
|
|
13581
|
+
push: () => push,
|
|
13582
|
+
removeRoute: () => removeRoute,
|
|
13583
|
+
replace: () => replace,
|
|
13584
|
+
requiresAuth: () => requiresAuth,
|
|
13585
|
+
setRouter: () => setRouter
|
|
13586
|
+
});
|
|
13587
|
+
//#endregion
|
|
13588
|
+
export { ANIMATION_DURATION, COMPONENT_PREFIX, CSS_PREFIX, DEBOUNCE_DEFAULTS, DEBOUNCE_DELAY, DEFAULT_LAYOUT_SIZE, Message, Notification, THROTTLE_DEFAULTS, THROTTLE_DELAY, YdAdminResolver, anchor_default as YdAnchor, auto_complete_default as YdAutoComplete, avatar_default as YdAvatar, badge_default as YdBadge, breadcrumb_default as YdBreadcrumb, button_default as YdButton, captcha_default as YdCaptcha, card_default as YdCard, cascader_default as YdCascader, checkbox_default as YdCheckbox, checkbox_group_default as YdCheckboxGroup, collapse_default as YdCollapse, color_picker_default as YdColorPicker, config_provider_default as YdConfigProvider, context_menu_default as YdContextMenu, date_picker_default as YdDatePicker, date_range_picker_default as YdDateRangePicker, divider_default as YdDivider, drawer_default as YdDrawer, dropdown_default as YdDropdown, empty_default as YdEmpty, form_default as YdForm, form_item_default as YdFormItem, icon_default as YdIcon, image_default as YdImage, image_preview_group_default as YdImagePreviewGroup, input_default as YdInput, input_number_default as YdInputNumber, layout_default as YdLayout, layout_content_default as YdLayoutContent, layout_header_default as YdLayoutHeader, layout_sidebar_default as YdLayoutSidebar, list_default as YdList, loading_bar_default as YdLoadingBar, login_default as YdLogin, login_centered_default as YdLoginCentered, menu_default as YdMenu, modal_default as YdModal, pagination_default as YdPagination, pin_input_default as YdPinInput, popconfirm_default as YdPopconfirm, progress_default as YdProgress, radio_default as YdRadio, radio_group_default as YdRadioGroup, rate_default as YdRate, result_default as YdResult, router_exports as YdRouter, SchemaForm_default as YdSchemaForm, select_default as YdSelect, skeleton_default as YdSkeleton, slider_default as YdSlider, space_default as YdSpace, spin_default as YdSpin, statistic_default as YdStatistic, steps_default as YdSteps, switch_default as YdSwitch, table_default as YdTable, tabs_default as YdTabs, tag_default as YdTag, textarea_default as YdTextarea, time_picker_default as YdTimePicker, timeline_default as YdTimeline, tooltip_default as YdTooltip, transfer_default as YdTransfer, tree_default as YdTree, tree_select_default as YdTreeSelect, upload_default as YdUpload, Z_INDEX, buildBreadcrumb, changeLocale, checkRoutePermission, cn, convertToSimpleRoute, debounce, decrypt, deepClone, dt, dynamicRouter, encrypt, filterMenuItems, findMenuItem, findMenuPath, flattenMenuItems, generateId, generateRouteTitle, generateSessionKey, getBreadcrumbPaths, getCurrentLocale, getIcon, getIconRegistry, i18n, initSecureStorage, isArray, isDate, isEmpty, isEmptyObject, isFunction, isObject, isPathMatch, isPromise, joinPath, loadingBar, menuToRoutes, nf, normalizePath, registerIcon, registerLazyLocale, searchMenuItems, secureLocal, secureSession, secureStoragePlugin, setLocale, setupI18n, supportedLocales, t, tc, themes, throttle, useConfig, useFormSchema, useFormValidate, useLoading, useLoadingBar, useLoginForm, useNamespace };
|