feat: 新增顶部菜单切换、菜单复制新增功能并优化侧边栏渲染
1. 新增顶部菜单选择器,支持切换顶级菜单并动态渲染对应侧边栏 2. 菜单管理页面添加复制新增按钮,可基于现有菜单快速创建新菜单 3. 重构侧边栏路由逻辑,支持自动匹配当前页面所属顶级菜单 4. 在vuex中新增顶部菜单状态管理,持久化激活的顶级菜单
This commit is contained in:
@@ -88,17 +88,19 @@ export default {
|
|||||||
return this.basePath
|
return this.basePath
|
||||||
},
|
},
|
||||||
subMenuRoute() {
|
subMenuRoute() {
|
||||||
const title = (this.item.meta && this.item.meta.title) || this.item.name || ''
|
return this.findFirstLeaf(this.item, this.basePath)
|
||||||
return {
|
|
||||||
path: '/redirect/subMenu',
|
|
||||||
query: {
|
|
||||||
parent: this.basePath,
|
|
||||||
title: title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
findFirstLeaf(item, basePath) {
|
||||||
|
const visibleChildren = (item.children || []).filter(c => !c.hidden)
|
||||||
|
if (visibleChildren.length === 0) {
|
||||||
|
return basePath
|
||||||
|
}
|
||||||
|
const firstChild = visibleChildren[0]
|
||||||
|
const childPath = path.resolve(basePath, firstChild.path)
|
||||||
|
return this.findFirstLeaf(firstChild, childPath)
|
||||||
|
},
|
||||||
hasOneShowingChild(children = [], parent) {
|
hasOneShowingChild(children = [], parent) {
|
||||||
if (!children) {
|
if (!children) {
|
||||||
children = [];
|
children = [];
|
||||||
|
|||||||
@@ -1,40 +1,123 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="{'has-logo':showLogo}" :style="{ backgroundColor: '#fff' }">
|
<div :class="{'has-logo':showLogo}" :style="{ backgroundColor: '#fff' }">
|
||||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||||
|
<el-popover
|
||||||
|
v-model="sectionPopoverVisible"
|
||||||
|
placement="bottom-start"
|
||||||
|
width="320"
|
||||||
|
trigger="click"
|
||||||
|
popper-class="top-menu-popper"
|
||||||
|
:disabled="topMenuList.length === 0"
|
||||||
|
>
|
||||||
|
<div class="top-menu-grid">
|
||||||
|
<div
|
||||||
|
v-for="menu in topMenuList"
|
||||||
|
:key="menu.path"
|
||||||
|
class="top-menu-card"
|
||||||
|
:class="{ 'is-active': menu.path === activeTopMenu }"
|
||||||
|
@click="selectTopMenu(menu)"
|
||||||
|
>
|
||||||
|
<div class="top-menu-card-icon">
|
||||||
|
<svg-icon v-if="menu.meta && menu.meta.icon" :icon-class="menu.meta.icon" class="top-menu-icon" />
|
||||||
|
</div>
|
||||||
|
<span class="top-menu-title">{{ (menu.meta && menu.meta.title) || menu.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div slot="reference" class="sidebar-section-title" :class="{ 'is-collapse': isCollapse }">
|
||||||
|
<div class="section-title-inner">
|
||||||
|
<div class="section-icon">
|
||||||
|
<svg-icon v-if="activeTopMenuIcon" :icon-class="activeTopMenuIcon" />
|
||||||
|
<img v-else :src="logoImg" class="section-logo" />
|
||||||
|
</div>
|
||||||
|
<span v-if="activeTopMenuTitle" class="section-module">{{ activeTopMenuTitle }}</span>
|
||||||
|
<i class="el-icon-arrow-down section-arrow" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
<el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
|
<el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
|
||||||
<el-menu
|
<transition name="sidebar-menu-fade" mode="out-in">
|
||||||
:default-active="activeMenu"
|
<el-menu
|
||||||
:collapse="isCollapse"
|
:key="activeTopMenuPath"
|
||||||
background-color="#fff"
|
:default-active="activeMenu"
|
||||||
text-color="#111"
|
:collapse="isCollapse"
|
||||||
:unique-opened="true"
|
background-color="#fff"
|
||||||
active-text-color="#111"
|
text-color="#111"
|
||||||
:collapse-transition="false"
|
:unique-opened="true"
|
||||||
mode="vertical"
|
active-text-color="#111"
|
||||||
>
|
:collapse-transition="false"
|
||||||
<sidebar-item
|
mode="vertical"
|
||||||
v-for="(route, index) in sidebarRouters"
|
>
|
||||||
:key="route.path + index"
|
<sidebar-item
|
||||||
:item="route"
|
v-for="(route, index) in currentSidebarRouters"
|
||||||
:base-path="route.path"
|
:key="route.path + index"
|
||||||
/>
|
:item="route"
|
||||||
</el-menu>
|
:base-path="resolveRootBasePath(route.path)"
|
||||||
|
/>
|
||||||
|
</el-menu>
|
||||||
|
</transition>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { mapGetters, mapState } from "vuex";
|
import { mapState } from "vuex";
|
||||||
import Logo from "./Logo";
|
import Logo from "./Logo";
|
||||||
import SidebarItem from "./SidebarItem";
|
import SidebarItem from "./SidebarItem";
|
||||||
import variables from "@/assets/styles/variables.scss";
|
import variables from "@/assets/styles/variables.scss";
|
||||||
|
import logoImg from '@/assets/logo/logo.png'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { SidebarItem, Logo },
|
components: { SidebarItem, Logo },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
logoImg,
|
||||||
|
sectionPopoverVisible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["settings"]),
|
...mapState(["settings"]),
|
||||||
...mapGetters(["sidebarRouters", "sidebar"]),
|
topMenuList() {
|
||||||
|
return this.$store.state.permission.topMenuList.filter(m => !m.hidden)
|
||||||
|
},
|
||||||
|
activeTopMenu() {
|
||||||
|
return this.$store.state.permission.activeTopMenu
|
||||||
|
},
|
||||||
|
storeTopMenuList() {
|
||||||
|
return this.$store.state.permission.topMenuList
|
||||||
|
},
|
||||||
|
activeTopMenuPath() {
|
||||||
|
const topMenus = this.$store.state.permission.topMenuList
|
||||||
|
const activeTop = this.$store.state.permission.activeTopMenu
|
||||||
|
const menu = topMenus.find(m => m.path === activeTop)
|
||||||
|
return menu ? menu.path : ''
|
||||||
|
},
|
||||||
|
activeTopMenuTitle() {
|
||||||
|
const topMenus = this.$store.state.permission.topMenuList
|
||||||
|
const activeTop = this.$store.state.permission.activeTopMenu
|
||||||
|
const menu = topMenus.find(m => m.path === activeTop)
|
||||||
|
return menu ? ((menu.meta && menu.meta.title) || menu.name) : ''
|
||||||
|
},
|
||||||
|
activeTopMenuIcon() {
|
||||||
|
const topMenus = this.$store.state.permission.topMenuList
|
||||||
|
const activeTop = this.$store.state.permission.activeTopMenu
|
||||||
|
const menu = topMenus.find(m => m.path === activeTop)
|
||||||
|
return (menu && menu.meta && menu.meta.icon) || ''
|
||||||
|
},
|
||||||
|
currentSidebarRouters() {
|
||||||
|
const topMenus = this.$store.state.permission.topMenuList
|
||||||
|
const activeTop = this.$store.state.permission.activeTopMenu
|
||||||
|
if (!activeTop) {
|
||||||
|
const firstMenu = topMenus.find(m => !m.hidden)
|
||||||
|
if (firstMenu) {
|
||||||
|
return firstMenu.children ? firstMenu.children.filter(c => !c.hidden) : []
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const menu = topMenus.find(m => m.path === activeTop)
|
||||||
|
if (!menu || !menu.children) return []
|
||||||
|
return menu.children.filter(c => !c.hidden)
|
||||||
|
},
|
||||||
activeMenu() {
|
activeMenu() {
|
||||||
const route = this.$route;
|
const route = this.$route;
|
||||||
const { meta, path: routePath } = route;
|
const { meta, path: routePath } = route;
|
||||||
@@ -54,12 +137,73 @@ export default {
|
|||||||
return variables;
|
return variables;
|
||||||
},
|
},
|
||||||
isCollapse() {
|
isCollapse() {
|
||||||
return !this.sidebar.opened;
|
return !this.$store.state.app.sidebar.opened;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newRoute) {
|
||||||
|
this.autoSelectTopMenu(newRoute.path)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
storeTopMenuList: {
|
||||||
|
handler() {
|
||||||
|
if (this.$route) {
|
||||||
|
this.autoSelectTopMenu(this.$route.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
selectTopMenu(menu) {
|
||||||
|
if (this.activeTopMenu === menu.path) {
|
||||||
|
this.sectionPopoverVisible = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$store.dispatch('selectTopMenu', menu.path)
|
||||||
|
this.$router.push('/')
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.sectionPopoverVisible = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
autoSelectTopMenu(currentPath) {
|
||||||
|
const topMenus = this.$store.state.permission.topMenuList
|
||||||
|
if (topMenus.length === 0) return
|
||||||
|
const activeTop = this.$store.state.permission.activeTopMenu
|
||||||
|
|
||||||
|
if (activeTop) {
|
||||||
|
const currentMenu = topMenus.find(m => m.path === activeTop)
|
||||||
|
if (currentMenu) {
|
||||||
|
this.$store.dispatch('selectTopMenu', activeTop)
|
||||||
|
if (currentPath === currentMenu.path || currentPath.startsWith(currentMenu.path + '/')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const menu of topMenus) {
|
||||||
|
if (menu.hidden) continue
|
||||||
|
if (currentPath === menu.path || currentPath.startsWith(menu.path + '/')) {
|
||||||
|
this.$store.dispatch('selectTopMenu', menu.path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!activeTop) {
|
||||||
|
const firstMenu = topMenus.find(m => !m.hidden)
|
||||||
|
if (firstMenu) {
|
||||||
|
this.$store.dispatch('selectTopMenu', firstMenu.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resolveRootBasePath(routePath) {
|
||||||
|
if (routePath && routePath.startsWith('/')) return routePath
|
||||||
|
const parentPath = this.activeTopMenuPath
|
||||||
|
if (!parentPath) return routePath
|
||||||
|
return path.resolve(parentPath, routePath)
|
||||||
|
},
|
||||||
findLevel2Parent(currentPath) {
|
findLevel2Parent(currentPath) {
|
||||||
return this.walkTree(this.sidebarRouters, currentPath, 0, '');
|
return this.walkTree(this.currentSidebarRouters, currentPath, 0, this.activeTopMenuPath);
|
||||||
},
|
},
|
||||||
walkTree(routes, currentPath, depth, basePath) {
|
walkTree(routes, currentPath, depth, basePath) {
|
||||||
for (const route of routes) {
|
for (const route of routes) {
|
||||||
@@ -82,3 +226,161 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.sidebar-section-title {
|
||||||
|
height: 50px;
|
||||||
|
padding: 0 12px;
|
||||||
|
background: #fafafa;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
transition: background 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title-inner {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-logo {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-icon {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 26px;
|
||||||
|
color: #555;
|
||||||
|
|
||||||
|
.section-logo {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-module {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-arrow {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
margin-left: 4px;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-collapse {
|
||||||
|
padding: 0 6px;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.section-icon {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title-right,
|
||||||
|
.section-arrow {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-menu-fade-enter-active,
|
||||||
|
.sidebar-menu-fade-leave-active {
|
||||||
|
transition: opacity 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-menu-fade-enter,
|
||||||
|
.sidebar-menu-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.top-menu-popper {
|
||||||
|
padding: 16px 12px;
|
||||||
|
|
||||||
|
.top-menu-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.top-menu-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 14px 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
color: #555;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.04);
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
color: var(--current-color, #409EFF);
|
||||||
|
background: rgba(64, 158, 255, 0.06);
|
||||||
|
|
||||||
|
.top-menu-card-icon {
|
||||||
|
background: var(--current-color, #409EFF);
|
||||||
|
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-menu-icon {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-menu-card-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
.top-menu-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #666;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-menu-title {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.4;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -61,8 +61,16 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
subNavItems() {
|
subNavItems() {
|
||||||
const sidebarRouters = this.$store.state.permission.sidebarRouters
|
const sidebarRouters = this.$store.state.permission.sidebarRouters
|
||||||
const items = this.getThirdLevelMenus(sidebarRouters)
|
const activeTop = this.$store.state.permission.activeTopMenu
|
||||||
return items
|
const topMenus = this.$store.state.permission.topMenuList
|
||||||
|
const menu = topMenus.find(m => m.path === activeTop)
|
||||||
|
const basePath = menu ? menu.path : ''
|
||||||
|
|
||||||
|
let currentPath = this.$route.path
|
||||||
|
if (currentPath === '/redirect/subMenu' && this.$route.query.parent) {
|
||||||
|
currentPath = this.$route.query.parent
|
||||||
|
}
|
||||||
|
return this.findActiveLevel2(sidebarRouters, currentPath, 0, basePath) || []
|
||||||
},
|
},
|
||||||
hasItems() {
|
hasItems() {
|
||||||
return this.subNavItems.length > 0
|
return this.subNavItems.length > 0
|
||||||
@@ -108,13 +116,6 @@ export default {
|
|||||||
isChildActive(child) {
|
isChildActive(child) {
|
||||||
return this.$route.path === child._ownPath || this.$route.path.startsWith(child._ownPath + '/')
|
return this.$route.path === child._ownPath || this.$route.path.startsWith(child._ownPath + '/')
|
||||||
},
|
},
|
||||||
getThirdLevelMenus(routes) {
|
|
||||||
let currentPath = this.$route.path
|
|
||||||
if (currentPath === '/redirect/subMenu' && this.$route.query.parent) {
|
|
||||||
currentPath = this.$route.query.parent
|
|
||||||
}
|
|
||||||
return this.findActiveLevel2(routes, currentPath, 0, '') || []
|
|
||||||
},
|
|
||||||
findActiveLevel2(routes, currentPath, depth, basePath) {
|
findActiveLevel2(routes, currentPath, depth, basePath) {
|
||||||
for (const route of routes) {
|
for (const route of routes) {
|
||||||
if (route.hidden) continue
|
if (route.hidden) continue
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ const getters = {
|
|||||||
topbarRouters:state => state.permission.topbarRouters,
|
topbarRouters:state => state.permission.topbarRouters,
|
||||||
defaultRoutes:state => state.permission.defaultRoutes,
|
defaultRoutes:state => state.permission.defaultRoutes,
|
||||||
sidebarRouters:state => state.permission.sidebarRouters,
|
sidebarRouters:state => state.permission.sidebarRouters,
|
||||||
|
topMenuList: state => state.permission.topMenuList,
|
||||||
|
activeTopMenu: state => state.permission.activeTopMenu,
|
||||||
productList: state => state.category.productList,
|
productList: state => state.category.productList,
|
||||||
rawMaterialList: state => state.category.rawMaterialList,
|
rawMaterialList: state => state.category.rawMaterialList,
|
||||||
bomMap: state => state.category.bomMap,
|
bomMap: state => state.category.bomMap,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { getRouters } from '@/api/menu'
|
|||||||
import Layout from '@/layout/index'
|
import Layout from '@/layout/index'
|
||||||
import ParentView from '@/components/ParentView'
|
import ParentView from '@/components/ParentView'
|
||||||
import InnerLink from '@/layout/components/InnerLink'
|
import InnerLink from '@/layout/components/InnerLink'
|
||||||
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
const permission = {
|
const permission = {
|
||||||
state: {
|
state: {
|
||||||
@@ -11,7 +12,9 @@ const permission = {
|
|||||||
addRoutes: [],
|
addRoutes: [],
|
||||||
defaultRoutes: [],
|
defaultRoutes: [],
|
||||||
topbarRouters: [],
|
topbarRouters: [],
|
||||||
sidebarRouters: []
|
sidebarRouters: [],
|
||||||
|
topMenuList: [],
|
||||||
|
activeTopMenu: Cookies.get('activeTopMenu') || ''
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
SET_ROUTES: (state, routes) => {
|
SET_ROUTES: (state, routes) => {
|
||||||
@@ -27,6 +30,13 @@ const permission = {
|
|||||||
SET_SIDEBAR_ROUTERS: (state, routes) => {
|
SET_SIDEBAR_ROUTERS: (state, routes) => {
|
||||||
state.sidebarRouters = routes
|
state.sidebarRouters = routes
|
||||||
},
|
},
|
||||||
|
SET_TOP_MENU_LIST: (state, menus) => {
|
||||||
|
state.topMenuList = menus
|
||||||
|
},
|
||||||
|
SET_ACTIVE_TOP_MENU: (state, path) => {
|
||||||
|
state.activeTopMenu = path
|
||||||
|
Cookies.set('activeTopMenu', path)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
// 生成路由
|
// 生成路由
|
||||||
@@ -45,9 +55,19 @@ const permission = {
|
|||||||
commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
|
commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
|
||||||
commit('SET_DEFAULT_ROUTES', sidebarRoutes)
|
commit('SET_DEFAULT_ROUTES', sidebarRoutes)
|
||||||
commit('SET_TOPBAR_ROUTES', sidebarRoutes)
|
commit('SET_TOPBAR_ROUTES', sidebarRoutes)
|
||||||
|
commit('SET_TOP_MENU_LIST', sidebarRoutes)
|
||||||
resolve(rewriteRoutes)
|
resolve(rewriteRoutes)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
selectTopMenu({ commit, state }, menuPath) {
|
||||||
|
const menu = state.topMenuList.find(m => m.path === menuPath)
|
||||||
|
if (menu) {
|
||||||
|
commit('SET_ACTIVE_TOP_MENU', menuPath)
|
||||||
|
const children = menu.children ? menu.children.filter(c => !c.hidden) : []
|
||||||
|
commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(children))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,13 @@
|
|||||||
@click="handleAdd(scope.row)"
|
@click="handleAdd(scope.row)"
|
||||||
v-hasPermi="['system:menu:add']"
|
v-hasPermi="['system:menu:add']"
|
||||||
>新增</el-button>
|
>新增</el-button>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="text"
|
||||||
|
icon="el-icon-document-copy"
|
||||||
|
@click="handleCopyAdd(scope.row)"
|
||||||
|
v-hasPermi="['system:menu:add']"
|
||||||
|
>复制新增</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
size="mini"
|
size="mini"
|
||||||
type="text"
|
type="text"
|
||||||
@@ -410,6 +417,17 @@ export default {
|
|||||||
this.open = true;
|
this.open = true;
|
||||||
this.title = "添加菜单";
|
this.title = "添加菜单";
|
||||||
},
|
},
|
||||||
|
/** 复制新增按钮操作:将当前菜单信息填入新增弹窗 */
|
||||||
|
handleCopyAdd(row) {
|
||||||
|
this.reset();
|
||||||
|
this.getTreeselect();
|
||||||
|
// 直接使用当前行数据拷贝给表单,不拷贝 menuId 确保提交走新增
|
||||||
|
const data = { ...row };
|
||||||
|
data.menuId = undefined;
|
||||||
|
this.form = data;
|
||||||
|
this.open = true;
|
||||||
|
this.title = "复制新增菜单";
|
||||||
|
},
|
||||||
/** 展开/折叠操作 */
|
/** 展开/折叠操作 */
|
||||||
toggleExpandAll() {
|
toggleExpandAll() {
|
||||||
this.refreshTable = false;
|
this.refreshTable = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user