<template>
  <div class="chart-card">
    <!-- 图表头部 -->
    <div class="chart-header">
      <div class="header-left">
        <h3 class="chart-title">{{ title }}</h3>
        <p class="chart-subtitle" v-if="subtitle">{{ subtitle }}</p>
      </div>
      <div class="header-right">
        <el-dropdown @command="handleCommand">
          <el-button type="text" icon="el-icon-more">
            <i class="el-icon-arrow-down el-icon--right"></i>
          </el-button>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item command="refresh">刷新</el-dropdown-item>
            <el-dropdown-item command="export">导出</el-dropdown-item>
            <el-dropdown-item command="fullscreen">全屏</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
      </div>
    </div>

    <!-- 图表内容 -->
    <div class="chart-content" v-loading="loading">
      <!-- 图表容器 -->
      <div
        ref="chartContainer"
        class="chart-container"
        :style="{ height: chartHeight + 'px' }"
      ></div>

      <!-- 无数据状态 -->
      <div class="no-data" v-if="!loading && (!data || data.length === 0)">
        <i class="el-icon-data-line"></i>
        <p>暂无数据</p>
      </div>

      <!-- 图表加载失败 -->
      <div class="chart-error" v-if="error">
        <i class="el-icon-warning"></i>
        <p>{{ error }}</p>
        <el-button type="text" @click="retry">重试</el-button>
      </div>
    </div>

    <!-- 图表底部信息 -->
    <div class="chart-footer" v-if="footerInfo">
      <div class="footer-info">
        <span v-for="(info, index) in footerInfo" :key="index" class="info-item">
          <span class="info-label">{{ info.label }}:</span>
          <span class="info-value">{{ info.value }}</span>
        </span>
      </div>
    </div>
  </div>
</template>

<script>
import * as echarts from 'echarts'

export default {
  name: 'ChartCard',
  props: {
    title: {
      type: String,
      required: true
    },
    subtitle: {
      type: String,
      default: ''
    },
    type: {
      type: String,
      default: 'line',
      validator: value => ['line', 'bar', 'pie', 'scatter', 'gauge', 'funnel'].includes(value)
    },
    data: {
      type: Array,
      default: () => []
    },
    options: {
      type: Object,
      default: () => ({})
    },
    loading: {
      type: Boolean,
      default: false
    },
    height: {
      type: Number,
      default: 300
    },
    footerInfo: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      chart: null,
      error: null,
      chartHeight: this.height
    }
  },
  computed: {
    // 合并默认配置和用户配置
    chartOptions() {
      const defaultOptions = this.getDefaultOptions()
      return this.mergeOptions(defaultOptions, this.options)
    }
  },
  watch: {
    data: {
      handler() {
        this.updateChart()
      },
      deep: true
    },
    options: {
      handler() {
        this.updateChart()
      },
      deep: true
    },
    loading(newVal) {
      if (!newVal && this.chart) {
        this.updateChart()
      }
    }
  },
  mounted() {
    this.initChart()
    window.addEventListener('resize', this.handleResize)
  },
  beforeDestroy() {
    if (this.chart) {
      this.chart.dispose()
    }
    window.removeEventListener('resize', this.handleResize)
  },
  methods: {
    // 初始化图表
    initChart() {
      if (!this.$refs.chartContainer) return

      try {
        this.chart = echarts.init(this.$refs.chartContainer)
        this.updateChart()
        this.error = null
      } catch (error) {
        console.error('图表初始化失败:', error)
        this.error = '图表初始化失败'
      }
    },

    // 更新图表
    updateChart() {
      if (!this.chart || this.loading) return

      try {
        const options = this.chartOptions
        this.chart.setOption(options, true)
        this.error = null
      } catch (error) {
        console.error('图表更新失败:', error)
        this.error = '图表更新失败'
      }
    },

    // 获取默认配置
    getDefaultOptions() {
      const baseOptions = {
        tooltip: {
          trigger: 'axis',
          backgroundColor: 'rgba(0, 0, 0, 0.8)',
          borderColor: 'transparent',
          textStyle: {
            color: '#fff'
          }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        color: ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399']
      }

      switch (this.type) {
        case 'line':
          return {
            ...baseOptions,
            xAxis: {
              type: 'category',
              boundaryGap: false,
              data: this.data.map(item => item.time || item.name || item.x)
            },
            yAxis: {
              type: 'value'
            },
            series: [{
              type: 'line',
              data: this.data.map(item => item.value || item.y),
              smooth: true,
              areaStyle: {
                opacity: 0.1
              }
            }]
          }

        case 'bar':
          return {
            ...baseOptions,
            xAxis: {
              type: 'category',
              data: this.data.map(item => item.name || item.x)
            },
            yAxis: {
              type: 'value'
            },
            series: [{
              type: 'bar',
              data: this.data.map(item => item.value || item.y),
              barWidth: '60%'
            }]
          }

        case 'pie':
          return {
            ...baseOptions,
            tooltip: {
              trigger: 'item',
              formatter: '{a} <br/>{b}: {c} ({d}%)'
            },
            series: [{
              type: 'pie',
              radius: ['40%', '70%'],
              data: this.data,
              emphasis: {
                itemStyle: {
                  shadowBlur: 10,
                  shadowOffsetX: 0,
                  shadowColor: 'rgba(0, 0, 0, 0.5)'
                }
              }
            }]
          }

        case 'gauge':
          return {
            ...baseOptions,
            series: [{
              type: 'gauge',
              data: this.data,
              radius: '80%',
              startAngle: 200,
              endAngle: -20,
              min: 0,
              max: 100,
              splitNumber: 10,
              axisLine: {
                lineStyle: {
                  width: 6
                }
              },
              axisTick: {
                distance: -30,
                splitNumber: 5,
                lineStyle: {
                  width: 2,
                  color: '#999'
                }
              },
              axisLabel: {
                distance: -20,
                color: '#999',
                fontSize: 12
              },
              pointer: {
                itemStyle: {
                  color: 'auto'
                }
              },
              title: {
                color: '#999'
              },
              detail: {
                valueAnimation: true,
                formatter: '{value}%',
                color: 'auto'
              }
            }]
          }

        default:
          return baseOptions
      }
    },

    // 合并配置
    mergeOptions(defaultOptions, userOptions) {
      return {
        ...defaultOptions,
        ...userOptions,
        series: userOptions.series || defaultOptions.series
      }
    },

    // 处理窗口大小变化
    handleResize() {
      if (this.chart) {
        this.chart.resize()
      }
    },

    // 处理下拉菜单命令
    handleCommand(command) {
      switch (command) {
        case 'refresh':
          this.$emit('refresh')
          break
        case 'export':
          this.exportChart()
          break
        case 'fullscreen':
          this.toggleFullscreen()
          break
      }
    },

    // 导出图表
    exportChart() {
      if (!this.chart) return

      try {
        const url = this.chart.getDataURL({
          type: 'png',
          pixelRatio: 2,
          backgroundColor: '#fff'
        })

        const link = document.createElement('a')
        link.download = `${this.title}_${new Date().getTime()}.png`
        link.href = url
        link.click()

        this.$message.success('图表导出成功')
      } catch (error) {
        console.error('图表导出失败:', error)
        this.$message.error('图表导出失败')
      }
    },

    // 切换全屏
    toggleFullscreen() {
      this.$emit('fullscreen', this.title)
    },

    // 重试
    retry() {
      this.error = null
      this.initChart()
    }
  }
}
</script>

<style scoped>
.chart-card {
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  transition: all 0.3s ease;
}

.chart-card:hover {
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}

.chart-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid #f0f0f0;
}

.header-left {
  flex: 1;
}

.chart-title {
  margin: 0 0 4px 0;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.chart-subtitle {
  margin: 0;
  font-size: 12px;
  color: #909399;
}

.header-right {
  display: flex;
  align-items: center;
}

.chart-content {
  position: relative;
  padding: 20px;
}

.chart-container {
  width: 100%;
  min-height: 200px;
}

.no-data {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 200px;
  color: #c0c4cc;
}

.no-data i {
  font-size: 48px;
  margin-bottom: 12px;
}

.no-data p {
  margin: 0;
  font-size: 14px;
}

.chart-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 200px;
  color: #f56c6c;
}

.chart-error i {
  font-size: 48px;
  margin-bottom: 12px;
}

.chart-error p {
  margin: 0 0 12px 0;
  font-size: 14px;
}

.chart-footer {
  padding: 12px 20px;
  border-top: 1px solid #f0f0f0;
  background-color: #fafafa;
}

.footer-info {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.info-item {
  font-size: 12px;
  color: #606266;
}

.info-label {
  font-weight: 500;
  margin-right: 4px;
}

.info-value {
  color: #909399;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .chart-header {
    padding: 12px 16px;
  }

  .chart-title {
    font-size: 14px;
  }

  .chart-content {
    padding: 16px;
  }

  .chart-container {
    min-height: 150px;
  }

  .chart-footer {
    padding: 8px 16px;
  }

  .footer-info {
    gap: 8px;
  }
}

/* 动画效果 */
.chart-card {
  animation: fadeInUp 0.6s ease-out;
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* 加载状态样式 */
.chart-content .el-loading-mask {
  background-color: rgba(255, 255, 255, 0.8);
}

.chart-content .el-loading-spinner {
  margin-top: -25px;
}

.chart-content .el-loading-spinner .el-icon-loading {
  font-size: 24px;
  color: #409EFF;
}
</style>

