<template>
  <div class="statstics-wrapper">
    <div
      ref="headerWrapper"
      class="statstics-header"
    >
      <StatisticsHeader
        :title="`${chartsTitle}统计`"
        :custom-items="customFormItems"
        @getFormData="getFormData"
        @export="exportHandler"
      />
    </div>
    <div class="statstics-content">
      <div
        id="chart"
        class="statistics-chart"
        :style="{ height: chartHeight }"
      />
    </div>
  </div>
</template>

<script>
import StatisticsHeader from './statisticsHeader.vue'
import { TempQuery } from '@/api/temp'
import { mapGetters } from 'vuex'
import * as XLSX from 'xlsx'
import XLSX_STYLE from 'xlsx-style'
import FileSaver from 'file-saver'

export default {
  name: 'CommonBarStatisticsCharts',
  components: { StatisticsHeader },
  props: {
    chartsTitle: {
      type: String,
      required: true
    },
    querySettings: {
      type: Object,
      required: true
    },
    categories: {
      type: Array,
      required: true
    },
    customFormItems: {
      type: Array,
      default: () => []
    },
    pieTitle: {
      type: String,
      default: '总件数'
    },
    onlyAirline: {
      type: Boolean
    }
  },
  data() {
    return {
      myChart: null,
      debounceTime: 300,
      chartHeight: '70vh',
      hasChartData: false,
      tableData: [],
      params: [],
      options: {
        backgroundColor: '#ffffff',
        tooltip: {
          trigger: 'item'
        },
        title: {
          text: '',
          // 副标题
          subtext: '0',
          // 主副标题间距
          itemGap: 24,
          x: 'left',
          y: 'center',
          left: '30%',
          top: '40%',
          textAlign: 'center',
          // 主标题样式
          textStyle: {
            fontSize: '48',
            color: '#ffffff',
            fontWeight: 'bold',
            fontFamily: 'Microsoft YaHei'
          },
          // 副标题样式
          subtextStyle: {
            fontSize: '80',
            color: '#ffffff',
            fontWeight: 'bold'
          }
        },
        legend: {
          show: true,
          left: '60%',
          x: 'right',
          y: 'center',
          icon: 'rect',
          itemWidth: 20,
          itemHeight: 20,
          formatter: name => this.legendFormatter(name),
          textStyle: {
            backgroundColor: 'transparent',
            lineHeight: 0,
            rich: {
              chartsTitle: {
                width: 200,
                lineHeight: 100,
                fontSize: 32,
                fontFamily: 'Microsoft YaHei',
                fontWeight: 'bold',
                color: '#101116',
                padding: [0, 1000, 0, -20]
              },
              name: {
                fontSize: 20,
                fontFamily: 'Microsoft YaHei',
                fontWeight: 'bold',
                color: '#101116',
                lineHeight: 100
              },
              label: {
                fontSize: 16,
                fontFamily: 'Microsoft YaHei',
                color: '#101116'
              },
              value: {
                width: 96,
                fontSize: 16,
                fontFamily: 'Helvetica',
                fontWeight: 'bold',
                color: '#101116'
              },
              ratio: {
                width: 80,
                fontSize: 16,
                fontFamily: 'Helvetica',
                fontWeight: 'bold',
                color: '#101116'
              },
              wrap: {
                padding: [0, 40, 0, 0]
              }
            }
          },
          selected: {
            [this.chartsTitle]: false
          }
        },
        series: [
          {
            name: '',
            type: 'pie',
            left: '30%',
            width: 560,
            height: 560,
            center: [0, '60%'],
            radius: ['60%', '90%'],
            avoidLabelOverlap: false,
            label: {
              show: false,
              position: 'center'
            },
            emphasis: {
              label: {
                show: false,
                fontSize: '40',
                fontWeight: 'bold'
              }
            },
            labelLine: {
              show: false
            },
            data: []
          },
          {
            name: '总数',
            type: 'pie',
            left: '30%',
            width: 560,
            height: 560,
            center: [0, '60%'],
            radius: ['0%', '50%'],
            avoidLabelOverlap: false,
            itemStyle: {
              normal: {
                color: '#101116'
              }
            },
            label: {
              show: false,
              position: 'center'
            },
            // 自定义中心内容的话需要把这个关闭
            emphasis: {
              label: {
                show: false
              }
            },
            labelLine: {
              show: false
            },
            data: []
          }
        ]
      },
      totalCount: [{ value: 0 }],
      categoryDatas: [],
      categoryKey: 'specialnum',
      seriesKey: 'special'
    }
  },
  computed: {
    ...mapGetters(['sidebar'])
  },
  watch: {
    pieTitle: {
      handler(val) {
        this.options.title.text = val
      },
      immediate: true
    },
    // 监听数据变化 重绘图形
    options: {
      handler(obj) {
        this.myChart.setOption(obj)
        this.resizeHandler()
      },
      deep: true
    },
    categories: {
      handler(arr) {
        this.categoryDatas = arr.map(categoryName => ({
          name: categoryName,
          value: 0
        }))
        this.categoryDatas.unshift({
          name: this.chartsTitle,
          value: null
        })
      },
      deep: true,
      immediate: true
    },
    querySettings: {
      handler({ categoryKey, seriesKey }) {
        if (seriesKey) {
          this.seriesKey = seriesKey
        }
        if (categoryKey) {
          this.categoryKey = categoryKey
        }
      },
      deep: true,
      immediate: true
    },
    'sidebar.expand'() {
      this.setChartHeight()
    }
  },
  mounted() {
    this.setChartHeight()
    this.myChart = this.$echarts.init(document.getElementById('chart'))
    this.options.series[0].data = this.categoryDatas
    this.options.legend.data = this.categoryDatas.map(({ name }, index) => {
      if (index === 0) {
        return {
          name,
          icon: 'none'
        }
      } else {
        return {
          name
        }
      }
    })
    this.options.series[1].data = this.totalCount
    this.myChart.setOption(this.options)
    this.myChart.on('legendselectchanged', ({ name }) => {
      if (name === this.chartsTitle) {
        this.myChart.dispatchAction({
          type: 'legendUnSelect',
          name
        })
      }
    })
    // 监听页面缩放
    this.debouncedChartHeightSetter = this._.debounce(this.setChartHeight, this.debounceTime)
    window.addEventListener('resize', this.debouncedChartHeightSetter)
  },
  beforeDestroy() {
    // 销毁实例和移除监听
    window.removeEventListener('resize', this.debouncedChartHeightSetter)
    if (this.myChart) {
      this.myChart.dispose()
      this.myChart = null
    }
  },
  methods: {
    legendFormatter(name) {
      const index = this.categoryDatas.findIndex(category => category.name === name)
      if (index === 0) {
        return `{chartsTitle|${name}}`
      } else {
        const value = this.categoryDatas[index].value
        const ratio = value && this.totalCount.value ? ((value / this.totalCount.value) * 100).toFixed(2) + '%' : '0%'
        const richString = `{name|${name}}\n{label|数量：}{value|${value}}{label|占比：}{ratio|${ratio}}`
        return index % 2 ? richString + '{wrap| }' : richString
      }
    },
    resetDatas() {
      this.hasChartData = false
      this.categoryDatas.forEach(category => {
        category && (category.value = 0)
      })
      this.options.title.subtext = '0'
      this.options.series[1].data[0].value = 0
    },
    getFormData(formData) {
      this.resetDatas()

      let id
      let params = []

      if (this.onlyAirline) {
        if (formData.range === '航线') {
          id = this.querySettings.byAirline
          params = [formData.airline, formData.dateTime[0], formData.dateTime[1]]
        } else {
          id = this.querySettings.all
          params = [formData.dateTime[0], formData.dateTime[1]]
        }
      } else {
        if (formData.range === '基地分公司') {
          id = this.querySettings.byArea
          params = [formData.interval, formData.area, formData.inOrOut, formData.dateTime[0], formData.dateTime[1]]
        } else {
          id = this.querySettings.byOther
          params = [formData.interval, formData.range, formData.inOrOut, formData.dateTime[0], formData.dateTime[1]]
          if (formData.airline.length) {
            params.splice(2, 0, formData.airline)
          } else if (formData.airport.length) {
            params.splice(2, 0, formData.airport)
          } else if (formData.terminal !== '') {
            params.splice(2, 0, formData.terminal)
          } else {
            params.splice(2, 0, '全部')
          }
        }
      }
      this.params = params
      if (params[0] instanceof Array) {
        const paramsList = params[0].map(param => [param, ...params.slice(1)])
        this.getMultipleChartsData(id, paramsList)
      } else if (params[2] instanceof Array) {
        const paramsList = params[2].map(param => [...params.slice(0, 2), param, ...params.slice(3)])
        this.getMultipleChartsData(id, paramsList)
      } else {
        this.getSingleChartsData(id, params)
      }
    },
    async getMultipleChartsData(id, paramsList) {
      try {
        const listValuesArray = await Promise.all(paramsList.map(params => this.getChartsData(id, params)))
        this.tableData = listValuesArray.flat()
        const listValues = listValuesArray.reduce((preValues, currentValues) => {
          currentValues.forEach(value => {
            const preValue = preValues.find(
              preValue => preValue.A === value.A && preValue[this.categoryKey] === value[this.categoryKey]
            )
            if (preValue) {
              preValue[this.seriesKey] += value[this.seriesKey]
            } else {
              preValues.push({
                A: value.A,
                [this.categoryKey]: value[this.categoryKey],
                [this.seriesKey]: value[this.seriesKey]
              })
            }
          })
          return preValues
        }, [])
        // console.log(listValues)

        this.setChartsData(this._.sortBy(listValues, 'A'))
      } catch (error) {
        this.$message.error(error.message)
      }
    },
    async getSingleChartsData(id, params) {
      try {
        const listValues = await this.getChartsData(id, params)
        this.tableData = listValues
        this.setChartsData(listValues)
      } catch (error) {
        this.$message.error(error.message)
      }
    },
    async getChartsData(id, params) {
      try {
        const {
          code,
          returnData: { listValues },
          message
        } = await TempQuery({
          id,
          dataContent: params
        })
        if (Number(code) === 0) {
          return listValues
        } else {
          return Promise.reject(message || '失败')
        }
      } catch (error) {
        return Promise.reject(error.message || '失败')
      }
    },
    setChartsData(listValues) {
      if (listValues.length === 0) {
        this.$message.info('未查询到对应数据')
        return
      }
      let totalCount = 0
      listValues.forEach(element => {
        this.categoryDatas.forEach(category => {
          if (element[this.categoryKey]?.includes(category.name)) {
            category.value += element[this.seriesKey]
          }
        })
        totalCount += element[this.seriesKey]
      })
      this.options.title.subtext = totalCount.toString()
      this.totalCount.value = totalCount
      this.hasChartData = true
    },
    setChartHeight() {
      const topBarHeight = 80
      const headerBlankHeight = 24
      const tabsWrapperHeight = 62
      const headerHeight = this.$refs['headerWrapper'].offsetHeight
      const footerBlankHeight = 24
      this.chartHeight = `calc(100vh - ${
        topBarHeight + headerBlankHeight + tabsWrapperHeight + headerHeight + footerBlankHeight
      }px)`
      this.$nextTick(() => {
        this.resizeHandler()
      })
    },
    resizeHandler() {
      if (this.myChart) {
        this.myChart.resize()
      }
    },
    exportHandler() {
      if (!this.hasChartData) {
        this.$message.warning('请查询后再进行导出')
        return
      }
      // const myCanvas = this.myChart._dom.querySelectorAll('canvas')[0]
      // const image = myCanvas.toDataURL('image/png')
      // const $a = document.createElement('a')
      // $a.setAttribute('href', image)
      // $a.setAttribute('download', `${this.chartsTitle}统计.png`)
      // $a.click()

      const xlsxDatas = [['时间', '位置', '分类', '数量', '占比']]
      xlsxDatas.push(
        ...this.tableData.map(element => [
          element['A'],
          element['location'],
          element[this.categoryKey],
          element[this.seriesKey],
          ((element[this.seriesKey] / this.totalCount.value) * 100).toFixed(2) + '%'
        ])
      )
      xlsxDatas.push(['合计', '', '', this.totalCount.value, ''])
      // 计算列宽
      const columnWidths = []
      xlsxDatas.forEach((row, rowIndex) => {
        // 计算每一列宽度，考虑换行
        row.forEach((cell, columnIndex) => {
          const cellWidth = Math.max(
            ...cell
              .toString()
              .split('\n')
              .map(cellRow =>
                cellRow.split('').reduce((pre, curr) => {
                  const letterSize = curr.charCodeAt(0) > 255 ? 2 : 1
                  return pre + letterSize
                }, 0)
              )
          )
          if ((!columnWidths[columnIndex] && cellWidth > 0) || cellWidth > columnWidths[columnIndex]) {
            columnWidths[columnIndex] = cellWidth
          }
        })
      })
      // 生成表格
      const sheet = XLSX.utils.aoa_to_sheet(xlsxDatas)
      // 添加列宽度
      sheet['!cols'] = columnWidths.map(width => ({
        wch: width + 2
      }))
      // 样式
      const borderStyle = {
        style: 'medium',
        color: {
          rgb: 'FFFFFF'
        }
      }
      const reg = /^[A-Z]+([\d]+$)/
      for (const key in sheet) {
        const match = reg.test(key)
        if (match) {
          const rowIndex = reg.exec(key)[1]
          let cellStyle = {
            alignment: {
              horizontal: 'center',
              vertical: 'center',
              wrapText: true
            }
          }
          if (Number(rowIndex) === 1) {
            cellStyle = {
              ...cellStyle,
              border: {
                top: borderStyle,
                right: borderStyle,
                bottom: borderStyle,
                left: borderStyle
              },
              font: {
                color: {
                  rgb: 'FFFFFF'
                }
              },
              fill: {
                fgColor: {
                  rgb: '3366FF'
                }
              }
            }
          } else {
            cellStyle.alignment.horizontal = 'left'
          }
          sheet[key].s = cellStyle
        }
      }
      // 表格数据转换
      const workBook = XLSX.utils.book_new()
      XLSX.utils.book_append_sheet(workBook, sheet, this.chartsTitle)
      const tableWrite = XLSX_STYLE.write(workBook, {
        bookType: 'xlsx',
        bookSST: true,
        type: 'buffer',
        cellStyles: true
      })
      // 下载表格
      const fileName = `${this.chartsTitle}统计-${this.params.join('-')}.xlsx`
      FileSaver.saveAs(new Blob([tableWrite], { type: 'application/octet-stream' }), fileName)
    }
  }
}
</script>

<style
  lang="scss"
  scoped
>
.statistics-chart {
  width: 100%;
}
</style>
