| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- <template>
- <div ref="chartRef" :class="className" :style="{ height: height, width: width }" />
- </template>
- <script setup>
- import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
- import * as echarts from 'echarts'
- const props = defineProps({
- className: { type: String, default: 'chart' },
- width: { type: String, default: '100%' },
- height: { type: String, default: '300px' },
- autoResize: { type: Boolean, default: true },
- // 三个系列数据
- jdData: { type: Array, default: () => [] },
- sfData: { type: Array, default: () => [] },
- totalData: { type: Array, default: () => [] },
- // X轴标签
- xAxisData: { type: Array, default: () => [] },
- // 可见系列,格式:['jd', 'sf', 'total'] 的子集
- visibleSeries: { type: Array, default: () => ['jd', 'sf', 'total'] }
- })
- const chartRef = ref(null)
- let chartInstance = null
- let resizeObserver = null
- let resizeTimer = null
- // 颜色定义(截图风格)
- const colors = {
- jd: '#FF9800', // 橙色
- sf: '#4CAF50', // 绿色
- total: '#2196F3' // 蓝色
- }
- onMounted(() => {
- nextTick(() => {
- initChart()
- if (props.autoResize) initResizeListener()
- })
- })
- onBeforeUnmount(() => {
- if (resizeTimer) clearTimeout(resizeTimer)
- if (resizeObserver && chartRef.value) {
- resizeObserver.unobserve(chartRef.value)
- resizeObserver.disconnect()
- }
- if (chartInstance) {
- chartInstance.dispose()
- chartInstance = null
- }
- })
- // 监听数据变化
- watch(
- () => [props.jdData, props.sfData, props.totalData, props.xAxisData, props.visibleSeries],
- () => setOptions(),
- { deep: true }
- )
- const handleResize = () => {
- if (resizeTimer) clearTimeout(resizeTimer)
- resizeTimer = setTimeout(() => {
- if (chartInstance) chartInstance.resize()
- }, 200)
- }
- const initResizeListener = () => {
- window.addEventListener('resize', handleResize)
- if (typeof ResizeObserver !== 'undefined' && chartRef.value) {
- resizeObserver = new ResizeObserver(handleResize)
- resizeObserver.observe(chartRef.value)
- }
- }
- const initChart = () => {
- if (!chartRef.value) return
- if (chartInstance) chartInstance.dispose()
- chartInstance = echarts.init(chartRef.value, 'macarons')
- setOptions()
- nextTick(() => chartInstance.resize())
- }
- const setOptions = () => {
- if (!chartInstance) return
- // 构建系列
- const series = []
- // 京东系列
- series.push({
- name: '京东订单',
- type: 'line',
- data: props.jdData,
- smooth: true,
- show: props.visibleSeries.includes('jd'),
- lineStyle: { color: colors.jd, width: 2 },
- itemStyle: { color: colors.jd },
- areaStyle: null,
- animationDuration: 2800,
- animationEasing: 'cubicInOut'
- })
- // 顺丰系列
- series.push({
- name: '顺丰订单',
- type: 'line',
- data: props.sfData,
- smooth: true,
- show: props.visibleSeries.includes('sf'),
- lineStyle: { color: colors.sf, width: 2 },
- itemStyle: { color: colors.sf },
- areaStyle: null,
- animationDuration: 2800,
- animationEasing: 'cubicInOut'
- })
- // 总订单系列(带面积)
- series.push({
- name: '总订单',
- type: 'line',
- data: props.totalData,
- smooth: true,
- show: props.visibleSeries.includes('total'),
- lineStyle: { color: colors.total, width: 2 },
- itemStyle: { color: colors.total },
- areaStyle: { color: 'rgba(33, 150, 243, 0.1)' }, // 浅蓝色面积
- animationDuration: 2800,
- animationEasing: 'cubicInOut'
- })
- // 配置项
- const option = {
- tooltip: {
- trigger: 'axis',
- z: 30,
- show: true,
- showContent: true
- },
- xAxis: {
- data: props.xAxisData,
- boundaryGap: false,
- axisTick: { show: false }
- },
- grid: {
- left: '5%',
- right: '5%',
- bottom: '5%',
- containLabel: true
- },
- yAxis: {
- axisTick: { show: false }
- },
- legend: {
- data: ['京东订单', '顺丰订单', '总订单'],
- top: '2%',
- textStyle: { color: '#666' }
- },
- series
- }
- try {
- chartInstance.setOption(option)
- } catch (error) {
- console.error('设置图表选项失败:', error)
- }
- }
- defineExpose({ resizeChart: handleResize })
- </script>
|