-
引入组件yxg-xlsx-style
-
导出excel主要逻辑文件(跟业务无关):excel-style.js
import XLSX from 'yxg-xlsx-style'
// 如果单元格是日期类型
function datenum (v, date1904) {
if (date1904) v += 1462
let epoch = Date.parse(v)
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000)
}
// 将二维数组(如:data[0][0])变换成excel数据格式(如:A1)
function sheet_from_array_of_arrays (data, callback) {
let ws = {}
let 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
let cell = {
v: data[R][C],
s: {
font: {
name: '微软雅黑',
sz: 9,
bold: false,
// color: {
// auto: 1
// },
color: {
rgb: callback ? callback(data[R][C]) : '',
},
},
border: {
color: { auto: 1, },
},
alignment: {
/// 自动换行
wrapText: 1,
// 居中
horizontal: 'center',
vertical: 'center',
indent: 0,
},
},
}
// 这里生成cell的时候,使用上面定义的默认样式
if (cell.v == null) continue
let 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
}
// 新建excel文件(一个excel文件里面有很多工作表)
function Workbook () {
if (!(this instanceof Workbook)) return new Workbook()
this.SheetNames = []
this.Sheets = {}
}
// 该函数尚不清楚是做啥的
function 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
}
// 生成excel文件
function saveAs (obj, fileName) {
let tmpa = document.createElement('a')
tmpa.download = fileName || '下载'
tmpa.href = URL.createObjectURL(obj)
tmpa.click()
setTimeout(function () {
URL.revokeObjectURL(obj)
}, 100)
}
// 生成excel文件总入口函数
export function export_json_to_excel (
{
title,
multiHeader = [],
header,
data,
filename,
merges = [],
autoWidth = true,
bookType = 'xlsx',
callback,
} = {}) {
console.log(callback)
const getFormattedTime = () => {
let today = new Date()
let y = today.getFullYear()
// JavaScript months are 0-based.
let m = today.getMonth() + 1
let d = today.getDate()
let h = today.getHours()
let mi = today.getMinutes()
let s = today.getSeconds()
return y + '-' + m + '-' + d + '-' + h + '-' + mi + '-' + s
}
filename = filename || getFormattedTime()
data = [ ...data, ]
data.unshift(header)
if (merges.length > 0) {
data.unshift(title)
}
for (let i = multiHeader.length - 1; i > -1; i--) {
data.unshift(multiHeader[i])
}
let ws_name = 'SheetJS'
let wb = new Workbook()
let ws = sheet_from_array_of_arrays(data, callback)
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 => {
if (val == null) {
return {
'wch': 10,
}
} else {
let maxWch = 0
let wch = 0
const arrForVal = val.split('\n')
arrForVal.forEach(val2 => {
if (val2 == null) {
wch = 10
} else if (val2.toString().charCodeAt(0) > 255) {
wch = val2.toString().length * 2
} else {
wch = val2.toString().length
}
if (wch > maxWch) {
maxWch = wch
}
})
return {
'wch': maxWch,
}
}
}))
// 以第一行基准,第二行及其以后的对比第一行的每列宽度,选择最宽的
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
} else {
// 设置worksheet每列的固定宽度
if (data[0]) {
ws['!cols'] = data[0].map(val => {
return {
'wch': 15,
}
})
}
}
// add worksheet to workbook
wb.SheetNames.push(ws_name)
wb.Sheets[ws_name] = ws
let dataInfo = wb.Sheets[wb.SheetNames[0]]
// 单元格外侧框线
const borderAll = {
top: {
style: 'thin',
color: {
rgb: 'e8eaec',
},
},
bottom: {
style: 'thin',
color: {
rgb: 'e8eaec',
},
},
left: {
style: 'thin',
color: {
rgb: 'e8eaec',
},
},
right: {
style: 'thin',
color: {
rgb: 'e8eaec',
},
},
color: { auto: 1, },
}
// 给所有单元格加上边框
for (let i in dataInfo) {
if (merges.length > 0) {
if (i === '!ref' || i === '!merges' || i === '!cols' || i === 'A1') {
} else {
dataInfo[i + ''].s.border = borderAll
}
} else {
if (i === '!ref' || i === '!merges' || i === '!cols') {
} else {
dataInfo[i + ''].s.border = borderAll
}
}
}
// 去掉标题边框
if (merges.length > 0) {
let arr = [ 'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1', 'K1', 'L1', 'M1', 'N1', 'O1', 'P1', 'Q1', 'R1', 'S1', 'T1', 'U1', 'V1', 'W1', 'X1', 'Y1', 'Z1', ]
arr.some(function (v) {
let a = merges[0].split(':')
if (v === a[1]) {
dataInfo[v].s = {}
return true
} else {
dataInfo[v].s = {}
}
})
}
if (merges.length > 0) {
// 设置主标题样式
dataInfo['A1'].s = {
font: {
name: '微软雅黑',
sz: 9,
color: { rgb: 'ff0000', },
bold: true,
italic: false,
underline: false,
},
alignment: {
horizontal: 'center',
vertical: 'center',
},
// fill: {
// fgColor: {rgb: "008000"},
// },
}
}
let wbout = XLSX.write(wb, {
bookType: bookType,
bookSST: false,
type: 'binary',
})
saveAs(new Blob([ s2ab(wbout), ], {
type: 'application/octet-stream',
}), `${filename}.${bookType}`)
}
- 拿到表格数据导出excel之前(即调用第1步总入口函数 export_json_to_excel )的预处理
export const radarDataExportExcel = (params) => {
const {
table,
} = params
import('@/libs/excel-style').then(excel => {
const getFormattedTime = () => {
let today = new Date()
let y = today.getFullYear()
// JavaScript months are 0-based.
let m = today.getMonth() + 1
let d = today.getDate()
let h = today.getHours()
let mi = today.getMinutes()
let s = today.getSeconds()
return y + '-' + m + '-' + d + '-' + h + '-' + mi + '-' + s
}
const title = [] // 标题
const tHeader = [] // 表头
const filterVal = []
table.columns.forEach((item, index) => {
tHeader.push(item.title)
filterVal.push(item.key)
})
// 表头对应字段
let list = []
table.data.forEach(item => {
let obj = {}
for (let key in item) {
if (filterVal.includes(key)) {
// 找到表格Header对应的字段
obj[key] = item[key]
}
}
list.push(obj)
})
const data = list.map(v => filterVal.map(j => v[j])) // 该函数将对象数组变成普通二维数组(如:data[0][0])
data.map(item => {
item.map((i, index) => {
if (!i) {
item[index] = ''
}
})
})
const merges = []
excel.export_json_to_excel({
title: title,
header: tHeader,
data,
merges,
filename: getFormattedTime(),
autoWidth: true,
bookType: 'xlsx',
})
}).catch(e => {
})
}
- 给一个例子看看
web页面表格样式
导出excel样式