Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
9
91isoft_web_vue3
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张伯涛
91isoft_web_vue3
Commits
6fdb8357
Commit
6fdb8357
authored
Jan 26, 2024
by
张毅辰
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
路由更改提交
parent
4f7ec01e
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
165 additions
and
46 deletions
+165
-46
index.ts
src/api/auth/index.ts
+2
-2
index.ts
src/api/user/index.ts
+3
-3
types.ts
src/api/user/types.ts
+47
-1
index.ts
src/directive/permission/index.ts
+2
-2
permission.ts
src/permission.ts
+22
-10
index.ts
src/router/index.ts
+4
-3
user.ts
src/store/modules/user.ts
+81
-19
index.ts
src/utils/auth/index.ts
+1
-1
websocket.vue
src/views/demo/websocket.vue
+1
-1
index.vue
src/views/login/index.vue
+2
-4
No files found.
src/api/auth/index.ts
View file @
6fdb8357
...
...
@@ -37,8 +37,8 @@ export function loginApi({
*/
export
function
logoutApi
()
{
return
request
({
url
:
"/
api/v1/auth/
logout"
,
method
:
"
delete
"
,
url
:
"/logout"
,
method
:
"
post
"
,
});
}
...
...
src/api/user/index.ts
View file @
6fdb8357
import
request
from
"@/utils/request"
;
import
{
AxiosPromise
}
from
"axios"
;
import
{
UserForm
,
UserInfo
,
UserPageVO
,
UserQuery
}
from
"./types"
;
import
{
User
,
User
Form
,
UserInfo
,
UserPageVO
,
UserQuery
}
from
"./types"
;
/**
* 登录成功后获取用户信息(昵称、头像、权限集合和角色集合)
*/
export
function
getUserInfoApi
()
:
AxiosPromise
<
UserInfo
>
{
export
function
getUserInfoApi
()
{
return
request
({
url
:
"/
api/v1/users/me
"
,
url
:
"/
system/user/getInfo
"
,
method
:
"get"
,
});
}
...
...
src/api/user/types.ts
View file @
6fdb8357
export
interface
User
{
/**
* 用户名称
*/
username
?:
string
;
/**
* 用户特殊标志
*/
specialTag
?:
string
;
/**
* 用户头像地址
*/
avatar
?:
any
;
}
/**
* 登录用户信息
*/
export
interface
UserInfo
{
/**
* 用户id
*/
userId
?:
number
;
/**
* 用户名称
*/
username
?:
string
;
/**
* 用户昵称
*/
nickname
?:
string
;
/**
* 用户头像地址
*/
avatar
?:
string
;
/**
* token
*/
token
:
string
|
null
;
/**
* 用户角色
*/
roles
:
string
[];
perms
:
string
[];
/**
* 用户权限
*/
permissions
:
string
[];
/**
* 用户特殊标志
*/
specialTag
?:
string
;
/**
* 用户数据
*/
user
?:
User
|
undefined
;
menus
?:
[];
}
/**
...
...
src/directive/permission/index.ts
View file @
6fdb8357
...
...
@@ -7,7 +7,7 @@ import { Directive, DirectiveBinding } from "vue";
export
const
hasPerm
:
Directive
=
{
mounted
(
el
:
HTMLElement
,
binding
:
DirectiveBinding
)
{
// 「超级管理员」拥有所有的按钮权限
const
{
roles
,
perms
}
=
useUserStoreHook
().
user
;
const
{
roles
,
perm
ission
s
}
=
useUserStoreHook
().
user
;
if
(
roles
.
includes
(
"ROOT"
))
{
return
true
;
}
...
...
@@ -16,7 +16,7 @@ export const hasPerm: Directive = {
if
(
value
)
{
const
requiredPerms
=
value
;
// DOM绑定需要的按钮权限标识
const
hasPerm
=
perms
?.
some
((
perm
)
=>
{
const
hasPerm
=
perm
ission
s
?.
some
((
perm
)
=>
{
return
requiredPerms
.
includes
(
perm
);
});
...
...
src/permission.ts
View file @
6fdb8357
import
router
from
"@/router"
;
import
{
useUserStoreHook
}
from
"@/store/modules/user"
;
import
{
usePermissionStoreHook
}
from
"@/store/modules/permission"
;
import
{
getToken
}
from
"@/utils/auth"
;
import
NProgress
from
"nprogress"
;
import
"nprogress/nprogress.css"
;
NProgress
.
configure
({
showSpinner
:
false
});
// 进度条
const
userStore
=
useUserStoreHook
();
const
permissionStore
=
usePermissionStoreHook
();
// 白名单路由
...
...
@@ -14,14 +16,12 @@ const whiteList = ["/login"];
router
.
beforeEach
(
async
(
to
,
from
,
next
)
=>
{
NProgress
.
start
();
const
hasToken
=
localStorage
.
getItem
(
"accessToken"
);
if
(
hasToken
)
{
if
(
getToken
())
{
if
(
to
.
path
===
"/login"
)
{
// 如果已登录,跳转首页
next
(
{
path
:
"/"
}
);
next
();
NProgress
.
done
();
}
else
{
const
userStore
=
useUserStoreHook
();
const
hasRoles
=
userStore
.
user
.
roles
&&
userStore
.
user
.
roles
.
length
>
0
;
if
(
hasRoles
)
{
// 未匹配到任何路由,跳转404
...
...
@@ -32,12 +32,24 @@ router.beforeEach(async (to, from, next) => {
}
}
else
{
try
{
const
{
roles
}
=
await
userStore
.
getUserInfo
();
const
accessRoutes
=
await
permissionStore
.
generateRoutes
(
roles
);
const
{
roles
,
permissions
,
menus
,
user
}
=
await
userStore
.
getUserInfo
();
if
(
permissions
&&
permissions
.
length
>
0
)
{
const
accessRoutes
=
await
userStore
.
generateRoutes
();
// const accessRoutes = await permissionStore.generateRoutes(roles);
console
.
log
(
accessRoutes
);
accessRoutes
.
forEach
((
route
)
=>
{
console
.
log
(
route
);
router
.
addRoute
(
route
);
});
next
({
...
to
,
replace
:
true
});
}
else
{
userStore
.
logout
().
then
((
_
)
=>
{
console
.
log
(
"用户无权限2"
);
alert
(
"用户无权限"
);
next
(
`/login`
);
});
}
}
catch
(
error
)
{
// 移除 token 并跳转登录页
await
userStore
.
resetToken
();
...
...
src/router/index.ts
View file @
6fdb8357
...
...
@@ -42,12 +42,12 @@ export const constantRoutes: RouteRecordRaw[] = [
},
},
{
path
:
"401"
,
path
:
"
/
401"
,
component
:
()
=>
import
(
"@/views/error-page/401.vue"
),
meta
:
{
hidden
:
true
},
},
{
path
:
"404"
,
path
:
"
/
404"
,
component
:
()
=>
import
(
"@/views/error-page/404.vue"
),
meta
:
{
hidden
:
true
},
},
...
...
@@ -58,7 +58,8 @@ export const constantRoutes: RouteRecordRaw[] = [
// {
// path: "/external-link",
// component: Layout,
// children: [ {
// children: [
// {
// component: () => import("@/views/external-link/index.vue"),
// path: "https://www.cnblogs.com/haoxianrui/",
// meta: { title: "外部链接", icon: "link" },
...
...
src/store/modules/user.ts
View file @
6fdb8357
import
{
RouteRecordRaw
}
from
"vue-router"
;
import
{
defineStore
}
from
"pinia"
;
import
{
loginApi
,
logoutApi
}
from
"@/api/auth"
;
import
{
getUserInfoApi
}
from
"@/api/user"
;
import
{
resetRouter
}
from
"@/router"
;
import
{
constantRoutes
,
resetRouter
}
from
"@/router"
;
import
{
store
}
from
"@/store"
;
import
{
LoginData
}
from
"@/api/auth/types"
;
import
{
UserInfo
}
from
"@/api/user/types"
;
import
{
useStorage
}
from
"@vueuse/core"
;
import
{
setToken
}
from
"@/utils/auth"
;
import
{
getToken
,
setToken
}
from
"@/utils/auth"
;
import
{
ref
}
from
"vue"
;
import
{
listRoutes
}
from
"@/api/menu"
;
const
Layout
=
()
=>
import
(
"@/layout/index.vue"
);
const
modules
=
import
.
meta
.
glob
(
"../../views/**/**.vue"
);
export
const
useUserStore
=
defineStore
(
"user"
,
()
=>
{
const
user
:
UserInfo
=
{
const
user
=
reactive
<
UserInfo
>
({
token
:
getToken
(),
username
:
""
,
avatar
:
""
,
roles
:
[],
perms
:
[],
};
const
token
=
useStorage
(
"accessToken"
,
""
);
perm
ission
s
:
[],
specialTag
:
""
,
});
const
menus
=
ref
<
RouteRecordRaw
[]
>
([]
);
function
setRoutes
(
newRoutes
:
RouteRecordRaw
[])
{
menus
.
value
=
constantRoutes
.
concat
(
newRoutes
);
}
/**
* 登录
*
...
...
@@ -30,7 +41,7 @@ export const useUserStore = defineStore("user", () => {
loginApi
(
loginData
)
.
then
((
response
)
=>
{
setToken
(
response
.
data
);
token
.
value
=
response
.
data
;
// Bearer eyJhbGciOiJIUzI1NiJ9.xxx.xxx
user
.
token
=
response
.
data
;
// Bearer eyJhbGciOiJIUzI1NiJ9.xxx.xxx
resolve
();
})
.
catch
((
error
)
=>
{
...
...
@@ -44,15 +55,17 @@ export const useUserStore = defineStore("user", () => {
return
new
Promise
<
UserInfo
>
((
resolve
,
reject
)
=>
{
getUserInfoApi
()
.
then
(({
data
})
=>
{
if
(
!
data
)
{
reject
(
"Verification failed, please Login again."
);
return
;
}
if
(
!
data
.
roles
||
data
.
roles
.
length
<=
0
)
{
reject
(
"getUserInfo: roles must be a non-null array!"
);
return
;
if
(
data
.
roles
.
length
>
0
)
{
user
.
roles
=
data
.
roles
;
}
else
{
user
.
roles
=
[
"ROLE_DEFAULT"
];
}
Object
.
assign
(
user
,
{
...
data
});
user
.
roles
=
data
.
roles
;
user
.
permissions
=
data
.
permissions
;
user
.
username
=
data
.
user
?.
username
;
user
.
specialTag
=
data
.
user
?.
specialTag
;
user
.
avatar
=
data
.
user
?.
avatar
;
menus
.
value
=
data
.
menus
;
resolve
(
data
);
})
.
catch
((
error
)
=>
{
...
...
@@ -66,7 +79,7 @@ export const useUserStore = defineStore("user", () => {
return
new
Promise
<
void
>
((
resolve
,
reject
)
=>
{
logoutApi
()
.
then
(()
=>
{
token
.
value
=
""
;
user
.
token
=
""
;
location
.
reload
();
// 清空路由
resolve
();
})
...
...
@@ -79,19 +92,68 @@ export const useUserStore = defineStore("user", () => {
// remove token
function
resetToken
()
{
return
new
Promise
<
void
>
((
resolve
)
=>
{
token
.
value
=
""
;
user
.
token
=
""
;
resetRouter
();
resolve
();
});
}
/**
* 生成动态路由
*
* @returns
*/
function
generateRoutes
()
{
return
new
Promise
<
RouteRecordRaw
[]
>
((
resolve
,
reject
)
=>
{
// 接口获取所有路由
if
(
menus
.
value
.
length
>
0
)
{
// 根据角色获取有访问权限的路由
const
accessedRoutes
=
filterAsyncRoutes
(
menus
.
value
);
console
.
log
(
accessedRoutes
);
setRoutes
(
accessedRoutes
);
resolve
(
accessedRoutes
);
}
else
{
reject
();
}
});
}
function
loadView
(
view
:
any
)
{
// return () => import(`@/views/${view}.vue`);
const
path
=
modules
[
`../../views/
${
view
}
.vue`
];
return
path
;
}
/**
* 递归过滤有权限的异步(动态)路由
*
* @param routes 接口返回的异步(动态)路由
* @param roles 用户角色集合
* @returns 返回用户有权限的异步(动态)路由
*/
function
filterAsyncRoutes
(
routes
:
RouteRecordRaw
[])
{
return
routes
.
filter
((
route
)
=>
{
if
(
route
.
component
)
{
// Layout组件特殊处理
if
(
route
.
component
?.
toString
()
===
"Layout"
)
{
route
.
component
=
Layout
;
}
else
{
route
.
component
=
loadView
(
route
.
component
);
}
}
if
(
route
.
children
!=
null
&&
route
.
children
&&
route
.
children
.
length
)
{
route
.
children
=
filterAsyncRoutes
(
route
.
children
);
}
return
true
;
});
}
return
{
token
,
user
,
login
,
getUserInfo
,
logout
,
resetToken
,
generateRoutes
,
};
});
...
...
src/utils/auth/index.ts
View file @
6fdb8357
const
TokenKey
=
"token"
;
const
emailKey
=
"email"
;
export
function
getToken
()
{
export
function
getToken
()
:
string
|
null
{
return
localStorage
.
getItem
(
TokenKey
)
||
sessionStorage
.
getItem
(
TokenKey
);
}
...
...
src/views/demo/websocket.vue
View file @
6fdb8357
...
...
@@ -57,7 +57,7 @@ function connectWebSocket() {
stompClient
=
Stomp
.
over
(
socket
);
stompClient
.
connect
(
{
Authorization
:
userStore
.
token
},
{
Authorization
:
userStore
.
user
.
token
},
()
=>
{
isConnected
.
value
=
true
;
messages
.
value
.
push
({
...
...
src/views/login/index.vue
View file @
6fdb8357
...
...
@@ -345,6 +345,7 @@ function successLogin() {
.
then
(()
=>
{
const
query
:
LocationQuery
=
route
.
query
;
const
redirect
=
(
query
.
redirect
as
LocationQueryValue
)
??
"/"
;
//
const
otherQueryParams
=
Object
.
keys
(
query
).
reduce
(
(
acc
:
any
,
cur
:
string
)
=>
{
if
(
cur
!==
"redirect"
)
{
...
...
@@ -354,7 +355,7 @@ function successLogin() {
},
{}
);
router
.
push
({
path
:
redirect
,
query
:
otherQueryParams
});
router
.
push
({
path
:
"/system/user"
,
query
:
otherQueryParams
});
})
.
catch
(()
=>
{
// 验证失败,重新生成验证码
...
...
@@ -444,9 +445,6 @@ onMounted(() => {
}
}
.my_btn
{
position
:
relative
;
width
:
100%
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment