<template>
  <div class="statstics-wrapper">
    <div
      ref="headerWrapper"
      class="statstics-header"
    >
      <StatisticsHeader
        title="扫描节点与位置分析"
        :items="formItems"
        :data="formData"
        with-setting
        @getFormData="getFormData"
        @export="exportHandler"
        @setting="settingHandler"
      />
    </div>
    <div class="statstics-content">
      <div
        ref="myChart"
        class="node-statistics-chart"
        :style="{ height: chartHeight }"
      />
      <div
        v-if="checkedTooltips.length"
        class="node-tooltip"
      >
        <div class="node-tooltip-title">节点扫描率</div>
        <div
          v-for="tooltip in checkedTooltips"
          :key="tooltip.label"
          class="node-tooltip-content"
        >
          <span>{{ tooltip.label }}：</span><span>{{ tooltip.ratio }}</span>
        </div>
      </div>
    </div>
    <Dialog
      :flag="dialogFlag"
      class="dialog-check-group"
    >
      <div class="dialog-wrapper">
        <div class="title">列设置</div>
        <div class="content">
          <el-checkbox-group v-model="checkListTemp">
            <el-checkbox
              v-for="node in nodeList"
              :key="node.name"
              :label="node.name"
              :disabled="node.disabled"
            />
          </el-checkbox-group>
        </div>
        <div class="foot right t30">
          <el-button
            size="medium"
            class="r24"
            type="primary"
            @click="onCheck"
            >确定</el-button
          >
          <el-button
            size="medium"
            @click="hide"
            >取消</el-button
          >
        </div>
      </div>
    </Dialog>
  </div>
</template>

<script>
import StatisticsHeader from '../components/statisticsHeader.vue'
import Dialog from '@/layout/components/Dialog'
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: 'FlightStatisticsCharts',
  components: { StatisticsHeader, Dialog },
  data() {
    return {
      formData: {
        range: '',
        airline: '',
        airport: '',
        inOrOut: '',
        dateTime: '',
      },
      formItems: [
        {
          prop: 'range',
          inputType: 'select',
          placeholder: '统计范围',
          options: [],
          queryId: SERVICE_ID.nodeRange,
          setKey: 'a1',
          changeHandler(value) {
            this.setInOrOutOptions(value)
            const rangeMap = {
              航线: 'airline',
              基地分公司: 'area',
              航站: 'airport',
              航站楼: 'terminal',
            }
            Object.entries(rangeMap).forEach(([k, v]) => {
              const theItem = this.formItems.find(item => item.prop === v)
              if (value === k) {
                theItem && (theItem.disabled = false)
              } else {
                this.formData[v] = ''
                theItem && (theItem.disabled = true)
              }
            })
          },
        },
        {
          prop: 'airline',
          inputType: 'select',
          placeholder: '航线',
          filterable: true,
          clearable: true,
          disabled: true,
          queryId: SERVICE_ID.nodeAirline,
          setKey: 'a2',
          options: [],
        },
        {
          prop: 'airport',
          inputType: 'select',
          placeholder: '航站',
          filterable: true,
          clearable: true,
          // multiple: true,
          disabled: true,
          queryId: SERVICE_ID.nodeAirport,
          setKey: 'a2',
          options: [],
        },
        {
          prop: 'inOrOut',
          inputType: 'select',
          placeholder: '进离港',
          clearable: true,
          options: [],
        },
        {
          prop: 'dateTime',
          inputType: 'datePicker',
          clearable: true,
          width: '240px',
          options: [],
        },
      ],
      queryData: null,
      nodeList: [
        {
          name: '行李总件数',
          label: '',
          disabled: true,
        },
        {
          name: '值机件数',
          label: '值机',
        },
        {
          name: '安检件数',
          label: '安检',
        },
        {
          name: '分拣件数',
          label: '分拣',
        },
        {
          name: '装车件数',
          label: '装车',
        },
        {
          name: '装机件数',
          label: '装机',
          // disabled: true
        },
        {
          name: '卸机件数',
          label: '卸机',
          disabled: true,
        },
        {
          name: '中转件数',
          label: '中转',
        },
        {
          name: '到达件数',
          label: '到达',
        },
      ],
      checkList: [],
      checkListTemp: [],
      dialogFlag: false,
      myChart: null,
      debounceTime: 300,
      chartHeight: '70vh',
      hasChartData: false,
      echartsOptions: {
        tooltip: {
          trigger: 'item',
        },
        label: {
          show: true,
          formatter: function (params) {
            return params.value
          },
        },
        radar: {
          indicator: [],
          axisName: {
            padding: 10,
            color: '#303133',
            fontFamily: 'Helvetica, "Microsoft YaHei"',
          },
        },
        triggerEvent: true,
        series: [
          {
            name: 'nodeRadar',
            type: 'radar',
            areaStyle: {
              color: '#6897D8',
            },
            itemStyle: {
              color: '#ffffff',
              borderWidth: 2,
              borderColor: '#4475B8',
            },
            lineStyle: {
              color: '#4475B8',
              width: 2,
            },
            data: [],
          },
        ],
      },
      indicator: [],
      seriesData: [],
      tooltips: [],
      descriptions: {},
    }
  },
  computed: {
    ...mapGetters(['sidebar']),
    checkedTooltips() {
      return this.tooltips.filter(tooltip =>
        this.checkList.includes(tooltip.name)
      )
    },
    checkedSeriesData() {
      return this.seriesData.reduce((pre, curr) => {
        if (this.checkList.includes(curr.name)) {
          return [...pre, curr.value]
        } else {
          return pre
        }
      }, [])
    },
    checkedIndicator() {
      return this.indicator.filter(node => this.checkList.includes(node.name))
    },
  },
  watch: {
    checkedIndicator: {
      handler(arr) {
        this.echartsOptions.radar.indicator = arr
      },
      deep: true,
    },
    checkedSeriesData: {
      handler(arr) {
        this.echartsOptions.series[0].data = [
          {
            name: this.queryData[2],
            value: arr,
          },
        ]
      },
      deep: true,
    },
    // 监听数据变化 重绘图形
    echartsOptions: {
      handler(obj) {
        this.myChart && this.myChart.setOption(obj)
        this.resizeHandler()
      },
      deep: true,
    },
    'sidebar.expand'() {
      this.setChartHeight()
    },
  },
  created() {
    this.getTips()

    this.tooltips = this.nodeList.reduce((pre, curr) => {
      if (curr.label) {
        return [
          ...pre,
          {
            name: curr.name,
            label: curr.label,
            ratio: '0%',
          },
        ]
      } else {
        return pre
      }
    }, [])

    this.indicator = this.nodeList.map(node => ({
      name: node.name,
      max: 10000,
    }))

    this.checkList = this.nodeList.reduce((pre, curr) => {
      if (
        [
          // '装机件数',
          '卸机件数',
        ].includes(curr.name)
      ) {
        return pre
      } else {
        return [...pre, curr.name]
      }
    }, [])
  },
  mounted() {
    const that = this

    this.setChartHeight()
    this.myChart = this.$echarts.init(this.$refs['myChart'])
    this.myChart.setOption(this.echartsOptions)

    // 监听页面缩放
    this.debouncedChartHeightSetter = this._.debounce(
      this.setChartHeight,
      this.debounceTime
    )
    window.addEventListener('resize', this.debouncedChartHeightSetter)

    // 防止修改标签造成的闪烁
    this.myChart.on('mousedown', this.hideTips)
    // 修改雷达图标签说明
    this.myChart.on('mousemove', this.changeTips)
    this.myChart.on('mouseup', params => {
      setTimeout(that.changeTips.bind(that, params), 0)
    })
  },
  beforeDestroy() {
    // 销毁实例和移除监听
    window.removeEventListener('resize', this.debouncedChartHeightSetter)
    if (this.myChart) {
      this.myChart.dispose()
      this.myChart = null
    }
  },
  methods: {
    hideTips(params) {
      if (params.componentType === 'radar') {
        this.myChart._dom.children[1].style.opacity = 0
      }
    },
    changeTips(params) {
      const tip = this.myChart._dom.children[1]
      if (params.componentType === 'radar' && this.descriptions[params.name]) {
        tip.innerHTML = tip.textContent = this.descriptions[params.name]
      }
    },
    getFormData(data) {
      this.queryChartsData(data)
    },
    setInOrOutOptions(range) {
      const theInOrOutItem = this.formItems.find(
        item => item.prop === 'inOrOut'
      )
      switch (range) {
        case '全部':
        case '航线':
          theInOrOutItem.options = [
            {
              label: '全部',
              value: '全部',
            },
          ]
          this.formData.inOrOut = '全部'
          this.formItems[3].disabled = true
          break
        case '航站':
          theInOrOutItem.options = [
            {
              value: '进港',
              label: '进港',
            },
            {
              value: '离港',
              label: '离港',
            },
          ]
          this.formItems[3].disabled = false
          break
        default:
          theInOrOutItem.options = []
          this.formItems[3].disabled = false
          break
      }
    },
    async getTips() {
      try {
        const {
          code,
          returnData: { listValues },
          message,
        } = await TempQuery({
          id: SERVICE_ID.nodeAxisDesc,
          dataContent: [],
        })
        if (Number(code) === 0 && listValues?.length) {
          this.descriptions = JSON.parse(listValues[0].jieshi)
        } else {
          this.$message.error(message ?? '失败')
        }
      } catch (error) {
        this.$message.error('失败')
      }
    },
    async queryChartsData(data) {
      const params = []
      let queryId
      if (data.range === '') {
        this.$message.warning('请先选择统计范围')
        return
      }
      if (data.range === '航线' && data.airline === '') {
        this.$message.warning('请先选择航线')
        return
      }
      if (data.range === '航站' && data.airport === '') {
        this.$message.warning('请先选择航站')
        return
      }
      switch (data.inOrOut) {
        case '全部':
          queryId = SERVICE_ID.nodeAll
          break
        case '进港':
          queryId = SERVICE_ID.nodeIn
          break
        case '离港':
          queryId = SERVICE_ID.nodeOut
          break
        default:
          this.$message.warning('请先选择进离港')
          return
      }
      if (data.dateTime === '') {
        this.$message.warning('请先选择统计时间范围')
        return
      }
      params.push(data.range, data.inOrOut, data.dateTime[0], data.dateTime[1])
      if (data.range === '航线') {
        params.splice(1, 0, data.airline)
      } else if (data.range === '航站') {
        params.splice(1, 0, data.airport)
      } else {
        params.splice(1, 0, '全部')
      }

      this.queryData = params

      try {
        this.echartsOptions.series[0].data = []
        this.tooltips.forEach(tooltip => (tooltip.ratio = '0%'))
        this.hasChartData = false

        const res = await TempQuery({
          id: queryId,
          dataContent: params,
        })
        if (Number(res.code) === 0) {
          if (res.returnData.listValues.length) {
            const list = Object.entries(res.returnData.listValues[0])
            const max = Math.max(...list.map(element => element[1]))
            this.indicator.forEach(node => {
              node.max = max
            })
            list.forEach(([name, value]) => {
              const tooltip = this.tooltips.find(
                tooltip => tooltip.name === name
              )
              if (tooltip && value) {
                tooltip.ratio = ((value / max) * 100).toFixed(2) + '%'
              }
            })
            this.seriesData = this.indicator.map(node => {
              const result = {
                name: node.name,
                value: 0,
              }
              const data = list.find(([key, value]) => key === node.name)
              if (data) {
                result.value = data[1]
              }
              return result
            })
            this.hasChartData = true
          }
        } else {
          this.$message.error(res.message || '失败')
        }
      } catch (error) {
        this.$message.error('失败')
      }
    },
    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
      }
      this.queryExportData(this.queryData)
      // 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', '扫描节点与位置分析统计.png')
      // $a.click()
    },
    async queryExportData(queryData) {
      let queryId
      switch (queryData[0]) {
        case '航站':
          queryId = SERVICE_ID.nodeExportAirport
          break
        case '航线':
          queryId = SERVICE_ID.nodeExportAirline
          break
        default:
          this.$message.warning('请先选择统计范围')
          return
      }
      try {
        const res = await TempQuery({
          id: queryId,
          dataContent: queryData,
        })
        if (Number(res.code) === 0) {
          const { listValues } = res.returnData
          if (listValues.length) {
            // 生成表格数据
            const xlsxDatas = [[]]
            const listArray = listValues.map(record =>
              Object.entries(record).filter(
                ([key, value]) => key === 'a4' || this.checkList.includes(key)
              )
            )
            xlsxDatas[0].push(...listArray[0].map(([key, value]) => key))
            xlsxDatas.push(
              ...listArray.map(record =>
                record.map(([key, value]) => value || 0)
              )
            )
            xlsxDatas[0][0] = '日期'
            // 添加合计行
            if (xlsxDatas.length > 2) {
              const summaryRow = ['合计']
              const colNum = xlsxDatas[0].length
              for (let columnIndex = 1; columnIndex < colNum; columnIndex++) {
                summaryRow[columnIndex] = xlsxDatas.reduce(
                  (pre, currentRow, currentRowIndex) => {
                    if (currentRowIndex === 0) {
                      return pre
                    } else {
                      return pre + currentRow[columnIndex]
                    }
                  },
                  0
                )
              }
              xlsxDatas.push(summaryRow)
            }
            // 添加节点扫描率列，计算列宽
            const columnWidths = []
            xlsxDatas.forEach((row, rowIndex) => {
              // 从行李总件数后一列开始遍历，添加节点扫描率数据
              for (
                let columnIndex = 2;
                columnIndex < row.length;
                columnIndex += 2
              ) {
                const totalcell = row[1]
                const cell = row[columnIndex]
                const newCell =
                  rowIndex === 0
                    ? `${cell.slice(0, 2)}扫描率`
                    : `${cell ? ((cell / totalcell) * 100).toFixed(2) : 0}%`
                row.splice(columnIndex + 1, 0, newCell)
              }
              // 计算每一列宽度，考虑换行
              row.forEach((cell, columnIndex) => {
                const cellWidth = Math.max(
                  ...String(cell)
                    .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, '扫描节点与位置分析')
            const tableWrite = XLSX_STYLE.write(workBook, {
              bookType: 'xlsx',
              bookSST: true,
              type: 'buffer',
              cellStyles: true,
            })
            // 下载表格
            const fileName = `扫描节点与位置分析-${queryData.join('-')}.xlsx`
            FileSaver.saveAs(
              new Blob([tableWrite], { type: 'application/octet-stream' }),
              fileName
            )
          }
        } else {
          this.$message.error(res.message || '失败')
        }
      } catch (error) {
        this.$message.error('失败')
      }
    },
    settingHandler() {
      this.dialogFlag = true
      this.checkListTemp = [...this.checkList]
    },
    onCheck() {
      if (this.dialogFlag === false) {
        return
      }
      if (this.checkListTemp.length < 3) {
        this.$message.warning('至少需要勾选2项（不包含行李总件数）')
        return
      }
      this.checkList = [...this.checkListTemp]
      this.dialogFlag = false
    },
    hide() {
      this.dialogFlag = false
    },
  },
}
</script>

<style lang="scss" scoped>
.statstics-wrapper {
  .statstics-content {
    background-color: #fff;
    position: relative;
    .node-tooltip {
      // width: 100px;
      position: absolute;
      bottom: 48px;
      left: 64px;
      z-index: 100;
      font-size: 14px;
      font-family: Helvetica, 'Microsoft YaHei';
      color: #303133;
      .node-tooltip-title {
        line-height: 14px;
        margin-bottom: 30px;
        font-weight: bold;
      }
      .node-tooltip-content {
        line-height: 14px;
        display: flex;
        justify-content: space-between;
        &:not(:last-child) {
          margin-bottom: 21px;
        }
      }
    }
    .node-statistics-chart {
      width: 100%;
    }
  }
  .dialog-check-group {
    .el-checkbox-group {
      display: flex;
      flex-wrap: wrap;
      .el-checkbox {
        margin-right: 0;
        width: 33.3%;
      }
    }
  }
}
</style>
