This commit is contained in:
qumeng039@126.com 2025-07-30 16:34:38 +08:00
commit 450852ebdf
5 changed files with 204 additions and 11 deletions

View File

@ -207,6 +207,10 @@ export const useSocialGroupsStore = defineStore("socialGroups", {
curSelecedGroupIds: [],
communityDetailNodeList: [],
timeList: [],
// 当前需要高亮的用户id
curHighlightUserIdList: [],
// 记录点击边的时序列表
clickEdgeTimeList: [],
statisticsList: [
{ id: 1, icon: nodePrefix, name: "节点数", key: "nodesCount" },
{ id: 2, icon: communityPrefix, name: "社团数", key: "groupCount" },
@ -442,6 +446,19 @@ export const useSocialGroupsStore = defineStore("socialGroups", {
}))
this.timeList = res.data.timeList || []
this.communityDetailNodeList = res.data.userRelation
},
// 修改timeList
setTimeList(timeList) {
this.timeList = timeList
},
// 点击边先获取需要的timeList
async getClickEdgeTimeList(ids, time = "2024-05-16 16:56:04") {
const res = await getSocialCommunityDetailNodes(ids, time)
if (res.code != 200) return
console.log("3.获取边中的timelist并设置成它")
this.curHighlightUserIdList = res.data.predictNodes
this.setTimeList(res.data.timeList)
}
},
persist: true // 开启持久化

View File

@ -17,6 +17,20 @@
<div class="time">{{ TansTimestamp(startTime, "YYYY.MM.DD HH:mm:ss") }}</div>
<div class="axis" ref="axisRef" @pointerdown="handlePointerDown">
<div class="progress-bar" :style="trackStyle"></div>
<el-tooltip
v-for="(time, index) in timePointsWithPositions"
:key="index"
:content="TansTimestamp(time.time, 'YYYY.MM.DD HH:mm:ss')"
placement="bottom"
effect="light"
>
<div
class="time-sign"
:class="{ active: isTimeSignActive(time.timeStr) }"
:style="{ left: `${time.position}px` }"
@click="handleTimePointClick(time.timeStr)"
></div>
</el-tooltip>
<div class="active-sign" :style="{ left: `${currentPosition}px` }">
<div class="active-needle"></div>
<el-tooltip
@ -37,7 +51,7 @@
</template>
<script setup>
import { defineEmits, onMounted, ref, onUnmounted, computed, watch } from "vue"
import { defineEmits, onMounted, ref, onUnmounted, computed, watch, nextTick } from "vue"
import { TansTimestamp } from "@/utils/transform"
import nodeHoverImg from "@/assets/images/nodeHover.png"
import * as echarts from "echarts"
@ -45,6 +59,10 @@ import { storeToRefs } from "pinia"
import { useSocialGroupsStore } from "@/store/llinkPrediction/index"
const socialGroupsStore = useSocialGroupsStore()
const { communityDetailNodeList } = storeToRefs(socialGroupsStore)
const { timeList } = storeToRefs(socialGroupsStore)
const { curHighlightUserIdList } = storeToRefs(socialGroupsStore)
const chartsData = ref({})
const emit = defineEmits(["click:goback"])
const handleGoback = () => {
emit("click:goback", "CommunityNode")
@ -58,12 +76,25 @@ watch(
},
{ deep: true }
)
// id
watch(
curHighlightUserIdList,
(newHiglightUserIdList) => {
if(newHiglightUserIdList.length!=0) {
nextTick(()=> {
console.log(newHiglightUserIdList)
highLightUserNodes(newHiglightUserIdList)
})
}
}
)
//
const startTime = ref(new Date("2024-05-16 16:56:04"))
const endTime = ref(new Date("2024-05-23 10:16:56"))
const currentTime = ref(new Date("2024-05-16 16:56:04")) //
const currentPosition = ref(0) //
const axisRef = ref(null)
const isDragging = ref(false)
@ -73,6 +104,53 @@ const startTimeMs = startTime.value.getTime()
const endTimeMs = endTime.value.getTime()
const totalDuration = endTimeMs - startTimeMs
//
const timePointsWithPositions = computed(() => {
// timeList
const list = Array.isArray(timeList.value) ? timeList.value : []
if (list.length === 0) return []
return list.map(timeStr => {
const time = new Date(timeStr)
const timeMs = time.getTime()
const ratio = Math.max(0, Math.min(1, (timeMs - startTimeMs) / totalDuration))
const position = ratio * axisWidth
return { time, position, timeStr }
})
})
watch(timeList, (newList) => {
console.log("🔥 timeList 被更新了:", newList)
})
// watchtimeList
watch(timePointsWithPositions, (newTimePoints) => {
if (newTimePoints && newTimePoints.length > 0) {
const lastTimePoint = newTimePoints[newTimePoints.length - 1]
currentTime.value = lastTimePoint.time
currentPosition.value = lastTimePoint.position
//
const currentTimes = TansTimestamp(currentTime.value, "YYYY-MM-DD HH:mm:ss")
}
}, { immediate: true })
//
const isTimeSignActive = (timeStr) => {
return new Date(timeStr).getTime() === currentTime.value.getTime()
}
//
const handleTimePointClick = (timeStr) => {
const time = new Date(timeStr)
currentTime.value = time
const ratio = (time.getTime() - startTimeMs) / totalDuration
currentPosition.value = ratio * axisWidth
//
const currentTimes = TansTimestamp(currentTime.value, "YYYY-MM-DD HH:mm:ss")
socialGroupsStore.initGraphCommunityDetailNode(socialGroupsStore.curSelecedGroupIds, currentTimes)
}
//
const getTimeFromPosition = (position) => {
const ratio = Math.max(0, Math.min(1, position / axisWidth))
@ -172,12 +250,55 @@ const initChart = async () => {
interactionTimes: child.interactionTime,
lineStyle: {
width: child.isHidden ? 4 : edgeWidth(child.interactionTime),
color: child.isHidden ? "#FF5E00" : "#37ACD7", // ==
color: child.isHidden ? "#37ACD7" : "#37ACD7", // ==
type: child.isHidden ? "dashed" : "solid" // =线=线
}
})
})
})
if(curHighlightUserIdList.value && curHighlightUserIdList.value.length >= 2) {
// timeList
const lastTimeStr = Array.isArray(timeList.value) && timeList.value.length > 0
? timeList.value[timeList.value.length - 1]
: null;
if (lastTimeStr) {
const lastTime = new Date(lastTimeStr).getTime();
const currentTimeMs = currentTime.value.getTime();
//
if (currentTimeMs >= lastTime) {
//
const highlightNodes = curHighlightUserIdList.value;
for (let i = 0; i < highlightNodes.length; i++) {
for (let j = i + 1; j < highlightNodes.length; j++) {
const sourceId = `parent_${highlightNodes[i]}`;
const targetId = `parent_${highlightNodes[j]}`;
// nodes
const sourceExists = nodes.some(n => n.id === sourceId);
const targetExists = nodes.some(n => n.id === targetId);
if (sourceExists && targetExists) {
links.push({
source: sourceId,
target: targetId,
edge: 1,
interactionTimes: 0,
lineStyle: {
width: 4,
color: "#FF5E00",
type: "dashed"
}
});
}
}
}
}
}
}
chartsData.value = { links, nodes }
const data = { links, nodes }
const categories = [
@ -330,7 +451,7 @@ const initChart = async () => {
shadowBlur: 20,
shadowColor: "#c4a651",
borderColor: "#fcd267",
borderWidth: 1,
borderWidth: 5,
borderType: "solid"
}
}
@ -346,6 +467,27 @@ const initChart = async () => {
chart.setOption(option)
}
const highLightUserNodes = (newHiglightUserIdList) => {
if (!newHiglightUserIdList) return
chart.dispatchAction({
type: "downplay",
seriesIndex: 0
})
setTimeout(() => {
//
newHiglightUserIdList.forEach((id) => {
const index = chartsData.value.nodes.findIndex((node) => node.id === `parent_${id}`)
if (index != -1) {
chart.dispatchAction({
type: "highlight",
dataIndex: index
})
}
})
}, 1000)
}
onMounted(() => {
initChart()
chart.on("legendselectchanged", function (params) {
@ -354,6 +496,8 @@ onMounted(() => {
chart.resize()
}, 0)
})
highLightUserNodes()
})
</script>
@ -456,6 +600,30 @@ onMounted(() => {
border-radius: 20px;
z-index: 1;
}
.time-sign{
width: 4px;
height: 18px;
border-radius: 10px;
background: linear-gradient(180deg, #FEE39E 0%, #F9BD25 100%);
z-index: 1;
//
position: absolute;
// 使
top: -6px;
&::before {
content: '';
position: absolute;
top: -6px;
left: -8px;
width: 20px;
height: 30px;
background: transparent;
}
&.active {
opacity: 0;
pointer-events: none;
}
}
.active-sign {
position: relative;
z-index: 2;
@ -499,6 +667,7 @@ onMounted(() => {
position: absolute;
}
}
}
}
.current-time-display {

View File

@ -34,8 +34,13 @@ const handleClickNode = async (nodeInfo) => {
}
const handleClickEdge = async (edgeInfo) => {
console.log("点击边");
socialGroupsStore.curComponent = "detailNode"
socialGroupsStore.initGraphCommunityDetailNode([edgeInfo.source, edgeInfo.target])
// socialGroupsStore.clickEdgeTimeList
console.log("1.初始化获取边中的详情节点-initGraphCommunityDetailNode");
await socialGroupsStore.initGraphCommunityDetailNode([edgeInfo.source, edgeInfo.target])
console.log("2.获取边中的timelist并设置");
await socialGroupsStore.getClickEdgeTimeList([edgeInfo.source, edgeInfo.target])
}
const handleClickGoBack = (currentComponentName) => {

View File

@ -40,6 +40,8 @@
<script setup>
import { defineProps, defineEmits, ref } from "vue";
import defaultAvatar from "@/assets/images/avatar/default.png";
import { useSocialGroupsStore } from "@/store/llinkPrediction/index";
const socialGroupsStore = useSocialGroupsStore()
const curUserGroupIndex = ref(0);
const emit = defineEmits(["click:selectedGroup"]);
const props = defineProps({
@ -59,8 +61,8 @@ const props = defineProps({
const handleUserItem = (index, group = {}) => {
curUserGroupIndex.value = index;
// console.log("item",index);
console.log("点击用户列表中的item",group);
// id
socialGroupsStore.curHighlightUserIdList = group.list.map((item)=>item.userId)
emit("click:selectedGroup", group);
};
</script>

View File

@ -83,12 +83,12 @@ const currentPostPost = ref(null);
const handleSelectedUserGroup = (group) => {
socialGroupsStore.curComponent = "detailkNode"
const groupIds = group?.list.map((item)=>item.groupId)
socialGroupsStore.timeList = group?.timeList
const length = socialGroupsStore.timeList.length
const lastTime = socialGroupsStore.timeList[length - 1]
const groupIds = group.list.map((item)=>item.groupId)
const length = group.timeList.length
const lastTime = group.timeList[length - 1]
socialGroupsStore.initGraphCommunityDetailNode(groupIds, lastTime)
socialGroupsStore.getSocialGroupPostListByRelationId(group?.relationId)
socialGroupsStore.setTimeList(group.timeList)
socialGroupsStore.getSocialGroupPostListByRelationId(group.relationId)
};
onMounted(() => {