feat:新增分栏

This commit is contained in:
zouzhibing 2023-02-27 17:44:14 +08:00
parent 6c87ac2508
commit f5f1d28435
11 changed files with 98 additions and 71 deletions

View File

@ -1,6 +1,6 @@
## 简介 ## 简介
vue-element-perfect 是一个后台前端解决方案,它使用了最新的前端技术栈、动态路由,权限验证,并且有着丰富的组件,企业级中后台解决方案可免费商用同时支持PC、平板、手机 vue-element-perfect 是一个后台前端解决方案,它使用了最新的前端技术栈、动态路由,权限验证,并且有着丰富的组件,企业级中后台解决方案可免费商用同时支持PC、平板、手机
本项目也参考了很多开源的项目、
### 在线预览 ### 在线预览
- link —— [http://182.61.5.190:8889/ ](http://182.61.5.190:8889/) - link —— [http://182.61.5.190:8889/ ](http://182.61.5.190:8889/)
- gitee国内访问地址https://yuanzbz.gitee.io/vue-admin-perfect/#/home - gitee国内访问地址https://yuanzbz.gitee.io/vue-admin-perfect/#/home

View File

@ -24,6 +24,7 @@
> >
<el-option label="纵向" value="vertical"></el-option> <el-option label="纵向" value="vertical"></el-option>
<el-option label="横向" value="horizontal"></el-option> <el-option label="横向" value="horizontal"></el-option>
<el-option label="分栏" value="columns"></el-option>
</el-select> </el-select>
</div> </div>
<div class="theme-item"> <div class="theme-item">

View File

@ -1,6 +1,9 @@
<template> <template>
<div class="main-columns"> <div class="main-columns">
<div class="layout-columns-aside"> <div class="layout-columns-aside">
<div class="logo flex-center">
<img src="@/assets/image/logo.png" alt="logo" />
</div>
<el-scrollbar> <el-scrollbar>
<div class="menu-wrap"> <div class="menu-wrap">
<div <div
@ -22,19 +25,21 @@
</div> </div>
<div class="layout-columns-sub" :style="{ width: isCollapse ? '60px' : '210px' }"> <div class="layout-columns-sub" :style="{ width: isCollapse ? '60px' : '210px' }">
<el-scrollbar style="height: 100%"> <div class="logo flex-center">
<span v-show="subMenus.length">{{ isCollapse ? "Vue" : "Vue Admin Perfect" }}</span>
</div>
<el-scrollbar >
<el-menu <el-menu
:collapse="isCollapse" :collapse="isCollapse"
:router="false"
:default-active="activeMenu" :default-active="activeMenu"
:unique-opened="SettingStore.themeConfig.uniqueOpened" :unique-opened="SettingStore.themeConfig.uniqueOpened"
:collapse-transition="false" :collapse-transition="false"
class="menu-columns" class="menu-columns"
> >
<SubItem <SubMenu
v-for="route in subMenus" :basePath="basePath"
:key="route.path" :menuList="subMenus"
:item="route"
:base-path="basePath"
/> />
</el-menu> </el-menu>
</el-scrollbar> </el-scrollbar>
@ -49,9 +54,8 @@
<TagsView v-if="themeConfig.showTag"/> <TagsView v-if="themeConfig.showTag"/>
</div> </div>
<Main/> <Main/>
<Footer/>
</div> </div>
</div> </div>
</template> </template>
@ -61,6 +65,8 @@ import { useRoute, useRouter } from "vue-router";
import {usePermissionStore} from "@/store/modules/permission" import {usePermissionStore} from "@/store/modules/permission"
import { useSettingStore } from "@/store/modules/setting"; import { useSettingStore } from "@/store/modules/setting";
import SubItem from '../components/SubMenu/SubItem.vue' import SubItem from '../components/SubMenu/SubItem.vue'
import Footer from '../components/Footer/index.vue'
import SubMenu from '../components/SubMenu/SubMenu.vue'
import TagsView from '../components/TagsView/index.vue' import TagsView from '../components/TagsView/index.vue'
const PermissionStore = usePermissionStore() const PermissionStore = usePermissionStore()
const SettingStore = useSettingStore() const SettingStore = useSettingStore()
@ -102,34 +108,40 @@ watch(()=>[route],()=>{
subMenus.value = [] subMenus.value = []
} }
basePath.value = firstMenu.path basePath.value = firstMenu.path
console.log('======触发========触发======',subMenus.value)
},{ },{
deep: true, deep: true,
immediate:true immediate:true
}) })
const handleChangeMenu = (item)=>{ const handleChangeMenu = (item)=>{
if (item.children?.length) {
subMenus.value = item.children
}else {
subMenus.value = [];
}
router.push(item.path); router.push(item.path);
} }
console.log('permission_routes',menusRoutes.value,)
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.main-columns{
display: flex;
flex-direction: row!important;
height: 100%;
width: 100%;
}
.layout-columns-aside{ .layout-columns-aside{
flex-shrink: 0; flex-shrink: 0;
width: 80px; width: 80px;
min-height: 100vh; height: 100%;
background-color: #304156; background-color: #304156;
.el-scrollbar{
height: calc(100% - 55px);
}
.logo {
box-sizing: border-box;
height: 50px;
img {
width: 32px;
object-fit: contain;
}
}
.menu-wrap{ .menu-wrap{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -157,24 +169,31 @@ console.log('permission_routes',menusRoutes.value,)
} }
} }
} }
.main-columns{
display: flex;
flex-direction: row!important;
}
.layout-columns-sub{ .layout-columns-sub{
flex-shrink: 0; flex-shrink: 0;
width: 200px; width:200px;
min-height: 100vh;
box-sizing: border-box; box-sizing: border-box;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
transition: all 0.3s ease; transition: all 0.3s ease;
background: white;
border-right: 1px solid #eee; border-right: 1px solid #eee;
::v-deep(.el-menu){ .el-scrollbar{
height: calc(100vh - 50px);
}
.logo {
width: 100%;
box-sizing: border-box;
height: 50px;
border-bottom: 1px solid #eee;
span{
font-weight: bold;
white-space: nowrap;
}
}
::v-deep(.menu-columns){
border-right: none; border-right: none;
min-height: 100vh;
} }
} }
.container{ .container{
@ -200,5 +219,4 @@ console.log('permission_routes',menusRoutes.value,)
justify-content: space-between; justify-content: space-between;
} }
} }
</style> </style>

View File

@ -2,26 +2,26 @@
<template v-if="!item.hidden"> <template v-if="!item.hidden">
<template v-if="!item.alwaysShow && hasOneShowingChild(item.children, item)"> <template v-if="!item.alwaysShow && hasOneShowingChild(item.children, item)">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<!-- <el-menu-item :index="resolvePath(onlyOneChild.path)">--> <el-menu-item :index="resolvePath(onlyOneChild.path)">
<!-- <el-icon :size="20">--> <el-icon :size="20">
<!-- <component :is="onlyOneChild?.meta.icon"></component>--> <component :is="onlyOneChild?.meta.icon"></component>
<!-- </el-icon>--> </el-icon>
<!-- <template #title>{{ onlyOneChild.meta && onlyOneChild.meta.title }}</template>--> <template #title>{{ onlyOneChild.meta && onlyOneChild.meta.title }}</template>
<!-- </el-menu-item>--> </el-menu-item>
</app-link> </app-link>
</template> </template>
<!-- <el-sub-menu :index="resolvePath(item.path)" v-else popper-append-to-body>--> <el-sub-menu :index="resolvePath(item.path)" v-else >
<!-- <template #title>--> <template #title>
<!-- <el-icon :size="20"> <component :is="item.meta?.icon"></component></el-icon>--> <el-icon :size="20"> <component :is="item.meta?.icon"></component></el-icon>
<!-- <span>{{ item.meta && item.meta.title }}</span>--> <span>{{ item.meta && item.meta.title }}</span>
<!-- </template>--> </template>
<!-- <sub-item--> <sub-item
<!-- v-for="child in item.children"--> v-for="child in item.children"
<!-- :key="child.path"--> :key="child.path"
<!-- :item="child"--> :item="child"
<!-- :base-path="resolvePath(child.path)"--> :base-path="resolvePath(child.path)"
<!-- />--> />
<!-- </el-sub-menu>--> </el-sub-menu>
</template> </template>
</template> </template>
@ -61,7 +61,6 @@ const hasOneShowingChild = (children = [], parent) => {
// //
if (showingChildren.length === 0) { if (showingChildren.length === 0) {
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true } onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
// onlyOneChild.value = { ...parent, noShowingChildren: true }
return true return true
} }
@ -75,8 +74,6 @@ const resolvePath = (routePath) => {
if (isExternal(props.basePath)) { if (isExternal(props.basePath)) {
return props.basePath return props.basePath
} }
let path2 = path.resolve(props.basePath, routePath) return path.resolve(props.basePath, routePath)
console.log('======path======',props.basePath)
return path2
} }
</script> </script>

View File

@ -7,9 +7,9 @@
</el-icon> </el-icon>
<span>{{ subItem.meta.title }}</span> <span>{{ subItem.meta.title }}</span>
</template> </template>
<SubMenu :menuList="subItem.children" /> <SubMenu :menuList="subItem.children" :basePath="`${basePath}/${subItem.path}`"/>
</el-sub-menu> </el-sub-menu>
<el-menu-item v-else :index="subItem.path" @click="handleClickMenu(subItem)"> <el-menu-item v-else-if="!subItem.hidden" :index="subItem.path" @click="handleClickMenu(subItem)">
<el-icon> <el-icon>
<component :is="subItem.meta.icon"></component> <component :is="subItem.meta.icon"></component>
</el-icon> </el-icon>
@ -22,12 +22,23 @@
<script setup lang="ts"> <script setup lang="ts">
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { isExternal } from '@/utils/validate.js'
defineProps<{ menuList: Menu.MenuOptions[] }>(); let props = defineProps({
menuList:{
type:Array,
default:()=>[]
},
basePath: {
type: String,
default: '',
},
})
const router = useRouter(); const router = useRouter();
const handleClickMenu = (subItem: Menu.MenuOptions) => { const handleClickMenu = (subItem) => {
if (subItem.meta.isLink) return window.open(subItem.meta.isLink, "_blank"); console.log('isExternal(subItem.path)',subItem.path,isExternal(subItem.path))
router.push(subItem.path); if (isExternal(subItem.path)) return window.open(subItem.path, "_blank");
let path = props.basePath+'/'+subItem.path
router.push(path);
}; };
</script> </script>

View File

@ -1,10 +1,9 @@
<template> <template>
<div class="g-container-layout" :class="classObj"> <div class="g-container-layout" :class="classObj">
<!-- <Mobile/>--> <Mobile/>
<!-- <LayoutVertical v-if="device === 'mobile'"/>--> <LayoutVertical v-if="device === 'mobile'"/>
<!-- <component :is="LayoutComponents[themeConfig.mode]" v-else/>--> <component :is="LayoutComponents[themeConfig.mode]" v-else/>
<!-- <Theme />--> <Theme />
<LayoutColumns/>
</div> </div>
</template> </template>

View File

@ -5,7 +5,7 @@ import Layout from "@/layout/index.vue";
const chartsRouter = [{ const chartsRouter = [{
path: '/chat', path: '/chat',
component: Layout, component: Layout,
redirect: '/charts/index', redirect: '/chat/index',
name: 'chat', name: 'chat',
meta: { meta: {
title: '聊天框', title: '聊天框',

View File

@ -5,7 +5,7 @@ import Layout from "@/layout/index.vue";
const externalLink = [{ const externalLink = [{
path: '/external-link', path: '/external-link',
component: Layout, component: Layout,
redirect: 'noRedirect', redirect: '/external-link/wechat',
name: 'external-link', name: 'external-link',
meta: { meta: {
title: '外部链接', title: '外部链接',

View File

@ -7,7 +7,7 @@ import Layout from "@/layout/index.vue";
const nestedRouter = [{ const nestedRouter = [{
path: '/nested', path: '/nested',
component: Layout, component: Layout,
redirect: '/form/menu1', redirect: '/nested/menu1',
name: 'nested', name: 'nested',
meta: { meta: {
title: '路由嵌套', title: '路由嵌套',
@ -20,6 +20,7 @@ const nestedRouter = [{
name: 'menu1', name: 'menu1',
meta: { title: '菜单1', icon: 'MenuIcon' }, meta: { title: '菜单1', icon: 'MenuIcon' },
alwaysShow:true, alwaysShow:true,
redirect: '/nested/menu1/menu1-1',
children: [ children: [
{ {
path: 'menu1-1', path: 'menu1-1',

View File

@ -5,7 +5,7 @@ import Layout from '@/layout/index.vue'
const systemRouter = [{ const systemRouter = [{
path: '/system', path: '/system',
component: Layout, component: Layout,
redirect: '/system/page', redirect: '/system/user',
name: 'system', name: 'system',
meta: { meta: {
title: '系统管理', title: '系统管理',

View File

@ -19,7 +19,7 @@ export const useSettingStore = defineStore({
// 显示设置 // 显示设置
showSetting:false, showSetting:false,
// 菜单展示模式 默认 vertical horizontal / vertical /columns // 菜单展示模式 默认 vertical horizontal / vertical /columns
mode: 'columns', mode: 'vertical',
// tagsView 是否展示 默认展示 // tagsView 是否展示 默认展示
showTag:true, showTag:true,
// 页脚 // 页脚