function ExcelHelper () {
  var WS = {}
  var titleHeader = []
  // 初始化数据格式
  var iniData = (option) => {
    const data = []
    if (option && option.otherData && option.otherData.ExcelHead && option.data) {
      for (var rowIndex = 0; rowIndex < option.data.length; rowIndex++) {
        const dataItem = {}
        // option.data[rowIndex]
        for (var colIndex = 0; colIndex < option.otherData.ExcelHead.length; colIndex++) {
          dataItem[option.otherData.ExcelHead[colIndex].text] = option.data[rowIndex][option.otherData.ExcelHead[colIndex].value]
          // dataItem.push(option.data[rowIndex][option.otherData.ExcelHead[colIndex].value])
        }
        data.push(dataItem)
      }
    }
    return data
  }

  /**
   * 构建excel表头
   * @param revealList 列表页面展示的表头
   * @returns {[]} excel表格展示的表头
   */
  var buildHeader = (revealList) => {
    let excelHeader = [];
    // 构建生成excel表头需要的数据结构
    getHeader(revealList, excelHeader, 0, 0);
    // 多行表头长短不一，短的向长的看齐，不够的补上行合并占位符
    let max = Math.max(...(excelHeader.map(a => a.length)))
    excelHeader.filter(e => e.length < max).forEach(
      e => pushRowSpanPlaceHolder(e, max - e.length))
    return excelHeader;
  }

  /**
   * 生成头部 
   * @param headers 展示的头部
   * @param excelHeader excel头部
   * @param deep 深度
   * @param perOffset 前置偏移量
   * @returns {number}  后置偏移量
   */
  var getHeader = (headers, excelHeader, deep, perOffset) => {
    let offset = 0
    let cur = excelHeader[deep]
    if (!cur) {
      cur = excelHeader[deep] = []
    }
    // 填充行合并占位符
    pushRowSpanPlaceHolder(cur, perOffset - cur.length)
    for (let i = 0; i < headers.length; i++) {
      let head = headers[i]
      cur.push(head.text)
      if (head.hasOwnProperty('childHead') && Array.isArray(head.childHead)
        && head.childHead.length > 0) {
        let childOffset = getHeader(head.childHead, excelHeader, deep + 1,
          cur.length - 1)
        // 填充列合并占位符
        pushColSpanPlaceHolder(cur, childOffset - 1)
        offset += childOffset
      } else {
        offset++
      }
    }
    return offset;

  }

  /**
   * 填充行合并占位符
   * */
  var pushRowSpanPlaceHolder = (arr, count) => {
    for (let i = 0; i < count; i++) {
      arr.push('!$ROW_SPAN_PLACEHOLDER')
    }
  }

  // 填充列合并占位符
  var pushColSpanPlaceHolder = (arr, count) => {
    for (let i = 0; i < count; i++) {
      arr.push('!$COL_SPAN_PLACEHOLDER')
    }
  }

  /**
   * 合并头部单元格
   **/
  var doMerges = (arr) => {
    // 要么横向合并 要么纵向合并
    let deep = arr.length;
    let merges = [];
    for (let y = 0; y < deep; y++) {
      // 先处理横向合并
      let row = arr[y];
      let colSpan = 0
      for (let x = 0; x < row.length; x++) {
        if (row[x] === '!$COL_SPAN_PLACEHOLDER') {
          row[x] = undefined;
          if (x + 1 === row.length) {
            merges.push({ s: { r: y, c: x - colSpan - 1 }, e: { r: y, c: x } })
          }
          colSpan++
        } else if (colSpan > 0 && x > colSpan) {
          merges.push({ s: { r: y, c: x - colSpan - 1 }, e: { r: y, c: x - 1 } })
          colSpan = 0
        } else {
          colSpan = 0
        }
      }
    }
    // 再处理纵向合并
    let colLength = arr[0].length
    for (let x = 0; x < colLength; x++) {
      let rowSpan = 0
      for (let y = 0; y < deep; y++) {
        if (arr[y][x] === '!$ROW_SPAN_PLACEHOLDER') {
          arr[y][x] = undefined;
          if (y + 1 === deep) {
            merges.push({ s: { r: y - rowSpan, c: x }, e: { r: y, c: x } })
          }
          rowSpan++;
        } else if (rowSpan > 0 && y > rowSpan) {
          merges.push({ s: { r: y - rowSpan - 1, c: x }, e: { r: y - 1, c: x } })
          rowSpan = 0;
        } else {
          rowSpan = 0;
        }
      }
    }
    return merges;
  }

  /**
   * 组织数据装载到sheet中
   */
  var aoa_to_sheet = (data, headerRows) => {
    // const ws = {};
    const range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } };
    for (let R = 0; R !== data.length; ++R) {
      for (let C = 0; C !== data[R].length; ++C) {
        if (range.s.r > R) {
          range.s.r = R;
        }
        if (range.s.c > C) {
          range.s.c = C;
        }
        if (range.e.r < R) {
          range.e.r = R;
        }
        if (range.e.c < C) {
          range.e.c = C;
        }
        /// 这里生成cell的时候，使用上面定义的默认样式

        const cell = {
          v: data[R][C] || '',
          s: {
            font: { name: "宋体", sz: 11, color: { auto: 1 } },
            alignment: {
              /// 自动换行
              wrapText: 1,
              // 居中
              horizontal: "left",
              vertical: "center",
              indent: 0
            }
          }
        }
        if (typeof cell.v === 'number') {
          cell.t = 'n';
          cell.s.alignment.horizontal = 'right'
        } else if (typeof cell.v === 'boolean') {
          cell.t = 'b';
        } else {
          cell.t = 's';
          cell.s.alignment.horizontal = 'left'
        }


        if(titleHeader.length > 0){
          if (R === 0 ) {
            // 生成主标题
            cell.s.font.sz = 24
            cell.s.font.bold = true
            cell.s.alignment.horizontal = 'center'
          } else if (R <= titleHeader.length - 1) {
            // 生成副标题
            cell.s.font.sz = 11
            cell.s.font.bold = true
            cell.s.alignment.horizontal = 'center'
          }
        }else if(R < headerRows){
          cell.s.alignment.horizontal = 'center'
          cell.s.font.color = { rgb: '606266' }
          cell.s.font.bold = true
          cell.s.border = {
            top: { style: 'thin', color: { rgb: "000000" } },
            left: { style: 'thin', color: { rgb: "000000" } },
            bottom: { style: 'thin', color: { rgb: "000000" } },
            right: { style: 'thin', color: { rgb: "000000" } },
          };
          cell.s.fill = {
            patternType: 'solid',
            fgColor: { tint: 0.3999755851924192, rgb: 'ebeef5' },
            bgColor: { tint: 0.3999755851924192, rgb: 'D9D9D9' }
          }
        }
        

        // 头部列表加边框
        if (R < titleHeader.length + headerRows - 1 && R >= titleHeader.length) {
          cell.s.alignment.horizontal = 'center'
          cell.s.font.color = { rgb: '606266' }
          cell.s.font.bold = true
          cell.s.border = {
            top: { style: 'thin', color: { rgb: "000000" } },
            left: { style: 'thin', color: { rgb: "000000" } },
            bottom: { style: 'thin', color: { rgb: "000000" } },
            right: { style: 'thin', color: { rgb: "000000" } },
          };
          cell.s.fill = {
            patternType: 'solid',
            fgColor: { tint: 0.3999755851924192, rgb: 'ebeef5' },
            bgColor: { tint: 0.3999755851924192, rgb: 'D9D9D9' }
          }
        } 
        const cell_ref = XLSX.utils.encode_cell({ c: C, r: R });

        WS[cell_ref] = cell
      }
    }
    if (range.s.c < 10000000) {
      WS['!ref'] = XLSX.utils.encode_range(range)
    }
    return WS
  }

  var s2ab = (s) => {
    let buf = new ArrayBuffer(s.length);
    let view = new Uint8Array(buf);
    for (let i = 0; i !== s.length; ++i) {
      view[i] = s.charCodeAt(i) & 0xFF;
    }
    return buf;
  }

  var openDownloadXLSXDialog = (url, saveName) => {
    if (typeof url == 'object' && url instanceof Blob) {
      url = URL.createObjectURL(url); // 创建blob地址
    }
    var aLink = document.createElement('a');
    aLink.href = url;
    aLink.download = saveName || ''; // HTML5新增的属性，指定保存文件名，可以不要后缀，注意，file:///模式下不会生效
    var event;
    if (window.MouseEvent) {
      event = new MouseEvent('click');
    } else {
      event = document.createEvent('MouseEvents');
      event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false,
        false, false, false, 0, null);
    }
    aLink.dispatchEvent(event);
    this.success()
  }

  var extractData = (selectionData, revealList) => {
    // 列
    let headerList = flat(revealList);
    // 导出的结果集
    let excelRows = [];
    if (!selectionData || selectionData.length < 1) {
      return excelRows
    }
    // 如果有child集合的话会用到
    let dataKeys = new Set(Object.keys(selectionData[0]));
    selectionData.some(e => {
      if (e.childHead && e.childHead.length > 0) {
        let childKeys = Object.keys(e.childHead[0]);
        for (let i = 0; i < childKeys.length; i++) {
          dataKeys.delete(childKeys[i]);
        }
        return true;
      }
    })
    flatData(selectionData, (list) => {
      excelRows.push(...buildExcelRow(dataKeys, headerList, list));
    })
    return excelRows;
  }
  var flatData = (list, eachDataCallBack) => {
    let resultList = [];
    for (let i = 0; i < list.length; i++) {
      let data = list[i];
      let rawDataList = [];
      // 每个子元素都父元素合并成一条数据
      if (data.childHead && data.childHead.length > 0) {
        for (let j = 0; j < data.childHead.length; j++) {
          delete data.childHead[j].bsm
          let copy = Object.assign({}, data, data.childHead[j]);
          rawDataList.push(copy);
          copy['rowSpan'] = (j > 0 ? 0 : data.childHead.length);
        }
      } else {
        data['rowSpan'] = 1;
        rawDataList.push(data);
      }
      resultList.push(...rawDataList);
      if (typeof eachDataCallBack === 'function') {
        eachDataCallBack(rawDataList)
      }
    }
    return resultList;
  }

  var buildExcelRow = (mainKeys, headers, rawDataList) => {
    // 合计行
    let sumCols = [];
    // 数据行
    let rows = [];
    for (let i = 0; i < rawDataList.length; i++) {
      let cols = []
      let rawData = rawDataList[i];
      // 提取数据
      for (let j = 0; j < headers.length; j++) {
        let header = headers[j];
        // 父元素键需要行合并
        if (rawData['rowSpan'] === 0 && mainKeys.has(header.value)) {
          cols.push('!$ROW_SPAN_PLACEHOLDER')
        } else {
          let value;
          if (typeof header.exeFun === 'function') {
            value = header.exeFun(rawData);
          } else {
            value = rawData[header.value];
          }
          cols.push(value)
          // 如果该列需要合计,并且是数字类型
          if (header['summable'] && typeof value === 'number') {
            sumCols[j] = (sumCols[j] ? sumCols[j] : 0) + value;
          }
        }
      }
      rows.push(cols);
    }
    // 如果有合计行
    if (sumCols.length > 0) {
      rows.push(...sumRowHandle(sumCols));
    }
    return rows;
  }

  // 合计行
  var sumRowHandle = (sumCols) => {
    //TODO
    return [];
  }

  // 扁平头部
  var flat = (revealList) => {
    let result = []
    revealList.forEach(e => {
      if (e.hasOwnProperty('childHead') && e.childHead.length > 0) {
        result.push(...flat(e.childHead))
      } else if (e.hasOwnProperty('exeFun')) {
        result.push(e)
      } else if (e.hasOwnProperty('text')) {
        result.push(e)
      }
    })
    return result;
  }

  // 初始化标题栏
  var iniTitle = (option, headers) => {
    var maxColumnSize = headers.length
    titleHeader = []
    // 主标题
    if (option.otherData && option.otherData.ExcelTitle && option.otherData.ExcelTitle.t) {
      var title = []
      title.push(option.otherData.ExcelTitle.t)
      for (var i = 1; i < maxColumnSize; i++) {
        title.push('!$COL_SPAN_PLACEHOLDER')
      }
      titleHeader.push(title)
    }

    // 副标题
    if (option.otherData && option.otherData.ExcelTitle && option.otherData.ExcelTitle.multiT) {
      var t = option.otherData.ExcelTitle.multiT
      var size = Math.floor(maxColumnSize / 3)
      for (var i = 0; i < option.otherData.ExcelTitle.multiT.t0.length; i++) {
        var t = []
        var e = size
        if (option.otherData.ExcelTitle.multiT.t0) {
          t.push(option.otherData.ExcelTitle.multiT.t0[i])
          for (let i = 1; i < e; i++) {
            t.push('!$COL_SPAN_PLACEHOLDER')
          }
        }

        if (option.otherData.ExcelTitle.multiT.t1) {
          t.push(option.otherData.ExcelTitle.multiT.t1[i])
          for (let i = 1; i < e; i++) {
            t.push('!$COL_SPAN_PLACEHOLDER')
          }
        }

        if (option.otherData.ExcelTitle.multiT.t2) {
          t.push(option.otherData.ExcelTitle.multiT.t2[i])
          e = maxColumnSize - t.length
          for (let i = 0; i < e; i++) {
            t.push('!$COL_SPAN_PLACEHOLDER')
          }
        }
        titleHeader.push(t)
      }
    }
    return titleHeader
  }

  // 初始化页脚
  var iniFoot = (option, headers) =>{
    var maxColumnSize = headers.length
    var foot = []
    if (option.otherData && option.otherData.ExcelFoot && option.otherData.ExcelFoot) {
      var size = Math.floor(maxColumnSize / 3)

      var t = []
      var e = size
      if (option.otherData.ExcelFoot.left) {
        t.push(option.otherData.ExcelFoot.left)
        for (let i = 1; i < e; i++) {
          t.push('!$COL_SPAN_PLACEHOLDER')
        }
      }

      if (option.otherData.ExcelFoot.center) {
        t.push(option.otherData.ExcelFoot.center)
        for (let i = 1; i < e; i++) {
          t.push('!$COL_SPAN_PLACEHOLDER')
        }
      }

      if (option.otherData.ExcelFoot.right) {
        t.push(option.otherData.ExcelFoot.right)
        e = maxColumnSize - t.length
        for (let i = 0; i < e; i++) {
          t.push('!$COL_SPAN_PLACEHOLDER')
        }
      }
      foot.push(t)
    }
    return foot
  }

  this.toExcel = function (option) {
    if (!option.sheetName) {
      option.sheetName = 'Sheet1'
    }

    iniData(option)

    // excel表头
    var excelHeader = buildHeader(option.otherData.ExcelHead)
    var headers = flat(option.otherData.ExcelHead)
    var foots = iniFoot(option, headers)
    iniTitle(option, headers)
    // 头部行数，用来固定表头
    var headerRows = excelHeader.length
    if (titleHeader.length > 0) {
      headerRows++
    }

    // 提取数据
    var dataList = extractData(option.data, option.otherData.ExcelHead)
    // excelHeader.unshift(titleHeader)
    excelHeader = titleHeader.concat(excelHeader)
    if (dataList.length > 0) {
      excelHeader.push(...dataList, [])
    }
    if (foots && foots.length>0){
      excelHeader.push(foots[0])
    }

    // 计算合并
    var merges = doMerges(excelHeader)
    // 生成sheet
    var ws = aoa_to_sheet(excelHeader, headerRows)
    // 单元格合并
    ws['!merges'] = merges
    // 头部冻结
    ws["!freeze"] = {
      xSplit: "1",
      ySplit: "" + headerRows,
      topLeftCell: "B" + (headerRows + 1),
      activePane: "bottomRight",
      state: "frozen",
    }
    // 列宽
    var columns = []
    for (var i = 0; i < headers.length; i++) {
      var n = (headers[i].width ? Number(headers[i].width) : 100)

      columns.push({
        wpx: Math.ceil(n)
      })
    }
    ws['!cols'] = columns
    var workbook = {
      SheetNames: [option.sheetName],
      Sheets: {}
    }
    workbook.Sheets[option.sheetName] = ws
    // excel样式
    var wopts = {
      bookType: 'xlsx',
      bookSST: false,
      type: 'binary',
      cellStyles: true
    }
    var wbout = XLSX.write(workbook, wopts)
    var blob = new Blob([s2ab(wbout)], { type: "application/octet-stream" })
    openDownloadXLSXDialog(blob, option.fileName)
  }

  this.success = function(){}
}

export default ExcelHelper