冲突解决

This commit is contained in:
duanhao 2025-08-05 11:23:49 +08:00
commit 3f1e4b60e7
7 changed files with 199 additions and 143 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,11 @@
import http from "@/utils/http"
//群体识别发现页面群体列表
export function getGroupEvolutionGroupList(time) {
return http.get(`/groupEvolution/identify/group_list?time=${time}`)
}
//群体识别发现页面群体规模演化图
export function getGroupEvolutionGroupScaleChart() {
return http.get(`/groupEvolution/identify/group_scale`)
}

View File

@ -6,72 +6,57 @@ import mergeImg from "@/assets/images/groupMember/mergeImg.png"
import shrinkImg from "@/assets/images/groupMember/shrinkImg.png" import shrinkImg from "@/assets/images/groupMember/shrinkImg.png"
import expamdImg from "@/assets/images/groupMember/expamdImg.png" import expamdImg from "@/assets/images/groupMember/expamdImg.png"
import defaultAvatar from "@/assets/images/avatar/default.png" import defaultAvatar from "@/assets/images/avatar/default.png"
import {
getGroupEvolutionGroupList,
getGroupEvolutionGroupScaleChart
} from "@/service/api/groupEvolution"
import { TansTimestamp } from "@/utils/transform"
export const useGroupDiscoveryStore = defineStore("groupDiscovery", { export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
state: () => ({ state: () => ({
groupList: [ groupList: [],
{ chartData: {},
id: 1,
type: "群体一",
title: "关注话题:#中国海警首次登检菲律宾运补船只#",
statistics: [
{ id: 1, iconImg: nodePrefix, name: "节点数", value: 293 },
{ id: 2, iconImg: edgePrefix, name: "连边数", value: 21389 }
]
},
{
id: 2,
type: "群体二",
title: "关注话题:#外交部回应中国海警缴获菲律宾士111111.",
statistics: [
{ id: 1, iconImg: nodePrefix, name: "节点数", value: 293 },
{ id: 2, iconImg: edgePrefix, name: "连边数", value: 21389 }
]
},
{
id: 3,
type: "群体三",
title: "关注话题:#美军机在南海盘旋并投放不明物体#",
statistics: [
{ id: 1, iconImg: nodePrefix, name: "节点数", value: 293 },
{ id: 2, iconImg: edgePrefix, name: "连边数", value: 21389 }
]
}
],
chartData: {
xAxisData: ["07:57:46", "09:30:14", "09:57:32", "10:04:47", "10:12:57"],
yAxisRange: { min: 0, max: 800, interval: 100 },
seriesList: [
{
name: "头部自媒体",
themeColor: "#32b6fb",
data: [200, 300, 330, 400, 380]
},
{
name: "官方媒体",
themeColor: "#00d6da",
data: [100, 200, 230, 300, 280]
},
{
name: "普通自媒体",
themeColor: "#fddc33",
data: [300, 400, 430, 500, 480]
}
]
},
chartsData: { chartsData: {
topSelfMedia: { topSelfMedia: {
xAxis: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"], 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, 0.5, 1.0, 1.5, 2.0, 2.5], yAxis: [0, 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] data: [1.0, 0.99, 1.0, 1.0, 1.01, 2.03, 1.2, 0.99]
}, },
officialMedia: { officialMedia: {
xAxis: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"], xAxis: [
yAxis: [0, 0.5, 1.0, 1.5, 2.0, 2.5], "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, 0.5, 1.0, 1.5],
data: [1.0, 0.99, 1.0, 1.0, 1.01, 1.01, 1.2, 0.99] data: [1.0, 0.99, 1.0, 1.0, 1.01, 1.01, 1.2, 0.99]
}, },
ordinaryMedia: { ordinaryMedia: {
xAxis: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"], xAxis: [
yAxis: [0, 1.0, 2.0, 3.0, 4.0, 5.0], "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] data: [1.08, 2.54, 1.47, 1.03, 0.98, 0.99, 1.0, 1.12]
} }
}, },
@ -221,8 +206,43 @@ export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
} }
] ]
}), }),
actions: {}, actions: {
persist: false // 开启持久化 async initializeGroupList(time = "2024-05-16 16:56:04") {
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 = {
群体一: "#32b6fb",
群体二: "#00d6da",
群体三: "#fddc33"
}
resultObj["xAxisData"] = res.data.timeList.map((item) => TansTimestamp(item, "HH:mm:ss"))
resultObj["yAxisRange"] = res.data.scale
resultObj["seriesList"] = []
Object.entries(res.data.data).forEach(([key, list]) => {
resultObj["seriesList"].push({ name: key, themeColor: themeMap[key], data: list })
})
this.chartData = resultObj
}
},
persist: true // 开启持久化
}) })
export const useGroupStructureStore = defineStore("groupStructure", { export const useGroupStructureStore = defineStore("groupStructure", {

View File

@ -17,7 +17,7 @@
</template> </template>
<script setup> <script setup>
import { defineProps, onMounted, onBeforeUnmount, ref, computed } from "vue" import { defineProps, onMounted, onBeforeUnmount, ref, computed, watch, nextTick } from "vue"
import * as echarts from "echarts" import * as echarts from "echarts"
let chartInstance = null let chartInstance = null
@ -69,11 +69,21 @@ const onMouseMove = (e) => {
const percent = newLeft / (sliderContainerWidth.value - sliderWidth) const percent = newLeft / (sliderContainerWidth.value - sliderWidth)
const xIndex = Math.floor(percent * (props.chartData.xAxisData.length - 1)) const xIndex = Math.floor(percent * (props.chartData.xAxisData.length - 1))
// EChartstooltip // ECharts dataZoom
if (chartInstance) { if (chartInstance && props.chartData.xAxisData.length) {
const total = props.chartData.xAxisData.length
const windowSize = Math.floor(total * 0.5) // 50%
let start = Math.floor(percent * (total - windowSize))
let end = start + windowSize
chartInstance.dispatchAction({
type: "dataZoom",
startValue: props.chartData.xAxisData[Math.max(0, start)],
endValue: props.chartData.xAxisData[Math.min(total - 1, end)]
})
// tooltip
chartInstance.dispatchAction({ chartInstance.dispatchAction({
type: "showTip", type: "showTip",
seriesIndex: 0, // tooltip seriesIndex: 0,
dataIndex: xIndex dataIndex: xIndex
}) })
} }
@ -90,6 +100,15 @@ const initChart = () => {
chartInstance = echarts.init(document.getElementById(chartId.value)) chartInstance = echarts.init(document.getElementById(chartId.value))
const legendData = props.chartData.seriesList.map((item) => item.name) const legendData = props.chartData.seriesList.map((item) => item.name)
const option = { const option = {
dataZoom: [
{
type: "slider",
show: false, // dataZoom
xAxisIndex: 0,
start: 0,
end: 60
}
],
tooltip: { tooltip: {
trigger: "axis" trigger: "axis"
}, },
@ -114,43 +133,11 @@ const initChart = () => {
borderWidth: 0, borderWidth: 0,
extraCssText: "box-shadow:none;padding:0;", extraCssText: "box-shadow:none;padding:0;",
formatter: function (params) { formatter: function (params) {
let color = { const color = {
头部自媒体: "#33b6fb", 群体一: "#33b6fb",
官方媒体: "#00d6da", 群体二: "#00d6da",
普通自媒体: "#fddc33" 群体三: "#fddc33"
};
// 使
switch(props.moduleName) {
case "全局群体成员演化图":
color = {
分裂总数: "#2AB8FD",
合并总数: "#02D7DA",
收缩指数: "#FFDA09",
扩展指数: "#EB57B0"
}
break;
case "群体规模演化图":
color = {
头部自媒体: "#33b6fb",
官方媒体: "#00d6da",
普通自媒体: "#fddc33"
}
break;
case "全局异常互动时刻表":
color = {
社团组一: "#2AB8FD",
社团组二: "#02D7DA",
社团组三: "#FFDA09"
}
break;
default:
color = {
头部自媒体: "#33b6fb",
官方媒体: "#00d6da",
普通自媒体: "#fddc33"
}
} }
const listHtml = params const listHtml = params
.map( .map(
(item) => ` (item) => `
@ -260,8 +247,21 @@ const initChart = () => {
chartInstance.setOption(option) chartInstance.setOption(option)
} }
//()
watch(
() => props.chartData,
(newVal) => {
if (newVal && newVal.seriesList && newVal.seriesList.length) {
// DOM
nextTick(() => {
initChart()
})
}
},
{ immediate: true, deep: true }
)
onMounted(() => { onMounted(() => {
initChart()
// //
sliderContainerWidth.value = document.querySelector(".slider-container").offsetWidth sliderContainerWidth.value = document.querySelector(".slider-container").offsetWidth
}) })

View File

@ -10,11 +10,11 @@
alt="" alt=""
/> />
<div class="group-item-title-type">{{ group.type }}</div> <div class="group-item-title-type">{{ group.type }}</div>
<div class="title-content">{{ group.title }}</div> <div class="title-content">关注话题:&nbsp;&nbsp;{{ group.title }}</div>
</div> </div>
<div class="group-item-statistics"> <div class="group-item-statistics">
<div class="statistics-item" v-for="statistic in group.statistics" :key="statistic.id"> <div class="statistics-item" v-for="statistic in group.list" :key="statistic.id">
<img :src="statistic.iconImg" alt="" class="sta-prefix" /> <img :src="statistic.iconImg" alt="" class="sta-prefix" />
<div class="statistics-content"> <div class="statistics-content">
<div class="sta-name">{{ statistic.name }}</div> <div class="sta-name">{{ statistic.name }}</div>

View File

@ -1,7 +1,11 @@
<template> <template>
<div class="postList-component"> <div class="postList-component">
<img <img
<<<<<<< HEAD
:src="isAbnormal ? abnormalTitle : groupEvolutionTitle" :src="isAbnormal ? abnormalTitle : groupEvolutionTitle"
=======
src="@/assets/images/groupEvolution/event-list-title.png"
>>>>>>> 203fd7c18d074bb2c7d3724b8d13e9ef244d7e82
alt="" alt=""
style="margin-top: -17px; margin-left: -11px" style="margin-top: -17px; margin-left: -11px"
/> />
@ -19,9 +23,12 @@
:class="{ highlighted: post.highlighted }" :class="{ highlighted: post.highlighted }"
@click="handleLeaderPost(post)" @click="handleLeaderPost(post)"
> >
<<<<<<< HEAD
<div class="post-type"> <div class="post-type">
<img src="@/assets/images/groupEvolution/group_icon.png" alt=""> <img src="@/assets/images/groupEvolution/group_icon.png" alt="">
</div> </div>
=======
>>>>>>> 203fd7c18d074bb2c7d3724b8d13e9ef244d7e82
<span class="timestamp">{{ post.timestamp }}</span> <span class="timestamp">{{ post.timestamp }}</span>
<span class="author" v-if="props.moduleName == '群体识别发现'">【{{ post.groupCategory }}】&nbsp;&nbsp;的节点数增加<span style="color: #9DF9FE;">{{ post.nodeAddCount }}</span>个,&nbsp;&nbsp;连边增加<span style="color: #9DF9FE;">{{ post.edgeAddCount }}</span> <span class="author" v-if="props.moduleName == '群体识别发现'">【{{ post.groupCategory }}】&nbsp;&nbsp;的节点数增加<span style="color: #9DF9FE;">{{ post.nodeAddCount }}</span>个,&nbsp;&nbsp;连边增加<span style="color: #9DF9FE;">{{ post.edgeAddCount }}</span>
</span> </span>
@ -72,10 +79,14 @@
</template> </template>
<script setup> <script setup>
<<<<<<< HEAD
import abnormalPostItemTitle from "@/assets/images/abnormalGroup/abnormal-action-analysis-item-title.png" import abnormalPostItemTitle from "@/assets/images/abnormalGroup/abnormal-action-analysis-item-title.png"
import groupEvolutionTitle from "@/assets/images/groupEvolution/group-evolution-analysis-titlt.png" import groupEvolutionTitle from "@/assets/images/groupEvolution/group-evolution-analysis-titlt.png"
import abnormalTitle from "@/assets/images/abnormalGroup/abnormal-action-analysis-title.png" import abnormalTitle from "@/assets/images/abnormalGroup/abnormal-action-analysis-title.png"
import { ref, computed, defineProps, defineEmits, onMounted, onBeforeUnmount } from "vue"; import { ref, computed, defineProps, defineEmits, onMounted, onBeforeUnmount } from "vue";
=======
import { ref, computed, defineProps, defineEmits, onMounted, onBeforeUnmount } from "vue"
>>>>>>> 203fd7c18d074bb2c7d3724b8d13e9ef244d7e82
const props = defineProps({ const props = defineProps({
posts: { posts: {
type: Array, type: Array,
@ -89,65 +100,70 @@ const props = defineProps({
type: String, type: String,
required: true required: true
} }
}); })
const emit = defineEmits(["click:openDialog"]); const emit = defineEmits(["click:openDialog"])
const animationDuration = computed(() => `${props.posts.length * 3}s`); const animationDuration = computed(() => `${props.posts.length * 3}s`)
const maxInfluence = 10000; const maxInfluence = 10000
const getInfluenceWidth = (influence) => { const getInfluenceWidth = (influence) => {
const percentage = (influence / maxInfluence) * 100; const percentage = (influence / maxInfluence) * 100
return `${Math.min(percentage, 100)}%`; return `${Math.min(percentage, 100)}%`
}; }
const handleLeaderPost = (item) => { const handleLeaderPost = (item) => {
emit("click:openDialog", item); emit("click:openDialog", item)
console.log(item); console.log(item)
}; }
const listRef = ref(null); const listRef = ref(null)
let scrollTimer = null; let scrollTimer = null
let direction = 1; // 1: , -1: let direction = 1 // 1: , -1:
const scrollStep = 1; // const scrollStep = 1 //
const scrollInterval = 80; // 40ms const scrollInterval = 80 // 40ms
function startScroll() { function startScroll() {
if (scrollTimer) return; if (scrollTimer) return
scrollTimer = setInterval(() => { scrollTimer = setInterval(() => {
const el = listRef.value; const el = listRef.value
if (!el) return; if (!el) return
el.scrollTop += direction * scrollStep; el.scrollTop += direction * scrollStep
// //
if (el.scrollTop + el.clientHeight >= el.scrollHeight) { if (el.scrollTop + el.clientHeight >= el.scrollHeight) {
direction = -1; direction = -1
} }
// //
if (el.scrollTop <= 0) { if (el.scrollTop <= 0) {
direction = 1; direction = 1
} }
}, scrollInterval); }, scrollInterval)
} }
function pauseScroll() { function pauseScroll() {
if (scrollTimer) { if (scrollTimer) {
clearInterval(scrollTimer); clearInterval(scrollTimer)
scrollTimer = null; scrollTimer = null
} }
} }
function resumeScroll() { function resumeScroll() {
startScroll(); startScroll()
} }
onMounted(() => { onMounted(() => {
<<<<<<< HEAD
console.log("打印moudleName:"); console.log("打印moudleName:");
console.log(props.moduleName); console.log(props.moduleName);
console.log(props.posts); console.log(props.posts);
startScroll(); startScroll();
}); });
=======
startScroll()
})
>>>>>>> 203fd7c18d074bb2c7d3724b8d13e9ef244d7e82
onBeforeUnmount(() => { onBeforeUnmount(() => {
pauseScroll(); pauseScroll()
}); })
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

View File

@ -65,31 +65,40 @@
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { onMounted, ref } from "vue"
import GroupPanel from "../component/groupPanel.vue"; import GroupPanel from "../component/groupPanel.vue"
import GroupChart from "../component/groupChart.vue"; import GroupChart from "../component/groupChart.vue"
import GroupPost from "../component/groupPost.vue"; import GroupPost from "../component/groupPost.vue"
import GroupShow from "../component/groupShow.vue"; import GroupShow from "../component/groupShow.vue"
import WordsCloud from "../component/wordsCloud.vue"; import WordsCloud from "../component/wordsCloud.vue"
import groupPanelTitleImg from "@/assets/images/groupEvolution/groupPanel-title.png"; import groupPanelTitleImg from "@/assets/images/groupEvolution/groupPanel-title.png"
import groupChartTitleImg from "@/assets/images/groupEvolution/chart-title.png"; import groupChartTitleImg from "@/assets/images/groupEvolution/chart-title.png"
import groupGroupShowImg from "@/assets/images/groupEvolution/groupDisc-title.png"; import groupGroupShowImg from "@/assets/images/groupEvolution/groupDisc-title.png"
import { Icon } from "@iconify/vue"; import { Icon } from "@iconify/vue"
import { useGroupDiscoveryStore } from "@/store/groupEvolution/index"; import { useGroupDiscoveryStore } from "@/store/groupEvolution/index"
<<<<<<< HEAD
const groupDiscoveryStore = useGroupDiscoveryStore(); const groupDiscoveryStore = useGroupDiscoveryStore();
const moduleName = '群体识别发现'; const moduleName = '群体识别发现';
=======
const groupDiscoveryStore = useGroupDiscoveryStore()
>>>>>>> 203fd7c18d074bb2c7d3724b8d13e9ef244d7e82
// //
const postDialog = ref(false); const postDialog = ref(false)
// //
const currentPostPost = ref(null); const currentPostPost = ref(null)
const handleOpenPostDialog = (post) => { const handleOpenPostDialog = (post) => {
postDialog.value = true; postDialog.value = true
currentPostPost.value = post; currentPostPost.value = post
}; }
onMounted(() => {
groupDiscoveryStore.initializeGroupList()
groupDiscoveryStore.initializeGroupScaleChart()
})
</script> </script>
<style scoped lang="less"> <style scoped lang="less">