加载中...

vue+element导出excel,并修改样式,以及动态合并单元格

首先安装以下三个安装包

npm install --save xlsx(无法设置样式)
npm install --save xlsx-style(支持设置样式)
npm install -S file-saver

注意:如果安装了npm install --save xlsx-style
会报错:This relative module was not found: ./cptable in ./node_modules/xlsx-style@0.8.13@xlsx-style/dist/cpexcel.js

可以直接修改源码:
在\node_modules\xlsx-style\dist\cpexcel.js 807行 的 var cpt = require(’./cpt’ + ‘able’); 改成 var cpt = cptable;

也可以在项目vue.config.js 文件中添加

module.exports = {
  lintOnSave: false,
  css: {
    loaderOptions: {
      sass: {
        data: `@import "~@/styles/variables.scss";`
      }
    }
  },  
  chainWebpack: config => {
  //在 chainWebpack 添加下面的一段代码
    config.externals({ "./cptable": "var cptable" });**
  },
  devServer: {}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

头部数据以及内容区的数据的合并:

// 计算合并行
//		listData是后台接口返回的数据
      const dataNew = JSON.parse(JSON.stringify(listData))
      const groupData = this.setrowspans(dataNew)
      const mergesArr = []
      // 内容数据合并单元格
      groupData.forEach((item, index) => {
        if (item.rowspan && item.rowspan > 0) {
          const indexNew = index + 3
          // 遍历合并单元格--内容部分
          const cellArr = [''A'', ''B'', ''C'', ''D'', ''E'', ''F'', ''G'', ''H'', ''I'', ''J'', ''K'', ''L'', ''M'']
          cellArr.forEach(cellItem => {
            const cell = cellItem + indexNew + '':'' + cellItem + (indexNew + item.rowspan - 1)
            mergesArr.push(cell)
          })
        }
      })
      import(''@/vendor/Export2Excel'').then(excel => {
        const multiHeader = [
          [''序号'', ''应用代号'', ''应用名称'', ''发布环境'', ''包版本'', ''包大小'', ''发布结果'', ''开始时间'', ''结束时间'', ''平均用时'', ''实例数'', ''预检查'', ''下载包'', ''平均用时'', '''', '''', '''']
        ]
        const tHeader = ['''', '''', '''', '''', '''', '''', '''', '''', '''', '''', '''', '''', '''', ''传包'', ''启动'', ''IP'', ''单台服务器平均用时'']
        let merges = [''A1:A2'', ''B1:B2'', ''C1:C2'', ''D1:D2'', ''E1:E2'', ''F1:F2'', ''G1:G2'', ''H1:H2'', ''I1:I2'', ''J1:J2'', ''K1:K2'', ''L1:L2'', ''M1:M2'', ''N1:Q1'']
        merges = merges.concat(mergesArr)
        const filterVal = [''serialNumber'', ''appCode'', ''appName'', ''environmentCode'', ''appPkgVersion'', ''packageSize'', ''publishResult'', ''publishStartTimeStr'', ''publishEndTimeStr'', ''publishTimeConsumingStr'', ''serverTotal'', ''precheckConsumingStr'', ''downloadPackageConsumingStr'', ''downStageStatisticsDetailList1'', ''downStageStatisticsDetailList2'', ''downStageStatisticsDetailList3'', ''downStageStatisticsDetailList4'']
        const data = this.formatJson(filterVal, groupData)
        // 数据为空赋值‘-’,不然单元格设置颜色会无效
        for (var key in data) {
          if (data[key]) {
            for (let index = 0; index < data[key].length; index++) {
              data[key][index] = data[key][index] ? data[key][index] : ''-''
            }
          }
        }
        // 头部样式
        const hearerStyle = [''A1'', ''B1'', ''C1'', ''D1'', ''E1'', ''F1'', ''G1'', ''H1'', ''I1'', ''J1'', ''K1'', ''L1'', ''M1'', ''N1'', ''O1'', ''P1'', ''Q1'', ''A2'', ''B2'', ''C2'', ''D2'', ''E2'', ''F2'', ''G2'', ''H2'', ''I2'', ''J2'', ''K2'', ''L2'', ''M2'', ''N2'', ''O2'', ''P2'', ''Q2'']
        excel.export_json_to_excel({
          multiHeader, // 第一行
          header: tHeader, // 第二行
          data,
          hearerStyle, // 头部样式
          filename: ''应用发布各阶段用时统计'' + name,
          merges // 单元格合并
        })
      })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

// 设置合并行方法: setrowspans(arrData)

// 设置合并行
    setrowspans(arrData) {
      // 先给所有的数据都加一个v.rowspan = 1
      arrData.forEach(v => {
        v.rowspan = 1
      })
      // 双层循环
      for (let i = 0; i < arrData.length; i++) {
        // 内层循环,上面已经给所有的行都加了v.rowspan = 1
        // 这里进行判断
        // 如果当前行的id和下一行的id相等
        // 就把当前v.rowspan + 1
        // 下一行的v.rowspan - 1
        for (let j = i + 1; j < arrData.length; j++) {
          if (arrData[i].pubType !== '''' && arrData[i].pubType === arrData[j].pubType) {
            arrData[i].rowspan++
            arrData[j].rowspan--
          }
        }
        // 这里跳过已经重复的数据
        i = i + arrData[i].rowspan - 1
      }
      return arrData
    },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Export2Excel.js文件代码如下:

/* eslint-disable */
import { saveAs } from ''file-saver''
// import XLSX from ''xlsx''
import XLSX from ''xlsx-style''
function generateArray(table) {
  var out = [];
  var rows = table.querySelectorAll(''tr'');
  var ranges = [];
  for (var R = 0; R < rows.length; ++R) {
    var outRow = [];
    var row = rows[R];
    var columns = row.querySelectorAll(''td'');
    for (var C = 0; C < columns.length; ++C) {
      var cell = columns[C];
      var colspan = cell.getAttribute(''colspan'');
      var rowspan = cell.getAttribute(''rowspan'');
      var cellValue = cell.innerText;
      if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;

      //Skip ranges
      ranges.forEach(function (range) {
        if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
          for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
        }
      });

      //Handle Row Span
      if (rowspan || colspan) {
        rowspan = rowspan || 1;
        colspan = colspan || 1;
        ranges.push({
          s: {
            r: R,
            c: outRow.length
          },
          e: {
            r: R + rowspan - 1,
            c: outRow.length + colspan - 1
          }
        });
      };

      //Handle Value
      outRow.push(cellValue !== "" ? cellValue : null);

      //Handle Colspan
      if (colspan)
        for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
    }
    out.push(outRow);
  }
  return [out, ranges];
};

function datenum(v, date1904) {
  if (date1904) v += 1462;
  var epoch = Date.parse(v);
  return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}

function sheet_from_array_of_arrays(data, opts) {
  var ws = {};
  var range = {
    s: {
      c: 10000000,
      r: 10000000
    },
    e: {
      c: 0,
      r: 0
    }
  };
  for (var R = 0; R != data.length; ++R) {
    for (var 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;
      var cell = {
        v: data[R][C]
      };
      if (cell.v == null) continue;
      var cell_ref = XLSX.utils.encode_cell({
        c: C,
        r: R
      });

      if (typeof cell.v === ''number'') cell.t = ''n'';
      else if (typeof cell.v === ''boolean'') cell.t = ''b'';
      else if (cell.v instanceof Date) {
        cell.t = ''n'';
        cell.z = XLSX.SSF._table[14];
        cell.v = datenum(cell.v);
      } else cell.t = ''s'';

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

function Workbook() {
  if (!(this instanceof Workbook)) return new Workbook();
  this.SheetNames = [];
  this.Sheets = {};
}

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

export function export_table_to_excel(id) {
  var theTable = document.getElementById(id);
  var oo = generateArray(theTable);
  var ranges = oo[1];

  /* original data */
  var data = oo[0];
  var ws_name = "SheetJS";

  var wb = new Workbook(),
    ws = sheet_from_array_of_arrays(data);

  /* add ranges to worksheet */
  // ws[''!cols''] = [''apple'', ''banan''];
  ws[''!merges''] = ranges;

  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name);
  wb.Sheets[ws_name] = ws;

  var wbout = XLSX.write(wb, {
    bookType: ''xlsx'',
    bookSST: false,
    type: ''binary''
  });

  saveAs(new Blob([s2ab(wbout)], {
    type: "application/octet-stream"
  }), "test.xlsx")
}

export function export_json_to_excel({
  multiHeader = [],
  header,
  data,
  filename,
  hearerStyle = [], //头部样式
  merges = [],
  autoWidth = true,
  bookType = ''xlsx''
} = {}) {
  /* original data */
  filename = filename || ''excel-list''
  data = [...data]
  data.unshift(header);

  for (let i = multiHeader.length - 1; i > -1; i--) {
    data.unshift(multiHeader[i])
  }

  var ws_name = "SheetJS";
  var wb = new Workbook(),
    ws = sheet_from_array_of_arrays(data);

  if (merges.length > 0) {
    if (!ws[''!merges'']) ws[''!merges''] = [];
    merges.forEach(item => {
      ws[''!merges''].push(XLSX.utils.decode_range(item))
    })
  }

  if (autoWidth) {
    /*设置worksheet每列的最大宽度*/
    const colWidth = data.map(row => row.map(val => {
      /*先判断是否为null/undefined*/
      if (val == null) {
        return {
          ''wch'': 10
        };
      }
      /*再判断是否为中文*/
      else if (val.toString().charCodeAt(0) > 255) {
        return {
          ''wch'': val.toString().length * 2
        };
      } else {
        return {
          ''wch'': val.toString().length
        };
      }
    }))
    /*以第一行为初始值*/
    let result = colWidth[0];
    for (let i = 1; i < colWidth.length; i++) {
      for (let j = 0; j < colWidth[i].length; j++) {
        if (result[j][''wch''] < colWidth[i][j][''wch'']) {
          result[j][''wch''] = colWidth[i][j][''wch''];
        }
      }
    }
    ws[''!cols''] = result;
  }

  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name);
  wb.Sheets[ws_name] = ws;

  var dataInfo = wb.Sheets[wb.SheetNames[0]];
  
  // 这是表头行的样式
  var tableTitleFont = {
    border: {
      top: {
        style: ''thin'',
        color: {rgb: "ffffff"},
      },
      right: {
        style: ''thin'',
        color: {rgb: "ffffff"},
      },
      bottom: {
        style: ''thin'',
        color: {rgb: "ffffff"},
      },
      left: {
        style: ''thin'',
        color: {rgb: "ffffff"},
      },
    },
    font: {
      sz: 12,
      color: {rgb: "ffffff"},
      bold: true,
    },
    alignment: {
      horizontal: "center",
      vertical: "center"
    },
    fill: {
      fgColor: {rgb: "017ede"},
    },
  };
  for (var i = 0; i < hearerStyle.length; i++) {
    dataInfo[hearerStyle[i]].s = tableTitleFont;
  }
  var wbout = XLSX.write(wb, {
    bookType: bookType,
    bookSST: false,
    type: ''binary''
  });
  saveAs(new Blob([s2ab(wbout)], {
    type: "application/octet-stream"
  }), `${filename}.${bookType}`);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260