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

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>
<script setup>
import { defineProps, onMounted, ref, defineEmits } from "vue"
import { onMounted, defineEmits, inject } from "vue"
import * as echarts from "echarts"
import nodeHoverImg from "@/assets/images/nodeHover.png"
import { inject } from "vue"
let chart = null
const emit = defineEmits(["click:node"])
const emit = defineEmits(["click:node", "click:edge"])
const initChart = async () => {
chart = echarts.init(document.getElementById("container"))
@ -20,10 +19,32 @@ const initChart = async () => {
id: parseInt(item.id),
name: parseInt(item.id),
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 }
@ -84,7 +105,6 @@ const initChart = async () => {
backgroundColor: "rgba(0,0,0,0)", //
borderColor: "rgba(0,0,0,0)", //
borderWidth: 0,
extraCssText: "box-shadow:none;padding:0;",
formatter: function (params) {
if (params.dataType === "node") {
@ -110,15 +130,14 @@ const initChart = async () => {
return ""
}
},
//
// edgeLabel: {
// show: false,
// position: "middle",
// formatter: function (params) {
// return params.data.edge
// },
// fontSize: 14
// },
edgeLabel: {
show: false,
position: "middle",
formatter: function (params) {
return params.data.edge
},
fontSize: 14
},
emphasis: {
edgeLabel: {
show: true,
@ -137,10 +156,11 @@ const initChart = async () => {
animation: false,
draggable: true,
roam: true,
zoom: 0.4,
zoom: 0.3,
categories: categories,
force: {
edgeLength: 2000,
edgeLength: 2500,
repulsion: 4000,
gravity: 0.4,
friction: 0.02,
@ -201,14 +221,20 @@ const initChart = async () => {
}
chart.setOption(option)
}
const handleClickNode = () => {
chart.on("click", function (params) {
//params.data.nameid
if (params.dataType === "node") {
emit("click:node", params.data)
} else if (params.dataType == "edge") {
const { data } = params
if (data.edge) {
emit("click:edge", data)
}
}
})
}
onMounted(async () => {
await initChart()
handleClickNode()

View File

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

View File

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

View File

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

View File

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