feat(projects): 新增静态路由

This commit is contained in:
Soybean 2022-03-30 01:19:37 +08:00
parent bbfdcc8276
commit ca2dfa6185
34 changed files with 1591 additions and 1875 deletions

4
.env
View File

@ -8,5 +8,5 @@ VITE_APP_DESC=SoybeanAdmin是一个中后台管理系统模版
VITE_SERVER_PORT=3200
VITE_HTTP_PROXY=true
# 权限路由模式: static dynamic
VITE_AUTH_ROUTE_MODE=dynamic

View File

@ -9,7 +9,7 @@ type ServiceEnv = Record<
}
>;
/** 请求的环境 */
/** 环境配置 */
const serviceEnvConfig: ServiceEnv = {
dev: {
url: 'http://localhost:8080',

View File

@ -1,2 +1,3 @@
# 是否开启打包文件大小结果分析
VITE_HTTP_PROXY=true
VITE_VISUALIZER=false

View File

@ -50,14 +50,15 @@ Soybean Admin 是一个基于 Vue3、Vite、TypeScript、Naive UI 的免费中
## 开发计划
- [ ] 添加前端静态路由
- [x] 添加前端静态路由
- [ ] 用户角色切换示例、按钮级别权限指令
- [ ] 最近功能的有关文档更新
- [ ] 引入ECharts替换AntV G2Plot
- [ ] 性能优化(优化递归函数)
- [ ] 精简版(新分支thin)
- [ ] 集成unocss替换windicss(新分支unocss)
- [ ] 表单、表格示例
- [ ] 添加锁屏组件、全局Iframe组件
- [ ] 用户角色切换示例、按钮级别权限指令
- [ ] 示例页面完善
- [ ] 其他UI版本
- [ ] element-plus版本
@ -133,7 +134,7 @@ pnpm i -g commitizen
- 微信交流群:
<div style="text-align:left">
<img src="https://s2.loli.net/2022/03/23/pNiaVoP6yIvtS5C.jpg" style="width:200px" />
<img src="https://s2.loli.net/2022/03/30/VpmnTMsgXJH72B9.jpg" style="width:200px" />
</div>
- QQ交流群 `711301266`

View File

@ -3,7 +3,7 @@ import { getEnvConfig } from '../../.env-config';
/**
*
* @param viteEnv
* @param viteEnv - vite环境描述
*/
export function createViteProxy(viteEnv: ImportMetaEnv) {
const isOpenProxy = viteEnv.VITE_HTTP_PROXY === 'true';

26
components.d.ts vendored
View File

@ -10,33 +10,7 @@ declare module 'vue' {
DarkModeSwitch: typeof import('./src/components/common/DarkModeSwitch.vue')['default']
GithubLink: typeof import('./src/components/custom/GithubLink.vue')['default']
HoverContainer: typeof import('./src/components/common/HoverContainer.vue')['default']
IconAntDesignCloseOutlined: typeof import('~icons/ant-design/close-outlined')['default']
IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
IconCustomAvatar: typeof import('~icons/custom/avatar')['default']
IconCustomLogo: typeof import('~icons/custom/logo')['default']
IconCustomLogoFill: typeof import('~icons/custom/logo-fill')['default']
IconCustomNoPermission: typeof import('~icons/custom/no-permission')['default']
IconCustomNotFound: typeof import('~icons/custom/not-found')['default']
IconCustomServiceError: typeof import('~icons/custom/service-error')['default']
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
IconIcOutlineCheck: typeof import('~icons/ic/outline-check')['default']
IconLineMdMenuFoldLeft: typeof import('~icons/line-md/menu-fold-left')['default']
IconLineMdMenuUnfoldLeft: typeof import('~icons/line-md/menu-unfold-left')['default']
IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default']
IconMdiClose: typeof import('~icons/mdi/close')['default']
IconMdiGithub: typeof import('~icons/mdi/github')['default']
IconMdiMoonWaningCrescent: typeof import('~icons/mdi/moon-waning-crescent')['default']
IconMdiPin: typeof import('~icons/mdi/pin')['default']
IconMdiPinOff: typeof import('~icons/mdi/pin-off')['default']
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
IconMdiWhiteBalanceSunny: typeof import('~icons/mdi/white-balance-sunny')['default']
IconPhCaretDoubleLeftBold: typeof import('~icons/ph/caret-double-left-bold')['default']
IconPhCaretDoubleRightBold: typeof import('~icons/ph/caret-double-right-bold')['default']
IconSelect: typeof import('./src/components/custom/IconSelect.vue')['default']
IconUilSearch: typeof import('~icons/uil/search')['default']
ImageVerify: typeof import('./src/components/custom/ImageVerify.vue')['default']
LoadingEmptyWrapper: typeof import('./src/components/business/LoadingEmptyWrapper.vue')['default']
LoginAgreement: typeof import('./src/components/business/LoginAgreement.vue')['default']

View File

@ -69,16 +69,6 @@ const routes: AuthRoute.Route[] = [
icon: 'simple-icons:vite',
},
},
{
name: 'document_naive',
path: '/document/naive',
component: 'self',
meta: {
title: 'naive文档',
requiresAuth: true,
icon: 'mdi:alpha-n-box-outline',
},
},
{
name: 'document_project',
path: '/document/project',

View File

@ -26,18 +26,18 @@
}
},
"dependencies": {
"@antv/g2plot": "^2.4.10",
"@antv/g2plot": "^2.4.13",
"@better-scroll/core": "^2.4.2",
"@vueuse/core": "^8.0.0",
"@vueuse/core": "^8.2.0",
"axios": "^0.26.1",
"clipboard": "^2.0.10",
"colord": "^2.9.2",
"crypto-js": "^4.1.1",
"dayjs": "^1.10.8",
"dayjs": "^1.11.0",
"form-data": "^4.0.0",
"lodash-es": "^4.17.21",
"naive-ui": "^2.26.4",
"pinia": "^2.0.11",
"naive-ui": "^2.27.0",
"pinia": "^2.0.12",
"print-js": "^1.6.0",
"qs": "^6.10.3",
"soybean-admin-layout": "^1.0.4",
@ -52,17 +52,17 @@
},
"devDependencies": {
"@amap/amap-jsapi-types": "^0.0.8",
"@commitlint/cli": "^16.2.1",
"@commitlint/cli": "^16.2.3",
"@commitlint/config-conventional": "^16.2.1",
"@iconify/json": "^2.1.14",
"@iconify/vue": "^3.1.4",
"@iconify/json": "^2.1.21",
"@iconify/vue": "^3.2.0",
"@types/bmapgl": "^0.0.5",
"@types/crypto-js": "^4.1.1",
"@types/node": "^17.0.21",
"@types/node": "^17.0.23",
"@types/qs": "^6.9.7",
"@types/ua-parser-js": "^0.7.36",
"@typescript-eslint/eslint-plugin": "^5.14.0",
"@typescript-eslint/parser": "^5.14.0",
"@typescript-eslint/eslint-plugin": "^5.17.0",
"@typescript-eslint/parser": "^5.17.0",
"@vitejs/plugin-vue": "^2.2.4",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^10.0.0",
@ -71,30 +71,30 @@
"cross-env": "^7.0.3",
"cz-conventional-changelog": "^3.3.0",
"cz-customizable": "^6.3.0",
"eslint": "^8.11.0",
"eslint": "^8.12.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.5.0",
"husky": "^7.0.4",
"lint-staged": "^12.3.5",
"lint-staged": "^12.3.7",
"mockjs": "^1.1.0",
"patch-package": "^6.4.7",
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.5.1",
"prettier": "^2.6.1",
"rollup-plugin-visualizer": "^5.6.0",
"sass": "^1.49.9",
"typescript": "~4.6.2",
"unplugin-icons": "^0.13.3",
"unplugin-vue-components": "^0.18.0",
"typescript": "^4.6.3",
"unplugin-icons": "^0.14.1",
"unplugin-vue-components": "^0.18.5",
"vite": "2.8.6",
"vite-plugin-html": "^3.1.0",
"vite-plugin-html": "^3.2.0",
"vite-plugin-html-template": "^1.1.2",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-windicss": "^1.8.3",
"vue-tsc": "^0.32.1",
"vueuc": "^0.4.27",
"vue-tsc": "^0.33.9",
"vueuc": "^0.4.28",
"windicss": "^3.5.1"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
import type { App, Directive } from 'vue';
import { useAuthStore } from '@/store';
export default function setupLoginDirective(app: App) {
const auth = useAuthStore();
const loginDirective: Directive<HTMLElement, Auth.RoleType | undefined> = {
mounted(el: HTMLElement, binding) {
if (binding.value !== auth.userInfo.userRole) {
el.remove();
}
},
};
app.directive('login', loginDirective);
}

View File

@ -15,9 +15,9 @@ export async function createDynamicRouteGuard(
const route = useRouteStore();
const isLogin = Boolean(getToken());
// 初始化动态路由
if (!route.isAddedDynamicRoute) {
// 未登录情况下直接回到登录页,登录成功后再加载动态路由
// 初始化权限路由
if (!route.isInitedAuthRoute) {
// 未登录情况下直接回到登录页,登录成功后再加载权限路由
if (!isLogin) {
if (to.name === routeName('login')) {
next();
@ -28,16 +28,16 @@ export async function createDynamicRouteGuard(
return false;
}
await route.initDynamicRoute(router);
await route.initAuthRoute(router);
if (to.name === routeName('not-found-page')) {
// 动态路由没有加载导致被not-found-page路由捕获等待动态路由加载好了,回到之前的路由
// 动态路由没有加载导致被not-found-page路由捕获等待权限路由加载好了,回到之前的路由
next({ path: to.fullPath, replace: true, query: to.query });
return false;
}
}
// 动态路由已经加载仍然未找到重定向到not-found
// 权限路由已经加载仍然未找到重定向到not-found
if (to.name === routeName('not-found-page')) {
next({ name: routeName('not-found'), replace: true });
return false;

View File

@ -21,3 +21,4 @@ export async function setupRouter(app: App) {
}
export * from './routes';
export * from './modules';

View File

@ -0,0 +1,15 @@
const about: AuthRoute.Route = {
name: 'about',
path: '/about',
component: 'self',
meta: {
title: '关于',
requiresAuth: true,
singleLayout: 'basic',
permissions: ['super', 'admin', 'test'],
icon: 'fluent:book-information-24-regular',
order: 7,
},
};
export default about;

View File

@ -0,0 +1,44 @@
const component: AuthRoute.Route = {
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,
},
};
export default component;

View File

@ -0,0 +1,35 @@
const dashboard: 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,
},
};
export default dashboard;

View File

@ -0,0 +1,54 @@
const document: AuthRoute.Route = {
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,
},
};
export default document;

View File

@ -0,0 +1,44 @@
const exception: AuthRoute.Route = {
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: 5,
},
};
export default exception;

View File

@ -0,0 +1,5 @@
import { handleModuleRoutes } from '@/utils';
const modules = import.meta.globEager('./**/*.ts') as AuthRoute.RouteModule;
export const routes = handleModuleRoutes(modules);

View File

@ -0,0 +1,56 @@
const multiMenu: AuthRoute.Route = {
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: 6,
},
};
export default multiMenu;

View File

@ -0,0 +1,105 @@
const plugin: AuthRoute.Route = {
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,
},
};
export default plugin;

View File

@ -1,5 +1,6 @@
import type { Router } from 'vue-router';
import { defineStore } from 'pinia';
import { routes as staticRoutes } from '@/router';
import { fetchUserRoutes } from '@/service';
import {
getUserInfo,
@ -11,9 +12,15 @@ import {
import { useTabStore } from '../tab';
interface RouteState {
/** 是否添加过动态路由 */
isAddedDynamicRoute: boolean;
/** 路由首页name */
/**
* :
* - static -
* - dynamic -
*/
authRouteMode: ImportMetaEnv['VITE_AUTH_ROUTE_MODE'];
/** 是否初始化了权限路由 */
isInitedAuthRoute: boolean;
/** 路由首页name(前端静态路由时生效,后端动态路由该值会被后端返回的值覆盖) */
routeHomeName: AuthRoute.RouteKey;
/** 菜单 */
menus: GlobalMenuOption[];
@ -25,38 +32,69 @@ interface RouteState {
export const useRouteStore = defineStore('route-store', {
state: (): RouteState => ({
isAddedDynamicRoute: false,
authRouteMode: import.meta.env.VITE_AUTH_ROUTE_MODE,
isInitedAuthRoute: false,
routeHomeName: 'dashboard_analysis',
menus: [],
searchMenus: [],
cacheRoutes: [],
}),
actions: {
/**
*
* @param routes -
* @param router -
*/
handleAuthRoutes(routes: AuthRoute.Route[], router: Router) {
this.menus = transformAuthRouteToMenu(routes);
this.searchMenus = transformAuthRoutesToSearchMenus(routes);
const vueRoutes = transformAuthRoutesToVueRoutes(routes);
vueRoutes.forEach((route) => {
router.addRoute(route);
});
this.cacheRoutes = getCacheRoutes(vueRoutes);
},
/**
*
* @param router -
*/
async initDynamicRoute(router: Router) {
const { initHomeTab } = useTabStore();
const { userId } = getUserInfo();
if (!userId) return;
const { data } = await fetchUserRoutes(userId);
if (data) {
this.routeHomeName = data.home;
this.menus = transformAuthRouteToMenu(data.routes);
this.searchMenus = transformAuthRoutesToSearchMenus(data.routes);
const vueRoutes = transformAuthRoutesToVueRoutes(data.routes);
vueRoutes.forEach((route) => {
router.addRoute(route);
});
this.cacheRoutes = getCacheRoutes(vueRoutes);
initHomeTab(data.home, router);
this.isAddedDynamicRoute = true;
this.handleAuthRoutes(data.routes, router);
}
},
/**
*
* @param router -
*/
async initStaticRoute(router: Router) {
// 先根据用户权限过滤一下staticRoutes
this.handleAuthRoutes(staticRoutes, router);
},
/**
*
* @param router -
*/
async initAuthRoute(router: Router) {
const { initHomeTab } = useTabStore();
const { userId } = getUserInfo();
if (!userId) return;
const isDynamicRoute = this.authRouteMode === 'dynamic';
if (isDynamicRoute) {
await this.initDynamicRoute(router);
} else {
await this.initStaticRoute(router);
}
initHomeTab(this.routeHomeName, router);
this.isInitedAuthRoute = true;
},
},
});

View File

@ -1,13 +1,13 @@
/** 用户相关模块 */
declare namespace Auth {
/**
*
* - super:
* ()
* - super: ()
* - admin: 管理员
* - test: 测试
* - visitor: 游客
* - normal: 普通用户
*/
type RoleType = 'super' | 'admin' | 'test' | 'visitor';
type RoleType = 'super' | 'admin' | 'test' | 'normal';
/** 用户信息 */
interface UserInfo {

12
src/typings/env.d.ts vendored
View File

@ -7,7 +7,12 @@ declare module '*.vue' {
export default component;
}
/** env环境类型 */
/**
* env环境类型
* - dev: 后台开发环境
* - test: 后台测试环境
* - prod: 后台生产环境
*/
type EnvType = 'dev' | 'test' | 'prod';
interface ImportMetaEnv {
@ -21,6 +26,11 @@ interface ImportMetaEnv {
readonly VITE_APP_DESC: string;
/** 开发启动的服务端口号 */
readonly VITE_SERVER_PORT: string;
/**
* :
* - static -
* - dynamic - */
readonly VITE_AUTH_ROUTE_MODE: 'static' | 'dynamic';
/** vite环境类型 */
readonly VITE_ENV_TYPE?: EnvType;
/** 开启请求代理 */

View File

@ -73,7 +73,10 @@ declare namespace AuthRoute {
singleLayout?: Extract<RouteComponent, 'basic' | 'blank'>;
/** 需要登录权限 */
requiresAuth?: boolean;
/** 哪些类型的用户有权限才能访问的路由(空的话则表示不需要权限) */
/**
* 访()
* @description
*/
permissions?: Auth.RoleType[];
/** 缓存页面 */
keepAlive?: boolean;
@ -89,7 +92,7 @@ declare namespace AuthRoute {
multi?: boolean;
};
/** 单个路由的类型结构(后端返回此类型结构的路由) */
/** 单个路由的类型结构(动态路由模式:后端返回此类型结构的路由) */
interface Route {
/** 路由名称(路由唯一标识) */
name: RouteKey;
@ -113,6 +116,9 @@ declare namespace AuthRoute {
props?: boolean | Record<string, any> | ((to: any) => Record<string, any>);
}
/** 前端导入的路由模块 */
type RouteModule = Record<string, { default: AuthRoute.Route }>;
/** 单独一级路由的key (单独路由需要添加一个父级路由用于应用布局组件) */
type SingleRouteKey = Exclude<
GetSingleRouteKey<RouteKey>,

View File

@ -37,7 +37,7 @@ export function getUserInfo() {
userId: '',
userName: '',
userPhone: '',
userRole: 'visitor',
userRole: 'test',
};
const userInfo: Auth.UserInfo = getLocal<Auth.UserInfo>(EnumStorageKey['user-info']) || emptyInfo;
return userInfo;

View File

@ -27,7 +27,7 @@ export function transformToTimeCountDown(seconds: number) {
* @param start -
* @param end -
*/
export function getRandomInterger(end: number, start = 0) {
export function getRandomInteger(end: number, start = 0) {
const range = end - start;
const random = Math.floor(Math.random() * range + start);
return random;

View File

@ -5,7 +5,6 @@ const CryptoSecret = '__CryptoJS_Secret__';
/**
*
* @param data -
* @param secret -
*/
export function encrypto(data: any) {
const newData = JSON.stringify(data);
@ -14,11 +13,10 @@ export function encrypto(data: any) {
/**
*
* @param ciphertext -
* @param secret -
* @param cipherText -
*/
export function decrypto(ciphertext: string) {
const bytes = CryptoJS.AES.decrypt(ciphertext, CryptoSecret);
export function decrypto(cipherText: string) {
const bytes = CryptoJS.AES.decrypt(cipherText, CryptoSecret);
const originalText = bytes.toString(CryptoJS.enc.Utf8);
if (originalText) {
return JSON.parse(originalText);

23
src/utils/router/auth.ts Normal file
View File

@ -0,0 +1,23 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/**
*
* @param routes -
* @param permission -
*/
export function filterAuthRoutesByUserPermission(routes: AuthRoute.Route[], permission: Auth.RoleType) {
const filters: AuthRoute.Route[] = [];
routes.forEach((route) => {
filterAuthRouteByUserPermission(route, permission);
});
return filters;
}
/**
*
* @param route -
* @param permission -
*/
function filterAuthRouteByUserPermission(route: AuthRoute.Route, permission: Auth.RoleType): AuthRoute.Route[] {
return [];
}

View File

@ -33,7 +33,7 @@ export function transformAuthRoutesToSearchMenus(routes: AuthRoute.Route[], tree
/**
* vue路由
* @param route -
* @param item -
*/
function transformAuthRouteToVueRoute(item: AuthRoute.Route) {
const resultRoute: RouteRecordRaw[] = [];

View File

@ -1,3 +1,4 @@
export * from './module';
export * from './helpers';
export * from './cache';
export * from './menu';

View File

@ -0,0 +1,28 @@
import { consoleError } from '../common';
/**
*
* @param routes -
*/
function sortRoutes(routes: AuthRoute.Route[]) {
return routes.sort((next, pre) => Number(next.meta?.order) - Number(pre.meta?.order));
}
/**
*
* @param modules -
*/
export function handleModuleRoutes(modules: AuthRoute.RouteModule) {
const routes: AuthRoute.Route[] = [];
Object.keys(modules).forEach((key) => {
const item = modules[key].default;
if (item) {
routes.push(item);
} else {
consoleError(`路由模块解析出错: key = ${key}`);
}
});
return sortRoutes(routes);
}

View File

@ -18,7 +18,7 @@
import { ref, onMounted } from 'vue';
import type { DataTableColumn } from 'naive-ui';
import { useLoadingEmpty } from '@/hooks';
import { getRandomInterger } from '@/utils';
import { getRandomInteger } from '@/utils';
interface DataSource {
name: string;
@ -52,7 +52,7 @@ function createDataSource(): DataSource[] {
.map((_item, index) => {
return {
name: `Name${index}`,
age: getRandomInterger(30, 20),
age: getRandomInteger(30, 20),
address: '中国',
};
});

View File

@ -5,6 +5,6 @@
</template>
<script setup lang="ts">
const src = 'https://www.naiveui.com';
const src = 'https://www.naiveui.com/zh-CN/os-theme/docs/introduction';
</script>
<style scoped></style>

View File

@ -5,8 +5,8 @@
"src/**/*",
"src/**/*.vue",
"vite.config.*",
"mock/**/*.ts",
"build/**/*.ts",
"mock/**/*.ts",
".env-config.ts",
"components.d.ts"
],