实现工作台布局

This commit is contained in:
wangchengming 2025-07-25 21:14:24 +08:00
parent d85788e461
commit 30e176fbda
21 changed files with 660 additions and 1294 deletions

View File

@ -1,8 +1,8 @@
{
"name": "ruoyi",
"name": "youkechuanmei_vue",
"version": "3.9.0",
"description": "媒介管理系统",
"author": "若依",
"author": "hivekion",
"license": "MIT",
"type": "module",
"scripts": {

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -1,31 +1,19 @@
<template>
<el-menu
:default-active="activeMenu"
mode="horizontal"
@select="handleSelect"
:ellipsis="false"
>
<el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
<template v-for="(item, index) in topMenus">
<el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber">
<svg-icon
v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
:icon-class="item.meta.icon"/>
<el-menu-item :style="{ '--theme': theme }" :index="item.path" :key="index" v-if="index < visibleNumber">
<svg-icon v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" :icon-class="item.meta.icon" />
{{ item.meta.title }}
</el-menu-item>
</template>
<!-- 顶部菜单超出数量折叠 -->
<el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
<el-sub-menu :style="{ '--theme': theme }" index="more" v-if="topMenus.length > visibleNumber">
<template #title>更多菜单</template>
<template v-for="(item, index) in topMenus">
<el-menu-item
:index="item.path"
:key="index"
v-if="index >= visibleNumber">
<svg-icon
v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
:icon-class="item.meta.icon"/>
{{ item.meta.title }}
<el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber">
<svg-icon v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" :icon-class="item.meta.icon" />
{{ item.meta.title }}
</el-menu-item>
</template>
</el-sub-menu>
@ -55,7 +43,212 @@ const router = useRouter()
//
const theme = computed(() => settingsStore.theme)
//
const routers = computed(() => permissionStore.topbarRouters)
// const routers = computed(() => permissionStore.topbarRouters)
const routers = ref([
{
path: "/",
hidden: false,
component: "Layout",
children: [
{
name: "工作台",
path: "index",
hidden: false,
component: "index",
meta: {
title: "工作台",
noCache: false,
link: null
}
}
]
},
{
path: "/",
hidden: false,
component: "Layout",
children: [
{
name: "媒体库管理",
path: "mediaLibrary",
hidden: false,
component: "index",
meta: {
title: "媒体库管理",
noCache: false,
link: null
}
}
]
},
{
path: "/",
hidden: false,
component: "Layout",
children: [
{
name: "户外媒介数据",
path: "outdoorMedia",
hidden: false,
component: "index",
meta: {
title: "户外媒介数据",
noCache: false,
link: null
}
}
]
},
{
path: "/",
hidden: false,
component: "Layout",
children: [
{
name: "供应商",
path: "supplier",
hidden: false,
component: "index",
meta: {
title: "供应商",
noCache: false,
link: null
}
}
]
},
{
path: "/",
hidden: false,
component: "Layout",
children: [
{
name: "问题反馈",
path: "problemFeedback",
hidden: false,
component: "index",
meta: {
title: "问题反馈",
noCache: false,
link: null
}
}
]
},
{
"name": "System",
"path": "/system",
"hidden": false,
"redirect": "noRedirect",
"component": "Layout",
"alwaysShow": true,
"meta": {
"title": "系统管理",
"noCache": false,
"link": null
},
"children": [
{
"name": "Menu",
"path": "menu",
"hidden": false,
"component": "system/menu/index",
"meta": {
"title": "菜单管理",
"icon": "#",
"noCache": false,
"link": null
}
},
{
"name": "Dept",
"path": "dept",
"hidden": false,
"component": "system/dept/index",
"meta": {
"title": "部门管理",
"icon": "#",
"noCache": false,
"link": null
}
},
{
"name": "Role",
"path": "role",
"hidden": false,
"component": "system/role/index",
"meta": {
"title": "角色管理",
"icon": "#",
"noCache": false,
"link": null
}
},
{
"name": "User",
"path": "user",
"hidden": false,
"component": "system/user/index",
"meta": {
"title": "用户管理",
"icon": "#",
"noCache": false,
"link": null
}
},
{
"name": "Locality",
"path": "locality",
"hidden": false,
"component": "system/locality/index",
"meta": {
"title": "属地管理",
"icon": "#",
"noCache": false,
"link": null
}
},
{
"name": "Section",
"path": "section",
"hidden": false,
"component": "system/section/index",
"meta": {
"title": "科室管理",
"icon": "#",
"noCache": false,
"link": null
}
},
{
"name": "UserApproval",
"path": "userApproval",
"hidden": false,
"component": "system/userApproval/index",
"meta": {
"title": "新用户审批",
"icon": "#",
"noCache": false,
"link": null
}
},
{
"name": "Dict",
"path": "dict",
"hidden": false,
"component": "system/dict/index",
"meta": {
"title": "字典管理",
"icon": "#",
"noCache": false,
"link": null
}
}
]
}
])
console.log('routers', routers.value)
//
const topMenus = computed(() => {
@ -64,25 +257,27 @@ const topMenus = computed(() => {
if (menu.hidden !== true) {
//
if (menu.path === '/' && menu.children) {
topMenus.push(menu.children[0])
topMenus.push(menu.children[0])
} else {
topMenus.push(menu)
topMenus.push(menu)
}
}
})
return topMenus
})
//
const childrenMenus = computed(() => {
let childrenMenus = []
routers.value.map((router) => {
for (let item in router.children) {
if (router.children[item].parentPath === undefined) {
if(router.path === "/") {
if (router.path === "/") {
router.children[item].path = "/" + router.children[item].path
} else {
if(!isHttp(router.children[item].path)) {
if (!isHttp(router.children[item].path)) {
router.children[item].path = router.path + "/" + router.children[item].path
}
}
@ -104,7 +299,7 @@ const activeMenu = computed(() => {
activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"))
appStore.toggleSideBarHide(false)
}
} else if(!route.children) {
} else if (!route.children) {
activePath = path
appStore.toggleSideBarHide(true)
}
@ -113,7 +308,9 @@ const activeMenu = computed(() => {
})
function setVisibleNumber() {
console.log('sdfsda')
const width = document.body.getBoundingClientRect().width / 3
console.log('sdfsda', width)
visibleNumber.value = parseInt(width / 85)
}
@ -149,7 +346,7 @@ function activeRoutes(key) {
}
})
}
if(routes.length > 0) {
if (routes.length > 0) {
permissionStore.setSidebarRouters(routes)
} else {
appStore.toggleSideBarHide(true)
@ -171,47 +368,94 @@ onMounted(() => {
</script>
<style lang="scss">
.topmenu-container.el-menu--horizontal > .el-menu-item {
float: left;
height: 50px !important;
line-height: 50px !important;
color: #999093 !important;
padding: 0 5px !important;
margin: 0 10px !important;
.el-menu--horizontal {
height: 43px;
background: transparent;
}
.topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title {
border-bottom: 2px solid #{'var(--theme)'} !important;
color: #303133;
.el-menu--horizontal.el-menu {
border-bottom: 0px solid var(--el-menu-border-color);
}
/* sub-menu item */
.topmenu-container.el-menu--horizontal > .el-sub-menu .el-sub-menu__title {
float: left;
height: 50px !important;
line-height: 50px !important;
color: #999093 !important;
padding: 0 5px !important;
margin: 0 10px !important;
.el-menu--horizontal>.el-menu-item {
font-family: Microsoft YaHei;
font-weight: 600;
font-size: 18px;
color: #FFFFFF;
padding: 0px !important;
margin: 0 36px !important;
}
/* 背景色隐藏 */
.topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover {
background-color: #ffffff;
//
.el-menu--horizontal>.el-menu-item.is-active,
.el-menu--horizontal>.el-sub-menu.is-active .el-sub-menu__title {
border-bottom: 2px solid #FFFFFF;
color: #FFFFFF !important;
background-color: transparent !important;
font-weight: 700;
}
/* 图标右间距 */
.topmenu-container .svg-icon {
margin-right: 4px;
//
.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,
.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,
.el-menu--horizontal>.el-submenu .el-submenu__title:hover {
border-bottom: 2px solid #FFFFFF;
color: #FFFFFF !important;
background-color: transparent !important;
font-weight: 700;
}
/* topmenu more arrow */
.topmenu-container .el-sub-menu .el-sub-menu__icon-arrow {
position: static;
vertical-align: middle;
margin-left: 8px;
margin-top: 0px;
.el-menu--horizontal .el-menu .el-menu-item:hover {
color: #ffffff !important;
background: #545454 !important;
}
.el-menu--horizontal .el-menu .el-menu-item.is-active {
color: #ffffff !important;
background: #545454 !important;
}
</style>
// .topmenu-container.el-menu--horizontal>.el-menu-item {
// float: left;
// height: 50px !important;
// line-height: 50px !important;
// color: #999093 !important;
// padding: 0 5px !important;
// margin: 0 10px !important;
// }
// .topmenu-container.el-menu--horizontal>.el-menu-item.is-active,
// .el-menu--horizontal>.el-sub-menu.is-active .el-submenu__title {
// border-bottom: 2px solid #{'var(--theme)'} !important;
// color: #303133;
// }
// /* sub-menu item */
// .topmenu-container.el-menu--horizontal>.el-sub-menu .el-sub-menu__title {
// float: left;
// height: 50px !important;
// line-height: 50px !important;
// color: #999093 !important;
// padding: 0 5px !important;
// margin: 0 10px !important;
// }
// /* */
// .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,
// .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,
// .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover {
// background-color: #ffffff;
// }
// /* */
// .topmenu-container .svg-icon {
// margin-right: 4px;
// }
// /* topmenu more arrow */
// .topmenu-container .el-sub-menu .el-sub-menu__icon-arrow {
// position: static;
// vertical-align: middle;
// margin-left: 8px;
// margin-top: 0px;
// }</style>

View File

@ -37,8 +37,8 @@ function addIframe() {
<style lang="scss" scoped>
.app-main {
/* 50= navbar 50 */
min-height: calc(100vh - 50px);
/* 80= navbar 80 */
min-height: calc(100vh - 80px);
width: 100%;
position: relative;
overflow: hidden;
@ -49,17 +49,17 @@ function addIframe() {
}
.fixed-header + .app-main {
padding-top: 50px;
padding-top: 80px;
}
.hasTagsView {
.app-main {
/* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 84px);
/* 114 = navbar + tags-view = 80 + 34 */
min-height: calc(100vh - 114px);
}
.fixed-header + .app-main {
padding-top: 84px;
padding-top: 114px;
}
}
</style>

View File

@ -1,53 +1,28 @@
<template>
<div class="navbar">
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<!-- <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container"
@toggleClick="toggleSideBar" /> -->
<breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" />
<top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" />
<div class="right-menu">
<template v-if="appStore.device !== 'mobile'">
<header-search id="header-search" class="right-menu-item" />
<el-tooltip content="源码地址" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip content="文档地址" effect="dark" placement="bottom">
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
</el-tooltip>
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="主题模式" effect="dark" placement="bottom">
<div class="right-menu-item hover-effect theme-switch-wrapper" @click="toggleTheme">
<svg-icon v-if="settingsStore.isDark" icon-class="sunny" />
<svg-icon v-if="!settingsStore.isDark" icon-class="moon" />
<div class="navContent">
<div class="systemLogoContent">
<img v-if="homeLogo" :src="homeLogo" class="sidebar-logo" />
</div>
<div class="topmenu-container">
<top-nav v-if="settingsStore.topNav" id="topmenu-container" />
</div>
<div class="right-menu">
<div class="el-dropdown avatar-container right-menu-item hover-effect">
<div class="avatar-wrapper">
<img :src="userStore.avatar ? userStore.avatar : avatar_icon" class="user-avatar" />
<span class="user-nickname"> {{ userStore.nickName }} admin </span>
<div class="logout_icon">
<img :src="logout_icon" class="custom-icon" @click="logout" />
</div>
</div>
</el-tooltip>
<el-tooltip content="布局大小" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip>
</template>
<el-dropdown @command="handleCommand" class="avatar-container right-menu-item hover-effect" trigger="hover">
<div class="avatar-wrapper">
<img :src="userStore.avatar" class="user-avatar" />
<span class="user-nickname"> {{ userStore.nickName }} </span>
</div>
<template #dropdown>
<el-dropdown-menu>
<router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
<el-dropdown-item divided command="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="right-menu-item hover-effect setting" @click="setLayout" v-if="settingsStore.showSettings">
<svg-icon icon-class="more-up" />
<div class="right-menu-item hover-effect setting" @click="setLayout" v-if="settingsStore.showSettings">
<svg-icon icon-class="more-up" />
</div>
</div>
</div>
</div>
@ -56,13 +31,10 @@
<script setup>
import { ElMessageBox } from 'element-plus'
import Breadcrumb from '@/components/Breadcrumb'
import homeLogo from '@/assets/logo/homeLogo.png'
import avatar_icon from '@/assets/images/avatar_icon.png'
import logout_icon from '@/assets/images/logout_icon.png'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect'
import HeaderSearch from '@/components/HeaderSearch'
import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc'
import useAppStore from '@/store/modules/app'
import useUserStore from '@/store/modules/user'
import useSettingsStore from '@/store/modules/settings'
@ -71,24 +43,14 @@ const appStore = useAppStore()
const userStore = useUserStore()
const settingsStore = useSettingsStore()
console.log('settingsStore.topNav', settingsStore.topNav)
function toggleSideBar() {
appStore.toggleSideBar()
}
function handleCommand(command) {
switch (command) {
case "setLayout":
setLayout()
break
case "logout":
logout()
break
default:
break
}
}
function logout() {
// 退
const logout = () => {
ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -111,60 +73,56 @@ function toggleTheme() {
</script>
<style lang='scss' scoped>
.myRow {
margin-left: 0 !important;
margin-right: 0 !important;
}
.navbar {
height: 50px;
height: 80px;
overflow: hidden;
position: relative;
background: var(--navbar-bg);
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
background: transparent;
box-shadow: none;
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
.navContent {
height: 43px;
width: 1840px;
margin: 19px auto 18px auto;
display: flex; // flex
justify-content: space-between; // 使
align-items: center; //
}
.breadcrumb-container {
float: left;
.systemLogoContent {
width: 220px;
}
.topmenu-container {
position: absolute;
left: 50px;
}
.errLog-container {
display: inline-block;
vertical-align: top;
flex: 1; //
padding-left: 284px; // padding-left
}
.right-menu {
float: right;
height: 100%;
line-height: 50px;
display: flex;
width: 220px;
text-align: right;
line-height: normal; // line-height
display: flex; // 使flex
align-items: center; //
justify-content: flex-end; //
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background 0.3s;
&:hover {
@ -191,23 +149,22 @@ function toggleTheme() {
padding-right: 0px;
.avatar-wrapper {
margin-top: 10px;
right: 5px;
position: relative;
display: flex;
align-items: center;
.user-avatar {
cursor: pointer;
width: 30px;
height: 30px;
border-radius: 50%;
}
.user-nickname{
position: relative;
left: 5px;
bottom: 10px;
font-size: 14px;
font-weight: bold;
.user-nickname {
bottom: 0 !important; // bottom
margin-left: 8px;
font-family: Microsoft YaHei;
font-weight: 400;
font-size: 18px;
color: #FFFFFF;
}
i {
@ -220,5 +177,32 @@ function toggleTheme() {
}
}
}
.logout_icon {
margin-left: 30px;
cursor: pointer;
}
}
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
.breadcrumb-container {
float: left;
}
.errLog-container {
display: inline-block;
vertical-align: top;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<div :class="{ 'has-logo': showLogo }" class="sidebar-container">
<logo v-if="showLogo" :collapse="isCollapse" />
<!-- <logo v-if="showLogo" :collapse="isCollapse" /> -->
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
@ -70,16 +70,17 @@ const activeMenu = computed(() => {
<style lang="scss" scoped>
.sidebar-container {
background-color: v-bind(getMenuBackground);
background-color: transparent;
.scrollbar-wrapper {
background-color: v-bind(getMenuBackground);
background-color: transparent;
}
.el-menu {
border: none;
height: 100%;
width: 100% !important;
background: transparent;
.el-menu-item, .el-sub-menu__title {
&:hover {

View File

@ -1,3 +1,5 @@
import { fa } from "element-plus/es/locales.mjs";
export default {
/**
* 网页标题
@ -7,22 +9,22 @@ export default {
/**
* 侧边栏主题 深色主题theme-dark浅色主题theme-light
*/
sideTheme: 'theme-dark',
sideTheme: 'theme-light',
/**
* 是否系统布局配置
*/
showSettings: true,
showSettings: false,
/**
* 是否显示顶部导航
*/
topNav: false,
topNav: true,
/**
* 是否显示 tagsView
*/
tagsView: true,
tagsView: false,
/**
* 显示页签图标
@ -32,7 +34,7 @@ export default {
/**
* 是否固定头部
*/
fixedHeader: false,
fixedHeader: true,
/**
* 是否显示logo

File diff suppressed because it is too large Load Diff

View File