feat: 动态路由逻辑更改,添加id和parendId用于生成路由树(结构为01-01-01),mock不再返回顶层路由,顶层layout路由改为直接静态导入
This commit is contained in:
parent
1f7c398c50
commit
b8e0497b1f
@ -1,4 +1,2 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/husky.sh"
|
||||
|
||||
npx --no-install commitlint --edit $1
|
||||
. "${0%/*}/h"
|
||||
@ -1,4 +1,2 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname "$0")/husky.sh"
|
||||
|
||||
pnpm run lint:lint-staged
|
||||
. "${0%/*}/h"
|
||||
32
src/components.d.ts
vendored
32
src/components.d.ts
vendored
@ -5,22 +5,22 @@
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {}
|
||||
|
||||
declare module "vue" {
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
BarcodeDraw: (typeof import("./components/barcode-draw/index.vue"))["default"];
|
||||
CodeView: (typeof import("./components/code-view/index.vue"))["default"];
|
||||
ExternalLinkPage: (typeof import("./components/external-link-page/index.vue"))["default"];
|
||||
FillPage: (typeof import("./components/fill-page/index.vue"))["default"];
|
||||
InternalLinkPage: (typeof import("./components/internal-link-page/index.vue"))["default"];
|
||||
LangProvider: (typeof import("./components/lang-provider/index.vue"))["default"];
|
||||
MainTransition: (typeof import("./components/main-transition/index.vue"))["default"];
|
||||
PinyinPro: (typeof import("./components/pinyin-pro/index.vue"))["default"];
|
||||
QrcodeDraw: (typeof import("./components/qrcode-draw/index.vue"))["default"];
|
||||
RouterLink: (typeof import("vue-router"))["RouterLink"];
|
||||
RouterView: (typeof import("vue-router"))["RouterView"];
|
||||
SelectIcon: (typeof import("./components/select-icon/index.vue"))["default"];
|
||||
SvgAndIcon: (typeof import("./components/svg-and-icon/index.vue"))["default"];
|
||||
SvgIcon: (typeof import("./components/svg-icon/index.vue"))["default"];
|
||||
VerifyCode: (typeof import("./components/verify-code/index.vue"))["default"];
|
||||
BarcodeDraw: typeof import('./components/barcode-draw/index.vue')['default']
|
||||
CodeView: typeof import('./components/code-view/index.vue')['default']
|
||||
ExternalLinkPage: typeof import('./components/external-link-page/index.vue')['default']
|
||||
FillPage: typeof import('./components/fill-page/index.vue')['default']
|
||||
InternalLinkPage: typeof import('./components/internal-link-page/index.vue')['default']
|
||||
LangProvider: typeof import('./components/lang-provider/index.vue')['default']
|
||||
MainTransition: typeof import('./components/main-transition/index.vue')['default']
|
||||
PinyinPro: typeof import('./components/pinyin-pro/index.vue')['default']
|
||||
QrcodeDraw: typeof import('./components/qrcode-draw/index.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
SelectIcon: typeof import('./components/select-icon/index.vue')['default']
|
||||
SvgAndIcon: typeof import('./components/svg-and-icon/index.vue')['default']
|
||||
SvgIcon: typeof import('./components/svg-icon/index.vue')['default']
|
||||
VerifyCode: typeof import('./components/verify-code/index.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
4
src/config/index.ts
Normal file
4
src/config/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
// 系统全局配置
|
||||
|
||||
// 首页地址(默认)
|
||||
export const HOME_PATH: string = "/home";
|
||||
@ -14,10 +14,13 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useThemeConfig } from "@/store/modules/theme-config";
|
||||
import { useRoutesConfigStore } from "@/store/modules/route-config";
|
||||
import { useDevicesSize } from "@/hooks/useDevicesSize";
|
||||
|
||||
import { HOME_PATH } from "@/config/index";
|
||||
const themeStore = useThemeConfig();
|
||||
const { isBreadcrumb, transitionPage } = storeToRefs(themeStore);
|
||||
const routesConfigStore = useRoutesConfigStore();
|
||||
const { routeList } = storeToRefs(routesConfigStore);
|
||||
const { isMobile } = useDevicesSize();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@ -25,16 +28,17 @@ const router = useRouter();
|
||||
/**
|
||||
* 获取面包屑
|
||||
* 根据当前路由信息获取,route.matched可以获取当前路由的所有父级路由信息
|
||||
* 如果当前路由是顶层的重定向路由,则只返回当前路由信息(说明当前就是顶层)
|
||||
* 如果当前路由是home路由,则只返回当前路由信息(说明当前就是顶层)
|
||||
* 否则返回所有父级路由信息,顶层路由重写为首页
|
||||
*/
|
||||
const breadcrumb = computed(() => {
|
||||
if (route.path === route.matched[0].redirect) {
|
||||
return [route];
|
||||
}
|
||||
// 如果是首页则直接返回当前路由信息
|
||||
if (route.path === HOME_PATH) return [route];
|
||||
|
||||
// 否则返回路径信息
|
||||
return route.matched.map((item: any) => {
|
||||
if (item.name == "/") {
|
||||
return item.children[0];
|
||||
if (item.name == "layout") {
|
||||
return routeList.value.find((item: any) => item.path == HOME_PATH);
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
@ -55,7 +59,7 @@ const transition = computed(() => {
|
||||
// 面包屑跳转
|
||||
const onBreadcrumb = (route: any) => {
|
||||
let path = route.redirect || route.path;
|
||||
router.replace((path as string) || "");
|
||||
router.replace((path as string) || HOME_PATH);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -14,9 +14,8 @@ import systemMenu from "../_data/system_menu";
|
||||
* 1、将模块设置为真实模块
|
||||
* 2、存储路由树,用于生成菜单
|
||||
* 3、根据树生成一维路由数组
|
||||
* 4、动态添加路由,设置完整的路由,二维路由:顶层路由 + 二级的一维路由
|
||||
* 5、动态添加路由
|
||||
* 6、缓存一维路由
|
||||
* 4、动态添加路由
|
||||
* 5、缓存一维路由
|
||||
*/
|
||||
|
||||
// post请求body,get请求query
|
||||
@ -30,8 +29,7 @@ export default [
|
||||
// 这里模拟两个角色,admin、common
|
||||
let userRoles = token === "Admin-Token" ? ["admin"] : ["common"];
|
||||
const originTree: any = deepClone(systemMenu);
|
||||
originTree[0].children = treeSort(filterByRole(originTree[0].children, userRoles));
|
||||
return resultSuccess(originTree);
|
||||
return resultSuccess(treeSort(filterByRole(originTree, userRoles)));
|
||||
}
|
||||
}
|
||||
] as MockMethod[];
|
||||
|
||||
@ -17,10 +17,10 @@ const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
/**
|
||||
* 设置静态路由,其它的路由通过addRoute动态添加
|
||||
* 1、staticRoutes登录页
|
||||
* 2、notFoundAndNoPower 添加默认 404、401界面,防止提示 No match found for location with path 'xxx'
|
||||
* 2、后端控制路由中也需要添加 notFoundAndNoPower 404、401界面
|
||||
* 静态添加 notFoundAndNoPower 404、401界面将全屏显示
|
||||
* 1、staticRoutes登录页、layout页、默认页面('/')
|
||||
* 2、notFoundAndNoPower 添加默认 401、500界面,防止提示 No match found for location with path 'xxx'
|
||||
* 2、后端控制路由中也需要添加 notFoundAndNoPower 401、500界面
|
||||
* 静态添加 notFoundAndNoPower 401、500界面将全屏显示
|
||||
* 如果要 notFoundAndNoPower 在layout容器展示,则需要移除静态添加并将其添加到缓存路由树
|
||||
*/
|
||||
routes: [...staticRoutes, ...notFoundAndNoPower]
|
||||
|
||||
@ -4,7 +4,6 @@ import { useRoutesConfigStore } from "@/store/modules/route-config";
|
||||
import { useThemeConfig } from "@/store/modules/theme-config";
|
||||
import { deepClone, arrayFlattened } from "@/utils/index";
|
||||
import { useRoutingMethod } from "@/hooks/useRoutingMethod";
|
||||
import Layout from "@/layout/index.vue";
|
||||
|
||||
/**
|
||||
* 路由树转一维数组
|
||||
@ -67,19 +66,13 @@ export const moduleReplacement = (tree: any) => {
|
||||
/**
|
||||
* 模块匹配
|
||||
* 1、导入 views 目录及其子目录下的所有 .vue 文件。
|
||||
* 2、匹配顶层layout,替换真实模块,layout为应用的基础结构
|
||||
* 3、匹配views下的所有文件路径,将模块转换为按需引入的真实模块
|
||||
* 4、未匹配上,不做处理
|
||||
* 2、匹配views下的所有文件路径,将模块转换为按需引入的真实模块
|
||||
* 3、未匹配上,不做处理
|
||||
*/
|
||||
// 匹配views里面所有的.vue文件
|
||||
const modules = import.meta.glob("@/views/**/*.vue");
|
||||
export const moduleMatch = (item: any) => {
|
||||
// 若是layout,则直接给予顶层layout
|
||||
if (item.component === "layout") {
|
||||
// 布局组件是应用的基础结构,在应用启动时就需要被加载,因此不需要按需引入
|
||||
return (item.component = Layout);
|
||||
}
|
||||
// 其它情况下,匹配每个views文件夹下的文件路径
|
||||
// 匹配每个views文件夹下的文件路径
|
||||
for (const key in modules) {
|
||||
const dir = key.split("views/")[1].replace(".vue", "");
|
||||
// 若匹配上,则替换真实模块
|
||||
|
||||
@ -1,29 +1,35 @@
|
||||
import { HOME_PATH } from "@/config/index";
|
||||
import Layout from "@/layout/index.vue";
|
||||
/**
|
||||
* 路由path路径与文件夹名称相同,找文件可以浏览器地址快速查找,方便定位文件
|
||||
*
|
||||
* 路由meta对象参数,我们通常将属性放到meta对象中
|
||||
* meta: {
|
||||
* title: 菜单栏以及 tabsView 栏、菜单搜索名称(国际化)
|
||||
* hide: 是否隐藏此路由,不会显示在菜单树,可以访问
|
||||
* disable: 是否停用,不会显示在菜单树,且不可访问
|
||||
* keepAlive: 是否缓存组件状态
|
||||
* affix: 是否固定在 tabsView 栏上
|
||||
* link: 是否是超链接菜单,开启外链条件:1、 link:链接地址不为空 2、iframe: false
|
||||
* iframe: 是否内嵌窗口,开启条件:1、iframe:true 2、link:链接地址不为空
|
||||
* roles: 当前路由权限表示,取角色管理。路由控制显示、隐藏。 超级管理员:admin;普通角色:common
|
||||
* icon: 菜单、tabsView 图标等
|
||||
* svgIcon: svg图标
|
||||
* sort: 排序
|
||||
* title: 菜单栏以及 tabsView 栏、菜单搜索名称(国际化)
|
||||
* hide: 是否隐藏此路由,不会显示在菜单树,可以访问
|
||||
* disable: 是否停用,不会显示在菜单树,且不可访问
|
||||
* keepAlive: 是否缓存组件状态
|
||||
* affix: 是否固定在 tabsView 栏上
|
||||
* link: 是否是超链接菜单,开启外链条件:1、 link:链接地址不为空 2、iframe: false
|
||||
* iframe: 是否内嵌窗口,开启条件:1、iframe:true 2、link:链接地址不为空
|
||||
* roles: 当前路由权限表示,取角色管理。路由控制显示、隐藏。 超级管理员:admin;普通角色:common
|
||||
* icon: 菜单、tabsView 图标等
|
||||
* svgIcon: svg图标
|
||||
* sort: 菜单顺序
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* 静态路由 (默认路由)
|
||||
* 此路由不要动,用于做静态路由定向,如果要添加路由,请在 `dynamicRoutes数组` 中添加
|
||||
* @description 前端控制路由 直接改 dynamicRoutes 中的路由,后端控制则不需要,请求接口路由数据时,覆盖 dynamicRoutes 第一个顶层 children 的内容(全屏,不包括 lauyout 中的路由出口)
|
||||
* 此路由不要动,用于做静态路由定向,如果要添加路由,请在 `layout-children` 中添加
|
||||
* @description 前端控制路由 直接改 mock/_data/system_menu 中的路由,后端控制则不需要
|
||||
* @returns 返回路由菜单数据
|
||||
*/
|
||||
export const staticRoutes = [
|
||||
{
|
||||
path: "/",
|
||||
redirect: HOME_PATH
|
||||
},
|
||||
{
|
||||
path: "/login",
|
||||
name: "login",
|
||||
@ -31,10 +37,18 @@ export const staticRoutes = [
|
||||
meta: {
|
||||
title: "login"
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/layout",
|
||||
name: "layout",
|
||||
redirect: HOME_PATH,
|
||||
component: Layout, // 容器布局-顶层路由
|
||||
// 二级路由-主要渲染页面
|
||||
children: []
|
||||
}
|
||||
/**
|
||||
* 提示:写在这里的为全屏界面,不建议写在这里
|
||||
* 非全屏界面,请写在 dynamicRoutes 路由数组中
|
||||
* 提示:写在这里的为全屏界面,不建议写在这里非全屏界面,请写在 layout.children 路由数组中
|
||||
*
|
||||
*/
|
||||
];
|
||||
|
||||
|
||||
@ -86,9 +86,8 @@ export const routesConfigStore = () => {
|
||||
* 2、将模块设置为真实模块
|
||||
* 3、存储路由树,用于生成菜单
|
||||
* 4、根据树生成一维路由数组
|
||||
* 5、动态添加路由,设置完整的路由,二维路由:顶层路由 + 二级的一维路由
|
||||
* 6、动态添加路由
|
||||
* 7、缓存一维路由
|
||||
* 5、动态添加路由
|
||||
* 6、缓存一维路由
|
||||
*/
|
||||
async function initSetRouter() {
|
||||
// 1、获取过滤角色权限后的树,后端做排序处理
|
||||
@ -96,15 +95,13 @@ export const routesConfigStore = () => {
|
||||
// 2、将模块设置为真实模块
|
||||
let tree = await moduleReplacement(data);
|
||||
// 3、存储路由树,用于生成菜单
|
||||
routeTree.value = tree[0].children;
|
||||
routeTree.value = tree;
|
||||
// 4、根据树生成一维路由数组
|
||||
tree[0].children = linearArray(tree[0].children);
|
||||
// 5、设置完整的路由,二维路由:顶层路由 + 二级的一维路由
|
||||
tree[0].redirect = tree[0].children[0].path;
|
||||
// 6、动态添加路由
|
||||
tree.forEach((route: any) => router.addRoute(route));
|
||||
// 7、缓存一维路由
|
||||
routeList.value = tree[0].children;
|
||||
tree = linearArray(tree);
|
||||
// 5、动态添加路由
|
||||
tree.forEach((route: any) => router.addRoute("layout", route));
|
||||
// 6、缓存一维路由
|
||||
routeList.value = tree;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@ -95,7 +95,7 @@ import MenuItemIcon from "@/layout/components/Menu/menu-item-icon.vue";
|
||||
import dynamicRoutes from "@/mock/_data/system_menu";
|
||||
|
||||
const tableData = computed(() => {
|
||||
return dynamicRoutes[0].children;
|
||||
return dynamicRoutes;
|
||||
});
|
||||
const formData = reactive({
|
||||
form: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user