人物互动隐关系预测二级界面跳转,一级界面互动隐关系已标识

This commit is contained in:
qumeng039@126.com 2025-07-25 17:24:14 +08:00
parent 49b4f2edd0
commit d79cb47cea
6 changed files with 138 additions and 81 deletions

View File

@ -1 +1 @@
VITE_APP_BASE_API = "http://127.0.0.1:3000/api" VITE_APP_BASE_API = "http://10.7.1.183:8080/api"

View File

@ -5,12 +5,11 @@
</template> </template>
<script setup> <script setup>
import { defineProps, onMounted, ref, defineEmits } from "vue" import { onMounted, defineEmits, inject } from "vue"
import * as echarts from "echarts" import * as echarts from "echarts"
import nodeHoverImg from "@/assets/images/nodeHover.png" import nodeHoverImg from "@/assets/images/nodeHover.png"
import { inject } from "vue"
let chart = null let chart = null
const emit = defineEmits(["click:node"]) const emit = defineEmits(["click:node", "click:edge"])
const initChart = async () => { const initChart = async () => {
chart = echarts.init(document.getElementById("container")) chart = echarts.init(document.getElementById("container"))
@ -20,10 +19,32 @@ const initChart = async () => {
id: parseInt(item.id), id: parseInt(item.id),
name: parseInt(item.id), name: parseInt(item.id),
isIncludePredictNodes: item.isIncludePredictNodes, isIncludePredictNodes: item.isIncludePredictNodes,
nodesNum: item.nodesNum nodesNum: item.nodesNum,
neighbors: item.neighbors.map((item) => ({ ...item, name: parseInt(item.id) })),
category: item.isIncludePredictNodes ? 1 : 0
})) }))
const links = [] // //
const links = []
const edgeSet = new Set() //
nodes.forEach((communityNode) => {
communityNode.neighbors.forEach((communityNei) => {
const key = [communityNode.name, communityNei.name].sort().join("-")
if (edgeSet.has(key)) return
links.push({
source: communityNode.name,
target: communityNei.name,
edge: communityNei.isHidden ? 1 : 0, //10
lineStyle: {
width: communityNei.isHidden ? 4 : 1, // =线=
color: communityNei.isHidden ? "#f8bf38" : "#37ACD7", // ==
type: communityNei.isHidden ? "dashed" : "solid", // =线=线
dashArray: [2, 1] // 2线1
}
})
edgeSet.add(key)
})
})
const data = { nodes, links } const data = { nodes, links }
@ -84,7 +105,6 @@ const initChart = async () => {
backgroundColor: "rgba(0,0,0,0)", // backgroundColor: "rgba(0,0,0,0)", //
borderColor: "rgba(0,0,0,0)", // borderColor: "rgba(0,0,0,0)", //
borderWidth: 0, borderWidth: 0,
extraCssText: "box-shadow:none;padding:0;", extraCssText: "box-shadow:none;padding:0;",
formatter: function (params) { formatter: function (params) {
if (params.dataType === "node") { if (params.dataType === "node") {
@ -110,15 +130,14 @@ const initChart = async () => {
return "" return ""
} }
}, },
// edgeLabel: {
// edgeLabel: { show: false,
// show: false, position: "middle",
// position: "middle", formatter: function (params) {
// formatter: function (params) { return params.data.edge
// return params.data.edge },
// }, fontSize: 14
// fontSize: 14 },
// },
emphasis: { emphasis: {
edgeLabel: { edgeLabel: {
show: true, show: true,
@ -137,10 +156,11 @@ const initChart = async () => {
animation: false, animation: false,
draggable: true, draggable: true,
roam: true, roam: true,
zoom: 0.4, zoom: 0.3,
categories: categories, categories: categories,
force: { force: {
edgeLength: 2000, edgeLength: 2500,
repulsion: 4000, repulsion: 4000,
gravity: 0.4, gravity: 0.4,
friction: 0.02, friction: 0.02,
@ -201,14 +221,20 @@ const initChart = async () => {
} }
chart.setOption(option) chart.setOption(option)
} }
const handleClickNode = () => { const handleClickNode = () => {
chart.on("click", function (params) { chart.on("click", function (params) {
//params.data.nameid
if (params.dataType === "node") { if (params.dataType === "node") {
emit("click:node", params.data) emit("click:node", params.data)
} else if (params.dataType == "edge") {
const { data } = params
if (data.edge) {
emit("click:edge", data)
}
} }
}) })
} }
onMounted(async () => { onMounted(async () => {
await initChart() await initChart()
handleClickNode() handleClickNode()

View File

@ -1,11 +1,12 @@
<template> <template>
<div class="detailNode-component"> <div class="detailNode-component">
<img src="@/assets/images/icon/goback.png" alt="" class="goback" @click="handleGoback" />
<div class="graph-container" id="container"></div> <div class="graph-container" id="container"></div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { defineProps } from "vue" import { defineProps, defineEmits } from "vue"
const props = defineProps({ const props = defineProps({
detailNode: { detailNode: {
@ -13,6 +14,10 @@ const props = defineProps({
default: () => [] default: () => []
} }
}) })
const emit = defineEmits(["click:goback"])
const handleGoback = () => {
emit("click:goback", "CommunityNode")
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
@ -20,6 +25,12 @@ const props = defineProps({
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative; position: relative;
.goback {
position: absolute;
top: 10px;
left: 20px;
cursor: pointer;
}
.graph-container { .graph-container {
width: 100%; width: 100%;
height: 93%; height: 93%;

View File

@ -2,8 +2,12 @@
<div class="graph-component"> <div class="graph-component">
<img :src="title" alt="" class="title" /> <img :src="title" alt="" class="title" />
<CommunityNode v-if="curComponent == '社团节点'" @click:node="handleClickNode"></CommunityNode> <CommunityNode
<DetailNode v-else></DetailNode> v-if="curComponent == 'CommunityNode'"
@click:node="handleClickNode"
@click:edge="handleClickEdge"
></CommunityNode>
<DetailNode v-else @click:goback="handleClickGoBack"></DetailNode>
<div class="time-axis"></div> <div class="time-axis"></div>
</div> </div>
@ -15,7 +19,7 @@ import CommunityNode from "./communityNode.vue"
import DetailNode from "./detailNode.vue" import DetailNode from "./detailNode.vue"
import { useCharacterInteractionStore } from "@/store/llinkPrediction/index" import { useCharacterInteractionStore } from "@/store/llinkPrediction/index"
const interactionStore = useCharacterInteractionStore() const interactionStore = useCharacterInteractionStore()
const curComponent = ref("社团节点") const curComponent = ref("CommunityNode")
const props = defineProps({ const props = defineProps({
title: { title: {
type: String, type: String,
@ -27,6 +31,16 @@ const handleClickNode = (nodeInfo) => {
interactionStore.initGraphCommunityDetailNode([nodeInfo.id]) interactionStore.initGraphCommunityDetailNode([nodeInfo.id])
console.log(nodeInfo) console.log(nodeInfo)
} }
const handleClickEdge = (edgeInfo) => {
curComponent.value = "detailNode"
const ids = [edgeInfo.source, edgeInfo.target]
console.log(ids)
}
const handleClickGoBack = (currentComponentName) => {
curComponent.value = currentComponentName
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

View File

@ -47,8 +47,6 @@ watch(riskEventIndex, (newIndex) => {
const tooltipList = keyNodeStore.tooltipList const tooltipList = keyNodeStore.tooltipList
const highRiskCount = tooltipList[newIndex].filter((item) => item.riskType == "高风险").length const highRiskCount = tooltipList[newIndex].filter((item) => item.riskType == "高风险").length
console.log(tooltipList[newIndex])
keyNodeStore.statisticsList[5].number = highRiskCount keyNodeStore.statisticsList[5].number = highRiskCount
keyNodeStore.statisticsList[4].number = tooltipList[newIndex].length keyNodeStore.statisticsList[4].number = tooltipList[newIndex].length
}) })

View File

@ -6,48 +6,48 @@
</template> </template>
<script setup> <script setup>
import { defineProps, onMounted, ref } from "vue"; import { defineProps, onMounted, ref } from "vue"
import * as echarts from "echarts"; import * as echarts from "echarts"
import { cropToCircleAsync } from "@/utils/transform"; import { cropToCircleAsync } from "@/utils/transform"
import anchorNeighbors from "@/assets/json/anchor_neighbors.json"; import anchorNeighbors from "@/assets/json/anchor_neighbors.json"
import nodeHoverImg from "@/assets/images/nodeHover.png"; import nodeHoverImg from "@/assets/images/nodeHover.png"
import { useKeyNodeRecognitionStore } from "@/store/keyNodeRecognition/index"; import { useKeyNodeRecognitionStore } from "@/store/keyNodeRecognition/index"
const keyNodeStore = useKeyNodeRecognitionStore(); const keyNodeStore = useKeyNodeRecognitionStore()
const props = defineProps({ const props = defineProps({
communityNode: { communityNode: {
type: Object, type: Object,
default: 0 default: 0
} }
}); })
const emit = defineEmits(["click:openDialog", "click:goback"]); const emit = defineEmits(["click:openDialog", "click:goback"])
const detailContainer = ref(null); const detailContainer = ref(null)
const currentSelectedCommunity = ref({}); const currentSelectedCommunity = ref({})
let chart = null; let chart = null
// //
const calculateInitialZoom = (nodes) => { const calculateInitialZoom = (nodes) => {
const NODE_COUNT = nodes.length; const NODE_COUNT = nodes.length
if (NODE_COUNT > 1000) return 0.1; if (NODE_COUNT > 1000) return 0.1
if (NODE_COUNT > 200) return 0.2; if (NODE_COUNT > 200) return 0.2
if (NODE_COUNT > 100) return 0.3; if (NODE_COUNT > 100) return 0.3
if (NODE_COUNT > 50) return 0.4; if (NODE_COUNT > 50) return 0.4
return 0.8; // return 0.8 //
}; }
const initChart = async () => { const initChart = async () => {
currentSelectedCommunity.value = props.communityNode; currentSelectedCommunity.value = props.communityNode
chart = echarts.init(document.getElementById("container")); chart = echarts.init(document.getElementById("container"))
// //
// //
let nodes = []; let nodes = []
//base64 //base64
const extraInfo = keyNodeStore.anchorExtraInfos; const extraInfo = keyNodeStore.anchorExtraInfos
const keys = Object.keys(extraInfo); const keys = Object.keys(extraInfo)
for (const key of keys) { for (const key of keys) {
const userInfo = extraInfo[key]; const userInfo = extraInfo[key]
userInfo.avatar = await cropToCircleAsync(userInfo.avatar); userInfo.avatar = await cropToCircleAsync(userInfo.avatar)
} }
// //
@ -57,40 +57,40 @@ const initChart = async () => {
...extraInfo[filteredList[0]], ...extraInfo[filteredList[0]],
anchor: filteredList[0], anchor: filteredList[0],
neighbors: filteredList[1].map((neighNode) => ({ name: neighNode, avatar: "" })) neighbors: filteredList[1].map((neighNode) => ({ name: neighNode, avatar: "" }))
})); }))
//线 //线
let links = []; let links = []
filterResult.forEach(({ anchor, neighbors }) => { filterResult.forEach(({ anchor, neighbors }) => {
(neighbors ?? []).forEach((neigh) => { ;(neighbors ?? []).forEach((neigh) => {
links.push({ source: anchor, target: neigh.name }); links.push({ source: anchor, target: neigh.name })
}); })
}); })
// //
let nodeSet = new Set(); let nodeSet = new Set()
filterResult.forEach((item) => { filterResult.forEach((item) => {
// //
if (!nodeSet.has(item.anchor)) { if (!nodeSet.has(item.anchor)) {
nodes.push({ name: item?.anchor, value: item?.anchor, category: 1, ...item }); nodes.push({ name: item?.anchor, value: item?.anchor, category: 1, ...item })
nodeSet.add(item?.anchor); nodeSet.add(item?.anchor)
} }
// //
(item.neighbors || []).forEach((n) => { ;(item.neighbors || []).forEach((n) => {
if (!nodeSet.has(n?.name)) { if (!nodeSet.has(n?.name)) {
nodes.push({ name: n.name, value: n.name, category: 0, avatar: n.avatar ?? "" }); nodes.push({ name: n.name, value: n.name, category: 0, avatar: n.avatar ?? "" })
nodeSet.add(n.name); nodeSet.add(n.name)
} }
}); })
}); })
const data = { nodes, links }; const data = { nodes, links }
console.log(data); console.log(data)
const categories = [ const categories = [
{ name: "邻居账号", category: 0 }, { name: "邻居账号", category: 0 },
{ name: "锚点账号", category: 1 } { name: "锚点账号", category: 1 }
]; ]
const option = { const option = {
// //
@ -178,7 +178,7 @@ const initChart = async () => {
<div style="margin-left: 20px">粉丝数: ${params.data.fancy}</div> <div style="margin-left: 20px">粉丝数: ${params.data.fancy}</div>
</div> </div>
</div> </div>
</div>`; </div>`
} else if (params.dataType === "node" && !params.data.category) { } else if (params.dataType === "node" && !params.data.category) {
return `<div return `<div
style=" style="
@ -211,7 +211,7 @@ const initChart = async () => {
</div> </div>
</div> </div>
</div> </div>
</div>`; </div>`
} }
} }
}, },
@ -273,29 +273,37 @@ const initChart = async () => {
lineStyle: { lineStyle: {
color: "#37ACD7", color: "#37ACD7",
width: 1 width: 1
},
emphasis: {
//
focus: "adjacency", //
lineStyle: {
// 线
width: 10 // 线(10)
}
} }
} }
] ]
}; }
chart.setOption(option); chart.setOption(option)
}; }
const handleClickNode = () => { const handleClickNode = () => {
chart.on("click", function (params) { chart.on("click", function (params) {
if (params.dataType == "node" && params.data.category == 1) { if (params.dataType == "node" && params.data.category == 1) {
emit("click:openDialog", params.data); emit("click:openDialog", params.data)
} }
}); })
}; }
const handleGoback = () => { const handleGoback = () => {
emit("click:goback", "CommunityNode"); emit("click:goback", "CommunityNode")
}; }
onMounted(async () => { onMounted(async () => {
await initChart(); await initChart()
handleClickNode(); handleClickNode()
}); })
</script> </script>
<style scoped lang="less"> <style scoped lang="less">