<template>
  <div
    v-loading="loading"
    element-loading-text="拼命加载中"
    element-loading-spinner="el-icon-loading"
    element-loading-background="rgba(0, 0, 0, 0.8)"
    class="statstics-wrapper"
  >
    <div
      ref="headerWrapper"
      class="statstics-header"
    >
      <StatisticsHeader
        :title="`${chartsTitle}统计`"
        :data="formData"
        :items="formItems"
        :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,
      validator(arr) {
        return (
          arr &&
          arr.every(
            category =>
              (category instanceof Object && 'name' in category) ||
              typeof category === 'string'
          )
        )
      },
    },
    formData: {
      type: Object,
      required: true,
    },
    formItems: {
      type: Array,
      default: () => [],
    },
    customFormItems: {
      type: Array,
      default: () => [],
    },
    pieTitle: {
      type: String,
      default: '总件数',
    },
  },
  data() {
    return {
      loading: false,
      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: [],
    }
  },
  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(category => {
          if (category instanceof Object) {
            return {
              ...category,
              value: 0,
            }
          } else {
            return {
              name: category,
              key: category,
              value: 0,
            }
          }
        })
      },
      deep: true,
      immediate: true,
    },
    'sidebar.expand'() {
      this.setChartHeight()
    },
  },
  mounted() {
    this.setChartHeight()
    this.myChart = this.$echarts.init(document.getElementById('chart'))
    this.options.series[0].data = [
      {
        name: this.chartsTitle,
        key: this.chartsTitle,
        value: null,
      },
      ...this.categoryDatas,
    ]
    this.options.legend.data = [
      {
        name: this.chartsTitle,
        icon: 'none',
      },
      ...this.categoryDatas.map(({ name }, index) => ({ 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 === -1) {
        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()
      const params = JSON.parse(JSON.stringify(formData))
      ;[params.fd1, params.fd2] = params.dateTime
      delete params.dateTime
      this.params = Object.values(params)
      const paramsList = [params]
      this.getMultipleChartsData(this.querySettings.serviceId, paramsList)
    },
    async getMultipleChartsData(serviceId, paramsList) {
      this.loading = true
      try {
        const listValuesArray = await Promise.all(
          paramsList.map(params => this.getChartsData(serviceId, params))
        )
        this.tableData = this._.sortBy(listValuesArray.flat(), 'fdt')
        const categories = this.categoryDatas.map(category => category.key)
        const listValues = listValuesArray.reduce(
          (preValues, currentValues) => {
            currentValues.forEach(value => {
              const preValue = preValues.find(
                preValue => preValue.fdt === value.fdt
              )
              if (preValue) {
                categories.forEach(key => {
                  preValue[key] += value[key] ?? 0
                })
              } else {
                const valuesObj = {
                  location: value.location,
                  fdt: value.fdt,
                }
                categories.forEach(key => {
                  valuesObj[key] = value[key] ?? 0
                })
                preValues.push(valuesObj)
              }
            })
            return preValues
          },
          []
        )
        // console.log(listValues)
        this.setChartsData(this._.sortBy(listValues, 'fdt'))
      } catch (error) {
        this.$message.error(error.message)
      }
      this.loading = false
    },
    async getChartsData(serviceId, params) {
      try {
        const {
          code,
          returnData: listValues,
          message,
        } = await TempQuery({
          serviceId,
          dataContent: params,
        })
        if (String(code) === '0') {
          return listValues.map(obj => ({
            ...obj,
            location: params.air_line || params.airport || '',
          }))
        } else {
          throw new Error(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[category.key]) {
            category.value += element[category.key]
            totalCount += element[category.key]
          }
        })
      })
      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 =>
            this.categoryDatas.map(category => [
              element['fdt'],
              element['location'],
              category.name,
              element[category.key],
              `${(
                (element[category.key] / this.totalCount.value) *
                100
              ).toFixed(2)}%`,
            ])
          )
          .flat(1)
      )
      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>
