<template>
  <div class="app-container" v-loading="loading">
    <el-card class="topCard">
      <div class="topDiv">
        <span style="margin-left: 10px">工位号：</span>
        <el-select
          v-model="stationValue"
          placeholder="全部工位"
          clearable
          filterable
          size="small"
          style="width: 180px"
        >
          <el-option
            v-for="item in stationList"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>

        <span style="margin-left: 10px">时间：</span>
        <el-date-picker
          :clearable="false"
          v-model="dateTime"
          size="small"
          type="daterange"
          align="center"
          style="width: 260px;"
          value-format="yyyy-MM-dd"
          format="yyyy-MM-dd"
          range-separator="～"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
        />

        <span style="margin-left: 10px">粒度：</span>
        <el-radio-group v-model="granularity" size="small">
          <el-radio-button label="auto">自动</el-radio-button>
          <el-radio-button label="hour">小时</el-radio-button>
          <el-radio-button label="day">天</el-radio-button>
        </el-radio-group>

        <el-button
          type="primary"
          plain
          size="small"
          icon="el-icon-search"
          style="margin-left: 8px"
          @click="handleQuery"
        >查询</el-button>
        <el-button
          type="default"
          size="small"
          icon="el-icon-refresh"
          style="margin-left: 6px"
          @click="stationValue='';handleQuery()"
        >重置工位</el-button>
      </div>

      <el-row :gutter="10" style="margin-bottom: 10px">
        <el-col :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
          <div class="kpi-card kpi-blue">
            <div class="kpi-title">报警总数</div>
            <div class="kpi-value">{{ kpi.total }}</div>
          </div>
        </el-col>
        <el-col :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
          <div class="kpi-card kpi-green">
            <div class="kpi-title">涉及工位数</div>
            <div class="kpi-value">{{ kpi.stations }}</div>
          </div>
        </el-col>
        <el-col :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
          <div class="kpi-card kpi-red">
            <div class="kpi-title">峰值(趋势)</div>
            <div class="kpi-value">{{ kpi.peakValue }}</div>
          </div>
        </el-col>
      </el-row>

      <el-row :gutter="10">
        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
          <div class="chart-card">
            <div class="chart-title">各工位报警分布（次数）</div>
            <div ref="stationBar" class="chart-box"></div>
          </div>
        </el-col>
        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
          <div class="chart-card">
            <div class="chart-title">各时间段报警趋势</div>
            <div ref="timeLine" class="chart-box"></div>
          </div>
        </el-col>
      </el-row>

      <el-row :gutter="10" style="margin-top: 10px">
        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
          <div class="chart-card">
            <div class="chart-title">工位 × 小时 热力图</div>
            <div ref="heatmap" class="chart-box"></div>
          </div>
        </el-col>
        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
          <div class="chart-card">
            <div class="chart-title">报警内容Top占比</div>
            <div ref="textPie" class="chart-box"></div>
          </div>
        </el-col>
      </el-row>
    </el-card>
  </div>
  </template>

<script>
export default {
  data() {
    return {
      loading: false,
      stationList: [],
      stationValue: '',
      dateTime: [],
      granularity: 'auto',
      rawAlarms: [],
      kpi: { total: 0, stations: 0, peakValue: 0 },
      chartStationBar: null,
      chartTimeLine: null,
      chartHeatmap: null,
      chartTextPie: null
    }
  },
  created() {
    const end = new Date()
    const start = new Date()
    start.setDate(start.getDate())
    const formatDate = (date) => {
      const y = date.getFullYear()
      const m = (date.getMonth() + 1).toString().padStart(2, '0')
      const d = date.getDate().toString().padStart(2, '0')
      return `${y}-${m}-${d}`
    }
    this.dateTime = [formatDate(end), formatDate(end)]
    this.getStationList()
  },
  mounted() {
    this.$nextTick(() => {
      this.initCharts()
      window.addEventListener('resize', this.handleResize)
    })
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.handleResize)
    this.disposeCharts()
  },
  methods: {
    // 获取工位列表
    getStationList() {
      this.stationList = []
      const Data = this.CreateData('11', 'MES_计划BOM_工位与名称_查询', [])
      this.ExecDatabase(Data).then(response => {
        let rows = []
        if (response && response.data) {
          if (Array.isArray(response.data)) {
            rows = response.data
          } else if (response.data.result && Array.isArray(response.data.result)) {
            rows = response.data.result
          }
        }
        for (const item of rows) {
          this.stationList.push({
            label: item.工位号 || item['工位号'],
            value: item.工位号 || item['工位号']
          })
        }
      }).finally(() => {
        // 初始查询
        this.handleQuery()
      })
    },

    // 触发查询
    handleQuery() {
      if (!this.dateTime || this.dateTime.length !== 2) {
        this.$message.warning('请选择日期范围')
        return
      }
      this.fetchAggregations()
    },

    // 并行拉取聚合数据，并渲染图表
    async fetchAggregations() {
      this.loading = true
      try {
        const start = this.dateTime[0] + ' 00:00:00'
        const end = this.dateTime[1] + ' 23:59:59'
        const daySpan = Math.ceil((new Date(end) - new Date(start)) / (24 * 3600 * 1000)) + 1
        const autoHour = daySpan <= 3
        const mode = this.granularity === 'auto' ? (autoHour ? 'hour' : 'day') : this.granularity

        // 工位分布 TopN=20（不受工位筛选影响）
        const pStationDist = (() => {
          const param = []
          param[0] = ['开始时间', start]
          param[1] = ['结束时间', end]
          param[2] = ['TopN', 20]
          const Data = this.CreateData('11', '报警统计_工位分布_按时间段', param)
          return this.ExecDatabase(Data).then(res => Array.isArray(res.data) ? res.data : [])
        })()

        // 时间趋势（小时/天）
        const pTrend = (() => {
          const param = []
          param[0] = ['开始时间', start]
          param[1] = ['结束时间', end]
          param[2] = ['工位号_ischeck', this.stationValue ? 1 : 0]
          param[3] = ['工位号', this.stationValue || '']
          const name = mode === 'hour' ? '报警统计_时间趋势_小时' : '报警统计_时间趋势_天'
          const Data = this.CreateData('11', name, param)
          return this.ExecDatabase(Data).then(res => Array.isArray(res.data) ? res.data : [])
        })()

        // 热力图 TopStation=15（受工位筛选影响）
        const pHeat = (() => {
          const param = []
          param[0] = ['开始时间', start]
          param[1] = ['结束时间', end]
          param[2] = ['工位号_ischeck', this.stationValue ? 1 : 0]
          param[3] = ['工位号', this.stationValue || '']
          param[4] = ['TopStation', 15]
          const Data = this.CreateData('11', '报警统计_热力_工位小时', param)
          return this.ExecDatabase(Data).then(res => Array.isArray(res.data) ? res.data : [])
        })()

        // 报警内容占比 TopN=10（受工位筛选影响）
        const pText = (() => {
          const param = []
          param[0] = ['开始时间', start]
          param[1] = ['结束时间', end]
          param[2] = ['工位号_ischeck', this.stationValue ? 1 : 0]
          param[3] = ['工位号', this.stationValue || '']
          param[4] = ['TopN', 10]
          const Data = this.CreateData('11', '报警统计_内容占比', param)
          return this.ExecDatabase(Data).then(res => Array.isArray(res.data) ? res.data : [])
        })()

        const [distRows, trendRows, heatRows, textRows] = await Promise.all([pStationDist, pTrend, pHeat, pText])
        this.computeKpi(distRows, trendRows)
        this.buildChartsFromAggregations(distRows, trendRows, textRows, heatRows)
      } catch (e) {
        console.error(e)
        this.$message.error('统计数据查询失败')
      } finally {
        this.loading = false
      }
    },

    // 初始化图表实例
    initCharts() {
      if (!this.chartStationBar) this.chartStationBar = this.$echarts.init(this.$refs.stationBar)
      if (!this.chartTimeLine) this.chartTimeLine = this.$echarts.init(this.$refs.timeLine)
      if (!this.chartHeatmap) this.chartHeatmap = this.$echarts.init(this.$refs.heatmap)
      if (!this.chartTextPie) this.chartTextPie = this.$echarts.init(this.$refs.textPie)
    },
    disposeCharts() {
      if (this.chartStationBar) { this.chartStationBar.dispose(); this.chartStationBar = null }
      if (this.chartTimeLine) { this.chartTimeLine.dispose(); this.chartTimeLine = null }
      if (this.chartHeatmap) { this.chartHeatmap.dispose(); this.chartHeatmap = null }
      if (this.chartTextPie) { this.chartTextPie.dispose(); this.chartTextPie = null }
    },
    handleResize() {
      this.chartStationBar && this.chartStationBar.resize()
      this.chartTimeLine && this.chartTimeLine.resize()
      this.chartHeatmap && this.chartHeatmap.resize()
      this.chartTextPie && this.chartTextPie.resize()
    },

    // 组装图表（使用聚合数据）
    buildChartsFromAggregations(distRows, trendRows, textRows, heatRows) {
      this.initCharts()
      // 工位分布
      const stationArr = (distRows || []).map(r => ({ name: r.工位号 || '未知工位', value: Number(r.报警次数) || 0 }))
      const topStations = stationArr.slice(0, 20)
      const needZoom = topStations.length > 12
      this.chartStationBar.setOption({
        grid: { left: 60, right: 20, top: 40, bottom: 50 },
        toolbox: { feature: { saveAsImage: {}, restore: {}, dataView: { readOnly: true } } },
        tooltip: { trigger: 'axis' },
        dataZoom: needZoom ? [{ type: 'inside' }, { type: 'slider', height: 12 }] : [],
        xAxis: {
          type: 'category',
          data: topStations.map(i => i.name),
          axisLabel: { interval: 0, rotate: 35 }
        },
        yAxis: { type: 'value', name: '次数' },
        color: ['#409EFF'],
        series: [{
          name: '报警次数',
          type: 'bar',
          barMaxWidth: 30,
          data: topStations.map(i => i.value),
          label: { show: true, position: 'top' },
          itemStyle: {
            color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
              { offset: 0, color: '#66b1ff' },
              { offset: 1, color: '#3a8ee6' }
            ])
          },
          markPoint: { data: [{ type: 'max', name: '最大' }, { type: 'min', name: '最小' }] },
          markLine: { data: [{ type: 'average', name: '平均' }] }
        }]
      })
      // 点击柱状筛选工位
      if (this.chartStationBar) {
        this.chartStationBar.off('click')
        this.chartStationBar.on('click', (params) => {
          if (!params || !params.name) return
          this.stationValue = params.name
          this.handleQuery()
        })
      }

      // 时间趋势（支持按小时/按天返回）
      const categories = []
      const timeBuckets = {}
      ;(trendRows || []).forEach(r => {
        const key = r.时间点 || r.日期 || ''
        if (!key) return
        timeBuckets[key] = Number(timeBuckets[key] || 0) + Number(r.报警次数 || 0)
      })
      Object.keys(timeBuckets).sort().forEach(k => categories.push(k))
      const timeData = categories.map(k => timeBuckets[k] || 0)
      const needZoomLine = categories.length > 20
      this.chartTimeLine.setOption({
        grid: { left: 50, right: 20, top: 40, bottom: 50 },
        toolbox: { feature: { saveAsImage: {}, restore: {}, dataZoom: {} } },
        tooltip: { trigger: 'axis' },
        dataZoom: needZoomLine ? [{ type: 'inside' }, { type: 'slider', height: 12 }] : [],
        xAxis: { type: 'category', data: categories },
        yAxis: { type: 'value', name: '次数' },
        color: ['#67C23A'],
        series: [{
          name: '报警次数',
          type: 'line',
          smooth: true,
          areaStyle: {
            color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
              { offset: 0, color: 'rgba(103,194,58,0.35)' },
              { offset: 1, color: 'rgba(103,194,58,0.05)' }
            ])
          },
          data: timeData,
          markPoint: { data: [{ type: 'max', name: '峰值' }] },
          markLine: { data: [{ type: 'average', name: '平均' }] }
        }]
      })
      // 已移除报警类型占比
      // 热力图（工位 × 小时）
      const heatStations = Array.from(new Set((heatRows || []).map(r => r.工位号))).slice(0, 15)
      const heatHours = Array.from({ length: 24 }).map((_, i) => (i < 10 ? '0' + i : '' + i) + ':00')
      const cellMap = {}
      ;(heatRows || []).forEach(r => {
        const st = r.工位号 || '未知工位'
        const hour = r.小时 || '00:00'
        if (heatStations.indexOf(st) === -1) return
        const key = st + '||' + hour
        cellMap[key] = Number(cellMap[key] || 0) + Number(r.报警次数 || 0)
      })
      const heatData = []
      heatStations.forEach((st, yi) => {
        heatHours.forEach((h, xi) => {
          heatData.push([xi, yi, cellMap[st + '||' + h] || 0])
        })
      })
      this.chartHeatmap.setOption({
        tooltip: { position: 'top' },
        grid: { left: 70, right: 20, bottom: 20, top: 30 },
        xAxis: { type: 'category', data: heatHours, splitArea: { show: true }, axisLabel: { interval: 0, rotate: 35 } },
        yAxis: { type: 'category', data: heatStations, splitArea: { show: true } },
        visualMap: { min: 0, max: Math.max(...heatData.map(d => d[2]), 10), calculable: true, orient: 'horizontal', left: 'center', bottom: 0 },
        series: [{
          name: '报警次数',
          type: 'heatmap',
          data: heatData,
          label: { show: false },
          emphasis: { itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0, 0, 0, 0.3)' } }
        }]
      })

      // 报警内容占比（Top 10 + 其他）
      const allText = (textRows || []).map(r => ({ name: r.报警内容 || '未知内容', value: Number(r.报警次数) || 0 }))
      // 按报警次数排序，取Top 10
      const sortedText = [...allText].sort((a, b) => b.value - a.value)
      const top10Text = sortedText.slice(0, 10)
      // 计算Top 10以外的总报警次数
      const remainingText = sortedText.slice(10)
      const otherCount = remainingText.reduce((sum, item) => sum + item.value, 0)
      // 构建最终数据，包含Top 10和"其他"
      const topText = [...top10Text]
      if (otherCount > 0) {
        topText.push({ name: '其他', value: otherCount })
      }
      this.chartTextPie.setOption({
        tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
        legend: {
          orient: 'vertical',
          right: 10,
          top: 'middle',
          formatter: name => {
            const item = (topText || []).find(i => i.name === name)
            return item ? `${name}  ${item.value}` : name
          },
          selectedMode: false
        },
        series: [{
          name: '内容占比',
          type: 'pie',
          radius: ['40%', '65%'],
          center: ['35%', '50%'],
          avoidLabelOverlap: true,
          itemStyle: { borderRadius: 4, borderColor: '#fff', borderWidth: 2 },
          label: { show: false },
          labelLine: { show: false },
          data: topText
        }]
      })
    }
    ,
    // KPI 计算
    computeKpi(distRows, trendRows) {
      const total = (trendRows || []).reduce((s, r) => s + (Number(r.报警次数) || 0), 0)
      const stations = (distRows || []).length
      let peakValue = 0
      ;(trendRows || []).forEach(r => {
        const v = Number(r.报警次数) || 0
        if (v > peakValue) peakValue = v
      })
      this.kpi = { total, stations, peakValue }
    }
  }
}
</script>

<style scoped>
.topCard{
  margin: 10px;
  padding: 10px;
}
.topDiv{
  margin-bottom: 10px;
  display: flex;
  align-items: center;
}
.chart-card{
  background: #fff;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  padding: 8px 8px 0 8px;
}
.chart-title{
  font-size: 14px;
  color: #303133;
  padding: 4px 8px 8px 8px;
}
.chart-box{
  width: 100%;
  height: 360px;
}
.kpi-card{
  height: 72px;
  background: #fff;
  border-radius: 4px;
  padding: 8px 12px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  border: 1px solid #ebeef5;
}
.kpi-title{
  font-size: 12px;
  color: #909399;
}
.kpi-value{
  font-size: 22px;
  font-weight: 600;
  color: #303133;
}
.kpi-blue{ box-shadow: inset 3px 0 0 #409EFF; }
.kpi-green{ box-shadow: inset 3px 0 0 #67C23A; }
.kpi-orange{ box-shadow: inset 3px 0 0 #E6A23C; }
.kpi-red{ box-shadow: inset 3px 0 0 #F56C6C; }
</style>

