refactor(projects): 动态路由权限完善
This commit is contained in:
parent
401f0c748d
commit
55ddc9cab0
@ -1,6 +1,6 @@
|
||||
VITE_VISUALIZER=true
|
||||
VITE_VISUALIZER=false
|
||||
|
||||
VITE_COMPRESS=true
|
||||
VITE_COMPRESS=false
|
||||
|
||||
# gzip | brotliCompress | deflate | deflateRaw
|
||||
VITE_COMPRESS_TYPE=gzip
|
||||
|
38
.eslintrc.js
38
.eslintrc.js
@ -55,12 +55,11 @@ module.exports = {
|
||||
group: 'external',
|
||||
position: 'before'
|
||||
},
|
||||
// ui framework, such as "naive-ui"
|
||||
// {
|
||||
// pattern: 'naive-ui',
|
||||
// group: 'external',
|
||||
// position: 'before'
|
||||
// },
|
||||
{
|
||||
pattern: 'naive-ui',
|
||||
group: 'external',
|
||||
position: 'before'
|
||||
},
|
||||
{
|
||||
pattern: '@/config',
|
||||
group: 'internal',
|
||||
@ -142,13 +141,7 @@ module.exports = {
|
||||
position: 'before'
|
||||
}
|
||||
],
|
||||
pathGroupsExcludedImportTypes: [
|
||||
'vue',
|
||||
'vue-router',
|
||||
'vuex',
|
||||
'pinia'
|
||||
// 'naive-ui'
|
||||
]
|
||||
pathGroupsExcludedImportTypes: ['vue', 'vue-router', 'vuex', 'pinia', 'naive-ui']
|
||||
}
|
||||
],
|
||||
'import/no-unresolved': 'off',
|
||||
@ -171,17 +164,7 @@ module.exports = {
|
||||
ignores: ['index']
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/ban-types': [
|
||||
'error',
|
||||
{
|
||||
types: {
|
||||
'{}': {
|
||||
message: 'Use object instead',
|
||||
fixWith: 'object'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/ban-types': 'off',
|
||||
'@typescript-eslint/no-empty-interface': [
|
||||
'error',
|
||||
{
|
||||
@ -192,17 +175,12 @@ module.exports = {
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'@typescript-eslint/no-unused-vars': ['warn', { ignoreRestSiblings: true, varsIgnorePattern: '^_' }],
|
||||
'@typescript-eslint/no-use-before-define': ['error', { classes: true, functions: false, typedefs: false }]
|
||||
'@typescript-eslint/no-use-before-define': ['warn', { classes: true, functions: false, typedefs: false }]
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.vue'],
|
||||
parser: 'vue-eslint-parser',
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser'
|
||||
},
|
||||
rules: {
|
||||
'no-unused-vars': 'off',
|
||||
'no-undef': 'off'
|
||||
}
|
||||
},
|
||||
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -33,7 +33,6 @@
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"javascript.updateImportsOnFileMove.enabled": "always",
|
||||
"[javascriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
@ -72,5 +71,6 @@
|
||||
"business": "core",
|
||||
"request": "api",
|
||||
"adapter": "middleware"
|
||||
}
|
||||
},
|
||||
"unocss.root": "src"
|
||||
}
|
||||
|
149
mock/api/auth.ts
149
mock/api/auth.ts
@ -1,9 +1,10 @@
|
||||
import type { MockMethod } from 'vite-plugin-mock';
|
||||
import { userModel } from '../model';
|
||||
|
||||
const token: ApiAuth.Token = {
|
||||
token: '__TEMP_TOKEN__',
|
||||
refreshToken: '__TEMP_REFRESH_TOKEN__'
|
||||
};
|
||||
/** 参数错误的状态码 */
|
||||
const ERROR_PARAM_CODE = 10000;
|
||||
|
||||
const ERROR_PARAM_MSG = '参数校验失败!';
|
||||
|
||||
const apis: MockMethod[] = [
|
||||
// 获取验证码
|
||||
@ -18,73 +19,107 @@ const apis: MockMethod[] = [
|
||||
};
|
||||
}
|
||||
},
|
||||
// 密码登录
|
||||
// 用户+密码 登录
|
||||
{
|
||||
url: '/mock/loginByPwd',
|
||||
url: '/mock/login',
|
||||
method: 'post',
|
||||
response: (): Service.MockServiceResult<ApiAuth.Token> => {
|
||||
return {
|
||||
code: 200,
|
||||
message: 'ok',
|
||||
data: token
|
||||
};
|
||||
}
|
||||
},
|
||||
// 验证码登录
|
||||
{
|
||||
url: '/mock/loginByCode',
|
||||
method: 'post',
|
||||
response: (): Service.MockServiceResult<ApiAuth.Token> => {
|
||||
return {
|
||||
code: 200,
|
||||
message: 'ok',
|
||||
data: token
|
||||
};
|
||||
}
|
||||
},
|
||||
// 获取用户信息(请求头携带token)
|
||||
{
|
||||
url: '/mock/getUserInfo',
|
||||
method: 'get',
|
||||
response: (): Service.MockServiceResult<ApiAuth.UserInfo> => {
|
||||
return {
|
||||
code: 200,
|
||||
message: 'ok',
|
||||
data: {
|
||||
userId: '0',
|
||||
userName: 'Soybean',
|
||||
userPhone: '15170283876',
|
||||
userRole: 'super'
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
url: '/mock/testToken',
|
||||
method: 'post',
|
||||
response: (option: Service.MockOption): Service.MockServiceResult<true | null> => {
|
||||
if (option.headers?.authorization !== token.token) {
|
||||
response: (options: Service.MockOption): Service.MockServiceResult<ApiAuth.Token | null> => {
|
||||
const { userName = undefined, password = undefined } = options.body;
|
||||
|
||||
if (!userName || !password) {
|
||||
return {
|
||||
code: 66666,
|
||||
message: 'token 失效',
|
||||
code: ERROR_PARAM_CODE,
|
||||
message: ERROR_PARAM_MSG,
|
||||
data: null
|
||||
};
|
||||
}
|
||||
|
||||
const findItem = userModel.find(item => item.userName === userName && item.password === password);
|
||||
|
||||
if (findItem) {
|
||||
return {
|
||||
code: 200,
|
||||
message: 'ok',
|
||||
data: {
|
||||
token: findItem.token,
|
||||
refreshToken: findItem.refreshToken
|
||||
}
|
||||
};
|
||||
}
|
||||
return {
|
||||
code: 200,
|
||||
message: 'ok',
|
||||
data: true
|
||||
code: 1000,
|
||||
message: '用户名或密码错误!',
|
||||
data: null
|
||||
};
|
||||
}
|
||||
},
|
||||
// 获取用户信息(请求头携带token, 根据token获取用户信息)
|
||||
{
|
||||
url: '/mock/getUserInfo',
|
||||
method: 'get',
|
||||
response: (options: Service.MockOption): Service.MockServiceResult<ApiAuth.UserInfo | null> => {
|
||||
// 这里的mock插件得到的字段是authorization, 前端传递的是Authorization字段
|
||||
const { authorization = '' } = options.headers;
|
||||
const REFRESH_TOKEN_CODE = 66666;
|
||||
|
||||
if (!authorization) {
|
||||
return {
|
||||
code: REFRESH_TOKEN_CODE,
|
||||
message: '用户已失效或不存在!',
|
||||
data: null
|
||||
};
|
||||
}
|
||||
const userInfo: Auth.UserInfo = {
|
||||
userId: '',
|
||||
userName: '',
|
||||
userRole: 'user'
|
||||
};
|
||||
const isInUser = userModel.some(item => {
|
||||
const flag = item.token === authorization;
|
||||
if (flag) {
|
||||
const { userId: itemUserId, userName, userRole } = item;
|
||||
Object.assign(userInfo, { userId: itemUserId, userName, userRole });
|
||||
}
|
||||
return flag;
|
||||
});
|
||||
|
||||
if (isInUser) {
|
||||
return {
|
||||
code: 200,
|
||||
message: 'ok',
|
||||
data: userInfo
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: REFRESH_TOKEN_CODE,
|
||||
message: '用户信息异常!',
|
||||
data: null
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
url: '/mock/updateToken',
|
||||
method: 'post',
|
||||
response: (): Service.MockServiceResult<ApiAuth.Token> => {
|
||||
response: (options: Service.MockOption): Service.MockServiceResult<ApiAuth.Token | null> => {
|
||||
const { refreshToken = '' } = options.body;
|
||||
|
||||
const findItem = userModel.find(item => item.refreshToken === refreshToken);
|
||||
|
||||
if (findItem) {
|
||||
return {
|
||||
code: 200,
|
||||
message: 'ok',
|
||||
data: {
|
||||
token: findItem.token,
|
||||
refreshToken: findItem.refreshToken
|
||||
}
|
||||
};
|
||||
}
|
||||
return {
|
||||
code: 200,
|
||||
message: 'ok',
|
||||
data: token
|
||||
code: 3000,
|
||||
message: '用户已失效或不存在!',
|
||||
data: null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,403 +1,26 @@
|
||||
import type { MockMethod } from 'vite-plugin-mock';
|
||||
import { filterAuthRoutesByUserPermission } from '../utils';
|
||||
|
||||
const routes: AuthRoute.Route[] = [
|
||||
{
|
||||
name: 'dashboard',
|
||||
path: '/dashboard',
|
||||
component: 'basic',
|
||||
children: [
|
||||
{
|
||||
name: 'dashboard_analysis',
|
||||
path: '/dashboard/analysis',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '分析页',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:analysis'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'dashboard_workbench',
|
||||
path: '/dashboard/workbench',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '工作台',
|
||||
requiresAuth: true,
|
||||
permissions: ['super', 'admin'],
|
||||
icon: 'icon-park-outline:workbench'
|
||||
}
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
title: '仪表盘',
|
||||
icon: 'carbon:dashboard',
|
||||
order: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'document',
|
||||
path: '/document',
|
||||
component: 'basic',
|
||||
children: [
|
||||
{
|
||||
name: 'document_vue',
|
||||
path: '/document/vue',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: 'vue文档',
|
||||
requiresAuth: true,
|
||||
icon: 'mdi:vuejs'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'document_vue-new',
|
||||
path: '/document/vue-new',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: 'vue文档(新版)',
|
||||
requiresAuth: true,
|
||||
icon: 'mdi:vuejs'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'document_vite',
|
||||
path: '/document/vite',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: 'vite文档',
|
||||
requiresAuth: true,
|
||||
icon: 'simple-icons:vite'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'document_project',
|
||||
path: '/document/project',
|
||||
meta: {
|
||||
title: '项目文档(外链)',
|
||||
requiresAuth: true,
|
||||
icon: 'mdi:file-link-outline',
|
||||
href: 'https://docs.soybean.pro/'
|
||||
}
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
title: '文档',
|
||||
icon: 'carbon:document',
|
||||
order: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'component',
|
||||
path: '/component',
|
||||
component: 'basic',
|
||||
children: [
|
||||
{
|
||||
name: 'component_button',
|
||||
path: '/component/button',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '按钮',
|
||||
requiresAuth: true,
|
||||
icon: 'ic:baseline-radio-button-checked'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'component_card',
|
||||
path: '/component/card',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '卡片',
|
||||
requiresAuth: true,
|
||||
icon: 'mdi:card-outline'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'component_table',
|
||||
path: '/component/table',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '表格',
|
||||
requiresAuth: true,
|
||||
icon: 'mdi:table-large'
|
||||
}
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
title: '组件示例',
|
||||
icon: 'fluent:app-store-24-regular',
|
||||
order: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'plugin',
|
||||
path: '/plugin',
|
||||
component: 'basic',
|
||||
children: [
|
||||
{
|
||||
name: 'plugin_map',
|
||||
path: '/plugin/map',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '地图',
|
||||
requiresAuth: true,
|
||||
icon: 'mdi:map'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'plugin_video',
|
||||
path: '/plugin/video',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '视频',
|
||||
requiresAuth: true,
|
||||
icon: 'mdi:video'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'plugin_editor',
|
||||
path: '/plugin/editor',
|
||||
component: 'multi',
|
||||
children: [
|
||||
{
|
||||
name: 'plugin_editor_quill',
|
||||
path: '/plugin/editor/quill',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '富文本编辑器',
|
||||
requiresAuth: true,
|
||||
icon: 'mdi:file-document-edit-outline'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'plugin_editor_markdown',
|
||||
path: '/plugin/editor/markdown',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: 'markdown编辑器',
|
||||
requiresAuth: true,
|
||||
icon: 'ri:markdown-line'
|
||||
}
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
title: '编辑器',
|
||||
icon: 'icon-park-outline:editor'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'plugin_swiper',
|
||||
path: '/plugin/swiper',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: 'Swiper插件',
|
||||
requiresAuth: true,
|
||||
icon: 'simple-icons:swiper'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'plugin_copy',
|
||||
path: '/plugin/copy',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '剪贴板',
|
||||
requiresAuth: true,
|
||||
icon: 'mdi:clipboard-outline'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'plugin_icon',
|
||||
path: '/plugin/icon',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '图标',
|
||||
requiresAuth: true,
|
||||
icon: 'ic:baseline-insert-emoticon'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'plugin_print',
|
||||
path: '/plugin/print',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '打印',
|
||||
requiresAuth: true,
|
||||
icon: 'ic:baseline-local-printshop'
|
||||
}
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
title: '插件示例',
|
||||
icon: 'clarity:plugin-line',
|
||||
order: 4
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'auth-demo',
|
||||
path: '/auth-demo',
|
||||
component: 'basic',
|
||||
children: [
|
||||
{
|
||||
name: 'auth-demo_permission',
|
||||
path: '/auth-demo/permission',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '权限切换',
|
||||
requiresAuth: true,
|
||||
icon: 'ic:round-construction'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'auth-demo_super',
|
||||
path: '/auth-demo/super',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '超级管理员可见',
|
||||
requiresAuth: true,
|
||||
permissions: ['super'],
|
||||
icon: 'ic:round-supervisor-account'
|
||||
}
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
title: '权限示例',
|
||||
icon: 'ic:baseline-security',
|
||||
order: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'exception',
|
||||
path: '/exception',
|
||||
component: 'basic',
|
||||
children: [
|
||||
{
|
||||
name: 'exception_403',
|
||||
path: '/exception/403',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '异常页403',
|
||||
requiresAuth: true,
|
||||
icon: 'ic:baseline-block'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'exception_404',
|
||||
path: '/exception/404',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '异常页404',
|
||||
requiresAuth: true,
|
||||
icon: 'ic:baseline-web-asset-off'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'exception_500',
|
||||
path: '/exception/500',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '异常页500',
|
||||
requiresAuth: true,
|
||||
icon: 'ic:baseline-wifi-off'
|
||||
}
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
title: '异常页',
|
||||
icon: 'ant-design:exception-outlined',
|
||||
order: 6
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'multi-menu',
|
||||
path: '/multi-menu',
|
||||
component: 'basic',
|
||||
children: [
|
||||
{
|
||||
name: 'multi-menu_first',
|
||||
path: '/multi-menu/first',
|
||||
component: 'multi',
|
||||
children: [
|
||||
{
|
||||
name: 'multi-menu_first_second',
|
||||
path: '/multi-menu/first/second',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '二级菜单',
|
||||
requiresAuth: true,
|
||||
icon: 'ic:outline-menu'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'multi-menu_first_second-new',
|
||||
path: '/multi-menu/first/second-new',
|
||||
component: 'multi',
|
||||
children: [
|
||||
{
|
||||
name: 'multi-menu_first_second-new_third',
|
||||
path: '/multi-menu/first/second-new/third',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '三级菜单',
|
||||
requiresAuth: true,
|
||||
icon: 'ic:outline-menu'
|
||||
}
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
title: '二级菜单(有子菜单)',
|
||||
icon: 'ic:outline-menu'
|
||||
}
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
title: '一级菜单',
|
||||
icon: 'ic:outline-menu'
|
||||
}
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
title: '多级菜单',
|
||||
icon: 'carbon:menu',
|
||||
order: 7
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'about',
|
||||
path: '/about',
|
||||
component: 'self',
|
||||
meta: {
|
||||
title: '关于',
|
||||
requiresAuth: true,
|
||||
singleLayout: 'basic',
|
||||
permissions: ['super', 'admin', 'user'],
|
||||
icon: 'fluent:book-information-24-regular',
|
||||
order: 8
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function dataMiddleware(data: AuthRoute.Route[]): ApiRoute.Route {
|
||||
const routeHomeName: AuthRoute.RouteKey = 'dashboard_analysis';
|
||||
|
||||
data.sort((next, pre) => Number(next.meta?.order) - Number(pre.meta?.order));
|
||||
|
||||
const filters = filterAuthRoutesByUserPermission(data, 'admin');
|
||||
|
||||
return {
|
||||
routes: filters,
|
||||
home: routeHomeName
|
||||
};
|
||||
}
|
||||
import { userModel, routeModel } from '../model';
|
||||
|
||||
const apis: MockMethod[] = [
|
||||
{
|
||||
url: '/mock/getUserRoutes',
|
||||
method: 'post',
|
||||
response: (): Service.MockServiceResult => {
|
||||
response: (options: Service.MockOption): Service.MockServiceResult => {
|
||||
const { userId = undefined } = options.body;
|
||||
|
||||
const routeHomeName: AuthRoute.RouteKey = 'dashboard_analysis';
|
||||
|
||||
const role = userModel.find(item => item.userId === userId)?.userRole || 'user';
|
||||
|
||||
const filterRoutes = routeModel[role];
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
message: 'ok',
|
||||
data: dataMiddleware(routes)
|
||||
data: {
|
||||
routes: filterRoutes,
|
||||
home: routeHomeName
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
40
mock/model/auth.ts
Normal file
40
mock/model/auth.ts
Normal file
@ -0,0 +1,40 @@
|
||||
interface UserModel extends Auth.UserInfo {
|
||||
token: string;
|
||||
refreshToken: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export const userModel: UserModel[] = [
|
||||
{
|
||||
token: '__TOKEN_SOYBEAN__',
|
||||
refreshToken: '__REFRESH_TOKEN_SOYBEAN__',
|
||||
userId: '0',
|
||||
userName: 'Soybean',
|
||||
userRole: 'super',
|
||||
password: 'soybean123'
|
||||
},
|
||||
{
|
||||
token: '__TOKEN_SUPER__',
|
||||
refreshToken: '__REFRESH_TOKEN_SUPER__',
|
||||
userId: '1',
|
||||
userName: 'Super',
|
||||
userRole: 'super',
|
||||
password: 'super123'
|
||||
},
|
||||
{
|
||||
token: '__TOKEN_ADMIN__',
|
||||
refreshToken: '__REFRESH_TOKEN_ADMIN__',
|
||||
userId: '2',
|
||||
userName: 'Admin',
|
||||
userRole: 'admin',
|
||||
password: 'admin123'
|
||||
},
|
||||
{
|
||||
token: '__TOKEN_USER01__',
|
||||
refreshToken: '__REFRESH_TOKEN_USER01__',
|
||||
userId: '3',
|
||||
userName: 'User01',
|
||||
userRole: 'user',
|
||||
password: 'user01123'
|
||||
}
|
||||
];
|
2
mock/model/index.ts
Normal file
2
mock/model/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './auth';
|
||||
export * from './route';
|
@ -1,4 +1,4 @@
|
||||
const routes: Record<Auth.RoleType, AuthRoute.Route[]> = {
|
||||
export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
|
||||
super: [
|
||||
{
|
||||
name: 'dashboard',
|
||||
@ -844,5 +844,3 @@ const routes: Record<Auth.RoleType, AuthRoute.Route[]> = {
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default routes;
|
||||
|
@ -1,35 +0,0 @@
|
||||
interface ModelUser {
|
||||
userId: string;
|
||||
userName: string;
|
||||
password: string;
|
||||
role: Auth.RoleType;
|
||||
}
|
||||
|
||||
const users: ModelUser[] = [
|
||||
{
|
||||
userId: '0',
|
||||
userName: 'Soybean',
|
||||
password: 'soybean',
|
||||
role: 'super'
|
||||
},
|
||||
{
|
||||
userId: '1',
|
||||
userName: 'Super',
|
||||
password: 'super',
|
||||
role: 'super'
|
||||
},
|
||||
{
|
||||
userId: '2',
|
||||
userName: 'Admin',
|
||||
password: 'admin',
|
||||
role: 'admin'
|
||||
},
|
||||
{
|
||||
userId: '3',
|
||||
userName: 'User01',
|
||||
password: 'user01',
|
||||
role: 'user'
|
||||
}
|
||||
];
|
||||
|
||||
export default users;
|
@ -1,24 +0,0 @@
|
||||
/**
|
||||
* 根据用户权限过滤路由
|
||||
* @param routes - 权限路由
|
||||
* @param permission - 权限
|
||||
*/
|
||||
export function filterAuthRoutesByUserPermission(routes: AuthRoute.Route[], permission: Auth.RoleType) {
|
||||
return routes.map(route => filterAuthRouteByUserPermission(route, permission)).flat(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户权限过滤单个路由
|
||||
* @param route - 单个权限路由
|
||||
* @param permission - 权限
|
||||
*/
|
||||
function filterAuthRouteByUserPermission(route: AuthRoute.Route, permission: Auth.RoleType): AuthRoute.Route[] {
|
||||
const hasPermission =
|
||||
!route.meta.permissions || permission === 'super' || route.meta.permissions.includes(permission);
|
||||
|
||||
if (route.children) {
|
||||
const filterChildren = route.children.map(item => filterAuthRouteByUserPermission(item, permission)).flat(1);
|
||||
Object.assign(route, { children: filterChildren });
|
||||
}
|
||||
return hasPermission ? [route] : [];
|
||||
}
|
@ -52,8 +52,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@amap/amap-jsapi-types": "^0.0.8",
|
||||
"@commitlint/cli": "^16.2.3",
|
||||
"@commitlint/config-conventional": "^16.2.1",
|
||||
"@commitlint/cli": "^16.2.4",
|
||||
"@commitlint/config-conventional": "^16.2.4",
|
||||
"@iconify/json": "^2.1.33",
|
||||
"@iconify/vue": "^3.2.1",
|
||||
"@types/bmapgl": "^0.0.5",
|
||||
@ -86,7 +86,7 @@
|
||||
"rollup-plugin-visualizer": "^5.6.0",
|
||||
"sass": "^1.51.0",
|
||||
"typescript": "^4.6.3",
|
||||
"unocss": "^0.31.17",
|
||||
"unocss": "^0.32.1",
|
||||
"unplugin-icons": "^0.14.1",
|
||||
"unplugin-vue-components": "0.19.3",
|
||||
"unplugin-vue-define-options": "^0.6.1",
|
||||
|
210
pnpm-lock.yaml
210
pnpm-lock.yaml
@ -4,8 +4,8 @@ specifiers:
|
||||
'@amap/amap-jsapi-types': ^0.0.8
|
||||
'@antv/g2plot': ^2.4.16
|
||||
'@better-scroll/core': ^2.4.2
|
||||
'@commitlint/cli': ^16.2.3
|
||||
'@commitlint/config-conventional': ^16.2.1
|
||||
'@commitlint/cli': ^16.2.4
|
||||
'@commitlint/config-conventional': ^16.2.4
|
||||
'@iconify/json': ^2.1.33
|
||||
'@iconify/vue': ^3.2.1
|
||||
'@soybeanjs/vue-admin-layout': ^1.0.3
|
||||
@ -54,7 +54,7 @@ specifiers:
|
||||
swiper: ^8.1.4
|
||||
typescript: ^4.6.3
|
||||
ua-parser-js: ^1.0.2
|
||||
unocss: ^0.31.17
|
||||
unocss: ^0.32.1
|
||||
unplugin-icons: ^0.14.1
|
||||
unplugin-vue-components: 0.19.3
|
||||
unplugin-vue-define-options: ^0.6.1
|
||||
@ -97,8 +97,8 @@ dependencies:
|
||||
|
||||
devDependencies:
|
||||
'@amap/amap-jsapi-types': 0.0.8
|
||||
'@commitlint/cli': 16.2.3
|
||||
'@commitlint/config-conventional': 16.2.1
|
||||
'@commitlint/cli': 16.2.4
|
||||
'@commitlint/config-conventional': 16.2.4
|
||||
'@iconify/json': 2.1.33
|
||||
'@iconify/vue': 3.2.1_vue@3.2.33
|
||||
'@types/bmapgl': 0.0.5
|
||||
@ -131,7 +131,7 @@ devDependencies:
|
||||
rollup-plugin-visualizer: 5.6.0
|
||||
sass: 1.51.0
|
||||
typescript: 4.6.3
|
||||
unocss: 0.31.17_vite@2.9.6
|
||||
unocss: 0.32.1_vite@2.9.6
|
||||
unplugin-icons: 0.14.1_vite@2.9.6
|
||||
unplugin-vue-components: 0.19.3_vite@2.9.6+vue@3.2.33
|
||||
unplugin-vue-define-options: 0.6.1_vite@2.9.6+vue@3.2.33
|
||||
@ -649,14 +649,14 @@ packages:
|
||||
resolution: {integrity: sha512-Gy/Jfbpu+hq0u+PcjkTqyXGqAf+0dexTzEZ5IDXEVwJVLmd3cx8A73oTcAZ8QZgk4wSHvlMjXecSaptkhnNPEw==}
|
||||
dev: false
|
||||
|
||||
/@commitlint/cli/16.2.3:
|
||||
resolution: {integrity: sha512-VsJBQLvhhlOgEfxs/Z5liYuK0dXqLE5hz1VJzLBxiOxG31kL/X5Q4OvK292BmO7IGZcm1yJE3XQPWSiFaEHbWA==}
|
||||
/@commitlint/cli/16.2.4:
|
||||
resolution: {integrity: sha512-rbvqvz9JI+uiKxV2nH65BtSU01fsADd3bxe9fWtO3rM0c+CI/H9FfzKkDLvSRmXjvk1G2/wXlCGeqO9IBT4X9g==}
|
||||
engines: {node: '>=v12'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@commitlint/format': 16.2.1
|
||||
'@commitlint/lint': 16.2.1
|
||||
'@commitlint/load': 16.2.3
|
||||
'@commitlint/lint': 16.2.4
|
||||
'@commitlint/load': 16.2.4
|
||||
'@commitlint/read': 16.2.1
|
||||
'@commitlint/types': 16.2.1
|
||||
lodash: 4.17.21
|
||||
@ -668,8 +668,8 @@ packages:
|
||||
- '@swc/wasm'
|
||||
dev: true
|
||||
|
||||
/@commitlint/config-conventional/16.2.1:
|
||||
resolution: {integrity: sha512-cP9gArx7gnaj4IqmtCIcHdRjTYdRUi6lmGE+lOzGGjGe45qGOS8nyQQNvkNy2Ey2VqoSWuXXkD8zCUh6EHf1Ww==}
|
||||
/@commitlint/config-conventional/16.2.4:
|
||||
resolution: {integrity: sha512-av2UQJa3CuE5P0dzxj/o/B9XVALqYzEViHrMXtDrW9iuflrqCStWBAioijppj9URyz6ONpohJKAtSdgAOE0gkA==}
|
||||
engines: {node: '>=v12'}
|
||||
dependencies:
|
||||
conventional-changelog-conventionalcommits: 4.6.3
|
||||
@ -704,21 +704,21 @@ packages:
|
||||
chalk: 4.1.2
|
||||
dev: true
|
||||
|
||||
/@commitlint/is-ignored/16.2.1:
|
||||
resolution: {integrity: sha512-exl8HRzTIfb1YvDJp2b2HU5z1BT+9tmgxR2XF0YEzkMiCIuEKh+XLeocPr1VcvAKXv3Cmv5X/OfNRp+i+/HIhQ==}
|
||||
/@commitlint/is-ignored/16.2.4:
|
||||
resolution: {integrity: sha512-Lxdq9aOAYCOOOjKi58ulbwK/oBiiKz+7Sq0+/SpFIEFwhHkIVugvDvWjh2VRBXmRC/x5lNcjDcYEwS/uYUvlYQ==}
|
||||
engines: {node: '>=v12'}
|
||||
dependencies:
|
||||
'@commitlint/types': 16.2.1
|
||||
semver: 7.3.5
|
||||
semver: 7.3.7
|
||||
dev: true
|
||||
|
||||
/@commitlint/lint/16.2.1:
|
||||
resolution: {integrity: sha512-fNINQ3X2ZqsCkNB3Z0Z8ElmhewqrS3gy2wgBTx97BkcjOWiyPAGwDJ752hwrsUnWAVBRztgw826n37xPzxsOgg==}
|
||||
/@commitlint/lint/16.2.4:
|
||||
resolution: {integrity: sha512-AUDuwOxb2eGqsXbTMON3imUGkc1jRdtXrbbohiLSCSk3jFVXgJLTMaEcr39pR00N8nE9uZ+V2sYaiILByZVmxQ==}
|
||||
engines: {node: '>=v12'}
|
||||
dependencies:
|
||||
'@commitlint/is-ignored': 16.2.1
|
||||
'@commitlint/is-ignored': 16.2.4
|
||||
'@commitlint/parse': 16.2.1
|
||||
'@commitlint/rules': 16.2.1
|
||||
'@commitlint/rules': 16.2.4
|
||||
'@commitlint/types': 16.2.1
|
||||
dev: true
|
||||
|
||||
@ -741,6 +741,27 @@ packages:
|
||||
- '@swc/core'
|
||||
- '@swc/wasm'
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@commitlint/load/16.2.4:
|
||||
resolution: {integrity: sha512-HjANm3/29ROV+zt4yfaY/K6gpr9Dbzgtlp0kSwZGW0poDXlD/yqVYgPQ6JolJzZii5FUz5R4yVLC15hVL/w60w==}
|
||||
engines: {node: '>=v12'}
|
||||
dependencies:
|
||||
'@commitlint/config-validator': 16.2.1
|
||||
'@commitlint/execute-rule': 16.2.1
|
||||
'@commitlint/resolve-extends': 16.2.1
|
||||
'@commitlint/types': 16.2.1
|
||||
'@types/node': 17.0.29
|
||||
chalk: 4.1.2
|
||||
cosmiconfig: 7.0.1
|
||||
cosmiconfig-typescript-loader: 1.0.9_5281fe59fc32158e106b8b5e2bebb315
|
||||
lodash: 4.17.21
|
||||
resolve-from: 5.0.0
|
||||
typescript: 4.6.3
|
||||
transitivePeerDependencies:
|
||||
- '@swc/core'
|
||||
- '@swc/wasm'
|
||||
dev: true
|
||||
|
||||
/@commitlint/message/16.2.1:
|
||||
resolution: {integrity: sha512-2eWX/47rftViYg7a3axYDdrgwKv32mxbycBJT6OQY/MJM7SUfYNYYvbMFOQFaA4xIVZt7t2Alyqslbl6blVwWw==}
|
||||
@ -778,8 +799,8 @@ packages:
|
||||
resolve-global: 1.0.0
|
||||
dev: true
|
||||
|
||||
/@commitlint/rules/16.2.1:
|
||||
resolution: {integrity: sha512-ZFezJXQaBBso+BOTre/+1dGCuCzlWVaeLiVRGypI53qVgPMzQqZhkCcrxBFeqB87qeyzr4A4EoG++IvITwwpIw==}
|
||||
/@commitlint/rules/16.2.4:
|
||||
resolution: {integrity: sha512-rK5rNBIN2ZQNQK+I6trRPK3dWa0MtaTN4xnwOma1qxa4d5wQMQJtScwTZjTJeallFxhOgbNOgr48AMHkdounVg==}
|
||||
engines: {node: '>=v12'}
|
||||
dependencies:
|
||||
'@commitlint/ensure': 16.2.1
|
||||
@ -1238,14 +1259,14 @@ packages:
|
||||
eslint-visitor-keys: 3.3.0
|
||||
dev: true
|
||||
|
||||
/@unocss/cli/0.31.17:
|
||||
resolution: {integrity: sha512-at/gAnZBrutoTuee7dujhN/TRSCWAq+1QYm2ekfNktt4dgA5xVzvFQo63GEUvnM4tE51SQkIbznf44BxNbuEUQ==}
|
||||
/@unocss/cli/0.32.1:
|
||||
resolution: {integrity: sha512-KrO0SCiyss9fYl+VM4yNdYUqqMGpNQdOjPXErr12eNLnY68WiM7yEPZrcQL3QZO2tza7CObkivMkuCC1PMITbQ==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@unocss/config': 0.31.17
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/preset-uno': 0.31.17
|
||||
'@unocss/config': 0.32.1
|
||||
'@unocss/core': 0.32.1
|
||||
'@unocss/preset-uno': 0.32.1
|
||||
cac: 6.7.12
|
||||
chokidar: 3.5.3
|
||||
colorette: 2.0.16
|
||||
@ -1255,107 +1276,112 @@ packages:
|
||||
perfect-debounce: 0.1.3
|
||||
dev: true
|
||||
|
||||
/@unocss/config/0.31.17:
|
||||
resolution: {integrity: sha512-Ggj2yCOeLxRfXd2Qt4ajWXJXQilZc/ozBFZM0vU77iFFq/yBlCWH6rLlhkYqGvSQT+K5SfaKluncskSG2090YA==}
|
||||
/@unocss/config/0.32.1:
|
||||
resolution: {integrity: sha512-BuS22lneXnuC6KkZUOYLVPdWnYKUx5reYzFOayUp0FmMcG2uMuMWZGGBx10JV/hWSWq3FKkCT8bNM0QcNZXysw==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/core': 0.32.1
|
||||
unconfig: 0.3.3
|
||||
dev: true
|
||||
|
||||
/@unocss/core/0.31.17:
|
||||
resolution: {integrity: sha512-DJ3Uk2ePVXvV1qQmgoLK44aqB6f0s+naOEvouI97nzVXDZgxDQPBxIPB/L4vvE4U+gQxEiHwwE3gJ75iPqVzXw==}
|
||||
/@unocss/core/0.32.1:
|
||||
resolution: {integrity: sha512-VlLF00eRvP8lsEspPWTju6kgl67R3POYl1HKZP0IPknbm9o6dyEwsKkG9VAHHvO4lDiQMI5O3ahI+DRvN0zmfg==}
|
||||
dev: true
|
||||
|
||||
/@unocss/inspector/0.31.17:
|
||||
resolution: {integrity: sha512-eBRSBtiSvIk5mVJnNyN6Ag9ykBmQi2xROvcNS5sa11SHMkwWEaj1/8kBxyYFuOvl6ysEtdC7eSzv0tMRjXuuTw==}
|
||||
/@unocss/inspector/0.32.1:
|
||||
resolution: {integrity: sha512-BaKKYg9llm1ZyPpvHfffBNJmJ2DqageFUQjd2uRFZCGjYzqiXF7wCSGFccYAwbS7vs+DhAqDuoAAS2F8n/Hbew==}
|
||||
dependencies:
|
||||
gzip-size: 6.0.0
|
||||
sirv: 2.0.2
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-attributify/0.31.17:
|
||||
resolution: {integrity: sha512-Kar6K6oF7Zp/qXbWq1g+RwphOKCHiU3kWhulgbwy/HbdhSXsR0EE8zAHIgEga25q72Mm0hxBlowPtbjvX107rQ==}
|
||||
/@unocss/preset-attributify/0.32.1:
|
||||
resolution: {integrity: sha512-rqjR/RDePVEoqEJMtnQ7uGE1qTHlzf07nQqVPBwebadOhbype4YguoC1Y7Dgiqc78tEiGj88OMoO1vBXMkw3SQ==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/core': 0.32.1
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-icons/0.31.17:
|
||||
resolution: {integrity: sha512-cdS/BuL15NOKWIBxTW8e3xnr26MmC1dOtOtPLljLyMhdnEWOwHQA2PB9YtUZIEvrr2zTyMv/9aPQlBQ78973kg==}
|
||||
/@unocss/preset-icons/0.32.1:
|
||||
resolution: {integrity: sha512-S31Qlqbr7NBduQR/jdirYHecyM8DNT9TpXjqvxX2ssKMB1Ie1zpAWrtwM5Y0JaprjKa0mmL1KZ0wWGTHJ+LypA==}
|
||||
dependencies:
|
||||
'@iconify/utils': 1.0.32
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/core': 0.32.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-mini/0.31.17:
|
||||
resolution: {integrity: sha512-gVgMTOKLt3O1ym348QIBmR5sS9W0Ozkk5xelhH6e0VXcpg0dXDPDrl4hFErMy4x6IB86yyJG6Dz5JhcwQB13Ig==}
|
||||
/@unocss/preset-mini/0.32.1:
|
||||
resolution: {integrity: sha512-9cq1yfJLKmgim8lr/CmfpGTEVOCdg5W1F5MbutRtRijYrsSsETCGLLCfdq4QhV4o84QE8kAM6iLoUm0j+Gn8Sg==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/core': 0.32.1
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-typography/0.31.17:
|
||||
resolution: {integrity: sha512-zFFZeGdcXxpjgLG1o1zUQNFCdBqyGoFfUa0Zj0SeIYs11a4Y3ra701jHr1F4X4mhYzIyCUEfGC9X852o0iPa+A==}
|
||||
/@unocss/preset-typography/0.32.1:
|
||||
resolution: {integrity: sha512-+bekG07fiOjSzzyaJ2LmaGbJJab9XNyyC18TOYPCtryChO3kr2AmJyqows2II2+uqcGlexe6rsjeNteHy58cNg==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/core': 0.32.1
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-uno/0.31.17:
|
||||
resolution: {integrity: sha512-zSajrrPQlPXBr+egbQ00Nvku9YrqFh3pWByVSx/4XPpZ1oSSjOqMAfGcdDPlmOWi++G6FLU28sglc3JB7jJEZA==}
|
||||
/@unocss/preset-uno/0.32.1:
|
||||
resolution: {integrity: sha512-SHLusZNl2d1mfqyu425xCUkShLOrqYANxXVvb/HOhDXtWDtf8dglE3afbYCcklTb1YDZ08M6k4AsSgZjsv23ng==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/preset-mini': 0.31.17
|
||||
'@unocss/preset-wind': 0.31.17
|
||||
'@unocss/core': 0.32.1
|
||||
'@unocss/preset-mini': 0.32.1
|
||||
'@unocss/preset-wind': 0.32.1
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-web-fonts/0.31.17:
|
||||
resolution: {integrity: sha512-4FVNYMBN70j8xNOTxnUG6XeEJ/1WoJ1shQ72UhXDMaH4ZgCORvmAYdjl4opjEEB4RoXg5yJ1N1W6B3O/bsupbQ==}
|
||||
/@unocss/preset-web-fonts/0.32.1:
|
||||
resolution: {integrity: sha512-cPIcrkRZKejGNwF/ZzrhGW8gLQpgAdr1EIhSNPsJG77kpWn7fnsA+VUqa//2shKYhx0hezS3Tbq47hDK5qc4gQ==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/core': 0.32.1
|
||||
axios: 0.26.1
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-wind/0.31.17:
|
||||
resolution: {integrity: sha512-GYVxPA66BovfXO9IAbSlE5yuBTO3ko7ChJS1Oisy3Y0+JBNXJsqzKlyLRLeKOSK76o2b/D0wRO8xEqirh76GQA==}
|
||||
/@unocss/preset-wind/0.32.1:
|
||||
resolution: {integrity: sha512-StgSnYQ4w7sUYqW1GURCICQ42qL83SQ1H5KZbSIJVnv2VVgo77m6dt96TmTmvizWJWH4Ga597YFhjXP4WUv6mw==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/preset-mini': 0.31.17
|
||||
'@unocss/core': 0.32.1
|
||||
'@unocss/preset-mini': 0.32.1
|
||||
dev: true
|
||||
|
||||
/@unocss/reset/0.31.17:
|
||||
resolution: {integrity: sha512-g3+bqtM6LetSEJ5NYhi2P4vdP8yVLUQLbNZUdMtggcmHXTY08ISWaJKWmnHptrO13rtRoQ+l9gFc4Y7kRpD7NA==}
|
||||
dev: false
|
||||
|
||||
/@unocss/scope/0.31.17:
|
||||
resolution: {integrity: sha512-X6V62OKexnhePLuVj9FtrpAJYUCpIedIieogvl6gHDZMnTnJPNaW9jJ7/e6r21F3u9IrqOzlikgCicFSm4J/TA==}
|
||||
/@unocss/reset/0.32.1:
|
||||
resolution: {integrity: sha512-tC2gCYY2isEDfBo1LWfcPAnxuM3my29fWtFUQRGvViZVTwYFjVIGD8BgIfiioifGumLunRW78qN7LT22fXoxgg==}
|
||||
dev: true
|
||||
|
||||
/@unocss/transformer-directives/0.31.17:
|
||||
resolution: {integrity: sha512-1FF6PQybr2eFVp1mlz+OeTDAIWTuJw61EJneFWlsnWk2PgqBlX25SIuQjTWhXfjWihL3n8F2wHrX8i0vcG39bg==}
|
||||
/@unocss/scope/0.32.1:
|
||||
resolution: {integrity: sha512-6Xsas4Fm797IIONNXP7Y7JLL7B4NTjk/BeFX7j++CS14SfGzF0wTTkyaHxE9ETecOiouUABwoiPQRzHNAkrNIA==}
|
||||
dev: true
|
||||
|
||||
/@unocss/transformer-directives/0.32.1:
|
||||
resolution: {integrity: sha512-F4rPaNGaKbRGKksHuzAfSrsIaMZLpvqRhlk1xpwN5AGHClhK+Ak0z9j+N9Yy4rUuRx5OeOCuOj9Kcvq8cL8JnA==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/core': 0.32.1
|
||||
css-tree: 2.1.0
|
||||
dev: true
|
||||
|
||||
/@unocss/transformer-variant-group/0.31.17:
|
||||
resolution: {integrity: sha512-q1L7jckHicv2GwdKp7KGhufHeH5sGhJeRv1EGVZkb7KFKt9AROH9X9LDzE6Xr0jWgywrCIyTUIBdZwb2aKrjeg==}
|
||||
/@unocss/transformer-variant-group/0.32.1:
|
||||
resolution: {integrity: sha512-SrT5nWvNuuGFlMSGYgP7+KemYaBSUlP7i6v5QqzbjX9bcMz8JicT5Rwvy1Z1GOdtRGCy7e5aB6LW3Mxpd/pQhw==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/core': 0.32.1
|
||||
dev: true
|
||||
|
||||
/@unocss/vite/0.31.17_vite@2.9.6:
|
||||
resolution: {integrity: sha512-+NH/In8zqBXbTWfpiu8u/7jkwBJdaq2lM/ErXzd0q07w8Jv0FmKRWxBGml168uDA6dHHoJRcGO1AvzOYxsv9+A==}
|
||||
/@unocss/vite/0.32.1_vite@2.9.6:
|
||||
resolution: {integrity: sha512-XLbBodjSfgoyTRUGL5XY8Fw+pW7GOZ1WrT1C+QfVJt8+BgY6wIdVhaERbfgOdAw/trzM0PYwhhbMHZp0SyJE5Q==}
|
||||
peerDependencies:
|
||||
vite: ^2.9.0
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 4.2.1
|
||||
'@unocss/config': 0.31.17
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/inspector': 0.31.17
|
||||
'@unocss/scope': 0.31.17
|
||||
'@unocss/transformer-directives': 0.31.17
|
||||
'@unocss/config': 0.32.1
|
||||
'@unocss/core': 0.32.1
|
||||
'@unocss/inspector': 0.32.1
|
||||
'@unocss/scope': 0.32.1
|
||||
'@unocss/transformer-directives': 0.32.1
|
||||
magic-string: 0.26.1
|
||||
vite: 2.9.6_sass@1.51.0
|
||||
dev: true
|
||||
@ -2293,7 +2319,7 @@ packages:
|
||||
longest: 2.0.1
|
||||
word-wrap: 1.2.3
|
||||
optionalDependencies:
|
||||
'@commitlint/load': 16.2.3
|
||||
'@commitlint/load': 16.2.4
|
||||
transitivePeerDependencies:
|
||||
- '@swc/core'
|
||||
- '@swc/wasm'
|
||||
@ -5177,14 +5203,6 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/semver/7.3.5:
|
||||
resolution: {integrity: sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
dev: true
|
||||
|
||||
/semver/7.3.7:
|
||||
resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==}
|
||||
engines: {node: '>=10'}
|
||||
@ -5793,23 +5811,23 @@ packages:
|
||||
engines: {node: '>= 10.0.0'}
|
||||
dev: true
|
||||
|
||||
/unocss/0.31.17_vite@2.9.6:
|
||||
resolution: {integrity: sha512-JJsxXfHfRRDvimDSgTTIpDPpYsVcp/jMxj+I/WsDIFQjBKhB4dq0VyjKl5dXlicgMTJfy2wrj/zBGMPl9W6/qA==}
|
||||
/unocss/0.32.1_vite@2.9.6:
|
||||
resolution: {integrity: sha512-Flp6FHOLznE7nTOSTSNPiyL3dd9V8TvhXPnReEwRo8yZxXOIg/+9cVzvF1nwGCIbfDYbjNK+eNKmtwxVmB78og==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@unocss/cli': 0.31.17
|
||||
'@unocss/core': 0.31.17
|
||||
'@unocss/preset-attributify': 0.31.17
|
||||
'@unocss/preset-icons': 0.31.17
|
||||
'@unocss/preset-mini': 0.31.17
|
||||
'@unocss/preset-typography': 0.31.17
|
||||
'@unocss/preset-uno': 0.31.17
|
||||
'@unocss/preset-web-fonts': 0.31.17
|
||||
'@unocss/preset-wind': 0.31.17
|
||||
'@unocss/reset': 0.31.17
|
||||
'@unocss/transformer-directives': 0.31.17
|
||||
'@unocss/transformer-variant-group': 0.31.17
|
||||
'@unocss/vite': 0.31.17_vite@2.9.6
|
||||
'@unocss/cli': 0.32.1
|
||||
'@unocss/core': 0.32.1
|
||||
'@unocss/preset-attributify': 0.32.1
|
||||
'@unocss/preset-icons': 0.32.1
|
||||
'@unocss/preset-mini': 0.32.1
|
||||
'@unocss/preset-typography': 0.32.1
|
||||
'@unocss/preset-uno': 0.32.1
|
||||
'@unocss/preset-web-fonts': 0.32.1
|
||||
'@unocss/preset-wind': 0.32.1
|
||||
'@unocss/reset': 0.32.1
|
||||
'@unocss/transformer-directives': 0.32.1
|
||||
'@unocss/transformer-variant-group': 0.32.1
|
||||
'@unocss/vite': 0.32.1_vite@2.9.6
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
- supports-color
|
||||
|
@ -5,9 +5,9 @@ export const REGEXP_PHONE =
|
||||
/** 邮箱正则 */
|
||||
export const REGEXP_EMAIL = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
|
||||
|
||||
/** 密码正则(密码为8-18位数字/字符/符号的组合) */
|
||||
/** 密码正则(密码为6-18位数字/字符/符号的组合) */
|
||||
export const REGEXP_PWD =
|
||||
/^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){8,18}$/;
|
||||
/^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){6,18}$/;
|
||||
|
||||
/** 6位数字验证码正则 */
|
||||
export const REGEXP_CODE_SIX = /^\d{6}$/;
|
||||
|
@ -50,7 +50,7 @@ const activeComponent = computed(() => (isChromeMode.value ? ChromeTab : ButtonT
|
||||
const tabRef = ref<HTMLElement>();
|
||||
async function getActiveTabClientX() {
|
||||
await nextTick();
|
||||
if (tabRef.value) {
|
||||
if (tabRef.value && tabRef.value.children.length && tabRef.value.children[tab.activeTabIndex]) {
|
||||
const activeTabElement = tabRef.value.children[tab.activeTabIndex];
|
||||
const { x, width } = activeTabElement.getBoundingClientRect();
|
||||
const clientX = x + width / 2;
|
||||
|
@ -1,4 +1,6 @@
|
||||
export function adapterOfDataWithAdapter(res: Service.RequestResult<ApiDemo.DataWithAdapter>): Demo.DataWithAdapter {
|
||||
export function adapterOfFetchDataWithAdapter(
|
||||
res: Service.RequestResult<ApiDemo.DataWithAdapter>
|
||||
): Demo.DataWithAdapter {
|
||||
const { dataId, dataName } = res.data!;
|
||||
|
||||
const result: Demo.DataWithAdapter = {
|
||||
|
@ -11,15 +11,11 @@ export function fetchSmsCode(phone: string) {
|
||||
|
||||
/**
|
||||
* 登录
|
||||
* @param phone - 手机号
|
||||
* @param pwdOrCode - 密码或验证码
|
||||
* @param type - 登录方式: pwd - 密码登录; sms - 验证码登录
|
||||
* @param userName - 用户名
|
||||
* @param password - 密码
|
||||
*/
|
||||
export function fetchLogin(phone: string, pwdOrCode: string, type: 'pwd' | 'sms') {
|
||||
if (type === 'pwd') {
|
||||
return mockRequest.post<ApiAuth.Token>('/loginByPwd', { phone, pwd: pwdOrCode });
|
||||
}
|
||||
return mockRequest.post<ApiAuth.Token>('/loginByCode', { phone, code: pwdOrCode });
|
||||
export function fetchLogin(userName: string, password: string) {
|
||||
return mockRequest.post<ApiAuth.Token>('/login', { userName, password });
|
||||
}
|
||||
|
||||
/** 获取用户信息 */
|
||||
|
@ -1,9 +1,14 @@
|
||||
import { adapterOfServiceResult } from '@/utils';
|
||||
import { mockRequest } from '../request';
|
||||
import { adapterOfDataWithAdapter } from '../adapter';
|
||||
import { serviceAdapter } from '@/utils';
|
||||
import { request, mockRequest } from '../request';
|
||||
import { adapterOfFetchDataWithAdapter } from '../adapter';
|
||||
|
||||
/** 带有适配器的请求(将请求结果进行数据处理) */
|
||||
export async function fetchDataWithAdapter() {
|
||||
const res = await mockRequest.post<ApiDemo.DataWithAdapter>('/apiDemoWithAdapter');
|
||||
return adapterOfServiceResult(adapterOfDataWithAdapter, res);
|
||||
return serviceAdapter(adapterOfFetchDataWithAdapter, res);
|
||||
}
|
||||
|
||||
/** 测试代理后的请求 */
|
||||
export function testRequestWithProxy() {
|
||||
return request.get('/test-proxy'); // 确保.env-config的url和当前地址组成的 `${url}/test-proxy` 是有效的后端接口
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { unref } from 'vue';
|
||||
import { unref, nextTick } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import { router as globalRouter } from '@/router';
|
||||
import { useRouterPush } from '@/composables';
|
||||
import { fetchLogin, fetchUserInfo } from '@/service';
|
||||
import { getUserInfo, getToken, setUserInfo, setToken, setRefreshToken, clearAuthStorage } from '@/utils';
|
||||
import { useTabStore } from '../tab';
|
||||
import { useRouteStore } from '../route';
|
||||
|
||||
interface AuthState {
|
||||
/** 用户信息 */
|
||||
@ -30,6 +32,8 @@ export const useAuthStore = defineStore('auth-store', {
|
||||
/** 重置auth状态 */
|
||||
resetAuthStore() {
|
||||
const { toLogin } = useRouterPush(false);
|
||||
const { resetTabStore } = useTabStore();
|
||||
const { resetRouteStore } = useRouteStore();
|
||||
const route = unref(globalRouter.currentRoute);
|
||||
|
||||
clearAuthStorage();
|
||||
@ -38,6 +42,11 @@ export const useAuthStore = defineStore('auth-store', {
|
||||
if (route.meta.requiresAuth) {
|
||||
toLogin();
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
resetTabStore();
|
||||
resetRouteStore();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 根据token进行登录
|
||||
@ -46,7 +55,7 @@ export const useAuthStore = defineStore('auth-store', {
|
||||
async loginByToken(backendToken: ApiAuth.Token) {
|
||||
const { toLoginRedirect } = useRouterPush(false);
|
||||
|
||||
// 先把token存储到缓存中
|
||||
// 先把token存储到缓存中(后面接口的请求头需要token)
|
||||
const { token, refreshToken } = backendToken;
|
||||
setToken(token);
|
||||
setRefreshToken(refreshToken);
|
||||
@ -76,13 +85,12 @@ export const useAuthStore = defineStore('auth-store', {
|
||||
},
|
||||
/**
|
||||
* 登录
|
||||
* @param phone - 手机号
|
||||
* @param pwdOrCode - 密码或验证码
|
||||
* @param type - 登录方式: pwd - 密码登录; sms - 验证码登录
|
||||
* @param userName - 用户名
|
||||
* @param password - 密码
|
||||
*/
|
||||
async login(phone: string, pwdOrCode: string, type: 'pwd' | 'sms') {
|
||||
async login(userName: string, password: string) {
|
||||
this.loginLoading = true;
|
||||
const { data } = await fetchLogin(phone, pwdOrCode, type);
|
||||
const { data } = await fetchLogin(userName, password);
|
||||
if (data) {
|
||||
await this.loginByToken(data);
|
||||
}
|
||||
|
@ -43,6 +43,9 @@ export const useRouteStore = defineStore('route-store', {
|
||||
cacheRoutes: []
|
||||
}),
|
||||
actions: {
|
||||
resetRouteStore() {
|
||||
this.$reset();
|
||||
},
|
||||
/**
|
||||
* 处理权限路由
|
||||
* @param routes - 权限路由
|
||||
@ -53,6 +56,7 @@ export const useRouteStore = defineStore('route-store', {
|
||||
this.searchMenus = transformAuthRoutesToSearchMenus(routes);
|
||||
|
||||
const vueRoutes = transformAuthRoutesToVueRoutes(routes);
|
||||
|
||||
vueRoutes.forEach(route => {
|
||||
router.addRoute(route);
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { Router, RouteLocationNormalizedLoaded } from 'vue-router';
|
||||
import { defineStore } from 'pinia';
|
||||
import { useRouterPush } from '@/composables';
|
||||
import { getTabRoutes } from '@/utils';
|
||||
import { getTabRoutes, clearTabRoutes } from '@/utils';
|
||||
import { useThemeStore } from '../theme';
|
||||
import { getTabRouteByVueRoute, isInTabRoutes, getIndexInTabRoutes } from './helpers';
|
||||
|
||||
@ -38,6 +38,11 @@ export const useTabStore = defineStore('tab-store', {
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
/** 重置Tab状态 */
|
||||
resetTabStore() {
|
||||
clearTabRoutes();
|
||||
this.$reset();
|
||||
},
|
||||
/**
|
||||
* 设置当前路由对应的页签为激活状态
|
||||
* @param path - 路由path
|
||||
|
@ -71,18 +71,3 @@ export function getNaiveThemeOverrides(colors: Record<ColorType, string>): Globa
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** windicss 暗黑模式 */
|
||||
export function handleWindicssDarkMode() {
|
||||
const DARK_CLASS = 'dark';
|
||||
function addDarkClass() {
|
||||
document.documentElement.classList.add(DARK_CLASS);
|
||||
}
|
||||
function removeDarkClass() {
|
||||
document.documentElement.classList.remove(DARK_CLASS);
|
||||
}
|
||||
return {
|
||||
addDarkClass,
|
||||
removeDarkClass
|
||||
};
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ export default function subscribeThemeStore() {
|
||||
const theme = useThemeStore();
|
||||
const osTheme = useOsTheme();
|
||||
const { width } = useElementSize(document.documentElement);
|
||||
const { addDarkClass, removeDarkClass } = handleWindicssDarkMode();
|
||||
const { addDarkClass, removeDarkClass } = handleCssDarkMode();
|
||||
|
||||
// 监听主题颜色
|
||||
const stopThemeColor = watch(
|
||||
@ -76,8 +76,8 @@ export default function subscribeThemeStore() {
|
||||
});
|
||||
}
|
||||
|
||||
/** windicss 暗黑模式 */
|
||||
function handleWindicssDarkMode() {
|
||||
/** css 暗黑模式 */
|
||||
function handleCssDarkMode() {
|
||||
const DARK_CLASS = 'dark';
|
||||
function addDarkClass() {
|
||||
document.documentElement.classList.add(DARK_CLASS);
|
||||
|
2
src/typings/business.d.ts
vendored
2
src/typings/business.d.ts
vendored
@ -15,8 +15,6 @@ declare namespace Auth {
|
||||
userId: string;
|
||||
/** 用户名 */
|
||||
userName: string;
|
||||
/** 用户手机号 */
|
||||
userPhone: string;
|
||||
/** 用户角色类型 */
|
||||
userRole: RoleType;
|
||||
}
|
||||
|
4
src/typings/env.d.ts
vendored
4
src/typings/env.d.ts
vendored
@ -8,9 +8,9 @@ type EnvType = 'dev' | 'test' | 'prod';
|
||||
|
||||
/** env环境配置 */
|
||||
interface EnvConfig {
|
||||
/** 请求地址 */
|
||||
/** 后端的请求地址 */
|
||||
url: string;
|
||||
/** 代理地址 */
|
||||
/** 代理标识, 用于拦截地址转发代理(如:"/api",这个和后端路径有无 "/api" 路径没有任何关系) */
|
||||
proxy: string;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,6 @@ export function getUserInfo() {
|
||||
const emptyInfo: Auth.UserInfo = {
|
||||
userId: '',
|
||||
userName: '',
|
||||
userPhone: '',
|
||||
userRole: 'user'
|
||||
};
|
||||
const userInfo: Auth.UserInfo = getLocal<Auth.UserInfo>(EnumStorageKey['user-info']) || emptyInfo;
|
||||
|
@ -22,7 +22,7 @@ export const formRules: CustomFormRules = {
|
||||
],
|
||||
pwd: [
|
||||
{ required: true, message: '请输入密码' },
|
||||
{ pattern: REGEXP_PWD, message: '密码为8-18位数字/字符/符号,至少2种组合', trigger: 'input' }
|
||||
{ pattern: REGEXP_PWD, message: '密码为6-18位数字/字符/符号,至少2种组合', trigger: 'input' }
|
||||
],
|
||||
code: [
|
||||
{ required: true, message: '请输入验证码' },
|
||||
|
@ -21,7 +21,7 @@ type Adapter<T = any> = (...args: Service.RequestResult[]) => T;
|
||||
* @param adapter - 适配器函数
|
||||
* @param args - 适配器函数的参数
|
||||
*/
|
||||
export function adapterOfServiceResult<T extends Adapter>(adapter: T, ...args: TypeUtil.GetFunArgs<T>) {
|
||||
export function serviceAdapter<T extends Adapter>(adapter: T, ...args: TypeUtil.GetFunArgs<T>) {
|
||||
let result: Service.RequestResult | undefined;
|
||||
|
||||
const hasError = args.some(item => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<n-card title="关于" :bordered="false" size="large" class="rounded-16px shadow-sm">
|
||||
<p class="leading-24px">
|
||||
<p class="leading-24px text-primary">
|
||||
Soybean Admin 是一个基于 Vue3、Vite、Naive UI、TypeScript
|
||||
的中后台解决方案,它使用了最新的前端技术栈,并提炼了典型的业务模型,页面,包括二次封装组件、动态菜单、权限校验、粒子化权限控制等功能,它可以帮助你快速搭建企业级中后台项目,相信不管是从新技术使用还是其他方面,都能帮助到你。
|
||||
</p>
|
||||
|
@ -106,11 +106,11 @@ const technology: Technology[] = [
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'WindiCSS',
|
||||
name: 'UnoCSS',
|
||||
description: '下一代实用优先的CSS框架',
|
||||
author: 'Windicss',
|
||||
site: 'https://windicss.org/',
|
||||
icon: 'file-icons:windi',
|
||||
author: 'Anthony Fu',
|
||||
site: 'https://uno.antfu.me/?s=',
|
||||
icon: 'logos:unocss',
|
||||
iconColor: '#48b0f1'
|
||||
},
|
||||
{
|
||||
|
@ -50,9 +50,9 @@ function handleSubmit(e: MouseEvent) {
|
||||
|
||||
formRef.value.validate(errors => {
|
||||
if (!errors) {
|
||||
window.$message?.success('验证成功');
|
||||
window.$message?.success('验证成功!');
|
||||
} else {
|
||||
window.$message?.error('验证失败');
|
||||
window.$message?.error('验证失败!');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ import { useSmsCode } from '@/hooks';
|
||||
import { formRules, getImgCodeRule } from '@/utils';
|
||||
|
||||
const auth = useAuthStore();
|
||||
const { login } = useAuthStore();
|
||||
const { toLoginModule } = useRouterPush();
|
||||
const { label, isCounting, loading: smsLoading, getSmsCode } = useSmsCode();
|
||||
|
||||
@ -70,8 +69,9 @@ function handleSubmit(e: MouseEvent) {
|
||||
|
||||
formRef.value.validate(errors => {
|
||||
if (!errors) {
|
||||
const { phone, code } = model;
|
||||
login(phone, code, 'sms');
|
||||
window.$message?.success('验证通过!');
|
||||
} else {
|
||||
window.$message?.error('验证失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<n-space :vertical="true">
|
||||
<n-divider class="!mb-0 text-14px text-[#666]">其他账户登录</n-divider>
|
||||
<n-space justify="center">
|
||||
<n-button
|
||||
v-for="item in accounts"
|
||||
:key="item.userName"
|
||||
type="primary"
|
||||
@click="login(item.userName, item.password)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
interface Emits {
|
||||
(e: 'login', param: { userName: string; password: string }): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const accounts = [
|
||||
{
|
||||
label: '超级管理员',
|
||||
userName: 'Super',
|
||||
password: 'super123'
|
||||
},
|
||||
{
|
||||
label: '管理员',
|
||||
userName: 'Admin',
|
||||
password: 'admin123'
|
||||
},
|
||||
{
|
||||
label: '普通用户',
|
||||
userName: 'User01',
|
||||
password: 'user01123'
|
||||
}
|
||||
];
|
||||
|
||||
function login(userName: string, password: string) {
|
||||
emit('login', { userName, password });
|
||||
}
|
||||
</script>
|
||||
<style scoped></style>
|
@ -1,3 +1,4 @@
|
||||
import OtherLogin from './OtherLogin.vue';
|
||||
import OtherAccount from './OtherAccount.vue';
|
||||
|
||||
export { OtherLogin };
|
||||
export { OtherLogin, OtherAccount };
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false">
|
||||
<n-form-item path="phone">
|
||||
<n-input v-model:value="model.phone" placeholder="请输入手机号码" />
|
||||
<n-form-item path="userName">
|
||||
<n-input v-model:value="model.userName" placeholder="请输入用户名" />
|
||||
</n-form-item>
|
||||
<n-form-item path="pwd">
|
||||
<n-input v-model:value="model.pwd" type="password" show-password-on="click" placeholder="请输入密码" />
|
||||
<n-form-item path="password">
|
||||
<n-input v-model:value="model.password" type="password" show-password-on="click" placeholder="请输入密码" />
|
||||
</n-form-item>
|
||||
<n-space :vertical="true" :size="24">
|
||||
<div class="flex-y-center justify-between">
|
||||
@ -31,7 +31,7 @@
|
||||
</n-button>
|
||||
</div>
|
||||
</n-space>
|
||||
<other-login />
|
||||
<other-account @login="handleLoginOtherAccount" />
|
||||
</n-form>
|
||||
</template>
|
||||
|
||||
@ -42,7 +42,7 @@ import { EnumLoginModule } from '@/enum';
|
||||
import { useAuthStore } from '@/store';
|
||||
import { useRouterPush } from '@/composables';
|
||||
import { formRules } from '@/utils';
|
||||
import { OtherLogin } from './components';
|
||||
import { OtherAccount } from './components';
|
||||
|
||||
const auth = useAuthStore();
|
||||
const { login } = useAuthStore();
|
||||
@ -50,12 +50,11 @@ const { toLoginModule } = useRouterPush();
|
||||
|
||||
const formRef = ref<(HTMLElement & FormInst) | null>(null);
|
||||
const model = reactive({
|
||||
phone: '15170283876',
|
||||
pwd: 'abc123456'
|
||||
userName: 'Soybean',
|
||||
password: 'soybean123'
|
||||
});
|
||||
const rules: FormRules = {
|
||||
phone: formRules.phone,
|
||||
pwd: formRules.pwd
|
||||
password: formRules.pwd
|
||||
};
|
||||
const rememberMe = ref(false);
|
||||
|
||||
@ -65,10 +64,15 @@ function handleSubmit(e: MouseEvent) {
|
||||
|
||||
formRef.value.validate(errors => {
|
||||
if (!errors) {
|
||||
const { phone, pwd } = model;
|
||||
login(phone, pwd, 'pwd');
|
||||
const { userName, password } = model;
|
||||
login(userName, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleLoginOtherAccount(param: { userName: string; password: string }) {
|
||||
const { userName, password } = param;
|
||||
login(userName, password);
|
||||
}
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
@ -63,9 +63,9 @@ function handleSubmit(e: MouseEvent) {
|
||||
formRef.value.validate(errors => {
|
||||
if (!errors) {
|
||||
if (!agreement.value) return;
|
||||
window.$message?.success('验证成功');
|
||||
window.$message?.success('验证成功!');
|
||||
} else {
|
||||
window.$message?.error('验证失败');
|
||||
window.$message?.error('验证失败!');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { defineConfig, presetMini } from 'unocss';
|
||||
|
||||
export default defineConfig({
|
||||
exclude: ['node_modules', '.git', './stats.html'],
|
||||
presets: [presetMini({ dark: 'class' })],
|
||||
shortcuts: {
|
||||
'wh-full': 'w-full h-full',
|
||||
|
Loading…
Reference in New Issue
Block a user