模块3接口

This commit is contained in:
duanhao 2025-08-05 17:46:21 +08:00
parent 24e7884a42
commit 022bb34123
11 changed files with 369 additions and 190 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -19,3 +19,10 @@ export function getGroupEvolutionTimeLine() {
export function getPostByUtcTime(utcTime) { export function getPostByUtcTime(utcTime) {
return http.get(`/groupEvolution/identify/posts?date=${utcTime}`) return http.get(`/groupEvolution/identify/posts?date=${utcTime}`)
} }
// 3.群体成员演化分析
// 3.1 群体成员演化信息列表信息
export function getGroupMemberInfoList() {
return http.get(`/groupEvolution/groupMember/infoList`)
}

View File

@ -11,7 +11,8 @@ import {
getGroupEvolutionGroupList, getGroupEvolutionGroupList,
getGroupEvolutionGroupScaleChart, getGroupEvolutionGroupScaleChart,
getGroupEvolutionTimeLine, getGroupEvolutionTimeLine,
getPostByUtcTime getPostByUtcTime,
getGroupMemberInfoList
} from "@/service/api/groupEvolution" } from "@/service/api/groupEvolution"
import { TansTimestamp } from "@/utils/transform" import { TansTimestamp } from "@/utils/transform"
@ -530,58 +531,13 @@ export const useGroupMemberStore = defineStore("groupMember", {
id: 1, id: 1,
type: "群体一", type: "群体一",
focusedTopic: "#中国海警首次登检菲律宾#", focusedTopic: "#中国海警首次登检菲律宾#",
series: [ value: [10, 5, 15, 5],
{
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, id: 2,
type: "群体二", type: "群体二",
focusedTopic: "#中国海警首次登检菲律宾#", focusedTopic: "#中国海警首次登检菲律宾#",
series: [ value: [10, 20, 15, 5],
{
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: [
@ -956,12 +912,58 @@ export const useGroupMemberStore = defineStore("groupMember", {
{ text: "手指", top: 195.5, left: 287.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 } { text: "手指", top: 195.5, left: 287.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 }
] ]
}), }),
actions: {}, actions: {
async initializeGroupList() {
const res = await getGroupMemberInfoList()
const groupList = res.data.map(item => ({
id: item.id,
type: item.type,
focusedTopic: item.focusedTopic,
value: item.value
}))
this.groupList = groupList
console.log("测试获取groupList:",res);
}
},
persist: false // 开启持久化 persist: false // 开启持久化
}) })
export const useAnomalousGroup = defineStore("anomalousGroup", { export const useAnomalousGroup = defineStore("anomalousGroup", {
state: () => ({ state: () => ({
groupList: [
{
id:1,
type: "异常社团组一",
abnormalGroup: [
{
groupId: "G02",
nodeCount: 112,
postNum: 21
},
{
groupId: "G07",
nodeCount: 183,
postNum: 13
}
]
},
{
id:2,
type: "异常社团组二",
abnormalGroup: [
{
groupId: "G04",
nodeCount: 86,
postNum: 12
},
{
groupId: "G08",
nodeCount: 143,
postNum: 7
}
]
}
],
wordCloudData: [ wordCloudData: [
{ {
text: "局座", text: "局座",

View File

@ -1,11 +1,11 @@
<template> <template>
<div class="anomalousContent-component"> <div class="anomalousContent-component">
<!-- 标题 --> <!-- 标题 -->
<img class="title" src="@/assets/images/abnormalGroup/anomalousContentInfoTitle.png" alt=""> <img class="title" src="@/assets/images/abnormalGroup/anomalousContentInfoTitle.png" alt="">
<!-- 异常互动内容列表 --> <!-- 异常互动内容列表 -->
<div class="anomalousContent-list"> <div class="anomalousContent-list">
<!-- 异常内容项 --> <!-- 异常内容项 -->
<div class="content-item" v-for="content in props.contentList" :key="content.id"> <div class="content-item" v-for="content in props.contentList" :key="content.id">
<!-- 矩形标题 --> <!-- 矩形标题 -->
<div class="content-item-title"> <div class="content-item-title">
<img <img
@ -49,25 +49,8 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
<!-- 用户区域 -->
<div class="content-item-users">
<!-- 评论人 -->
<div class="user-item">
<img :src="content.commenter.userAvatar" alt="" class="user-avatar" />
<div class="user-name">{{ content.commenter.userName }}</div>
</div> </div>
<!-- 评论接受人 --> </div>
<div class="user-item">
<img :src="content.commentRecipient.userAvatar" alt="" class="user-avatar" />
<div class="user-name">{{ content.commentRecipient.userName }}</div>
</div>
</div>
<!-- 评论的内容 -->
<div class="content-item-comment">
<!-- <div class="post-content">{{ content.commentContent }}</div> -->
</div>
</div> </div>
</template> </template>
@ -88,121 +71,112 @@ const props = defineProps({
.title { .title {
margin-top: -7px; margin-top: -7px;
} }
.content-item { .anomalousContent-list {
width: 100%; height: 490px;
height: 100%; overflow: auto;
.anomalousContent-list { .content-item {
width: 100%; width: 100%;
height: 500px; padding-left: 24px;
overflow: auto; padding-bottom: 20px;
.content-item { .content-item-title {
width: 100%; position: relative;
padding-left: 24px; .content-item-title-icon {
padding-bottom: 20px; width: 130px;
.content-item-title { }
position: relative; .content-item-title-text {
.content-item-title-icon { position: absolute;
width: 160px; top: 3px;
} color: #8efbff;
.content-item-title-text { left: 12px;
position: absolute; font-size: 14px;
top: 7px; }
color: #8efbff; }
left: 12px; .content-item-users {
font-size: 14px; padding-top: 16px;
} padding-bottom: 16px;
} display: flex;
.content-item-users { justify-content: flex-start;
display: flex; gap: 16px;
.user-item { .user-item {
display: flex; display: flex;
align-items: center; align-items: center;
margin-top: 16px; color: #fff;
padding-right: 20px; font-family: PingFang SC;
.user-avatar { font-weight: 400;
width: 20px; font-style: Bold;
height: 20px; font-size: 16px;
margin-right: 6px; .user-avatar {
} margin-right: 6px;
.user-name { width: 20px;
font-family: "PingFang SC"; height: 20px;
color: #fff; }
font-size: 16px; }
font-style: Bold; }
font-weight: 400; .commit-item {
} width: 304px;
} padding-top: 14px;
} padding-left: 10px;
.commit-item { padding-right: 10px;
margin-top: 14px; padding-bottom: 14px;
padding-bottom: 12px; background: linear-gradient(0deg, rgba(13, 39, 67, 0.66), rgba(13, 39, 67, 0.66)),
width: 304px; linear-gradient(270deg, rgba(147, 210, 255, 0.06) 0%, rgba(147, 210, 255, 0.16) 100%);
height: 100%; .commit-content-text {
color: #fff;
font-family: PingFang SC;
font-weight: 400;
font-style: Regular;
font-size: 14px;
}
.commit-statistic {
display: flex;
align-items: center;
gap: 16px;
padding-top: 8px;
.like-item {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 54px;
color: #fff; color: #fff;
font-family: PingFang SC; }
font-weight: 400; .comment-num-item {
font-style: Regular; display: flex;
font-size: 14px; align-items: center;
background: linear-gradient(0deg, rgba(13, 39, 67, 0.66), rgba(13, 39, 67, 0.66)), justify-content: center;
linear-gradient(270deg, rgba(147, 210, 255, 0.06) 0%, rgba(147, 210, 255, 0.16) 100%); gap: 8px;
.commit-content { width: 54px;
width: 284px; color: #fff;
margin-left: 10px; }
padding-top: 12px; .transmit-item {
padding-bottom: 8px; display: flex;
} align-items: center;
.commit-statistic { gap: 8px;
display: flex; justify-content: center;
padding-left: 10px; width: 54px;
padding-right: 10px; color: #fff;
.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 { /* 滚动条整体样式 - WebKit浏览器 */
width: 5px; /* 垂直滚动条宽度 */ .anomalousContent-list::-webkit-scrollbar {
height: 5px; /* 水平滚动条高度 */ width: 5px; /* 垂直滚动条宽度 */
} height: 5px; /* 水平滚动条高度 */
}
/* 滚动条滑块 */ /* 滚动条滑块 */
.anomalousContent-list::-webkit-scrollbar-thumb { .anomalousContent-list::-webkit-scrollbar-thumb {
background: rgba(147, 210, 255, 0.3); /* 蓝色半透明滑块 */ background: rgba(147, 210, 255, 0.3); /* 蓝色半透明滑块 */
border-radius: 4px; border-radius: 4px;
} }
/* 鼠标悬停在滑块上的效果 */
/* 鼠标悬停在滑块上的效果 */ .anomalousContent-list::-webkit-scrollbar-thumb:hover {
.anomalousContent-list::-webkit-scrollbar-thumb:hover { background: rgba(147, 210, 255, 0.5); /* 更明显的蓝色 */
background: rgba(147, 210, 255, 0.5); /* 更明显的蓝色 */ }
} .title {
.title { margin-top: -7px;
margin-top: -7px; }
}
} }
</style> </style>

View File

@ -0,0 +1,165 @@
<template>
<div class="groupPanel-component">
<img :src="title" alt="" class="title" />
<div class="groupPanel-list">
<div class="group-item" v-for="group in props.groupList" :key="group.id">
<div class="group-item-title">
<img
class="group-item-title-icon"
src="@/assets/images/abnormalGroup/abnormal-group-item-title.png"
alt=""
/>
<div class="group-item-title-type">{{ group.type }}</div>
</div>
<div class="item-info" v-for="abnormalGroup in group.abnormalGroup">
<div class="anbormalGroupId">社团ID:&nbsp;&nbsp;{{ abnormalGroup.groupId }}</div>
<div class="statistics-item">
<div class="node-item">
<img class="node-icon" src="@/assets/images/abnormalGroup/abnormal-user-group-node-icon.png" alt="">
<div class="node-content">
<div class="node-content-title">
节点数
</div>
<div class="node-content-count">{{ abnormalGroup.nodeCount }}</div>
</div>
</div>
<div class="post-item">
<img class="post-icon" src="@/assets/images/abnormalGroup/abnormal-user-group-post-icon.png" alt="">
<div class="post-content">
<div class="post-content-title">
发帖总数
</div>
<div class="post-content-count">{{ abnormalGroup.postNum }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { defineProps } from "vue"
const props = defineProps({
groupList: {
type: Array,
default: () => []
},
title: {
type: String,
default: ""
}
})
</script>
<style lang="less">
.groupPanel-component {
width: 100%;
height: 100%;
.title {
margin-top: -1px;
margin-left: -2px;
}
.groupPanel-list {
width: 100%;
height: 470px;
padding: 20px 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%;
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: 3px;
color: #8efbff;
left: 8px;
font-size: 14px;
}
}
.item-info {
margin-top: 10px;
.anbormalGroupId {
color: #fff;
font-family: PingFang SC;
font-weight: 400;
font-style: Medium;
font-size: 14px;
}
.statistics-item {
margin-top: 16px;
display: flex;
gap: 40px;
.node-item {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
.node-content {
display: flex;
flex-direction: column;
.node-content-title {
color: #fff;
font-family: MiSanb;
font-weight: 400;
font-style: Medium;
font-size: 14px;
}
.node-content-count {
color: #fff;
font-family: MiSans;
font-weight: 630;
font-style: Bold;
font-size: 18px;
}
}
}
.post-item {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
.post-content {
display: flex;
flex-direction: column;
.post-content-title {
color: #fff;
font-family: MiSanb;
font-weight: 400;
font-style: Medium;
font-size: 14px;
}
.post-content-count {
color: #fff;
font-family: MiSans;
font-weight: 630;
font-style: Bold;
font-size: 18px;
}
}
}
}
}
}
}
}
</style>

View File

@ -5,7 +5,9 @@
</div> </div>
<div class="content"> <div class="content">
<div class="left-container"> <div class="left-container">
<div class="userPanel"></div> <div class="userPanel">
<GroupPanel :groupList="anomalousGroupStore.groupList" :title="userGroupTitle"></GroupPanel>
</div>
<div class="userChart"> <div class="userChart">
<GroupChart <GroupChart
:title="userChartTitleImg" :title="userChartTitleImg"
@ -23,7 +25,7 @@
</div> </div>
<div class="right-container"> <div class="right-container">
<div class="anlysisPanel"> <div class="anlysisPanel">
<!-- <AnomalousContentInfo :contentList="anomalousGroupStore.abnormalContentList"></AnomalousContentInfo> --> <AnomalousContentInfo :contentList="anomalousGroupStore.abnormalContentList"></AnomalousContentInfo>
</div> </div>
<div class="cloudWords"> <div class="cloudWords">
<WordsCloud :wordsCloudList="anomalousGroupStore.wordCloudData"></WordsCloud> <WordsCloud :wordsCloudList="anomalousGroupStore.wordCloudData"></WordsCloud>
@ -57,12 +59,14 @@
<script setup> <script setup>
import { ref } from "vue"; import { ref } from "vue";
import userGroupTitle from "@/assets/images/abnormalGroup/abnormal-user-group-title.png"
import userChartTitleImg from "@/assets/images/abnormalGroup/abnormal-group-hudo-time-chart.png" 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 GroupPanel from "./components/groupPanel.vue"
import GroupPost from "../component/groupPost.vue" import GroupPost from "../component/groupPost.vue"
import GroupChart from "../component/groupChart.vue" import GroupChart from "../component/groupChart.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();

View File

@ -46,7 +46,7 @@ const indicator = [
const initChart = (groupList) => { const initChart = (groupList) => {
groupList.forEach(group => { groupList.forEach(group => {
const chartDom = document.getElementById(`group-chart-${group.id}`); const chartDom = document.getElementById(`group-chart-${group.id}`);
if (chartDom && group.series) { if (chartDom && group.value) {
const myChart = echarts.init(chartDom); const myChart = echarts.init(chartDom);
chartInstances.set(group.id, myChart); chartInstances.set(group.id, myChart);
const option = { const option = {
@ -83,7 +83,30 @@ const initChart = (groupList) => {
} }
}, },
}, },
series: group.series series: [
{
type: 'radar',
data: [
{
value: group.value,
symbol: "circle",
symbolSize: 5,
itemStyle: {
color: "#01D7DA" //
},
areaStyle: {
color: "rgba(87, 196, 255, 0.3)" //
},
// 线
lineStyle: {
color: "#0374FE",
type: "dashed",
width: 1
}
}
]
}
]
}; };
myChart.setOption(option); myChart.setOption(option);

View File

@ -72,7 +72,7 @@
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { onMounted, ref } from "vue";
import GroupPanel from "./components/groupPanel.vue"; import GroupPanel from "./components/groupPanel.vue";
import GroupPost from "../component/groupPost.vue"; import GroupPost from "../component/groupPost.vue";
import GroupAnalysis from "./components/groupAnalysis.vue"; import GroupAnalysis from "./components/groupAnalysis.vue";
@ -103,6 +103,10 @@ const handleOpenPostDialog = (post) => {
postDialog.value = true; postDialog.value = true;
currentPostPost.value = post; currentPostPost.value = post;
}; };
onMounted(async () => {
await groupMemberStore.initializeGroupList()
})
</script> </script>
<style scoped lang="less"> <style scoped lang="less">