配置前端工程化,模块化,组件化,调整项目目录,文件名等
This commit is contained in:
parent
4735723452
commit
7f5dac177f
263
src/App.vue
263
src/App.vue
|
|
@ -1,139 +1,11 @@
|
|||
<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>
|
||||
<router-view />
|
||||
</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
|
||||
}
|
||||
|
||||
import { onMounted, onUnmounted } from "vue"
|
||||
const disableZoom = () => {
|
||||
// 强制重置浏览器缩放为 100%
|
||||
const resetZoom = () => {
|
||||
|
|
@ -182,139 +54,10 @@ onMounted(() => {
|
|||
.app-container {
|
||||
width: 100vw;
|
||||
height: 111vh;
|
||||
background-image: url("./assets/images/bci.png");
|
||||
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>
|
||||
|
|
|
|||
208
src/layout/components/aside/index.vue
Normal file
208
src/layout/components/aside/index.vue
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
<template>
|
||||
<div class="aside-component">
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, defineEmits } from "vue"
|
||||
import { useRoute, useRouter } from "vue-router"
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const emit = defineEmits(["update:openDialog"])
|
||||
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 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
|
||||
}
|
||||
emit("update:openDialog", true)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
jumpPage("/key-node-1")
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.aside-component {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.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);
|
||||
}
|
||||
</style>
|
||||
46
src/layout/components/dialog/index.vue
Normal file
46
src/layout/components/dialog/index.vue
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<template>
|
||||
<div class="dialog-component">
|
||||
<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" class="pre-icon" />
|
||||
<div class="tips-font">该案例正在开发中</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineProps } from "vue"
|
||||
const props = defineProps({
|
||||
openDialog: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
const openDialog = ref(props.openDialog)
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
: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;
|
||||
}
|
||||
</style>
|
||||
15
src/layout/components/header/index.vue
Normal file
15
src/layout/components/header/index.vue
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<div class="header-logo"></div>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="less">
|
||||
.header-logo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("@/assets/images/head.png");
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
</style>
|
||||
50
src/layout/index.vue
Normal file
50
src/layout/index.vue
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<div class="home-container">
|
||||
<el-container>
|
||||
<el-header>
|
||||
<QHeader></QHeader>
|
||||
</el-header>
|
||||
<el-container>
|
||||
<el-aside>
|
||||
<QAside @update:open-dialog="handleOpenDialog"></QAside>
|
||||
</el-aside>
|
||||
<el-main>
|
||||
<router-view></router-view>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
<QDialog :openDialog="openDialog"></QDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue"
|
||||
import QAside from "./components/aside/index.vue"
|
||||
import QHeader from "./components/header/index.vue"
|
||||
import QDialog from "./components/dialog/index.vue"
|
||||
const openDialog = ref(false)
|
||||
|
||||
const handleOpenDialog = (isOpen) => {
|
||||
openDialog.value = isOpen
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.el-header {
|
||||
width: 100%;
|
||||
height: 115px;
|
||||
padding: 0;
|
||||
}
|
||||
.el-main {
|
||||
padding: 0 0;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.el-aside {
|
||||
height: 96.6vh;
|
||||
overflow: visible;
|
||||
color: aliceblue;
|
||||
font-family: Arial, sans-serif;
|
||||
margin-left: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,35 +1,59 @@
|
|||
import { createRouter, createWebHistory } from "vue-router";
|
||||
// 导入组件,这里先占位
|
||||
const KeyNodeRecognition2 = () => import("@/views/KeyNodeRecognition1/index.vue");
|
||||
const KeyNodeRecognition3 = () => import("@/views/KeyNodeRecognition2/index.vue");
|
||||
const KeyNodeRecognition1 = () => import("@/views/KeyNodeRecognition3/index.vue");
|
||||
const LinkPrediction1 = () => import("@/views/LinkPrediction/characterInteraction/index.vue");
|
||||
const LinkPrediction2 = () => import("@/views/LinkPrediction/socialGroups/index.vue");
|
||||
const LinkPrediction3 = () =>
|
||||
import("@/views/LinkPrediction/charactersHiddenInteraction/index.vue");
|
||||
|
||||
const GroupEvolution1 = () => import("@/views/GroupEvolution/groupIdentifyDiscovery/index.vue");
|
||||
const GroupEvolution2 = () => import("@/views/GroupEvolution/groupStructure/index.vue");
|
||||
const GroupEvolution3 = () => import("@/views/GroupEvolution/groupMember/index.vue");
|
||||
const GroupEvolution4 = () => import("@/views/GroupEvolution/abnormalGroup/index.vue");
|
||||
import { createRouter, createWebHistory } from "vue-router"
|
||||
|
||||
const routes = [
|
||||
{ path: "/", redirect: "/home" },
|
||||
{
|
||||
path: "/home",
|
||||
component: () => import("@/layout/index.vue"),
|
||||
children: [
|
||||
{ path: "/", redirect: "/key-node-1" },
|
||||
{ path: "/key-node-3", component: KeyNodeRecognition3 },
|
||||
{ path: "/key-node-2", component: KeyNodeRecognition2 },
|
||||
{ path: "/key-node-1", component: KeyNodeRecognition1 },
|
||||
{ path: "/link-prediction-1", component: LinkPrediction1 },
|
||||
{ path: "/link-prediction-2", component: LinkPrediction2 },
|
||||
{ path: "/link-prediction-3", component: LinkPrediction3 },
|
||||
{ path: "/group-evolution-1", component: GroupEvolution1 },
|
||||
{ path: "/group-evolution-2", component: GroupEvolution2 },
|
||||
{ path: "/group-evolution-3", component: GroupEvolution3 },
|
||||
{ path: "/group-evolution-4", component: GroupEvolution4 }
|
||||
];
|
||||
{
|
||||
path: "/key-node-1",
|
||||
component: () => import("@/views/KeyNodeDiscern/anchorRecommendation/index.vue")
|
||||
},
|
||||
{
|
||||
path: "/key-node-2",
|
||||
component: () => import("@/views/KeyNodeDiscern/opinionLeader/index.vue")
|
||||
},
|
||||
{
|
||||
path: "/key-node-3",
|
||||
component: () => import("@/views/KeyNodeDiscern/bridgeCommunication/index.vue")
|
||||
},
|
||||
{
|
||||
path: "/link-prediction-1",
|
||||
component: () => import("@/views/LinkPrediction/characterInteraction/index.vue")
|
||||
},
|
||||
{
|
||||
path: "/link-prediction-2",
|
||||
component: () => import("@/views/LinkPrediction/socialGroups/index.vue")
|
||||
},
|
||||
{
|
||||
path: "/link-prediction-3",
|
||||
component: () => import("@/views/LinkPrediction/charactersHiddenInteraction/index.vue")
|
||||
},
|
||||
{
|
||||
path: "/group-evolution-1",
|
||||
component: () => import("@/views/GroupEvolution/groupIdentifyDiscovery/index.vue")
|
||||
},
|
||||
{
|
||||
path: "/group-evolution-2",
|
||||
component: () => import("@/views/GroupEvolution/groupStructure/index.vue")
|
||||
},
|
||||
{
|
||||
path: "/group-evolution-3",
|
||||
component: () => import("@/views/GroupEvolution/groupMember/index.vue")
|
||||
},
|
||||
{
|
||||
path: "/group-evolution-4",
|
||||
component: () => import("@/views/GroupEvolution/abnormalGroup/index.vue")
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
});
|
||||
})
|
||||
|
||||
export default router;
|
||||
export default router
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ const defaultConfig = {
|
|||
borderWidth: 5,
|
||||
borderColor: "100,250,100",
|
||||
showShadow: true, // 是否展示阴影
|
||||
shadowBlur: 5, //阴影范围大小
|
||||
shadowBlur: 10, //阴影范围大小
|
||||
shadowColor: "50,250,30" // 选中是的阴影颜色
|
||||
}
|
||||
},
|
||||
|
|
@ -137,6 +137,8 @@ const highLightAboutNodesOrLinks = (type) => {
|
|||
const { newNodes, newLinks } = graph.value
|
||||
if (type == "nodes") {
|
||||
//实现高亮节点逻辑
|
||||
console.log(graphVis.nodes)
|
||||
|
||||
graphVis.nodes.forEach((node) =>
|
||||
newNodes.forEach((newNode) => {
|
||||
if (node.id === newNode.name) {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
<div class="content">
|
||||
<!-- Title Image: using a placeholder as the local asset is not available -->
|
||||
<img
|
||||
src="../../../assets/images/chuanbo-show-title.png"
|
||||
src="@/assets/images/chuanbo-show-title.png"
|
||||
class="title-img"
|
||||
style="margin-top: -22px; margin-left: -24px"
|
||||
/>
|
||||
|
|
@ -58,7 +58,12 @@
|
|||
<div v-for="chart in chartData" :key="chart.id" class="chart-section">
|
||||
<!-- Section Title -->
|
||||
<div class="section-title">
|
||||
<img src="../../../assets/images/icon/qiaolianganalysisicon.png" alt="" style="" class="icon"/>
|
||||
<img
|
||||
src="@/assets/images/icon/qiaolianganalysisicon.png"
|
||||
alt=""
|
||||
style=""
|
||||
class="icon"
|
||||
/>
|
||||
<span>{{ chart.title }}</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -83,7 +88,15 @@
|
|||
:class="row.type"
|
||||
:style="{ width: (row.value / chart.max) * 100 + '%' }"
|
||||
></div>
|
||||
<span class="value" :class="{ highlight: row.highlight, 'value-leader': row.type === 'leader', 'value-user': row.type === 'user' }">{{ row.value }}</span>
|
||||
<span
|
||||
class="value"
|
||||
:class="{
|
||||
highlight: row.highlight,
|
||||
'value-leader': row.type === 'leader',
|
||||
'value-user': row.type === 'user'
|
||||
}"
|
||||
>{{ row.value }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<!-- X-Axis Labels -->
|
||||
|
|
@ -100,7 +113,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ref } from "vue"
|
||||
|
||||
const chartData = ref([
|
||||
{
|
||||
|
|
@ -133,7 +146,7 @@ const chartData = ref([
|
|||
{ label: "其他节点", value: 120, type: "user" }
|
||||
]
|
||||
}
|
||||
]);
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
@ -208,7 +221,7 @@ const chartData = ref([
|
|||
justify-content: space-around;
|
||||
padding-right: 15px;
|
||||
font-size: 14px;
|
||||
color: #94C1EC;
|
||||
color: #94c1ec;
|
||||
text-align: right;
|
||||
height: 70px;
|
||||
flex-shrink: 0;
|
||||
|
|
@ -281,11 +294,11 @@ const chartData = ref([
|
|||
}
|
||||
|
||||
.value-leader {
|
||||
color: #2AB8FD;
|
||||
color: #2ab8fd;
|
||||
}
|
||||
|
||||
.value-user {
|
||||
color: #34DFF2;
|
||||
color: #34dff2;
|
||||
}
|
||||
|
||||
.x-axis-labels {
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="left-panel">
|
||||
<img
|
||||
src="../../../assets/images/chuanbo_account_list.png"
|
||||
src="@/assets/images/chuanbo_account_list.png"
|
||||
alt=""
|
||||
class="headerImage"
|
||||
style="margin-top: -22px; margin-left: -15px"
|
||||
|
|
@ -50,32 +50,36 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, nextTick, defineEmits } from 'vue';
|
||||
import { useKeyNodeStore2 } from '@/store/keyNodeStore2';
|
||||
import { ref, computed, watch, nextTick, defineEmits } from "vue"
|
||||
import { useKeyNodeStore2 } from "@/store/keyNodeStore2"
|
||||
|
||||
const emit = defineEmits(['selectLeader']);
|
||||
const store = useKeyNodeStore2();
|
||||
const emit = defineEmits(["selectLeader"])
|
||||
const store = useKeyNodeStore2()
|
||||
|
||||
const leaderListRef = ref(null);
|
||||
const tabs = ref(["全部", "新闻媒体", "自媒体", "政府官号"]);
|
||||
const activeTab = ref("全部");
|
||||
const leaderListRef = ref(null)
|
||||
const tabs = ref(["全部", "新闻媒体", "自媒体", "政府官号"])
|
||||
const activeTab = ref("全部")
|
||||
|
||||
const filteredVisibleLeaders = computed(() => {
|
||||
if (activeTab.value === "全部") {
|
||||
return store.visibleLeaders;
|
||||
return store.visibleLeaders
|
||||
}
|
||||
return store.visibleLeaders.filter((leader) => leader.category === activeTab.value);
|
||||
});
|
||||
return store.visibleLeaders.filter((leader) => leader.category === activeTab.value)
|
||||
})
|
||||
|
||||
watch(filteredVisibleLeaders, async () => {
|
||||
await nextTick();
|
||||
watch(
|
||||
filteredVisibleLeaders,
|
||||
async () => {
|
||||
await nextTick()
|
||||
if (leaderListRef.value) {
|
||||
leaderListRef.value.scrollTo({
|
||||
top: leaderListRef.value.scrollHeight,
|
||||
behavior: "smooth"
|
||||
});
|
||||
})
|
||||
}
|
||||
}, { deep: true });
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
@ -39,68 +39,67 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import { useKeyNodeStore2 } from "@/store/keyNodeStore2";
|
||||
import { ref, onMounted, onUnmounted } from "vue"
|
||||
import { useKeyNodeStore2 } from "@/store/keyNodeStore2"
|
||||
|
||||
import LeaderList from "./components/LeaderList.vue";
|
||||
import GraphPanel from "./components/GraphPanel.vue";
|
||||
import DetailsModal from "./components/DetailsModal.vue";
|
||||
import LeaderDetailDialog from "./components/LeaderDetailDialog.vue";
|
||||
import PostDetailDialog from "./components/PostDetailDialog.vue";
|
||||
import LeaderList from "./components/LeaderList.vue"
|
||||
import GraphPanel from "./components/GraphPanel.vue"
|
||||
import DetailsModal from "./components/DetailsModal.vue"
|
||||
import LeaderDetailDialog from "./components/LeaderDetailDialog.vue"
|
||||
import PostDetailDialog from "./components/PostDetailDialog.vue"
|
||||
|
||||
import LeaderAnalysis from "./components/LeaderAnalysis.vue";
|
||||
import EventHeatmap from "../../components/weight/EventHeatmap.vue";
|
||||
import PostDynamics from "../../components/weight/PostDynamics.vue";
|
||||
import WordCloud from "../../components/weight/WordCloud.vue";
|
||||
import LeaderAnalysis from "./components/LeaderAnalysis.vue"
|
||||
import EventHeatmap from "../../../components/weight/EventHeatmap.vue"
|
||||
import PostDynamics from "../../../components/weight/PostDynamics.vue"
|
||||
import WordCloud from "../../../components/weight/WordCloud.vue"
|
||||
|
||||
const store = useKeyNodeStore2();
|
||||
const graphPanelRef = ref(null);
|
||||
const store = useKeyNodeStore2()
|
||||
const graphPanelRef = ref(null)
|
||||
// 添加 activeChartTab 状态---用于判断在事件热度图弹窗显示的图表类型
|
||||
const activeChartTab = ref('trend'); // 默认值设为 'trend'
|
||||
const activeChartTab = ref("trend") // 默认值设为 'trend'
|
||||
const handleLeaderSelect = (leader) => {
|
||||
console.log("选中的领袖ID:", leader);
|
||||
console.log("选中的领袖ID:", leader)
|
||||
if (graphPanelRef.value && leader.id) {
|
||||
graphPanelRef.value.highlightNode(leader.id);
|
||||
graphPanelRef.value.highlightNode(leader.id)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleShowDetails = (chartConfig, tab) => {
|
||||
store.openDetailsModal(chartConfig);
|
||||
activeChartTab.value = tab;
|
||||
console.log("图表数据类型:",activeChartTab.value);
|
||||
|
||||
};
|
||||
store.openDetailsModal(chartConfig)
|
||||
activeChartTab.value = tab
|
||||
console.log("图表数据类型:", activeChartTab.value)
|
||||
}
|
||||
|
||||
const handleOpenPostDialog = (post) => {
|
||||
store.openPostDetail(post);
|
||||
};
|
||||
|
||||
let timer = null;
|
||||
const automaticPlay = () => {
|
||||
let index = 1;
|
||||
if (timer) clearInterval(timer);
|
||||
timer = setInterval(() => {
|
||||
store.setActiveTimePoint(index);
|
||||
if (index >= store.allLeaderData.length) {
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
return;
|
||||
store.openPostDetail(post)
|
||||
}
|
||||
|
||||
let timer = null
|
||||
const automaticPlay = () => {
|
||||
let index = 1
|
||||
if (timer) clearInterval(timer)
|
||||
timer = setInterval(() => {
|
||||
store.setActiveTimePoint(index)
|
||||
if (index >= store.allLeaderData.length) {
|
||||
clearInterval(timer)
|
||||
timer = null
|
||||
return
|
||||
}
|
||||
index++
|
||||
}, 1500)
|
||||
}
|
||||
index++;
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
// 调用 store.initializeTimePoints() 初始化时间点
|
||||
onMounted(() => {
|
||||
store.initializeTimePoints();
|
||||
automaticPlay();
|
||||
});
|
||||
store.initializeTimePoints()
|
||||
automaticPlay()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer);
|
||||
clearInterval(timer)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
const analysisChartData = ref([
|
||||
{
|
||||
|
|
@ -130,7 +129,7 @@ const analysisChartData = ref([
|
|||
{ name: "所有用户", value: 0.46 }
|
||||
]
|
||||
}
|
||||
]);
|
||||
])
|
||||
|
||||
const wordCloudData = ref([
|
||||
{
|
||||
|
|
@ -265,7 +264,7 @@ const wordCloudData = ref([
|
|||
fontSize: 16,
|
||||
opacity: 1
|
||||
}
|
||||
]);
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
@ -59,7 +59,12 @@
|
|||
<div v-for="chart in chartData" :key="chart.id" class="chart-section">
|
||||
<!-- Section Title -->
|
||||
<div class="section-title">
|
||||
<img src="../../../assets/images/icon/qiaolianganalysisicon.png" alt="" style="" class="icon"/>
|
||||
<img
|
||||
src="@/assets/images/icon/qiaolianganalysisicon.png"
|
||||
alt=""
|
||||
style=""
|
||||
class="icon"
|
||||
/>
|
||||
<span>{{ chart.title }}</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -84,7 +89,15 @@
|
|||
:class="row.type"
|
||||
:style="{ width: (row.value / chart.max) * 100 + '%' }"
|
||||
></div>
|
||||
<span class="value" :class="{ highlight: row.highlight, 'value-leader': row.type === 'leader', 'value-user': row.type === 'user' }">{{ row.value }}</span>
|
||||
<span
|
||||
class="value"
|
||||
:class="{
|
||||
highlight: row.highlight,
|
||||
'value-leader': row.type === 'leader',
|
||||
'value-user': row.type === 'user'
|
||||
}"
|
||||
>{{ row.value }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<!-- X-Axis Labels -->
|
||||
|
|
@ -101,7 +114,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ref } from "vue"
|
||||
|
||||
const chartData = ref([
|
||||
{
|
||||
|
|
@ -134,7 +147,7 @@ const chartData = ref([
|
|||
{ label: "所有用户", value: 1.31, type: "user" }
|
||||
]
|
||||
}
|
||||
]);
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
@ -281,11 +294,11 @@ const chartData = ref([
|
|||
}
|
||||
|
||||
.value-leader {
|
||||
color: #2AB8FD;
|
||||
color: #2ab8fd;
|
||||
}
|
||||
|
||||
.value-user {
|
||||
color: #34DFF2;
|
||||
color: #34dff2;
|
||||
}
|
||||
|
||||
.x-axis-labels {
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="left-panel">
|
||||
<img
|
||||
src="../../../assets/images/leaderTitle.png"
|
||||
src="@/assets/images/leaderTitle.png"
|
||||
alt=""
|
||||
class="headerImage"
|
||||
style="margin-top: -22px; margin-left: -15px"
|
||||
|
|
@ -50,32 +50,36 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, nextTick, defineEmits } from 'vue';
|
||||
import { useKeyNodeStore1 } from '@/store/keyNodeStore1';
|
||||
import { ref, computed, watch, nextTick, defineEmits } from "vue"
|
||||
import { useKeyNodeStore1 } from "@/store/keyNodeStore1"
|
||||
|
||||
const emit = defineEmits(['selectLeader']);
|
||||
const store = useKeyNodeStore1();
|
||||
const emit = defineEmits(["selectLeader"])
|
||||
const store = useKeyNodeStore1()
|
||||
|
||||
const leaderListRef = ref(null);
|
||||
const tabs = ref(["全部", "新闻媒体", "自媒体", "政府官号"]);
|
||||
const activeTab = ref("全部");
|
||||
const leaderListRef = ref(null)
|
||||
const tabs = ref(["全部", "新闻媒体", "自媒体", "政府官号"])
|
||||
const activeTab = ref("全部")
|
||||
|
||||
const filteredVisibleLeaders = computed(() => {
|
||||
if (activeTab.value === "全部") {
|
||||
return store.visibleLeaders;
|
||||
return store.visibleLeaders
|
||||
}
|
||||
return store.visibleLeaders.filter((leader) => leader.category === activeTab.value);
|
||||
});
|
||||
return store.visibleLeaders.filter((leader) => leader.category === activeTab.value)
|
||||
})
|
||||
|
||||
watch(filteredVisibleLeaders, async () => {
|
||||
await nextTick();
|
||||
watch(
|
||||
filteredVisibleLeaders,
|
||||
async () => {
|
||||
await nextTick()
|
||||
if (leaderListRef.value) {
|
||||
leaderListRef.value.scrollTo({
|
||||
top: leaderListRef.value.scrollHeight,
|
||||
behavior: "smooth"
|
||||
});
|
||||
})
|
||||
}
|
||||
}, { deep: true });
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
@ -47,66 +47,66 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import { useKeyNodeStore1 } from "@/store/keyNodeStore1";
|
||||
import { ref, onMounted, onUnmounted } from "vue"
|
||||
import { useKeyNodeStore1 } from "@/store/keyNodeStore1"
|
||||
|
||||
import LeaderList from "./components/LeaderList.vue";
|
||||
import GraphPanel from "./components/GraphPanel.vue";
|
||||
import DetailsModal from "./components/DetailsModal.vue";
|
||||
import LeaderDetailDialog from "./components/LeaderDetailDialog.vue";
|
||||
import PostDetailDialog from "./components/PostDetailDialog.vue";
|
||||
import LeaderList from "./components/LeaderList.vue"
|
||||
import GraphPanel from "./components/GraphPanel.vue"
|
||||
import DetailsModal from "./components/DetailsModal.vue"
|
||||
import LeaderDetailDialog from "./components/LeaderDetailDialog.vue"
|
||||
import PostDetailDialog from "./components/PostDetailDialog.vue"
|
||||
|
||||
import LeaderAnalysis from "./components/LeaderAnalysis.vue";
|
||||
import EventHeatmap from "../../components/weight/EventHeatmap.vue";
|
||||
import PostDynamics from "../../components/weight/PostDynamics.vue";
|
||||
import WordCloud from "../../components/weight/WordCloud.vue";
|
||||
import LeaderAnalysis from "./components/LeaderAnalysis.vue"
|
||||
import EventHeatmap from "../../../components/weight/EventHeatmap.vue"
|
||||
import PostDynamics from "../../../components/weight/PostDynamics.vue"
|
||||
import WordCloud from "../../../components/weight/WordCloud.vue"
|
||||
|
||||
const store = useKeyNodeStore1();
|
||||
const graphPanelRef = ref(null);
|
||||
const store = useKeyNodeStore1()
|
||||
const graphPanelRef = ref(null)
|
||||
// 添加 activeChartTab 状态---用于判断在事件热度图弹窗显示的图表类型
|
||||
const activeChartTab = ref('trend'); // 默认值设为 'trend'
|
||||
const activeChartTab = ref("trend") // 默认值设为 'trend'
|
||||
|
||||
const handleLeaderSelect = (leader) => {
|
||||
if (graphPanelRef.value && leader.id) {
|
||||
graphPanelRef.value.highlightNode(leader.id);
|
||||
graphPanelRef.value.highlightNode(leader.id)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleShowDetails = (chartConfig, tab) => {
|
||||
store.openDetailsModal(chartConfig);
|
||||
activeChartTab.value = tab;
|
||||
console.log("图表数据类型:",activeChartTab.value);
|
||||
};
|
||||
store.openDetailsModal(chartConfig)
|
||||
activeChartTab.value = tab
|
||||
console.log("图表数据类型:", activeChartTab.value)
|
||||
}
|
||||
|
||||
const handleOpenPostDialog = (post) => {
|
||||
store.openPostDetail(post);
|
||||
};
|
||||
|
||||
let timer = null;
|
||||
const automaticPlay = () => {
|
||||
let index = 1;
|
||||
if (timer) clearInterval(timer);
|
||||
timer = setInterval(() => {
|
||||
store.setActiveTimePoint(index);
|
||||
if (index >= store.allLeaderData.length) {
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
return;
|
||||
store.openPostDetail(post)
|
||||
}
|
||||
|
||||
let timer = null
|
||||
const automaticPlay = () => {
|
||||
let index = 1
|
||||
if (timer) clearInterval(timer)
|
||||
timer = setInterval(() => {
|
||||
store.setActiveTimePoint(index)
|
||||
if (index >= store.allLeaderData.length) {
|
||||
clearInterval(timer)
|
||||
timer = null
|
||||
return
|
||||
}
|
||||
index++
|
||||
}, 1500)
|
||||
}
|
||||
index++;
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
store.initializeTimePoints();
|
||||
automaticPlay();
|
||||
});
|
||||
store.initializeTimePoints()
|
||||
automaticPlay()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer);
|
||||
clearInterval(timer)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
const analysisChartData = ref([
|
||||
{
|
||||
|
|
@ -136,7 +136,7 @@ const analysisChartData = ref([
|
|||
{ name: "所有用户", value: 0.46 }
|
||||
]
|
||||
}
|
||||
]);
|
||||
])
|
||||
|
||||
const wordCloudData = ref([
|
||||
{
|
||||
|
|
@ -210,7 +210,7 @@ const wordCloudData = ref([
|
|||
{ text: "领土", top: 57.5, left: 72.5, width: 49, height: 19, fontSize: 12, opacity: 0.6 },
|
||||
{ text: "原则", top: 77.5, left: 264.5, width: 49, height: 19, fontSize: 12, opacity: 0.7 },
|
||||
{ text: "台湾", top: 195.5, left: 287.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 }
|
||||
]);
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
Loading…
Reference in New Issue
Block a user