7 changed files with 490 additions and 27 deletions
-
2index.html
-
237package-lock.json
-
2package.json
-
32src/App.vue
-
BINsrc/assets/images/deepChart.png
-
229src/layout/Layout.vue
-
15src/main.js
@ -1,30 +1,14 @@ |
|||
<script setup> |
|||
import HelloWorld from './components/HelloWorld.vue' |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<a href="https://vite.dev" target="_blank"> |
|||
<img src="/vite.svg" class="logo" alt="Vite logo" /> |
|||
</a> |
|||
<a href="https://vuejs.org/" target="_blank"> |
|||
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" /> |
|||
</a> |
|||
</div> |
|||
<HelloWorld msg="Vite + Vue" /> |
|||
<router-view /> |
|||
</template> |
|||
|
|||
<script setup> |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.logo { |
|||
height: 6em; |
|||
padding: 1.5em; |
|||
will-change: filter; |
|||
transition: filter 300ms; |
|||
} |
|||
.logo:hover { |
|||
filter: drop-shadow(0 0 2em #646cffaa); |
|||
} |
|||
.logo.vue:hover { |
|||
filter: drop-shadow(0 0 2em #42b883aa); |
|||
* { |
|||
margin: 0; |
|||
padding: 0; |
|||
box-sizing: border-box; |
|||
} |
|||
</style> |
|||
|
After Width: 48 | Height: 48 | Size: 1.9 KiB |
@ -0,0 +1,229 @@ |
|||
<template> |
|||
<el-container style="min-height: 100vh;"> |
|||
<el-aside |
|||
class="sidebar" |
|||
v-if="!$route.meta.hiddenSidebar" |
|||
> |
|||
<!-- 侧边栏头部 --> |
|||
<div class="sidebar-header"> |
|||
<img src="../assets/images/deepChart.png" class="sidebar-logo"> |
|||
<span class="sidebar-title">DeepChart</span> |
|||
</div> |
|||
|
|||
<!-- 侧边栏菜单 --> |
|||
<el-menu |
|||
class="sidebar-menu" |
|||
background-color="transparent" |
|||
router |
|||
:default-active="currentRoutePath" |
|||
:unique-opened="true" |
|||
> |
|||
<el-sub-menu |
|||
v-for="parentRoute in filteredSidebarRoutes" |
|||
:key="parentRoute.name" |
|||
:index="`/${parentRoute.path}`" |
|||
> |
|||
<!-- 父目录 --> |
|||
<template #title> |
|||
<el-icon> |
|||
<component :is="parentRoute.meta.icon" /> |
|||
</el-icon> |
|||
<span class="sidebar-parent-text">{{ parentRoute.meta.title }}</span> |
|||
</template> |
|||
|
|||
<!-- 子目录 --> |
|||
<el-menu-item |
|||
v-for="childRoute in parentRoute.filteredChildren" |
|||
:key="childRoute.name" |
|||
:index="`/${parentRoute.path}/${childRoute.path}`" |
|||
:to="`/${parentRoute.path}/${childRoute.path}`" |
|||
class="sidebar-child-container" |
|||
> |
|||
<el-icon class="sidebar-child-icon" /> |
|||
<span class="sidebar-child-text">{{ childRoute.meta.title }}</span> |
|||
</el-menu-item> |
|||
</el-sub-menu> |
|||
</el-menu> |
|||
</el-aside> |
|||
|
|||
<!-- 主页面 --> |
|||
<el-main class="main-content"> |
|||
<router-view /> |
|||
</el-main> |
|||
</el-container> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed } from 'vue' |
|||
import { useRouter, useRoute } from 'vue-router' |
|||
|
|||
const router = useRouter() |
|||
const route = useRoute() |
|||
|
|||
// 递归收集父路由 |
|||
const collectParentRoutes = (routes) => { |
|||
let parentRoutes = []; |
|||
routes.forEach(route => { |
|||
if (route.meta?.isParentNav === true && route.meta?.showSidebar === true) { |
|||
parentRoutes.push(route); |
|||
} |
|||
if (route.children && route.children.length > 0) { |
|||
parentRoutes = [...parentRoutes, ...collectParentRoutes(route.children)]; |
|||
} |
|||
}); |
|||
return parentRoutes; |
|||
}; |
|||
|
|||
// 过滤侧边栏路由 |
|||
const filteredSidebarRoutes = computed(() => { |
|||
const allParentRoutes = collectParentRoutes(router.options.routes); |
|||
return allParentRoutes.map(parentRoute => { |
|||
const filteredChildren = parentRoute.children?.filter(childRoute => |
|||
childRoute.meta?.showSidebar === true |
|||
) || []; |
|||
return { ...parentRoute, filteredChildren }; |
|||
}).filter(parentRoute => parentRoute.filteredChildren.length > 0); |
|||
}); |
|||
|
|||
// 计算当前路由的绝对路径 |
|||
const currentRoutePath = computed(() => route.path); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* 侧边栏核心样式 */ |
|||
.sidebar { |
|||
position: fixed; |
|||
left: 24px; |
|||
width: 336px; |
|||
height: 100vh; |
|||
flex-shrink: 0; |
|||
border-radius: 8px; |
|||
background: #FEE6E6; |
|||
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.25); |
|||
overflow: hidden; |
|||
position: relative; |
|||
} |
|||
|
|||
/* 侧边栏头部样式 */ |
|||
.sidebar-header { |
|||
position: absolute; |
|||
left: 45px; |
|||
top: 59px; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.sidebar-logo { |
|||
height: 40px; |
|||
width: auto; |
|||
object-fit: contain; |
|||
} |
|||
|
|||
.sidebar-title { |
|||
margin-left: 10px; |
|||
color: #000000; |
|||
font-family: "PingFang SC", sans-serif; |
|||
font-size: 32px; |
|||
font-style: normal; |
|||
font-weight: 700; |
|||
line-height: 33.1px; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
/* 侧边栏菜单容器 */ |
|||
.sidebar-menu { |
|||
margin-left: 20px; |
|||
margin-top: 169px; |
|||
width: calc(100% - 20px); |
|||
border-right: none; |
|||
} |
|||
|
|||
/* 主内容区样式 */ |
|||
.main-content { |
|||
padding: 20px; |
|||
background-color: #FEE6E6; |
|||
height: 100vh; |
|||
margin-left: 50px; |
|||
box-shadow: 0 0 4px 0 #00000040; |
|||
} |
|||
|
|||
/* 父目录文字样式 */ |
|||
.sidebar-parent-text { |
|||
height: 33.1px; |
|||
flex: 1 0 0; |
|||
overflow: hidden; |
|||
color: #1f0303; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
font-family: "PingFang SC", sans-serif; |
|||
font-size: 21.06px; |
|||
font-style: normal; |
|||
font-weight: 700; |
|||
line-height: 33.1px; |
|||
display: inline-flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
/* 子目录核心样式 */ |
|||
.sidebar-child-container { |
|||
width: 300px !important; |
|||
height: 60px !important; |
|||
margin-left: 2px !important; |
|||
background: #FEE6E6 !important; |
|||
position: relative; |
|||
padding: 0 !important; |
|||
border-radius: 6.02px !important; |
|||
box-sizing: border-box !important; |
|||
} |
|||
|
|||
/* 子目录图标样式 */ |
|||
.sidebar-child-icon { |
|||
position: absolute; |
|||
left: 48px; |
|||
top: 50%; |
|||
transform: translateY(-50%); |
|||
font-size: 18px !important; |
|||
color: inherit; |
|||
} |
|||
|
|||
/* 子目录文字样式(未选中) */ |
|||
.sidebar-child-text { |
|||
position: absolute; |
|||
left: 58px; |
|||
top: 20px; |
|||
height: 33.1px; |
|||
overflow: hidden; |
|||
color: #03071f; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
font-family: "PingFang SC", sans-serif; |
|||
font-size: 18px; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
line-height: 22px; |
|||
} |
|||
|
|||
/* 子目录选中态样式 */ |
|||
.sidebar-child-container.is-active { |
|||
background: #FFFFFF !important; /* 选中后容器变为白色 */ |
|||
} |
|||
|
|||
/* 选中态文字样式 */ |
|||
.sidebar-child-container.is-active .sidebar-child-text { |
|||
color: #FF0000 !important; /* 选中后文字红色 */ |
|||
font-weight: 500; |
|||
} |
|||
|
|||
/* 覆盖Element Plus默认样式 */ |
|||
.el-sub-menu__title { |
|||
height: 33.1px !important; |
|||
line-height: 33.1px !important; |
|||
padding: 0 !important; |
|||
} |
|||
.el-menu-item { |
|||
border: none !important; |
|||
} |
|||
.el-menu--vertical .el-menu-item { |
|||
width: 300px !important; |
|||
} |
|||
</style> |
|||
@ -1,8 +1,19 @@ |
|||
import {createApp} from 'vue' |
|||
import './style.css' |
|||
import { createApp } from 'vue' |
|||
import App from './App.vue' |
|||
import router from './router' |
|||
// 导入 Element Plus 样式和组件
|
|||
import ElementPlus from 'element-plus' |
|||
import 'element-plus/dist/index.css' |
|||
// 导入 Element Plus 图标
|
|||
import * as ElementPlusIconsVue from '@element-plus/icons-vue' |
|||
|
|||
const app = createApp(App) |
|||
|
|||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { |
|||
app.component(key, component) |
|||
} |
|||
|
|||
app.use(ElementPlus) |
|||
app.use(router) |
|||
|
|||
app.mount('#app') |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue