SocialNetworks_duan/src/store/groupEvolution/index.js

1318 lines
40 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { defineStore } from "pinia"
import nodePrefix from "@/assets/images/groupEvolution/node-prefix.png"
import edgePrefix from "@/assets/images/groupEvolution/edge-prefix.png"
import splitImg from "@/assets/images/groupMember/splitImg.png"
import mergeImg from "@/assets/images/groupMember/mergeImg.png"
import shrinkImg from "@/assets/images/groupMember/shrinkImg.png"
import expamdImg from "@/assets/images/groupMember/expamdImg.png"
import defaultAvatar from "@/assets/images/avatar/default.png"
import {
getGroupEvolutionGroupList,
getGroupEvolutionGroupScaleChart,
getGroupEvolutionTimeLine,
getPostByUtcTime,
getGroupMemberInfo,
getStructuralEvolutionChart,
getStructuralEvolutionAnalysisChart,
getStructuralEvolutionAnalysisTimeLine,
getStructuralEvolutionAnalysisInfoList,
getStructuralEvolutionAnalysisPost,
getGroupMemberInfoList,
getGroupMemberTimeLine,
getGroupMemberChart,
getGroupMemberEvolutionInfoByTime,
getGroupMemberEvolutionAnalysisChart,
getStructuralEvolutionAnalysisGraph,
getGroupMemberEvolutionAnalysisGraph,
// 4.异常群体捕捉
getAbnormalGroupTimeLine,
getAbnormalGroupList,
getAbnormalGroupInteractionChart,
getAbnormalGroupBehaviorPosts,
getAbnormalGroupBehaviorDetail,
getRelationGraphByUtcTime
} from "@/service/api/groupEvolution"
import { TansTimestamp, utcStringToHHMMSS, getMaxCeiled, parsePercentage } from "@/utils/transform"
import groupDiscoveryTitle from "@/assets/images/groupEvolution/graph-title.png"
import groupStructTitle from "@/assets/images/head/evolutionStruct-title.png"
import groupAnalysis from "@/assets/images/head/groupAnlysis-title.png"
import groupAbnormal from "@/assets/images/head/groupAnlysis-title.png"
export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
state: () => ({
groupList: [],
graphTitle: groupDiscoveryTitle,
chartData: {},
timeList: [],
graph: {},
groupMemberInfo: {},
chartsData: {
topSelfMedia: {
xAxis: [
"15:57:46",
"16:57:55",
"17:57:32",
"18:58:03",
"19:58:03",
"20:58:04",
"21:57:47",
"22:58:12"
],
yAxis: [0.5, 1.0, 1.5, 2.0, 2.5],
data: [1.0, 0.99, 1.0, 1.0, 1.01, 2.03, 1.2, 0.99]
},
officialMedia: {
xAxis: [
"15:57:46",
"16:57:55",
"17:57:32",
"18:58:03",
"19:58:03",
"20:58:04",
"21:57:47",
"22:58:12"
],
yAxis: [0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2],
data: [1.0, 0.99, 1.0, 1.0, 1.01, 2.03, 1.2, 0.99]
},
ordinaryMedia: {
xAxis: [
"15:57:46",
"16:57:55",
"17:57:32",
"18:58:03",
"19:58:03",
"20:58:04",
"21:57:47",
"22:58:12"
],
yAxis: [0, 1.0, 2.0, 3.0],
data: [1.08, 2.54, 1.47, 1.03, 0.98, 0.99, 1.0, 1.12]
}
},
wordCloudData: [
{
text: "主权权益",
top: 115.5,
left: 215.5,
width: 80,
height: 22,
fontSize: 13,
opacity: 1
},
{
text: "局座预言",
top: 80,
left: 69.5,
width: 73,
height: 22,
fontSize: 12,
opacity: 0.7
},
{
text: "吃瓜",
top: 72.5,
left: 132.5,
width: 50,
height: 22,
fontSize: 12,
opacity: 1
},
{
text: "中国海警",
top: 140,
left: 212.5,
width: 130,
height: 40,
fontSize: 22,
opacity: 0.8
},
{
text: "菲律宾",
top: 150,
left: 50,
width: 81,
height: 22,
fontSize: 14,
opacity: 0.8
},
{
text: "手指",
top: 200.5,
left: 38.5,
width: 73,
height: 19,
fontSize: 12,
opacity: 0.7
},
{
text: "装甲船",
top: 50,
left: 160.5,
width: 73,
height: 19,
fontSize: 12,
opacity: 0.7
},
{
text: "登检",
top: 211.5,
left: 143.5,
width: 50,
height: 19,
fontSize: 12,
opacity: 1
},
{ text: "执法", top: 176.5, left: 15.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 },
{ text: "现场画面", top: 110, left: 26, width: 90, 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 },
{
text: "大刀长矛",
top: 186,
left: 200.5,
width: 70,
height: 19,
fontSize: 12,
opacity: 0.8
}
],
posts: []
}),
actions: {
//获取群体列表数据
async initializeGroupList(time = "") {
const res = await getGroupEvolutionGroupList(time)
if (res.code != 200) return
const iconMap = {
节点数: nodePrefix,
连边数: edgePrefix
}
this.groupList = res.data
this.groupList.forEach((item) => {
item.list = item.list.map((statistic) => ({
...statistic,
iconImg: iconMap[statistic.name]
}))
})
},
//获取群体规模演化图数据
async initializeGroupScaleChart() {
const res = await getGroupEvolutionGroupScaleChart()
if (res.code != 200) return
let resultObj = {}
const themeMap = {
群体一: "#00d6da",
群体二: "#fddc33",
群体三: "#32b6fb"
}
resultObj["xAxisData"] = res.data.timeList.map((item) => TansTimestamp(item, "HH:mm:ss"))
resultObj["yAxisRange"] = res.data.scale
resultObj["seriesList"] = []
// 定义明确的群体顺序
const groupOrder = ["群体一", "群体二", "群体三"]
groupOrder.forEach((key) => {
if (res.data.data[key]) {
resultObj["seriesList"].push({
name: key,
themeColor: themeMap[key],
data: res.data.data[key]
})
}
})
this.chartData = resultObj
},
//获取时间轴参数
async initialGraphTimestamp() {
const res = await getGroupEvolutionTimeLine()
if (res.code != 200) return
this.timeList = res.data
},
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 initialPostByUtcTime(utcTime) {
const res = await getPostByUtcTime(utcTime)
if (res.code != 200) return
this.posts = res.data
},
// 悬浮显示群体中的成员
async initialGroupMemberInfo(time = "2024-06-19T07:57:46Z") {
const res = await getGroupMemberInfo(time)
if (res.code != 200) return
const groupOne = []
const groupTwo = []
const groupThree = []
res.data.forEach((item) => {
if (item.groupId == 0) {
groupOne.push(item.userId)
} else if (item.groupId == 1) {
groupTwo.push(item.userId)
} else if (item.groupId == 6) {
groupThree.push(item.userId)
}
})
this.groupMemberInfo = {
0: groupOne,
1: groupTwo,
6: groupThree
}
}
},
persist: true // 开启持久化
})
export const useGroupStructureStore = defineStore("groupStructure", {
state: () => ({
groupList: [],
groupMemberInfo: {},
graphTitle: groupStructTitle,
graph: {},
timeList: [],
chartData: {},
chartsData: {},
wordCloudData: [
{
text: "主权权益",
top: 115.5,
left: 215.5,
width: 80,
height: 22,
fontSize: 13,
opacity: 1
},
{
text: "局座预言",
top: 80,
left: 69.5,
width: 73,
height: 22,
fontSize: 12,
opacity: 0.7
},
{
text: "吃瓜",
top: 72.5,
left: 132.5,
width: 50,
height: 22,
fontSize: 12,
opacity: 1
},
{
text: "中国海警",
top: 140,
left: 212.5,
width: 130,
height: 40,
fontSize: 22,
opacity: 0.8
},
{
text: "菲律宾",
top: 150,
left: 50,
width: 81,
height: 22,
fontSize: 14,
opacity: 0.8
},
{
text: "手指",
top: 200.5,
left: 38.5,
width: 73,
height: 19,
fontSize: 12,
opacity: 0.7
},
{
text: "装甲船",
top: 50,
left: 160.5,
width: 73,
height: 19,
fontSize: 12,
opacity: 0.7
},
{
text: "登检",
top: 211.5,
left: 143.5,
width: 50,
height: 19,
fontSize: 12,
opacity: 1
},
{ text: "执法", top: 176.5, left: 15.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 },
{ text: "现场画面", top: 110, left: 26, width: 90, 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 },
{
text: "大刀长矛",
top: 186,
left: 200.5,
width: 70,
height: 19,
fontSize: 12,
opacity: 0.8
}
],
posts: [
{
id: 1,
time: "2024-01-04 0:03:16",
groupCategory: "群体一",
innerEdgeAddCount: 8,
outerEdgeAddCount: 2
},
{
id: 2,
time: "2024-02-03 12:58:53",
groupCategory: "群体一",
innerEdgeAddCount: 8,
outerEdgeAddCount: 2
},
{
id: 3,
time: "2024-02-22 17:13:44",
groupCategory: "群体二",
innerEdgeAddCount: 13,
outerEdgeAddCount: 3
},
{
id: 4,
time: "2024-02-23 17:54:46",
groupCategory: "群体三",
innerEdgeAddCount: 1,
outerEdgeAddCount: 2
},
{
id: 5,
time: "2024-03-14 09:58:12",
groupCategory: "群体三",
innerEdgeAddCount: 1,
outerEdgeAddCount: 2
},
{
id: 6,
time: "2024-03-23 21:20:40",
groupCategory: "群体三",
innerEdgeAddCount: 1,
outerEdgeAddCount: 2
},
{
id: 7,
time: "2024-03-23 21:42:36",
groupCategory: "群体三",
innerEdgeAddCount: 1,
outerEdgeAddCount: 2
},
{
id: 8,
time: "2024-04-06 18:17:30",
groupCategory: "群体三",
innerEdgeAddCount: 1,
outerEdgeAddCount: 2
},
{
id: 9,
time: "2024-04-06 19:19:50",
groupCategory: "群体三",
innerEdgeAddCount: 1,
outerEdgeAddCount: 2
},
{
id: 10,
time: "2024-05-16 00:22:18",
groupCategory: "群体三",
innerEdgeAddCount: 1,
outerEdgeAddCount: 2
}
]
}),
actions: {
// 初始化timeList
async initializeStructuralEvolutionAnalysisTimeLine() {
const res = await getStructuralEvolutionAnalysisTimeLine()
this.timeList = res.data
},
// 初始化群体结构演化分析信息列表
async initializeStructuralEvolutionAnalysisInfoList(time = "2024-06-19T07:57:46Z") {
const res = await getStructuralEvolutionAnalysisInfoList(time)
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)
}))
},
// 悬浮显示群体中的成员
async initialGroupMemberInfo(time = "2024-06-19T07:57:46Z") {
const res = await getGroupMemberInfo(time)
if (res.code != 200) return
const groupOne = []
const groupTwo = []
const groupThree = []
res.data.forEach((item) => {
if (item.groupId == 0) {
groupOne.push(item.userId)
} else if (item.groupId == 1) {
groupTwo.push(item.userId)
} else if (item.groupId == 6) {
groupThree.push(item.userId)
}
})
this.groupMemberInfo = {
0: groupOne,
1: groupTwo,
6: groupThree
}
},
// 初始化全局连通性演化图--左下方
async initializeStructuralEvolutionChart() {
const res = await getStructuralEvolutionChart()
this.chartData = {
xAxisData: res.data.xaxisData.map((item) => utcStringToHHMMSS(item)),
seriesList: [
{
name: "",
data: res.data.seriesList[0].data,
themeColor: "#2AB8FD"
}
],
yAxisRange: { min: 0, max: 1, interval: 0.2 }
}
},
// 初始化群体结构演化分析图表--右上方
async initializeStructuralEvolutionAnalysisChart() {
const res = await getStructuralEvolutionAnalysisChart()
const topSelfMedia = res.data.topSelfMedia.map((item) => ({
id: item.id,
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {
min: item.name === "内部密度指数演化" ? 20.0 : 0,
max:
item.name === "内部密度指数演化"
? 20.5
: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval:
item.name === "内部密度指数演化" ? 0.1 : 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) => ({
id: item.id,
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {
min: item.name === "内部密度指数演化" ? 20.0 : 0,
max:
item.name === "内部密度指数演化"
? 20.5
: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval:
item.name === "内部密度指数演化" ? 0.1 : 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) => ({
id: item.id,
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {
min: item.name === "内部密度指数演化" ? 20.0 : 0,
max:
item.name === "内部密度指数演化"
? 20.5
: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval:
item.name === "内部密度指数演化" ? 0.1 : Math.ceil(item.chart.yaxisRange.max / 5)
},
seriesList: item.chart.seriesList.map((item) => ({
data: item.data,
name: item.name,
themeColor: "#2AB8FD"
}))
}
}))
this.chartsData = {
topSelfMedia,
officalMedia,
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 getStructuralEvolutionAnalysisGraph(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
}
})
this.graph["newLinks"] = res.data?.newAddRelation ?? []
},
// 初始化群体结构演化分析的群体演化信息-中下-随时间轴变化
async initializeStructuralPost(time = "2024-06-19T07:57:46Z") {
const res = await getStructuralEvolutionAnalysisPost(time)
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
}))
}
},
persist: true // 开启持久化
})
export const useGroupMemberStore = defineStore("groupMember", {
state: () => ({
groupList: [],
groupMemberInfo: {},
graphTitle: groupAnalysis,
timeList: [],
graph: {},
chartData: {},
chartsData: {},
posts: [],
wordCloudData: [
{
text: "主权权益",
top: 115.5,
left: 215.5,
width: 80,
height: 22,
fontSize: 13,
opacity: 1
},
{
text: "局座预言",
top: 80,
left: 69.5,
width: 73,
height: 22,
fontSize: 12,
opacity: 0.7
},
{
text: "吃瓜",
top: 72.5,
left: 132.5,
width: 50,
height: 22,
fontSize: 12,
opacity: 1
},
{
text: "中国海警",
top: 140,
left: 212.5,
width: 130,
height: 40,
fontSize: 22,
opacity: 0.8
},
{
text: "菲律宾",
top: 150,
left: 50,
width: 81,
height: 22,
fontSize: 14,
opacity: 0.8
},
{
text: "手指",
top: 200.5,
left: 38.5,
width: 73,
height: 19,
fontSize: 12,
opacity: 0.7
},
{
text: "装甲船",
top: 50,
left: 160.5,
width: 73,
height: 19,
fontSize: 12,
opacity: 0.7
},
{
text: "登检",
top: 211.5,
left: 143.5,
width: 50,
height: 19,
fontSize: 12,
opacity: 1
},
{ text: "执法", top: 176.5, left: 15.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 },
{ text: "现场画面", top: 110, left: 26, width: 90, 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 },
{
text: "大刀长矛",
top: 186,
left: 200.5,
width: 70,
height: 19,
fontSize: 12,
opacity: 0.8
}
]
}),
actions: {
// 获取时间轴
async initializeGroupMemberTimeLine() {
const res = await getGroupMemberTimeLine()
this.timeList = res.data
},
// 群体成员演化信息列表-左上
async initializeGroupList(time = "2024-06-19T07:57:46Z") {
const res = await getGroupMemberInfoList(time)
const groupList = res.data.map((item) => ({
id: item.id,
type: item.type,
focusedTopic: item.focusedTopic,
value: item.value.map((item) => item.toFixed(2))
// value: item.value.map(item => (item * 100 + 20).toFixed(2))
}))
this.groupList = groupList
},
// 悬浮显示群体中的成员
async initialGroupMemberInfo(time = "2024-06-19T07:57:46Z") {
const res = await getGroupMemberInfo(time)
if (res.code != 200) return
const groupOne = []
const groupTwo = []
const groupThree = []
res.data.forEach((item) => {
if (item.groupId == 0) {
groupOne.push(item.userId)
} else if (item.groupId == 1) {
groupTwo.push(item.userId)
} else if (item.groupId == 6) {
groupThree.push(item.userId)
}
})
this.groupMemberInfo = {
0: groupOne,
1: groupTwo,
6: groupThree
}
},
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
},
async initializeGroupMemberEvolutionAnalysisChart() {
const res = await getGroupMemberEvolutionAnalysisChart()
const themeColors = {
分裂演化: "#2AB8FD",
合并演化: "#02D7DA",
收缩演化: "#FFDA09",
扩展演化: "#EB57B0"
}
const topSelfMedia = res.data.topSelfMedia.map((item) => ({
id: item.id,
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {
min: item.name === "合并演化" || item.name === "扩展演化" ? 19 : 0,
max:
item.name === "合并演化" || item.name === "扩展演化"
? 21
: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval:
item.name === "合并演化" || item.name === "扩展演化"
? 0.4
: Math.ceil(item.chart.yaxisRange.max / 5)
},
seriesList: item.chart.seriesList.map((item) => ({
data: item.data.map((item) => item.toFixed(2)),
name: item.name,
themeColor: themeColors[item.name]
}))
}
}))
const officalMedia = res.data.officalMedia.map((item) => ({
id: item.id,
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {
min: item.name === "合并演化" || item.name === "扩展演化" ? 19.0 : 0,
max:
item.name === "合并演化" || item.name === "扩展演化"
? 21.0
: Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval:
item.name === "合并演化" || item.name === "扩展演化"
? 0.4
: Math.ceil(item.chart.yaxisRange.max / 5)
},
seriesList: item.chart.seriesList.map((item) => ({
data: item.data.map((item) => item.toFixed(2)),
name: item.name,
themeColor: themeColors[item.name]
}))
}
}))
const ordinaryMedia = res.data.ordinaryMedia.map((item) => ({
id: item.id,
name: item.name,
chart: {
xAxisData: item.chart.xaxisData.map((item) => utcStringToHHMMSS(item)),
yAxisRange: {
min: item.name === "合并演化" ? 19 : 0,
max: item.name === "合并演化" ? 21 : Math.ceil(item.chart.yaxisRange.max / 5) * 5,
interval: item.name === "合并演化" ? 0.4 : Math.ceil(item.chart.yaxisRange.max / 5)
},
seriesList: item.chart.seriesList.map((item) => ({
data: item.data.map((item) => item.toFixed(2)),
name: item.name,
themeColor: themeColors[item.name]
}))
}
}))
this.chartsData = {
topSelfMedia: topSelfMedia,
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 getGroupMemberEvolutionAnalysisGraph(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
}
})
this.graph["newNodes"] = res.data?.newAddUser ?? []
}
},
persist: true // 开启持久化
})
// —— 时间门槛 ——
const T0 = "2024-06-19T07:57:46Z" // 默认渲染出全部节点
const TA = "2024-06-19T08:57:55Z" // A 组异常开始
const TB = "2024-06-19T10:58:03Z" // B 组异常开始
const TC = "2024-06-19T12:58:04Z" // C 组异常开始
export const useAnomalousGroup = defineStore("anomalousGroup", {
state: () => ({
groupList: [],
graph: {},
timeList: [],
graphTitle: groupAbnormal,
wordCloudData: [
{
text: "局座",
top: 115.5,
left: 220.5,
width: 80,
height: 40,
fontSize: 28,
opacity: 1
},
{ text: "折叠屏", top: 160.5, left: 69.5, width: 105, height: 35, fontSize: 20, opacity: 1 },
{
text: "蹬鼻子上脸",
top: 50.5,
left: 132.5,
width: 90,
height: 22,
fontSize: 12,
opacity: 1
},
{
text: "菲律宾",
top: 171.5,
left: 200.5,
width: 81,
height: 22,
fontSize: 14,
opacity: 0.8
},
{
text: "中国海警",
top: 120.5,
left: 30.5,
width: 100,
height: 24,
fontSize: 16,
opacity: 1
},
{
text: "船",
top: 223.5,
left: 230.5,
width: 50,
height: 22,
fontSize: 14,
opacity: 0.8
},
{
text: "斧头",
top: 200.5,
left: 38.5,
width: 40,
height: 19,
fontSize: 12,
opacity: 0.7
},
{
text: "执法",
top: 223.5,
left: 130.5,
width: 60,
height: 19,
fontSize: 12,
opacity: 0.7
},
{
text: "登检",
top: 200.5,
left: 143.5,
width: 60,
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: 20.5, width: 106, 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 } */
],
abnormalContentList: [],
chartData: {
xAxisData: ["t0", "t1", "t2", "t3", "t4", "t5", "t6"],
yAxisRange: { min: 0, max: 5, interval: 1 },
seriesList: [
{
name: "社团组一",
themeColor: "#2AB8FD",
data: [0, 5, 4, 3, 0, 5, 0]
},
{
name: "社团组二",
themeColor: "#02D7DA",
data: [3, 0, 1, 0, 3, 5, 0]
},
{
name: "社团组三",
themeColor: "#FFDA09",
data: [5, 0, 4, 0, 3, 0, 0]
}
]
},
posts: [
{
id: 1,
abnormalGroup: "G02与G07互动方式出现显著异常",
explanation: "持续异常行为已累积显著,疑似某组织突然发动“”信息攻击“或”舆论战“",
firstDiscoverTime: "2024.06.20",
duration: 6,
JS: 0.3,
CUSUM: 6.21,
KS: 0.02
},
{
id: 2,
abnormalGroup: "GO4与G08互动方式出现显著异常",
firstDiscoverTime: "2024.06.23",
duration: 4,
explanation: "疑似“统一指令”或“操控集群”在某时段被同时激活",
JS: 0.41,
CUSUM: 5.0,
KS: 0.05
},
{
id: 3,
abnormalGroup: "G02与G07互动方式出现显著异常",
firstDiscoverTime: "2024.07.25",
duration: 6,
explanation: "疑似群体间短时高强度联动",
JS: 0.41,
CUSUM: 5.0,
KS: 0.02
}
],
currentUtc: T0,
graphData: {
nodes: [
{ id: "G01_A", type: "0", isAnomaly: false, label: "G01" },
{ id: "G02_A", type: "0", isAnomaly: true, label: "G02" },
{ id: "G03_A", type: "0", isAnomaly: false, label: "G03" },
{ id: "G04_A", type: "0", isAnomaly: false, label: "G04" },
{ id: "G05_A", type: "0", isAnomaly: false, label: "G05" },
{ id: "G06_A", type: "0", isAnomaly: false, label: "G06" },
{ id: "G07_A", type: "0", isAnomaly: true, label: "G07" },
{ id: "G08_A", type: "0", isAnomaly: false, label: "G08" },
{ id: "G09_A", type: "0", isAnomaly: false, label: "G09" },
{ id: "G10_A", type: "0", isAnomaly: false, label: "G10" },
{ id: "G11_A", type: "0", isAnomaly: false, label: "G11" },
{ id: "G12_A", type: "0", isAnomaly: false, label: "G12" },
{ id: "G01_B", type: "1", isAnomaly: false, label: "G01" },
{ id: "G02_B", type: "1", isAnomaly: false, label: "G02" },
{ id: "G03_B", type: "1", isAnomaly: false, label: "G03" },
{ id: "G04_B", type: "1", isAnomaly: true, label: "G04" },
{ id: "G05_B", type: "1", isAnomaly: false, label: "G05" },
{ id: "G06_B", type: "1", isAnomaly: false, label: "G06" },
{ id: "G07_B", type: "1", isAnomaly: false, label: "G07" },
{ id: "G08_B", type: "1", isAnomaly: true, label: "G08" },
{ id: "G09_B", type: "1", isAnomaly: false, label: "G09" },
{ id: "G10_B", type: "1", isAnomaly: false, label: "G10" },
{ id: "G11_B", type: "1", isAnomaly: false, label: "G11" },
{ id: "G12_B", type: "1", isAnomaly: false, label: "G12" },
{ id: "G01_C", type: "6", isAnomaly: false, label: "G01" },
{ id: "G02_C", type: "6", isAnomaly: false, label: "G02" },
{ id: "G03_C", type: "6", isAnomaly: true, label: "G03" },
{ id: "G04_C", type: "6", isAnomaly: false, label: "G04" },
{ id: "G05_C", type: "6", isAnomaly: false, label: "G05" },
{ id: "G06_C", type: "6", isAnomaly: true, label: "G06" },
{ id: "G07_C", type: "6", isAnomaly: false, label: "G07" },
{ id: "G08_C", type: "6", isAnomaly: false, label: "G08" },
{ id: "G09_C", type: "6", isAnomaly: false, label: "G09" },
{ id: "G10_C", type: "6", isAnomaly: false, label: "G10" },
{ id: "G11_C", type: "6", isAnomaly: false, label: "G11" },
{ id: "G12_C", type: "6", isAnomaly: false, label: "G12" }
],
links: [
/* —— 组内A 环 —— */
{ source: "G01_A", target: "G02_A", type: "0" },
{ source: "G02_A", target: "G03_A", type: "0" },
{ source: "G03_A", target: "G04_A", type: "0" },
{ source: "G04_A", target: "G05_A", type: "0" },
{ source: "G05_A", target: "G06_A", type: "0" },
{ source: "G06_A", target: "G07_A", type: "0" },
{ source: "G07_A", target: "G08_A", type: "0" },
{ source: "G08_A", target: "G09_A", type: "0" },
{ source: "G09_A", target: "G10_A", type: "0" },
{ source: "G10_A", target: "G11_A", type: "0" },
{ source: "G11_A", target: "G12_A", type: "0" },
{ source: "G12_A", target: "G01_A", type: "0" },
/* —— A 组:异常节点额外连边(突出)—— */
{ source: "G02_A", target: "G05_A", type: "0" },
{ source: "G02_A", target: "G08_A", type: "0" },
{ source: "G02_A", target: "G11_A", type: "0" },
{ source: "G07_A", target: "G10_A", type: "0" },
{ source: "G07_A", target: "G01_A", type: "0" },
{ source: "G07_A", target: "G04_A", type: "0" },
/* —— 组内B 环 —— */
{ source: "G01_B", target: "G02_B", type: "1" },
{ source: "G02_B", target: "G03_B", type: "1" },
{ source: "G03_B", target: "G04_B", type: "1" },
{ source: "G04_B", target: "G05_B", type: "1" },
{ source: "G05_B", target: "G06_B", type: "1" },
{ source: "G06_B", target: "G07_B", type: "1" },
{ source: "G07_B", target: "G08_B", type: "1" },
{ source: "G08_B", target: "G09_B", type: "1" },
{ source: "G09_B", target: "G10_B", type: "1" },
{ source: "G10_B", target: "G11_B", type: "1" },
{ source: "G11_B", target: "G12_B", type: "1" },
{ source: "G12_B", target: "G01_B", type: "1" },
/* —— B 组:异常节点额外连边 —— */
{ source: "G04_B", target: "G07_B", type: "1" },
{ source: "G04_B", target: "G10_B", type: "1" },
{ source: "G04_B", target: "G01_B", type: "1" },
{ source: "G08_B", target: "G11_B", type: "1" },
{ source: "G08_B", target: "G02_B", type: "1" },
{ source: "G08_B", target: "G05_B", type: "1" },
/* —— 组内C 环 —— */
{ source: "G01_C", target: "G02_C", type: "6" },
{ source: "G02_C", target: "G03_C", type: "6" },
{ source: "G03_C", target: "G04_C", type: "6" },
{ source: "G04_C", target: "G05_C", type: "6" },
{ source: "G05_C", target: "G06_C", type: "6" },
{ source: "G06_C", target: "G07_C", type: "6" },
{ source: "G07_C", target: "G08_C", type: "6" },
{ source: "G08_C", target: "G09_C", type: "6" },
{ source: "G09_C", target: "G10_C", type: "6" },
{ source: "G10_C", target: "G11_C", type: "6" },
{ source: "G11_C", target: "G12_C", type: "6" },
{ source: "G12_C", target: "G01_C", type: "6" },
/* —— C 组:异常节点额外连边 —— */
{ source: "G03_C", target: "G06_C", type: "6" },
{ source: "G03_C", target: "G09_C", type: "6" },
{ source: "G03_C", target: "G12_C", type: "6" },
{ source: "G06_C", target: "G09_C", type: "6" },
{ source: "G06_C", target: "G12_C", type: "6" },
{ source: "G06_C", target: "G03_C", type: "6" },
/* —— 跨组连边 —— */
{ source: "G02_A", target: "G04_B", type: "0" },
{ source: "G07_A", target: "G08_B", type: "0" },
{ source: "G01_A", target: "G05_B", type: "0" },
{ source: "G05_A", target: "G10_B", type: "0" },
{ source: "G04_B", target: "G03_C", type: "1" },
{ source: "G08_B", target: "G06_C", type: "1" },
{ source: "G02_B", target: "G09_C", type: "1" },
{ source: "G11_B", target: "G01_C", type: "1" },
{ source: "G03_C", target: "G02_A", type: "6" },
{ source: "G06_C", target: "G07_A", type: "6" },
{ source: "G04_C", target: "G09_A", type: "6" },
{ source: "G12_C", target: "G06_A", type: "6" }
],
meta: {
groups: [
{ id: "A", anomalies: ["G02_A", "G07_A"] },
{ id: "B", anomalies: ["G04_B", "G08_B"] },
{ id: "C", anomalies: ["G03_C", "G06_C"] }
]
}
},
graphAbnormalData: {
groupA: ["G02_A", "G07_A"],
groupB: ["G04_B", "G08_B"],
groupC: ["G03_C", "G06_C"],
abnormalNodesT1: ["G02_A", "G07_A"],
abnormalNodesT2: ["G04_B", "G08_B"],
abnormalNodesT3: ["G02_A", "G07_A", "G04_B", "G08_B", "G03_C", "G06_C"]
}
}),
actions: {
// 获取时间轴数据-中间时间轴
async initializeAbnormalGroupTimeLine() {
const res = await getAbnormalGroupTimeLine()
if (res.code === 200) {
this.timeList = res.data
}
},
// 异常用户组展示-左上
async initializeAbnormalGroupList() {
const res = await getAbnormalGroupList()
if (res.code === 200) {
this.groupList = res.data
}
},
// 全局异常互动时刻表-左下
async initializeAbnormalGroupInteractionChart() {
const res = await getAbnormalGroupInteractionChart()
const xAxisData = res.data.xaxisData.map((item) => utcStringToHHMMSS(item))
const yAxisRange = res.data.yaxisRange
const themeColors = {
社团组一: "#00d6da",
社团组二: "#fddc33",
社团组三: "#32b6fb"
}
const seriesList = res.data.seriesList.map((item) => ({
data: item.data.map((item) => item.toFixed(2)),
name: item.name,
themeColor: themeColors[item.name]
}))
this.chartData = {
xAxisData,
yAxisRange,
seriesList
}
},
// 异常行为分析-中下
async initializeAbnormalGroupPosts(time = "2024-06-19T07:57:46Z") {
const res = await getAbnormalGroupBehaviorPosts(time)
if (res.code === 200) {
this.posts = res.data.map((item) => ({
id: item.id,
abnormalGroup: item.abnormalGroup,
explanation: item.explanation,
firstDiscoverTime: TansTimestamp(item.firstDiscoverTime, "YYYY-MM-DD"),
duration: item.duration,
JS: parseFloat(item.js),
CUSUM: parseFloat(item.cusum),
KS: parseFloat(item.ks)
}))
}
},
// 异常互动详情-右上
async initializeAbnormalGroupInteractionDetail(time = "2024-06-19T07:57:46Z") {
const res = await getAbnormalGroupBehaviorDetail(time)
if (res.code === 200) {
this.abnormalContentList = res.data
}
},
// 用于画中间组件的圆
async initialGraphByUtcTime(utcIso) {
this.currentUtc = utcIso
// 1) 复制 nodes 并上色
const nodes = this.graphData.nodes.map((n) => {
return {
id: n.id,
label: n.label,
type: n.type, // 0=A, 1=B, 6=C组件里 colorMap 已按这三个上色/分组)
isAnomaly: n.isAnomaly
}
})
this.graph["nodes"] = nodes
const setColor = (type) => {
const colorMap = {
0: "50,141,120",
1: "133,129,48",
6: "12,112,144"
}
return colorMap[type]
}
const links = this.graphData.links.map((l) => ({
source: l.source,
target: l.target,
color: setColor(l.type)
}))
this.graph["links"] = links
}
},
persist: true // 开启持久化
})