解决冲突

This commit is contained in:
duanhao 2025-08-08 10:21:05 +08:00
commit 240f149d4a
8 changed files with 423 additions and 645 deletions

View File

@ -17,8 +17,6 @@ import {
getStructuralEvolutionAnalysisTimeLine,
getStructuralEvolutionAnalysisInfoList,
getStructuralEvolutionAnalysisPost,
getGroupMemberInfoList,
getGroupMemberTimeLine,
getGroupMemberChart,
@ -31,11 +29,9 @@ import {
getAbnormalGroupInteractionChart,
getAbnormalGroupBehaviorPosts,
getAbnormalGroupBehaviorDetail,
getRelationGraphByUtcTime
} from "@/service/api/groupEvolution"
import { TansTimestamp, utcStringToHHMMSS, getMaxCeiled, parsePercentage } from "@/utils/transform"
import { time } from "echarts"
export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
state: () => ({
@ -270,140 +266,11 @@ export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
export const useGroupStructureStore = defineStore("groupStructure", {
state: () => ({
groupList: [
{
id: 1,
type: "群体一",
focusedTopic: "#中国海警首次登检菲律宾运补船只",
innerNum: 20,
outerNum: 100
},
{
id: 2,
type: "群体二",
focusedTopic: "#外交部回应中国海警缴获菲土乓枪支",
innerNum: 20,
outerNum: 100
},
{
id: 3,
type: "群体三",
focusedTopic: "#社会群体对中国海警缴获菲土乓枪支",
innerNum: 20,
outerNum: 100
}
],
groupList: [],
graph: {},
timeList: [],
chartData: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 1, interval: 0.2 },
seriesList: [
{
data: [0.3055, 0.3939, 0.5813, 0.6094, 0.6289],
name: "",
themeColor: "#2AB8FD"
}
]
},
chartsData: {
/* topSelfMedia: [
{
id: 1,
name: "内部密度指数演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 0.0035, interval: 0.0005 },
seriesList: [
{
data: [0.0005, 0.002, 0.0024, 0.0026, 0.0027],
name: "",
themeColor: "#2AB8FD"
}
]
}
},
{
id: 2,
name: "外部拓展指数演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 2.1, interval: 0.3 },
seriesList: [
{
name: "",
themeColor: "#2AB8FD",
data: [1.9787, 0.6044, 0.6757, 0.6763, 0.6853]
}
]
}
}
],
officalMedia: [
{
id: 1,
name: "内部密度指数演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 0.0035, interval: 0.0005 },
seriesList: [
{
name: "",
themeColor: "#2AB8FD",
data: [0.0001, 0.02, 0.024, 0.026, 0.027]
}
]
}
},
{
id: 2,
name: "外部拓展指数演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 2.1, interval: 0.3 },
seriesList: [
{
name: "",
themeColor: "#2AB8FD",
data: [1.787, 0.044, 0.757, 0.763, 0.853]
}
]
}
}
],
ordinaryMedia: [
{
id: 1,
name: "内部密度指数演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 0.0035, interval: 0.0005 },
seriesList: [
{
name: "",
themeColor: "#2AB8FD",
data: [0.01, 0.2, 0.24, 0.26, 0.27]
}
]
}
},
{
id: 2,
name: "外部拓展指数演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 2.1, interval: 0.3 },
seriesList: [
{
name: "",
themeColor: "#2AB8FD",
data: [1.87, 0.44, 0.57, 0.63, 0.53]
}
]
}
}
] */
},
chartData: {},
chartsData: {},
wordCloudData: [
{
text: "佩洛西",
@ -557,15 +424,15 @@ export const useGroupStructureStore = defineStore("groupStructure", {
this.timeList = res.data
},
// 初始化群体结构演化分析信息列表
async initializeStructuralEvolutionAnalysisInfoList(time = '2024-06-19T07:57:46Z') {
async initializeStructuralEvolutionAnalysisInfoList(time = "2024-06-19T07:57:46Z") {
const res = await getStructuralEvolutionAnalysisInfoList(time)
this.groupList = res.data.map(item => ({
this.groupList = res.data.map((item) => ({
id: item.id,
type: item.type,
name: item.name,
focusedTopic: item.focusedTopic,
innerNum: parsePercentage(item.innerNum),
outerNum: parsePercentage(item.outerNum),
outerNum: parsePercentage(item.outerNum)
}))
},
@ -588,46 +455,55 @@ export const useGroupStructureStore = defineStore("groupStructure", {
// 初始化群体结构演化分析图表--右上方
async initializeStructuralEvolutionAnalysisChart() {
const res = await getStructuralEvolutionAnalysisChart()
console.log(res);
const topSelfMedia = res.data.topSelfMedia.map(item => ({
const topSelfMedia = res.data.topSelfMedia.map((item) => ({
id: item.id,
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map(item => utcStringToHHMMSS(item)),
yAxisRange: {min: 0, max: Math.ceil((item.chart.yaxisRange.max) / 5) * 5, interval: Math.ceil((item.chart.yaxisRange.max) / 5)},
seriesList: item.chart.seriesList.map((item => ({
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {
min: 0,
max: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval: Math.ceil(item.chart.yaxisRange.max / 5)
},
seriesList: item.chart.seriesList.map((item) => ({
data: item.data,
name: item.name,
themeColor: "#2AB8FD"
})))
}))
}
}))
const officalMedia = res.data.officalMedia.map(item => ({
const officalMedia = res.data.officalMedia.map((item) => ({
id: item.id,
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map(item => utcStringToHHMMSS(item)),
yAxisRange: {min: 0, max: Math.ceil((item.chart.yaxisRange.max) / 5) * 5, interval: Math.ceil((item.chart.yaxisRange.max) / 5)},
seriesList: item.chart.seriesList.map((item => ({
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {
min: 0,
max: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval: Math.ceil(item.chart.yaxisRange.max / 5)
},
seriesList: item.chart.seriesList.map((item) => ({
data: item.data,
name: item.name,
themeColor: "#2AB8FD"
})))
}))
}
}))
const ordinaryMedia = res.data.ordinaryMedia.map(item => ({
const ordinaryMedia = res.data.ordinaryMedia.map((item) => ({
id: item.id,
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map(item => utcStringToHHMMSS(item)),
yAxisRange: {min: 0, max: Math.ceil((item.chart.yaxisRange.max) / 5) * 5, interval: Math.ceil((item.chart.yaxisRange.max) / 5)},
seriesList: item.chart.seriesList.map((item => ({
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {
min: 0,
max: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval: Math.ceil(item.chart.yaxisRange.max / 5)
},
seriesList: item.chart.seriesList.map((item) => ({
data: item.data,
name: item.name,
themeColor: "#2AB8FD"
})))
}))
}
}))
@ -638,277 +514,60 @@ export const useGroupStructureStore = defineStore("groupStructure", {
}
},
async initialGraphByUtcTime(utcTime = "") {
const setColor = (groupId) => {
const colorMap = {
0: "50,141,120",
1: "133,129,48",
6: "12,112,144"
}
return colorMap[parseInt(groupId)]
}
const res = await getRelationGraphByUtcTime(utcTime)
if (res.code != 200) return
const newSet = new Set()
this.graph["links"] = res.data.links.map((link) => ({
source: link.source,
target: link.target,
color: setColor(link.type)
}))
this.graph["nodes"] = res.data.nodes
.filter((node) => {
if (!newSet.has(node.name)) {
newSet.add(node.name)
return true
}
return false
})
.map((node) => {
return {
id: node.name,
label: node.name,
type: node.groupId
}
})
},
// 初始化群体结构演化分析的群体演化信息-中下-随时间轴变化
async initializeStructuralPost(time = '2024-06-19T07:57:46Z') {
async initializeStructuralPost(time = "2024-06-19T07:57:46Z") {
const res = await getStructuralEvolutionAnalysisPost(time)
this.posts = res.data.map(item => ({
this.posts = res.data.map((item) => ({
id: item.id,
time: TansTimestamp(item.time, "YYYY.MM.DD HH:mm:ss"),
groupCategory: item.groupCategory,
innerEdgeAddCount: item.innerEdgeAddCount,
outerEdgeAddCount: item.outerEdgeAddCount,
outerEdgeAddCount: item.outerEdgeAddCount
}))
},
}
},
persist: true // 开启持久化
})
export const useGroupMemberStore = defineStore("groupMember", {
state: () => ({
/* groupList
{
id: 1,
type: "群体一",
focusedTopic: "#中国海警首次登检菲律宾#",
value: [10, 5, 15, 5]
},
{
id: 2,
type: "群体二",
focusedTopic: "#中国海警首次登检菲律宾#",
value: [10, 20, 15, 5]
}
*/
groupList: [],
timeList: [],
groupMemberList: [
{
id: 1,
type: "头部媒体",
statistics: [
{ id: 1, iconImg: splitImg, name: "分裂", value: 0.0298 },
{ id: 2, iconImg: mergeImg, name: "合并", value: 0 },
{ id: 3, iconImg: shrinkImg, name: "收缩", value: 0.4741 },
{ id: 4, iconImg: expamdImg, name: "扩展", value: 1.04e-14 }
]
},
{
id: 2,
type: "头部媒体",
statistics: [
{ id: 1, iconImg: splitImg, name: "分裂", value: 0.2125 },
{ id: 2, iconImg: mergeImg, name: "合并", value: 1.65e-15 },
{ id: 3, iconImg: shrinkImg, name: "收缩", value: 0.4313 },
{ id: 4, iconImg: expamdImg, name: "扩展", value: 6.02e-15 }
]
}
],
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: [
{
data: [0.9237, 0.14507, 0, 0, 0],
name: "分裂指数",
themeColor: "#2AB8FD"
},
{
data: [9.8011, 21.3123, 10.4338, 14.1912, 10.1523],
name: "合并指数",
themeColor: "#02D7DA"
},
{
data: [1.9057, 1.5123, 1.0338, 0.5912, 0.1523],
name: "收缩指数",
themeColor: "#FFDA09"
},
{
data: [15.1119, 6.5123, 10.6338, 9.5912, 4.1523],
name: "扩展指数",
themeColor: "#EB57B0"
}
]
},
/* chartsData: {
topSelfMedia: [
{
id: 1,
name: "分裂演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 1, interval: 0.2 },
seriesList: [
{
name: "分裂演化",
themeColor: "#2AB8FD",
data: [0.9237, 0.14507, 0, 0, 0]
}
]
}
},
{
id: 2,
name: "合并演化",
chart: {
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: "合并演化",
themeColor: "#02D7DA",
data: [9.8011, 21.3123, 10.4338, 14.1912, 10.1523]
}
]
}
},
{
id: 3,
name: "收缩演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 2, interval: 0.5 },
seriesList: [
{
name: "收缩演化",
themeColor: "#FFDA09",
data: [1.9057, 1.5123, 1.0338, 0.5912, 0.1523]
}
]
}
},
{
id: 4,
name: "扩展演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 20, interval: 5 },
seriesList: [
{
name: "扩展演化",
themeColor: "#EB57B0",
data: [15.1119, 6.5123, 10.6338, 9.5912, 4.1523]
}
]
}
}
],
officalMedia: [
{
id: 1,
name: "分裂演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 1, interval: 0.2 },
seriesList: [
{
name: "分裂演化",
themeColor: "#2AB8FD",
data: [0.9237, 0.14507, 0, 0, 0]
}
]
}
},
{
id: 2,
name: "合并演化",
chart: {
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: "合并演化",
themeColor: "#02D7DA",
data: [9.8011, 21.3123, 10.4338, 14.1912, 10.1523]
}
]
}
},
{
id: 3,
name: "收缩演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 2, interval: 0.5 },
seriesList: [
{
name: "收缩演化",
themeColor: "#FFDA09",
data: [1.9057, 1.5123, 1.0338, 0.5912, 0.1523]
}
]
}
},
{
id: 4,
name: "扩展演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 20, interval: 5 },
seriesList: [
{
name: "扩展演化",
themeColor: "#EB57B0",
data: [15.1119, 6.5123, 10.6338, 9.5912, 4.1523]
}
]
}
}
],
ordinaryMedia: [
{
id: 1,
name: "分裂演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 1, interval: 0.2 },
seriesList: [
{
name: "分裂演化",
themeColor: "#2AB8FD",
data: [0.9237, 0.14507, 0, 0, 0]
}
]
}
},
{
id: 2,
name: "合并演化",
chart: {
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: "合并演化",
themeColor: "#02D7DA",
data: [9.8011, 21.3123, 10.4338, 14.1912, 10.1523]
}
]
}
},
{
id: 3,
name: "收缩演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 2, interval: 0.5 },
seriesList: [
{
name: "收缩演化",
themeColor: "#FFDA09",
data: [1.9057, 1.5123, 1.0338, 0.5912, 0.1523]
}
]
}
},
{
id: 4,
name: "扩展演化",
chart: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 20, interval: 5 },
seriesList: [
{
name: "扩展演化",
themeColor: "#EB57B0",
data: [15.1119, 6.5123, 10.6338, 9.5912, 4.1523]
}
]
}
}
]
}, */
graph: {},
chartData: {},
chartsData: {},
posts: [
{
@ -1051,12 +710,10 @@ export const useGroupMemberStore = defineStore("groupMember", {
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,
@ -1087,11 +744,9 @@ export const useGroupMemberStore = defineStore("groupMember", {
async initialPostByUtcTime(utcTime) {
const res = await getGroupMemberEvolutionInfoByTime(utcTime)
this.posts = res.data
console.log("测试获取groupMemberEvolutionInfoByTime:", res.data)
},
async initializeGroupMemberEvolutionAnalysisChart() {
const res = await getGroupMemberEvolutionAnalysisChart()
console.log("测试获取groupMemberEvolutionAnalysisChart:", res)
const themeColors = {
分裂演化: "#2AB8FD",
合并演化: "#02D7DA",
@ -1103,7 +758,11 @@ export const useGroupMemberStore = defineStore("groupMember", {
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {min: 0, max: Math.ceil((item.chart.yaxisRange.max) / 5) * 5, interval: Math.ceil((item.chart.yaxisRange.max) / 5)},
yAxisRange: {
min: 0,
max: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval: Math.ceil(item.chart.yaxisRange.max / 5)
},
seriesList: item.chart.seriesList.map((item) => ({
data: item.data.map((item) => item.toFixed(2)),
name: item.name,
@ -1117,7 +776,11 @@ export const useGroupMemberStore = defineStore("groupMember", {
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {min: 0, max: Math.ceil((item.chart.yaxisRange.max) / 5) * 5, interval: Math.ceil((item.chart.yaxisRange.max) / 5)},
yAxisRange: {
min: 0,
max: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval: Math.ceil(item.chart.yaxisRange.max / 5)
},
seriesList: item.chart.seriesList.map((item) => ({
data: item.data.map((item) => item.toFixed(2)),
name: item.name,
@ -1131,7 +794,11 @@ export const useGroupMemberStore = defineStore("groupMember", {
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {min: 0, max: Math.ceil((item.chart.yaxisRange.max) / 5) * 5, interval: Math.ceil((item.chart.yaxisRange.max) / 5)},
yAxisRange: {
min: 0,
max: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval: Math.ceil(item.chart.yaxisRange.max / 5)
},
seriesList: item.chart.seriesList.map((item) => ({
data: item.data.map((item) => item.toFixed(2)),
name: item.name,
@ -1145,6 +812,40 @@ export const useGroupMemberStore = defineStore("groupMember", {
officalMedia: officalMedia,
ordinaryMedia: ordinaryMedia
}
},
async initialGraphByUtcTime(utcTime = "") {
const setColor = (groupId) => {
const colorMap = {
0: "50,141,120",
1: "133,129,48",
6: "12,112,144"
}
return colorMap[parseInt(groupId)]
}
const res = await getRelationGraphByUtcTime(utcTime)
if (res.code != 200) return
const newSet = new Set()
this.graph["links"] = res.data.links.map((link) => ({
source: link.source,
target: link.target,
color: setColor(link.type)
}))
this.graph["nodes"] = res.data.nodes
.filter((node) => {
if (!newSet.has(node.name)) {
newSet.add(node.name)
return true
}
return false
})
.map((node) => {
return {
id: node.name,
label: node.name,
type: node.groupId
}
})
}
},
persist: true // 开启持久化
@ -1381,7 +1082,7 @@ export const useAnomalousGroup = defineStore("anomalousGroup", {
}
},
// 异常行为分析-中下
async initializeAbnormalGroupPosts(time = '2024-06-19T07:57:46Z') {
async initializeAbnormalGroupPosts(time = "2024-06-19T07:57:46Z") {
const res = await getAbnormalGroupBehaviorPosts(time)
if (res.code === 200) {
this.posts = res.data
@ -1389,13 +1090,12 @@ export const useAnomalousGroup = defineStore("anomalousGroup", {
},
// 异常互动详情-右上
async initializeAbnormalGroupInteractionDetail(time = '2024-06-19T07:57:46Z') {
async initializeAbnormalGroupInteractionDetail(time = "2024-06-19T07:57:46Z") {
const res = await getAbnormalGroupBehaviorDetail(time)
if (res.code === 200) {
this.interactionDetail = res.data
}
},
}
},
persist: true // 开启持久化
})

View File

@ -1,12 +1,13 @@
<template>
<div class="layout-container">
<div class="top-container">
</div>
<div class="top-container"></div>
<div class="content">
<div class="left-container">
<div class="userPanel">
<GroupPanel :groupList="anomalousGroupStore.groupList" :title="userGroupTitle"></GroupPanel>
<GroupPanel
:groupList="anomalousGroupStore.groupList"
:title="userGroupTitle"
></GroupPanel>
</div>
<div class="userChart">
<GroupChart
@ -25,12 +26,18 @@
></GroupGraph>
</div>
<div class="postList">
<GroupPost :posts="anomalousGroupStore.posts" :isAbnormal="true" :moduleName="moduleName"></GroupPost>
<GroupPost
:posts="anomalousGroupStore.posts"
:isAbnormal="true"
:moduleName="moduleName"
></GroupPost>
</div>
</div>
<div class="right-container">
<div class="anlysisPanel">
<AnomalousContentInfo :contentList="anomalousGroupStore.abnormalContentList"></AnomalousContentInfo>
<AnomalousContentInfo
:contentList="anomalousGroupStore.abnormalContentList"
></AnomalousContentInfo>
</div>
<div class="cloudWords">
<WordsCloud :wordsCloudList="anomalousGroupStore.wordCloudData"></WordsCloud>
@ -63,43 +70,36 @@
</template>
<script setup>
import { onMounted, ref } from "vue";
import { onMounted, 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 { Icon } from "@iconify/vue";
import { Icon } from "@iconify/vue"
import GroupGraph from "../component/groupGraph.vue"
import WordsCloud from "../component/wordsCloud.vue"
import GroupPanel from "./components/groupPanel.vue"
import GroupPost from "../component/groupPost.vue"
import GroupChart from "../component/groupChart.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 handleChangeXAxis = (utcTime) => {
console.log("点击时间轴:",utcTime)
//
// --
}
//
const postDialog = ref(false);
const postDialog = ref(false)
//
const currentPostPost = ref(null);
const currentPostPost = ref(null)
const handleOpenPostDialog = (post) => {
postDialog.value = true;
currentPostPost.value = post;
};
postDialog.value = true
currentPostPost.value = post
}
onMounted(async () => {
await anomalousGroupStore.initializeAbnormalGroupTimeLine()

View File

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

View File

@ -33,6 +33,7 @@ const { timeList, graph } = storeToRefs(props.store)
let isPlay = ref(false)
let graphVis = null
let forceSimulator = null
const storeId = props.store.$id
let currentSelectNode = ref(null)
const defaultConfig = {
node: {
@ -80,9 +81,7 @@ const registCustomePaintFunc = () => {
}
//
const handlePointerDown = (time) => {
console.log("检查点击1",time)
const utcTime = convertToUtcIsoString(time)
console.log("检查点击2",utcTime)
emit("click:pointerDownAndSlide", utcTime)
}
@ -175,6 +174,29 @@ const clusterAnalyze = () => {
group.smoothPath = false //线
})
graphVis.autoGroupLayout(graphVis.nodes)
function handleGroupDiscoveryDiff() {
console.log(storeId)
}
function handleGroupStructureDiff() {
console.log(storeId)
}
function handleGroupMemberDiff() {
console.log(storeId)
}
function handleAnomalousGroup() {
console.log(storeId)
}
new Map([
["groupDiscovery", () => handleGroupDiscoveryDiff()],
["groupStructure", () => handleGroupStructureDiff()],
["groupMember", () => handleGroupMemberDiff()],
["anomalousGroup", () => handleAnomalousGroup()]
]).get(storeId)?.()
// graphVis.selectedEdge(graphVis.links[0])
}

View File

@ -1,35 +1,35 @@
<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/groupMember/group-member-user-list-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 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/groupMember/group-member-user-list-title.png"
alt=""
/>
<div class="group-item-title-type">{{ group.type }}</div>
</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, watch, nextTick } from "vue";
import * as echarts from "echarts";
import { defineProps, ref, onMounted, onUnmounted, watch, nextTick } from "vue"
import * as echarts from "echarts"
import nodeHoverImg from "@/assets/images/nodeHover.png"
//
const isEqual = (arr1, arr2) => {
if (arr1.length !== arr2.length) return false;
return arr1.every((val, index) => val === arr2[index]);
};
if (arr1.length !== arr2.length) return false
return arr1.every((val, index) => val === arr2[index])
}
const props = defineProps({
groupList: {
@ -40,71 +40,78 @@ const props = defineProps({
type: String,
default: ""
}
});
})
const groupList = ref(props.groupList);
const groupList = ref(props.groupList)
// groupList
const prevGroupList = ref([]);
const prevGroupList = ref([])
// groupList
watch(() => props.groupList, (newVal) => {
//
const hasChanged = newVal.length !== prevGroupList.value.length ||
newVal.some((group, index) => {
const prevGroup = prevGroupList.value[index];
return prevGroup?.id !== group.id ||
prevGroup?.type !== group.type ||
prevGroup?.focusedTopic !== group.focusedTopic ||
!isEqual(prevGroup?.value || [], group.value || []);
});
watch(
() => props.groupList,
(newVal) => {
//
const hasChanged =
newVal.length !== prevGroupList.value.length ||
newVal.some((group, index) => {
const prevGroup = prevGroupList.value[index]
return (
prevGroup?.id !== group.id ||
prevGroup?.type !== group.type ||
prevGroup?.focusedTopic !== group.focusedTopic ||
!isEqual(prevGroup?.value || [], group.value || [])
)
})
if (hasChanged) {
groupList.value = newVal;
prevGroupList.value = JSON.parse(JSON.stringify(newVal));
if (hasChanged) {
groupList.value = newVal
prevGroupList.value = JSON.parse(JSON.stringify(newVal))
// 使nextTickDOM
nextTick(() => {
updateCharts(groupList.value);
});
}
}, { deep: true });
// 使nextTickDOM
nextTick(() => {
updateCharts(groupList.value)
})
}
},
{ deep: true }
)
//
const chartInstances = new Map();
const chartInstances = new Map()
// initChart
const updateCharts = (groupList) => {
groupList.forEach(group => {
const chartDom = document.getElementById(`group-chart-${group.id}`);
groupList.forEach((group) => {
const chartDom = document.getElementById(`group-chart-${group.id}`)
if (chartDom && group.value) {
//
if (chartInstances.has(group.id)) {
//
const myChart = chartInstances.get(group.id);
const myChart = chartInstances.get(group.id)
// maxValue
const firstElement = group.value[0];
const allEqual = group.value.every(item => item === firstElement);
let maxValue = 0;
if(allEqual){
maxValue = parseFloat(firstElement) + 40;
}else{
maxValue = Math.ceil(Math.max(...group.value.map(item => parseFloat(item))));
const firstElement = group.value[0]
const allEqual = group.value.every((item) => item === firstElement)
let maxValue = 0
if (allEqual) {
maxValue = parseFloat(firstElement) + 40
} else {
maxValue = Math.ceil(Math.max(...group.value.map((item) => parseFloat(item))))
}
//
myChart.setOption({
radar: {
indicator: [
{ name: '成长期', max: maxValue },
{ name: '收缩期', max: maxValue },
{ name: '合并期', max: maxValue },
{ name: '分裂期', max: maxValue },
{ name: "成长期", max: maxValue },
{ name: "收缩期", max: maxValue },
{ name: "合并期", max: maxValue },
{ name: "分裂期", max: maxValue }
]
},
series: [
{
data: [
{
value: group.value || [0,0,0,0],
value: group.value || [0, 0, 0, 0],
symbol: "circle",
symbolSize: 5,
itemStyle: {
@ -122,20 +129,20 @@ const updateCharts = (groupList) => {
]
}
]
});
})
} else {
//
const myChart = echarts.init(chartDom);
chartInstances.set(group.id, myChart);
const myChart = echarts.init(chartDom)
chartInstances.set(group.id, myChart)
// maxValue
const firstElement = group.value[0];
const allEqual = group.value.every(item => item === firstElement);
let maxValue = 0;
if(allEqual){
maxValue = parseFloat(firstElement) + 20;
}else{
maxValue = Math.ceil(Math.max(...group.value.map(item => parseFloat(item))));
const firstElement = group.value[0]
const allEqual = group.value.every((item) => item === firstElement)
let maxValue = 0
if (allEqual) {
maxValue = parseFloat(firstElement) + 20
} else {
maxValue = Math.ceil(Math.max(...group.value.map((item) => parseFloat(item))))
}
const option = {
@ -166,49 +173,49 @@ const updateCharts = (groupList) => {
<div >合并${(parseFloat(params.data.value[2]) - 20).toFixed(2)}</div>
<div >分裂${(parseFloat(params.data.value[3]) - 20).toFixed(2)}</div>
</div>
</div>`;
</div>`
}
},
radar: {
startAngle: 135,
indicator: [
{ name: '成长期', max: maxValue },
{ name: '收缩期', max: maxValue },
{ name: '合并期', max: maxValue },
{ name: '分裂期', max: maxValue },
{ name: "成长期", max: maxValue },
{ name: "收缩期", max: maxValue },
{ name: "合并期", max: maxValue },
{ name: "分裂期", max: maxValue }
],
shape: 'circle',
shape: "circle",
splitNumber: 5,
min: 0,
alignTicks: false,
axisName: {
color: '#94C1EC',
fontSize: 14,
color: "#94C1EC",
fontSize: 14
},
axisLine: {
lineStyle: {
type: 'dashed',
color: 'rgba(35, 60, 92, 0.75)'
type: "dashed",
color: "rgba(35, 60, 92, 0.75)"
}
},
splitLine: {
lineStyle: {
color: 'rgba(37, 50, 67, 1)'
color: "rgba(37, 50, 67, 1)"
}
},
splitArea: {
show: true,
areaStyle: {
color: ['rgba(10, 26, 47, 0.3)', 'rgba(10, 26, 47, 0.5)']
color: ["rgba(10, 26, 47, 0.3)", "rgba(10, 26, 47, 0.5)"]
}
},
}
},
series: [
{
type: 'radar',
type: "radar",
data: [
{
value: group.value || [0,0,0,0],
value: group.value || [0, 0, 0, 0],
symbol: "circle",
symbolSize: 5,
itemStyle: {
@ -226,40 +233,38 @@ const updateCharts = (groupList) => {
]
}
]
};
}
myChart.setOption(option);
myChart.setOption(option)
}
}
});
};
})
}
onMounted(() => {
console.log("props.groupList:", props.groupList);
prevGroupList.value = JSON.parse(JSON.stringify(props.groupList));
prevGroupList.value = JSON.parse(JSON.stringify(props.groupList))
// 使nextTickDOM
nextTick(() => {
updateCharts(props.groupList);
});
updateCharts(props.groupList)
})
window.addEventListener('resize', handleResize);
});
window.addEventListener("resize", handleResize)
})
const handleResize = () => {
chartInstances.forEach(chart => {
chart.resize();
});
};
chartInstances.forEach((chart) => {
chart.resize()
})
}
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
chartInstances.forEach(chart => {
chart.dispose();
});
chartInstances.clear();
});
window.removeEventListener("resize", handleResize)
chartInstances.forEach((chart) => {
chart.dispose()
})
chartInstances.clear()
})
</script>
<style lang="less">

View File

@ -1,5 +1,4 @@
<template>
<div class="layout-container">
<!-- 头部 -->
<div class="top-container"></div>
@ -76,60 +75,47 @@
</template>
<script setup>
import { onMounted, ref } from "vue";
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";
import GroupChart from "../component/groupChart.vue";
import GroupPanel from "./components/groupPanel.vue"
import GroupPost from "../component/groupPost.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
import WordsCloud from "../component/wordsCloud.vue";
import WordsCloud from "../component/wordsCloud.vue"
import userPanelTitleImg from "@/assets/images/groupMember/evolutionAnalysisListTitle.png"
import groupAnalsisTitleImg from "@/assets/images/groupMember/groupEvolutionAnalsisTitleImg.png"
import { Icon } from "@iconify/vue";
import { useGroupMemberStore } from "@/store/groupEvolution/index.js";
import { Icon } from "@iconify/vue"
import { useGroupMemberStore } from "@/store/groupEvolution/index.js"
const groupMemberStore = useGroupMemberStore();
const groupMemberStore = useGroupMemberStore()
const moduleName = "群体成员演化分析";
const moduleName = "群体成员演化分析"
//
const postDialog = ref(false);
const postDialog = ref(false)
//
const currentPostPost = ref(null);
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) //
groupMemberStore.initialGraphByUtcTime(utcTime) //
}
const handleOpenPostDialog = (post) => {
postDialog.value = true;
currentPostPost.value = post;
};
postDialog.value = true
currentPostPost.value = post
}
onMounted(async () => {
await groupMemberStore.initializeGroupMemberTimeLine()
console.log("初始化成员演化信息表");
await groupMemberStore.initializeGroupList()
console.log("初始化后的群体成员信息表:",groupMemberStore.groupList);
await groupMemberStore.initializeGroupMemberChart()
console.log("初始化后的全局群体成员演化图:");
await groupMemberStore.initializeGroupMemberEvolutionAnalysisChart()
console.log("初始化后的群体成员演化分析图:", groupMemberStore.chartsData);
await groupMemberStore.initialGraphByUtcTime() //
})
</script>

View File

@ -14,12 +14,7 @@
</div>
<div class="group-item-statistics">
<div class="statistics-item">
<el-tooltip
class="box-item"
effect="dark"
content="内部密度"
placement="bottom-end"
>
<el-tooltip class="box-item" effect="dark" content="内部密度" placement="bottom-end">
<div class="statistics-item-name">内部</div>
</el-tooltip>
<div class="statistics-item-value">
@ -28,24 +23,67 @@
<!-- 轨道中的方块容器 -->
<div class="track-squares">
<div class="square-container">
<div class="square-text" :class="{ 'hidden': !(group.innerNum < 0), 'highlightfont': group.innerNum < 0 }">{{ group.innerNum }}<span>%</span></div>
<div class="square" :class="{ 'highlight': group.innerNum < 0 }"></div>
<div class="square-text" :class="{ 'highlightfont': group.innerNum < 0 }">衰退期</div>
<div
class="square-text"
:class="{ hidden: !(group.innerNum < 0), highlightfont: group.innerNum < 0 }"
>
{{ group.innerNum }}<span>%</span>
</div>
<div class="square" :class="{ highlight: group.innerNum < 0 }"></div>
<div class="square-text" :class="{ highlightfont: group.innerNum < 0 }">
衰退期
</div>
</div>
<div class="square-container">
<div class="square-text" :class="{ 'hidden': !(group.innerNum === 0), 'highlightfont': group.innerNum === 0 }">{{ group.innerNum }}<span>%</span></div>
<div class="square" :class="{ 'highlight': group.innerNum === 0 }"></div>
<div class="square-text" :class="{ 'highlightfont': group.innerNum === 0 }">稳定期</div>
<div
class="square-text"
:class="{
hidden: !(group.innerNum === 0),
highlightfont: group.innerNum === 0
}"
>
{{ group.innerNum }}<span>%</span>
</div>
<div class="square" :class="{ highlight: group.innerNum === 0 }"></div>
<div class="square-text" :class="{ highlightfont: group.innerNum === 0 }">
稳定期
</div>
</div>
<div class="square-container">
<div class="square-text" :class="{ 'hidden': !(group.innerNum > 0 && group.innerNum <= 100), 'highlightfont': group.innerNum > 0 && group.innerNum <= 100 }">{{ group.innerNum }}<span>%</span></div>
<div class="square" :class="{ 'highlight': group.innerNum > 0 && group.innerNum <= 100 }"></div>
<div class="square-text" :class="{ 'highlightfont': group.innerNum > 0 && group.innerNum <= 100 }">增长期</div>
<div
class="square-text"
:class="{
hidden: !(group.innerNum > 0 && group.innerNum <= 100),
highlightfont: group.innerNum > 0 && group.innerNum <= 100
}"
>
{{ group.innerNum }}<span>%</span>
</div>
<div
class="square"
:class="{ highlight: group.innerNum > 0 && group.innerNum <= 100 }"
></div>
<div
class="square-text"
:class="{ highlightfont: group.innerNum > 0 && group.innerNum <= 100 }"
>
增长期
</div>
</div>
<div class="square-container">
<div class="square-text" :class="{ 'hidden': !(group.innerNum > 100), 'highlightfont': group.innerNum > 100 }">{{ group.innerNum }}<span>%</span></div>
<div class="square" :class="{ 'highlight': group.innerNum > 100 }"></div>
<div class="square-text" :class="{ 'highlightfont': group.innerNum > 100 }">繁荣期</div>
<div
class="square-text"
:class="{
hidden: !(group.innerNum > 100),
highlightfont: group.innerNum > 100
}"
>
{{ group.innerNum }}<span>%</span>
</div>
<div class="square" :class="{ highlight: group.innerNum > 100 }"></div>
<div class="square-text" :class="{ highlightfont: group.innerNum > 100 }">
繁荣期
</div>
</div>
</div>
</div>
@ -53,12 +91,7 @@
</div>
</div>
<div class="statistics-item">
<el-tooltip
class="box-item"
effect="dark"
content="外部扩展"
placement="bottom-end"
>
<el-tooltip class="box-item" effect="dark" content="外部扩展" placement="bottom-end">
<div class="statistics-item-name">外部</div>
</el-tooltip>
<div class="statistics-item-value">
@ -67,24 +100,67 @@
<!-- 轨道中的方块容器 -->
<div class="track-squares">
<div class="square-container">
<div class="square-text" :class="{ 'hidden': !(group.outerNum < 0), 'highlightfont': group.outerNum < 0 }">{{ group.outerNum }}<span>%</span></div>
<div class="square" :class="{ 'highlight': group.outerNum < 0 }"></div>
<div class="square-text" :class="{ 'highlightfont': group.outerNum < 0 }">衰退期</div>
<div
class="square-text"
:class="{ hidden: !(group.outerNum < 0), highlightfont: group.outerNum < 0 }"
>
{{ group.outerNum }}<span>%</span>
</div>
<div class="square" :class="{ highlight: group.outerNum < 0 }"></div>
<div class="square-text" :class="{ highlightfont: group.outerNum < 0 }">
衰退期
</div>
</div>
<div class="square-container">
<div class="square-text" :class="{ 'hidden': !(group.outerNum === 0), 'highlightfont': group.outerNum === 0 }">{{ group.outerNum }}<span>%</span></div>
<div class="square" :class="{ 'highlight': group.outerNum === 0 }"></div>
<div class="square-text" :class="{ 'highlightfont': group.outerNum === 0 }">稳定期</div>
<div
class="square-text"
:class="{
hidden: !(group.outerNum === 0),
highlightfont: group.outerNum === 0
}"
>
{{ group.outerNum }}<span>%</span>
</div>
<div class="square" :class="{ highlight: group.outerNum === 0 }"></div>
<div class="square-text" :class="{ highlightfont: group.outerNum === 0 }">
稳定期
</div>
</div>
<div class="square-container">
<div class="square-text" :class="{ 'hidden': !(group.outerNum > 0 && group.outerNum <= 100), 'highlightfont': group.outerNum > 0 && group.outerNum <= 100 }">{{ group.outerNum }}<span>%</span></div>
<div class="square" :class="{ 'highlight': group.outerNum > 0 && group.outerNum <= 100 }"></div>
<div class="square-text" :class="{ 'highlightfont': group.outerNum > 0 && group.outerNum <= 100 }">增长期</div>
<div
class="square-text"
:class="{
hidden: !(group.outerNum > 0 && group.outerNum <= 100),
highlightfont: group.outerNum > 0 && group.outerNum <= 100
}"
>
{{ group.outerNum }}<span>%</span>
</div>
<div
class="square"
:class="{ highlight: group.outerNum > 0 && group.outerNum <= 100 }"
></div>
<div
class="square-text"
:class="{ highlightfont: group.outerNum > 0 && group.outerNum <= 100 }"
>
增长期
</div>
</div>
<div class="square-container">
<div class="square-text" :class="{ 'hidden': !(group.outerNum > 100), 'highlightfont': group.outerNum > 100 }">{{ group.outerNum }}<span>%</span></div>
<div class="square" :class="{ 'highlight': group.outerNum > 100 }"></div>
<div class="square-text" :class="{ 'highlightfont': group.outerNum > 100 }">繁荣期</div>
<div
class="square-text"
:class="{
hidden: !(group.outerNum > 100),
highlightfont: group.outerNum > 100
}"
>
{{ group.outerNum }}<span>%</span>
</div>
<div class="square" :class="{ highlight: group.outerNum > 100 }"></div>
<div class="square-text" :class="{ highlightfont: group.outerNum > 100 }">
繁荣期
</div>
</div>
</div>
</div>
@ -111,9 +187,7 @@ const props = defineProps({
}
})
onMounted(() => {
console.log(props.groupList)
})
onMounted(() => {})
</script>
<style scoped lang="less">
@ -184,7 +258,7 @@ onMounted(() => {
white-space: nowrap; //
padding-top: -5px;
padding-right: 5px;
color: #94C1EC;
color: #94c1ec;
}
.statistics-item-value {
width: 100%;
@ -194,7 +268,7 @@ onMounted(() => {
.track {
width: 262px;
height: 8px;
background-image: url('@/assets/images/groupStructure/track.png');
background-image: url("@/assets/images/groupStructure/track.png");
background-size: cover;
background-repeat: no-repeat;
position: relative; /* 设置为相对定位,使子元素可以绝对定位 */
@ -213,26 +287,26 @@ onMounted(() => {
align-items: center;
.square-text {
font-size: 14px;
color: #94C1EC;
color: #94c1ec;
line-height: 1;
}
.hidden {
visibility: hidden;
}
.highlightfont {
color: #30CC5C;
color: #30cc5c;
}
.square {
width: 12px;
height: 12px;
background-image: url('@/assets/images/groupStructure/track-fangkuai-default.png');
background-image: url("@/assets/images/groupStructure/track-fangkuai-default.png");
background-size: cover;
background-repeat: no-repeat;
margin: 2px 0; /* 为文字和滑块之间添加间距 */
}
.highlight {
background-image: url('@/assets/images/groupStructure/track-fangkuai-highlight.png');
background-image: url("@/assets/images/groupStructure/track-fangkuai-highlight.png");
}
}
}

View File

@ -95,23 +95,20 @@ const moduleName = "群体结构演化分析"
const postDialog = ref(false)
//
const currentPostPost = ref(null);
const currentPostPost = ref(null)
const handleChangeXAxis = (utcTime) => {
console.log("点击时间轴:",utcTime)
//
groupStructureStore.initializeStructuralEvolutionAnalysisInfoList(utcTime)
// --
groupStructureStore.initializeStructuralPost(utcTime)
//
groupStructureStore.initialGraphByUtcTime(utcTime)
}
const handleOpenPostDialog = (post) => {
postDialog.value = true
currentPostPost.value = post
console.log(currentPostPost.value)
}
onMounted(async () => {
@ -125,11 +122,8 @@ onMounted(async () => {
await groupStructureStore.initializeStructuralEvolutionAnalysisChart()
// --
await groupStructureStore.initializeStructuralPost()
console.log(groupStructureStore.posts)
//
await groupStructureStore.initialGraphByUtcTime()
})
</script>