需求:
table列表,右上角有导出按钮,点击导出table的list数据。前端实现导出。
1.antd的button实现样式。
<div className={style.Btns}> <Button.Group> <Button onClick={this.clickFresh}> <MyIcon type='icon-refresh' /> 刷新 </Button> {eventManagePrivilege && ( <Button onClick={this.onExport}> <MyIcon type='icon-export' /> 导出 </Button> )} </Button.Group> </div>
eventManagePrivilege,是管理权限判断。
2.导出方法onExport()
当前页面
//导出 onExport = async e => { const { dispatch } = this.props; dispatch(spinControl(true, '正在导出,请稍后...')); const {condition} = this.state; const payload = { ...condition, startwith: 0, limit: 9999, }; const res = await _fetchLogs(payload); const dataList = res.collection || []; let list = dataList.map(item => { return { ['用户']: item.user, ['名称']: item.performedBy, ['严重性']: item.severity, ['时间']: moment(item.timestamp).format('YYYY-MM-DD HH:mm:ss'), ['追踪']: item.stacktrace, }; }); await downloadExl(list, 'xlsx', '操作日志.xlsx'); dispatch(spinControl(false, '')); };
获取列表数据,然后return里面进行数据处理,返回需要导出的内容。
这里关键是downloadExl方法,在until写的公共方法。
`import { downloadExl } from 'utils/exportXlsx';`
以下是exportXlsx.js
import { message,notification } from 'antd';
import XLSX from 'xlsx';
/**
* @param {Array} arr 数据源
* @param {String} type 下载类型
* @param {String} filename 下载文件名
*/
export function downloadExl(arr, type, filename = '操作日志.xlsx') {
if(!arr || !arr.length){
return notification.error({
message: '导出失败',
description: '列表数据为空'
});
}
let tmpDown, //导出的二进制对象
data = arr[0];
arr.unshift({});
let keyMap = []; //获取keys
for (let k in data) {
keyMap.push(k);
arr[0][k] = k;
}
let tmpdata = []; //用来保存转换好的json
arr.map((v, i) =>
keyMap.map((k, j) =>
Object.assign({}, { v: v[k], position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1) }),
),
)
.reduce((prev, next) => prev.concat(next))
.forEach((v, i) => (tmpdata[v.position] = { v: v.v }));
var outputPos = Object.keys(tmpdata); //设置区域,比如表格从A1到D10
var tmpWB = {
SheetNames: ['mySheet'], //保存的表标题
Sheets: {
mySheet: Object.assign(
{},
tmpdata, //内容
{
'!ref': outputPos[0] + ':' + outputPos[outputPos.length === 0 ? 0 : outputPos.length - 1], //设置填充区域
},
),
},
};
tmpDown = new Blob(
[
s2ab(
XLSX.write(
tmpWB,
{ bookType: type === undefined ? 'xlsx' : type, bookSST: false, type: 'binary' }, //这里的数据是用来定义导出的格式类型
),
),
],
{ type: '' },
); //创建二进制对象写入转换好的字节流
const href = URL.createObjectURL(tmpDown); //创建对象超链接
const a = document.createElement('a');
a.href = href; //绑定a标签
a.download = filename;
a.click(); //模拟点击实现下载
setTimeout(function() {
//延时释放
URL.revokeObjectURL(tmpDown); //用URL.revokeObjectURL()来释放这个object URL
}, 100);
}
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;
} // 将指定的自然数转换为26进制表示。映射关系:[0-25] -> [A-Z]。
function getCharCol(n) {
let s = '',
m = 0;
while (n > 0) {
m = (n % 26) + 1;
s = String.fromCharCode(m + 64) + s;
n = (n - m) / 26;
}
return s;
}
如果是后端导出,那就简单了,直接调后端接口就可以了。