3,4模块绘制

This commit is contained in:
duanhao 2025-08-04 17:40:17 +08:00
parent d698bb5f4f
commit 794d1dce90
11 changed files with 577 additions and 42 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -684,6 +684,65 @@ export const useGroupStructureStore = defineStore("groupStructure", {
export const useGroupMemberStore = defineStore("groupMember", { export const useGroupMemberStore = defineStore("groupMember", {
state: () => ({ state: () => ({
groupList: [
{
id: 1,
type: "群体一",
focusedTopic: "#中国海警首次登检菲律宾#",
series: [
{
type: "radar",
data: [
{
value: [10, 5, 15, 5],
symbol: 'circle',
symbolSize: 5,
itemStyle: {
color: '#01D7DA', // 圆点颜色
},
areaStyle: {
color: 'rgba(87, 196, 255, 0.3)' // 区域填充
},
// 点之间的连线
lineStyle: {
color: '#0374FE',
type: 'dashed',
width: 1
}
}
]
}
]
},
{
id: 2,
type: "群体二",
focusedTopic: "#中国海警首次登检菲律宾#",
series: [
{
type: "radar",
data: [
{
value: [10, 20, 15, 5],
symbol: 'circle',
symbolSize: 5,
itemStyle: {
color: '#01D7DA', // 圆点颜色
},
areaStyle: {
color: 'rgba(87, 196, 255, 0.3)' // 区域填充
},
lineStyle: {
color: '#0374FE',
type: 'dashed',
width: 1
}
}
]
}
]
}
],
groupMemberList: [ groupMemberList: [
{ {
id: 1, id: 1,
@ -706,6 +765,79 @@ export const useGroupMemberStore = defineStore("groupMember", {
] ]
}, },
], ],
chartData: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 25, interval: 5},
seriesList: [
{
name: "分裂指数",
type: "line",
lineStyle: {
color: "#2AB8FD",
width: 1 // 设置线条宽度为3像素
},
itemStyle: {
color: '#0A1A2F',
borderColor: '#2AB8FD',
borderWidth: 1
},
symbol: "circle",
symbolSize: 10, // 圆点大小
data: [0.9237, 0.14507, 0, 0, 0]
},
{
name: "合并指数",
type: "line",
lineStyle: {
color: "#02D7DA",
width: 1 // 设置线条宽度为3像素
},
itemStyle: {
color: '#0A1A2F',
borderColor: '#01D7DA',
borderWidth: 1
},
symbol: "circle",
symbolSize: 10, // 圆点大小
borderWidth: 1, // 边框宽度
data: [9.8011, 21.3123, 10.4338, 14.1912, 10.1523]
},
{
name: "收缩指数",
type: "line",
lineStyle: {
color: "#FFDA09",
width: 1 // 设置线条宽度为3像素
},
itemStyle: {
color: '#0A1A2F',
borderColor: '#FFDA09',
borderWidth: 1
},
symbol: "circle",
symbolSize: 10, // 圆点大小
borderWidth: 1, // 边框宽度
data: [1.9057, 1.5123, 1.0338, 0.5912, 0.1523]
},
{
name: "扩展指数",
type: "line",
lineStyle: {
color: "#EB57B0",
width: 1 // 设置线条宽度为3像素
},
itemStyle: {
color: '#0A1A2F',
borderColor: '#EB57B0',
borderWidth: 1
},
symbol: "circle",
symbolSize: 10, // 圆点大小
borderWidth: 1, // 边框宽度
data: [15.1119, 6.5123, 10.6338, 9.5912, 4.1523]
}
]
},
chartsData: { chartsData: {
topSelfMedia: [ topSelfMedia: [
{ {
@ -1213,7 +1345,72 @@ export const useAnomalousGroup = defineStore("anomalousGroup", {
commentCount: 100, commentCount: 100,
// 转发数 // 转发数
shareCount: 6890 shareCount: 6890
},
{
id: 2,
// 评论人
commenter: {
userId: "1",
userName: "Trump-Good",
userAvatar: defaultAvatar
},
// 评论接收人
commentRecipient: {
userId: "2",
userName: "疾风中青劲草",
userAvatar: defaultAvatar
},
//
mutualCommentCount: 3,
// 评论内容
content: "在我国海域偷运軍械彈藥是應該依法拘捕送交法院睿理判刑,而且在中国的裹服刑的!难道外国人特权?更何况是這千点小国!#中国海警首次登检菲律宾运补船只# #外交部回应中国海警缴获菲士兵枪支#",
// 点赞数
likeCount: "4.8w",
// 评论数
commentCount: 100,
// 转发数
shareCount: 6890
} }
] ],
chartData: {
xAxisData: ["t0", "t1", "t2", "t3", "t4", "t5", "t6"],
yAxisRange: { min: 0, max: 5, interval: 1},
seriesList: [
{
name: "社团组一",
type: "bar",
itemStyle: {
color: '#2AB8FD',
borderColor: '#2AB8FD',
borderWidth: 1,
borderRadius: [4, 4, 0, 0] // 顶部圆角
},
data: [0, 5, 4, 3, 0, 5, 0]
},
{
name: "社团组二",
type: "bar",
itemStyle: {
color: '#02D7DA',
borderColor: '#02D7DA',
borderWidth: 1,
borderRadius: [4, 4, 0, 0] // 顶部圆角
},
data: [3, 0, 1, 0, 3, 5, 0 ]
},
{
name: "社团组三",
type: "bar",
itemStyle: {
color: '#FFDA09',
borderColor: '#FFDA09',
borderWidth: 1,
borderRadius: [4, 4, 0, 0] // 顶部圆角
},
data: [5, 0, 4, 0, 3, 0, 0]
}
]
},
}) })
}) })

View File

@ -30,9 +30,25 @@
</div> </div>
</div> </div>
<!-- 评论的内容 --> <!-- 评论的内容 -->
<div class="content-item-comment"> <div class="commit-item">
<!-- <div class="post-content">{{ content.commentContent }}</div> --> <div class="commit-content"><div class="commit-content-text">{{ content.content }}</div></div>
</div> <div class="commit-statistic">
<div class="like-item">
<!-- D:\CodeProject\SocialNetworks_duan\src\assets\images\icon\like_icon.png -->
<img src="@/assets/images/icon/like_icon.png" alt="">
<div class="like-count">{{ content.likeCount }}</div>
</div>
<div class="comment-num-item">
<!-- D:\CodeProject\SocialNetworks_duan\src\assets\images\icon\comment_icon.png -->
<img src="@/assets/images/icon/commit_icon.png" alt="">
<div class="comment-count">{{ content.commentCount }}</div>
</div>
<div class="transmit-item">
<img src="@/assets/images/icon/transmit_icon.png" alt="">
<div class="transmit-count">{{ content.shareCount }}</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -52,15 +68,15 @@ const props = defineProps({
.anomalousContent-component { .anomalousContent-component {
width: 100%; width: 100%;
height: 100%; height: 100%;
.title { .anomalousContent-list {
margin-top: -7px;
}
.content-item {
width: 100%; width: 100%;
margin-left: 24px; height: 500px;
padding-bottom: 20px; overflow: auto;
border-bottom: 0.5px solid rgba(0, 113, 188, 0.5); .content-item {
.content-item-title { width: 100%;
padding-left: 24px;
padding-bottom: 20px;
.content-item-title {
position: relative; position: relative;
.content-item-title-icon { .content-item-title-icon {
width: 160px; width: 160px;
@ -72,28 +88,97 @@ const props = defineProps({
left: 12px; left: 12px;
font-size: 14px; font-size: 14px;
} }
} }
.content-item-users { .content-item-users {
display: flex;
.user-item {
display: flex; display: flex;
align-items: center; .user-item {
margin-top: 16px; display: flex;
margin-right: 40px; align-items: center;
.user-avatar { margin-top: 16px;
width: 20px; padding-right: 20px;
height: 20px; .user-avatar {
margin-right: 6px; width: 20px;
height: 20px;
margin-right: 6px;
}
.user-name {
font-family: "PingFang SC";
color: #fff;
font-size: 16px;
font-style: Bold;
font-weight: 400;
}
} }
.user-name { }
font-family: "PingFang SC"; .commit-item {
color: #fff; margin-top: 14px;
font-size: 16px; padding-bottom: 12px;
font-style: Bold; width: 304px;
font-weight: 400; height: 100%;
color: #fff;
font-family: PingFang SC;
font-weight: 400;
font-style: Regular;
font-size: 14px;
background: linear-gradient(0deg, rgba(13, 39, 67, 0.66), rgba(13, 39, 67, 0.66)),
linear-gradient(270deg, rgba(147, 210, 255, 0.06) 0%, rgba(147, 210, 255, 0.16) 100%);
.commit-content {
width: 284px;
margin-left: 10px;
padding-top: 12px;
padding-bottom: 8px;
}
.commit-statistic {
display: flex;
padding-left: 10px;
padding-right: 10px;
.like-item {
display: flex;
align-items: center;
margin-right: 20px;
.like-count {
margin-left: 8px;
}
} }
.comment-num-item {
display: flex;
align-items: center;
margin-right: 16px;
.comment-count {
margin-left: 8px;
}
}
.transmit-item {
display: flex;
align-items: center;
.transmit-count {
margin-left: 8px;
}
}
}
} }
} }
} }
/* 滚动条整体样式 - WebKit浏览器 */
.anomalousContent-list::-webkit-scrollbar {
width: 5px; /* 垂直滚动条宽度 */
height: 5px; /* 水平滚动条高度 */
}
/* 滚动条滑块 */
.anomalousContent-list::-webkit-scrollbar-thumb {
background: rgba(147, 210, 255, 0.3); /* 蓝色半透明滑块 */
border-radius: 4px;
}
/* 鼠标悬停在滑块上的效果 */
.anomalousContent-list::-webkit-scrollbar-thumb:hover {
background: rgba(147, 210, 255, 0.5); /* 更明显的蓝色 */
}
.title {
margin-top: -7px;
}
} }
</style> </style>

View File

@ -1,10 +1,18 @@
<template> <template>
<div class="layout-container"> <div class="layout-container">
<div class="top-container"></div> <div class="top-container">
</div>
<div class="content"> <div class="content">
<div class="left-container"> <div class="left-container">
<div class="userPanel"></div> <div class="userPanel"></div>
<div class="userChart"></div> <div class="userChart">
<GroupChart
:title="userChartTitleImg"
:moduleName="moduleName"
:chartData="anomalousGroupStore.chartData"
></GroupChart>
</div>
</div> </div>
<div class="middle-container"> <div class="middle-container">
<div class="graph"></div> <div class="graph"></div>
@ -46,13 +54,15 @@
<script setup> <script setup>
import { ref } from "vue"; import { ref } from "vue";
import GroupChart from "../component/groupChart.vue";
import userChartTitleImg from "@/assets/images/abnormalGroup/abnormal-group-hudo-time-chart.png"
import { Icon } from "@iconify/vue"; import { Icon } from "@iconify/vue";
import WordsCloud from "../component/wordsCloud.vue" import WordsCloud from "../component/wordsCloud.vue"
import AnomalousContentInfo from "./components/anomalousContentInfo.vue" import AnomalousContentInfo from "./components/anomalousContentInfo.vue"
import { useAnomalousGroup } from "@/store/groupEvolution/index"; import { useAnomalousGroup } from "@/store/groupEvolution/index";
const anomalousGroupStore = useAnomalousGroup(); const anomalousGroupStore = useAnomalousGroup();
const moduleName = "全局异常互动时刻表"
// //
const postDialog = ref(false); const postDialog = ref(false);

View File

@ -33,6 +33,10 @@ const props = defineProps({
chartName: { chartName: {
type: String, type: String,
default: "" default: ""
},
moduleName: {
type: String,
default: ""
} }
}); });
@ -95,10 +99,16 @@ const initChart = () => {
}, },
legend: { legend: {
data: legendData, data: legendData,
right: 10, // 10px itemStyle: {
top: 13, // color: "#fff"
},
right: 5, // 10px
top: 15,
itemWidth: 10, //
itemHeight: 10, //
textStyle: { textStyle: {
color: "#fff" color: "#fff",
fontSize: 12
} }
}, },
tooltip: { tooltip: {
@ -108,11 +118,43 @@ const initChart = () => {
borderWidth: 0, borderWidth: 0,
extraCssText: "box-shadow:none;padding:0;", extraCssText: "box-shadow:none;padding:0;",
formatter: function (params) { formatter: function (params) {
const color = { let color = {
头部自媒体: "#33b6fb", 头部自媒体: "#33b6fb",
官方媒体: "#00d6da", 官方媒体: "#00d6da",
普通自媒体: "#fddc33" 普通自媒体: "#fddc33"
}; };
// 使
switch(props.moduleName) {
case "全局群体成员演化图":
color = {
分裂总数: "#2AB8FD",
合并总数: "#02D7DA",
收缩指数: "#FFDA09",
扩展指数: "#EB57B0"
}
break;
case "群体规模演化图":
color = {
头部自媒体: "#33b6fb",
官方媒体: "#00d6da",
普通自媒体: "#fddc33"
}
break;
case "全局异常互动时刻表":
color = {
社团组一: "#2AB8FD",
社团组二: "#02D7DA",
社团组三: "#FFDA09"
}
break;
default:
color = {
头部自媒体: "#33b6fb",
官方媒体: "#00d6da",
普通自媒体: "#fddc33"
}
}
const listHtml = params const listHtml = params
.map( .map(
(item) => ` (item) => `
@ -242,7 +284,7 @@ onBeforeUnmount(() => {
font-weight: 400; font-weight: 400;
} }
.container { .container {
top: -15px; top: -19px;
width: 100%; width: 100%;
height: 180px; height: 180px;
} }

View File

@ -12,6 +12,7 @@
<div class="userChart"> <div class="userChart">
<GroupChart <GroupChart
:title="groupChartTitleImg" :title="groupChartTitleImg"
:moduleName="群体规模演化图"
:chartData="groupDiscoveryStore.chartData" :chartData="groupDiscoveryStore.chartData"
></GroupChart> ></GroupChart>
</div> </div>

View File

@ -0,0 +1,178 @@
<template>
<div class="groupPanel-component">
<img :src="title" alt="" class="title" />
<div class="groupPanel-list">
<div class="group-item" v-for="group in groupList" :key="group.id">
<div class="group-item-title">
<img
class="group-item-title-icon"
src="@/assets/images/linkPrediction/title/group-item-title.png"
alt=""
/>
<div class="group-item-title-type">{{ group.type }}</div>
</div>
<div class="group-item-statistics">
<div class="statistics-title">关注话题{{ group.focusedTopic }}</div>
<div class="container" :id="`group-chart-${group.id}`"></div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { defineProps, ref, onMounted, onUnmounted } from "vue";
import * as echarts from "echarts";
const props = defineProps({
groupList: {
type: Array,
default: () => []
},
title: {
type: String,
default: ""
}
});
//
const chartInstances = new Map();
const indicator = [
{ name: '成长期', max: 30 },
{ name: '收缩期', max: 30 },
{ name: '合并期', max: 30 },
{ name: '分裂期', max: 30 },
]
//
const initChart = (groupList) => {
groupList.forEach(group => {
const chartDom = document.getElementById(`group-chart-${group.id}`);
if (chartDom && group.series) {
const myChart = echarts.init(chartDom);
chartInstances.set(group.id, myChart);
const option = {
tooltip: {},
//
radar: {
startAngle: 135, // -45°
indicator: indicator, //
shape: 'circle', //
splitNumber: 5, //
//
axisName: {
color: '#94C1EC',
fontSize: 14,
},
// 线
axisLine: {
lineStyle: {
type: 'dashed',
color: 'rgba(35, 60, 92, 0.75)'
}
},
// 线
splitLine: {
lineStyle: {
color: 'rgba(37, 50, 67, 1)'
}
},
//
splitArea: {
show: true,
areaStyle: {
color: ['rgba(10, 26, 47, 0.3)', 'rgba(10, 26, 47, 0.5)']
}
},
},
series: group.series
};
myChart.setOption(option);
}
});
};
onMounted(() => {
//
initChart(props.groupList);
//
window.addEventListener('resize', handleResize);
});
//
const handleResize = () => {
chartInstances.forEach(chart => {
chart.resize();
});
};
//
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
chartInstances.forEach(chart => {
chart.dispose();
});
chartInstances.clear();
});
</script>
<style lang="less">
.groupPanel-component {
width: 100%;
height: 100%;
.title {
margin-top: -7px;
margin-left: -2px;
}
.groupPanel-list {
width: 100%;
height: 470px;
padding: 0 20px;
overflow: auto;
&::-webkit-scrollbar {
width: 3px; /* 垂直滚动条宽度 */
height: 5px; /* 水平滚动条高度 */
}
&::-webkit-scrollbar-thumb {
background: rgba(147, 210, 255, 0.3); /* 蓝色半透明滑块 */
border-radius: 4px;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(147, 210, 255, 0.5); /* 更明显的蓝色 */
}
.group-item {
width: 100%;
height: 260px;
padding-top: 16px;
padding-bottom: 20px;
border-bottom: 0.5px solid rgba(0, 113, 188, 0.5);
.group-item-title {
position: relative;
.group-item-title-type {
position: absolute;
top: 0;
color: #8efbff;
left: 17px;
font-size: 14px;
}
}
.group-item-statistics {
width: 100%;
height: 40px;
margin-top: 20px;
color: #fff;
font-family: PingFang SC;
font-weight: 400;
font-style: Medium;
font-size: 14px;
.container {
left: 40px;
width: 218px;
height: 170px;
}
}
}
}
}
</style>

View File

@ -13,7 +13,13 @@
></GroupPanel> ></GroupPanel>
</div> </div>
<!-- 全局群体成员演化图 --> <!-- 全局群体成员演化图 -->
<div class="userChart"></div> <div class="userChart">
<GroupChart
:title="userChartTitleImg"
:moduleName="全局群体成员演化图"
:chartData="groupMemberStore.chartData"
></GroupChart>
</div>
</div> </div>
<!-- 中间大矩形 2 --> <!-- 中间大矩形 2 -->
<div class="middle-container"> <div class="middle-container">
@ -60,8 +66,10 @@
<script setup> <script setup>
import { ref } from "vue"; import { ref } from "vue";
import GroupPanel from "../component/groupPanel.vue"; import GroupPanel from "./components/groupPanel.vue";
import GroupAnalysis from "./components/groupAnalysis.vue"; import GroupAnalysis from "./components/groupAnalysis.vue";
import GroupChart from "../component/groupChart.vue";
import userChartTitleImg from "@/assets/images/groupMember/group-member-evolution-chart-title.png"
// src\views\GroupEvolution\component\wordsCloud.vue // src\views\GroupEvolution\component\wordsCloud.vue
import WordsCloud from "../component/wordsCloud.vue"; import WordsCloud from "../component/wordsCloud.vue";
import userPanelTitleImg from "@/assets/images/groupMember/evolutionAnalysisListTitle.png" import userPanelTitleImg from "@/assets/images/groupMember/evolutionAnalysisListTitle.png"
@ -77,6 +85,9 @@ const postDialog = ref(false);
// //
const currentPostPost = ref(null); const currentPostPost = ref(null);
//
const handleOpenPostDialog = (post) => { const handleOpenPostDialog = (post) => {
postDialog.value = true; postDialog.value = true;
currentPostPost.value = post; currentPostPost.value = post;

View File

@ -6,6 +6,7 @@
<div class="userPanel"> <div class="userPanel">
<GroupPanel <GroupPanel
:groupList="groupStructureStore.groupList" :groupList="groupStructureStore.groupList"
:moduleName="全局连通性演化图"
:title="userPanelTitleImg" :title="userPanelTitleImg"
></GroupPanel> ></GroupPanel>
</div> </div>
@ -86,6 +87,7 @@ const postDialog = ref(false);
// //
const currentPostPost = ref(null); const currentPostPost = ref(null);
const handleOpenPostDialog = (post) => { const handleOpenPostDialog = (post) => {
postDialog.value = true; postDialog.value = true;
currentPostPost.value = post; currentPostPost.value = post;

View File

@ -171,19 +171,27 @@ const initChart = async() => {
// //
chartInstance.on('mouseover', function(params) { chartInstance.on('mouseover', function(params) {
if (params.data && params.data.category === 0) { if (!params.data) return;
const isBridgeNode = params.data.category === 0;
const isCommunityNode = params.data.category === 1;
if (isBridgeNode) {
// //
const nodeId = params.data.originalId; const nodeId = params.data.originalId;
// //
activeNodeId.value = nodeId; activeNodeId.value = nodeId;
updateNodeImage(nodeId, true); updateNodeImage(nodeId, true);
} }
}); });
// //
chartInstance.on('mouseout', function(params) { chartInstance.on('mouseout', function(params) {
if (params.data && params.data.category === 0) { if (!params.data) return;
const isBridgeNode = params.data.category === 0;
const isCommunityNode = params.data.category === 1;
if (isBridgeNode) {
// //
const nodeId = params.data.originalId; const nodeId = params.data.originalId;
if (activeNodeId.value === nodeId) { if (activeNodeId.value === nodeId) {
@ -384,6 +392,7 @@ const initChart = async() => {
animationEasingUpdate: 'quinticInOut', animationEasingUpdate: 'quinticInOut',
emphasis: { // emphasis: { //
focus: 'adjacency', // focus: 'adjacency', //
blurScope: 'coordinateSystem', //
lineStyle: { // 线 lineStyle: { // 线
width: 10 // 线(10) width: 10 // 线(10)
} }