321 lines
8.4 KiB
Vue
321 lines
8.4 KiB
Vue
<template>
|
||
<div class="app-container">
|
||
<el-container>
|
||
<el-header>
|
||
<div class="header-logo"></div>
|
||
</el-header>
|
||
<el-container>
|
||
<el-aside>
|
||
<nav class="menu">
|
||
<!-- 手动生成第一个菜单项 -->
|
||
<div v-for="item in menuItems" :key="item.index" class="el-sub-menu">
|
||
<div class="menu-title" :class="{ 'active-parent': hasActiveChild(item) }">
|
||
<!-- 激活状态的左侧青色图片 -->
|
||
<img
|
||
v-if="hasActiveChild(item)"
|
||
src="./assets/images/titleActiveLeftRec.png"
|
||
alt=""
|
||
class="title-active-left"
|
||
/>
|
||
<div class="tltlemenu-left">
|
||
<img
|
||
src="./assets/images/titlelogo.png"
|
||
style="width: 20px; height: 20px; margin-right: 12px"
|
||
/>
|
||
{{ item.title }}
|
||
</div>
|
||
<img
|
||
src="./assets/images/titleright.png"
|
||
alt=""
|
||
style="width: 66px; height: 16px"
|
||
/>
|
||
</div>
|
||
<ul class="menu-items">
|
||
<div
|
||
v-for="child in item.subItems"
|
||
:key="child.index"
|
||
style="text-decoration: none"
|
||
>
|
||
<li
|
||
:key="child.index"
|
||
class="el-menu-item"
|
||
@click="jumpPage(child.index)"
|
||
:class="{ active: isActive(child.index) }"
|
||
>
|
||
<div>
|
||
{{ child.title }}
|
||
</div>
|
||
</li>
|
||
</div>
|
||
</ul>
|
||
</div>
|
||
</nav>
|
||
</el-aside>
|
||
<el-main>
|
||
<router-view></router-view>
|
||
</el-main>
|
||
</el-container>
|
||
</el-container>
|
||
<el-dialog v-model="openDialog" width="500" align-center class="custom-dialog-prepare">
|
||
<div class="center-tips">
|
||
<img src="./assets/images/icon/pre-icon.png" alt="" class="pre-icon" />
|
||
<div class="tips-font">该案例正在开发中</div>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { onMounted, ref, onUnmounted } from "vue"
|
||
import { useRoute, useRouter } from "vue-router"
|
||
|
||
const router = useRouter()
|
||
const route = useRoute()
|
||
const menuItems = [
|
||
{
|
||
index: "1",
|
||
title: "关键节点识别",
|
||
subItems: [
|
||
{ index: "/key-node-1", title: "重大舆情事件锚点推荐" },
|
||
{ index: "/key-node-2", title: "传播意见领袖识别" },
|
||
{ index: "/key-node-3", title: "传播桥梁节点识别" }
|
||
]
|
||
},
|
||
{
|
||
index: "2",
|
||
title: "链路预测",
|
||
subItems: [
|
||
{ index: "/link-prediction-1", title: "人物互动隐关系预测" },
|
||
{ index: "/link-prediction-2", title: "社交紧密团体识别" },
|
||
{ index: "/link-prediction-3", title: "人物社交隐关系预测" }
|
||
]
|
||
},
|
||
{
|
||
index: "3",
|
||
title: "群体演化分析",
|
||
subItems: [
|
||
{ index: "/group-evolution-1", title: "群体识别发现" },
|
||
{ index: "/group-evolution-2", title: "群体结构演化分析" },
|
||
{ index: "/group-evolution-3", title: "群体成员演化分析" },
|
||
{ index: "/group-evolution-4", title: "异常群体捕捉" }
|
||
]
|
||
}
|
||
]
|
||
|
||
const openDialog = ref(false)
|
||
// 判断当前路由是否激活菜单项
|
||
const isActive = (routePath) => {
|
||
return route.path === routePath
|
||
}
|
||
|
||
// 判断父菜单是否有激活的子项
|
||
const hasActiveChild = (item) => {
|
||
return item.subItems.some((child) => isActive(child.index))
|
||
}
|
||
|
||
//处理跳转页面逻辑
|
||
const jumpPage = (routePath) => {
|
||
const activedPaths = [
|
||
"/key-node-1",
|
||
"/key-node-2",
|
||
"/key-node-3",
|
||
"/link-prediction-1",
|
||
"/link-prediction-2",
|
||
"/link-prediction-3",
|
||
"/group-evolution-1",
|
||
"/group-evolution-2",
|
||
"/group-evolution-3",
|
||
"/group-evolution-4"
|
||
]
|
||
if (activedPaths.includes(routePath)) {
|
||
router.push({ path: routePath })
|
||
return
|
||
}
|
||
openDialog.value = true
|
||
}
|
||
|
||
const disableZoom = () => {
|
||
// 强制重置浏览器缩放为 100%
|
||
const resetZoom = () => {
|
||
document.body.style.zoom = "100%"
|
||
if (window.devicePixelRatio !== 1) {
|
||
const viewportMeta = document.querySelector('meta[name="viewport"]')
|
||
if (viewportMeta) {
|
||
viewportMeta.content =
|
||
"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
|
||
}
|
||
}
|
||
}
|
||
// 禁用快捷键(Ctrl/Cmd + +/-/0 和 滚轮)
|
||
const keysToBlock = new Set(["+", "-", "=", "0"])
|
||
const codesToBlock = new Set(["Equal", "Minus", "NumpadAdd", "NumpadSubtract", "Digit0"])
|
||
const handleKeyDown = (e) => {
|
||
if ((e.ctrlKey || e.metaKey) && (keysToBlock.has(e.key) || codesToBlock.has(e.code))) {
|
||
e.preventDefault()
|
||
}
|
||
}
|
||
const handleWheel = (e) => {
|
||
if (e.ctrlKey) {
|
||
e.preventDefault()
|
||
}
|
||
}
|
||
|
||
// 初始化
|
||
resetZoom()
|
||
document.addEventListener("keydown", handleKeyDown)
|
||
document.addEventListener("wheel", handleWheel, { passive: false })
|
||
|
||
// 可选,用于组件卸载时移除监听
|
||
return () => {
|
||
document.removeEventListener("keydown", handleKeyDown)
|
||
document.removeEventListener("wheel", handleWheel)
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
const cleanup = disableZoom()
|
||
onUnmounted(() => cleanup())
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.app-container {
|
||
width: 100vw;
|
||
height: 111vh;
|
||
background-image: url("./assets/images/bci.png");
|
||
background-size: cover;
|
||
background-repeat: no-repeat;
|
||
background-position: center;
|
||
background-color: #02131f;
|
||
}
|
||
:deep(.custom-dialog-prepare) {
|
||
width: 480px;
|
||
height: 250px;
|
||
background: url("./assets/images/preparation.png") no-repeat center;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
:deep(.custom-dialog-prepare) .pre-icon {
|
||
width: 30px;
|
||
height: 30px;
|
||
margin-right: 10px;
|
||
}
|
||
:deep(.custom-dialog-prepare) .center-tips {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
:deep(.custom-dialog-prepare) .center-tips .tips-font {
|
||
font-size: 24px;
|
||
color: #fff;
|
||
opacity: 0.7;
|
||
}
|
||
.el-header {
|
||
width: 100%;
|
||
height: 115px;
|
||
padding: 0;
|
||
.header-logo {
|
||
width: 100%;
|
||
height: 100%;
|
||
background-image: url("./assets/images/head.png");
|
||
background-size: cover;
|
||
background-repeat: no-repeat;
|
||
}
|
||
}
|
||
|
||
.menu {
|
||
width: 320px;
|
||
height: 100%;
|
||
border-width: 2px;
|
||
border-style: solid;
|
||
border-image: linear-gradient(to bottom, #3aa1f8, #3aa1f833) 1;
|
||
background-image: linear-gradient(to right, #063d7133, #081e38cc);
|
||
.menu-title {
|
||
cursor: pointer;
|
||
padding: 10px;
|
||
width: 288px;
|
||
border-radius: 2px;
|
||
margin-top: 16px;
|
||
margin-left: 16px;
|
||
background-image: linear-gradient(270deg, rgba(6, 61, 113, 0.2) 0%, rgba(8, 30, 56, 0.8) 100%);
|
||
/* border-image: linear-gradient(to right, #225f9200, #3aa1f8) 1; */
|
||
border: 2px solid;
|
||
border-image-source: linear-gradient(90deg, #3aa1f8 0%, rgba(58, 161, 248, 0.2) 100%);
|
||
border-image-slice: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
&:hover {
|
||
border-radius: 2px;
|
||
background: linear-gradient(270deg, rgba(14, 167, 213, 0) 0%, rgba(8, 118, 190, 0.24) 100%);
|
||
}
|
||
}
|
||
.menu-items {
|
||
padding: 0 15px;
|
||
}
|
||
}
|
||
|
||
.menu-title.active-parent {
|
||
/* 设置背景图片 */
|
||
background-image:
|
||
url("./assets/images/titleActiveMaskGroup.png"), Linear-gradient(to right, #0876be, #0ea7d500);
|
||
background-repeat: no-repeat;
|
||
background-size: contain;
|
||
position: relative;
|
||
border: none;
|
||
padding-left: 30px; /* 为左侧图片腾出空间 */
|
||
}
|
||
|
||
.title-active-left {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 8%;
|
||
width: 3px; /* 根据实际图片大小调整 */
|
||
height: 88%;
|
||
z-index: 1;
|
||
}
|
||
|
||
.el-menu-item {
|
||
width: 100%;
|
||
height: 36px;
|
||
margin-top: 12px;
|
||
line-height: 36px;
|
||
cursor: pointer;
|
||
color: #fff;
|
||
padding-left: 40px;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.el-menu-item.active {
|
||
background-image: linear-gradient(270deg, rgba(14, 167, 213, 0) 0%, rgba(8, 118, 190, 0.24) 100%);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.tltlemenu-left {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.sub-menu-items {
|
||
list-style-type: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.el-menu-item:hover {
|
||
background-image: linear-gradient(to right, #0876be, #0ea7d500);
|
||
}
|
||
|
||
.el-main {
|
||
padding: 0 0;
|
||
margin-left: 30px;
|
||
}
|
||
.el-aside {
|
||
overflow: visible;
|
||
color: aliceblue;
|
||
font-family: Arial, sans-serif;
|
||
margin-left: 20px;
|
||
}
|
||
</style>
|