mirror of
https://gitee.com/yiming_chang/vue-pure-admin.git
synced 2024-11-30 02:07:38 +08:00
feat: 添加菜单树结构事例
This commit is contained in:
parent
eb0771e7ec
commit
10fa0ee8c8
@ -13,6 +13,8 @@ export function findIconReg(icon: string) {
|
||||
const faReg = /^FA-/;
|
||||
// iconfont
|
||||
const iFReg = /^IF-/;
|
||||
// remixicon
|
||||
const riReg = /^RI-/;
|
||||
// typeof icon === "function" 属于SVG
|
||||
if (faReg.test(icon)) {
|
||||
const text = icon.split(faReg)[1];
|
||||
@ -25,12 +27,14 @@ export function findIconReg(icon: string) {
|
||||
return findIcon(icon.split(iFReg)[1], "IF");
|
||||
} else if (typeof icon === "function") {
|
||||
return findIcon(icon, "SVG");
|
||||
} else if (riReg.test(icon)) {
|
||||
return findIcon(icon.split(riReg)[1], "RI");
|
||||
} else {
|
||||
return findIcon(icon, "EL");
|
||||
}
|
||||
}
|
||||
|
||||
// 支持fontawesome、iconfont、element-plus/icons、自定义svg
|
||||
// 支持fontawesome、iconfont、remixicon、element-plus/icons、自定义svg
|
||||
export function findIcon(icon: String, type = "EL", property?: string) {
|
||||
if (type === "FA") {
|
||||
return defineComponent({
|
||||
@ -49,6 +53,14 @@ export function findIcon(icon: String, type = "EL", property?: string) {
|
||||
},
|
||||
template: `<i :class="icon" />`
|
||||
});
|
||||
} else if (type === "RI") {
|
||||
return defineComponent({
|
||||
name: "RIIcon",
|
||||
data() {
|
||||
return { icon: `ri-${icon}` };
|
||||
},
|
||||
template: `<i :class="icon" />`
|
||||
});
|
||||
} else if (type === "EL") {
|
||||
const components = iconComponents.filter(
|
||||
component => component.name === icon
|
||||
|
@ -43,6 +43,7 @@ import {
|
||||
ElEmpty,
|
||||
ElCollapse,
|
||||
ElCollapseItem,
|
||||
ElTreeV2,
|
||||
// 指令
|
||||
ElLoading,
|
||||
ElInfiniteScroll
|
||||
@ -94,7 +95,8 @@ const components = [
|
||||
ElAvatar,
|
||||
ElEmpty,
|
||||
ElCollapse,
|
||||
ElCollapseItem
|
||||
ElCollapseItem,
|
||||
ElTreeV2
|
||||
];
|
||||
|
||||
// https://element-plus.org/zh-CN/component/icon.html
|
||||
|
@ -43,6 +43,7 @@ export const menusConfig = {
|
||||
permissionPage: "页面权限",
|
||||
permissionButton: "按钮权限",
|
||||
hstabs: "标签页操作",
|
||||
hsMenuTree: "菜单树结构",
|
||||
externalLink: "外链"
|
||||
}
|
||||
},
|
||||
@ -80,6 +81,7 @@ export const menusConfig = {
|
||||
permissionPage: "Page Permission",
|
||||
permissionButton: "Button Permission",
|
||||
hstabs: "Tabs Operate",
|
||||
hsMenuTree: "Menu Tree",
|
||||
externalLink: "External Link"
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ const homeRouter = {
|
||||
redirect: "/welcome",
|
||||
meta: {
|
||||
icon: "HomeFilled",
|
||||
title: "message.hshome",
|
||||
showLink: true,
|
||||
i18n: true,
|
||||
rank: 0
|
||||
|
@ -3,6 +3,7 @@ import homeRouter from "./home";
|
||||
import errorRouter from "./error";
|
||||
import editorRouter from "./editor";
|
||||
import nestedRouter from "./nested";
|
||||
import menuTreeRouter from "./menuTree";
|
||||
import externalLink from "./externalLink";
|
||||
import flowChartRouter from "./flowchart";
|
||||
import remainingRouter from "./remaining";
|
||||
@ -22,6 +23,7 @@ const routes = [
|
||||
nestedRouter,
|
||||
externalLink,
|
||||
editorRouter,
|
||||
menuTreeRouter,
|
||||
flowChartRouter,
|
||||
componentsRouter
|
||||
];
|
||||
|
29
src/router/modules/menuTree.ts
Normal file
29
src/router/modules/menuTree.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import Layout from "/@/layout/index.vue";
|
||||
|
||||
const menuTreeRouter = {
|
||||
path: "/menuTree",
|
||||
name: "reMenuTree",
|
||||
component: Layout,
|
||||
redirect: "/menuTree/index",
|
||||
meta: {
|
||||
icon: "RI-node-tree",
|
||||
title: "message.hsMenuTree",
|
||||
i18n: true,
|
||||
showLink: true,
|
||||
rank: 9
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/menuTree/index",
|
||||
name: "reMenuTree",
|
||||
component: () => import("/@/views/menu-tree/index.vue"),
|
||||
meta: {
|
||||
title: "message.hsMenuTree",
|
||||
showLink: true,
|
||||
i18n: true
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default menuTreeRouter;
|
@ -1,6 +1,7 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { store } from "/@/store";
|
||||
import { cacheType } from "./types";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { RouteConfigs } from "/@/layout/types";
|
||||
import { constantMenus } from "/@/router/modules";
|
||||
import { ascending, filterTree } from "/@/router/utils";
|
||||
@ -12,6 +13,8 @@ export const usePermissionStore = defineStore({
|
||||
constantMenus,
|
||||
// 整体路由生成的菜单(静态、动态)
|
||||
wholeMenus: [],
|
||||
// 深拷贝一个菜单树,与导航菜单不突出
|
||||
menusTree: [],
|
||||
buttonAuth: [],
|
||||
// 缓存页面keepAlive
|
||||
cachePageList: []
|
||||
@ -24,6 +27,10 @@ export const usePermissionStore = defineStore({
|
||||
ascending(this.constantMenus.concat(routes))
|
||||
);
|
||||
|
||||
this.menusTree = cloneDeep(
|
||||
filterTree(ascending(this.constantMenus.concat(routes)))
|
||||
);
|
||||
|
||||
const getButtonAuth = (arrRoutes: Array<RouteConfigs>) => {
|
||||
if (!arrRoutes || !arrRoutes.length) return;
|
||||
arrRoutes.forEach((v: RouteConfigs) => {
|
||||
|
42
src/utils/tree.ts
Normal file
42
src/utils/tree.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 提取菜单树中的每一项path
|
||||
* @param {Object} {menuTree 菜单树}
|
||||
* @param {return}} expandedPaths 每一项path组成的数组
|
||||
*/
|
||||
const expandedPaths = [];
|
||||
export function extractPathList(menuTree) {
|
||||
if (!Array.isArray(menuTree)) {
|
||||
console.warn("menuTree must be an array");
|
||||
return;
|
||||
}
|
||||
if (!menuTree || menuTree.length === 0) return;
|
||||
for (const node of menuTree) {
|
||||
const hasChildren = node.children && node.children.length > 0;
|
||||
if (hasChildren) {
|
||||
extractPathList(node.children);
|
||||
}
|
||||
expandedPaths.push(node.path);
|
||||
}
|
||||
return expandedPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果父级下children的length为1,删除children
|
||||
* @param {Object} {menuTree 菜单树}
|
||||
* @param {return}}
|
||||
*/
|
||||
export function deleteChildren(menuTree) {
|
||||
if (!Array.isArray(menuTree)) {
|
||||
console.warn("menuTree must be an array");
|
||||
return;
|
||||
}
|
||||
if (!menuTree || menuTree.length === 0) return;
|
||||
for (const node of menuTree) {
|
||||
if (node.children && node.children.length === 1) delete node.children;
|
||||
const hasChildren = node.children && node.children.length > 0;
|
||||
if (hasChildren) {
|
||||
deleteChildren(node.children);
|
||||
}
|
||||
}
|
||||
return menuTree;
|
||||
}
|
36
src/views/menu-tree/index.vue
Normal file
36
src/views/menu-tree/index.vue
Normal file
@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "reMenuTree"
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from "vue";
|
||||
import { extractPathList, deleteChildren } from "/@/utils/tree";
|
||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
|
||||
|
||||
let dataProps = ref({
|
||||
value: "path",
|
||||
children: "children"
|
||||
});
|
||||
|
||||
let menusData = computed(() => {
|
||||
return deleteChildren(usePermissionStoreHook().menusTree);
|
||||
});
|
||||
|
||||
let expandedKeys = extractPathList(menusData.value);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-tree-v2
|
||||
:data="menusData"
|
||||
:props="dataProps"
|
||||
show-checkbox
|
||||
:height="500"
|
||||
:default-expanded-keys="expandedKeys"
|
||||
>
|
||||
<template #default="{ data }">
|
||||
<span>{{ $t(data.meta.title) }}</span>
|
||||
</template>
|
||||
</el-tree-v2>
|
||||
</template>
|
Loading…
Reference in New Issue
Block a user