LineChart.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <template>
  2. <div ref="chartRef" :class="className" :style="{ height: height, width: width }" />
  3. </template>
  4. <script setup>
  5. import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
  6. import * as echarts from 'echarts'
  7. const props = defineProps({
  8. className: { type: String, default: 'chart' },
  9. width: { type: String, default: '100%' },
  10. height: { type: String, default: '300px' },
  11. autoResize: { type: Boolean, default: true },
  12. // 三个系列数据
  13. jdData: { type: Array, default: () => [] },
  14. sfData: { type: Array, default: () => [] },
  15. totalData: { type: Array, default: () => [] },
  16. // X轴标签
  17. xAxisData: { type: Array, default: () => [] },
  18. // 可见系列,格式:['jd', 'sf', 'total'] 的子集
  19. visibleSeries: { type: Array, default: () => ['jd', 'sf', 'total'] }
  20. })
  21. const chartRef = ref(null)
  22. let chartInstance = null
  23. let resizeObserver = null
  24. let resizeTimer = null
  25. // 颜色定义(截图风格)
  26. const colors = {
  27. jd: '#FF9800', // 橙色
  28. sf: '#4CAF50', // 绿色
  29. total: '#2196F3' // 蓝色
  30. }
  31. onMounted(() => {
  32. nextTick(() => {
  33. initChart()
  34. if (props.autoResize) initResizeListener()
  35. })
  36. })
  37. onBeforeUnmount(() => {
  38. if (resizeTimer) clearTimeout(resizeTimer)
  39. if (resizeObserver && chartRef.value) {
  40. resizeObserver.unobserve(chartRef.value)
  41. resizeObserver.disconnect()
  42. }
  43. if (chartInstance) {
  44. chartInstance.dispose()
  45. chartInstance = null
  46. }
  47. })
  48. // 监听数据变化
  49. watch(
  50. () => [props.jdData, props.sfData, props.totalData, props.xAxisData, props.visibleSeries],
  51. () => setOptions(),
  52. { deep: true }
  53. )
  54. const handleResize = () => {
  55. if (resizeTimer) clearTimeout(resizeTimer)
  56. resizeTimer = setTimeout(() => {
  57. if (chartInstance) chartInstance.resize()
  58. }, 200)
  59. }
  60. const initResizeListener = () => {
  61. window.addEventListener('resize', handleResize)
  62. if (typeof ResizeObserver !== 'undefined' && chartRef.value) {
  63. resizeObserver = new ResizeObserver(handleResize)
  64. resizeObserver.observe(chartRef.value)
  65. }
  66. }
  67. const initChart = () => {
  68. if (!chartRef.value) return
  69. if (chartInstance) chartInstance.dispose()
  70. chartInstance = echarts.init(chartRef.value, 'macarons')
  71. setOptions()
  72. nextTick(() => chartInstance.resize())
  73. }
  74. const setOptions = () => {
  75. if (!chartInstance) return
  76. // 构建系列
  77. const series = []
  78. // 京东系列
  79. series.push({
  80. name: '京东订单',
  81. type: 'line',
  82. data: props.jdData,
  83. smooth: true,
  84. show: props.visibleSeries.includes('jd'),
  85. lineStyle: { color: colors.jd, width: 2 },
  86. itemStyle: { color: colors.jd },
  87. areaStyle: null,
  88. animationDuration: 2800,
  89. animationEasing: 'cubicInOut'
  90. })
  91. // 顺丰系列
  92. series.push({
  93. name: '顺丰订单',
  94. type: 'line',
  95. data: props.sfData,
  96. smooth: true,
  97. show: props.visibleSeries.includes('sf'),
  98. lineStyle: { color: colors.sf, width: 2 },
  99. itemStyle: { color: colors.sf },
  100. areaStyle: null,
  101. animationDuration: 2800,
  102. animationEasing: 'cubicInOut'
  103. })
  104. // 总订单系列(带面积)
  105. series.push({
  106. name: '总订单',
  107. type: 'line',
  108. data: props.totalData,
  109. smooth: true,
  110. show: props.visibleSeries.includes('total'),
  111. lineStyle: { color: colors.total, width: 2 },
  112. itemStyle: { color: colors.total },
  113. areaStyle: { color: 'rgba(33, 150, 243, 0.1)' }, // 浅蓝色面积
  114. animationDuration: 2800,
  115. animationEasing: 'cubicInOut'
  116. })
  117. // 配置项
  118. const option = {
  119. tooltip: {
  120. trigger: 'axis',
  121. z: 30,
  122. show: true,
  123. showContent: true
  124. },
  125. xAxis: {
  126. data: props.xAxisData,
  127. boundaryGap: false,
  128. axisTick: { show: false }
  129. },
  130. grid: {
  131. left: '5%',
  132. right: '5%',
  133. bottom: '5%',
  134. containLabel: true
  135. },
  136. yAxis: {
  137. axisTick: { show: false }
  138. },
  139. legend: {
  140. data: ['京东订单', '顺丰订单', '总订单'],
  141. top: '2%',
  142. textStyle: { color: '#666' }
  143. },
  144. series
  145. }
  146. try {
  147. chartInstance.setOption(option)
  148. } catch (error) {
  149. console.error('设置图表选项失败:', error)
  150. }
  151. }
  152. defineExpose({ resizeChart: handleResize })
  153. </script>