群体成员演化分析-左-中时间轴-中群体演化信息

This commit is contained in:
duanhao 2025-08-06 15:50:15 +08:00
parent 022bb34123
commit bb9aae9172
11 changed files with 208 additions and 63 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

View File

@ -122,6 +122,8 @@ watch(
timeList.value = newVal
},
{ deep: true }
)
// active-needle timeList
const showHidden = computed(() => {

View File

@ -22,7 +22,22 @@ export function getPostByUtcTime(utcTime) {
// 3.群体成员演化分析
// 3.1 群体成员演化信息列表信息
export function getGroupMemberInfoList() {
return http.get(`/groupEvolution/groupMember/infoList`)
}
// 3.1 获取时间线数据
export function getGroupMemberTimeLine() {
return http.get(`/groupEvolution/groupMember/timeline`)
}
// 3.2 群体成员演化信息列表信息
export function getGroupMemberInfoList(time) {
return http.get(`/groupEvolution/groupMember/infoList?time=${time}`)
}
// 3.3 全局群体成员演化图
export function getGroupMemberChart() {
return http.get(`/groupEvolution/groupMember/chart`)
}
// 3.4 群体演化信息
export function getGroupMemberEvolutionInfoByTime(date) {
return http.get(`/groupEvolution/groupMember/changeList?date=${date}`)
}

View File

@ -12,9 +12,12 @@ import {
getGroupEvolutionGroupScaleChart,
getGroupEvolutionTimeLine,
getPostByUtcTime,
getGroupMemberInfoList
getGroupMemberInfoList,
getGroupMemberTimeLine,
getGroupMemberChart,
getGroupMemberEvolutionInfoByTime
} from "@/service/api/groupEvolution"
import { TansTimestamp } from "@/utils/transform"
import { TansTimestamp, utcStringToHHMMSS } from "@/utils/transform"
export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
state: () => ({
@ -183,10 +186,9 @@ export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
async initialGraphByUtcTime() {},
// 通过时间来获取帖文列表
async initialPostByUtcTime(utcTime) {
const res = await getPostByUtcTime(utcTime)
if (res.code != 200) return
this.posts = res.data
}
},
persist: true // 开启持久化
@ -526,7 +528,7 @@ export const useGroupStructureStore = defineStore("groupStructure", {
export const useGroupMemberStore = defineStore("groupMember", {
state: () => ({
groupList: [
/* groupList
{
id: 1,
type: "群体一",
@ -539,7 +541,9 @@ export const useGroupMemberStore = defineStore("groupMember", {
focusedTopic: "#中国海警首次登检菲律宾#",
value: [10, 20, 15, 5],
}
],
*/
groupList: [],
timeList: [],
groupMemberList: [
{
id: 1,
@ -779,62 +783,62 @@ export const useGroupMemberStore = defineStore("groupMember", {
posts: [
{
id: 1,
timestamp: "2024-01-04 0:03:16",
groupCategory: "群体一",
time: "2024-01-04 0:03:16",
type: "群体一",
memberAddCount: 1
},
{
id: 2,
timestamp: "2024-02-03 12:58:53",
groupCategory: "群体二",
time: "2024-02-03 12:58:53",
type: "群体二",
memberAddCount: 2
},
{
id: 3,
timestamp: "2024-02-22 17:13:44",
groupCategory: "群体三",
time: "2024-02-22 17:13:44",
type: "群体三",
memberAddCount: 4
},
{
id: 4,
timestamp: "2024-02-23 17:54:46",
groupCategory: "群体一",
time: "2024-02-23 17:54:46",
type: "群体一",
memberAddCount: 4
},
{
id: 5,
timestamp: "2024-03-14 09:58:12",
groupCategory: "群体三",
time: "2024-03-14 09:58:12",
type: "群体三",
memberAddCount: 4
},
{
id: 6,
timestamp: "2024-03-23 21:20:40",
groupCategory: "群体二",
time: "2024-03-23 21:20:40",
type: "群体二",
memberAddCount: 4
},
{
id: 7,
timestamp: "2024-03-23 21:42:36",
groupCategory: "群体一",
time: "2024-03-23 21:42:36",
type: "群体一",
memberAddCount: 2
},
{
id: 8,
timestamp: "2024-04-06 18:17:30",
groupCategory: "群体二",
time: "2024-04-06 18:17:30",
type: "群体二",
memberAddCount: 4
},
{
id: 9,
timestamp: "2024-04-06 19:19:50",
groupCategory: "群体一",
time: "2024-04-06 19:19:50",
type: "群体一",
memberAddCount: 4
},
{
id: 10,
timestamp: "2024-05-16 00:22:18",
groupCategory: "群体二",
time: "2024-05-16 00:22:18",
type: "群体二",
memberAddCount: 5
}
],
@ -913,19 +917,46 @@ export const useGroupMemberStore = defineStore("groupMember", {
]
}),
actions: {
async initializeGroupList() {
const res = await getGroupMemberInfoList()
async initializeGroupMemberTimeLine() {
const res = await getGroupMemberTimeLine()
this.timeList = res.data
console.log("测试获取timeList:",this.timeList);
},
async initializeGroupList(time = "2024-06-19T07:57:46Z") {
const res = await getGroupMemberInfoList(time)
console.log("测试获取groupMemberInfoList:",res);
const groupList = res.data.map(item => ({
id: item.id,
type: item.type,
focusedTopic: item.focusedTopic,
value: item.value
value: item.value.map(item => item * 100)
}))
this.groupList = groupList
console.log("测试获取groupList:",res);
},
async initializeGroupMemberChart() {
const res = await getGroupMemberChart()
const xAxisData = res.data.xaxisData.map(item => utcStringToHHMMSS(item))
const yAxisRange = res.data.yaxisRange
const themeColors = ["#2AB8FD", "#02D7DA", "#FFDA09", "#EB57B0"]
const seriesList = res.data.seriesList.map(item => ({
data: item.data.map(item => item.toFixed(2)),
name: item.name,
themeColor: themeColors[item.id - 1],
}))
this.chartData = {
xAxisData,
yAxisRange,
seriesList
}
},
async initialPostByUtcTime(utcTime) {
const res = await getGroupMemberEvolutionInfoByTime(utcTime)
this.posts = res.data
console.log("测试获取groupMemberEvolutionInfoByTime:",res.data);
}
},
persist: false // 开启持久化
persist: true // 开启持久化
})
export const useAnomalousGroup = defineStore("anomalousGroup", {

View File

@ -91,3 +91,17 @@ export function getAvatarUrl(binaryStream) {
return `data:image/jpeg;base64,${binaryStream}`
}
}
/**
* 将UTC格式时间字符串转换为时间戳并返回HH:mm:ss格式
* @param {string} utcString - UTC格式时间字符串"2024-06-19T07:57:46Z"
* @returns {string} 格式化后的时间字符串格式为HH:mm:ss
*/
export function utcStringToHHMMSS(utcString) {
if (!utcString) return ''
// 解析UTC时间字符串为dayjs对象
const date = dayjs.utc(utcString).add(8, 'hour')
// 格式化为HH:mm:ss
return date.format('HH:mm:ss')
}

View File

@ -287,9 +287,6 @@ watch(
)
onMounted(() => {
console.log("111");
console.log(props.moduleName)
//
sliderContainerWidth.value = document.querySelector(".slider-container").offsetWidth
})

View File

@ -35,6 +35,7 @@ const handlePointerDown = (time) => {
const utcTime = convertToUtcIsoString(time)
emit("click:pointerDownAndSlide", utcTime)
}
</script>
<style scoped lang="less">

View File

@ -40,8 +40,8 @@
>
</span>
<span class="author" v-else-if="props.moduleName == '群体成员演化分析'"
>{{ post.groupCategory }}&nbsp;&nbsp;的成员数目增加了<span style="color: #9df9fe">{{
post.memberAddCount
>{{ post.type }}&nbsp;&nbsp;的成员数目{{ post.memberAddCount < 0 ? "减少" : "增加"}}<span style="color: #9df9fe">{{
Math.abs(post.memberAddCount)
}}</span
>
</span>

View File

@ -30,9 +30,10 @@
<script setup>
import { defineProps, onMounted, ref } from "vue";
import GroupChart from "../../component/groupChart.vue";
const curSelectedTab = ref("头部自媒体");
const curSelectedTab = ref("群体一");
const curSelectedTabData = ref(null);
const tabs = ["头部自媒体", "官方媒体", "普通自媒体"];
const tabs = ["群体一", "群体二", "群体三"];
const moduleName = "群体成员演化分析"
const props = defineProps({
title: {
@ -48,15 +49,15 @@ const props = defineProps({
const handleSwitch = (item) => {
curSelectedTab.value = item;
const keyMapList = {
头部自媒体: "topSelfMedia",
官方媒体: "officalMedia",
普通自媒体: "ordinaryMedia"
群体一: "topSelfMedia",
群体二: "officalMedia",
群体三: "ordinaryMedia"
};
curSelectedTabData.value = props.chartsData[keyMapList[item]];
};
onMounted(() => {
handleSwitch("头部自媒体");
handleSwitch("群体一");
});
</script>

View File

@ -6,7 +6,7 @@
<div class="group-item-title">
<img
class="group-item-title-icon"
src="@/assets/images/linkPrediction/title/group-item-title.png"
src="@/assets/images/groupMember/group-member-user-list-title.png"
alt=""
/>
<div class="group-item-title-type">{{ group.type }}</div>
@ -21,8 +21,9 @@
</template>
<script setup>
import { defineProps, ref, onMounted, onUnmounted } from "vue";
import { defineProps, ref, onMounted, onUnmounted, watch, nextTick } from "vue";
import * as echarts from "echarts";
import nodeHoverImg from "@/assets/images/nodeHover.png"
const props = defineProps({
groupList: {
type: Array,
@ -34,6 +35,23 @@ const props = defineProps({
}
});
const groupList = ref(props.groupList)
// groupList
watch(() => props.groupList, (newVal) => {
groupList.value = newVal
//
chartInstances.forEach(chart => {
chart.dispose();
});
chartInstances.clear();
// 使nextTickDOM
nextTick(() => {
initChart(groupList.value);
});
}, { deep: true });
//
const chartInstances = new Map();
const indicator = [
@ -49,14 +67,55 @@ const initChart = (groupList) => {
if (chartDom && group.value) {
const myChart = echarts.init(chartDom);
chartInstances.set(group.id, myChart);
// indicator
const maxValue = Math.ceil(Math.max(...group.value));
const option = {
tooltip: {},
tooltip: {
trigger: "item",
backgroundColor: "rgba(0,0,0,0)", //
borderColor: "rgba(0,0,0,0)", //
borderWidth: 0,
extraCssText: "box-shadow:none;padding:0;",
formatter: function (params) {
return `<div
style="
padding:10px 15px;
height: 100px;
border-radius: 4px;
background: url('${nodeHoverImg}');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
">
<div style="color:#fff;letter-spacing: 0.14px;">
<div >成长${params.data.value[0]}</div>
<div >收缩${params.data.value[1]}</div>
<div >合并${params.data.value[2]}</div>
<div >分裂${params.data.value[3]}</div>
</div>
</div>`
}
},
//
radar: {
startAngle: 135, // -45°
indicator: indicator, //
indicator: [
{ name: '成长期', max: Math.max(30, maxValue) },
{ name: '收缩期', max: Math.max(30, maxValue) },
{ name: '合并期', max: Math.max(30, maxValue) },
{ name: '分裂期', max: Math.max(30, maxValue) },
], //
shape: 'circle', //
splitNumber: 5, //
min: 0,
alignTicks: false,
//
axisName: {
color: '#94C1EC',
@ -88,7 +147,7 @@ const initChart = (groupList) => {
type: 'radar',
data: [
{
value: group.value,
value: group.value || [0,0,0,0],
symbol: "circle",
symbolSize: 5,
itemStyle: {
@ -116,7 +175,12 @@ const initChart = (groupList) => {
onMounted(() => {
//
initChart(props.groupList);
console.log("props.groupList:",props.groupList);
// 使nextTickDOM
nextTick(() => {
initChart(props.groupList);
});
//
window.addEventListener('resize', handleResize);
@ -145,7 +209,7 @@ onUnmounted(() => {
width: 100%;
height: 100%;
.title {
margin-top: -7px;
margin-top: -8px;
margin-left: -2px;
}
.groupPanel-list {
@ -166,17 +230,17 @@ onUnmounted(() => {
}
.group-item {
width: 100%;
height: 260px;
padding-top: 16px;
padding-bottom: 20px;
height: 240px;
padding-top: 10px;
padding-bottom: 10px;
border-bottom: 0.5px solid rgba(0, 113, 188, 0.5);
.group-item-title {
position: relative;
.group-item-title-type {
position: absolute;
top: 0;
top: 2px;
color: #8efbff;
left: 17px;
left: 12px;
font-size: 14px;
}
}
@ -191,8 +255,8 @@ onUnmounted(() => {
font-size: 14px;
.container {
left: 40px;
width: 218px;
height: 170px;
width: 210px;
height: 160px;
}
}
}

View File

@ -23,7 +23,12 @@
</div>
<!-- 中间大矩形 2 -->
<div class="middle-container">
<div class="graph"></div>
<div class="graph">
<GroupGraph
:store="groupMemberStore"
@click:pointerDownAndSlide="handleChangeXAxis"
></GroupGraph>
</div>
<div class="postList">
<GroupPost
@ -73,6 +78,7 @@
<script setup>
import { onMounted, ref } from "vue";
import GroupGraph from "../component/groupGraph.vue"
import GroupPanel from "./components/groupPanel.vue";
import GroupPost from "../component/groupPost.vue";
import GroupAnalysis from "./components/groupAnalysis.vue";
@ -96,8 +102,15 @@ const postDialog = ref(false);
//
const currentPostPost = ref(null);
//
const handleChangeXAxis = (utcTime) => {
const timeList = groupMemberStore.timeList
// console.log("",utcTime)
// if (!timeList.includes(utcTime)) return
groupMemberStore.initializeGroupList(utcTime) //
groupMemberStore.initialPostByUtcTime(utcTime) //
}
const handleOpenPostDialog = (post) => {
postDialog.value = true;
@ -105,7 +118,14 @@ const handleOpenPostDialog = (post) => {
};
onMounted(async () => {
await groupMemberStore.initializeGroupMemberTimeLine()
console.log("初始化成员演化信息表");
await groupMemberStore.initializeGroupList()
console.log("初始化后的群体成员信息表:",groupMemberStore.groupList);
await groupMemberStore.initializeGroupMemberChart()
console.log("初始化后的全局群体成员演化图:");
})
</script>