@litianxiang/portal-core 0.1.1
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/dist/index.cjs +183 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +155 -0
- package/package.json +24 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
createAppRouter: () => createAppRouter
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/router.ts
|
|
28
|
+
var import_vue_router = require("vue-router");
|
|
29
|
+
var import_meta = {};
|
|
30
|
+
function createAppRouter(options) {
|
|
31
|
+
const { staticRoutes, getUserStore, getTabStore, getFirstPage, authLoginUrl } = options;
|
|
32
|
+
const router = (0, import_vue_router.createRouter)({
|
|
33
|
+
history: (0, import_vue_router.createWebHashHistory)(),
|
|
34
|
+
routes: staticRoutes
|
|
35
|
+
});
|
|
36
|
+
const AUTH_LOGIN_URL = authLoginUrl || `${window.location.origin}/auth/#/login`;
|
|
37
|
+
const modules = import_meta.glob("@/views/**/*.vue");
|
|
38
|
+
const registeredPaths = /* @__PURE__ */ new Set();
|
|
39
|
+
const resolveRouteAndView = (item) => {
|
|
40
|
+
const [rawPath] = (item.path || "").split("?");
|
|
41
|
+
const normalizedPath = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
|
|
42
|
+
const routePath = normalizedPath.slice(1);
|
|
43
|
+
const candidates = [
|
|
44
|
+
`/main${normalizedPath}`,
|
|
45
|
+
// /views/main/system/user.vue
|
|
46
|
+
`${normalizedPath}`
|
|
47
|
+
// /views/system/user.vue 或 /views/kq/leave.vue
|
|
48
|
+
];
|
|
49
|
+
let viewKey = "";
|
|
50
|
+
for (const viewPath of candidates) {
|
|
51
|
+
const key = `/src/views${viewPath}.vue`;
|
|
52
|
+
if (key in modules) {
|
|
53
|
+
viewKey = key;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (!viewKey) {
|
|
58
|
+
const fallbackPath = `/main${normalizedPath}`;
|
|
59
|
+
viewKey = `/src/views${fallbackPath}.vue`;
|
|
60
|
+
}
|
|
61
|
+
return { routePath, viewKey };
|
|
62
|
+
};
|
|
63
|
+
const transformRoutes = (menuItems) => {
|
|
64
|
+
const routes = [];
|
|
65
|
+
for (const item of menuItems) {
|
|
66
|
+
if (item.category === "button") continue;
|
|
67
|
+
const { routePath, viewKey } = resolveRouteAndView(item);
|
|
68
|
+
const isPage = item.category === "page" || item.category === "flow-page";
|
|
69
|
+
if (!registeredPaths.has(routePath)) {
|
|
70
|
+
registeredPaths.add(routePath);
|
|
71
|
+
routes.push({
|
|
72
|
+
path: routePath,
|
|
73
|
+
name: `menu_${item.id}`,
|
|
74
|
+
component: isPage ? modules[viewKey] : void 0,
|
|
75
|
+
meta: {
|
|
76
|
+
id: item.id,
|
|
77
|
+
parent_id: item.parent_id,
|
|
78
|
+
icon: item.icon,
|
|
79
|
+
category: item.category,
|
|
80
|
+
keepAlive: true,
|
|
81
|
+
title: item.name,
|
|
82
|
+
fullPath: item.path
|
|
83
|
+
},
|
|
84
|
+
children: item.children ? transformRoutes(item.children) : []
|
|
85
|
+
});
|
|
86
|
+
} else if (item.children?.length) {
|
|
87
|
+
routes.push(...transformRoutes(item.children));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return routes;
|
|
91
|
+
};
|
|
92
|
+
const addDynamicRoutes = (menuData) => {
|
|
93
|
+
const dynamicRoutes = transformRoutes(menuData);
|
|
94
|
+
dynamicRoutes.forEach((route) => {
|
|
95
|
+
router.addRoute("main", route);
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
const clearDynamicRoutes = () => {
|
|
99
|
+
const routes = router.getRoutes();
|
|
100
|
+
routes.forEach((route) => {
|
|
101
|
+
if (route.name?.toString().startsWith("menu_") && router.hasRoute(route.name)) {
|
|
102
|
+
router.removeRoute(route.name);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
registeredPaths.clear();
|
|
106
|
+
};
|
|
107
|
+
let justLoadedMenu = false;
|
|
108
|
+
router.beforeEach(async (to, _from, next) => {
|
|
109
|
+
const userStore = getUserStore();
|
|
110
|
+
let access_token = userStore.getUserAccessToken;
|
|
111
|
+
if (!access_token && typeof window !== "undefined") {
|
|
112
|
+
const restored = userStore.syncFromAuthStore();
|
|
113
|
+
if (restored) {
|
|
114
|
+
access_token = userStore.getUserAccessToken;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (!access_token) {
|
|
118
|
+
const currentUrl = encodeURIComponent(window.location.href);
|
|
119
|
+
window.location.href = `${AUTH_LOGIN_URL}?redirect=${currentUrl}`;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (justLoadedMenu) {
|
|
123
|
+
justLoadedMenu = false;
|
|
124
|
+
next();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (userStore.isMenuLoaded && (to.path === "/" || to.path === "")) {
|
|
128
|
+
const tabStore = getTabStore();
|
|
129
|
+
tabStore.clearAll();
|
|
130
|
+
const allMenu = userStore.getUserALLMenu;
|
|
131
|
+
if (allMenu && allMenu.length > 0) {
|
|
132
|
+
const firstPage = getFirstPage(allMenu);
|
|
133
|
+
if (firstPage) {
|
|
134
|
+
const [basePath, queryString] = firstPage.split("?");
|
|
135
|
+
const query = {};
|
|
136
|
+
if (queryString) {
|
|
137
|
+
queryString.split("&").forEach((param) => {
|
|
138
|
+
const [key, value] = param.split("=");
|
|
139
|
+
if (key) query[key] = value || "";
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
next({ path: basePath, query, replace: true });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (!userStore.isMenuLoaded) {
|
|
148
|
+
clearDynamicRoutes();
|
|
149
|
+
const tabStore = getTabStore();
|
|
150
|
+
tabStore.clearAll();
|
|
151
|
+
userStore.resetMenuLoaded();
|
|
152
|
+
const success = await userStore.fetchUserMenu();
|
|
153
|
+
if (!success) {
|
|
154
|
+
window.location.href = AUTH_LOGIN_URL;
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const allMenu = userStore.getUserALLMenu;
|
|
158
|
+
if (allMenu && allMenu.length > 0) {
|
|
159
|
+
addDynamicRoutes(allMenu);
|
|
160
|
+
const firstPage = getFirstPage(allMenu);
|
|
161
|
+
if (firstPage) {
|
|
162
|
+
const [basePath, queryString] = firstPage.split("?");
|
|
163
|
+
const query = {};
|
|
164
|
+
if (queryString) {
|
|
165
|
+
queryString.split("&").forEach((param) => {
|
|
166
|
+
const [key, value] = param.split("=");
|
|
167
|
+
if (key) query[key] = value || "";
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
justLoadedMenu = true;
|
|
171
|
+
next({ path: basePath, query, replace: true });
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
next();
|
|
177
|
+
});
|
|
178
|
+
return router;
|
|
179
|
+
}
|
|
180
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
181
|
+
0 && (module.exports = {
|
|
182
|
+
createAppRouter
|
|
183
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as vue_router from 'vue-router';
|
|
2
|
+
import { RouteRecordRaw } from 'vue-router';
|
|
3
|
+
|
|
4
|
+
interface AppRouterOptions {
|
|
5
|
+
staticRoutes: RouteRecordRaw[];
|
|
6
|
+
getUserStore: () => any;
|
|
7
|
+
getTabStore: () => any;
|
|
8
|
+
getFirstPage: (allMenu: any[]) => string | null | undefined;
|
|
9
|
+
authLoginUrl?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 创建带统一登录、动态菜单和 Tab 管理的 Router
|
|
13
|
+
* 各站点只需注入各自的 userStore / tabStore / getFirstPage 即可复用
|
|
14
|
+
*/
|
|
15
|
+
declare function createAppRouter(options: AppRouterOptions): vue_router.Router;
|
|
16
|
+
|
|
17
|
+
export { type AppRouterOptions, createAppRouter };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// src/router.ts
|
|
2
|
+
import { createRouter, createWebHashHistory } from "vue-router";
|
|
3
|
+
function createAppRouter(options) {
|
|
4
|
+
const { staticRoutes, getUserStore, getTabStore, getFirstPage, authLoginUrl } = options;
|
|
5
|
+
const router = createRouter({
|
|
6
|
+
history: createWebHashHistory(),
|
|
7
|
+
routes: staticRoutes
|
|
8
|
+
});
|
|
9
|
+
const AUTH_LOGIN_URL = authLoginUrl || `${window.location.origin}/auth/#/login`;
|
|
10
|
+
const modules = import.meta.glob("@/views/**/*.vue");
|
|
11
|
+
const registeredPaths = /* @__PURE__ */ new Set();
|
|
12
|
+
const resolveRouteAndView = (item) => {
|
|
13
|
+
const [rawPath] = (item.path || "").split("?");
|
|
14
|
+
const normalizedPath = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
|
|
15
|
+
const routePath = normalizedPath.slice(1);
|
|
16
|
+
const candidates = [
|
|
17
|
+
`/main${normalizedPath}`,
|
|
18
|
+
// /views/main/system/user.vue
|
|
19
|
+
`${normalizedPath}`
|
|
20
|
+
// /views/system/user.vue 或 /views/kq/leave.vue
|
|
21
|
+
];
|
|
22
|
+
let viewKey = "";
|
|
23
|
+
for (const viewPath of candidates) {
|
|
24
|
+
const key = `/src/views${viewPath}.vue`;
|
|
25
|
+
if (key in modules) {
|
|
26
|
+
viewKey = key;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (!viewKey) {
|
|
31
|
+
const fallbackPath = `/main${normalizedPath}`;
|
|
32
|
+
viewKey = `/src/views${fallbackPath}.vue`;
|
|
33
|
+
}
|
|
34
|
+
return { routePath, viewKey };
|
|
35
|
+
};
|
|
36
|
+
const transformRoutes = (menuItems) => {
|
|
37
|
+
const routes = [];
|
|
38
|
+
for (const item of menuItems) {
|
|
39
|
+
if (item.category === "button") continue;
|
|
40
|
+
const { routePath, viewKey } = resolveRouteAndView(item);
|
|
41
|
+
const isPage = item.category === "page" || item.category === "flow-page";
|
|
42
|
+
if (!registeredPaths.has(routePath)) {
|
|
43
|
+
registeredPaths.add(routePath);
|
|
44
|
+
routes.push({
|
|
45
|
+
path: routePath,
|
|
46
|
+
name: `menu_${item.id}`,
|
|
47
|
+
component: isPage ? modules[viewKey] : void 0,
|
|
48
|
+
meta: {
|
|
49
|
+
id: item.id,
|
|
50
|
+
parent_id: item.parent_id,
|
|
51
|
+
icon: item.icon,
|
|
52
|
+
category: item.category,
|
|
53
|
+
keepAlive: true,
|
|
54
|
+
title: item.name,
|
|
55
|
+
fullPath: item.path
|
|
56
|
+
},
|
|
57
|
+
children: item.children ? transformRoutes(item.children) : []
|
|
58
|
+
});
|
|
59
|
+
} else if (item.children?.length) {
|
|
60
|
+
routes.push(...transformRoutes(item.children));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return routes;
|
|
64
|
+
};
|
|
65
|
+
const addDynamicRoutes = (menuData) => {
|
|
66
|
+
const dynamicRoutes = transformRoutes(menuData);
|
|
67
|
+
dynamicRoutes.forEach((route) => {
|
|
68
|
+
router.addRoute("main", route);
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
const clearDynamicRoutes = () => {
|
|
72
|
+
const routes = router.getRoutes();
|
|
73
|
+
routes.forEach((route) => {
|
|
74
|
+
if (route.name?.toString().startsWith("menu_") && router.hasRoute(route.name)) {
|
|
75
|
+
router.removeRoute(route.name);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
registeredPaths.clear();
|
|
79
|
+
};
|
|
80
|
+
let justLoadedMenu = false;
|
|
81
|
+
router.beforeEach(async (to, _from, next) => {
|
|
82
|
+
const userStore = getUserStore();
|
|
83
|
+
let access_token = userStore.getUserAccessToken;
|
|
84
|
+
if (!access_token && typeof window !== "undefined") {
|
|
85
|
+
const restored = userStore.syncFromAuthStore();
|
|
86
|
+
if (restored) {
|
|
87
|
+
access_token = userStore.getUserAccessToken;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (!access_token) {
|
|
91
|
+
const currentUrl = encodeURIComponent(window.location.href);
|
|
92
|
+
window.location.href = `${AUTH_LOGIN_URL}?redirect=${currentUrl}`;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (justLoadedMenu) {
|
|
96
|
+
justLoadedMenu = false;
|
|
97
|
+
next();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (userStore.isMenuLoaded && (to.path === "/" || to.path === "")) {
|
|
101
|
+
const tabStore = getTabStore();
|
|
102
|
+
tabStore.clearAll();
|
|
103
|
+
const allMenu = userStore.getUserALLMenu;
|
|
104
|
+
if (allMenu && allMenu.length > 0) {
|
|
105
|
+
const firstPage = getFirstPage(allMenu);
|
|
106
|
+
if (firstPage) {
|
|
107
|
+
const [basePath, queryString] = firstPage.split("?");
|
|
108
|
+
const query = {};
|
|
109
|
+
if (queryString) {
|
|
110
|
+
queryString.split("&").forEach((param) => {
|
|
111
|
+
const [key, value] = param.split("=");
|
|
112
|
+
if (key) query[key] = value || "";
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
next({ path: basePath, query, replace: true });
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (!userStore.isMenuLoaded) {
|
|
121
|
+
clearDynamicRoutes();
|
|
122
|
+
const tabStore = getTabStore();
|
|
123
|
+
tabStore.clearAll();
|
|
124
|
+
userStore.resetMenuLoaded();
|
|
125
|
+
const success = await userStore.fetchUserMenu();
|
|
126
|
+
if (!success) {
|
|
127
|
+
window.location.href = AUTH_LOGIN_URL;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const allMenu = userStore.getUserALLMenu;
|
|
131
|
+
if (allMenu && allMenu.length > 0) {
|
|
132
|
+
addDynamicRoutes(allMenu);
|
|
133
|
+
const firstPage = getFirstPage(allMenu);
|
|
134
|
+
if (firstPage) {
|
|
135
|
+
const [basePath, queryString] = firstPage.split("?");
|
|
136
|
+
const query = {};
|
|
137
|
+
if (queryString) {
|
|
138
|
+
queryString.split("&").forEach((param) => {
|
|
139
|
+
const [key, value] = param.split("=");
|
|
140
|
+
if (key) query[key] = value || "";
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
justLoadedMenu = true;
|
|
144
|
+
next({ path: basePath, query, replace: true });
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
next();
|
|
150
|
+
});
|
|
151
|
+
return router;
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
createAppRouter
|
|
155
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@litianxiang/portal-core",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.mjs",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsup src/index.ts --format esm --dts"
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"vue": "^3.5.0",
|
|
17
|
+
"vue-router": "^4.5.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"tsup": "^8.3.0",
|
|
21
|
+
"typescript": "^5.6.3"
|
|
22
|
+
},
|
|
23
|
+
"license": "UNLICENSED"
|
|
24
|
+
}
|