2025-07-17 10:28:56 +08:00
|
|
|
<template>
|
|
|
|
|
<div class="panel-container event-hot">
|
|
|
|
|
<!-- 1. 标题行 -->
|
|
|
|
|
<div class="header-title">
|
|
|
|
|
<img
|
|
|
|
|
src="../../assets/images/evenhot.png"
|
|
|
|
|
alt=""
|
|
|
|
|
style="margin-top: -22px; margin-left: -22px"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 2. 控件行 -->
|
|
|
|
|
<div class="header-controls">
|
|
|
|
|
<div class="chart-tabs">
|
|
|
|
|
<button :class="{ active: activeChartTab === 'trend' }" @click="activeChartTab = 'trend'">
|
|
|
|
|
时序热度图
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
:class="{ active: activeChartTab === 'cumulative' }"
|
|
|
|
|
@click="activeChartTab = 'cumulative'"
|
|
|
|
|
>
|
|
|
|
|
累计热度图
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="details-btn" @click="showDetails">查看详情</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 3. ECharts 容器 -->
|
|
|
|
|
<div ref="hotspotChart" class="chart-container"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, watch, onMounted, onUnmounted, defineProps } from "vue";
|
|
|
|
|
import * as echarts from "echarts";
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
panelTrendData: {
|
|
|
|
|
//时序热度列表
|
|
|
|
|
type: Array,
|
|
|
|
|
default: () => []
|
|
|
|
|
},
|
|
|
|
|
panelXAxisLabels: {
|
|
|
|
|
//x轴
|
|
|
|
|
type: Array,
|
|
|
|
|
default: () => []
|
|
|
|
|
},
|
|
|
|
|
granularTrendData: {
|
|
|
|
|
//查看详情数据
|
|
|
|
|
type: Array,
|
|
|
|
|
default: () => []
|
|
|
|
|
},
|
|
|
|
|
granularXAxisLabels: {
|
|
|
|
|
//查看详情x轴数据
|
|
|
|
|
type: Array,
|
|
|
|
|
default: () => []
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits(["showDetails"]);
|
|
|
|
|
|
|
|
|
|
// ===================================================================
|
|
|
|
|
// 数据定义与处理
|
|
|
|
|
// ===================================================================
|
|
|
|
|
const activeChartTab = ref("trend");
|
|
|
|
|
|
|
|
|
|
// --- 完整/详情用数据 (Granular/Details Data) ---
|
|
|
|
|
const granularTrendData = props.granularTrendData;
|
|
|
|
|
const granularXAxisLabels = props.granularXAxisLabels;
|
|
|
|
|
const granularCumulativeData = granularTrendData.reduce((acc, val) => {
|
|
|
|
|
acc.push((acc.length > 0 ? acc[acc.length - 1] : 0) + val);
|
|
|
|
|
return acc;
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// --- 面板用数据 (Panel Data - Daily Summary) ---
|
|
|
|
|
const panelTrendData = props.panelTrendData; // Figma中的数据
|
|
|
|
|
const panelXAxisLabels = props.panelXAxisLabels;
|
|
|
|
|
const panelCumulativeData = panelTrendData.reduce((acc, val) => {
|
|
|
|
|
acc.push((acc.length > 0 ? acc[acc.length - 1] : 0) + val);
|
|
|
|
|
return acc;
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// --- 整合数据集 ---
|
|
|
|
|
const chartDataSets = {
|
|
|
|
|
panel: {
|
|
|
|
|
trend: { data: panelTrendData, xAxis: panelXAxisLabels, yAxisMax: 60000 },
|
|
|
|
|
cumulative: { data: panelCumulativeData, xAxis: panelXAxisLabels, yAxisMax: 120000 }
|
|
|
|
|
},
|
|
|
|
|
details: {
|
|
|
|
|
trend: { data: granularTrendData, xAxis: granularXAxisLabels, yAxisMax: 20000 },
|
|
|
|
|
cumulative: { data: granularCumulativeData, xAxis: granularXAxisLabels, yAxisMax: 120000 }
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ===================================================================
|
|
|
|
|
// ECharts 逻辑
|
|
|
|
|
// ===================================================================
|
|
|
|
|
const hotspotChart = ref(null);
|
|
|
|
|
let myChart = null;
|
|
|
|
|
|
|
|
|
|
const getChartOptions = (xAxisData, seriesData, yMax, rotate = 0) => ({
|
|
|
|
|
tooltip: {
|
|
|
|
|
trigger: "axis",
|
|
|
|
|
backgroundColor: "rgba(0,21,41,0.8)",
|
|
|
|
|
borderColor: "#3a95ff",
|
2025-07-18 17:44:13 +08:00
|
|
|
textStyle: { color: "#cbeaff" },
|
2025-07-17 10:28:56 +08:00
|
|
|
},
|
|
|
|
|
grid: { left: "3%", right: "8%", bottom: "5%", top: "20%", containLabel: true },
|
|
|
|
|
xAxis: {
|
|
|
|
|
type: "category",
|
|
|
|
|
boundaryGap: false,
|
|
|
|
|
data: xAxisData,
|
|
|
|
|
axisLine: { lineStyle: { color: "rgba(62, 115, 171, 0.5)" } },
|
|
|
|
|
axisLabel: { color: "#a7c5d4", fontSize: 10, rotate: rotate, interval: 0 },
|
|
|
|
|
axisTick: { show: false }
|
|
|
|
|
},
|
|
|
|
|
yAxis: {
|
|
|
|
|
type: "value",
|
|
|
|
|
max: yMax,
|
|
|
|
|
axisLabel: { color: "#a7c5d4", fontSize: 12 },
|
|
|
|
|
splitLine: { show: true, lineStyle: { color: "rgba(62, 115, 171, 0.2)", type: "dashed" } }
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
name: "热度",
|
|
|
|
|
type: "line",
|
|
|
|
|
smooth: true,
|
|
|
|
|
symbol: "circle",
|
|
|
|
|
symbolSize: 8,
|
|
|
|
|
data: seriesData,
|
|
|
|
|
label: { show: true, position: "top", color: "#cdeeff", fontSize: 12 },
|
|
|
|
|
itemStyle: { color: "#00baff", borderColor: "#041421", borderWidth: 2 },
|
|
|
|
|
lineStyle: { color: "#00baff", width: 2 },
|
|
|
|
|
areaStyle: {
|
|
|
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
{ offset: 0, color: "rgba(0, 186, 255, 0.4)" },
|
|
|
|
|
{ offset: 1, color: "rgba(0, 186, 255, 0)" }
|
|
|
|
|
])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 监听标签页切换,更新面板小图
|
|
|
|
|
watch(activeChartTab, (newTab) => {
|
|
|
|
|
if (myChart) {
|
|
|
|
|
const dataSet = chartDataSets.panel[newTab];
|
|
|
|
|
myChart.setOption({
|
|
|
|
|
xAxis: [{ data: dataSet.xAxis }],
|
|
|
|
|
yAxis: { max: dataSet.yAxisMax },
|
|
|
|
|
series: [{ data: dataSet.data }]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 点击“查看详情”时,触发事件并传递完整数据
|
|
|
|
|
const showDetails = () => {
|
|
|
|
|
const dataSet = chartDataSets.details[activeChartTab.value];
|
|
|
|
|
const rotate = dataSet.xAxis.length > 5 ? 15 : 0;
|
|
|
|
|
const option = getChartOptions(dataSet.xAxis, dataSet.data, dataSet.yAxisMax, rotate);
|
|
|
|
|
emit("showDetails", { option });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
if (hotspotChart.value) {
|
|
|
|
|
myChart = echarts.init(hotspotChart.value);
|
|
|
|
|
// 初始化时使用面板数据
|
|
|
|
|
const initialDataSet = chartDataSets.panel[activeChartTab.value];
|
|
|
|
|
myChart.setOption(
|
|
|
|
|
getChartOptions(initialDataSet.xAxis, initialDataSet.data, initialDataSet.yAxisMax)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
if (myChart) myChart.dispose();
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
/* 容器样式,无边框 */
|
|
|
|
|
.panel-container {
|
|
|
|
|
width: 350px;
|
|
|
|
|
height: 276px;
|
|
|
|
|
background: rgba(4, 20, 33, 0.4);
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
box-shadow: 0 0 18px 0 #0a2e55 inset;
|
|
|
|
|
backdrop-filter: blur(4px);
|
|
|
|
|
-webkit-backdrop-filter: blur(4px);
|
|
|
|
|
padding: 15px 20px;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
border: 1px solid #1a8bff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 标题行 */
|
|
|
|
|
.header-title {
|
|
|
|
|
width: 100%;
|
|
|
|
|
margin-bottom: 5px;
|
|
|
|
|
}
|
|
|
|
|
.header-title img {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 控件行 */
|
|
|
|
|
.header-controls {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chart-tabs {
|
|
|
|
|
display: flex;
|
|
|
|
|
border: 1px solid #1c588f;
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
background-color: #031826;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chart-tabs button {
|
|
|
|
|
background: none;
|
|
|
|
|
border: none;
|
|
|
|
|
color: #a7c5d4;
|
|
|
|
|
padding: 4px 12px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chart-tabs button.active {
|
|
|
|
|
background-color: #236291;
|
|
|
|
|
color: white;
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.details-btn {
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
background: none;
|
|
|
|
|
border: 1px solid #1c588f;
|
|
|
|
|
color: #a7c5d4;
|
|
|
|
|
padding: 4px 12px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chart-container {
|
|
|
|
|
flex-grow: 1;
|
|
|
|
|
width: 100%;
|
|
|
|
|
margin-left: -10px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|