feat:新增分栏
This commit is contained in:
parent
6c87ac2508
commit
f5f1d28435
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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: '聊天框',
|
||||||
|
|
|
||||||
|
|
@ -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: '外部链接',
|
||||||
|
|
|
||||||
|
|
@ -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',
|
||||||
|
|
|
||||||
|
|
@ -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: '系统管理',
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
// 页脚
|
// 页脚
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue