xto-fronted 0.4.102 → 0.4.104
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-CJSTBnGF.js → index-C2zTmROz.js} +1072 -1062
- package/dist/{index-BKj-34y6.js → index-Ci9SM-gg.js} +2 -2
- package/dist/{index-BK4Mut6H.js → index-HtulbTHk.js} +2 -2
- package/dist/{index-3ekBp4iW.js → index-j1GPEQjY.js} +2 -2
- package/dist/{index-B5DLfOYb.js → index-x7bKZmey.js} +23 -23
- package/dist/index.js +1 -1
- package/dist/stores/app.d.ts +8 -2
- package/dist/stores/auth.d.ts +2 -2
- package/dist/style.css +1 -1
- package/package.json +94 -94
- package/src/App.vue +48 -48
- package/src/api/index.ts +7 -7
- package/src/assets/styles/_dark.scss +639 -639
- package/src/assets/styles/_root.scss +183 -183
- package/src/assets/styles/_variables.scss +69 -69
- package/src/assets/styles/index.scss +460 -460
- package/src/components/Layout/Header.vue +2 -2
- package/src/components/Layout/MixTopMenu.vue +1185 -1185
- package/src/components/Layout/Sidebar.vue +229 -229
- package/src/components/Layout/SidebarMenuItem.vue +163 -163
- package/src/components/Layout/TopMenu.vue +1177 -1177
- package/src/components/Layout/index.vue +199 -199
- package/src/composables/useI18n.ts +43 -43
- package/src/index.ts +114 -100
- package/src/router/guards.ts +129 -127
- package/src/router/layoutRoute.ts +70 -70
- package/src/stores/app.ts +9 -0
- package/src/stores/index.ts +15 -15
- package/src/stores/locale.ts +66 -66
- package/src/stores/user.ts +0 -2
- package/src/types/api.d.ts +0 -1
- package/src/types/json-bigint.d.ts +18 -18
- package/src/types/xto.d.ts +172 -172
- package/src/utils/request.ts +184 -184
- package/src/views/dashboard/index.vue +545 -545
- package/src/views/error/403.vue +251 -251
- package/src/views/error/404.vue +253 -253
- package/src/views/login/index.vue +586 -586
- package/src/views/system/menu/index.vue +690 -690
- package/src/views/system/role/index.vue +583 -583
- package/src/views/system/user/index.vue +655 -655
- package/vite.config.ts +139 -139
- package/dist/assets/404-C9Uh6Uu-.css +0 -1
- package/dist/assets/404-fVB40gfP.js +0 -1
- package/dist/assets/404-zjGLLssH.js +0 -1
- package/dist/assets/_plugin-vue_export-helper-DlAUqK2U.js +0 -1
- package/dist/assets/index-B2Y_ySNp.js +0 -2
- package/dist/assets/index-B5xc4gQB.css +0 -1
- package/dist/assets/index-B75sburk.js +0 -1
- package/dist/assets/index-BBdRdMfs.js +0 -1
- package/dist/assets/index-BDgOY6Rp.js +0 -1
- package/dist/assets/index-BIoRANs0.js +0 -1
- package/dist/assets/index-BRR97dc6.js +0 -1
- package/dist/assets/index-Bz0BgZQ1.js +0 -1
- package/dist/assets/index-CAdztNsv.css +0 -1
- package/dist/assets/index-CCXrcISf.css +0 -1
- package/dist/assets/index-CDPHn9Pd.js +0 -1
- package/dist/assets/index-CfpZmcpk.css +0 -1
- package/dist/assets/index-Cpew6d-v.css +0 -1
- package/dist/assets/index-CwJSA85U.js +0 -1
- package/dist/assets/index-CwRA10ac.js +0 -1
- package/dist/assets/index-D8NDxq9d.js +0 -1
- package/dist/assets/index-DEB6-Iv_.js +0 -2
- package/dist/assets/index-DM4Ezclc.css +0 -1
- package/dist/assets/index-DYv7nImj.css +0 -1
- package/dist/assets/index-Dm3Gq6SY.js +0 -1
- package/dist/assets/index-DxbgF-OR.js +0 -1
- package/dist/assets/index-RUdXk1fA.css +0 -1
- package/dist/assets/index-_xB0udHf.js +0 -1
- package/dist/assets/index-t-2Y0KhA.css +0 -1
- package/dist/assets/vendor-CUVPinTg.js +0 -13
- package/dist/assets/vue-vendor-Bpie-0gH.js +0 -29
- package/dist/assets/vue-vendor-DeJXJVbN.js +0 -29
- package/dist/assets/xto-base-C3XNcx7i.js +0 -1
- package/dist/assets/xto-base-CL2NKZJJ.css +0 -1
- package/dist/assets/xto-base-PwLGsxxb.js +0 -1
- package/dist/assets/xto-business--V1F5Gwb.css +0 -1
- package/dist/assets/xto-core-B1Ho_Ytu.js +0 -1
- package/dist/assets/xto-core-CtL4zKiV.js +0 -1
- package/dist/assets/xto-data-Coeo_ZYH.js +0 -1
- package/dist/assets/xto-data-MxZsiJgi.css +0 -1
- package/dist/assets/xto-data-bCXQa7fT.js +0 -1
- package/dist/assets/xto-feedback-Bxx38c3P.css +0 -1
- package/dist/assets/xto-feedback-CFysasJi.js +0 -1
- package/dist/assets/xto-feedback-CPydp0kn.js +0 -1
- package/dist/assets/xto-form-Cu6q3VLG.css +0 -1
- package/dist/assets/xto-form-DBlhgyXp.js +0 -1
- package/dist/assets/xto-form-bywohdAf.js +0 -1
- package/dist/assets/xto-layout-BDD6sSlM.css +0 -1
- package/dist/assets/xto-navigation-Bbdpine9.js +0 -1
- package/dist/assets/xto-navigation-I2o1CycT.js +0 -1
- package/dist/assets/xto-navigation-XfpyMpEo.css +0 -1
- package/dist/index-58aI1w0v.js +0 -515
- package/dist/index-A_B_Ap_A.js +0 -4240
- package/dist/index-B-lMqzxZ.js +0 -479
- package/dist/index-B6s_uLJE.js +0 -189
- package/dist/index-BAmYUT0G.js +0 -189
- package/dist/index-BJlOXgu5.js +0 -515
- package/dist/index-BMQao91y.js +0 -189
- package/dist/index-BRvi9qW-.js +0 -515
- package/dist/index-BVGW4DDQ.js +0 -189
- package/dist/index-BXg94yA2.js +0 -515
- package/dist/index-BYAkZ2gD.js +0 -641
- package/dist/index-BfXnrw05.js +0 -515
- package/dist/index-Bmb0rt9C.js +0 -641
- package/dist/index-Bmf0YbVq.js +0 -189
- package/dist/index-C1BnOFy7.js +0 -3145
- package/dist/index-C1j4f3mM.js +0 -479
- package/dist/index-C2-a5KSQ.js +0 -4233
- package/dist/index-C3K89jzC.js +0 -515
- package/dist/index-C92NkXAn.js +0 -479
- package/dist/index-CAHSv7LK.js +0 -4285
- package/dist/index-CVH7bDsl.js +0 -4285
- package/dist/index-Ccp6zfq-.js +0 -4290
- package/dist/index-CeZ0CSSs.js +0 -641
- package/dist/index-Cf8E7FM1.js +0 -4270
- package/dist/index-CgyQqbdx.js +0 -189
- package/dist/index-ChowNrlU.js +0 -641
- package/dist/index-CvQgEgUM.js +0 -641
- package/dist/index-D25KzR0I.js +0 -479
- package/dist/index-D4LWXVnG.js +0 -515
- package/dist/index-DCApv1oX.js +0 -641
- package/dist/index-DCBIjLHy.js +0 -515
- package/dist/index-DEYOivza.js +0 -641
- package/dist/index-DHH8Os_2.js +0 -189
- package/dist/index-DReodgBw.js +0 -4233
- package/dist/index-DTRJONCd.js +0 -515
- package/dist/index-DgffG7KK.js +0 -641
- package/dist/index-DjERNRXX.js +0 -515
- package/dist/index-DjXyzwL0.js +0 -479
- package/dist/index-DkOqM4e2.js +0 -3147
- package/dist/index-Ds8IV04t.js +0 -189
- package/dist/index-LSdsO2Ox.js +0 -479
- package/dist/index-UJixTdep.js +0 -479
- package/dist/index-WPRGF_GX.js +0 -189
- package/dist/index-WPWzllES.js +0 -641
- package/dist/index-Wl2Qg26t.js +0 -3147
- package/dist/index-dk0diNwi.js +0 -479
- package/dist/index-gBlRG4kk.js +0 -479
- package/dist/index-mVol7F2K.js +0 -479
- package/dist/index-xWU3J3OH.js +0 -641
- package/dist/index-zKJLxthI.js +0 -189
- package/dist/index.es.js +0 -95
- package/dist/index.html +0 -28
- package/dist/index.umd.js +0 -8
package/src/index.ts
CHANGED
|
@@ -1,101 +1,115 @@
|
|
|
1
|
-
// 样式
|
|
2
|
-
import './style.scss'
|
|
3
|
-
|
|
4
|
-
// 配置
|
|
5
|
-
import { initAppConfig, getAppId, getClientId, getApiBaseUrl } from './utils/config'
|
|
6
|
-
import type { LocaleCode } from '@xto/core/locale'
|
|
7
|
-
|
|
8
|
-
// XtoConfig 类型定义
|
|
9
|
-
export interface XtoConfig {
|
|
10
|
-
appName?: string
|
|
11
|
-
appId?: string
|
|
12
|
-
clientId?: string
|
|
13
|
-
apiBaseUrl?: string
|
|
14
|
-
indexPath?: string
|
|
15
|
-
loginPath?: string
|
|
16
|
-
locale?: LocaleCode
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 初始化 XTO 应用
|
|
21
|
-
* 在项目入口文件中调用此函数设置应用配置
|
|
22
|
-
* @param config 应用配置
|
|
23
|
-
*/
|
|
24
|
-
export function createXtoApp(config: Partial<XtoConfig>) {
|
|
25
|
-
initAppConfig({
|
|
26
|
-
appId: config.appId,
|
|
27
|
-
clientId: config.clientId,
|
|
28
|
-
apiBaseUrl: config.apiBaseUrl
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
config
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
export
|
|
68
|
-
export
|
|
69
|
-
export
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
export
|
|
75
|
-
export
|
|
76
|
-
export
|
|
77
|
-
|
|
78
|
-
//
|
|
79
|
-
export * from './
|
|
80
|
-
export * from './
|
|
81
|
-
export * from './
|
|
82
|
-
export * from './
|
|
83
|
-
export * from './
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
export
|
|
87
|
-
export * from './
|
|
88
|
-
export * from './
|
|
89
|
-
export
|
|
90
|
-
export
|
|
91
|
-
|
|
92
|
-
//
|
|
93
|
-
export * from './
|
|
94
|
-
export * from './
|
|
95
|
-
export * from './
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
1
|
+
// 样式
|
|
2
|
+
import './style.scss'
|
|
3
|
+
|
|
4
|
+
// 配置
|
|
5
|
+
import { initAppConfig, getAppId, getClientId, getApiBaseUrl } from './utils/config'
|
|
6
|
+
import type { LocaleCode } from '@xto/core/locale'
|
|
7
|
+
|
|
8
|
+
// XtoConfig 类型定义
|
|
9
|
+
export interface XtoConfig {
|
|
10
|
+
appName?: string
|
|
11
|
+
appId?: string
|
|
12
|
+
clientId?: string
|
|
13
|
+
apiBaseUrl?: string
|
|
14
|
+
indexPath?: string
|
|
15
|
+
loginPath?: string
|
|
16
|
+
locale?: LocaleCode
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 初始化 XTO 应用
|
|
21
|
+
* 在项目入口文件中调用此函数设置应用配置
|
|
22
|
+
* @param config 应用配置
|
|
23
|
+
*/
|
|
24
|
+
export function createXtoApp(config: Partial<XtoConfig>) {
|
|
25
|
+
initAppConfig({
|
|
26
|
+
appId: config.appId,
|
|
27
|
+
clientId: config.clientId,
|
|
28
|
+
apiBaseUrl: config.apiBaseUrl
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// 设置应用名称和路径到 store
|
|
32
|
+
import('./stores/app').then(({ useAppStore }) => {
|
|
33
|
+
const appStore = useAppStore()
|
|
34
|
+
if (config.appName) {
|
|
35
|
+
appStore.setAppName(config.appName)
|
|
36
|
+
}
|
|
37
|
+
if (config.indexPath) {
|
|
38
|
+
appStore.setIndexPath(config.indexPath)
|
|
39
|
+
}
|
|
40
|
+
if (config.loginPath) {
|
|
41
|
+
appStore.setLoginPath(config.loginPath)
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// 设置初始语言(如果提供)
|
|
46
|
+
if (config.locale) {
|
|
47
|
+
import('./stores/locale').then(({ useLocaleStore }) => {
|
|
48
|
+
const localeStore = useLocaleStore()
|
|
49
|
+
localeStore.changeLocale(config.locale!)
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
config: {
|
|
55
|
+
appName: config.appName || 'XTO App',
|
|
56
|
+
appId: getAppId(),
|
|
57
|
+
clientId: getClientId(),
|
|
58
|
+
apiBaseUrl: getApiBaseUrl(),
|
|
59
|
+
indexPath: config.indexPath || '/dashboard',
|
|
60
|
+
loginPath: config.loginPath || '/login',
|
|
61
|
+
locale: config.locale || 'zh-CN'
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 组件
|
|
67
|
+
export { default as Layout } from './components/Layout/index.vue'
|
|
68
|
+
export { default as Header } from './components/Layout/Header.vue'
|
|
69
|
+
export { default as Sidebar } from './components/Layout/Sidebar.vue'
|
|
70
|
+
export { default as Tabs } from './components/Layout/Tabs.vue'
|
|
71
|
+
export { default as Footer } from './components/Layout/Footer.vue'
|
|
72
|
+
|
|
73
|
+
// 错误页面组件
|
|
74
|
+
export { default as Login } from './views/login/index.vue'
|
|
75
|
+
export { default as NotFound } from './views/error/404.vue'
|
|
76
|
+
export { default as Forbidden } from './views/error/403.vue'
|
|
77
|
+
|
|
78
|
+
// 组合式函数
|
|
79
|
+
export * from './composables/useApp'
|
|
80
|
+
export * from './composables/useAuth'
|
|
81
|
+
export * from './composables/useForm'
|
|
82
|
+
export * from './composables/useTable'
|
|
83
|
+
export * from './composables/useI18n'
|
|
84
|
+
|
|
85
|
+
// 工具函数
|
|
86
|
+
export * from './utils/auth'
|
|
87
|
+
export * from './utils/permission'
|
|
88
|
+
export * from './utils/request'
|
|
89
|
+
export * from './utils/storage'
|
|
90
|
+
export * from './utils/config'
|
|
91
|
+
|
|
92
|
+
// Store
|
|
93
|
+
export * from './stores/app'
|
|
94
|
+
export * from './stores/auth'
|
|
95
|
+
export * from './stores/menu'
|
|
96
|
+
export * from './stores/user'
|
|
97
|
+
export * from './stores/locale'
|
|
98
|
+
|
|
99
|
+
// 路由
|
|
100
|
+
export { default as router, resetRouter } from './router'
|
|
101
|
+
export * from './router/staticRoutes'
|
|
102
|
+
export * from './router/dynamicRoutes'
|
|
103
|
+
export { createLayoutRoute, createRouter } from './router/layoutRoute'
|
|
104
|
+
export { setupRouterGuards } from './router/guards'
|
|
105
|
+
|
|
106
|
+
// API
|
|
107
|
+
export * from './api/auth'
|
|
108
|
+
export * from './api/system'
|
|
109
|
+
export * from './api/user'
|
|
110
|
+
|
|
111
|
+
// 枚举
|
|
112
|
+
export * from './enums'
|
|
113
|
+
|
|
114
|
+
// 指令
|
|
101
115
|
export { default as permissionDirective } from './directives/permission'
|
package/src/router/guards.ts
CHANGED
|
@@ -1,127 +1,129 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 路由守卫设置
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Router } from 'vue-router'
|
|
6
|
-
import { getToken, clearToken } from '@/utils/auth'
|
|
7
|
-
import { useUserStore } from '@/stores/user'
|
|
8
|
-
import { useMenuStore } from '@/stores/menu'
|
|
9
|
-
import { useAppStore } from '@/stores/app'
|
|
10
|
-
import { getUserInfo } from '@/api/auth'
|
|
11
|
-
import { getMenuTree } from '@/api/system'
|
|
12
|
-
|
|
13
|
-
// 白名单路由
|
|
14
|
-
const defaultWhiteList = ['/login', '/404', '/403']
|
|
15
|
-
|
|
16
|
-
interface RouterGuardOptions {
|
|
17
|
-
// 白名单路由
|
|
18
|
-
whiteList?: string[]
|
|
19
|
-
// 登录页路径
|
|
20
|
-
loginPath?: string
|
|
21
|
-
// 首页路径
|
|
22
|
-
homePath?: string
|
|
23
|
-
// 应用ID
|
|
24
|
-
appId?: string
|
|
25
|
-
// 获取用户信息的回调(可选,默认调用 API)
|
|
26
|
-
fetchUserInfo?: () => Promise<any>
|
|
27
|
-
// 获取菜单的回调(可选,默认调用 API)
|
|
28
|
-
fetchMenu?: () => Promise<any>
|
|
29
|
-
// 登录成功后的回调
|
|
30
|
-
onLoginSuccess?: () => void
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 设置路由守卫
|
|
35
|
-
* @param router 路由实例
|
|
36
|
-
* @param options 配置选项
|
|
37
|
-
*/
|
|
38
|
-
export function setupRouterGuards(router: Router, options: RouterGuardOptions = {}) {
|
|
39
|
-
const whiteList = options.whiteList || defaultWhiteList
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 路由守卫设置
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Router } from 'vue-router'
|
|
6
|
+
import { getToken, clearToken } from '@/utils/auth'
|
|
7
|
+
import { useUserStore } from '@/stores/user'
|
|
8
|
+
import { useMenuStore } from '@/stores/menu'
|
|
9
|
+
import { useAppStore } from '@/stores/app'
|
|
10
|
+
import { getUserInfo } from '@/api/auth'
|
|
11
|
+
import { getMenuTree } from '@/api/system'
|
|
12
|
+
|
|
13
|
+
// 白名单路由
|
|
14
|
+
const defaultWhiteList = ['/login', '/404', '/403']
|
|
15
|
+
|
|
16
|
+
interface RouterGuardOptions {
|
|
17
|
+
// 白名单路由
|
|
18
|
+
whiteList?: string[]
|
|
19
|
+
// 登录页路径
|
|
20
|
+
loginPath?: string
|
|
21
|
+
// 首页路径
|
|
22
|
+
homePath?: string
|
|
23
|
+
// 应用ID
|
|
24
|
+
appId?: string
|
|
25
|
+
// 获取用户信息的回调(可选,默认调用 API)
|
|
26
|
+
fetchUserInfo?: () => Promise<any>
|
|
27
|
+
// 获取菜单的回调(可选,默认调用 API)
|
|
28
|
+
fetchMenu?: () => Promise<any>
|
|
29
|
+
// 登录成功后的回调
|
|
30
|
+
onLoginSuccess?: () => void
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 设置路由守卫
|
|
35
|
+
* @param router 路由实例
|
|
36
|
+
* @param options 配置选项
|
|
37
|
+
*/
|
|
38
|
+
export function setupRouterGuards(router: Router, options: RouterGuardOptions = {}) {
|
|
39
|
+
const whiteList = options.whiteList || defaultWhiteList
|
|
40
|
+
|
|
41
|
+
router.beforeEach(async (to, _from, next) => {
|
|
42
|
+
const appStore = useAppStore()
|
|
43
|
+
const userStore = useUserStore()
|
|
44
|
+
const menuStore = useMenuStore()
|
|
45
|
+
|
|
46
|
+
// 从 store 获取路径配置(createXtoApp 已设置)
|
|
47
|
+
const loginPath = appStore.loginPath || options.loginPath || '/login'
|
|
48
|
+
const homePath = appStore.indexPath || options.homePath || '/dashboard'
|
|
49
|
+
|
|
50
|
+
// 初始化主题
|
|
51
|
+
appStore.initTheme()
|
|
52
|
+
|
|
53
|
+
// 检查是否有 token
|
|
54
|
+
const token = getToken()
|
|
55
|
+
|
|
56
|
+
if (token) {
|
|
57
|
+
// 已登录
|
|
58
|
+
if (to.path === loginPath) {
|
|
59
|
+
// 已登录访问登录页,跳转到首页
|
|
60
|
+
next({ path: homePath })
|
|
61
|
+
} else {
|
|
62
|
+
// 检查是否已获取用户信息
|
|
63
|
+
if (userStore.isLoggedIn) {
|
|
64
|
+
// 已有用户信息,直接放行
|
|
65
|
+
// 添加缓存页面
|
|
66
|
+
if (to.name && to.meta.keepAlive) {
|
|
67
|
+
appStore.addCachedView(to.name as string)
|
|
68
|
+
}
|
|
69
|
+
next()
|
|
70
|
+
} else {
|
|
71
|
+
// 尝试获取用户信息
|
|
72
|
+
try {
|
|
73
|
+
// 获取用户信息
|
|
74
|
+
if (options.fetchUserInfo) {
|
|
75
|
+
const userInfo = await options.fetchUserInfo()
|
|
76
|
+
userStore.setUserInfo(userInfo)
|
|
77
|
+
} else {
|
|
78
|
+
const userInfo = await getUserInfo()
|
|
79
|
+
userStore.setUserInfo(userInfo)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 获取菜单
|
|
83
|
+
if (options.fetchMenu) {
|
|
84
|
+
const menuList = await options.fetchMenu()
|
|
85
|
+
menuStore.setMenuList(menuList)
|
|
86
|
+
} else {
|
|
87
|
+
const menuList = await getMenuTree(options.appId)
|
|
88
|
+
menuStore.setMenuList(menuList)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 登录成功回调
|
|
92
|
+
if (options.onLoginSuccess) {
|
|
93
|
+
options.onLoginSuccess()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 添加缓存页面
|
|
97
|
+
if (to.name && to.meta.keepAlive) {
|
|
98
|
+
appStore.addCachedView(to.name as string)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 重新导航到目标路由,确保动态路由已添加
|
|
102
|
+
next({ ...to, replace: true })
|
|
103
|
+
} catch (error) {
|
|
104
|
+
// 获取用户信息失败,清除所有 token 相关数据并跳转到登录页
|
|
105
|
+
console.error('获取用户信息失败:', error)
|
|
106
|
+
userStore.clearUserInfo()
|
|
107
|
+
menuStore.clearMenu()
|
|
108
|
+
// 使用 clearToken 清除所有 token 相关数据(包括 expires_time、refresh_time 等)
|
|
109
|
+
clearToken()
|
|
110
|
+
next({ path: loginPath, query: { redirect: to.fullPath } })
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
// 未登录
|
|
116
|
+
if (whiteList.includes(to.path)) {
|
|
117
|
+
// 在白名单中,直接放行
|
|
118
|
+
next()
|
|
119
|
+
} else {
|
|
120
|
+
// 不在白名单中,跳转到登录页
|
|
121
|
+
next({ path: loginPath, query: { redirect: to.fullPath } })
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
router.afterEach(() => {
|
|
127
|
+
// 可以在这里添加进度条结束等
|
|
128
|
+
})
|
|
129
|
+
}
|
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 布局路由工厂函数
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { createRouter as vueCreateRouter, createWebHistory } from 'vue-router'
|
|
6
|
-
import type { RouteRecordRaw, Router } from 'vue-router'
|
|
7
|
-
import { h, defineComponent } from 'vue'
|
|
8
|
-
import Layout from '@/components/Layout/index.vue'
|
|
9
|
-
|
|
10
|
-
interface LayoutRouteOptions {
|
|
11
|
-
indexPath?: string
|
|
12
|
-
logoSrc?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface CreateRouterOptions {
|
|
16
|
-
base?: string
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 创建布局路由
|
|
21
|
-
* @param children 子路由配置
|
|
22
|
-
* @param options 配置选项
|
|
23
|
-
* @returns 布局路由配置
|
|
24
|
-
*/
|
|
25
|
-
export function createLayoutRoute(
|
|
26
|
-
children: RouteRecordRaw[],
|
|
27
|
-
options: LayoutRouteOptions = {}
|
|
28
|
-
): RouteRecordRaw {
|
|
29
|
-
const indexPath = options.indexPath || '/dashboard'
|
|
30
|
-
const logoSrc = options.logoSrc || '/vite.svg'
|
|
31
|
-
|
|
32
|
-
// 添加 catch-all 路由,让404在Layout内部渲染,保持左侧菜单显示
|
|
33
|
-
const catchAllRoute: RouteRecordRaw = {
|
|
34
|
-
path: '/:pathMatch(.*)*',
|
|
35
|
-
name: 'CatchAll',
|
|
36
|
-
component: () => import('@/views/error/404.vue'),
|
|
37
|
-
meta: {
|
|
38
|
-
title: '404'
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// 创建带 props 的 Layout 包装组件
|
|
43
|
-
const LayoutWrapper = defineComponent({
|
|
44
|
-
name: 'LayoutWrapper',
|
|
45
|
-
render() {
|
|
46
|
-
return h(Layout, { logoSrc })
|
|
47
|
-
}
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
path: '/',
|
|
52
|
-
name: 'Layout',
|
|
53
|
-
component: LayoutWrapper,
|
|
54
|
-
redirect: indexPath,
|
|
55
|
-
children: [...children, catchAllRoute]
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* 创建路由实例
|
|
61
|
-
* @param routes 路由配置数组
|
|
62
|
-
* @param options 配置选项
|
|
63
|
-
* @returns 路由实例
|
|
64
|
-
*/
|
|
65
|
-
export function createRouter(routes: RouteRecordRaw[], options: CreateRouterOptions = {}): Router {
|
|
66
|
-
return vueCreateRouter({
|
|
67
|
-
history: createWebHistory(options.base),
|
|
68
|
-
routes,
|
|
69
|
-
scrollBehavior: () => ({ left: 0, top: 0 })
|
|
70
|
-
})
|
|
1
|
+
/**
|
|
2
|
+
* 布局路由工厂函数
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createRouter as vueCreateRouter, createWebHistory } from 'vue-router'
|
|
6
|
+
import type { RouteRecordRaw, Router } from 'vue-router'
|
|
7
|
+
import { h, defineComponent } from 'vue'
|
|
8
|
+
import Layout from '@/components/Layout/index.vue'
|
|
9
|
+
|
|
10
|
+
interface LayoutRouteOptions {
|
|
11
|
+
indexPath?: string
|
|
12
|
+
logoSrc?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface CreateRouterOptions {
|
|
16
|
+
base?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 创建布局路由
|
|
21
|
+
* @param children 子路由配置
|
|
22
|
+
* @param options 配置选项
|
|
23
|
+
* @returns 布局路由配置
|
|
24
|
+
*/
|
|
25
|
+
export function createLayoutRoute(
|
|
26
|
+
children: RouteRecordRaw[],
|
|
27
|
+
options: LayoutRouteOptions = {}
|
|
28
|
+
): RouteRecordRaw {
|
|
29
|
+
const indexPath = options.indexPath || '/dashboard'
|
|
30
|
+
const logoSrc = options.logoSrc || '/vite.svg'
|
|
31
|
+
|
|
32
|
+
// 添加 catch-all 路由,让404在Layout内部渲染,保持左侧菜单显示
|
|
33
|
+
const catchAllRoute: RouteRecordRaw = {
|
|
34
|
+
path: '/:pathMatch(.*)*',
|
|
35
|
+
name: 'CatchAll',
|
|
36
|
+
component: () => import('@/views/error/404.vue'),
|
|
37
|
+
meta: {
|
|
38
|
+
title: '404'
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 创建带 props 的 Layout 包装组件
|
|
43
|
+
const LayoutWrapper = defineComponent({
|
|
44
|
+
name: 'LayoutWrapper',
|
|
45
|
+
render() {
|
|
46
|
+
return h(Layout, { logoSrc })
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
path: '/',
|
|
52
|
+
name: 'Layout',
|
|
53
|
+
component: LayoutWrapper,
|
|
54
|
+
redirect: indexPath,
|
|
55
|
+
children: [...children, catchAllRoute]
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 创建路由实例
|
|
61
|
+
* @param routes 路由配置数组
|
|
62
|
+
* @param options 配置选项
|
|
63
|
+
* @returns 路由实例
|
|
64
|
+
*/
|
|
65
|
+
export function createRouter(routes: RouteRecordRaw[], options: CreateRouterOptions = {}): Router {
|
|
66
|
+
return vueCreateRouter({
|
|
67
|
+
history: createWebHistory(options.base),
|
|
68
|
+
routes,
|
|
69
|
+
scrollBehavior: () => ({ left: 0, top: 0 })
|
|
70
|
+
})
|
|
71
71
|
}
|
package/src/stores/app.ts
CHANGED
|
@@ -13,6 +13,7 @@ export const useAppStore = defineStore('app', () => {
|
|
|
13
13
|
// 状态
|
|
14
14
|
const appName = ref<string>(local.get<string>('appName') || 'XTO App')
|
|
15
15
|
const indexPath = ref<string>(local.get<string>('indexPath') || '/dashboard')
|
|
16
|
+
const loginPath = ref<string>(local.get<string>('loginPath') || '/login')
|
|
16
17
|
const isDark = ref<boolean>(local.get<boolean>('isDark') || false)
|
|
17
18
|
const theme = ref<ThemeMode>(local.get<ThemeMode>('theme') || 'light')
|
|
18
19
|
const layout = ref<LayoutMode>(local.get<LayoutMode>('layout') || 'sidebar')
|
|
@@ -39,6 +40,12 @@ export const useAppStore = defineStore('app', () => {
|
|
|
39
40
|
local.set('indexPath', path)
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
// 设置登录页路径
|
|
44
|
+
const setLoginPath = (path: string) => {
|
|
45
|
+
loginPath.value = path
|
|
46
|
+
local.set('loginPath', path)
|
|
47
|
+
}
|
|
48
|
+
|
|
42
49
|
// 切换主题
|
|
43
50
|
const toggleTheme = () => {
|
|
44
51
|
isDark.value = !isDark.value
|
|
@@ -141,6 +148,7 @@ export const useAppStore = defineStore('app', () => {
|
|
|
141
148
|
return {
|
|
142
149
|
appName,
|
|
143
150
|
indexPath,
|
|
151
|
+
loginPath,
|
|
144
152
|
isDark,
|
|
145
153
|
theme,
|
|
146
154
|
layout,
|
|
@@ -154,6 +162,7 @@ export const useAppStore = defineStore('app', () => {
|
|
|
154
162
|
themeClass,
|
|
155
163
|
setAppName,
|
|
156
164
|
setIndexPath,
|
|
165
|
+
setLoginPath,
|
|
157
166
|
toggleTheme,
|
|
158
167
|
toggleCollapse,
|
|
159
168
|
setTheme,
|