导航+首页

This commit is contained in:
bb_pan 2026-01-25 15:31:18 +08:00
parent 56991cbf86
commit 3ba7b31681
6 changed files with 420 additions and 279 deletions

View File

@ -121,7 +121,7 @@ aside {
//main-container全局样式 //main-container全局样式
.app-container { .app-container {
height: calc(100vh - 84px); height: calc(100vh - 90px);
padding: 20px; padding: 20px;
box-sizing: border-box; box-sizing: border-box;
// display: flex; // display: flex;

View File

@ -54,81 +54,82 @@
</el-dropdown> </el-dropdown>
</div> </div>
</div> </div>
<div style="height: 50px"></div>
<div class="menu-box" v-show="showMenuBox" @mouseenter="handleBoxEnter" @mouseleave="handleBoxLeave"> <div class="menu-box" v-show="showMenuBox" @mouseenter="handleBoxEnter">
<div class="menu-list"> <div class="menu-warp" @mouseleave="handleBoxLeave">
<div class="list-box"> <div class="menu-list">
<!-- 顶部标题 --> <div class="list-box">
<div class="menu-title-top" v-if="currentMenu && currentMenu.meta"> <div class="menu-title-top" v-if="currentMenu && currentMenu.meta">
<div class="title-tip"></div> <div class="title-tip"></div>
<span style="font-weight: bold; font-size: 16px">{{ currentMenu.meta.title }}</span> <span class="title-text">{{ currentMenu.meta.title }}</span>
</div> </div>
<!-- 一级 --> <div v-for="(child, i) in currentMenu.children || []" :key="i" class="sub-menu-item" v-if="!child.hidden">
<div v-for="(child, i) in currentMenu.children || []" :key="i" class="sub-menu-item" v-if="!child.hidden"> <div v-if="child.children && child.children.length">
<!-- 一级有子级 --> <div class="menu-title" @click="toggleLevel1(child)">
<div v-if="child.children && child.children.length"> <div class="children-title-tip"></div>
<!-- 一级父节点点击展开 --> <span>
<div class="menu-title" @click="toggleLevel1(child)"> <span style="margin-right: 5px">{{ child.meta.title }}</span>
<div class="children-title-tip"></div> <img
<span> v-if="openLevel1.includes(child.path)"
<span style="margin-right: 5px">{{ child.meta.title }}</span> src="@/assets/images/up.png"
<img style="width: 14px; height: 14px"
v-if="openLevel1 == child.path" />
src="@/assets/images/up.png" <img v-else src="@/assets/images/down.png" style="width: 14px; height: 14px" />
style="width: 14px; height: 14px" </span>
alt="" <span class="menu-star">
/> <img src="@/assets/images/star.png" style="width: 10px; height: 9px" />
<img v-else src="@/assets/images/down.png" style="width: 14px; height: 14px" alt="" /> </span>
</span> </div>
<span class="menu-star">
<img src="@/assets/images/star.png" style="width: 10px; height: 9px" alt="" />
</span>
</div>
<!-- 二级区域只在当前一级展开时显示 --> <div v-show="openLevel1.includes(child.path)">
<div v-show="openLevel1 === child.path"> <div v-for="(c2, j) in child.children" :key="j" class="sub-menu-item" v-if="!c2.hidden">
<!-- 二级 --> <div v-if="c2.children && c2.children.length">
<div v-for="(c2, j) in child.children" :key="j" class="sub-menu-item" v-if="!c2.hidden"> <div class="menu-title" @click="toggleLevel2(c2)">
<!-- 二级还有子级 --> {{ c2.meta.title }}
<div v-if="c2.children && c2.children.length"> <img
<!-- 二级父节点 --> v-if="openLevel2.includes(c2.path)"
<div class="menu-title" @click="toggleLevel2(c2)"> src="@/assets/images/up.png"
{{ c2.meta.title }} style="width: 12px; height: 12px; margin-left: 6px"
</div> />
<img
v-else
src="@/assets/images/down.png"
style="width: 12px; height: 12px; margin-left: 6px"
/>
</div>
<!-- 三级只展开当前二级 --> <div v-show="openLevel2.includes(c2.path)">
<div v-show="openLevel2 === c2.path"> <div
<div v-for="(c3, k) in c2.children"
v-for="(c3, k) in c2.children" :key="k"
:key="k" class="sub-menu-item"
class="sub-menu-item" v-if="!c3.hidden"
v-if="!c3.hidden" @click="goRoute(c3)"
@click="goRoute(c3)" >
> {{ c3.meta.title }}
{{ c3.meta.title }} </div>
</div> </div>
</div> </div>
</div>
<!-- 二级叶子节点 --> <div v-else class="menu-title" @click="goRoute(c2)">
<div v-else class="menu-title" @click="goRoute(c2)"> <span class="child-left">- {{ c2.meta.title }}</span>
<span class="child-left">- {{ c2.meta.title }}</span> <span class="menu-star">
<span class="menu-star"> <img src="@/assets/images/star.png" style="width: 10px; height: 9px" />
<img src="@/assets/images/star.png" style="width: 10px; height: 9px" alt="" /> </span>
</span> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- 一级就是叶子节点 --> <div v-else class="menu-title" @click="goRoute(child)">
<div v-else class="menu-title" @click="goRoute(child)"> <div class="children-title-tip"></div>
<div class="children-title-tip"></div> <span>{{ child.meta.title }}</span>
<span>{{ child.meta.title }}</span> <span class="menu-star">
<span class="menu-star"> <img src="@/assets/images/star.png" style="width: 10px; height: 9px" />
<img src="@/assets/images/star.png" style="width: 10px; height: 9px" alt="" /> </span>
</span> </div>
</div> </div>
</div> </div>
</div> </div>
@ -139,43 +140,24 @@
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch' import Search from '@/components/HeaderSearch'
import bonusGit from '@/components/bonus/Git'
import bonusDoc from '@/components/bonus/Doc'
import { getUserProfile } from '@/api/system/user' import { getUserProfile } from '@/api/system/user'
export default { export default {
components: { components: { Search },
Breadcrumb,
TopNav,
Hamburger,
Screenfull,
SizeSelect,
Search,
bonusGit,
bonusDoc,
},
data() { data() {
return { return {
title: process.env.VUE_APP_TITLE, title: process.env.VUE_APP_TITLE,
user: {}, user: {},
onlyOneChild: null,
basePath: null,
basePath2: null,
menuList: [], menuList: [],
showMenuBox: false, showMenuBox: false,
currentMenu: {}, // hover currentMenu: {},
openLevel1: '', // path openLevel1: [],
openLevel2: '', // path openLevel2: [],
} }
}, },
computed: { computed: {
...mapGetters(['sidebarRouters', 'sidebar', 'avatar', 'device']), ...mapGetters(['sidebarRouters', 'avatar', 'device']),
setting: { setting: {
get() { get() {
return this.$store.state.settings.showSettings return this.$store.state.settings.showSettings
@ -187,27 +169,17 @@ export default {
}) })
}, },
}, },
topNav: {
get() {
return this.$store.state.settings.topNav
},
},
}, },
created() { created() {
this.getUser() this.getUser()
// sidebarRouters
this.menuList = this.sidebarRouters.filter((route) => !route.hidden) this.menuList = this.sidebarRouters.filter((route) => !route.hidden)
}, },
mounted() {},
methods: { methods: {
getUser() { getUser() {
getUserProfile().then((response) => { getUserProfile().then((response) => {
this.user = response.data this.user = response.data
}) })
}, },
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
async logout() { async logout() {
this.$confirm('确定注销并退出系统吗?', '提示', { this.$confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
@ -216,8 +188,6 @@ export default {
}) })
.then(() => { .then(() => {
this.$store.dispatch('LogOut').then((res) => { this.$store.dispatch('LogOut').then((res) => {
console.log('🚀 ~ res-退出登录:', res)
console.log('logout', process.env.VUE_APP_BASE_API)
this.$store.dispatch('tagsView/delAllViews') this.$store.dispatch('tagsView/delAllViews')
if (process.env.VUE_APP_BASE_API == '/iws/jxhzb-api') { if (process.env.VUE_APP_BASE_API == '/iws/jxhzb-api') {
window.location.href = 'http://sgwpdm.ah.sgcc.com.cn/iws' window.location.href = 'http://sgwpdm.ah.sgcc.com.cn/iws'
@ -231,11 +201,8 @@ export default {
}) })
}, },
handleMenuClick(item) { handleMenuClick(item) {
console.log('🚀 ~ item.redirect:', item.redirect)
if (item.redirect == 'index' || item.redirect == 'index1') { if (item.redirect == 'index' || item.redirect == 'index1') {
this.$router.push({ this.$router.push({ path: '/' + item.redirect })
path: '/' + item.redirect,
})
} }
}, },
handleMenuEnter(item) { handleMenuEnter(item) {
@ -243,22 +210,17 @@ export default {
this.showMenuBox = false this.showMenuBox = false
return return
} }
this.showMenuBox = true this.showMenuBox = true
// fullPath
const buildPath = (nodes, parentPath = '') => { const buildPath = (nodes, parentPath = '') => {
return nodes.map((n) => { return nodes.map((n) => {
let currentPath = n.path || '' let currentPath = n.path || ''
// /
if (!currentPath.startsWith('/')) { if (!currentPath.startsWith('/')) {
currentPath = parentPath.replace(/\/$/, '') + '/' + currentPath currentPath = parentPath.replace(/\/$/, '') + '/' + currentPath
} }
const newNode = { const newNode = { ...n, fullPath: currentPath }
...n,
fullPath: currentPath,
}
if (n.children && n.children.length) { if (n.children && n.children.length) {
newNode.children = buildPath(n.children, currentPath) newNode.children = buildPath(n.children, currentPath)
@ -268,57 +230,55 @@ export default {
}) })
} }
const children = buildPath(item.children || [], item.path)
this.currentMenu = { this.currentMenu = {
...item, ...item,
fullPath: item.path, fullPath: item.path,
children: buildPath(item.children || [], item.path), children,
} }
},
const level1 = []
const level2 = []
children.forEach((l1) => {
if (l1.children && l1.children.length) {
level1.push(l1.path)
l1.children.forEach((l2) => {
if (l2.children && l2.children.length) {
level2.push(l2.path)
}
})
}
})
this.openLevel1 = level1
this.openLevel2 = level2
},
handleMenuLeave() { handleMenuLeave() {
this.showMenuBox = false this.showMenuBox = false
}, },
handleBoxEnter() { handleBoxEnter() {
this.showMenuBox = true this.showMenuBox = true
}, },
handleBoxLeave() { handleBoxLeave() {
this.showMenuBox = false this.showMenuBox = false
}, },
goRoute(route) { goRoute(route) {
console.log('🚀 ~ route:', route)
if (route.fullPath) { if (route.fullPath) {
this.$router.push({ this.$router.push({ path: route.fullPath, query: route.query })
path: route.fullPath,
query: route.query,
})
this.showMenuBox = false this.showMenuBox = false
} }
}, },
//
toggleLevel1(item) { toggleLevel1(item) {
console.log('🚀 ~ item:', item) const idx = this.openLevel1.indexOf(item.path)
if (this.openLevel1 === item.path) { if (idx > -1) this.openLevel1.splice(idx, 1)
// else this.openLevel1.push(item.path)
this.openLevel1 = ''
this.openLevel2 = ''
} else {
//
this.openLevel1 = item.path
this.openLevel2 = ''
}
}, },
//
toggleLevel2(item) { toggleLevel2(item) {
console.log('🚀 ~ item:', item) const idx = this.openLevel2.indexOf(item.path)
if (this.openLevel2 === item.path) { if (idx > -1) this.openLevel2.splice(idx, 1)
this.openLevel2 = '' else this.openLevel2.push(item.path)
} else {
this.openLevel2 = item.path
}
}, },
}, },
} }
@ -326,9 +286,10 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.navbar { .navbar {
width: 100%;
height: 50px; height: 50px;
overflow: hidden; overflow: hidden;
position: relative; position: fixed;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@ -339,6 +300,7 @@ export default {
// background-position: center; // background-position: center;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%); background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%);
z-index: 10;
.app-title { .app-title {
width: 314px; width: 314px;
height: 50px; height: 50px;
@ -473,7 +435,15 @@ export default {
position: absolute; position: absolute;
z-index: 99999999; z-index: 99999999;
width: 100%; width: 100%;
background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%); height: calc(100% - 50px);
// background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%);
//
background: rgba(0, 0, 0, 0.5);
.menu-warp {
width: 100%;
background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%);
border-radius: 0 0 16px 16px;
}
.menu-list { .menu-list {
padding: 16px 20px; padding: 16px 20px;
width: 100%; width: 100%;
@ -483,15 +453,16 @@ export default {
font-family: Microsoft YaHei, Microsoft YaHei; font-family: Microsoft YaHei, Microsoft YaHei;
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
color: #095A4D; color: #095a4d;
line-height: 30px; line-height: 30px;
.list-box { .list-box {
padding: 16px; padding: 16px;
width: 290px; width: 290px;
height: 100%; height: 100%;
background: linear-gradient(0deg, rgba(44, 186, 178, 0.1) 0%, rgba(44, 186, 178, 0) 100%); // background: linear-gradient(0deg, rgba(44, 186, 178, 0) 0%, rgba(44, 186, 178, 0.1) 100%);
border-radius: 8px; background: linear-gradient(180deg, #e6ffff, rgba(233, 255, 255, 0) 90px);
border-radius: 12px;
} }
} }
.menu-title-top { .menu-title-top {
@ -499,7 +470,7 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
span { span {
color: #095A4D; color: #095a4d;
font-weight: 800; font-weight: 800;
} }
} }
@ -511,7 +482,7 @@ export default {
// //
&:hover { &:hover {
color: #2CBAB2; color: #2cbab2;
background: rgba(44, 186, 178, 0.1); background: rgba(44, 186, 178, 0.1);
border-radius: 4px; border-radius: 4px;
} }
@ -533,9 +504,18 @@ export default {
margin-right: 4px; margin-right: 4px;
width: 8px; width: 8px;
height: 16px; height: 16px;
line-height: 24px;
background: #2cbab2; background: #2cbab2;
margin-bottom: 20px;
border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
} }
.title-text {
font-size: 18px;
// color: #0f7969;
line-height: 24px;
font-weight: 700;
margin-bottom: 20px;
}
.children-title-tip { .children-title-tip {
margin-right: 4px; margin-right: 4px;
width: 8px; width: 8px;
@ -548,4 +528,20 @@ export default {
margin-left: 1rem; margin-left: 1rem;
} }
} }
/* 只改“下一级里的”二级、三级颜色 */
.menu-box {
/* 二级child.children 里面的 menu-title */
.sub-menu-item {
.sub-menu-item {
> .menu-title {
color: #333;
}
/* 三级:最里面的 sub-menu-item */
.sub-menu-item {
color: #333;
}
}
}
}
</style> </style>

View File

@ -1,54 +1,57 @@
<template> <template>
<div class="box-card"> <div class="warp">
<div id="tags-view-container" class="tags-view-container"> <div class="box-card">
<scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll"> <div id="tags-view-container" class="tags-view-container">
<router-link <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
v-for="tag in visitedViews" <router-link
ref="tag" v-for="tag in visitedViews"
:key="tag.path" ref="tag"
:class="isActive(tag) ? 'active' : ''" :key="tag.path"
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" :class="isActive(tag) ? 'active' : ''"
tag="span" :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
class="tags-view-item" tag="span"
:style="activeStyle(tag)" class="tags-view-item"
@click.middle.native="!isAffix(tag) ? closeSelectedTag(tag) : ''" :style="activeStyle(tag)"
@contextmenu.prevent.native="openMenu(tag, $event)" @click.middle.native="!isAffix(tag) ? closeSelectedTag(tag) : ''"
> @contextmenu.prevent.native="openMenu(tag, $event)"
<!-- {{ tag.title }} --> >
<span> <!-- {{ tag.title }} -->
<i v-if="showBackHome(tag)" class="el-icon-arrow-left back-icon" /> <span>
{{ renderTitle(tag) }} <i v-if="showBackHome(tag)" class="el-icon-arrow-left back-icon" />
</span> {{ renderTitle(tag) }}
<span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /> </span>
</router-link> <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
</scroll-pane> </router-link>
<div class="right-tag-fixed"> </scroll-pane>
<div class="line" /> <div class="right-tag-fixed">
<i class="el-icon-arrow-down right-icon" @click.stop="toggleDropDown" /> <div class="line" />
<div class="line" /> <i class="el-icon-arrow-down right-icon" @click.stop="toggleDropDown" />
<i class="el-icon-close right-icon" @click="handleClose" /> <div class="line" />
</div> <i class="el-icon-close right-icon" @click="handleClose" />
<transition name="ant-popover-br">
<div v-if="showDropDown" class="drop-down" ref="dropDown">
<div class="drop-item" v-for="(item, index) in dropDownViews" :key="index">
<div style="cursor: pointer" :class="{ 'active-title': isActive(item) }" @click="handleDownJump(item)">
{{ item.title }}
</div>
<i class="el-icon-close" style="cursor: pointer" @click="closeSelectedTag(item)" />
</div>
</div> </div>
</transition> <transition name="ant-popover-br">
<ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu"> <div v-if="showDropDown" class="drop-down" ref="dropDown">
<li @click="refreshSelectedTag(selectedTag)"> <i class="el-icon-refresh-right"></i> 刷新页面 </li> <div class="drop-item" v-for="(item, index) in dropDownViews" :key="index">
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"> <div style="cursor: pointer" :class="{ 'active-title': isActive(item) }" @click="handleDownJump(item)">
<i class="el-icon-close"></i> 关闭当前 {{ item.title }}
</li> </div>
<li @click="closeOthersTags"> <i class="el-icon-circle-close"></i> 关闭其他 </li> <i class="el-icon-close" style="cursor: pointer" @click="closeSelectedTag(item)" />
<li v-if="!isFirstView()" @click="closeLeftTags"> <i class="el-icon-back"></i> 关闭左侧 </li> </div>
<li v-if="!isLastView()" @click="closeRightTags"> <i class="el-icon-right"></i> 关闭右侧 </li> </div>
<li @click="closeAllTags(selectedTag)"> <i class="el-icon-circle-close"></i> 全部关闭 </li> </transition>
</ul> <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
<li @click="refreshSelectedTag(selectedTag)"> <i class="el-icon-refresh-right"></i> 刷新页面 </li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
<i class="el-icon-close"></i> 关闭当前
</li>
<li @click="closeOthersTags"> <i class="el-icon-circle-close"></i> 关闭其他 </li>
<li v-if="!isFirstView()" @click="closeLeftTags"> <i class="el-icon-back"></i> 关闭左侧 </li>
<li v-if="!isLastView()" @click="closeRightTags"> <i class="el-icon-right"></i> 关闭右侧 </li>
<li @click="closeAllTags(selectedTag)"> <i class="el-icon-circle-close"></i> 全部关闭 </li>
</ul>
</div>
</div> </div>
<div style="height: 40px"></div>
</div> </div>
</template> </template>
@ -330,17 +333,25 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.warp {
width: 100%;
}
.box-card { .box-card {
width: 100%; width: 100%;
height: 40px; height: 40px;
z-index: 11;
position: fixed;
background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%); background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%);
box-sizing: border-box;
} }
.tags-view-container { .tags-view-container {
position: relative; position: fixed;
height: 40px; height: 40px;
width: 100%; width: 100%;
background: #fff; background: #fff;
border-radius: 16px 16px 0px 0px; border-radius: 16px 16px 0px 0px;
box-sizing: border-box;
z-index: 10;
.tags-view-wrapper { .tags-view-wrapper {
padding-right: 100px; padding-right: 100px;

View File

@ -1830,7 +1830,6 @@ export default {
.app-container { .app-container {
padding: 12px; padding: 12px;
background-color: #f5f7fa; background-color: #f5f7fa;
height: calc(100vh - 84px);
} }
/* 搜索区域收起/展开按钮 */ /* 搜索区域收起/展开按钮 */

View File

@ -1,50 +1,55 @@
<template> <template>
<div class="app-container"> <div class="viewport">
<div class="top"> <div class="screen" :style="screenStyle">
<div class="top-1"> <div class="app-container">
<Top1 @openDialog="openSystemEquip"/> <div style="height: 90px"></div>
</div> <div class="top">
<div class="top-2" style="padding: 0;"> <div class="top-1">
<Top2 /> <Top1 @openDialog="openSystemEquip" />
</div> </div>
<div class="top-3"> <div class="top-2" style="padding: 0">
<Top3 @openDialog="openEquipItemMore"/> <Top2 />
</div> </div>
</div> <div class="top-3">
<Top3 @openDialog="openEquipItemMore" />
<div class="center"> </div>
<div class="center-1">
<Center1 @openDialog="openRetirementWarning"/>
</div>
<div class="center-2">
<Center2 @openDialog="openProEquip"/>
</div>
</div>
<div class="bottom">
<div class="bottom-1">
<Bottom1 @openDialog="openWarning"/>
<!-- <div class="bottom-1-1">
<Bottom1 />
</div> </div>
<div class="bottom-1-2">
<Bottom2 /> <div class="center">
</div> --> <div class="center-1">
</div> <Center1 @openDialog="openRetirementWarning" />
<div class="bottom-2"> </div>
<Bottom2 @openDialog="openEquipStatusMore"/> <div class="center-2">
</div> <Center2 @openDialog="openProEquip" />
<div class="bottom-3"> </div>
<Bottom3 @openDialog="openEquipTurnroundRate"/> </div>
<div class="bottom">
<div class="bottom-1">
<Bottom1 @openDialog="openWarning" />
<!-- <div class="bottom-1-1">
<Bottom1 />
</div>
<div class="bottom-1-2">
<Bottom2 />
</div> -->
</div>
<div class="bottom-2">
<Bottom2 @openDialog="openEquipStatusMore" />
</div>
<div class="bottom-3">
<Bottom3 @openDialog="openEquipTurnroundRate" />
</div>
</div>
<EquipTurnroundRate ref="equipTurnroundRate" />
<EquipWarning ref="equipWarning" />
<ProEquip ref="proEquip" />
<RetirementWarning ref="retirementWarning" />
<EquipItemMore ref="equipItemMore" />
<EquipStatusMore ref="equipStatusMore" />
<SystemEquip ref="systemEquip" />
</div> </div>
</div> </div>
<EquipTurnroundRate ref="equipTurnroundRate" />
<EquipWarning ref="equipWarning" />
<ProEquip ref="proEquip" />
<RetirementWarning ref="retirementWarning" />
<EquipItemMore ref="equipItemMore" />
<EquipStatusMore ref="equipStatusMore" />
<SystemEquip ref="systemEquip" />
</div> </div>
</template> </template>
@ -75,12 +80,59 @@ export default {
Bottom1, Bottom1,
Bottom2, Bottom2,
Bottom3, Bottom3,
EquipTurnroundRate,EquipWarning,ProEquip,RetirementWarning,EquipItemMore,EquipStatusMore,SystemEquip EquipTurnroundRate,
EquipWarning,
ProEquip,
RetirementWarning,
EquipItemMore,
EquipStatusMore,
SystemEquip,
}, },
data() { data() {
return {} return {
scale: 1,
offsetX: 0,
offsetY: 0,
}
},
computed: {
screenStyle() {
return {
width: '1920px',
height: '1080px',
transform: `translate(${this.offsetX}px, ${this.offsetY}px) scale(${this.scale})`,
transformOrigin: '0 0',
}
},
},
mounted() {
this.calcScale()
window.addEventListener('resize', this.calcScale)
},
beforeDestroy() {
window.removeEventListener('resize', this.calcScale)
}, },
methods: { methods: {
calcScale() {
const baseW = 1920
const baseH = 1080
const vw = document.documentElement.clientWidth
const vh = document.documentElement.clientHeight
const scale = Math.min(vw / baseW, vh / baseH)
const realW = baseW * scale
const realH = baseH * scale
//
this.offsetX = (vw - realW) / 2 / scale
//
this.offsetY = 0
this.scale = scale
},
openEquipTurnroundRate() { openEquipTurnroundRate() {
this.$refs.equipTurnroundRate.openDialog() this.$refs.equipTurnroundRate.openDialog()
}, },
@ -107,7 +159,24 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 外层视口:锁满屏 */
.viewport {
position: fixed;
inset: 0;
overflow: hidden;
background: #e1ebf7; /* 大屏底色 */
}
/* 被缩放的 1920×1080 画布 */
.screen {
position: absolute;
top: 0;
left: 0;
}
.app-container { .app-container {
width: 1920px;
height: 1080px;
background: #e1ebf7; background: #e1ebf7;
} }
.top { .top {

View File

@ -1,37 +1,42 @@
<template> <template>
<div class="app-container"> <div class="viewport">
<div class="top"> <div class="screen" :style="screenStyle">
<div class="top-1"> <div class="app-container">
<Top1 /> <div style="height: 90px"></div>
</div> <div class="top">
<div class="top-2"> <div class="top-1">
<Top2 /> <Top1 />
</div> </div>
<div class="top-3"> <div class="top-2">
<Top3 /> <Top2 />
</div> </div>
</div> <div class="top-3">
<Top3 />
<div class="center"> </div>
<div class="center-1">
<Center1 />
</div>
<div class="center-2">
<Center2 />
</div>
</div>
<div class="bottom">
<div class="bottom-1">
<div class="bottom-1-1">
<Bottom11 />
</div> </div>
<div class="bottom-1-2">
<Bottom12 /> <div class="center">
<div class="center-1">
<Center1 />
</div>
<div class="center-2">
<Center2 />
</div>
</div>
<div class="bottom">
<div class="bottom-1">
<div class="bottom-1-1">
<Bottom11 />
</div>
<div class="bottom-1-2">
<Bottom12 />
</div>
</div>
<div class="bottom-2">
<Bottom2 />
</div>
</div> </div>
</div>
<div class="bottom-2">
<Bottom2 />
</div> </div>
</div> </div>
</div> </div>
@ -60,15 +65,76 @@ export default {
Bottom2, Bottom2,
}, },
data() { data() {
return {} return {
scale: 1,
offsetX: 0,
offsetY: 0,
}
},
computed: {
screenStyle() {
return {
width: '1920px',
height: '1080px',
transform: `translate(${this.offsetX}px, ${this.offsetY}px) scale(${this.scale})`,
transformOrigin: '0 0',
}
},
},
mounted() {
this.calcScale()
window.addEventListener('resize', this.calcScale)
},
beforeDestroy() {
window.removeEventListener('resize', this.calcScale)
},
methods: {
calcScale() {
const baseW = 1920
const baseH = 1080
const vw = document.documentElement.clientWidth
const vh = document.documentElement.clientHeight
const scale = Math.min(vw / baseW, vh / baseH)
const realW = baseW * scale
const realH = baseH * scale
//
this.offsetX = (vw - realW) / 2 / scale
//
this.offsetY = 0
this.scale = scale
},
}, },
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 外层视口:锁满屏 */
.viewport {
position: fixed;
inset: 0;
overflow: hidden;
background: #e1ebf7; /* 大屏底色 */
}
/* 被缩放的 1920×1080 画布 */
.screen {
position: absolute;
top: 0;
left: 0;
}
.app-container { .app-container {
width: 1920px;
height: 1080px;
background: #e1ebf7; background: #e1ebf7;
} }
.top { .top {
margin-bottom: 16px; margin-bottom: 16px;
display: flex; display: flex;
@ -104,7 +170,7 @@ export default {
.center-1, .center-1,
.center-2 { .center-2 {
width: 50%; width: 928px;
height: 390px; height: 390px;
padding: 24px; padding: 24px;
background: rgba(255, 255, 255, 0.91); background: rgba(255, 255, 255, 0.91);
@ -125,7 +191,7 @@ export default {
justify-content: space-between; justify-content: space-between;
.bottom-1 { .bottom-1 {
width: 50%; width: 928px;
height: 350px; height: 350px;
display: flex; display: flex;
align-items: center; align-items: center;
@ -148,7 +214,7 @@ export default {
} }
} }
.bottom-2 { .bottom-2 {
width: 50%; width: 928px;
height: 350px; height: 350px;
padding: 24px; padding: 24px;
background: rgba(255, 255, 255, 0.91); background: rgba(255, 255, 255, 0.91);