Merge branch 'master' of http://172.16.20.1:3000/duanhao/SocialNetworks_duan
This commit is contained in:
commit
761373ed93
Binary file not shown.
|
After Width: | Height: | Size: 148 B |
|
|
@ -86,9 +86,27 @@ export function getSocialCommunityDetailNodes(ids, relationId, time = "2024-05-1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//人物社交隐关系预测用户组列表
|
//获取人物社交隐关系预测社团节点
|
||||||
export function getInteractionHiddenPostList(outoIncrement) {
|
export function getCharacterSocialCommunityNodes() {
|
||||||
return http.get(`/linkPrediction/triangle/post_list?page=${outoIncrement}`)
|
return http.get("/linkPrediction/social/community")
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//获取人物社交隐关系预测社团统计
|
||||||
|
export function getCharacterSocialCommunityStatistics() {
|
||||||
|
return http.get(`/linkPrediction/social/community_statistics`)
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取人物社交隐关系预测社团内部节点
|
||||||
|
export function getCharacterSocialCommunityDetailNodes(
|
||||||
|
ids,
|
||||||
|
relationId,
|
||||||
|
time = "2024-05-16 16:56:04"
|
||||||
|
) {
|
||||||
|
if (relationId != -1) {
|
||||||
|
return http.get(
|
||||||
|
`/linkPrediction/social/community_detail?groupIds=${ids}&dateTime=${time}&relationId=${relationId}`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return http.get(`/linkPrediction/social/community_detail?groupIds=${ids}&dateTime=${time}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,16 @@ import {
|
||||||
getGroupUserListFromTriangle,
|
getGroupUserListFromTriangle,
|
||||||
getGroupUserListFromSocial,
|
getGroupUserListFromSocial,
|
||||||
getInteractionPostList,
|
getInteractionPostList,
|
||||||
getInteractionHiddenPostList,
|
|
||||||
getInteractionCommunityNodes,
|
getInteractionCommunityNodes,
|
||||||
getInteractionCommunityDetailNodes,
|
getInteractionCommunityDetailNodes,
|
||||||
getInteractionCommunityStatistics,
|
getInteractionCommunityStatistics,
|
||||||
getSocialCommunityList,
|
getSocialCommunityList,
|
||||||
getSocialCommunityStatistics,
|
getSocialCommunityStatistics,
|
||||||
getSocialCommunityDetailNodes,
|
getSocialCommunityDetailNodes,
|
||||||
getSocialPostListByRelationId
|
getSocialPostListByRelationId,
|
||||||
|
getCharacterSocialCommunityNodes,
|
||||||
|
getCharacterSocialCommunityStatistics,
|
||||||
|
getCharacterSocialCommunityDetailNodes
|
||||||
} from "@/service/api/linkPrediction"
|
} from "@/service/api/linkPrediction"
|
||||||
|
|
||||||
import defaultAvatar from "@/assets/images/avatar/default.png"
|
import defaultAvatar from "@/assets/images/avatar/default.png"
|
||||||
|
|
@ -28,11 +30,14 @@ export const useCharacterInteractionStore = defineStore("characterInteraction",
|
||||||
communityNodeList: [], //所有社团数据
|
communityNodeList: [], //所有社团数据
|
||||||
curComponent: "CommunityNode",
|
curComponent: "CommunityNode",
|
||||||
curSelecedGroupIds: [],
|
curSelecedGroupIds: [],
|
||||||
|
predictionLegendContent: "互动隐关系",
|
||||||
communityDetailNodeRelation: [], //点击一级界面后,查询到的节点间关系
|
communityDetailNodeRelation: [], //点击一级界面后,查询到的节点间关系
|
||||||
communityDetailNodeList: [], //节点用户列表
|
communityDetailNodeList: [], //节点用户列表
|
||||||
timeList: [],
|
timeList: [],
|
||||||
predictionUserIds: [], //包含从用户组选择的用户id或者是点击某个社团或者连边后,所需要高亮的所有用户的id
|
predictionUserIds: [], //包含从用户组选择的用户id或者是点击某个社团或者连边后,所需要高亮的所有用户的id
|
||||||
curRelationId: "",
|
curRelationId: "",
|
||||||
|
predictionLineColor: "#f8bf38",
|
||||||
|
predictionLegendIcon: `image://${new URL("@/assets/images/linkPrediction/icon/hidden-icon.png", import.meta.url)}`,
|
||||||
anlysisList: [
|
anlysisList: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
|
|
@ -159,7 +164,7 @@ export const useCharacterInteractionStore = defineStore("characterInteraction",
|
||||||
if (res.code != 200) {
|
if (res.code != 200) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.userList = res.data.userList
|
this.userList = res.data.userList.sort((a, b) => a.rank - b.rank)
|
||||||
},
|
},
|
||||||
|
|
||||||
initGroupCorrelationForChart() {
|
initGroupCorrelationForChart() {
|
||||||
|
|
@ -181,7 +186,6 @@ export const useCharacterInteractionStore = defineStore("characterInteraction",
|
||||||
if (res.code != 200) return
|
if (res.code != 200) return
|
||||||
const customStatisticsObj = Object.assign({}, res.data.communityStatistics)
|
const customStatisticsObj = Object.assign({}, res.data.communityStatistics)
|
||||||
//计算两个用户是否同属与同一个社团
|
//计算两个用户是否同属与同一个社团
|
||||||
|
|
||||||
if (
|
if (
|
||||||
customStatisticsObj.groupCount == null &&
|
customStatisticsObj.groupCount == null &&
|
||||||
customStatisticsObj.hiddenInteractionCount == null
|
customStatisticsObj.hiddenInteractionCount == null
|
||||||
|
|
@ -497,58 +501,23 @@ export const useSocialGroupsStore = defineStore("socialGroups", {
|
||||||
export const useCharacterHiddenStore = defineStore("characterHidden", {
|
export const useCharacterHiddenStore = defineStore("characterHidden", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
userList: [],
|
userList: [],
|
||||||
userChartList: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
group: [
|
|
||||||
{ id: 1, name: "Polo Hun", avatar: defaultAvatar, fancy: 634, post: 32 },
|
|
||||||
{ id: 2, name: "楊政子", avatar: defaultAvatar, fancy: 5556, post: 23 }
|
|
||||||
],
|
|
||||||
number: "0.36"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
group: [
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
name: "一人一讚 馬總統感恩有您 永遠支...",
|
|
||||||
avatar: defaultAvatar,
|
|
||||||
fancy: 0,
|
|
||||||
post: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
name: "一人一讚 馬總統感恩有您 永遠支...",
|
|
||||||
avatar: defaultAvatar,
|
|
||||||
fancy: 564,
|
|
||||||
post: 13
|
|
||||||
}
|
|
||||||
],
|
|
||||||
number: 0.28
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
group: [
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
name: "一人一讚 馬總統感恩有您 永遠支...",
|
|
||||||
avatar: defaultAvatar,
|
|
||||||
fancy: 0,
|
|
||||||
post: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
name: "一人一讚 馬總統感恩有您 永遠支...",
|
|
||||||
avatar: defaultAvatar,
|
|
||||||
fancy: 564,
|
|
||||||
post: 13
|
|
||||||
}
|
|
||||||
],
|
|
||||||
number: 0.24
|
|
||||||
}
|
|
||||||
],
|
|
||||||
posts: [],
|
posts: [],
|
||||||
|
communityNodeList: [],
|
||||||
|
curComponent: "CommunityNode",
|
||||||
|
timeList: [],
|
||||||
|
predictionUserIds: [], //包含从用户组选择的用户id或者是点击某个社团或者连边后,所需要高亮的所有用户的id
|
||||||
|
curRelationId: "",
|
||||||
|
curSelecedGroupIds: [],
|
||||||
|
communityDetailNodeRelation: [], //点击一级界面后,查询到的节点间关系
|
||||||
|
communityDetailNodeList: [], //节点用户列表
|
||||||
|
predictionLineColor: "#FF3F8F",
|
||||||
|
predictionLegendContent: "社交隐关系",
|
||||||
|
predictionLegendIcon: `image://${new URL("@/assets/images/linkPrediction/icon/socialCharacter-legend-icon.png", import.meta.url)}`,
|
||||||
|
statisticsList: [
|
||||||
|
{ id: 1, icon: nodePrefix, name: "节点数", key: "nodesCount" },
|
||||||
|
{ id: 2, icon: communityPrefix, name: "社团数", key: "groupCount" },
|
||||||
|
{ id: 3, icon: hiddenPrefix, name: "隐关系数", key: "hiddenInteractionCount" }
|
||||||
|
],
|
||||||
anlysisList: [
|
anlysisList: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
|
|
@ -656,19 +625,60 @@ export const useCharacterHiddenStore = defineStore("characterHidden", {
|
||||||
{ text: "领土", top: 57.5, left: 72.5, width: 49, height: 19, fontSize: 12, opacity: 0.6 },
|
{ 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: 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: 195.5, left: 287.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 }
|
||||||
|
],
|
||||||
|
statisticsDetailList: [
|
||||||
|
{ id: 1, icon: nodePrefix, name: "节点数", key: "nodesCount" },
|
||||||
|
{ id: 2, icon: communityPrefix, name: "社团数", key: "groupCount" },
|
||||||
|
{ id: 3, icon: hiddenPrefix, name: "隐关系数", key: "hiddenInteractionCount" }
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async initGroupList() {
|
async initGroupList() {
|
||||||
const res = await getGroupUserListFromSocial()
|
const res = await getGroupUserListFromSocial()
|
||||||
if (res.code != 200) return
|
if (res.code != 200) return
|
||||||
this.userList = res.data.userList
|
this.userList = res.data.userList.sort((a, b) => a.rank - b.rank)
|
||||||
},
|
},
|
||||||
async initPostList(autoIncrement) {
|
|
||||||
const res = await getInteractionHiddenPostList(autoIncrement)
|
async initCharacterSocialHiddenPostList(relationId) {
|
||||||
|
const res = await getInteractionPostList(relationId)
|
||||||
if (res.code != 200) return
|
if (res.code != 200) return
|
||||||
if (this.posts.length != 0) this.posts.push(...res.data)
|
this.posts = res.data
|
||||||
else this.posts = res.data
|
},
|
||||||
|
|
||||||
|
async initGraphCommunityNode() {
|
||||||
|
const res = await getCharacterSocialCommunityNodes()
|
||||||
|
if (res.code !== 200) return
|
||||||
|
this.communityNodeList = res.data
|
||||||
|
},
|
||||||
|
async initGraphStatistics() {
|
||||||
|
const res = await getCharacterSocialCommunityStatistics()
|
||||||
|
this.statisticsList = this.statisticsList.map((item) => ({
|
||||||
|
...item,
|
||||||
|
count: res.data[item.key]
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
async initGraphCommunityDetailNode(ids, time = "2024-05-16 16:56:04", relationId = -1) {
|
||||||
|
this.curSelecedGroupIds = ids
|
||||||
|
const res = await getCharacterSocialCommunityDetailNodes(ids, relationId, time)
|
||||||
|
if (res.code != 200) return
|
||||||
|
const customStatisticsObj = Object.assign({}, res.data.communityStatistics)
|
||||||
|
//计算两个用户是否同属与同一个社团
|
||||||
|
if (
|
||||||
|
customStatisticsObj.groupCount == null &&
|
||||||
|
customStatisticsObj.hiddenInteractionCount == null
|
||||||
|
) {
|
||||||
|
customStatisticsObj.hiddenInteractionCount = 1
|
||||||
|
customStatisticsObj.groupCount = ids[0] === ids[1] ? 1 : 2
|
||||||
|
}
|
||||||
|
|
||||||
|
this.statisticsDetailList = this.statisticsDetailList.map((item) => ({
|
||||||
|
...item,
|
||||||
|
count: customStatisticsObj[item.key]
|
||||||
|
}))
|
||||||
|
this.communityDetailNodeRelation = res.data.userRelation
|
||||||
|
this.communityDetailNodeList = res.data.userList
|
||||||
|
this.timeList = res.data.timeList
|
||||||
|
this.predictionUserIds = res.data.predictNodes
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
persist: true // 开启持久化
|
persist: true // 开启持久化
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="middle-container">
|
<div class="middle-container">
|
||||||
<div class="graph">
|
<div class="graph">
|
||||||
<Graph :title="graphTitleImg"></Graph>
|
<Graph :title="graphTitleImg" :interactionStore="interactionStore"></Graph>
|
||||||
</div>
|
</div>
|
||||||
<div class="postList">
|
<div class="postList">
|
||||||
<PostList :posts="interactionStore.posts"></PostList>
|
<PostList :posts="interactionStore.posts"></PostList>
|
||||||
|
|
@ -53,7 +53,6 @@ const interactionStore = useCharacterInteractionStore()
|
||||||
const handleSelectedUserGroup = (group) => {
|
const handleSelectedUserGroup = (group) => {
|
||||||
interactionStore.curComponent = "detailNode"
|
interactionStore.curComponent = "detailNode"
|
||||||
interactionStore.timeList = group.timeList //保存从用户列表选择的用户组,为了显示这两个用户交互的时间切片
|
interactionStore.timeList = group.timeList //保存从用户列表选择的用户组,为了显示这两个用户交互的时间切片
|
||||||
interactionStore.userIds = group.list.map((user) => user.userId) //保存选中的用户组的所有用户id,为了高亮二级关系图的用户
|
|
||||||
interactionStore.curRelationId = group.relationId //保存当前点击的relationid,为了区分到底是从哪点进二级界面的
|
interactionStore.curRelationId = group.relationId //保存当前点击的relationid,为了区分到底是从哪点进二级界面的
|
||||||
interactionStore.initInteractionPostList(group.relationId)
|
interactionStore.initInteractionPostList(group.relationId)
|
||||||
interactionStore.initGraphCommunityDetailNode(
|
interactionStore.initGraphCommunityDetailNode(
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="middle-container">
|
<div class="middle-container">
|
||||||
<div class="graph">
|
<div class="graph">
|
||||||
<Graph :title="graphTitleImg"></Graph>
|
<Graph :title="graphTitleImg" :interactionStore="characterHiddenStore"></Graph>
|
||||||
</div>
|
</div>
|
||||||
<div class="postList">
|
<div class="postList">
|
||||||
<PostList
|
<PostList :posts="characterHiddenStore.posts"></PostList>
|
||||||
:posts="characterHiddenStore.posts"
|
|
||||||
@click:openDialog="handleOpenPostDialog"
|
|
||||||
@scroll:touchButtom="handleTouchButtom"
|
|
||||||
></PostList>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right-container">
|
<div class="right-container">
|
||||||
|
|
@ -36,70 +32,43 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-dialog v-model="postDialog" width="640" align-center class="custom-dialog">
|
|
||||||
<img src="@/assets/images/head/post-dialog-title.png" alt="" class="postTitleImage" />
|
|
||||||
<div class="dialog-content">
|
|
||||||
<div class="post-content">{{ currentPostPost.content }}</div>
|
|
||||||
<div class="heat">
|
|
||||||
<div class="item-heat-detail">
|
|
||||||
<div class="item-heat-like">
|
|
||||||
<Icon icon="ei:like" width="25" height="25" /> {{ currentPostPost.like }}
|
|
||||||
</div>
|
|
||||||
<div class="item-heat-comment">
|
|
||||||
<Icon icon="la:comment-dots" width="25" height="25" /> {{ currentPostPost.comment }}
|
|
||||||
</div>
|
|
||||||
<div class="item-heat-transmit">
|
|
||||||
<Icon icon="mdi:share-outline" width="25" height="25" /> {{
|
|
||||||
currentPostPost.transmit
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, provide } from "vue"
|
||||||
import UserPanel from "../components/userPanel.vue";
|
import UserPanel from "../components/userPanel.vue"
|
||||||
import UserChart from "../components/userChart.vue";
|
import PostList from "../components/postList.vue"
|
||||||
import PostList from "../components/postList.vue";
|
import AnlysisPanle from "../components/anlysisPanle.vue"
|
||||||
import AnlysisPanle from "../components/anlysisPanle.vue";
|
import Graph from "../components/graph.vue"
|
||||||
import Graph from "../components/graph.vue";
|
import WordsCloud from "../components/cloudWords.vue"
|
||||||
import WordsCloud from "../components/cloudWords.vue";
|
import { useCharacterHiddenStore } from "@/store/llinkPrediction/index"
|
||||||
import { Icon } from "@iconify/vue";
|
import userPanelTitleImg from "@/assets/images/linkPrediction/title/user-title.png"
|
||||||
import { useCharacterHiddenStore } from "@/store/llinkPrediction/index";
|
import graphTitleImg from "@/assets/images/linkPrediction/title/graph1-title.png"
|
||||||
import userPanelTitleImg from "@/assets/images/linkPrediction/title/user-title.png";
|
import analysisTitleImg from "@/assets/images/linkPrediction/title/analysis-title.png"
|
||||||
import userChartTitleImg from "@/assets/images/linkPrediction/title/interaction-strenth-title.png";
|
|
||||||
import graphTitleImg from "@/assets/images/linkPrediction/title/graph1-title.png";
|
|
||||||
import analysisTitleImg from "@/assets/images/linkPrediction/title/analysis-title.png";
|
|
||||||
const characterHiddenStore = useCharacterHiddenStore();
|
|
||||||
|
|
||||||
//控制弹窗
|
const characterHiddenStore = useCharacterHiddenStore()
|
||||||
const postDialog = ref(false);
|
|
||||||
|
|
||||||
//当前选中的贴文数据
|
|
||||||
const currentPostPost = ref(null);
|
|
||||||
|
|
||||||
const handleSelectedUserGroup = (group) => {
|
const handleSelectedUserGroup = (group) => {
|
||||||
console.log(group);
|
characterHiddenStore.curComponent = "detailNode"
|
||||||
};
|
characterHiddenStore.timeList = group.timeList //保存从用户列表选择的用户组,为了显示这两个用户交互的时间切片
|
||||||
|
characterHiddenStore.curRelationId = group.relationId //保存当前点击的relationid,为了区分到底是从哪点进二级界面的
|
||||||
const handleOpenPostDialog = (post) => {
|
characterHiddenStore.initCharacterSocialHiddenPostList(group.relationId)
|
||||||
postDialog.value = true;
|
characterHiddenStore.initGraphCommunityDetailNode(
|
||||||
currentPostPost.value = post;
|
group.list.map((item) => item.groupId),
|
||||||
};
|
"2024-05-16 16:56:04",
|
||||||
|
group.relationId
|
||||||
const handleTouchButtom = (autoIncrement) => {
|
)
|
||||||
characterHiddenStore.initPostList(autoIncrement);
|
}
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
characterHiddenStore.initGroupList();
|
characterHiddenStore.initGroupList()
|
||||||
characterHiddenStore.initPostList(0);
|
characterHiddenStore.initCharacterSocialHiddenPostList("79") //初始贴文列表
|
||||||
});
|
characterHiddenStore.initGraphCommunityNode() //初始化社团节点
|
||||||
|
characterHiddenStore.initGraphStatistics() //初始化社团统计
|
||||||
|
})
|
||||||
|
provide("communityNodeList", characterHiddenStore.communityNodeList) // 提供数据
|
||||||
|
provide("statisticsList", characterHiddenStore.statisticsList)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
|
||||||
|
|
@ -12,23 +12,28 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, defineEmits, inject } from "vue"
|
import { onMounted, defineEmits, inject, defineProps } 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"
|
||||||
let chart = null
|
let chart = null
|
||||||
const emit = defineEmits(["click:node", "click:edge"])
|
const emit = defineEmits(["click:node", "click:edge"])
|
||||||
const statisticsList = inject("statisticsList")
|
const statisticsList = inject("statisticsList")
|
||||||
|
const props = defineProps({
|
||||||
const initChart = async () => {
|
interactionStore: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const initChart = () => {
|
||||||
chart = echarts.init(document.getElementById("container"))
|
chart = echarts.init(document.getElementById("container"))
|
||||||
|
|
||||||
//处理社团节点
|
//处理社团节点
|
||||||
const nodes = Object.values(inject("communityNodeList") ?? []).map((item) => ({
|
const nodes = Object.values(inject("communityNodeList") ?? []).map((item) => ({
|
||||||
id: parseInt(item.id),
|
id: item.id,
|
||||||
name: parseInt(item.id),
|
name: item.id,
|
||||||
isIncludePredictNodes: item.isIncludePredictNodes,
|
isIncludePredictNodes: item.isIncludePredictNodes,
|
||||||
nodesNum: item.nodesNum,
|
nodesNum: item.nodesNum,
|
||||||
neighbors: item.neighbors.map((item) => ({ ...item, name: parseInt(item.id) })),
|
neighbors: item.neighbors,
|
||||||
category: item.isIncludePredictNodes ? 1 : 0,
|
category: item.isIncludePredictNodes ? 1 : 0,
|
||||||
selfIncludeImplicitRelationship:
|
selfIncludeImplicitRelationship:
|
||||||
item.neighbors.map((nei) => nei.id).includes(item.id) && //若该社团的id在该社团邻居中可以找到,说明自己这个社团中有互动隐关系
|
item.neighbors.map((nei) => nei.id).includes(item.id) && //若该社团的id在该社团邻居中可以找到,说明自己这个社团中有互动隐关系
|
||||||
|
|
@ -37,24 +42,23 @@ const initChart = async () => {
|
||||||
|
|
||||||
//处理连边
|
//处理连边
|
||||||
const links = []
|
const links = []
|
||||||
const edgeSet = new Set() //去除重复边
|
const newSet = new Set()
|
||||||
nodes.forEach((communityNode) => {
|
nodes.forEach((communityNode) => {
|
||||||
communityNode.neighbors.forEach((communityNei) => {
|
communityNode.neighbors.forEach((communityNei) => {
|
||||||
const key = [communityNode.name, communityNei.name].sort().join("-")
|
if (newSet.has(communityNei.id)) return
|
||||||
if (edgeSet.has(key)) return
|
|
||||||
links.push({
|
links.push({
|
||||||
source: communityNode.name,
|
source: communityNode.id,
|
||||||
target: communityNei.name,
|
target: communityNei.id,
|
||||||
edge: communityNei.isHidden ? 1 : 0, //该边存在互动隐关系则权值为1,否则为0
|
edge: communityNei.isHidden ? 1 : 0, //该边存在互动隐关系则权值为1,否则为0
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
width: communityNei.isHidden ? 4 : 1, // 无互动=细线,有互动=加粗
|
width: communityNei.isHidden ? 4 : 1, // 无互动=细线,有互动=加粗
|
||||||
color: communityNei.isHidden ? "#f8bf38" : "#37ACD7", // 无互动=灰色,有互动=黄色
|
color: communityNei.isHidden ? props.interactionStore.predictionLineColor : "#37ACD7", // 无互动=灰色,有互动=黄色
|
||||||
type: communityNei.isHidden ? "dashed" : "solid", // 无互动=实线,有互动=虚线
|
opacity: communityNei.isHidden ? 1 : 0.8, // 可选:调整透明度增强模糊感
|
||||||
dashArray: [2, 1] // 2像素实线,1像素空白
|
type: communityNei.isHidden ? "dashed" : "solid" // 无互动=实线,有互动=虚线
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
edgeSet.add(key)
|
|
||||||
})
|
})
|
||||||
|
newSet.add(communityNode.id) // 添加当前社团节点id到集合中,避免重复添加
|
||||||
})
|
})
|
||||||
|
|
||||||
const data = { nodes, links }
|
const data = { nodes, links }
|
||||||
|
|
@ -63,9 +67,9 @@ const initChart = async () => {
|
||||||
{ name: "普通社团", category: 0, icon: "circle" },
|
{ name: "普通社团", category: 0, icon: "circle" },
|
||||||
{ name: "含预测节点社团", category: 1, icon: "circle" },
|
{ name: "含预测节点社团", category: 1, icon: "circle" },
|
||||||
{
|
{
|
||||||
name: "互动隐关系",
|
name: props.interactionStore.predictionLegendContent,
|
||||||
category: 2,
|
category: 2,
|
||||||
icon: `image://${new URL("@/assets/images/linkPrediction/icon/hidden-icon.png", import.meta.url)}`
|
icon: props.interactionStore.predictionLegendIcon
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
const option = {
|
const option = {
|
||||||
|
|
@ -196,7 +200,9 @@ const initChart = async () => {
|
||||||
]),
|
]),
|
||||||
|
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
borderColor: node.selfIncludeImplicitRelationship ? "#f8bf38" : "#46C6AD",
|
borderColor: node.selfIncludeImplicitRelationship
|
||||||
|
? props.interactionStore.predictionLineColor
|
||||||
|
: "#46C6AD",
|
||||||
borderWidth: node.selfIncludeImplicitRelationship ? 3 : 1,
|
borderWidth: node.selfIncludeImplicitRelationship ? 3 : 1,
|
||||||
shadowBlur: 4,
|
shadowBlur: 4,
|
||||||
borderType: "dashed",
|
borderType: "dashed",
|
||||||
|
|
@ -233,6 +239,8 @@ const initChart = async () => {
|
||||||
|
|
||||||
const handleClickNode = () => {
|
const handleClickNode = () => {
|
||||||
chart.on("click", function (params) {
|
chart.on("click", function (params) {
|
||||||
|
console.log(params)
|
||||||
|
|
||||||
if (params.dataType === "node") {
|
if (params.dataType === "node") {
|
||||||
emit("click:node", params.data)
|
emit("click:node", params.data)
|
||||||
} else if (params.dataType == "edge") {
|
} else if (params.dataType == "edge") {
|
||||||
|
|
@ -245,7 +253,7 @@ const handleClickNode = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await initChart()
|
initChart()
|
||||||
handleClickNode()
|
handleClickNode()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -55,15 +55,30 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineEmits, onMounted, ref, onUnmounted, computed, watch, nextTick } from "vue"
|
import {
|
||||||
|
defineEmits,
|
||||||
|
onMounted,
|
||||||
|
ref,
|
||||||
|
onUnmounted,
|
||||||
|
computed,
|
||||||
|
watch,
|
||||||
|
nextTick,
|
||||||
|
defineProps
|
||||||
|
} from "vue"
|
||||||
import { TansTimestamp } from "@/utils/transform"
|
import { TansTimestamp } from "@/utils/transform"
|
||||||
import nodeHoverImg from "@/assets/images/nodeHover.png"
|
import nodeHoverImg from "@/assets/images/nodeHover.png"
|
||||||
import * as echarts from "echarts"
|
import * as echarts from "echarts"
|
||||||
import { storeToRefs } from "pinia"
|
import { storeToRefs } from "pinia"
|
||||||
import { useCharacterInteractionStore } from "@/store/llinkPrediction/index"
|
|
||||||
|
|
||||||
const interactionStore = useCharacterInteractionStore()
|
const props = defineProps({
|
||||||
const { communityDetailNodeRelation, timeList, predictionUserIds } = storeToRefs(interactionStore)
|
interactionStore: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const { communityDetailNodeRelation, timeList, predictionUserIds } = storeToRefs(
|
||||||
|
props.interactionStore
|
||||||
|
)
|
||||||
const emit = defineEmits(["click:goback"])
|
const emit = defineEmits(["click:goback"])
|
||||||
const chartsData = ref({})
|
const chartsData = ref({})
|
||||||
const handleGoback = () => {
|
const handleGoback = () => {
|
||||||
|
|
@ -128,13 +143,16 @@ const pause = () => {
|
||||||
// 发送请求逻辑封装
|
// 发送请求逻辑封装
|
||||||
const sendTimeChangeRequest = () => {
|
const sendTimeChangeRequest = () => {
|
||||||
const currentTimes = TansTimestamp(currentTime.value, "YYYY-MM-DD HH:mm:ss")
|
const currentTimes = TansTimestamp(currentTime.value, "YYYY-MM-DD HH:mm:ss")
|
||||||
if (interactionStore.curRelationId == "") {
|
if (props.interactionStore.curRelationId == "") {
|
||||||
interactionStore.initGraphCommunityDetailNode(interactionStore.curSelecedGroupIds, currentTimes)
|
props.interactionStore.initGraphCommunityDetailNode(
|
||||||
|
props.interactionStore.curSelecedGroupIds,
|
||||||
|
currentTimes
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
interactionStore.initGraphCommunityDetailNode(
|
props.interactionStore.initGraphCommunityDetailNode(
|
||||||
interactionStore.curSelecedGroupIds,
|
props.interactionStore.curSelecedGroupIds,
|
||||||
currentTimes,
|
currentTimes,
|
||||||
interactionStore.curRelationId
|
props.interactionStore.curRelationId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -206,16 +224,16 @@ const handlePointPointerDown = (e) => {
|
||||||
isDragging.value = false
|
isDragging.value = false
|
||||||
// 拖动结束时输出当前时间
|
// 拖动结束时输出当前时间
|
||||||
const currentTimes = TansTimestamp(currentTime.value, "YYYY-MM-DD HH:mm:ss")
|
const currentTimes = TansTimestamp(currentTime.value, "YYYY-MM-DD HH:mm:ss")
|
||||||
if (interactionStore.curRelationId == "") {
|
if (props.interactionStore.curRelationId == "") {
|
||||||
interactionStore.initGraphCommunityDetailNode(
|
props.interactionStore.initGraphCommunityDetailNode(
|
||||||
interactionStore.curSelecedGroupIds,
|
props.interactionStore.curSelecedGroupIds,
|
||||||
currentTimes
|
currentTimes
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
interactionStore.initGraphCommunityDetailNode(
|
props.interactionStore.initGraphCommunityDetailNode(
|
||||||
interactionStore.curSelecedGroupIds,
|
props.interactionStore.curSelecedGroupIds,
|
||||||
currentTimes,
|
currentTimes,
|
||||||
interactionStore.curRelationId
|
props.interactionStore.curRelationId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,10 +274,10 @@ const initChart = async () => {
|
||||||
else if (interactionTime > 30) return 10
|
else if (interactionTime > 30) return 10
|
||||||
else return 1
|
else return 1
|
||||||
}
|
}
|
||||||
if (!Object.keys(interactionStore.communityDetailNodeRelation).length) return
|
if (!Object.keys(props.interactionStore.communityDetailNodeRelation).length) return
|
||||||
|
|
||||||
//先处理节点
|
//先处理节点
|
||||||
nodes = interactionStore.communityDetailNodeList.map((item) => ({
|
nodes = props.interactionStore.communityDetailNodeList.map((item) => ({
|
||||||
id: item.userId,
|
id: item.userId,
|
||||||
name: item.userName,
|
name: item.userName,
|
||||||
symbolSize: 40,
|
symbolSize: 40,
|
||||||
|
|
@ -267,7 +285,8 @@ const initChart = async () => {
|
||||||
fancy: item.fans
|
fancy: item.fans
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Object.entries(interactionStore.communityDetailNodeRelation).forEach(([parentId, children]) => {
|
Object.entries(props.interactionStore.communityDetailNodeRelation).forEach(
|
||||||
|
([parentId, children]) => {
|
||||||
children.forEach((child) => {
|
children.forEach((child) => {
|
||||||
links.push({
|
links.push({
|
||||||
source: parentId,
|
source: parentId,
|
||||||
|
|
@ -275,13 +294,15 @@ const initChart = async () => {
|
||||||
edge: child.isHidden ? 1 : 0,
|
edge: child.isHidden ? 1 : 0,
|
||||||
interactionTimes: child.interactionTime,
|
interactionTimes: child.interactionTime,
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
width: child.isHidden ? 4 : edgeWidth(child.interactionTime),
|
width: child.isHidden ? 7 : edgeWidth(child.interactionTime),
|
||||||
color: child.isHidden ? "#f8bf38" : "#37ACD7", // 无互动=灰色,有互动=黄色
|
color: child.isHidden ? props.interactionStore.predictionLineColor : "#37ACD7", // 无互动=灰色,有互动=黄色
|
||||||
|
opacity: child.isHidden ? 1 : 0.5, // 可选:调整透明度增强模糊感
|
||||||
type: child.isHidden ? "dashed" : "solid" // 无互动=实线,有互动=虚线
|
type: child.isHidden ? "dashed" : "solid" // 无互动=实线,有互动=虚线
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
)
|
||||||
chartsData.value = { links, nodes }
|
chartsData.value = { links, nodes }
|
||||||
|
|
||||||
const categories = [
|
const categories = [
|
||||||
|
|
@ -292,9 +313,9 @@ const initChart = async () => {
|
||||||
icon: `image://${new URL("@/assets/images/linkPrediction/icon/interaction-icon2.png", import.meta.url)}`
|
icon: `image://${new URL("@/assets/images/linkPrediction/icon/interaction-icon2.png", import.meta.url)}`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "互动隐关系",
|
name: props.interactionStore.predictionLegendContent,
|
||||||
category: 2,
|
category: 2,
|
||||||
icon: `image://${new URL("@/assets/images/linkPrediction/icon/hidden-icon.png", import.meta.url)}`
|
icon: props.interactionStore.predictionLegendIcon
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
const option = {
|
const option = {
|
||||||
|
|
@ -404,7 +425,7 @@ const initChart = async () => {
|
||||||
zoom: 0.1,
|
zoom: 0.1,
|
||||||
categories: categories,
|
categories: categories,
|
||||||
force: {
|
force: {
|
||||||
edgeLength: 2500,
|
edgeLength: 4000,
|
||||||
repulsion: 4000,
|
repulsion: 4000,
|
||||||
gravity: 0.1,
|
gravity: 0.1,
|
||||||
friction: 0.02,
|
friction: 0.02,
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,13 @@
|
||||||
v-if="interactionStore.curComponent == 'CommunityNode'"
|
v-if="interactionStore.curComponent == 'CommunityNode'"
|
||||||
@click:node="handleClickNode"
|
@click:node="handleClickNode"
|
||||||
@click:edge="handleClickEdge"
|
@click:edge="handleClickEdge"
|
||||||
|
:interaction-store="interactionStore"
|
||||||
></CommunityNode>
|
></CommunityNode>
|
||||||
<DetailNode v-else @click:goback="handleClickGoBack"></DetailNode>
|
<DetailNode
|
||||||
|
v-else
|
||||||
|
@click:goback="handleClickGoBack"
|
||||||
|
:interaction-store="interactionStore"
|
||||||
|
></DetailNode>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -15,30 +20,33 @@
|
||||||
import { defineProps } from "vue"
|
import { defineProps } from "vue"
|
||||||
import CommunityNode from "./communityNode.vue"
|
import CommunityNode from "./communityNode.vue"
|
||||||
import DetailNode from "./detailNode.vue"
|
import DetailNode from "./detailNode.vue"
|
||||||
import { useCharacterInteractionStore } from "@/store/llinkPrediction/index"
|
|
||||||
const interactionStore = useCharacterInteractionStore()
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ""
|
default: ""
|
||||||
|
},
|
||||||
|
interactionStore: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
//点击社团节点
|
//点击社团节点
|
||||||
const handleClickNode = async (nodeInfo) => {
|
const handleClickNode = async (nodeInfo) => {
|
||||||
interactionStore.curComponent = "detailNode"
|
props.interactionStore.curComponent = "detailNode"
|
||||||
interactionStore.curRelationId = ""
|
props.interactionStore.curRelationId = ""
|
||||||
interactionStore.initGraphCommunityDetailNode([nodeInfo.id])
|
props.interactionStore.initGraphCommunityDetailNode([nodeInfo.id])
|
||||||
}
|
}
|
||||||
//点击社团边
|
//点击社团边
|
||||||
const handleClickEdge = (edgeInfo) => {
|
const handleClickEdge = (edgeInfo) => {
|
||||||
interactionStore.curComponent = "detailNode"
|
props.interactionStore.curComponent = "detailNode"
|
||||||
interactionStore.curRelationId = ""
|
props.interactionStore.curRelationId = ""
|
||||||
interactionStore.initGraphCommunityDetailNode([edgeInfo.source, edgeInfo.target])
|
props.interactionStore.initGraphCommunityDetailNode([edgeInfo.source, edgeInfo.target])
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleClickGoBack = (currentComponentName) => {
|
const handleClickGoBack = (currentComponentName) => {
|
||||||
interactionStore.curComponent = currentComponentName
|
props.interactionStore.curComponent = currentComponentName
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user