配置前端工程化,模块化,组件化,调整项目目录,文件名等
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: "/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: "/", redirect: "/home" },
 | 
			
		||||
  {
 | 
			
		||||
    path: "/home",
 | 
			
		||||
    component: () => import("@/layout/index.vue"),
 | 
			
		||||
    children: [
 | 
			
		||||
      { path: "/", redirect: "/key-node-1" },
 | 
			
		||||
      {
 | 
			
		||||
        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();
 | 
			
		||||
  if (leaderListRef.value) {
 | 
			
		||||
    leaderListRef.value.scrollTo({
 | 
			
		||||
      top: leaderListRef.value.scrollHeight,
 | 
			
		||||
      behavior: "smooth"
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}, { deep: true });
 | 
			
		||||
watch(
 | 
			
		||||
  filteredVisibleLeaders,
 | 
			
		||||
  async () => {
 | 
			
		||||
    await nextTick()
 | 
			
		||||
    if (leaderListRef.value) {
 | 
			
		||||
      leaderListRef.value.scrollTo({
 | 
			
		||||
        top: leaderListRef.value.scrollHeight,
 | 
			
		||||
        behavior: "smooth"
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  { deep: true }
 | 
			
		||||
)
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="less">
 | 
			
		||||
| 
						 | 
				
			
			@ -200,4 +204,4 @@ watch(filteredVisibleLeaders, async () => {
 | 
			
		|||
  width: 100px; /* 固定宽度确保对齐 */
 | 
			
		||||
  justify-content: flex-start; /* 内容靠左对齐 */
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
  // 添加 activeChartTab 状态---用于判断在事件热度图弹窗显示的图表类型
 | 
			
		||||
const activeChartTab = ref('trend'); // 默认值设为 'trend'
 | 
			
		||||
const store = useKeyNodeStore2()
 | 
			
		||||
const graphPanelRef = ref(null)
 | 
			
		||||
// 添加 activeChartTab 状态---用于判断在事件热度图弹窗显示的图表类型
 | 
			
		||||
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);
 | 
			
		||||
};
 | 
			
		||||
  store.openPostDetail(post)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let timer = null;
 | 
			
		||||
let timer = null
 | 
			
		||||
const automaticPlay = () => {
 | 
			
		||||
  let index = 1;
 | 
			
		||||
  if (timer) clearInterval(timer);
 | 
			
		||||
  let index = 1
 | 
			
		||||
  if (timer) clearInterval(timer)
 | 
			
		||||
  timer = setInterval(() => {
 | 
			
		||||
    store.setActiveTimePoint(index);
 | 
			
		||||
    store.setActiveTimePoint(index)
 | 
			
		||||
    if (index >= store.allLeaderData.length) {
 | 
			
		||||
      clearInterval(timer);
 | 
			
		||||
      timer = null;
 | 
			
		||||
      return;
 | 
			
		||||
      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();
 | 
			
		||||
  if (leaderListRef.value) {
 | 
			
		||||
    leaderListRef.value.scrollTo({
 | 
			
		||||
      top: leaderListRef.value.scrollHeight,
 | 
			
		||||
      behavior: "smooth"
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}, { deep: true });
 | 
			
		||||
watch(
 | 
			
		||||
  filteredVisibleLeaders,
 | 
			
		||||
  async () => {
 | 
			
		||||
    await nextTick()
 | 
			
		||||
    if (leaderListRef.value) {
 | 
			
		||||
      leaderListRef.value.scrollTo({
 | 
			
		||||
        top: leaderListRef.value.scrollHeight,
 | 
			
		||||
        behavior: "smooth"
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  { deep: true }
 | 
			
		||||
)
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="less">
 | 
			
		||||
| 
						 | 
				
			
			@ -200,4 +204,4 @@ watch(filteredVisibleLeaders, async () => {
 | 
			
		|||
  width: 100px; /* 固定宽度确保对齐 */
 | 
			
		||||
  justify-content: flex-start; /* 内容靠左对齐 */
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -40,73 +40,73 @@
 | 
			
		|||
      <WordCloud :wordsCloudList="wordCloudData" />
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <DetailsModal :activeChartTab="activeChartTab"/>
 | 
			
		||||
    <DetailsModal :activeChartTab="activeChartTab" />
 | 
			
		||||
    <LeaderDetailDialog />
 | 
			
		||||
    <PostDetailDialog />
 | 
			
		||||
  </div>
 | 
			
		||||
</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);
 | 
			
		||||
};
 | 
			
		||||
  store.openPostDetail(post)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let timer = null;
 | 
			
		||||
let timer = null
 | 
			
		||||
const automaticPlay = () => {
 | 
			
		||||
  let index = 1;
 | 
			
		||||
  if (timer) clearInterval(timer);
 | 
			
		||||
  let index = 1
 | 
			
		||||
  if (timer) clearInterval(timer)
 | 
			
		||||
  timer = setInterval(() => {
 | 
			
		||||
    store.setActiveTimePoint(index);
 | 
			
		||||
    store.setActiveTimePoint(index)
 | 
			
		||||
    if (index >= store.allLeaderData.length) {
 | 
			
		||||
      clearInterval(timer);
 | 
			
		||||
      timer = null;
 | 
			
		||||
      return;
 | 
			
		||||
      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