转换 antd table 的数据格式,导入导出 excel 文件

1,169 阅读3分钟

文本通过转换 antd-table 的数据格式,通过之前的文章 xlsx-style 在 express 中的应用 ,使用 xlsx-style 组件库的 express 的接口,导出带样式的 excel 文件。下面是一个与antd table的数据格式转换的一个实例,大家可以参考来进行改造,将 antd table 与 xlsx-style 组件库进行打通,前端进行 excel 文件导入导出,而不需要依赖 java 后台。

import { message } from 'antd'
import { getCookie } from './cookie'

/**
 * [s] cell style property 共4个顶级属性
 * 1. {fill}
 * -------------------------------------
 *    patternType: solid|node 有无
 *    fgColor: COLOR_SPEC 文本色
 *    bgColor: COLOR_SPEC 背景色
 * -------------------------------------
 * 2. {font}
 * -------------------------------------
 *    name: 字体 // default "Calibri"
 *    sz: 字体大小 // default "11"
 *    color: 颜色
 *    bold: 加粗 // true || false
 *    underline: 下划线 // true || false
 *    italic: 斜体 // true || false
 *    strike: 删除线 // true || false
 *    outline: 轮廓线 // true || false
 *    shadow: 阴影 // true || false
 *    vertAlign: **
 * ------------------------------------
 * 3. {alignment}
 * ------------------------------------
 *    vertical: 垂直 // "bottom"||"center"||"top"
 *    horizontal: 水平 // "bottom"||"center"||"top"
 *    wrapText: 本文超出自动换行 // true || false
 *    readingOrder: 阅读方式 // 2 从右到左
 *    textRotation: 旋转 // Number from 0 to 180 or 255 (default is 0)
 * ------------------------------------
 * 4. {border}
 * ------------------------------------
 *    top/bottom/left/right: { style: BORDER_STYLE, color: COLOR_SPEC }
 *    diagonal: 对角线 { style: BORDER_STYLE, color: COLOR_SPEC }
 *    diagonalUp/diagonalDown: 两种对角线的方式 true||false
 * ------------------------------------
 * 【注】BORDER_STYLE:边框样式是一个字符串值,可以采用以下值之一:
 *  thin | medium | thick | dotted | hair | dashed | mediumDashed | dashDot | mediumDashDot
 *  dashDotDot | mediumDashDotDot | slantDashDot
 */
const headerStyleDefault = {
  fill: { fgColor: { rgb: '38364B' } },
  font: { sz: '14', name: '华文宋体', bold: true, color: { rgb: 'F6F6F6' } },
  alignment: { horizontal: 'center', vertical: 'center', wrapText: true, readingOrder: 2 },
  border: {
    top: { style: 'thin', color: { rgb: '000000' } },
    bottom: { style: 'thin', color: { rgb: '000000' } },
    left: { style: 'thin', color: { rgb: '000000' } },
    right: { style: 'thin', color: { rgb: '000000' } }
  }
}
const bodyStyleDefault = {
  font: { sz: '14', name: '华文宋体' },
  fill: { bgColor: { indexed: 64 }, fgColor: { rgb: 'F2F2F2' } },
  border: {
    top: { style: 'thin', color: { rgb: 'BCBCBC' } },
    bottom: { style: 'thin', color: { rgb: 'BCBCBC' } },
    left: { style: 'thin', color: { rgb: 'BCBCBC' } },
    right: { style: 'thin', color: { rgb: 'BCBCBC' } }
  },
  alignment: { horizontal: 'center', vertical: 'center' }
}
const sideStyleDefault = {
  fill: { bgColor: { indexed: 64 }, fgColor: { rgb: 'B1D9F5' } },
  font: { sz: '14', name: '华文宋体' },
  border: {
    top: { style: 'thin', color: { rgb: '000000' } },
    bottom: { style: 'thin', color: { rgb: '000000' } },
    left: { style: 'thin', color: { rgb: '000000' } },
    right: { style: 'thin', color: { rgb: '000000' } }
  }
}
/** 
 * workSheet 的 Sheet 参数,用来进行设置 【!merges合并单元格】【!cols设置列宽】 
 * e.g. 
 */
// cols 设置单元格每一列的宽度,该数组第一位是第一列,依此类推,不设置为默认宽度
const sheetColsDefault = [{ wch: 20 }, { wch: 20 }, { wch: 20 }]
// merges s:起始单元格,e:结束单元格;c(列号)和r(行号),是以0为开头的索引。以合并的第一个单元格value进行填充内容
const sheetMergesDefault = [{
  s: { c: 0, r: 0 },
// 第1列 第1行//
  e: { c: 3, r: 1 }
//第4列 第2行
}]

/**
 * operate progress
 * 1.需要将json数据从this.response取出
 * 2.将json数据转成buffer流
 * 3.将buffer流数据转成blob类型,用于在a标签中导出
 * 4.在a标签中导出数据
 * 【注】fileHeader 数据类型:
 * [
 *  { title: '',
 *    key: '',
 *    children: [
 *      {
 *        title: '',
 *        key: '',
 *       }
 *    ]
 *  },
 *  {
 *    title: '',
 *    key: '',
 *  },
 * ]
 */


/** -------- API start ----------
 * 参数                      说明              类型           默认值                 是否必填
 * fileData                 excel数据         object         {...}                 true
 * —>fileName               excel文件名       stying         'report'               false
 * ->fileHeader             table表头         [{...}]        [{...}]               true
 * ->fileHeaderKey          tableBody键值     []             []                    true
 * ->fileBody               tableBody        [{...}]        [{...}]               true
 * sheetStyle               excel样式         object         {...}                 false
 * ->headerStyle            表头样式           object         headerStyleDefault    false
 * ->bodyStyle              内容样式           object         bodyStyleDefault      false
 * ->sideStyle              侧边栏样式         object         sideStyleDefault      false
 * sheetCols                设置excel列宽      array          [{}]                  false
 * sheetMerges              单元格合并         array          [{}]                   false
 * isNeedSideStyle          侧边栏样式          bool          true                  false
 * isNeedSideWidth          侧边栏默认20宽度    bool           true                  false
 * isNeedBodyStyleCross     body交错样式       bool           true                  false
 * --------- API end -----------
 */
function xlsxStyleExport(sheetData = {}) {
  const {
    fileData,
    sheetStyle = {},
    sheetCols = [],
    sheetMerges = [],
    isNeedSideWidth = true,
    isNeedSideStyle = true,
    isNeedBodyStyleCross = true
  } = sheetData
  const styleDefaultParams = {
    headerStyle: headerStyleDefault,
    bodyStyle: bodyStyleDefault,
    bodyStyleBlank: { ...bodyStyleDefault, fill: { fgColor: { rgb: 'FFFFFF' } } },
    sideStyle: isNeedSideStyle ? sideStyleDefault : bodyStyleDefault, ...sheetStyle
  }
  const fileDataParams = {
    fileHeader: fileData.fileHeader || [],
    fileBody: fileData.fileBody || [],
    fileName: fileData.fileName || ''
  }

  // eslint-disable-next-line no-nested-ternary
  const sheetColsParams = sheetCols.length ? sheetCols : (isNeedSideWidth ? sheetColsDefault : [])
  const sheetMergesParams = sheetMerges.length ? sheetMerges : []
  const params = {
    style: styleDefaultParams,
    fileData: fileDataParams,
    sheetCols: sheetColsParams,
    sheetMerges: sheetMergesParams,
    isNeedBodyStyleCross,
    isNeedSideStyle
  }
  fetch(new Request('/elxsStyle/export', {
    credentials: 'same-origin',
    method: 'POST',
    headers: new Headers({
      ddjjuuid: getCookie('ddjjuuid'),
      'X-Requested-With': 'XMLHttpRequest',
      'Content-Type': 'application/json',
      pragma: 'no-cache',
      'cache-control': 'no-cache'
    }),
    body: JSON.stringify(params)
  })).then(response => response.json()).then((res) => {
    if (res.code === '0') {
      const buffer = Buffer.from(res.data.data)
      const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' })
      const url = URL.createObjectURL(blob)
      const linkElement = document.createElement('a')

      // 创建点击下载的元素
      linkElement.setAttribute('href', url)
      linkElement.setAttribute('downLoad', `${fileData.fileName || 'report'}.xlsx`)
      const evt = document.createEvent('MouseEvents')

      // 兼容火狐浏览器不支持a标签点击事件
      evt.initEvent('click', true, true)
      linkElement.dispatchEvent(evt)
      linkElement.remove()
    } else {
      message.error('导出文件失败,请重试')
    }
  })
}

export default xlsxStyleExport