UNPKG

ryui-vue

Version:

ry公共组件库

170 lines (161 loc) 5.02 kB
import {utils, writeFile} from 'xlsx'; /** * 导出excel表格 * @param {Object} options * @param {Array} options.columns 表格列规则 * @param {Array} options.data 表格数据 - 例:this.$refs.table._data.datas * @param {String} options.fileName 导出文件名 - *.xlsx/*.csv * @param {Array} options.excludes 排除列 - 不需要导出的列, ['index'] * @param {Object} options.formatters 格式化函数 - 自定义formatter() * @return */ export default function exportExcel(options) { let { columns, data, fileName, excludes = [], formatters = {} } = options // 排除项 excludes = ['action', ...excludes]; // 获取不包含排除列的表格列规则 const headerList = columns.filter( (v) => v.prop && !excludes.includes(v.prop) ); // const depthArr = [...new Array(tree(headerList)).keys()]; let obj = []; // 获取多级表头标题数据 for (let depth of depthArr) { obj[depth] = traverse(headerList, depth, 0, []); } // 始化用于存储表头和数据的对象 并赋值[表头标题]-----导出所需要的数据结构 --> 二维数组 [[表头标题], [每一行数据],[每一行数据]...] // let array = [[...headerList.map((v) => v.label)]]; let array = [...obj]; // 获取列表数据 data.forEach((v) => { let list = []; getData(v, headerList, list, formatters); array.push(list); }); // 获取合并单元格规则 const merges = mergeCells(headerList); const sheet = utils.aoa_to_sheet(array); sheet['!merges'] = merges; // 无效 sheet['A1']['s'] = { alignment: { horizontal: 'center', // 水平居中 vertical: 'center' // 垂直居中 } }; // 打印(导出)方法 writeFile( { SheetNames: ['Sheet1'], Sheets: { Sheet1: sheet } }, fileName ); } // 计算多级表头最大深度(层级) function tree(data) { let depth = 1; data.forEach((v) => { if (v.children) { const curDepth = tree(v.children) + 1; depth = Math.max(depth, curDepth); } }); return depth; } // 递归遍历多级表头,生成表头数据 function traverse(array, depth, level, list) { array.map((v) => { if (level === depth && v?.children) { list.push(v.label); const arr = v.children.filter((v) => v.children); const arr2 = new Array(v.children.length - arr.length - 1).fill(null); arr2.push(...arr); traverse(arr2, depth, level + 1, list); } else if (level === depth && !v?.children) { return list.push(v.label); } else if (level !== depth && !v?.children) { return list.push(null); } else if (level !== depth && v?.children) { traverse(v?.children, depth, level + 1, list); } }); return list; } // 根据数据和表头规则提取数据,同时根据自定义格式化规则formatters格式化数据 function getData(v, headerList, list = [], formatters) { headerList.forEach((r) => { // 获取列配置字段名 let propChildren = r.prop.split('.').at(-1); if (r.children) { getData(v[propChildren], r.children, list, formatters); } else { // 获取exportExcel工具函数自定义的formatter格式化规则 const formatterFun = formatters[propChildren]; // 自定义优先级最高 if (formatterFun) { try { list.push(formatterFun(v, r, v[propChildren])); } catch (e) { list.push(v[propChildren]); } // 列配置上定义的formatter格式化规则 } else if (r.formatter) { try { list.push(r.formatter(v, r, v[propChildren])); } catch (e) { list.push(v[propChildren]); } } else { list.push(v[propChildren]); } } }); } // 动态生成多级表头合并需要的合并单元格规则 function mergeCells(columns) { const maxDepth = tree(columns) === 1 ? 0 : tree(columns); const merges = []; let startCol = {index: 0}; processColumns(columns, 0, maxDepth, merges, startCol); return merges; } // 辅助函数 - 根据columns规则动态生成处理多级表头合并需要的数据结构 function processColumns(columns, level, depth, merges, startCol) { for (let column of columns) { // const nextStartCol = startCol + colIndex; const length = getChildrenLength(column.children || []); if (column.children) { merges.push({ s: {r: level, c: startCol.index}, e: {r: level, c: startCol.index + (length - 1)} }); processColumns(column.children, level + 1, depth, merges, startCol); } else { merges.push({ s: {r: level, c: startCol.index}, e: {r: depth, c: startCol.index} }); startCol.index++; } } } // 获取子级的长度---需要合并的列数 function getChildrenLength(columns) { return columns.reduce((pre, cru) => { if (cru.children) { return pre + getChildrenLength(cru.children); } else { return pre + 1; } }, 0); }