<template>
  <div ref="chartRef" style="width: 800px; height: 500px;"></div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import * as echarts from 'echarts';

const chartRef = ref(null);
const chartInstance = ref(null);

// 配置数据
const days = Array.from({ length: 15 }, (_, i) => `${i + 1}号`);
const actualData = [120, 135, null, null, null, null, null, 210, 175, 190, 205, null, 230, 185, 160];

// 计算无数据区间
const emptyRanges = computed(() => {
  const ranges = [];
  let start = null;
  
  actualData.forEach((val, index) => {
    if (val === null && start === null) {
      start = index;
    } else if (val !== null && start !== null) {
      ranges.push({ start, end: index - 1 });
      start = null;
    }
  });
  
  if (start !== null) {
    ranges.push({ start, end: actualData.length - 1 });
  }
  
  return ranges;
});

// 生成占位点(每个区间中心一个点)
const placeholderPoints = computed(() => {
  return emptyRanges.value.map(range => {
    const centerPos = Math.floor((range.start + range.end) / 2);
    const dayRange = `${days[range.start]}至${days[range.end]}`;
    return {
      xIndex: centerPos,
      info: `${dayRange}无数据\n原因:系统维护期间`
    };
  });
});

// 计算Y轴中点位置
const yMiddle = computed(() => {
  const validData = actualData.filter(v => v !== null);
  return validData.length ? (Math.max(...validData) * 0.6) : 50;
});

// 初始化图表
const initChart = () => {
  if (!chartRef.value) return;
  
  chartInstance.value = echarts.init(chartRef.value);
  
  const option = {
    grid: {
      top: 30,
      right: 30,
      bottom: 30,
      left: 50
    },
    xAxis: {
      type: 'category',
      data: days,
      axisLabel: {
        interval: 0,
        rotate: 45
      },
      axisLine: {
        lineStyle: {
          color: '#999'
        }
      }
    },
    yAxis: {
      type: 'value',
      axisLine: {
        show: true,
        lineStyle: {
          color: '#999'
        }
      },
      splitLine: {
        lineStyle: {
          type: 'dashed'
        }
      }
    },
    tooltip: {
      trigger: 'item',
      formatter: (params) => {
        if (params.seriesName === 'missing') {
          return params.data.info.replace('\n', '<br/>');
        }
        return `${params.name}<br/>值:${params.value}`;
      },
      backgroundColor: 'rgba(50,50,50,0.9)',
      borderColor: '#333',
      textStyle: {
        color: '#fff'
      }
    },
    series: [
      {
        name: 'data',
        type: 'line',
        data: actualData,
        lineStyle: {
          color: '#4285F4',
          width: 3
        },
        itemStyle: {
          color: '#4285F4'
        },
        symbol: 'circle',
        symbolSize: 8,
        emphasis: {
          itemStyle: {
            color: '#FF7043',
            borderColor: '#fff',
            borderWidth: 2
          }
        }
      },
      {
        name: 'data',
        type: 'bar',
        data: actualData,
        lineStyle: {
          color: '#4285F4',
          width: 3
        },
        itemStyle: {
          color: '#4285F4'
        },
        symbol: 'circle',
        symbolSize: 8,
        emphasis: {
          itemStyle: {
            color: '#FF7043',
            borderColor: '#fff',
            borderWidth: 2
          }
        }
      },
      {
        name: 'missing',
        type: 'scatter',
        data: placeholderPoints.value.map(point => ({
          value: [point.xIndex, yMiddle.value],
          info: point.info
        })),
        symbol: 'circle',
        symbolSize: 16,
        itemStyle: {
          color: '#FF5252',
          opacity: 0.8,
          borderColor: '#fff',
          borderWidth: 2
        },
        emphasis: {
          scale: 1.2,
          itemStyle: {
            opacity: 1
          }
        },
        // label: {
        //   show: true,
        //   formatter: '无数据',
        //   color: '#FF5252',
        //   fontWeight: 'bold',
        //   position: 'top'
        // }
      }
    ]
  };
  
  chartInstance.value.setOption(option);
};

// 响应式调整
const handleResize = () => {
  chartInstance.value?.resize();
};

onMounted(() => {
  initChart();
  window.addEventListener('resize', handleResize);
});

onBeforeUnmount(() => {
  window.removeEventListener('resize', handleResize);
  chartInstance.value?.dispose();
});
</script>

<style scoped>
/* 增加图表容器阴影效果 */
div {
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  background: white;
  padding: 10px;
}
</style>

  

posted on 2025-05-18 22:11  铭の  阅读(8)  评论(0)    收藏  举报

友情链接:箫竹影(Java工程师)