link1 initial draft done

This commit is contained in:
chatgpt-yunju 2025-07-04 08:40:57 +08:00
parent 970c793dc0
commit 14f5f9b9cb
15 changed files with 524 additions and 51 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,174 @@
<!-- src/components/weight/ImplicitRelationAnalysis.vue -->
<template>
<div class="implicit-relation-panel">
<img src="@/assets/images/implicit-relation-title.png" class="panel-title-img" alt="互动隐关系预测分析" />
<div class="charts-container">
<div v-for="(section, sectionIndex) in chartData" :key="sectionIndex" class="chart-section">
<div class="section-header">
<span class="icon"></span>
<span class="title">{{ section.title }}</span>
</div>
<div class="axis-container">
<div class="axis">
<span v-for="tick in getTicks(section.max)" :key="tick">{{ tick }}</span>
</div>
<span class="unit">{{ section.unit }}</span>
</div>
<div class="rows-container">
<div v-for="(series, seriesIndex) in section.series" :key="seriesIndex" class="bar-row">
<span class="row-label">{{ series.name }}</span>
<div class="bar-wrapper">
<div class="bar-track">
<!-- Dotted lines for axis ticks -->
<div v-for="tick in getTicks(section.max).slice(1)" :key="tick"
class="tick-line"
:style="{ left: (tick / section.max) * 100 + '%' }">
</div>
<!-- Data bar -->
<div class="bar-fill" :style="{ width: (series.value / section.max) * 100 + '%', backgroundColor: series.color }"></div>
</div>
<span class="bar-value" :style="{ color: series.color }">{{ series.value }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
defineProps({
chartData: {
type: Array,
required: true,
},
});
const getTicks = (max) => {
const ticks = [];
const interval = max / 5; // Create 6 ticks (0, 20, 40, 60, 80, 100) -> 5 intervals
for (let i = 0; i <= max; i += interval) {
ticks.push(Math.round(i));
}
return ticks;
};
</script>
<style scoped>
.implicit-relation-panel {
width: 352px;
height: 410px; /* Adjusted height for content */
background: rgba(2, 8, 13, 0.4);
border: 1px solid #1a8bff;
border-radius: 2px;
display: flex;
flex-direction: column;
padding: 10px 20px;
box-sizing: border-box;
color: #fff;
}
.panel-title-img {
width: 303px;
height: 34px;
align-self: center;
margin-top: 5px;
margin-bottom: 20px;
}
.charts-container {
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.section-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 10px;
}
.section-header .icon {
width: 8px;
height: 8px;
background-color: #29b8fb;
border-radius: 1px;
}
.section-header .title {
font-size: 14px;
}
.axis-container {
display: flex;
align-items: center;
font-size: 12px;
color: #94c2ed;
font-family: 'D-DIN', sans-serif;
margin-bottom: 8px;
padding-left: 60px; /* Align with bars */
}
.axis-container .axis {
flex-grow: 1;
display: flex;
justify-content: space-between;
}
.axis-container .unit {
margin-left: 10px;
}
.bar-row {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.row-label {
width: 60px;
text-align: left;
font-size: 14px;
padding-right: 10px;
flex-shrink: 0;
}
.bar-wrapper {
flex-grow: 1;
display: flex;
align-items: center;
gap: 8px;
}
.bar-track {
flex-grow: 1;
height: 6px;
background-color: rgba(25, 46, 64, 0.5);
border-radius: 3px;
position: relative;
}
.tick-line {
position: absolute;
top: 10px;
height: 40px; /* Height to span across both bars */
border-left: 1px dotted rgba(148, 194, 237, 0.3);
transform: translateX(-50%);
}
.bar-fill {
height: 100%;
border-radius: 3px;
position: relative;
z-index: 2;
}
.bar-value {
font-family: 'D-DIN', sans-serif;
font-size: 16px;
font-weight: bold;
}
</style>

View File

@ -0,0 +1,299 @@
<template>
<!-- Main container -->
<div class="leader-ansys">
<!-- Background SVG provided by the user -->
<div class="bg-svg">
<svg
width="100%"
height="100%"
viewBox="0 0 352 542"
fill="none"
preserveAspectRatio="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M350 0.5H2C1.17157 0.5 0.500008 1.17157 0.5 2V540C0.5 540.828 1.17156 541.5 2 541.5H350C350.828 541.5 351.5 540.828 351.5 540V2C351.5 1.17157 350.828 0.5 350 0.5Z"
fill="url(#paint0_linear_845_47161)"
fill-opacity="0.48"
stroke="url(#paint1_linear_845_47161)"
/>
<defs>
<linearGradient
id="paint0_linear_845_47161"
x1="-1.82995e-07"
y1="167.719"
x2="352"
y2="167.719"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#063D71" stop-opacity="0.2" />
<stop offset="1" stop-color="#081E38" stop-opacity="0.8" />
</linearGradient>
<linearGradient
id="paint1_linear_845_47161"
x1="176"
y1="0"
x2="176"
y2="542"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#3AA1F8" />
<stop offset="1" stop-color="#3AA1F8" stop-opacity="0.2" />
</linearGradient>
</defs>
</svg>
</div>
<!-- Content Area -->
<div class="content">
<!-- Title Image: using a placeholder as the local asset is not available -->
<img
src="../../assets/images/link1t3.png"
alt="传播意见领袖分析"
class="title-img"
style="margin-top: -22px; margin-left: -24px"
/>
<!-- Charts Wrapper -->
<div class="charts-wrapper">
<div v-for="chart in chartData" :key="chart.id" class="chart-section">
<!-- Section Title -->
<div class="section-title">
<span class="icon"></span>
<span>{{ chart.title }}</span>
</div>
<!-- Chart Layout -->
<div class="chart-layout">
<!-- Y-Axis Labels -->
<div class="y-axis-labels">
<span v-for="(row, index) in chart.rows" :key="index">{{ row.label }}</span>
</div>
<!-- Main Chart Area (Gridlines, Bars, X-Axis) -->
<div class="chart-main">
<!-- Grid Lines -->
<div class="grid-lines">
<div v-for="n in 5" :key="n" class="line"></div>
</div>
<!-- Bars -->
<div class="bars">
<div v-for="(row, index) in chart.rows" :key="index" class="bar-container">
<div
class="bar"
:class="row.type"
:style="{ width: (row.value / chart.max) * 100 + '%' }"
></div>
<span class="value" :class="{ highlight: row.highlight }">{{ row.value }}</span>
</div>
</div>
<!-- X-Axis Labels -->
<div class="x-axis-labels">
<span v-for="n in 6" :key="n">{{ (n - 1) * 2 }}</span>
<span class="unit">{{ chart.unit }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
const chartData = ref([
{
id: 1,
title: "平均评论数",
unit: "数量",
max: 10,
rows: [
{ label: "目标用户", value: 90.8, type: "leader" },
{ label: "所有用户", value: 0.01, type: "user" }
]
},
{
id: 2,
title: "平均转发次数",
unit: "天数",
max: 10,
rows: [
{ label: "目标用户", value: 17, type: "leader" },
{ label: "所有用户", value: 0.01, type: "user" }
]
},
{
id: 3,
title: "互动时间间隔",
unit: "天数",
max: 10,
rows: [
{ label: "目标用户", value: 3.63, type: "leader", highlight: false },
{ label: "所有用户", value: 127.63, type: "user" }
]
}
]);
</script>
<style scoped>
.leader-ansys {
position: relative;
width: 372px;
height: 542px;
background-color: #04142166;
border-radius: 2px;
box-shadow: 0px 0px 18px 0px #0a2e55 inset;
backdrop-filter: blur(4px);
color: #fff;
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
overflow: hidden;
box-sizing: border-box;
}
.bg-svg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.content {
position: relative;
z-index: 1;
padding: 15px 25px;
height: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.title-img {
display: block;
margin: 0 auto;
}
.charts-wrapper {
margin-top: 24px;
display: flex;
flex-direction: column;
gap: 20px;
}
.section-title {
display: flex;
align-items: center;
margin-bottom: 16px;
font-size: 16px;
color: #e0e0e0;
}
.section-title .icon {
width: 8px;
height: 8px;
background-color: #3aa1f8;
margin-right: 8px;
flex-shrink: 0;
}
.chart-layout {
display: flex;
}
.y-axis-labels {
display: flex;
flex-direction: column;
justify-content: space-around;
padding-right: 15px;
font-size: 14px;
color: #a9c2e1;
text-align: right;
height: 70px;
flex-shrink: 0;
}
.chart-main {
flex: 1;
position: relative;
}
.grid-lines {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 70px; /* Match Y-axis height */
display: flex;
justify-content: space-between;
}
.grid-lines .line {
width: 1px;
height: 100%;
border-left: 1px dotted rgba(58, 90, 142, 0.5);
}
.grid-lines .line:first-child,
.grid-lines .line:last-child {
display: none;
}
.bars {
position: relative;
z-index: 2;
height: 70px; /* Match Y-axis height */
display: flex;
flex-direction: column;
justify-content: space-around;
}
.bar-container {
display: flex;
align-items: center;
}
.bar {
height: 10px;
border-radius: 5px;
transition: width 0.5s ease-out;
}
.bar.leader {
background: linear-gradient(90deg, #2e7cfb 0%, #3adbf3 100%);
}
.bar.user {
background: linear-gradient(90deg, #07bdb8 0%, #3adbf3 100%);
}
.value {
margin-left: 8px;
font-size: 14px;
color: #ffffff;
white-space: nowrap;
font-size: 20px;
}
.value.highlight {
background-color: #d65050;
padding: 2px 5px;
border-radius: 3px;
font-size: 12px;
}
.x-axis-labels {
margin-top: 8px;
display: flex;
justify-content: space-between;
font-size: 12px;
color: rgba(169, 194, 225, 0.7);
position: relative;
}
.x-axis-labels .unit {
position: absolute;
right: -25px;
top: 0;
}
</style>

View File

@ -323,20 +323,20 @@ const activeLeader = ref({});
const allLeaderData = ref([
{
id: "huxijin",
userid: "huxijin",
name: "Hu Xijin",
chineseName: "胡锡进",
followers: "53.8万",
posts: "54",
avatar: new URL("@/assets/images/huxijin.png", import.meta.url).toString(),
default_avatar: new URL(
"@/assets/images/avatar/1/blue_huxijin.png",
import.meta.url
).toString(),
active_avatar: new URL(
"@/assets/images/avatar/1/light_huxijin.png",
import.meta.url
).toString(),
// default_avatar: new URL(
// "@/assets/images/avatar/1/blue_huxijin.png",
// import.meta.url
// ).toString(),
// active_avatar: new URL(
// "@/assets/images/avatar/1/light_huxijin.png",
// import.meta.url
// ).toString(),
category: "自媒体",
labelling: [
{

View File

@ -91,7 +91,7 @@
</div>
<div class="content-wrapper">
<img
src="../assets/images/graphTitle.png"
src="../assets/images/link1t2.png"
alt=""
style="margin-top: -15px; margin-left: -15px"
/>
@ -275,7 +275,7 @@ import { TitleComponent, TooltipComponent } from "echarts/components";
import { SVGRenderer } from "echarts/renderers";
echarts.use([TitleComponent, TooltipComponent, GraphChart, SVGRenderer]);
//
import LeaderAnalysis from "../components/weight/LeaderAnalysis.vue";
import LeaderAnalysis from "../components/weight/ReleationshipAnalysis.vue";
import InteractionStrengthChart from "../components/weight/InteractionStrengthChart.vue"; // Replaced EventHeatmap
import PostDynamics from "../components/weight/PostDynamics.vue";
import WordCloud from "../components/weight/WordCloud.vue";
@ -340,11 +340,11 @@ const allLeaderData = ref([
posts: "12847",
avatar: new URL("@/assets/images/link1p2.png", import.meta.url).toString(),
default_avatar: new URL(
"@/assets/images/avatar/4/link1p2.png",
"@/assets/images/link1p2.png",
import.meta.url
).toString(),
active_avatar: new URL(
"@/assets/images/avatar/4/link1p2.png",
"@/assets/images/link1p2.png",
import.meta.url
).toString(),
category: "自媒体",
@ -378,11 +378,11 @@ const allLeaderData = ref([
posts: "8380",
avatar: new URL("@/assets/images/link1p3.png", import.meta.url).toString(),
default_avatar: new URL(
"@/assets/images/avatar/4/link1p3.png",
"@/assets/images/link1p3.png",
import.meta.url
).toString(),
active_avatar: new URL(
"@/assets/images/avatar/4/link1p3.png",
"@/assets/images/link1p3.png",
import.meta.url
).toString(),
category: "自媒体",
@ -407,11 +407,11 @@ const allLeaderData = ref([
posts: "11.3万",
avatar: new URL("@/assets/images/link1p4.png", import.meta.url).toString(),
default_avatar: new URL(
"@/assets/images/avatar/4/link1p4.png",
"@/assets/images/link1p4.png",
import.meta.url
).toString(),
active_avatar: new URL(
"@/assets/images/avatar/4/link1p4.png",
"@/assets/images/link1p4.png",
import.meta.url
).toString(),
category: "新闻媒体",
@ -447,11 +447,11 @@ const allLeaderData = ref([
avatar: new URL("@/assets/images/link1p5.png", import.meta.url).toString(),
category: "新闻媒体",
default_avatar: new URL(
"@/assets/images/avatar/4/link1p5.png",
"@/assets/images/link1p5.png",
import.meta.url
).toString(),
active_avatar: new URL(
"@/assets/images/avatar/4/link1p5.png",
"@/assets/images/link1p5.png",
import.meta.url
).toString(),
labelling: [
@ -485,11 +485,11 @@ const allLeaderData = ref([
avatar: new URL("@/assets/images/link1p6.png", import.meta.url).toString(),
category: "新闻媒体",
default_avatar: new URL(
"@/assets/images/avatar/4/link1p6.png",
"@/assets/images/link1p6.png",
import.meta.url
).toString(),
active_avatar: new URL(
"@/assets/images/avatar/4/link1p6.png",
"@/assets/images/link1p6.png",
import.meta.url
).toString(),
labelling: [
@ -714,36 +714,36 @@ const onTimePointClick = (pointId) => {
// ===================================================================
//
// ===================================================================
const analysisChartData = ref([
{
title: "平均发帖数",
unit: "数量",
max: 10,
series: [
{ name: "领袖", value: 6.4 },
{ name: "所有用户", value: 0.46 }
]
},
{
title: "帖子平均生存周期",
unit: "天数",
max: 10,
series: [
{ name: "领袖", value: 2.19 },
{ name: "所有用户", value: 0.46 }
]
},
{
title: "平均粉丝数",
unit: "天数",
max: 10,
series: [
{ name: "领袖", value: 2.19 },
{ name: "所有用户", value: 0.46 }
]
}
]);
// // ===================================================================
// const analysisChartData = ref([
// {
// title: "",
// unit: "",
// max: 10,
// series: [
// { name: "", value: 6.4 },
// { name: "", value: 0.46 }
// ]
// },
// {
// title: "",
// unit: "",
// max: 10,
// series: [
// { name: "", value: 2.19 },
// { name: "", value: 0.46 }
// ]
// },
// {
// title: "",
// unit: "",
// max: 10,
// series: [
// { name: "", value: 2.19 },
// { name: "", value: 0.46 }
// ]
// }
// ]);
const wordCloudData = ref([
{
text: "賴清德",