UNPKG

@asasugar-use/custom-json2excel

Version:

✌传入json,可自定义表格标题名称和列数、头部名称、过滤列和绑定生成开始与成功的回调函数

196 lines (186 loc) 6.13 kB
import { utils, read } from 'xlsx'; import { parse, ParseResult } from 'papaparse'; import type { WorkSheet, WorkBook } from 'xlsx'; import type { AnyObject, ExcelData } from '../typing'; /** * 获取工作表的标题行 * @param sheet - 工作表对象 * @returns 标题行数组 */ function getHeaderRow (sheet: WorkSheet) { // 如果工作表或其引用不存在,则返回空数组 if (!sheet || !sheet['!ref']) return []; const headers: string[] = []; // 解码工作表的引用范围 const range = utils.decode_range(sheet['!ref']); const R = range.s.r; // 遍历范围内的每一列 for (let C = range.s.c; C <= range.e.c; ++C) { // 获取当前列的第一个单元格 const cell = sheet[utils.encode_cell({ c: C, r: R })]; // 设置默认的标题为 "UNKNOWN" 加上列索引 let hdr = 'UNKNOWN ' + C; // 如果单元格存在且有类型,则格式化单元格内容作为标题 if (cell && cell.t) hdr = utils.format_cell(cell); headers.push(hdr); } // 返回标题行数组 return headers; } /** * 从工作簿中获取 Excel 数据 * @param workbook - 工作簿对象 * @returns ExcelData 数组 */ function getExcelData (workbook: WorkBook) { const excelData: ExcelData[] = []; // 遍历工作簿中的每个工作表 for (const sheetName of workbook.SheetNames) { const worksheet = workbook.Sheets[sheetName]; // 获取工作表的标题行 const header: string[] = getHeaderRow(worksheet); // 将工作表转换为 JSON 数据 let results = utils.sheet_to_json(worksheet, { raw: true, }) as AnyObject[]; // 将标题行、结果数据和元数据添加到 ExcelData 数组中 excelData.push({ header, results, meta: { sheetName } }); } return excelData; } /** * 从 Csv 中获取 Excel 数据 * @param csv - csv对象 * @returns ExcelData 数组 */ function getCsvData (csv: ParseResult<any>) { // 获取 CSV 数据的标题行 const header = csv.meta.fields ?? []; // 获取 CSV 数据的结果行 const results = csv.data.filter((item) => { return Object.keys(item as AnyObject).length === header.length; }); const excelData = [{ header, results, meta: { sheetName: `Sheet1` } }]; return excelData; } /** * 读取文件并解析为 Excel 数据 * @param rawFile - 文件对象 * @returns 解析后的 ExcelData 数组的 Promise */ export function readerData (rawFile: File): Promise<ExcelData[]> { return new Promise((resolve, reject) => { if (!(rawFile instanceof File)) { reject(new Error('RawFile must be file')); } let reader = new FileReader(); if (rawFile.type === 'application/vnd.ms-excel' || rawFile.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') { reader.onload = async e => { try { const data = e.target?.result; // 如果没有数据,则抛出错误 if (!data) { reject(new Error('No data')); } // 如果文件类型是 Excel // 处理Excel文件 // 使用 xlsx 库的 read 方法读取文件数据为工作簿对象 const workbook = read(data, { type: 'array', cellDates: true }); // 从工作簿中获取 Excel 数据 const excelData = getExcelData(workbook); resolve(excelData); } catch (error) { reject(error); } }; // 以 ArrayBuffer 格式读取文件 reader.readAsArrayBuffer(rawFile); } else if (rawFile.type === 'text/csv') { reader.onload = async e => { try { const data = e.target?.result; // 如果没有数据,则抛出错误 if (!data) { reject(new Error('No data')); } // 处理CSV文件 // 如果数据不是字符串类型,则抛出错误,因为会乱码 if (typeof data !== 'string') { reject(new Error('Invalid data type')); } // 使用 papaparse 库的 parse 方法解析 CSV 数据 const csv = parse<any>(data as string, { header: true }); // 从工作簿中获取 Excel 数据 const excelData = getCsvData(csv); resolve(excelData); } catch (error) { reject(error); } }; // 以文本格式读取文件 reader.readAsText(rawFile); } }); } /** * 将 Base64 字符串转换为 Blob 对象 * @param data - Base64 编码的字符串 * @param mime - MIME 类型字符串 * @returns Blob 对象 */ export function base64ToBlob (data: string, mime: string) { try { // 确保输入是一个有效的 Base64 编码字符串 if (typeof data !== 'string') { throw new Error('Input data must be a string'); } // 解码 Base64 字符串为二进制字符串 let binaryString = window.btoa(data); // 将二进制字符串转换为 Uint8Array const len = binaryString.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = binaryString.charCodeAt(i); } // 创建并返回 Blob 对象 return new Blob([bytes], { type: mime }); } catch (error) { // 重新抛出异常以便调用者处理 console.error('Error converting Base64 to Blob:', error); throw error; } } /** * 将 String 字符串转换为 Blob 对象 * @param data - String 类型的字符串 * @param mime - MIME 类型字符串 * @returns Blob 对象 */ export function stringToBlob (data: string, mime: string): Blob { try { // 确保输入是一个有效的字符串 if (typeof data !== 'string') { throw new Error('Input data must be a string'); } // 使用 TextEncoder 将字符串编码为 Uint8Array const encoder = new TextEncoder(); const uint8Array = encoder.encode(data); // 创建 Blob 对象 return new Blob([uint8Array], { type: mime }); } catch (error) { console.error('Error converting string to Blob:', error); throw error; // 重新抛出异常以便调用者处理 } }