2025-04-18 16:26:51 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div style="height:100%;width:100%" :id="echartsId"></div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import * as echarts from "echarts";
|
2025-09-20 17:29:35 +08:00
|
|
|
|
import { nextTick, onMounted, onUnmounted, watch, defineProps, ref } from "vue";
|
|
|
|
|
|
|
2025-04-18 16:26:51 +08:00
|
|
|
|
const props = defineProps({
|
2025-09-20 17:29:35 +08:00
|
|
|
|
echartsId: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: 'barHatId'
|
2025-04-18 16:26:51 +08:00
|
|
|
|
},
|
2025-09-20 17:29:35 +08:00
|
|
|
|
data: {
|
|
|
|
|
|
type: Object,
|
|
|
|
|
|
default: {
|
2025-04-18 16:26:51 +08:00
|
|
|
|
xDate: ['巴宜区', '工布江达县', '波密县', '朗县', '墨脱县', '察隅县', '米林县'],
|
2025-09-20 17:29:35 +08:00
|
|
|
|
list: [
|
|
|
|
|
|
{ name: "总数", value: [10,20,30,40,50,60,70], color:['rgba(0,244,255,1)','rgba(0,77,167,1)'], hatColor:'#087df9'},
|
|
|
|
|
|
{ name: "已处置", value: [10,20,30,40,50,60,70], color:['rgba(24, 232, 229, 1)','rgba(3, 110, 83, 1)'], hatColor:'#00FFFF'},
|
2025-04-18 16:26:51 +08:00
|
|
|
|
],
|
|
|
|
|
|
}
|
2025-09-20 17:29:35 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 新增:是否启用自动循环展示提示框
|
|
|
|
|
|
autoTooltip: {
|
|
|
|
|
|
type: Boolean,
|
2025-09-20 18:36:44 +08:00
|
|
|
|
default: false
|
2025-09-20 17:29:35 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 新增:提示框循环间隔时间(毫秒)
|
|
|
|
|
|
tooltipInterval: {
|
|
|
|
|
|
type: Number,
|
|
|
|
|
|
default: 2000
|
|
|
|
|
|
},
|
|
|
|
|
|
// 新增:鼠标悬停时是否暂停循环
|
|
|
|
|
|
pauseOnHover: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: true
|
2025-04-18 16:26:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-09-20 17:29:35 +08:00
|
|
|
|
// 响应式变量
|
|
|
|
|
|
const myChart = ref(null);
|
|
|
|
|
|
const tooltipTimer = ref(null);
|
|
|
|
|
|
const currentTooltipIndex = ref(0);
|
|
|
|
|
|
const isPaused = ref(false);
|
|
|
|
|
|
|
|
|
|
|
|
watch(() => props.data, val => {
|
|
|
|
|
|
nextTick(() => { handleDate() })
|
|
|
|
|
|
}, { immediate: true, deep: true })
|
|
|
|
|
|
|
|
|
|
|
|
// 启动自动循环展示提示框
|
|
|
|
|
|
function startAutoTooltip() {
|
|
|
|
|
|
// 详细的条件检查和日志
|
|
|
|
|
|
if (!props.autoTooltip) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!props.data) {
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.warn('自动提示框未启动 - 缺少数据');
|
2025-09-20 17:29:35 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!props.data.xDate || props.data.xDate.length === 0) {
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.warn('自动提示框未启动 - xDate数据为空');
|
2025-09-20 17:29:35 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!props.data.list || props.data.list.length === 0) {
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.warn('自动提示框未启动 - list数据为空');
|
2025-09-20 17:29:35 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!myChart.value) {
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.warn('自动提示框未启动 - 图表实例不存在');
|
2025-09-20 17:29:35 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清除之前的定时器
|
|
|
|
|
|
stopAutoTooltip();
|
|
|
|
|
|
|
|
|
|
|
|
const dataLength = props.data.xDate.length;
|
|
|
|
|
|
currentTooltipIndex.value = 0;
|
|
|
|
|
|
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.log(`开始自动提示框循环 - 数据长度: ${dataLength}, 间隔: ${props.tooltipInterval}ms`);
|
|
|
|
|
|
// console.log('数据预览:', {
|
|
|
|
|
|
// xDate: props.data.xDate.slice(0, 3),
|
|
|
|
|
|
// listCount: props.data.list.length,
|
|
|
|
|
|
// firstSeriesName: props.data.list[0]?.name,
|
|
|
|
|
|
// firstSeriesValueCount: props.data.list[0]?.value?.length
|
|
|
|
|
|
// });
|
2025-09-20 17:29:35 +08:00
|
|
|
|
|
|
|
|
|
|
tooltipTimer.value = setInterval(() => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 检查图表实例是否仍然存在
|
|
|
|
|
|
if (!myChart.value) {
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.error('图表实例丢失,停止自动提示框');
|
2025-09-20 17:29:35 +08:00
|
|
|
|
stopAutoTooltip();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否暂停
|
|
|
|
|
|
if (isPaused.value) {
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.log('提示框循环已暂停');
|
2025-09-20 17:29:35 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 先隐藏当前提示框
|
|
|
|
|
|
myChart.value.dispatchAction({
|
|
|
|
|
|
type: 'hideTip'
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 延迟一点时间再显示新的提示框,确保动画效果
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
if (myChart.value && !isPaused.value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 获取当前数据点信息
|
|
|
|
|
|
const currentData = props.data.xDate[currentTooltipIndex.value];
|
|
|
|
|
|
const currentValues = props.data.list.map(series => series.value[currentTooltipIndex.value]);
|
|
|
|
|
|
|
|
|
|
|
|
// 验证数据有效性
|
|
|
|
|
|
if (currentData === undefined) {
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.error(`数据索引 ${currentTooltipIndex.value} 超出范围`);
|
2025-09-20 17:29:35 +08:00
|
|
|
|
stopAutoTooltip();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示当前索引的提示框 - 使用第一个系列
|
|
|
|
|
|
myChart.value.dispatchAction({
|
|
|
|
|
|
type: 'showTip',
|
|
|
|
|
|
seriesIndex: 0,
|
|
|
|
|
|
dataIndex: currentTooltipIndex.value
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.log(`✓ 显示提示框 [${currentTooltipIndex.value}/${dataLength-1}] - ${currentData}:`, currentValues);
|
2025-09-20 17:29:35 +08:00
|
|
|
|
} catch (error) {
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.error('显示提示框时出错:', error);
|
2025-09-20 17:29:35 +08:00
|
|
|
|
// 如果出错,尝试停止循环避免持续错误
|
|
|
|
|
|
stopAutoTooltip();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 100);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新索引,循环展示
|
|
|
|
|
|
currentTooltipIndex.value = (currentTooltipIndex.value + 1) % dataLength;
|
|
|
|
|
|
} catch (error) {
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.error('自动提示框循环出错:', error);
|
2025-09-20 17:29:35 +08:00
|
|
|
|
stopAutoTooltip();
|
|
|
|
|
|
}
|
|
|
|
|
|
}, props.tooltipInterval);
|
|
|
|
|
|
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.log(`✓ 自动提示框已启动 - 间隔: ${props.tooltipInterval}ms, 数据长度: ${dataLength}`);
|
2025-09-20 17:29:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 停止自动循环展示提示框
|
|
|
|
|
|
function stopAutoTooltip() {
|
|
|
|
|
|
if (tooltipTimer.value) {
|
|
|
|
|
|
clearInterval(tooltipTimer.value);
|
|
|
|
|
|
tooltipTimer.value = null;
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.log('自动提示框已停止');
|
2025-09-20 17:29:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 暂停自动循环
|
|
|
|
|
|
function pauseAutoTooltip() {
|
|
|
|
|
|
isPaused.value = true;
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.log('自动提示框已暂停');
|
2025-09-20 17:29:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 恢复自动循环
|
|
|
|
|
|
function resumeAutoTooltip() {
|
|
|
|
|
|
isPaused.value = false;
|
2025-09-20 19:55:19 +08:00
|
|
|
|
// console.log('自动提示框已恢复');
|
2025-09-20 17:29:35 +08:00
|
|
|
|
}
|
2025-04-18 16:26:51 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理数据
|
|
|
|
|
|
function handleDate() {
|
|
|
|
|
|
let xDate = props.data.xDate;
|
2025-09-20 17:29:35 +08:00
|
|
|
|
let legend = props.data.list.map(v => { return { name: v.name } })
|
|
|
|
|
|
let series = props.data.list.map((item, i) => {
|
2025-04-18 16:26:51 +08:00
|
|
|
|
let obj = {
|
|
|
|
|
|
name: item.name,
|
|
|
|
|
|
type: "bar",
|
|
|
|
|
|
data: item.value,
|
|
|
|
|
|
barWidth: "10px",
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
normal: {
|
2025-09-20 17:29:35 +08:00
|
|
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
2025-04-18 16:26:51 +08:00
|
|
|
|
{ offset: 0, color: item.color ? item.color[0] : "rgba(0,244,255,1)" },
|
2025-09-20 17:29:35 +08:00
|
|
|
|
{ offset: 1, color: item.color ? item.color[1] : "rgba(0,77,167,1)" }], false),
|
2025-04-18 16:26:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
markPoint: {
|
|
|
|
|
|
symbol: 'path://M62 62h900v900h-900v-900z', // 使用 SVG path 绘制扁圆形状
|
|
|
|
|
|
symbolSize: [11, 4], // 设置扁圆的宽和高
|
2025-09-20 17:29:35 +08:00
|
|
|
|
itemStyle: { color: item.hatColor || '#087df9' },// 圆盘颜色
|
2025-04-18 16:26:51 +08:00
|
|
|
|
data: item.value.map((obj, index) => ({
|
|
|
|
|
|
xAxis: index, // 对应柱子的横坐标
|
|
|
|
|
|
yAxis: obj + 0 // 柱子的值加上一些偏移量
|
|
|
|
|
|
}))
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
return obj
|
|
|
|
|
|
})
|
2025-09-20 17:29:35 +08:00
|
|
|
|
lineChartFn(xDate, legend, series)
|
2025-04-18 16:26:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-20 17:29:35 +08:00
|
|
|
|
function lineChartFn(xDate, legend, series) {
|
|
|
|
|
|
myChart.value = echarts.init(document.getElementById(props.echartsId));
|
2025-04-18 16:26:51 +08:00
|
|
|
|
var option = {
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
type: "plain",
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
right: 0,
|
|
|
|
|
|
textStyle: { color: "#ddd" },
|
|
|
|
|
|
data: legend
|
|
|
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
2025-09-20 17:29:35 +08:00
|
|
|
|
trigger: "item",
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.9)',
|
|
|
|
|
|
borderColor: '#00d4ff',
|
|
|
|
|
|
borderWidth: 2,
|
|
|
|
|
|
borderRadius: 8,
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: '#fff',
|
|
|
|
|
|
fontSize: 13,
|
|
|
|
|
|
fontWeight: 'normal'
|
|
|
|
|
|
},
|
|
|
|
|
|
formatter: function(params) {
|
|
|
|
|
|
// 获取当前数据点的所有系列信息
|
|
|
|
|
|
const dataIndex = params.dataIndex;
|
|
|
|
|
|
const categoryName = params.name;
|
|
|
|
|
|
|
|
|
|
|
|
let result = `<div style="margin-bottom: 8px; font-weight: bold; color: #00d4ff; font-size: 14px; border-bottom: 1px solid #00d4ff; padding-bottom: 4px;">${categoryName}</div>`;
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历所有系列,显示该数据点的所有信息
|
|
|
|
|
|
if (props.data && props.data.list) {
|
|
|
|
|
|
props.data.list.forEach((seriesData, index) => {
|
|
|
|
|
|
const value = seriesData.value[dataIndex];
|
|
|
|
|
|
const color = seriesData.color ? seriesData.color[0] : '#00d4ff';
|
|
|
|
|
|
result += `<div style="margin: 4px 0; display: flex; align-items: center;">
|
|
|
|
|
|
<span style="display: inline-block; width: 12px; height: 12px; background: ${color}; border-radius: 50%; margin-right: 8px; border: 1px solid rgba(255,255,255,0.3);"></span>
|
|
|
|
|
|
<span style="color: #fff; margin-right: 8px; min-width: 60px;">${seriesData.name}:</span>
|
|
|
|
|
|
<span style="color: #00d4ff; font-weight: bold; font-size: 14px;">${value}</span>
|
|
|
|
|
|
</div>`;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
},
|
|
|
|
|
|
// 确保提示框能够正确显示
|
|
|
|
|
|
confine: true,
|
|
|
|
|
|
// 添加动画效果
|
|
|
|
|
|
transitionDuration: 0.2,
|
|
|
|
|
|
// 设置提示框位置
|
|
|
|
|
|
position: function (point, params, dom, rect, size) {
|
|
|
|
|
|
// 计算提示框位置,避免超出边界
|
|
|
|
|
|
let x = point[0] + 15;
|
|
|
|
|
|
let y = point[1] - 10;
|
|
|
|
|
|
|
|
|
|
|
|
// 如果右侧空间不够,显示在左侧
|
|
|
|
|
|
if (x + size.contentSize[0] > size.viewSize[0]) {
|
|
|
|
|
|
x = point[0] - size.contentSize[0] - 15;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果上方空间不够,显示在下方
|
|
|
|
|
|
if (y < 0) {
|
|
|
|
|
|
y = point[1] + 20;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return [x, y];
|
2025-04-18 16:26:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
top: "25%",
|
2025-09-20 18:36:44 +08:00
|
|
|
|
right: "2%",
|
|
|
|
|
|
left: "6%",
|
2025-04-18 16:26:51 +08:00
|
|
|
|
bottom: "22%"
|
|
|
|
|
|
},
|
|
|
|
|
|
xAxis: [
|
|
|
|
|
|
{
|
|
|
|
|
|
type: "category",
|
|
|
|
|
|
data: xDate,
|
|
|
|
|
|
axisLine: {
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: "rgba(255,255,255,0.12)"
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
margin: 10,
|
|
|
|
|
|
color: "#e2e9ff",
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
fontSize: 14
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
yAxis: [
|
|
|
|
|
|
{
|
|
|
|
|
|
// name: '单位:万元',
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
formatter: "{value}",
|
|
|
|
|
|
color: "#e2e9ff"
|
|
|
|
|
|
},
|
|
|
|
|
|
axisLine: {
|
|
|
|
|
|
show: false,
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: "rgba(255,255,255,1)"
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
splitLine: {
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: "rgba(255,255,255,0.12)"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
series: series
|
|
|
|
|
|
};
|
2025-09-20 17:29:35 +08:00
|
|
|
|
|
|
|
|
|
|
option && myChart.value.setOption(option);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加鼠标事件监听
|
|
|
|
|
|
if (props.pauseOnHover) {
|
|
|
|
|
|
myChart.value.on('mouseover', () => {
|
|
|
|
|
|
pauseAutoTooltip();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
myChart.value.on('mouseout', () => {
|
|
|
|
|
|
resumeAutoTooltip();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 启动自动循环展示
|
|
|
|
|
|
if (props.autoTooltip) {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
startAutoTooltip();
|
|
|
|
|
|
}, 1000); // 延迟1秒启动,确保图表完全渲染
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
window.onresize = function () {
|
|
|
|
|
|
if (myChart.value) {
|
|
|
|
|
|
myChart.value.resize();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2025-04-18 16:26:51 +08:00
|
|
|
|
}
|
2025-09-20 17:29:35 +08:00
|
|
|
|
|
2025-04-18 16:26:51 +08:00
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
lineChartFn();
|
|
|
|
|
|
});
|
2025-09-20 17:29:35 +08:00
|
|
|
|
|
|
|
|
|
|
// 组件卸载时清理定时器
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
stopAutoTooltip();
|
|
|
|
|
|
if (myChart.value) {
|
|
|
|
|
|
myChart.value.dispose();
|
|
|
|
|
|
myChart.value = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-04-18 16:26:51 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.circlecz {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
background: rgba(0,29,75,0.6);
|
|
|
|
|
|
border-radius: 0 0 4px 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|