xto-fronted 0.4.109 → 0.4.111

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.
@@ -1,37 +1,37 @@
1
- /**
2
- * 权限指令
3
- * v-permission="['user:edit']" 或 v-permission="'user:edit'"
4
- */
5
-
6
- import type { Directive, DirectiveBinding } from 'vue'
7
- import { useUserStore } from '@/stores/user'
8
- import { useMenuStore } from '@/stores/menu'
9
-
10
- const permission: Directive = {
11
- mounted(el: HTMLElement, binding: DirectiveBinding<string | string[]>) {
12
- const userStore = useUserStore()
13
- const menuStore = useMenuStore()
14
-
15
- // 如果没有登录,移除元素
16
- if (!userStore.isLoggedIn) {
17
- el.parentNode?.removeChild(el)
18
- return
19
- }
20
-
21
- // 获取权限标识
22
- const value = binding.value
23
- const permissions = Array.isArray(value) ? value : [value]
24
-
25
- // 检查是否有权限
26
- if (!menuStore.hasPermission(permissions)) {
27
- el.parentNode?.removeChild(el)
28
- }
29
- }
30
- }
31
-
32
- export default permission
33
-
34
- // 注册指令
35
- export function setupPermissionDirective(app: any) {
36
- app.directive('permission', permission)
1
+ /**
2
+ * 权限指令
3
+ * v-permission="['user:edit']" 或 v-permission="'user:edit'"
4
+ */
5
+
6
+ import type { Directive, DirectiveBinding } from 'vue'
7
+ import { useUserStore } from '@/stores/user'
8
+ import { useMenuStore } from '@/stores/menu'
9
+
10
+ const permission: Directive = {
11
+ mounted(el: HTMLElement, binding: DirectiveBinding<string | string[]>) {
12
+ const userStore = useUserStore()
13
+ const menuStore = useMenuStore()
14
+
15
+ // 如果没有登录,移除元素
16
+ if (!userStore.isLoggedIn) {
17
+ el.parentNode?.removeChild(el)
18
+ return
19
+ }
20
+
21
+ // 获取权限标识
22
+ const value = binding.value
23
+ const permissions = Array.isArray(value) ? value : [value]
24
+
25
+ // 检查是否有权限
26
+ if (!menuStore.hasPermission(permissions)) {
27
+ el.parentNode?.removeChild(el)
28
+ }
29
+ }
30
+ }
31
+
32
+ export default permission
33
+
34
+ // 注册指令
35
+ export function setupPermissionDirective(app: any) {
36
+ app.directive('permission', permission)
37
37
  }
package/src/index.ts CHANGED
@@ -39,7 +39,8 @@ export async function createXtoApp(config: Partial<XtoConfig>) {
39
39
  initAppConfig({
40
40
  appId: config.appId,
41
41
  clientId: config.clientId,
42
- apiBaseUrl: baseUrl || config.apiBaseUrl
42
+ apiBaseUrl: baseUrl || config.apiBaseUrl,
43
+ basePath: config.basePath
43
44
  })
44
45
 
45
46
  // 设置 base 路径(用于登录过期时正确跳转)
@@ -6,6 +6,7 @@ import { createRouter as vueCreateRouter, createWebHistory } from 'vue-router'
6
6
  import type { RouteRecordRaw, Router } from 'vue-router'
7
7
  import { h, defineComponent } from 'vue'
8
8
  import Layout from '@/components/Layout/index.vue'
9
+ import { getBasePath } from '@/utils/config'
9
10
 
10
11
  interface LayoutRouteOptions {
11
12
  indexPath?: string
@@ -63,8 +64,10 @@ export function createLayoutRoute(
63
64
  * @returns 路由实例
64
65
  */
65
66
  export function createRouter(routes: RouteRecordRaw[], options: CreateRouterOptions = {}): Router {
67
+ // 优先使用传入的 base,否则使用全局配置的 basePath
68
+ const base = options.base || getBasePath()
66
69
  return vueCreateRouter({
67
- history: createWebHistory(options.base),
70
+ history: createWebHistory(base),
68
71
  routes,
69
72
  scrollBehavior: () => ({ left: 0, top: 0 })
70
73
  })
package/src/stores/app.ts CHANGED
@@ -1,180 +1,180 @@
1
- /**
2
- * 应用状态
3
- */
4
-
5
- import { defineStore } from 'pinia'
6
- import { ref, computed, watch } from 'vue'
7
- import { local } from '@/utils/storage'
8
-
9
- export type ThemeMode = 'light' | 'dark'
10
- export type LayoutMode = 'sidebar' | 'top' | 'mix'
11
-
12
- export const useAppStore = defineStore('app', () => {
13
- // 状态
14
- const appName = ref<string>(local.get<string>('appName') || 'XTO App')
15
- const indexPath = ref<string>(local.get<string>('indexPath') || '/dashboard')
16
- const loginPath = ref<string>(local.get<string>('loginPath') || '/login')
17
- const isDark = ref<boolean>(local.get<boolean>('isDark') || false)
18
- const theme = ref<ThemeMode>(local.get<ThemeMode>('theme') || 'light')
19
- const layout = ref<LayoutMode>(local.get<LayoutMode>('layout') || 'sidebar')
20
- const isCollapsed = ref<boolean>(local.get<boolean>('isCollapsed') || false)
21
- const showTabs = ref<boolean>(local.get<boolean>('showTabs') ?? true)
22
- const showFooter = ref<boolean>(local.get<boolean>('showFooter') ?? true)
23
- const showBreadcrumb = ref<boolean>(local.get<boolean>('showBreadcrumb') ?? true)
24
- const primaryColor = ref<string>(local.get<string>('primaryColor') || '#409eff')
25
- const cachedViews = ref<string[]>([])
26
- const mixSubMenus = ref<any[]>([])
27
-
28
- // 计算属性
29
- const themeClass = computed(() => (isDark.value ? 'dark' : 'light'))
30
-
31
- // 设置应用名称
32
- const setAppName = (name: string) => {
33
- appName.value = name
34
- local.set('appName', name)
35
- }
36
-
37
- // 设置默认首页路径
38
- const setIndexPath = (path: string) => {
39
- indexPath.value = path
40
- local.set('indexPath', path)
41
- }
42
-
43
- // 设置登录页路径
44
- const setLoginPath = (path: string) => {
45
- loginPath.value = path
46
- local.set('loginPath', path)
47
- }
48
-
49
- // 切换主题
50
- const toggleTheme = () => {
51
- isDark.value = !isDark.value
52
- theme.value = isDark.value ? 'dark' : 'light'
53
- updateTheme()
54
- }
55
-
56
- // 设置主题
57
- const setTheme = (mode: ThemeMode) => {
58
- theme.value = mode
59
- isDark.value = mode === 'dark'
60
- updateTheme()
61
- }
62
-
63
- // 更新主题
64
- const updateTheme = () => {
65
- const html = document.documentElement
66
- if (isDark.value) {
67
- html.classList.add('dark')
68
- } else {
69
- html.classList.remove('dark')
70
- }
71
- local.set('isDark', isDark.value)
72
- local.set('theme', theme.value)
73
- }
74
-
75
- // 切换菜单折叠
76
- const toggleCollapse = () => {
77
- isCollapsed.value = !isCollapsed.value
78
- local.set('isCollapsed', isCollapsed.value)
79
- }
80
-
81
- // 设置布局
82
- const setLayout = (mode: LayoutMode) => {
83
- layout.value = mode
84
- local.set('layout', mode)
85
- }
86
-
87
- // 切换标签页
88
- const toggleTabs = () => {
89
- showTabs.value = !showTabs.value
90
- local.set('showTabs', showTabs.value)
91
- }
92
-
93
- // 切换底部
94
- const toggleFooter = () => {
95
- showFooter.value = !showFooter.value
96
- local.set('showFooter', showFooter.value)
97
- }
98
-
99
- // 切换面包屑
100
- const toggleBreadcrumb = () => {
101
- showBreadcrumb.value = !showBreadcrumb.value
102
- local.set('showBreadcrumb', showBreadcrumb.value)
103
- }
104
-
105
- // 设置主题色
106
- const setPrimaryColor = (color: string) => {
107
- primaryColor.value = color
108
- document.documentElement.style.setProperty('--color-primary', color)
109
- local.set('primaryColor', color)
110
- }
111
-
112
- // 添加缓存页面
113
- const addCachedView = (name: string) => {
114
- if (!cachedViews.value.includes(name)) {
115
- cachedViews.value.push(name)
116
- }
117
- }
118
-
119
- // 移除缓存页面
120
- const removeCachedView = (name: string) => {
121
- const index = cachedViews.value.indexOf(name)
122
- if (index > -1) {
123
- cachedViews.value.splice(index, 1)
124
- }
125
- }
126
-
127
- // 清除缓存页面
128
- const clearCachedViews = () => {
129
- cachedViews.value = []
130
- }
131
-
132
- // 设置混合模式子菜单
133
- const setMixSubMenus = (menus: any[]) => {
134
- mixSubMenus.value = menus
135
- }
136
-
137
- // 初始化主题
138
- const initTheme = () => {
139
- updateTheme()
140
- if (primaryColor.value !== '#409eff') {
141
- document.documentElement.style.setProperty('--color-primary', primaryColor.value)
142
- }
143
- }
144
-
145
- // 监听主题变化
146
- watch(isDark, updateTheme)
147
-
148
- return {
149
- appName,
150
- indexPath,
151
- loginPath,
152
- isDark,
153
- theme,
154
- layout,
155
- isCollapsed,
156
- showTabs,
157
- showFooter,
158
- showBreadcrumb,
159
- primaryColor,
160
- cachedViews,
161
- mixSubMenus,
162
- themeClass,
163
- setAppName,
164
- setIndexPath,
165
- setLoginPath,
166
- toggleTheme,
167
- toggleCollapse,
168
- setTheme,
169
- setLayout,
170
- toggleTabs,
171
- toggleFooter,
172
- toggleBreadcrumb,
173
- setPrimaryColor,
174
- addCachedView,
175
- removeCachedView,
176
- clearCachedViews,
177
- setMixSubMenus,
178
- initTheme
179
- }
1
+ /**
2
+ * 应用状态
3
+ */
4
+
5
+ import { defineStore } from 'pinia'
6
+ import { ref, computed, watch } from 'vue'
7
+ import { local } from '@/utils/storage'
8
+
9
+ export type ThemeMode = 'light' | 'dark'
10
+ export type LayoutMode = 'sidebar' | 'top' | 'mix'
11
+
12
+ export const useAppStore = defineStore('app', () => {
13
+ // 状态
14
+ const appName = ref<string>(local.get<string>('appName') || 'XTO App')
15
+ const indexPath = ref<string>(local.get<string>('indexPath') || '/dashboard')
16
+ const loginPath = ref<string>(local.get<string>('loginPath') || '/login')
17
+ const isDark = ref<boolean>(local.get<boolean>('isDark') || false)
18
+ const theme = ref<ThemeMode>(local.get<ThemeMode>('theme') || 'light')
19
+ const layout = ref<LayoutMode>(local.get<LayoutMode>('layout') || 'sidebar')
20
+ const isCollapsed = ref<boolean>(local.get<boolean>('isCollapsed') || false)
21
+ const showTabs = ref<boolean>(local.get<boolean>('showTabs') ?? true)
22
+ const showFooter = ref<boolean>(local.get<boolean>('showFooter') ?? true)
23
+ const showBreadcrumb = ref<boolean>(local.get<boolean>('showBreadcrumb') ?? true)
24
+ const primaryColor = ref<string>(local.get<string>('primaryColor') || '#409eff')
25
+ const cachedViews = ref<string[]>([])
26
+ const mixSubMenus = ref<any[]>([])
27
+
28
+ // 计算属性
29
+ const themeClass = computed(() => (isDark.value ? 'dark' : 'light'))
30
+
31
+ // 设置应用名称
32
+ const setAppName = (name: string) => {
33
+ appName.value = name
34
+ local.set('appName', name)
35
+ }
36
+
37
+ // 设置默认首页路径
38
+ const setIndexPath = (path: string) => {
39
+ indexPath.value = path
40
+ local.set('indexPath', path)
41
+ }
42
+
43
+ // 设置登录页路径
44
+ const setLoginPath = (path: string) => {
45
+ loginPath.value = path
46
+ local.set('loginPath', path)
47
+ }
48
+
49
+ // 切换主题
50
+ const toggleTheme = () => {
51
+ isDark.value = !isDark.value
52
+ theme.value = isDark.value ? 'dark' : 'light'
53
+ updateTheme()
54
+ }
55
+
56
+ // 设置主题
57
+ const setTheme = (mode: ThemeMode) => {
58
+ theme.value = mode
59
+ isDark.value = mode === 'dark'
60
+ updateTheme()
61
+ }
62
+
63
+ // 更新主题
64
+ const updateTheme = () => {
65
+ const html = document.documentElement
66
+ if (isDark.value) {
67
+ html.classList.add('dark')
68
+ } else {
69
+ html.classList.remove('dark')
70
+ }
71
+ local.set('isDark', isDark.value)
72
+ local.set('theme', theme.value)
73
+ }
74
+
75
+ // 切换菜单折叠
76
+ const toggleCollapse = () => {
77
+ isCollapsed.value = !isCollapsed.value
78
+ local.set('isCollapsed', isCollapsed.value)
79
+ }
80
+
81
+ // 设置布局
82
+ const setLayout = (mode: LayoutMode) => {
83
+ layout.value = mode
84
+ local.set('layout', mode)
85
+ }
86
+
87
+ // 切换标签页
88
+ const toggleTabs = () => {
89
+ showTabs.value = !showTabs.value
90
+ local.set('showTabs', showTabs.value)
91
+ }
92
+
93
+ // 切换底部
94
+ const toggleFooter = () => {
95
+ showFooter.value = !showFooter.value
96
+ local.set('showFooter', showFooter.value)
97
+ }
98
+
99
+ // 切换面包屑
100
+ const toggleBreadcrumb = () => {
101
+ showBreadcrumb.value = !showBreadcrumb.value
102
+ local.set('showBreadcrumb', showBreadcrumb.value)
103
+ }
104
+
105
+ // 设置主题色
106
+ const setPrimaryColor = (color: string) => {
107
+ primaryColor.value = color
108
+ document.documentElement.style.setProperty('--color-primary', color)
109
+ local.set('primaryColor', color)
110
+ }
111
+
112
+ // 添加缓存页面
113
+ const addCachedView = (name: string) => {
114
+ if (!cachedViews.value.includes(name)) {
115
+ cachedViews.value.push(name)
116
+ }
117
+ }
118
+
119
+ // 移除缓存页面
120
+ const removeCachedView = (name: string) => {
121
+ const index = cachedViews.value.indexOf(name)
122
+ if (index > -1) {
123
+ cachedViews.value.splice(index, 1)
124
+ }
125
+ }
126
+
127
+ // 清除缓存页面
128
+ const clearCachedViews = () => {
129
+ cachedViews.value = []
130
+ }
131
+
132
+ // 设置混合模式子菜单
133
+ const setMixSubMenus = (menus: any[]) => {
134
+ mixSubMenus.value = menus
135
+ }
136
+
137
+ // 初始化主题
138
+ const initTheme = () => {
139
+ updateTheme()
140
+ if (primaryColor.value !== '#409eff') {
141
+ document.documentElement.style.setProperty('--color-primary', primaryColor.value)
142
+ }
143
+ }
144
+
145
+ // 监听主题变化
146
+ watch(isDark, updateTheme)
147
+
148
+ return {
149
+ appName,
150
+ indexPath,
151
+ loginPath,
152
+ isDark,
153
+ theme,
154
+ layout,
155
+ isCollapsed,
156
+ showTabs,
157
+ showFooter,
158
+ showBreadcrumb,
159
+ primaryColor,
160
+ cachedViews,
161
+ mixSubMenus,
162
+ themeClass,
163
+ setAppName,
164
+ setIndexPath,
165
+ setLoginPath,
166
+ toggleTheme,
167
+ toggleCollapse,
168
+ setTheme,
169
+ setLayout,
170
+ toggleTabs,
171
+ toggleFooter,
172
+ toggleBreadcrumb,
173
+ setPrimaryColor,
174
+ addCachedView,
175
+ removeCachedView,
176
+ clearCachedViews,
177
+ setMixSubMenus,
178
+ initTheme
179
+ }
180
180
  })