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.
Files changed (145) hide show
  1. package/dist/{index-CJSTBnGF.js → index-C2zTmROz.js} +1072 -1062
  2. package/dist/{index-BKj-34y6.js → index-Ci9SM-gg.js} +2 -2
  3. package/dist/{index-BK4Mut6H.js → index-HtulbTHk.js} +2 -2
  4. package/dist/{index-3ekBp4iW.js → index-j1GPEQjY.js} +2 -2
  5. package/dist/{index-B5DLfOYb.js → index-x7bKZmey.js} +23 -23
  6. package/dist/index.js +1 -1
  7. package/dist/stores/app.d.ts +8 -2
  8. package/dist/stores/auth.d.ts +2 -2
  9. package/dist/style.css +1 -1
  10. package/package.json +94 -94
  11. package/src/App.vue +48 -48
  12. package/src/api/index.ts +7 -7
  13. package/src/assets/styles/_dark.scss +639 -639
  14. package/src/assets/styles/_root.scss +183 -183
  15. package/src/assets/styles/_variables.scss +69 -69
  16. package/src/assets/styles/index.scss +460 -460
  17. package/src/components/Layout/Header.vue +2 -2
  18. package/src/components/Layout/MixTopMenu.vue +1185 -1185
  19. package/src/components/Layout/Sidebar.vue +229 -229
  20. package/src/components/Layout/SidebarMenuItem.vue +163 -163
  21. package/src/components/Layout/TopMenu.vue +1177 -1177
  22. package/src/components/Layout/index.vue +199 -199
  23. package/src/composables/useI18n.ts +43 -43
  24. package/src/index.ts +114 -100
  25. package/src/router/guards.ts +129 -127
  26. package/src/router/layoutRoute.ts +70 -70
  27. package/src/stores/app.ts +9 -0
  28. package/src/stores/index.ts +15 -15
  29. package/src/stores/locale.ts +66 -66
  30. package/src/stores/user.ts +0 -2
  31. package/src/types/api.d.ts +0 -1
  32. package/src/types/json-bigint.d.ts +18 -18
  33. package/src/types/xto.d.ts +172 -172
  34. package/src/utils/request.ts +184 -184
  35. package/src/views/dashboard/index.vue +545 -545
  36. package/src/views/error/403.vue +251 -251
  37. package/src/views/error/404.vue +253 -253
  38. package/src/views/login/index.vue +586 -586
  39. package/src/views/system/menu/index.vue +690 -690
  40. package/src/views/system/role/index.vue +583 -583
  41. package/src/views/system/user/index.vue +655 -655
  42. package/vite.config.ts +139 -139
  43. package/dist/assets/404-C9Uh6Uu-.css +0 -1
  44. package/dist/assets/404-fVB40gfP.js +0 -1
  45. package/dist/assets/404-zjGLLssH.js +0 -1
  46. package/dist/assets/_plugin-vue_export-helper-DlAUqK2U.js +0 -1
  47. package/dist/assets/index-B2Y_ySNp.js +0 -2
  48. package/dist/assets/index-B5xc4gQB.css +0 -1
  49. package/dist/assets/index-B75sburk.js +0 -1
  50. package/dist/assets/index-BBdRdMfs.js +0 -1
  51. package/dist/assets/index-BDgOY6Rp.js +0 -1
  52. package/dist/assets/index-BIoRANs0.js +0 -1
  53. package/dist/assets/index-BRR97dc6.js +0 -1
  54. package/dist/assets/index-Bz0BgZQ1.js +0 -1
  55. package/dist/assets/index-CAdztNsv.css +0 -1
  56. package/dist/assets/index-CCXrcISf.css +0 -1
  57. package/dist/assets/index-CDPHn9Pd.js +0 -1
  58. package/dist/assets/index-CfpZmcpk.css +0 -1
  59. package/dist/assets/index-Cpew6d-v.css +0 -1
  60. package/dist/assets/index-CwJSA85U.js +0 -1
  61. package/dist/assets/index-CwRA10ac.js +0 -1
  62. package/dist/assets/index-D8NDxq9d.js +0 -1
  63. package/dist/assets/index-DEB6-Iv_.js +0 -2
  64. package/dist/assets/index-DM4Ezclc.css +0 -1
  65. package/dist/assets/index-DYv7nImj.css +0 -1
  66. package/dist/assets/index-Dm3Gq6SY.js +0 -1
  67. package/dist/assets/index-DxbgF-OR.js +0 -1
  68. package/dist/assets/index-RUdXk1fA.css +0 -1
  69. package/dist/assets/index-_xB0udHf.js +0 -1
  70. package/dist/assets/index-t-2Y0KhA.css +0 -1
  71. package/dist/assets/vendor-CUVPinTg.js +0 -13
  72. package/dist/assets/vue-vendor-Bpie-0gH.js +0 -29
  73. package/dist/assets/vue-vendor-DeJXJVbN.js +0 -29
  74. package/dist/assets/xto-base-C3XNcx7i.js +0 -1
  75. package/dist/assets/xto-base-CL2NKZJJ.css +0 -1
  76. package/dist/assets/xto-base-PwLGsxxb.js +0 -1
  77. package/dist/assets/xto-business--V1F5Gwb.css +0 -1
  78. package/dist/assets/xto-core-B1Ho_Ytu.js +0 -1
  79. package/dist/assets/xto-core-CtL4zKiV.js +0 -1
  80. package/dist/assets/xto-data-Coeo_ZYH.js +0 -1
  81. package/dist/assets/xto-data-MxZsiJgi.css +0 -1
  82. package/dist/assets/xto-data-bCXQa7fT.js +0 -1
  83. package/dist/assets/xto-feedback-Bxx38c3P.css +0 -1
  84. package/dist/assets/xto-feedback-CFysasJi.js +0 -1
  85. package/dist/assets/xto-feedback-CPydp0kn.js +0 -1
  86. package/dist/assets/xto-form-Cu6q3VLG.css +0 -1
  87. package/dist/assets/xto-form-DBlhgyXp.js +0 -1
  88. package/dist/assets/xto-form-bywohdAf.js +0 -1
  89. package/dist/assets/xto-layout-BDD6sSlM.css +0 -1
  90. package/dist/assets/xto-navigation-Bbdpine9.js +0 -1
  91. package/dist/assets/xto-navigation-I2o1CycT.js +0 -1
  92. package/dist/assets/xto-navigation-XfpyMpEo.css +0 -1
  93. package/dist/index-58aI1w0v.js +0 -515
  94. package/dist/index-A_B_Ap_A.js +0 -4240
  95. package/dist/index-B-lMqzxZ.js +0 -479
  96. package/dist/index-B6s_uLJE.js +0 -189
  97. package/dist/index-BAmYUT0G.js +0 -189
  98. package/dist/index-BJlOXgu5.js +0 -515
  99. package/dist/index-BMQao91y.js +0 -189
  100. package/dist/index-BRvi9qW-.js +0 -515
  101. package/dist/index-BVGW4DDQ.js +0 -189
  102. package/dist/index-BXg94yA2.js +0 -515
  103. package/dist/index-BYAkZ2gD.js +0 -641
  104. package/dist/index-BfXnrw05.js +0 -515
  105. package/dist/index-Bmb0rt9C.js +0 -641
  106. package/dist/index-Bmf0YbVq.js +0 -189
  107. package/dist/index-C1BnOFy7.js +0 -3145
  108. package/dist/index-C1j4f3mM.js +0 -479
  109. package/dist/index-C2-a5KSQ.js +0 -4233
  110. package/dist/index-C3K89jzC.js +0 -515
  111. package/dist/index-C92NkXAn.js +0 -479
  112. package/dist/index-CAHSv7LK.js +0 -4285
  113. package/dist/index-CVH7bDsl.js +0 -4285
  114. package/dist/index-Ccp6zfq-.js +0 -4290
  115. package/dist/index-CeZ0CSSs.js +0 -641
  116. package/dist/index-Cf8E7FM1.js +0 -4270
  117. package/dist/index-CgyQqbdx.js +0 -189
  118. package/dist/index-ChowNrlU.js +0 -641
  119. package/dist/index-CvQgEgUM.js +0 -641
  120. package/dist/index-D25KzR0I.js +0 -479
  121. package/dist/index-D4LWXVnG.js +0 -515
  122. package/dist/index-DCApv1oX.js +0 -641
  123. package/dist/index-DCBIjLHy.js +0 -515
  124. package/dist/index-DEYOivza.js +0 -641
  125. package/dist/index-DHH8Os_2.js +0 -189
  126. package/dist/index-DReodgBw.js +0 -4233
  127. package/dist/index-DTRJONCd.js +0 -515
  128. package/dist/index-DgffG7KK.js +0 -641
  129. package/dist/index-DjERNRXX.js +0 -515
  130. package/dist/index-DjXyzwL0.js +0 -479
  131. package/dist/index-DkOqM4e2.js +0 -3147
  132. package/dist/index-Ds8IV04t.js +0 -189
  133. package/dist/index-LSdsO2Ox.js +0 -479
  134. package/dist/index-UJixTdep.js +0 -479
  135. package/dist/index-WPRGF_GX.js +0 -189
  136. package/dist/index-WPWzllES.js +0 -641
  137. package/dist/index-Wl2Qg26t.js +0 -3147
  138. package/dist/index-dk0diNwi.js +0 -479
  139. package/dist/index-gBlRG4kk.js +0 -479
  140. package/dist/index-mVol7F2K.js +0 -479
  141. package/dist/index-xWU3J3OH.js +0 -641
  142. package/dist/index-zKJLxthI.js +0 -189
  143. package/dist/index.es.js +0 -95
  144. package/dist/index.html +0 -28
  145. 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
- if (config.locale) {
33
- import('./stores/locale').then(({ useLocaleStore }) => {
34
- const localeStore = useLocaleStore()
35
- localeStore.changeLocale(config.locale!)
36
- })
37
- }
38
-
39
- return {
40
- config: {
41
- appName: config.appName || 'XTO App',
42
- appId: getAppId(),
43
- clientId: getClientId(),
44
- apiBaseUrl: getApiBaseUrl(),
45
- indexPath: config.indexPath || '/dashboard',
46
- loginPath: config.loginPath || '/login',
47
- locale: config.locale || 'zh-CN'
48
- }
49
- }
50
- }
51
-
52
- // 组件
53
- export { default as Layout } from './components/Layout/index.vue'
54
- export { default as Header } from './components/Layout/Header.vue'
55
- export { default as Sidebar } from './components/Layout/Sidebar.vue'
56
- export { default as Tabs } from './components/Layout/Tabs.vue'
57
- export { default as Footer } from './components/Layout/Footer.vue'
58
-
59
- // 错误页面组件
60
- export { default as Login } from './views/login/index.vue'
61
- export { default as NotFound } from './views/error/404.vue'
62
- export { default as Forbidden } from './views/error/403.vue'
63
-
64
- // 组合式函数
65
- export * from './composables/useApp'
66
- export * from './composables/useAuth'
67
- export * from './composables/useForm'
68
- export * from './composables/useTable'
69
- export * from './composables/useI18n'
70
-
71
- // 工具函数
72
- export * from './utils/auth'
73
- export * from './utils/permission'
74
- export * from './utils/request'
75
- export * from './utils/storage'
76
- export * from './utils/config'
77
-
78
- // Store
79
- export * from './stores/app'
80
- export * from './stores/auth'
81
- export * from './stores/menu'
82
- export * from './stores/user'
83
- export * from './stores/locale'
84
-
85
- // 路由
86
- export { default as router, resetRouter } from './router'
87
- export * from './router/staticRoutes'
88
- export * from './router/dynamicRoutes'
89
- export { createLayoutRoute, createRouter } from './router/layoutRoute'
90
- export { setupRouterGuards } from './router/guards'
91
-
92
- // API
93
- export * from './api/auth'
94
- export * from './api/system'
95
- export * from './api/user'
96
-
97
- // 枚举
98
- export * from './enums'
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'
@@ -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
- const loginPath = options.loginPath || '/login'
41
- const homePath = options.homePath || '/'
42
-
43
- router.beforeEach(async (to, _from, next) => {
44
- const appStore = useAppStore()
45
- const userStore = useUserStore()
46
- const menuStore = useMenuStore()
47
-
48
- // 初始化主题
49
- appStore.initTheme()
50
-
51
- // 检查是否有 token
52
- const token = getToken()
53
-
54
- if (token) {
55
- // 已登录
56
- if (to.path === loginPath) {
57
- // 已登录访问登录页,跳转到首页
58
- next({ path: homePath })
59
- } else {
60
- // 检查是否已获取用户信息
61
- if (userStore.isLoggedIn) {
62
- // 已有用户信息,直接放行
63
- // 添加缓存页面
64
- if (to.name && to.meta.keepAlive) {
65
- appStore.addCachedView(to.name as string)
66
- }
67
- next()
68
- } else {
69
- // 尝试获取用户信息
70
- try {
71
- // 获取用户信息
72
- if (options.fetchUserInfo) {
73
- const userInfo = await options.fetchUserInfo()
74
- userStore.setUserInfo(userInfo)
75
- } else {
76
- const userInfo = await getUserInfo()
77
- userStore.setUserInfo(userInfo)
78
- }
79
-
80
- // 获取菜单
81
- if (options.fetchMenu) {
82
- const menuList = await options.fetchMenu()
83
- menuStore.setMenuList(menuList)
84
- } else {
85
- const menuList = await getMenuTree(options.appId)
86
- menuStore.setMenuList(menuList)
87
- }
88
-
89
- // 登录成功回调
90
- if (options.onLoginSuccess) {
91
- options.onLoginSuccess()
92
- }
93
-
94
- // 添加缓存页面
95
- if (to.name && to.meta.keepAlive) {
96
- appStore.addCachedView(to.name as string)
97
- }
98
-
99
- // 重新导航到目标路由,确保动态路由已添加
100
- next({ ...to, replace: true })
101
- } catch (error) {
102
- // 获取用户信息失败,清除所有 token 相关数据并跳转到登录页
103
- console.error('获取用户信息失败:', error)
104
- userStore.clearUserInfo()
105
- menuStore.clearMenu()
106
- // 使用 clearToken 清除所有 token 相关数据(包括 expires_time、refresh_time 等)
107
- clearToken()
108
- next({ path: loginPath, query: { redirect: to.fullPath } })
109
- }
110
- }
111
- }
112
- } else {
113
- // 未登录
114
- if (whiteList.includes(to.path)) {
115
- // 在白名单中,直接放行
116
- next()
117
- } else {
118
- // 不在白名单中,跳转到登录页
119
- next({ path: loginPath, query: { redirect: to.fullPath } })
120
- }
121
- }
122
- })
123
-
124
- router.afterEach(() => {
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,