xto-fronted 0.1.1 → 0.1.3
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/.env.development +3 -4
- package/.env.production +3 -4
- package/bin/cli.js +104 -0
- package/dist/{403-MQkNUulz.js → 403-DM5wfQkM.js} +6 -6
- package/dist/{404-BOFYLq4X.js → 404-BurAu5LC.js} +7 -7
- package/dist/api/auth.d.ts +9 -8
- package/dist/api/menu.d.ts +3 -0
- package/dist/api/user.d.ts +2 -12
- package/dist/composables/index.d.ts +8 -0
- package/dist/composables/useApp.d.ts +64 -0
- package/dist/composables/useAuth.d.ts +19 -4
- package/dist/composables/useMenu.d.ts +34 -0
- package/dist/config/index.d.ts +11 -0
- package/dist/index-BNiEld34.js +15 -0
- package/dist/index-Be9RiEfo.js +98 -0
- package/dist/index-BqRv1bdN.js +1185 -0
- package/dist/index-CQLVXvNJ.js +15 -0
- package/dist/index-CyiE8n2V.js +15 -0
- package/dist/index-xauR1bOL.js +15 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.es.js +50 -66
- package/dist/index.umd.js +1 -1
- package/dist/stores/auth.d.ts +60 -23
- package/dist/stores/menu.d.ts +40 -29
- package/dist/stores/user.d.ts +63 -84
- package/dist/style.css +1 -1
- package/dist/utils/auth.d.ts +15 -7
- package/dist/utils/permission.d.ts +1 -6
- package/dist/views/system/menu/index.vue.d.ts +1 -3
- package/dist/views/system/role/index.vue.d.ts +1 -3
- package/dist/views/system/user/index.vue.d.ts +1 -3
- package/package.json +27 -19
- package/src/api/auth.ts +34 -25
- package/src/api/menu.ts +13 -0
- package/src/api/user.ts +11 -45
- package/src/components/Layout/Header.vue +334 -389
- package/src/components/Layout/Sidebar.vue +212 -296
- package/src/components/Layout/Tabs.vue +19 -133
- package/src/composables/index.ts +9 -0
- package/src/composables/useApp.ts +170 -0
- package/src/composables/useAuth.ts +69 -44
- package/src/composables/useMenu.ts +141 -0
- package/src/config/index.ts +19 -0
- package/src/directives/permission.ts +40 -37
- package/src/index.ts +9 -4
- package/src/router/index.ts +70 -80
- package/src/stores/auth.ts +44 -31
- package/src/stores/menu.ts +157 -79
- package/src/stores/user.ts +40 -72
- package/src/types/api.d.ts +102 -83
- package/src/types/xto.d.ts +148 -148
- package/src/utils/auth.ts +85 -61
- package/src/utils/permission.ts +29 -41
- package/src/utils/request.ts +125 -125
- package/src/utils/storage.ts +10 -1
- package/src/views/dashboard/index.vue +31 -283
- package/src/views/login/index.vue +140 -247
- package/src/views/system/menu/index.vue +31 -380
- package/src/views/system/role/index.vue +31 -303
- package/src/views/system/user/index.vue +31 -326
- package/vite.config.ts +3 -3
- package/dist/index-BJxYdNPy.js +0 -475
- package/dist/index-BvnIIBR1.js +0 -142
- package/dist/index-CEvAq6KE.js +0 -372
- package/dist/index-DPkqej__.js +0 -345
- package/dist/index-pq9Z5K62.js +0 -184
- package/dist/index-vVfjShJR.js +0 -1183
package/src/router/index.ts
CHANGED
|
@@ -1,81 +1,71 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 路由配置
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { createRouter, createWebHistory } from 'vue-router'
|
|
6
|
-
import { staticRoutes, errorRoute } from './staticRoutes'
|
|
7
|
-
import { layoutRoute } from './dynamicRoutes'
|
|
8
|
-
import { hasToken } from '@/utils/auth'
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
export function resetRouter() {
|
|
74
|
-
const newRouter = createRouter({
|
|
75
|
-
history: createWebHistory(),
|
|
76
|
-
routes: [...staticRoutes, layoutRoute, errorRoute]
|
|
77
|
-
})
|
|
78
|
-
;(router as any).matcher = (newRouter as any).matcher
|
|
79
|
-
}
|
|
80
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 路由配置
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createRouter, createWebHistory } from 'vue-router'
|
|
6
|
+
import { staticRoutes, errorRoute } from './staticRoutes'
|
|
7
|
+
import { layoutRoute } from './dynamicRoutes'
|
|
8
|
+
import { hasToken } from '@/utils/auth'
|
|
9
|
+
import { useAppStore } from '@/stores/app'
|
|
10
|
+
import { useApp } from '@/composables'
|
|
11
|
+
|
|
12
|
+
const router = createRouter({
|
|
13
|
+
history: createWebHistory(),
|
|
14
|
+
routes: [...staticRoutes, layoutRoute, errorRoute],
|
|
15
|
+
scrollBehavior: () => ({ left: 0, top: 0 })
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
// 白名单路由
|
|
19
|
+
const whiteList = ['/login', '/404', '/403']
|
|
20
|
+
|
|
21
|
+
// 路由守卫
|
|
22
|
+
router.beforeEach(async (to, _from, next) => {
|
|
23
|
+
const appStore = useAppStore()
|
|
24
|
+
|
|
25
|
+
// 初始化主题
|
|
26
|
+
appStore.initTheme()
|
|
27
|
+
|
|
28
|
+
// 已登录
|
|
29
|
+
if (hasToken()) {
|
|
30
|
+
if (to.path === '/login') {
|
|
31
|
+
// 已登录,跳转到首页
|
|
32
|
+
next({ path: '/' })
|
|
33
|
+
} else {
|
|
34
|
+
// 初始化应用(加载用户信息和菜单)
|
|
35
|
+
const { initApp, isLoggedIn } = useApp()
|
|
36
|
+
|
|
37
|
+
if (!isLoggedIn.value) {
|
|
38
|
+
const success = await initApp()
|
|
39
|
+
if (!success) {
|
|
40
|
+
// 初始化失败,跳转登录页
|
|
41
|
+
next('/login')
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 添加缓存页面
|
|
47
|
+
if (to.name && to.meta.keepAlive) {
|
|
48
|
+
appStore.addCachedView(to.name as string)
|
|
49
|
+
}
|
|
50
|
+
next()
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
// 未登录
|
|
54
|
+
if (whiteList.includes(to.path)) {
|
|
55
|
+
next()
|
|
56
|
+
} else {
|
|
57
|
+
// 记录当前路径,登录后跳转
|
|
58
|
+
next({ path: '/login', query: { redirectUrl: encodeURIComponent(to.fullPath) } })
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
export function resetRouter() {
|
|
64
|
+
const newRouter = createRouter({
|
|
65
|
+
history: createWebHistory(),
|
|
66
|
+
routes: [...staticRoutes, layoutRoute, errorRoute]
|
|
67
|
+
})
|
|
68
|
+
;(router as any).matcher = (newRouter as any).matcher
|
|
69
|
+
}
|
|
70
|
+
|
|
81
71
|
export default router
|
package/src/stores/auth.ts
CHANGED
|
@@ -1,32 +1,45 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 认证状态
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { defineStore } from 'pinia'
|
|
6
|
-
import { ref, computed } from 'vue'
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 认证状态
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { defineStore } from 'pinia'
|
|
6
|
+
import { ref, computed } from 'vue'
|
|
7
|
+
import { getLoginInfo, setLoginInfo, clearToken, hasToken } from '@/utils/auth'
|
|
8
|
+
import type { LoginInfo } from '@/utils/auth'
|
|
9
|
+
|
|
10
|
+
export const useAuthStore = defineStore('auth', () => {
|
|
11
|
+
// 状态
|
|
12
|
+
const loginInfo = ref<LoginInfo | null>(getLoginInfo())
|
|
13
|
+
const isLoggedIn = computed(() => hasToken())
|
|
14
|
+
|
|
15
|
+
// 设置登录信息
|
|
16
|
+
const login = (data: Record<string, unknown>) => {
|
|
17
|
+
setLoginInfo(data)
|
|
18
|
+
loginInfo.value = getLoginInfo()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 登出
|
|
22
|
+
const logout = () => {
|
|
23
|
+
loginInfo.value = null
|
|
24
|
+
clearToken()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 获取 access token
|
|
28
|
+
const accessToken = computed(() => loginInfo.value?.accessToken || null)
|
|
29
|
+
|
|
30
|
+
// 获取 token type
|
|
31
|
+
const tokenType = computed(() => loginInfo.value?.tokenType || 'Bearer')
|
|
32
|
+
|
|
33
|
+
// 获取 code
|
|
34
|
+
const code = computed(() => loginInfo.value?.code || null)
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
loginInfo,
|
|
38
|
+
isLoggedIn,
|
|
39
|
+
accessToken,
|
|
40
|
+
tokenType,
|
|
41
|
+
code,
|
|
42
|
+
login,
|
|
43
|
+
logout
|
|
44
|
+
}
|
|
32
45
|
})
|
package/src/stores/menu.ts
CHANGED
|
@@ -1,80 +1,158 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 菜单状态
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { defineStore } from 'pinia'
|
|
6
|
-
import { ref, computed } from 'vue'
|
|
7
|
-
import type {
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 菜单状态
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { defineStore } from 'pinia'
|
|
6
|
+
import { ref, computed } from 'vue'
|
|
7
|
+
import type { MenuItem, RemoteMenuItem } from '@/types/api'
|
|
8
|
+
import { local } from '@/utils/storage'
|
|
9
|
+
|
|
10
|
+
export const useMenuStore = defineStore('menu', () => {
|
|
11
|
+
// 存储 key
|
|
12
|
+
const MENU_LIST_KEY = 'menu_list'
|
|
13
|
+
const MENU_BTN_LIST_KEY = 'menu_btn_list'
|
|
14
|
+
|
|
15
|
+
// 状态
|
|
16
|
+
const menuList = ref<MenuItem[]>(local.get<MenuItem[]>(MENU_LIST_KEY) || [])
|
|
17
|
+
const menuBtnListMap = ref<Record<string, MenuItem[]>>(local.get<Record<string, MenuItem[]>>(MENU_BTN_LIST_KEY) || {})
|
|
18
|
+
|
|
19
|
+
// 首页菜单信息
|
|
20
|
+
const indexMenu: MenuItem = {
|
|
21
|
+
code: 'home',
|
|
22
|
+
name: '首页',
|
|
23
|
+
icon: 'home',
|
|
24
|
+
closable: false,
|
|
25
|
+
default: false,
|
|
26
|
+
out: false,
|
|
27
|
+
path: '/dashboard',
|
|
28
|
+
title: '首页'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 计算属性
|
|
32
|
+
const hasMenu = computed(() => menuList.value.length > 0)
|
|
33
|
+
|
|
34
|
+
// 获取首页地址
|
|
35
|
+
const index = computed(() => {
|
|
36
|
+
function recursion(menuList: MenuItem[]): string | null {
|
|
37
|
+
if (menuList && menuList.length > 0) {
|
|
38
|
+
for (let i = 0; i < menuList.length; i++) {
|
|
39
|
+
const menu = menuList[i]
|
|
40
|
+
if (menu.default) {
|
|
41
|
+
return menu.path
|
|
42
|
+
} else {
|
|
43
|
+
const url = recursion(menu.children || [])
|
|
44
|
+
if (url) {
|
|
45
|
+
return url
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
const indexUrl = recursion(menuList.value)
|
|
53
|
+
return indexUrl || indexMenu.path
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// 解析后端菜单数据
|
|
57
|
+
const parseMenuData = (remoteMenuList: RemoteMenuItem[], parentMenuUrl?: string) => {
|
|
58
|
+
const localMenuList: MenuItem[] = []
|
|
59
|
+
|
|
60
|
+
if (!remoteMenuList || remoteMenuList.length <= 0) {
|
|
61
|
+
return localMenuList
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
remoteMenuList.forEach(remoteMenu => {
|
|
65
|
+
if (remoteMenu.type === 1) {
|
|
66
|
+
// 按钮权限
|
|
67
|
+
const btn: MenuItem = {
|
|
68
|
+
code: remoteMenu.menuCode,
|
|
69
|
+
name: remoteMenu.menuName,
|
|
70
|
+
path: '',
|
|
71
|
+
title: remoteMenu.menuName
|
|
72
|
+
}
|
|
73
|
+
const parentUrl = parentMenuUrl || ''
|
|
74
|
+
let btnList = menuBtnListMap.value[parentUrl] || []
|
|
75
|
+
btnList.push(btn)
|
|
76
|
+
menuBtnListMap.value[parentUrl] = btnList
|
|
77
|
+
} else {
|
|
78
|
+
// 菜单权限
|
|
79
|
+
const children: MenuItem[] = []
|
|
80
|
+
let menuPath = remoteMenu.menuUrl
|
|
81
|
+
|
|
82
|
+
// 处理外链
|
|
83
|
+
let isOut = remoteMenu.isOut || false
|
|
84
|
+
if (!isOut && remoteMenu.menuUrl) {
|
|
85
|
+
if (remoteMenu.menuUrl.startsWith('http')) {
|
|
86
|
+
menuPath = '/iframe/' + encodeURIComponent(menuPath)
|
|
87
|
+
} else if (remoteMenu.menuUrl.startsWith('keep-alive:')) {
|
|
88
|
+
menuPath = '/iframe/keep-alive/' + encodeURIComponent(menuPath.split('keep-alive:')[1])
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const menu: MenuItem = {
|
|
93
|
+
code: remoteMenu.menuCode,
|
|
94
|
+
name: remoteMenu.menuName,
|
|
95
|
+
path: menuPath,
|
|
96
|
+
icon: remoteMenu.icon,
|
|
97
|
+
closable: remoteMenu.closable,
|
|
98
|
+
default: remoteMenu.isDefault,
|
|
99
|
+
out: isOut,
|
|
100
|
+
children: children,
|
|
101
|
+
title: remoteMenu.menuName
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
localMenuList.push(menu)
|
|
105
|
+
|
|
106
|
+
// 递归处理子菜单
|
|
107
|
+
if (remoteMenu.children && remoteMenu.children.length > 0) {
|
|
108
|
+
const childMenus = parseMenuData(remoteMenu.children, remoteMenu.menuUrl)
|
|
109
|
+
menu.children = childMenus
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
return localMenuList
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 设置菜单
|
|
118
|
+
const setMenuList = (menus: MenuItem[]) => {
|
|
119
|
+
menuList.value = menus
|
|
120
|
+
local.set(MENU_LIST_KEY, menus)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 设置菜单(从后端数据)
|
|
124
|
+
const setMenuFromRemote = (remoteMenus: RemoteMenuItem[]) => {
|
|
125
|
+
// 清除旧数据
|
|
126
|
+
clearMenu()
|
|
127
|
+
|
|
128
|
+
// 添加首页
|
|
129
|
+
menuList.value.push(indexMenu)
|
|
130
|
+
|
|
131
|
+
// 解析后端菜单
|
|
132
|
+
const parsedMenus = parseMenuData(remoteMenus)
|
|
133
|
+
menuList.value.push(...parsedMenus)
|
|
134
|
+
|
|
135
|
+
// 保存到本地存储
|
|
136
|
+
local.set(MENU_LIST_KEY, menuList.value)
|
|
137
|
+
local.set(MENU_BTN_LIST_KEY, menuBtnListMap.value)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 清除菜单
|
|
141
|
+
const clearMenu = () => {
|
|
142
|
+
menuList.value = []
|
|
143
|
+
menuBtnListMap.value = {}
|
|
144
|
+
local.remove(MENU_LIST_KEY)
|
|
145
|
+
local.remove(MENU_BTN_LIST_KEY)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
menuList,
|
|
150
|
+
menuBtnListMap,
|
|
151
|
+
hasMenu,
|
|
152
|
+
index,
|
|
153
|
+
indexMenu,
|
|
154
|
+
setMenuList,
|
|
155
|
+
setMenuFromRemote,
|
|
156
|
+
clearMenu
|
|
157
|
+
}
|
|
80
158
|
})
|
package/src/stores/user.ts
CHANGED
|
@@ -1,73 +1,41 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 用户状态
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { defineStore } from 'pinia'
|
|
6
|
-
import { ref, computed } from 'vue'
|
|
7
|
-
import type { UserInfo } from '@/types/api'
|
|
8
|
-
import { local } from '@/utils/storage'
|
|
9
|
-
|
|
10
|
-
export const useUserStore = defineStore('user', () => {
|
|
11
|
-
// 状态
|
|
12
|
-
const userInfo = ref<UserInfo | null>(local.get<UserInfo>('
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
local.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// 检查权限
|
|
44
|
-
const hasPermission = (permission: string | string[]): boolean => {
|
|
45
|
-
if (Array.isArray(permission)) {
|
|
46
|
-
return permission.some(p => permissions.value.includes(p))
|
|
47
|
-
}
|
|
48
|
-
return permissions.value.includes(permission)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 检查角色
|
|
52
|
-
const hasRole = (role: string | string[]): boolean => {
|
|
53
|
-
if (Array.isArray(role)) {
|
|
54
|
-
return role.some(r => roles.value.includes(r))
|
|
55
|
-
}
|
|
56
|
-
return roles.value.includes(role)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
userInfo,
|
|
61
|
-
roles,
|
|
62
|
-
permissions,
|
|
63
|
-
isLoggedIn,
|
|
64
|
-
username,
|
|
65
|
-
nickname,
|
|
66
|
-
avatar,
|
|
67
|
-
userId,
|
|
68
|
-
setUserInfo,
|
|
69
|
-
clearUserInfo,
|
|
70
|
-
hasPermission,
|
|
71
|
-
hasRole
|
|
72
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 用户状态
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { defineStore } from 'pinia'
|
|
6
|
+
import { ref, computed } from 'vue'
|
|
7
|
+
import type { UserInfo } from '@/types/api'
|
|
8
|
+
import { local } from '@/utils/storage'
|
|
9
|
+
|
|
10
|
+
export const useUserStore = defineStore('user', () => {
|
|
11
|
+
// 状态
|
|
12
|
+
const userInfo = ref<UserInfo | null>(local.get<UserInfo>('user_info'))
|
|
13
|
+
|
|
14
|
+
// 计算属性
|
|
15
|
+
const isLoggedIn = computed(() => !!userInfo.value)
|
|
16
|
+
const userName = computed(() => userInfo.value?.userName || '')
|
|
17
|
+
const avatar = computed(() => userInfo.value?.avatar || '')
|
|
18
|
+
const userId = computed(() => userInfo.value?.userId)
|
|
19
|
+
|
|
20
|
+
// 设置用户信息
|
|
21
|
+
const setUserInfo = (info: UserInfo) => {
|
|
22
|
+
userInfo.value = info
|
|
23
|
+
local.set('user_info', info)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 清除用户信息
|
|
27
|
+
const clearUserInfo = () => {
|
|
28
|
+
userInfo.value = null
|
|
29
|
+
local.remove('user_info')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
userInfo,
|
|
34
|
+
isLoggedIn,
|
|
35
|
+
userName,
|
|
36
|
+
avatar,
|
|
37
|
+
userId,
|
|
38
|
+
setUserInfo,
|
|
39
|
+
clearUserInfo
|
|
40
|
+
}
|
|
73
41
|
})
|