#
Junjie
2026-02-02 8f946b567ee6bd0fa40c6d28541d5dcfe7544e5a
#
1个文件已添加
1个文件已修改
362 ■■■■■ 已修改文件
components/EChartsLine/EChartsLine.vue 333 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/dashboard/dashboard.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/EChartsLine/EChartsLine.vue
New file
@@ -0,0 +1,333 @@
<template>
  <view class="echarts-container">
    <!-- #ifdef H5 || APP-PLUS -->
    <view
      :id="chartId"
      class="echarts-chart"
      :style="chartStyle"
    ></view>
    <!-- #endif -->
    <!-- #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO -->
    <view class="mp-not-supported">
      <text class="mp-text">图表组件暂不支持小程序平台</text>
    </view>
    <!-- #endif -->
  </view>
</template>
<script>
export default {
  name: 'EChartsLine',
  props: {
    chartData: {
      type: Object,
      default: () => ({
        categories: [],
        series: []
      })
    },
    width: {
      type: [Number, String],
      default: 400
    },
    height: {
      type: [Number, String],
      default: 250
    },
    colors: {
      type: Array,
      default: () => ['#1890FF', '#F04864']
    }
  },
  data() {
    return {
      chartId: '',
      chartInstance: null
    }
  },
  computed: {
    chartStyle() {
      const w = typeof this.width === 'number' ? `${this.width}px` : this.width
      const h = typeof this.height === 'number' ? `${this.height}px` : this.height
      return { width: w, height: h }
    }
  },
  created() {
    // Generate unique chart ID
    this.chartId = 'echarts-line-' + Math.random().toString(36).substr(2, 9)
  },
  mounted() {
    // Delay initialization to ensure DOM is ready
    setTimeout(() => {
      this.initChart()
    }, 100)
  },
  watch: {
    chartData: {
      handler(newData) {
        if (this.chartInstance) {
          this.updateChart(newData)
        }
      },
      deep: true
    }
  },
  methods: {
    initChart() {
      // #ifdef H5
      this.initH5Chart()
      // #endif
      // #ifdef APP-PLUS
      this.initAppChart()
      // #endif
      // #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO
      this.initMpChart()
      // #endif
    },
    initH5Chart() {
      // For H5 platform, use the existing echarts from qiun-data-charts
      this.$nextTick(() => {
        try {
          const echarts = window.echarts
          if (echarts) {
            this.createChart(echarts)
          } else {
            // Fallback: load from qiun-data-charts
            import('../../uni_modules/qiun-data-charts/static/h5/echarts.min.js').then(module => {
              const echarts = window.echarts || module.default
              this.createChart(echarts)
            }).catch(err => {
              console.error('Failed to load ECharts for H5:', err)
            })
          }
        } catch (error) {
          console.error('Error initializing H5 chart:', error)
        }
      })
    },
    initAppChart() {
      // For App platform
      this.$nextTick(() => {
        try {
          const echarts = window.echarts
          if (echarts) {
            this.createChart(echarts)
          } else {
            // Load from qiun-data-charts
            import('../../uni_modules/qiun-data-charts/static/app-plus/echarts.min.js').then(module => {
              const echarts = window.echarts || module.default
              this.createChart(echarts)
            }).catch(err => {
              console.error('Failed to load ECharts for App:', err)
            })
          }
        } catch (error) {
          console.error('Error initializing App chart:', error)
        }
      })
    },
    initMpChart() {
      // For mini-program platforms
      this.$nextTick(() => {
        try {
          // Use the same approach as qiun-data-charts for mini-programs
          const echarts = window.echarts
          if (echarts) {
            this.createChart(echarts)
          } else {
            console.warn('ECharts not available in mini-program environment')
          }
        } catch (error) {
          console.error('Error initializing mini-program chart:', error)
        }
      })
    },
    createChart(echarts) {
      try {
        const chartDom = document.getElementById(this.chartId)
        if (!chartDom) {
          console.error('Chart DOM element not found with ID:', this.chartId)
          return
        }
        this.chartInstance = echarts.init(chartDom, null, {
          devicePixelRatio: window.devicePixelRatio
        })
        this.updateChart(this.chartData)
        // Handle window resize for H5
        // #ifdef H5
        window.addEventListener('resize', this.handleResize)
        // #endif
      } catch (error) {
        console.error('Error creating chart:', error)
      }
    },
    updateChart(data) {
      if (!this.chartInstance || !data || !data.categories || !data.series) {
        return
      }
      const option = {
        color: this.colors,
        grid: {
          top: '25%',
          left: '5%',
          right: '5%',
          bottom: '10%',
          containLabel: true
        },
        legend: {
          show: true,
          top: '5%',
          itemGap: 20,
          textStyle: {
            color: '#666666',
            fontSize: 14
          }
        },
        xAxis: {
          type: 'category',
          data: data.categories,
          axisLine: {
            lineStyle: {
              color: '#CCCCCC'
            }
          },
          axisLabel: {
            color: '#666666',
            fontSize: 12
          },
          axisTick: {
            show: false
          }
        },
        yAxis: {
          type: 'value',
          axisLine: {
            lineStyle: {
              color: '#CCCCCC'
            }
          },
          axisLabel: {
            color: '#666666',
            fontSize: 12
          },
          splitLine: {
            lineStyle: {
              type: 'dashed',
              color: '#333333'
            }
          },
          axisTick: {
            show: false
          }
        },
        series: data.series.map((serie, index) => ({
          name: serie.name,
          type: 'line',
          data: serie.data,
          smooth: false,
          lineStyle: {
            width: 3,
            color: this.colors[index % this.colors.length]
          },
          itemStyle: {
            color: this.colors[index % this.colors.length]
          },
          symbol: 'circle',
          symbolSize: 8,
          emphasis: {
            itemStyle: {
              borderWidth: 2,
              borderColor: '#fff',
              scale: 1.5
            }
          }
        })),
        tooltip: {
          trigger: 'axis',
          backgroundColor: 'rgba(0, 0, 0, 0.8)',
          borderColor: '#333',
          borderWidth: 1,
          textStyle: {
            color: '#fff',
            fontSize: 14
          },
          formatter: function(params) {
            let result = params[0].axisValue + '<br/>'
            params.forEach(param => {
              result += `${param.seriesName}: ${param.value}<br/>`
            })
            return result
          }
        }
      }
      this.chartInstance.setOption(option, true)
    },
    handleResize() {
      if (this.chartInstance) {
        this.chartInstance.resize()
      }
    },
    // Method to manually resize chart
    resize() {
      if (this.chartInstance) {
        this.chartInstance.resize()
      }
    }
  },
  beforeDestroy() {
    if (this.chartInstance) {
      this.chartInstance.dispose()
      this.chartInstance = null
    }
    // #ifdef H5
    window.removeEventListener('resize', this.handleResize)
    // #endif
  }
}
</script>
<style scoped>
.echarts-container {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.echarts-chart {
  display: block;
}
.mp-not-supported {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.1);
  border-radius: 4px;
}
.mp-text {
  color: #999;
  font-size: 14px;
  text-align: center;
}
</style>
pages/dashboard/dashboard.vue
@@ -91,15 +91,15 @@
                        <view class="panel-content">
                            <view class="panel-header">
                                <text class="panel-title">入出库统计</text>
                                <text class="panel-sub-title">ORDER STATISTICS</text>
                                <text class="panel-sub-title">STATISTICS</text>
                            </view>
                            <view class="chart-container">
                                <qiun-data-charts
                                <EChartsLine
                                    v-if="isLineChartReady"
                                    type="line"
                                    :opts="lineChartOpts"
                                    :chartData="lineChartData"
                                    :ontouch="true"
                                    :colors="['#1890FF', '#F04864']"
                                    width="100%"
                                    height="100%"
                                />
                                <view v-else class="chart-loading" style="display: flex; align-items: center; justify-content: center; height: 100%; color: #999;">
                                    <text>加载中...</text>
@@ -163,7 +163,7 @@
                            <view class="st-head-item">任务: {{station.taskNo}}</view>
                            <view class="st-head-item">类型: {{station.ioTypeName}}</view>
                            <view class="st-head-item" v-if="station.barcode">托盘: {{station.barcode}}</view>
                            <view class="st-head-item">物料数: {{station.wrkDetls.length}}</view>
                            <!-- <view class="st-head-item">物料数: {{station.wrkDetls.length}}</view> -->
                        </view>
                        
                        <!-- Station Body (Material List) -->
@@ -228,6 +228,7 @@
</template>
<script>
    import EChartsLine from '@/components/EChartsLine/EChartsLine.vue'
    import { serverUrl, versionText as localVersionText, versionType as localVersionType } from '../../config'
    /* API Constants */
    const IO_TYPE_NAME_MAP = {
@@ -240,6 +241,9 @@
    }
    export default {
        components: {
            EChartsLine
        },
        data() {
            return {
                serverUrl,
@@ -270,19 +274,6 @@
                        { name: '入库', data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
                        { name: '出库', data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }
                    ]
                },
                lineChartOpts: {
                    color: ['#1890FF', '#F04864'],
                    padding: [15,10,0,15],
                    legend: { show: true, position: 'top', float: 'center' },
                    xAxis: { disableGrid: true, fontColor: '#666666' },
                    yAxis: { gridType: 'dash', gridColor: '#333333', fontColor: '#666666', splitNumber: 5 },
                    extra: {
                        line: {
                            type: 'straight',
                            width: 2
                        }
                    }
                },
                ringChartData: {
                    series: [{