From 7c2cdcbc7f5585b96fba76a07b0e4417a09c4d7e Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 02 六月 2026 11:06:10 +0800
Subject: [PATCH] 新疆马铃薯 1.过程检验下载添加3个模版

---
 src/components/Echarts/echarts.vue |  223 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 223 insertions(+), 0 deletions(-)

diff --git a/src/components/Echarts/echarts.vue b/src/components/Echarts/echarts.vue
new file mode 100644
index 0000000..54a6c39
--- /dev/null
+++ b/src/components/Echarts/echarts.vue
@@ -0,0 +1,223 @@
+<template>
+  <div style="position: relative;">
+    <div ref="chartRef" :style="chartStyle"></div>
+    <slot></slot>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import * as echarts from 'echarts'
+
+const emit = defineEmits(['finished', 'click'])
+
+// Props
+const props = defineProps({
+  options: {
+    type: Object,
+    default: () => ({})
+  },
+  chartStyle: {
+    type: Object,
+    default: () => ({
+      height: '80%',
+      width: '100%'
+    })
+  },
+  dataset: {
+    type: Object,
+    default: () => { }
+  },
+  xAxis: {
+    type: Array,
+    default: () => []
+  },
+  yAxis: {
+    type: Array,
+    default: () => []
+  },
+  series: {
+    type: Array,
+    default: () => []
+  },
+  grid: {
+    type: Object,
+    default: () => ({})
+  },
+  legend: {
+    type: Object,
+    default: () => ({})
+  },
+  tooltip: {
+    type: Object,
+    default: () => ({})
+  },
+  lineColors: {
+    type: Array,
+    default: () => []
+  },
+  barColors: {
+    type: Array,
+    default: () => []
+  },
+  pieColors: {
+    type: Array,
+    default: () => []
+  },
+  loadingOption: {
+    type: Object,
+    default: () => ({
+      text: '鏁版嵁鍔犺浇涓�...',
+      color: '#00BAFF',
+      textColor: '#000',
+      maskColor: 'rgba(255, 255, 255, 0.8)',
+      zlevel: 0
+    })
+  },
+  color: {
+    type: Array,
+    default: () => []
+  },
+  visualMap: {
+    type: Object,
+    default: () => ({})
+  },
+  option: {
+    type: Object,
+    default: () => ({})
+  },
+})
+
+import { watch } from 'vue'
+
+// Refs
+const chartRef = ref(null)
+let chartInstance = null
+let finishedHandler = null
+let initTimer = null
+let initAttempts = 0
+
+function clearInitTimer() {
+  if (initTimer) {
+    clearTimeout(initTimer)
+    initTimer = null
+  }
+}
+
+function isContainerReady() {
+  const el = chartRef.value
+  if (!el) return false
+  // offsetWidth/offsetHeight 鏇磋创杩戠湡瀹炲竷灞�锛堜负 0 寰�寰�浠h〃杩樻病甯冨眬/涓嶅彲瑙侊級
+  return el.offsetWidth > 0 && el.offsetHeight > 0
+}
+
+function initChartWhenReady() {
+  clearInitTimer()
+  initAttempts += 1
+
+  if (!isContainerReady()) {
+    // 绛夊鍣ㄧ湡姝f湁灏哄锛堥伩鍏嶉灞忓垵濮嬪寲鍋忕Щ/绌虹櫧锛岀儹鏇存柊鍚庢墠姝e父鐨勬儏鍐碉級
+    // 鏈�澶氶噸璇曠害 3 绉掞紝閬垮厤鏃犻檺寰幆
+    if (initAttempts < 60) {
+      initTimer = setTimeout(initChartWhenReady, 50)
+    }
+    return
+  }
+
+  if (chartInstance) return
+  chartInstance = echarts.init(chartRef.value)
+  finishedHandler = () => emit('finished')
+  chartInstance.on('finished', finishedHandler)
+  chartInstance.on('click', (params) => {
+    emit('click', params)
+  })
+  renderChart()
+  // setOption 鍚庤ˉ涓�娆� resize锛岀‘淇濋灞忓昂瀵告纭�
+  nextTick(() => {
+    if (chartInstance) chartInstance.resize()
+  })
+}
+
+// Methods
+function generateChart(option) {
+  const copiedOption = option
+
+  if (copiedOption.series && copiedOption.series.length > 0) {
+    copiedOption.series.forEach((s, index) => {
+      if (s.type === 'line' && props.lineColors.length) {
+        s.itemStyle = s.itemStyle || {}
+        s.lineStyle = s.lineStyle || {}
+        s.itemStyle.color = props.lineColors[index] || props.lineColors[0]
+        s.lineStyle.color = props.lineColors[index] || props.lineColors[0]
+      } else if (s.type === 'bar' && props.barColors.length) {
+        s.itemStyle = s.itemStyle || {}
+        s.itemStyle.color = props.barColors[index] || props.barColors[0]
+      }
+    })
+  }
+
+  chartInstance.setOption(copiedOption)
+}
+
+function renderChart() {
+  const option = {
+    color: props.color.length ? props.color : undefined,
+    backgroundColor: props.options.backgroundColor || '#fff',
+    textStyle: props.options.textStyle || { color: '#333' },
+    xAxis: props.xAxis,
+    yAxis: props.yAxis,
+    dataset: props.dataset,
+    series: props.series,
+    grid: props.grid,
+    legend: props.legend,
+    tooltip: props.tooltip,
+    visualMap: Object.keys(props.visualMap).length ? props.visualMap : undefined,
+  }
+
+  chartInstance.clear()
+  generateChart(option)
+}
+
+function windowResizeListener() {
+  if (!chartInstance) return
+  chartInstance.resize()
+}
+
+// Lifecycle hooks
+onMounted(() => {
+  initAttempts = 0
+  initChartWhenReady()
+  window.addEventListener('resize', windowResizeListener)
+})
+
+onBeforeUnmount(() => {
+  if (chartInstance) {
+    window.removeEventListener('resize', windowResizeListener)
+    if (finishedHandler) {
+      chartInstance.off('finished', finishedHandler)
+      finishedHandler = null
+    }
+    chartInstance.dispose()
+    chartInstance = null
+  }
+  clearInitTimer()
+})
+
+// Watch all reactive props that affect the chart
+watch(
+  () => [props.xAxis, props.yAxis, props.series, props.legend, props.tooltip, props.visualMap],
+  () => {
+    // 濡傛灉棣栧睆杩樻病鍒濆鍖栨垚鍔燂紝绛夊緟瀹瑰櫒 ready 鍚庡啀娓叉煋
+    if (!chartInstance) {
+      initChartWhenReady()
+      return
+    }
+    renderChart()
+    // 鏁版嵁鍙樺寲鍚庤ˉ涓�娆� resize锛岄伩鍏嶅竷灞�鍙樺寲瀵艰嚧鐨勫亸绉�
+    nextTick(() => {
+      if (chartInstance) chartInstance.resize()
+    })
+  },
+  { deep: true, immediate: true }
+)
+</script>
\ No newline at end of file

--
Gitblit v1.9.3