1100 lines
29 KiB
Vue
1100 lines
29 KiB
Vue
<template>
|
||
<div class="keyNodeOne-container">
|
||
<!-- 1. 顶部介绍图片 -->
|
||
<div>
|
||
<img src="../assets/images/head/chuanbo.png" alt="系统介绍" class="intruduction" />
|
||
</div>
|
||
|
||
<!-- 2. 第一行布局容器 (布局不变) -->
|
||
<div class="leader-containner1">
|
||
<!-- 区域1: 意见领袖列表 -->
|
||
<div class="left-panel">
|
||
<img
|
||
src="../assets/images/leaderTitle.png"
|
||
alt=""
|
||
style="margin-top: -22px; margin-left: -15px"
|
||
/>
|
||
<div class="tabs">
|
||
<button
|
||
v-for="tab in tabs"
|
||
:key="tab"
|
||
:class="{ active: activeTab === tab }"
|
||
@click="activeTab = tab"
|
||
>
|
||
{{ tab }}
|
||
</button>
|
||
</div>
|
||
<div class="leader-list" ref="leaderListRef">
|
||
<div
|
||
v-for="leader in filteredVisibleLeaders"
|
||
:key="leader.id"
|
||
class="leader-item"
|
||
@click="handleLeaderHighLight(leader)"
|
||
>
|
||
<img :src="leader.avatar" :alt="leader.name" class="avatar" />
|
||
<div class="info">
|
||
<div class="name">
|
||
<span class="en-name">{{ leader.name }}</span>
|
||
<span v-if="leader.chineseName" class="cn-name">{{ leader.chineseName }}</span>
|
||
</div>
|
||
<div class="stats">
|
||
<span>粉丝数量: {{ leader.followers }}</span>
|
||
<span>发帖总数: {{ leader.posts }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 区域2: 佩洛西图谱 (视觉效果已更新) -->
|
||
<div class="right-panel">
|
||
<div class="key-node-recognition">
|
||
<div class="background-svg-wrapper">
|
||
<svg
|
||
width="100%"
|
||
height="100%"
|
||
viewBox="0 0 800 540"
|
||
preserveAspectRatio="none"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
>
|
||
<defs>
|
||
<linearGradient
|
||
id="paint0_linear_bg"
|
||
x1="0"
|
||
y1="167.1"
|
||
x2="800"
|
||
y2="167.1"
|
||
gradientUnits="userSpaceOnUse"
|
||
>
|
||
<stop stop-color="#063D71" stop-opacity="0.2" />
|
||
<stop offset="1" stop-color="#081E38" stop-opacity="0.8" />
|
||
</linearGradient>
|
||
<linearGradient
|
||
id="paint1_linear_border"
|
||
x1="400"
|
||
y1="0"
|
||
x2="400"
|
||
y2="540"
|
||
gradientUnits="userSpaceOnUse"
|
||
>
|
||
<stop stop-color="#3AA1F8" />
|
||
<stop offset="1" stop-color="#3AA1F8" stop-opacity="0.2" />
|
||
</linearGradient>
|
||
</defs>
|
||
<path
|
||
d="M798 0.5H2C1.17159 0.5 0.500003 1.17158 0.5 2V538C0.5 538.828 1.17159 539.5 2 539.5H798C798.828 539.5 799.5 538.828 799.5 538V2C799.5 1.17157 798.828 0.5 798 0.5Z"
|
||
fill="url(#paint0_linear_bg)"
|
||
fill-opacity="0.48"
|
||
stroke="url(#paint1_linear_border)"
|
||
/>
|
||
</svg>
|
||
</div>
|
||
<div class="content-wrapper">
|
||
<img
|
||
src="../assets/images/graphTitle.png"
|
||
alt=""
|
||
style="margin-top: -15px; margin-left: -15px"
|
||
/>
|
||
<div class="chart-container">
|
||
<dynamicGraph
|
||
ref="leaderGraphRef"
|
||
:timestamp="activeTimePoint"
|
||
@handle:openDialog="handleOpen"
|
||
:allLeaderData="allLeaderData"
|
||
></dynamicGraph>
|
||
</div>
|
||
<div class="timeline-container">
|
||
<span class="time-label">2022.07.31 00:00:00</span>
|
||
<div class="timeline-track">
|
||
<div
|
||
v-for="point in timePoints"
|
||
:key="point.id"
|
||
class="timeline-point-wrapper"
|
||
@click="onTimePointClick(point.id)"
|
||
>
|
||
<el-tooltip
|
||
class="timePoint-box-item"
|
||
effect="light"
|
||
:content="point.timestamp"
|
||
placement="bottom"
|
||
>
|
||
<div class="timeline-point" :class="{ active: activeTimePoint === point.id }">
|
||
<el-popover
|
||
v-if="activeTimePoint === point.id"
|
||
effect="dark"
|
||
placement="top"
|
||
:title="point.leaderId"
|
||
:width="50"
|
||
trigger="click"
|
||
content="发布贴文"
|
||
>
|
||
<template #reference>
|
||
<div class="active-pin"></div>
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</el-tooltip>
|
||
</div>
|
||
</div>
|
||
<span class="time-label">2022.08.01 00:00:00</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 区域3: 领袖分析 -->
|
||
<LeaderAnalysis :chart-data="analysisChartData" />
|
||
</div>
|
||
|
||
<!-- 第二行布局容器 (布局不变) -->
|
||
<div class="leader-containner2">
|
||
<EventHeatmap
|
||
@show-details="openDetailsModal"
|
||
:panelTrendData="[32655, 29182, 55732, 1051]"
|
||
:panelXAxisLabels="['2022.7.31', '2022.8.1', '2022.8.2', '2022.8.3']"
|
||
:granularTrendData="[
|
||
8959, 7460, 8334, 7902, 5753, 3070, 3481, 16878, 17819, 15296, 18883, 3734, 938, 101, 12
|
||
]"
|
||
:granularXAxisLabels="[
|
||
'7.31 00h',
|
||
'7.31 06h',
|
||
'7.31 12h',
|
||
'7.31 18h',
|
||
'8.1 00h',
|
||
'8.1 06h',
|
||
'8.1 12h',
|
||
'8.1 18h',
|
||
'8.2 00h',
|
||
'8.2 06h',
|
||
'8.2 12h',
|
||
'8.2 18h',
|
||
'8.3 00h',
|
||
'8.3 06h',
|
||
'8.3 12h'
|
||
]"
|
||
/>
|
||
<PostDynamics :posts="posts" @handle:openDialog="handleLeaderPost" />
|
||
<WordCloud :wordsCloudList="wordCloudData" />
|
||
</div>
|
||
|
||
<!-- 详情弹窗 -->
|
||
<div v-if="showDetailsModal" class="modal-overlay" @click="closeDetailsModal">
|
||
<div class="modal-content" @click.stop>
|
||
<button class="close-btn" @click="closeDetailsModal">×</button>
|
||
<div ref="detailsChart" class="details-chart-container"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<el-dialog
|
||
v-model="leaderDetailDialog"
|
||
width="500"
|
||
align-center
|
||
class="custom-leader-detail-dialog"
|
||
>
|
||
<img src="../assets/images/leaderDialogTitle.png" alt="" class="dialogTitleImg" />
|
||
<div class="dialog-content">
|
||
<div class="dialog-content-leaderInfo">
|
||
<img class="leaderInfo-avatar" :src="activeLeader.leaderOriginInfo.avatar" alt="" />
|
||
<div class="leaderInfo-message">
|
||
<div class="leader-name">{{ activeLeader.name }}</div>
|
||
<div class="leader-heat">
|
||
<div class="fancy">
|
||
粉丝量: {{ activeLeader.leaderOriginInfo.followers }}
|
||
</div>
|
||
<div class="post-number">
|
||
发帖数: {{ activeLeader.leaderOriginInfo.posts }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="dialog-content-post">
|
||
<!-- <img src="../assets/images/leaderPostTitle.png" alt="" class="post-title" /> -->
|
||
<div class="leader-post-detail-content">
|
||
<div
|
||
class="content-item"
|
||
v-for="item in activeLeader.leaderOriginInfo.labelling"
|
||
:key="item.id"
|
||
>
|
||
<div class="item-type">{{ item.type }}</div>
|
||
<div class="item-content">
|
||
{{ item.content }}
|
||
</div>
|
||
<div class="item-heat">
|
||
<div class="item-time">{{ item.time }}</div>
|
||
<div class="item-heat-detail">
|
||
<div class="item-heat-like">
|
||
<Icon icon="ei:like" width="25" height="25" /> {{ item.like }}
|
||
</div>
|
||
<div class="item-heat-comment">
|
||
<Icon icon="la:comment-dots" width="25" height="25" /> {{ item.comment }}
|
||
</div>
|
||
<div class="item-heat-transmit">
|
||
<Icon icon="mdi:share-outline" width="25" height="25" /> {{
|
||
item.transmit
|
||
}}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="dialog-content-heat-degree">
|
||
<div class="heat-item">
|
||
<p class="diamond"></p>
|
||
粉丝数量: {{ activeLeader.leaderOriginInfo.followers }}
|
||
</div>
|
||
<div class="heat-item">
|
||
<p class="diamond"></p>
|
||
关注数量: 1329
|
||
</div>
|
||
<div class="heat-item">
|
||
<p class="diamond"></p>
|
||
发帖总数: {{ activeLeader.leaderOriginInfo.posts }}
|
||
</div>
|
||
<div class="heat-item">
|
||
<p class="diamond"></p>
|
||
贴文被转总数: 1329
|
||
</div>
|
||
<div class="heat-item">
|
||
<p class="diamond"></p>
|
||
参与互动次数: 30
|
||
</div>
|
||
<div class="heat-item">
|
||
<p class="diamond"></p>
|
||
首次活跃事件: 2022.7.31 00:14
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog
|
||
v-model="leaderPostDialog"
|
||
width="500"
|
||
align-center
|
||
class="custom-leader-post-dialog"
|
||
>
|
||
<img src="../assets/images/head/post-dialog-title.png" alt="" class="postTitleImage" />
|
||
<div class="dialog-content">
|
||
<div class="content">{{ currentPost.content }}</div>
|
||
<div class="heat">
|
||
<div class="item-heat-detail">
|
||
<div class="item-heat-like">
|
||
<Icon icon="ei:like" width="25" height="25" /> {{ currentPost.like }}
|
||
</div>
|
||
<div class="item-heat-comment">
|
||
<Icon icon="la:comment-dots" width="25" height="25" /> {{ currentPost.comment }}
|
||
</div>
|
||
<div class="item-heat-transmit">
|
||
<Icon icon="mdi:share-outline" width="25" height="25" /> {{
|
||
currentPost.transmit
|
||
}}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, nextTick, computed, watch } from "vue";
|
||
import * as echarts from "echarts/core";
|
||
import { GraphChart } from "echarts/charts";
|
||
import { TitleComponent, TooltipComponent } from "echarts/components";
|
||
import { SVGRenderer } from "echarts/renderers";
|
||
echarts.use([TitleComponent, TooltipComponent, GraphChart, SVGRenderer]);
|
||
// 引入其他子组件
|
||
import LeaderAnalysis from "../components/weight/LeaderAnalysis.vue";
|
||
import EventHeatmap from "../components/weight/EventHeatmap.vue";
|
||
import PostDynamics from "../components/weight/PostDynamics.vue";
|
||
import WordCloud from "../components/weight/WordCloud.vue";
|
||
import dynamicGraph from "../components/graph/dynamicGraph.vue";
|
||
import { Icon } from "@iconify/vue";
|
||
// ===================================================================
|
||
// 核心状态与数据
|
||
// ===================================================================
|
||
const activeTimePoint = ref(1);
|
||
const timePoints = ref([]);
|
||
const leaderDetailDialog = ref(false);
|
||
const leaderPostDialog = ref(false);
|
||
const leaderListRef = ref(null);
|
||
//点击任意一个领导后,保存该领导数据为了显示弹窗详细信息
|
||
const activeLeader = ref({});
|
||
|
||
|
||
|
||
//当前选中的贴文
|
||
const currentPost = ref({});
|
||
//贴文数据
|
||
const posts = ref([
|
||
{
|
||
id: 1,
|
||
timestamp: "2022.07.31 00:52:43",
|
||
author: "Hu Xijin 胡锡进",
|
||
influence: 5292,
|
||
highlighted: false,
|
||
like: 2827,
|
||
comment: 1350,
|
||
transmit: 1115,
|
||
content:
|
||
"If Pelosi really visits Taiwan as planned, the Tsai Ing-wen authorities are accomplice. The mainland will definitely carry out severe punishment actions on Taiwan at the same time. The unbearable consequences will fall on Tsai authorities."
|
||
},
|
||
{
|
||
id: 2,
|
||
timestamp: "2022-07-31 01:26:23",
|
||
author: "Levi Godman",
|
||
influence: 6919,
|
||
like: 5354,
|
||
comment: 155,
|
||
transmit: 1410,
|
||
highlighted: false,
|
||
content: "BREAKING : Pelosi seen flying over Taiwan https://t.co/VQdm88KVeU"
|
||
},
|
||
{
|
||
id: 3,
|
||
timestamp: "2022-07-31 02:24:23",
|
||
author: "bidishalolo",
|
||
influence: 6636,
|
||
highlighted: false,
|
||
like: 5013,
|
||
comment: 247,
|
||
transmit: 1376,
|
||
content:
|
||
"BREAKING: #Pelosi seen flying over #Taiwan. Stunning footage... https://t.co/8AOJ6yMPvl"
|
||
},
|
||
{
|
||
id: 4,
|
||
timestamp: "2022-07-31 10:53:51",
|
||
author: "Indo-Pacific News",
|
||
influence: 545,
|
||
highlighted: false,
|
||
like: 5013,
|
||
comment: 247,
|
||
transmit: 1376,
|
||
content:
|
||
'#China Is Issuing The Same "Red Line" Warnings About #Taiwan That Russia Issued About Ukraine.Pelosi pours gasoline on the foreign policy dumpster fire with her visit to Taiwan. The #CCP is big on not losing face, this one is for real, careful......'
|
||
},
|
||
{
|
||
id: 5,
|
||
timestamp: "2022-07-31 13:57:12",
|
||
author: "The Spectator Index",
|
||
influence: 8345,
|
||
highlighted: false,
|
||
like: 6238,
|
||
comment: 409,
|
||
transmit: 1698,
|
||
content:
|
||
"BREAKING: Press release by US House Speaker Pelosi lists she will visit Singapore, Malaysia, South Korea and Japan on upcoming trip, without mention of Taiwan."
|
||
},
|
||
{
|
||
id: 6,
|
||
timestamp: "2022-07-31 15:10:08",
|
||
author: "Reuters",
|
||
influence: 557,
|
||
highlighted: false,
|
||
like: 1786,
|
||
comment: 362,
|
||
transmit: 741,
|
||
content: "U.S House Speaker Pelosi to visit Asia, no mention of Taiwan."
|
||
},
|
||
{
|
||
id: 7,
|
||
timestamp: "2022-7-31 16:11:53",
|
||
author: "Mick Wallace",
|
||
influence: 2473,
|
||
highlighted: false,
|
||
like: 1923,
|
||
comment: 124,
|
||
transmit: 426,
|
||
content:
|
||
"As if the Warmongering #Pelosi hasn't done enough damage, it seems she's arrived in Taiwan already on her latest War promotion..."
|
||
},
|
||
{
|
||
id: 8,
|
||
timestamp: "2022-07-31 16:12:49",
|
||
author: "Jiushiniya",
|
||
influence: 8,
|
||
highlighted: false,
|
||
like: 1923,
|
||
comment: 124,
|
||
transmit: 426,
|
||
content:
|
||
"@Dr_Mo2019 蓬佩奥在媒体上说拜登政府要有战略战术,说白了川普政府如果有战略战术,就不会有hk沦陷乌克兰战争台海危机三战川普也可能不会滚下台,蓬佩奥今天还用的着蹭佩洛西访台?蓬佩奥就直接自己率团去台湾了。川普支持蓬佩奥的话,今天就不会有佩洛西什么事,如果拜登软弱的话,今天更不会有佩洛西什么事。 https://t.co/g8VQLWoKRA"
|
||
},
|
||
{
|
||
id: 9,
|
||
timestamp: "2022-07-31 17:19:13",
|
||
author: "刘晓明",
|
||
influence: 6919,
|
||
highlighted: false,
|
||
like: 1923,
|
||
comment: 124,
|
||
transmit: 426,
|
||
content:
|
||
"澳大利亚前总理保罗·基廷日前发表个人声明,公开谴责美国会众议长佩洛西拟访台的行为,称佩洛西此访无论基于任何理由都将会是愚蠢、危险且不必要的。如果对两岸形势判断错误或处理不当,将给台湾地区乃至全世界的安全、繁荣和秩序造成灾难性后果。我们希望美方能听进去理性的声音。"
|
||
},
|
||
{
|
||
id: 10,
|
||
timestamp: "2022-07-31 18:03:18",
|
||
author: "Indobosss",
|
||
influence: 6636,
|
||
like: 1310,
|
||
comment: 60,
|
||
transmit: 300,
|
||
highlighted: false,
|
||
content: "usa chickened out 😂🤣🙃🤪 https://t.co/ZlchyKtAur"
|
||
}
|
||
]);
|
||
|
||
const leaderGraphRef = ref(null);
|
||
const visibleLeaders = computed(() => allLeaderData.value.slice(0, activeTimePoint.value));
|
||
const tabs = ref(["全部", "新闻媒体", "自媒体", "政府官号"]);
|
||
const activeTab = ref("全部");
|
||
const filteredVisibleLeaders = computed(() => {
|
||
if (activeTab.value === "全部") return visibleLeaders.value;
|
||
return visibleLeaders.value.filter((leader) => leader.category === activeTab.value);
|
||
});
|
||
|
||
//初始化时间轴(根据allLeaderData数据的来)
|
||
const initTimePoint = () => {
|
||
if (timePoints.value.length != 0) return;
|
||
const timePointList = [];
|
||
allLeaderData.value.forEach((item, index) => {
|
||
timePointList.push({
|
||
id: index + 1,
|
||
leaderId: item.id,
|
||
timestamp: posts.value[index].timestamp
|
||
});
|
||
});
|
||
timePoints.value = timePointList;
|
||
};
|
||
|
||
//当时间轴改变时,意见领袖数量展示超过了可视区域时,应该让可视区域平滑滚动到最下方
|
||
watch(filteredVisibleLeaders, async () => {
|
||
await nextTick();
|
||
if (leaderListRef.value) {
|
||
leaderListRef.value.scrollTo({
|
||
top: leaderListRef.value.scrollHeight,
|
||
behavior: "smooth" // 平滑滚动
|
||
});
|
||
}
|
||
});
|
||
//点击意见领袖展示的任意一个领导
|
||
const handleLeaderHighLight = (leader) => {
|
||
if (leaderGraphRef.value && leader.id) {
|
||
leaderGraphRef.value.highlightNode(leader.id); // 调用子组件暴露的方法
|
||
}
|
||
};
|
||
|
||
// 时间轴变化点击事件
|
||
const onTimePointClick = (pointId) => {
|
||
activeTimePoint.value = pointId;
|
||
};
|
||
|
||
// ===================================================================
|
||
// 其他组件的数据和逻辑
|
||
// ===================================================================
|
||
const analysisChartData = ref([
|
||
{
|
||
title: "平均发帖数",
|
||
unit: "数量",
|
||
max: 10,
|
||
series: [
|
||
{ name: "领袖", value: 6.4 },
|
||
{ name: "所有用户", value: 0.46 }
|
||
]
|
||
},
|
||
{
|
||
title: "帖子平均生存周期",
|
||
unit: "天数",
|
||
max: 10,
|
||
series: [
|
||
{ name: "领袖", value: 2.19 },
|
||
{ name: "所有用户", value: 0.46 }
|
||
]
|
||
},
|
||
{
|
||
title: "平均粉丝数",
|
||
unit: "天数",
|
||
max: 10,
|
||
series: [
|
||
{ name: "领袖", value: 2.19 },
|
||
{ name: "所有用户", value: 0.46 }
|
||
]
|
||
}
|
||
]);
|
||
const wordCloudData = ref([
|
||
{
|
||
text: "佩洛西",
|
||
top: 115.5,
|
||
left: 215.5,
|
||
width: 109,
|
||
height: 40,
|
||
fontSize: 28,
|
||
opacity: 1
|
||
},
|
||
{ text: "中国", top: 183.5, left: 69.5, width: 73, height: 35, fontSize: 22, opacity: 1 },
|
||
{
|
||
text: "中国人民解放军",
|
||
top: 72.5,
|
||
left: 132.5,
|
||
width: 123,
|
||
height: 22,
|
||
fontSize: 12,
|
||
opacity: 1
|
||
},
|
||
{
|
||
text: "中美关系",
|
||
top: 171.5,
|
||
left: 212.5,
|
||
width: 81,
|
||
height: 22,
|
||
fontSize: 14,
|
||
opacity: 0.8
|
||
},
|
||
{ text: "台独", top: 135.5, left: 42.5, width: 57, height: 24, fontSize: 16, opacity: 1 },
|
||
{
|
||
text: "台海和平",
|
||
top: 228.5,
|
||
left: 230.5,
|
||
width: 81,
|
||
height: 22,
|
||
fontSize: 14,
|
||
opacity: 0.8
|
||
},
|
||
{
|
||
text: "坚决反对",
|
||
top: 233.5,
|
||
left: 38.5,
|
||
width: 73,
|
||
height: 19,
|
||
fontSize: 12,
|
||
opacity: 0.7
|
||
},
|
||
{
|
||
text: "联合公报",
|
||
top: 241.5,
|
||
left: 130.5,
|
||
width: 73,
|
||
height: 19,
|
||
fontSize: 12,
|
||
opacity: 0.7
|
||
},
|
||
{
|
||
text: "有力反制",
|
||
top: 211.5,
|
||
left: 143.5,
|
||
width: 73,
|
||
height: 19,
|
||
fontSize: 12,
|
||
opacity: 1
|
||
},
|
||
{ text: "白宫", top: 176.5, left: 15.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 },
|
||
{ text: "内政", top: 87.5, left: 36.5, width: 53, height: 22, fontSize: 14, opacity: 1 },
|
||
{ text: "访台", top: 103.5, left: 95.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 },
|
||
{ 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 }
|
||
]);
|
||
const showDetailsModal = ref(false);
|
||
const detailsChart = ref(null);
|
||
let myDetailsChart = null;
|
||
const openDetailsModal = (chartConfig) => {
|
||
showDetailsModal.value = true;
|
||
nextTick(() => {
|
||
if (detailsChart.value) {
|
||
myDetailsChart = echarts.init(detailsChart.value);
|
||
myDetailsChart.setOption(chartConfig.option);
|
||
}
|
||
});
|
||
};
|
||
const closeDetailsModal = () => {
|
||
showDetailsModal.value = false;
|
||
if (myDetailsChart) {
|
||
myDetailsChart.dispose();
|
||
myDetailsChart = null;
|
||
}
|
||
};
|
||
//页面启动自动播放
|
||
let timer = null;
|
||
const automaticPlay = () => {
|
||
let index = 1;
|
||
if (timer) clearInterval(timer);
|
||
timer = setInterval(() => {
|
||
onTimePointClick(index);
|
||
if (index == allLeaderData.value.length) {
|
||
clearInterval(timer);
|
||
timer = null;
|
||
return;
|
||
}
|
||
index++;
|
||
}, 1500);
|
||
};
|
||
const handleOpen = (e) => {
|
||
activeLeader.value = e;
|
||
leaderDetailDialog.value = true;
|
||
console.log(e);
|
||
};
|
||
const handleLeaderPost = (item) => {
|
||
currentPost.value = item;
|
||
leaderPostDialog.value = true;
|
||
};
|
||
// ===================================================================
|
||
// 生命周期钩子
|
||
// ===================================================================
|
||
onMounted(() => {
|
||
initTimePoint();
|
||
automaticPlay();
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.keyNodeOne-container{
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
.intruduction {
|
||
width: 100%;
|
||
margin-top: 0px;
|
||
border-radius: 2px;
|
||
}
|
||
.leader-containner1,
|
||
.leader-containner2 {
|
||
display: flex;
|
||
flex-direction: row;
|
||
gap: 10px;
|
||
}
|
||
.leader-containner2 {
|
||
margin-top: 10px;
|
||
}
|
||
.left-panel {
|
||
width: 350px;
|
||
flex-shrink: 0;
|
||
background-color: rgba(6, 45, 90, 0.3);
|
||
border: 1px solid #1a8bff;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 15px;
|
||
}
|
||
.panel-title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
text-align: center;
|
||
padding: 10px;
|
||
margin: 0 0 15px 0;
|
||
background: linear-gradient(
|
||
to right,
|
||
rgba(58, 161, 248, 0),
|
||
rgba(58, 161, 248, 0.3),
|
||
rgba(58, 161, 248, 0)
|
||
);
|
||
border-top: 1px solid #3aa1f8;
|
||
border-bottom: 1px solid #3aa1f8;
|
||
color: #fff;
|
||
}
|
||
.tabs {
|
||
display: flex;
|
||
margin-bottom: 15px;
|
||
border-bottom: 2px solid #1a5a9c;
|
||
}
|
||
.tabs button {
|
||
background: none;
|
||
border: none;
|
||
color: #a9c2e0;
|
||
padding: 8px 16px;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
position: relative;
|
||
}
|
||
.tabs button.active {
|
||
color: #fff;
|
||
font-weight: bold;
|
||
}
|
||
.tabs button.active::after {
|
||
content: "";
|
||
position: absolute;
|
||
bottom: -2px;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 2px;
|
||
background-color: #3aa1f8;
|
||
}
|
||
.leader-list {
|
||
width: 100%;
|
||
height: 310px;
|
||
flex-grow: 1;
|
||
overflow: auto;
|
||
scrollbar-width: none;
|
||
color: #fff;
|
||
}
|
||
.leader-list::-webkit-scrollbar {
|
||
width: 4px;
|
||
}
|
||
.leader-list::-webkit-scrollbar-track {
|
||
background: transparent;
|
||
}
|
||
.leader-list::-webkit-scrollbar-thumb {
|
||
background: #3aa1f8;
|
||
border-radius: 2px;
|
||
}
|
||
.leader-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 10px 5px;
|
||
border-bottom: 1px solid rgba(58, 161, 248, 0.2);
|
||
cursor: pointer;
|
||
}
|
||
.avatar {
|
||
width: 50px;
|
||
height: 50px;
|
||
border-radius: 50%;
|
||
margin-right: 15px;
|
||
flex-shrink: 0;
|
||
}
|
||
.info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 5px;
|
||
}
|
||
.name {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 8px;
|
||
}
|
||
.en-name {
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
}
|
||
.cn-name {
|
||
font-size: 14px;
|
||
color: #a9c2e0;
|
||
}
|
||
.stats {
|
||
font-size: 12px;
|
||
color: #a9c2e0;
|
||
display: flex;
|
||
gap: 20px;
|
||
}
|
||
.right-panel {
|
||
flex-grow: 1;
|
||
position: relative;
|
||
}
|
||
.key-node-recognition {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
.background-svg-wrapper {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: 1;
|
||
}
|
||
.content-wrapper {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
padding: 15px 20px;
|
||
box-sizing: border-box;
|
||
}
|
||
.graph-title {
|
||
text-align: center;
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
color: #cce7ff;
|
||
letter-spacing: 2px;
|
||
margin: 0 0 5px 0;
|
||
text-shadow: 0 0 5px rgba(58, 161, 248, 0.5);
|
||
}
|
||
.chart-container {
|
||
flex-grow: 1;
|
||
width: 100%;
|
||
height: calc(100% - 100px);
|
||
}
|
||
.timeline-container {
|
||
width: 100%;
|
||
height: 50px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 10px;
|
||
box-sizing: border-box;
|
||
background-color: rgba(4, 67, 92, 0.6); /* 80%不透明度 */
|
||
border-radius: 5px;
|
||
z-index: 1;
|
||
}
|
||
.time-label {
|
||
font-size: 12px;
|
||
color: #a9c2e0;
|
||
}
|
||
.timeline-track {
|
||
flex-grow: 1;
|
||
height: 4px;
|
||
background: linear-gradient(90deg, #1b62a9, #3aa1f8, #1b62a9);
|
||
margin: 0 15px;
|
||
position: relative;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
.timeline-point-wrapper {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 20px;
|
||
cursor: pointer;
|
||
}
|
||
.timeline-point {
|
||
width: 10px;
|
||
height: 10px;
|
||
background-color: #8dc5ff;
|
||
border-radius: 50%;
|
||
border: 1px solid #cce7ff;
|
||
transition: transform 0.3s ease;
|
||
position: relative;
|
||
}
|
||
.timeline-point-wrapper:hover .timeline-point {
|
||
transform: scale(1.5);
|
||
}
|
||
.timeline-point.active {
|
||
background-color: #ffc94d;
|
||
border-color: #fff;
|
||
transform: scale(1.3);
|
||
}
|
||
.timePoint-box-item {
|
||
color: #fff !important;
|
||
}
|
||
.active-pin {
|
||
width: 30px;
|
||
height: 34px;
|
||
background-image: url("../assets/images/point.png");
|
||
background-size: cover;
|
||
bottom: 5px;
|
||
left: -11px;
|
||
position: absolute;
|
||
}
|
||
.active-leader-info {
|
||
width: 20px;
|
||
height: 30px;
|
||
bottom: 10px;
|
||
left: -11px;
|
||
position: absolute;
|
||
background-color: #1a8bff;
|
||
}
|
||
.modal-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: rgba(0, 0, 0, 0.7);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 1000;
|
||
}
|
||
.modal-content {
|
||
position: relative;
|
||
background-color: #0d1b38;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
border: 1px solid #3a95ff;
|
||
box-shadow: 0 0 25px rgba(58, 149, 255, 0.5);
|
||
width: 50vw;
|
||
height: 45vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.close-btn {
|
||
position: absolute;
|
||
width: 20px;
|
||
height: 20px;
|
||
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
top: 10px;
|
||
right: 15px;
|
||
border: none;
|
||
color: #a7c5d4;
|
||
background: none;
|
||
font-size: 24px;
|
||
cursor: pointer;
|
||
}
|
||
.details-chart-container {
|
||
width: 100%;
|
||
flex-grow: 1;
|
||
}
|
||
:deep(.custom-leader-detail-dialog) {
|
||
width: 640px;
|
||
height: 680px;
|
||
border-width: 0px, 0px, 0px, 0px;
|
||
border-style: solid;
|
||
border-image-source: linear-gradient(180deg, #3aa1f8 0%, rgba(58, 161, 248, 0.2) 100%);
|
||
background-color: rgba(6, 45, 90, 1);
|
||
border: 1px solid #1a8bff;
|
||
border-radius: 2px;
|
||
padding: 0 0;
|
||
z-index: 1;
|
||
}
|
||
.dialogTitleImg {
|
||
margin-top: -23px;
|
||
}
|
||
:deep(.custom-leader-detail-dialog) .dialog-content {
|
||
width: 100%;
|
||
height: 100%;
|
||
|
||
padding: 23px 23px;
|
||
}
|
||
.dialog-content-leaderInfo {
|
||
width: 100%;
|
||
height: 70px;
|
||
|
||
display: flex;
|
||
}
|
||
.leaderInfo-avatar {
|
||
width: 70px;
|
||
height: 70px;
|
||
border-radius: 5px;
|
||
}
|
||
.leaderInfo-message {
|
||
flex: 1;
|
||
height: 100%;
|
||
|
||
padding-left: 15px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
.leader-name {
|
||
font-size: 20px;
|
||
color: #fff;
|
||
}
|
||
.leader-heat {
|
||
display: flex;
|
||
color: #fff;
|
||
font-size: 16px;
|
||
}
|
||
.post-number {
|
||
margin-left: 30px;
|
||
}
|
||
.dialog-content-post {
|
||
width: 100%;
|
||
padding: 25px 0px;
|
||
}
|
||
.leader-post-detail-content {
|
||
width: 100%;
|
||
background:
|
||
linear-gradient(0deg, #0d2743, #0d2743),
|
||
linear-gradient(270deg, rgba(147, 210, 255, 0.06) 0%, rgba(147, 210, 255, 0.16) 100%);
|
||
|
||
height: 340px;
|
||
overflow: auto;
|
||
padding: 10px 20px;
|
||
}
|
||
/* 滚动条整体样式 - WebKit浏览器 */
|
||
.leader-post-detail-content::-webkit-scrollbar {
|
||
width: 5px; /* 垂直滚动条宽度 */
|
||
height: 5px; /* 水平滚动条高度 */
|
||
}
|
||
|
||
/* 滚动条滑块 */
|
||
.leader-post-detail-content::-webkit-scrollbar-thumb {
|
||
background: rgba(147, 210, 255, 0.3); /* 蓝色半透明滑块 */
|
||
border-radius: 4px;
|
||
}
|
||
|
||
/* 鼠标悬停在滑块上的效果 */
|
||
.leader-post-detail-content::-webkit-scrollbar-thumb:hover {
|
||
background: rgba(147, 210, 255, 0.5); /* 更明显的蓝色 */
|
||
}
|
||
.post-title {
|
||
width: 100%;
|
||
height: 36px;
|
||
}
|
||
|
||
.item-type {
|
||
font-size: 16px;
|
||
color: #ffffff;
|
||
}
|
||
.item-content {
|
||
color: #ffffffcc;
|
||
font-size: 16px;
|
||
}
|
||
.content-item div {
|
||
margin-bottom: 10px;
|
||
}
|
||
.item-heat {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
color: #ffffffcc;
|
||
}
|
||
.item-heat-detail {
|
||
display: flex;
|
||
}
|
||
.item-heat-detail div {
|
||
width: 60px;
|
||
margin-right: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.dialog-content-heat-degree {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
row-gap: 15px;
|
||
color: #fff;
|
||
font-size: 16px;
|
||
}
|
||
.heat-item {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.heat-item .diamond {
|
||
width: 6px;
|
||
height: 6px;
|
||
background-color: #fff;
|
||
margin-right: 10px;
|
||
box-shadow: 0 4px 8px rgb(0, 123, 255);
|
||
}
|
||
:deep(.custom-leader-post-dialog) {
|
||
width: 640px;
|
||
height: 215px;
|
||
border-width: 0px, 0px, 0px, 0px;
|
||
border-style: solid;
|
||
border-image-source: linear-gradient(180deg, #3aa1f8 0%, rgba(58, 161, 248, 0.2) 100%);
|
||
background-color: rgba(6, 45, 90, 1);
|
||
border: 1px solid #1a8bff;
|
||
border-radius: 2px;
|
||
padding: 0 0;
|
||
z-index: 1;
|
||
}
|
||
:deep(.custom-leader-post-dialog) .dialog-content {
|
||
width: 100%;
|
||
padding: 25px 25px;
|
||
}
|
||
.content {
|
||
color: #fff;
|
||
opacity: 0.7;
|
||
}
|
||
.heat {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
margin-top: 20px;
|
||
}
|
||
.heat .item-heat-detail div {
|
||
color: #fff;
|
||
opacity: 0.7;
|
||
}
|
||
.postTitleImage {
|
||
margin-top: -24px;
|
||
margin-left: -2px;
|
||
}
|
||
</style>
|