我的需求是,仅仅需要预览excel,展示图片、链接、样式等基本内容 univerjs区分两种模式,预设模式和插件模式
插件模式
index.tsx
import
import { Spin } from 'antd'
import { LocaleType, mergeLocales, Univer, UniverInstanceType } from '@univerjs/core'
import type { IWorkbookData } from '@univerjs/core'
import DesignZhCN from '@univerjs/design/locale/zh-CN'
import { UniverDocsPlugin } from '@univerjs/docs'
import { UniverDocsUIPlugin } from '@univerjs/docs-ui'
import DocsUIZhCN from '@univerjs/docs-ui/locale/zh-CN'
import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'
import { UniverRenderEnginePlugin } from '@univerjs/engine-render'
import { UniverSheetsPlugin } from '@univerjs/sheets'
import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'
import SheetsUIZhCN from '@univerjs/sheets-ui/locale/zh-CN'
import SheetsZhCN from '@univerjs/sheets/locale/zh-CN'
import { UniverUIPlugin } from '@univerjs/ui'
import UIZhCN from '@univerjs/ui/locale/zh-CN'
import SheetsHyperLinkUIZhCN from '@univerjs/sheets-hyper-link-ui/locale/zh-CN'
import { UniverSheetsHyperLinkUIPlugin } from '@univerjs/sheets-hyper-link-ui'
import { UniverSheetsDrawingUIPlugin } from '@univerjs/sheets-drawing-ui'
import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'
import { UniverSheetsFormulaUIPlugin } from '@univerjs/sheets-formula-ui'
import SheetsFormulaUIZhCN from '@univerjs/sheets-formula-ui/locale/zh-CN'
// 样式
import '@univerjs/design/lib/index.css'
import '@univerjs/ui/lib/index.css'
import '@univerjs/docs-ui/lib/index.css'
import '@univerjs/sheets-ui/lib/index.css'
import '@univerjs/sheets-formula-ui/lib/index.css'
import '@univerjs/sheets-hyper-link-ui/lib/index.css'
import '@univerjs/sheets-drawing-ui/lib/index.css'
import { handleXlsx, handleXls, handleCsv } from './utils'
interface IProps {
requestUrl: string
height?: string | number
getPreviewFile: (url: string) => Promise<any>
fileType: 'xlsx' | 'xls' | 'csv'
}
const ExcelPreview: React.FC<IProps> = ({ requestUrl, getPreviewFile, fileType, height }) => {
const [loading, setLoading] = useState(false)
const [excelData, setExcelData] = useState<IWorkbookData>()
const univerRef = useRef<any | null>(null)
useEffect(() => {
setLoading(true)
getPreviewFile(requestUrl)
.then(async response => {
if (!response) {
setLoading(false)
return
}
let workbookData: IWorkbookData | undefined
if (fileType === 'xlsx') {
workbookData = await handleXlsx(await response.arrayBuffer())
} else if (fileType === 'xls') {
workbookData = await handleXls(await response.arrayBuffer())
} else {
workbookData = await handleCsv(await response.blob())
}
setExcelData(workbookData)
setLoading(false)
})
.catch(error => {
console.error(error)
setLoading(false)
})
}, [getPreviewFile, fileType, requestUrl])
// 2️⃣ 初始化 Univer 实例
useEffect(() => {
const univer = new Univer({
locale: LocaleType.ZH_CN,
locales: {
[LocaleType.ZH_CN]: mergeLocales(
DesignZhCN,
UIZhCN,
DocsUIZhCN,
SheetsZhCN,
SheetsUIZhCN,
SheetsFormulaUIZhCN,
SheetsHyperLinkUIZhCN,
),
},
})
univer.registerPlugin(UniverRenderEnginePlugin)
univer.registerPlugin(UniverFormulaEnginePlugin, { notExecuteFormula: true })
univer.registerPlugin(UniverUIPlugin, {
container: 'excel-preview-container-univer',
toolbar: false,
contextMenu: false,
footer: true,
header: false,
// editable: false,
// selectionMode: 'text',
})
// 表格核心与 UI
univer.registerPlugin(UniverDocsPlugin)
univer.registerPlugin(UniverDocsUIPlugin)
univer.registerPlugin(UniverSheetsPlugin, {
notExecuteFormula: true,
autoHeightForMergedCells: true,
})
univer.registerPlugin(UniverSheetsUIPlugin)
univer.registerPlugin(UniverSheetsFormulaPlugin, { notExecuteFormula: false })
univer.registerPlugin(UniverSheetsFormulaUIPlugin)
// 绘图与超链接功能
univer.registerPlugin(UniverSheetsDrawingUIPlugin)
univer.registerPlugin(UniverSheetsHyperLinkUIPlugin)
univerRef.current = univer
return () => {
univerRef.current?.dispose()
univerRef.current = null
}
}, [])
useEffect(() => {
if (!excelData || !univerRef.current) return
univerRef.current.createUnit(UniverInstanceType.UNIVER_SHEET, excelData)
}, [excelData])
return (
<Spin size="large" spinning={loading}>
<div
id="excel-preview-container-univer"
style={{
width: '100%',
height: height || '100%',
userSelect: 'text',
}}
/>
</Spin>
)
}
export default ExcelPreview
utils.ts
typescript
import { IWorkbookData, IWorksheetData, ICellData, LocaleType } from '@univerjs/core'
import * as XLSX from 'xlsx'
import LuckyExcel from '@zwight/luckyexcel'
import { v4 as uuidv4 } from 'uuid'
const DEFAULT_ROW_COUNT = 1000
const DEFAULT_COLUMN_COUNT = 20
const DEFAULT_COLUMN_WIDTH = 73
const DEFAULT_ROW_HEIGHT = 19
/**
* 生成基础 WorkbookData
*/
function createWorkbookData(sheets: IWorksheetData[]): IWorkbookData {
const sheetOrder = sheets.map(s => s.id)
const sheetsMap: { [sheetId: string]: Partial<IWorksheetData> } = {}
sheets.forEach(s => {
sheetsMap[s.id] = s
})
return {
id: uuidv4(),
name: 'Workbook',
appVersion: '1.0.0',
locale: LocaleType.ZH_CN,
styles: {},
sheetOrder,
sheets: sheetsMap,
// 资源(图片/样式等)。此处先空数组,避免渲染期望字段缺失
resources: [],
defaultStyle: null,
}
}
/**
* 将二维数组转换成 IWorksheetData 的 cellData 结构(行、列均为数字索引)
*/
function arrayToCellData(data: any[][]): { [row: number]: { [col: number]: ICellData } } {
const cellData: { [row: number]: { [col: number]: ICellData } } = {}
data.forEach((row, rowIndex) => {
if (!cellData[rowIndex]) cellData[rowIndex] = {}
row.forEach((value, colIndex) => {
// 仅在有值时填充 cell,避免生成庞大的稀疏表
if (value !== undefined && value !== null && value !== '') {
const cell: ICellData = { v: value }
// 简单类型标记(可选)
if (typeof value === 'number') {
;(cell as any).t = 2 // number
} else if (typeof value === 'boolean') {
;(cell as any).t = 3 // boolean
} else {
;(cell as any).t = 1 // string / others
}
cellData[rowIndex][colIndex] = cell
}
})
})
return cellData
}
/**
* 计算二维数组的行列数(含默认兜底)
*/
function computeDimensions(rows: any[][]): { rowCount: number; columnCount: number } {
const rowCount = Math.max(DEFAULT_ROW_COUNT, rows.length)
const columnCount = Math.max(
DEFAULT_COLUMN_COUNT,
rows.reduce((max, row) => Math.max(max, row.length), 0),
)
return { rowCount, columnCount }
}
/**
* 从二维数组构建 IWorksheetData
*/
function buildSheetFrom2DArray(name: string, rows: any[][]): IWorksheetData {
const { rowCount, columnCount } = computeDimensions(rows)
return {
id: uuidv4(),
name,
rowCount,
columnCount,
defaultColumnWidth: DEFAULT_COLUMN_WIDTH,
defaultRowHeight: DEFAULT_ROW_HEIGHT,
zoomRatio: 1,
scrollTop: 0,
scrollLeft: 0,
hidden: 0,
tabColor: '',
drawings: {},
drawingsOrder: [],
cellData: arrayToCellData(rows),
} as unknown as IWorksheetData
}
/**
* 将 XLSX 解析结果转换为 sheets(所有 sheet 使用 header:1 的二维数组)
*/
function buildSheetsFromXlsxWorkbook(xlsxWorkbook: XLSX.WorkBook): IWorksheetData[] {
return xlsxWorkbook.SheetNames.map(sheetName => {
const rows = XLSX.utils.sheet_to_json<any[]>(xlsxWorkbook.Sheets[sheetName], { header: 1 })
return buildSheetFrom2DArray(sheetName, rows)
})
}
/**
* 仅使用 xlsx 解析(值级别)并返回完整 IWorkbookData
*/
function parseXlsxArrayBufferToWorkbook(buffer: ArrayBuffer): IWorkbookData {
const xlsxWorkbook = XLSX.read(buffer, { type: 'array' })
const sheets: IWorksheetData[] = buildSheetsFromXlsxWorkbook(xlsxWorkbook)
return createWorkbookData(sheets)
}
/**
* 处理 XLSX 文件
*/
export const handleXlsx = async (buffer: ArrayBuffer): Promise<IWorkbookData> => {
function ensureSheetDefaults(sheet: any): IWorksheetData {
const s: any = { ...sheet }
// 计算行列数(若缺失)
if ((s.rowCount == null || s.columnCount == null) && s.cellData) {
const rowIndices = Object.keys(s.cellData)
.map(k => Number(k))
.filter(n => !Number.isNaN(n))
const maxRow = rowIndices.length > 0 ? Math.max(...rowIndices) : -1
let maxCol = -1
rowIndices.forEach(r => {
const cols = s.cellData[r]
if (!cols) return
const colIndices = Object.keys(cols)
.map(k => Number(k))
.filter(n => !Number.isNaN(n))
if (colIndices.length > 0) maxCol = Math.max(maxCol, Math.max(...colIndices))
})
if (s.rowCount == null) s.rowCount = Math.max(DEFAULT_ROW_COUNT, maxRow + 1)
if (s.columnCount == null) s.columnCount = Math.max(DEFAULT_COLUMN_COUNT, maxCol + 1)
}
if (s.rowCount == null) s.rowCount = DEFAULT_ROW_COUNT
if (s.columnCount == null) s.columnCount = DEFAULT_COLUMN_COUNT
if (s.defaultColumnWidth == null) s.defaultColumnWidth = DEFAULT_COLUMN_WIDTH
if (s.defaultRowHeight == null) s.defaultRowHeight = DEFAULT_ROW_HEIGHT
if (s.zoomRatio == null) s.zoomRatio = 1
if (s.scrollTop == null) s.scrollTop = 0
if (s.scrollLeft == null) s.scrollLeft = 0
if (s.hidden == null) s.hidden = 0
if (s.tabColor == null) s.tabColor = ''
if (s.drawings == null) s.drawings = {}
if (s.drawingsOrder == null) s.drawingsOrder = []
return s as IWorksheetData
}
function normalizeExportJsonToWorkbook(exportJson: any): IWorkbookData {
if (!exportJson) throw new Error('Invalid exportJson')
const wb: any = { ...exportJson }
if (!wb.id) wb.id = uuidv4()
if (!wb.name) wb.name = 'Workbook'
if (!wb.styles) wb.styles = {}
if (!wb.resources) wb.resources = []
if (Array.isArray(wb.sheets)) {
const arr = wb.sheets
const sheetOrder: string[] = []
const map: Record<string, any> = {}
arr.forEach((s: any) => {
const id = s.id || uuidv4()
sheetOrder.push(id)
map[id] = ensureSheetDefaults({ ...s, id })
})
wb.sheets = map
if (!wb.sheetOrder) wb.sheetOrder = sheetOrder
} else if (wb.sheets && typeof wb.sheets === 'object') {
if (!wb.sheetOrder) wb.sheetOrder = Object.keys(wb.sheets)
Object.keys(wb.sheets).forEach((id: string) => {
wb.sheets[id] = ensureSheetDefaults({ id, ...wb.sheets[id] })
})
} else {
throw new Error('exportJson.sheets missing')
}
return wb as IWorkbookData
}
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
})
const file = new File([blob], 'import.xlsx', { type: blob.type })
return new Promise<IWorkbookData>((resolve, reject) => {
LuckyExcel.transformExcelToUniver(
file,
(exportJson: any) => {
try {
const wb = normalizeExportJsonToWorkbook(exportJson)
resolve(wb)
} catch (err) {
// 解析结果异常时,回退到 xlsx 仅值解析
try {
resolve(parseXlsxArrayBufferToWorkbook(buffer))
} catch (fallbackErr) {
reject(fallbackErr)
}
}
},
(error: any) => {
// 插件报错时,回退到 xlsx 仅值解析
try {
resolve(parseXlsxArrayBufferToWorkbook(buffer))
} catch (e) {
reject(error || e)
}
},
)
})
}
/**
* 处理 XLS 文件
*/
export function handleXls(buffer: ArrayBuffer): IWorkbookData {
const xlsWorkbook = XLSX.read(buffer, { type: 'array' })
const sheets: IWorksheetData[] = buildSheetsFromXlsxWorkbook(xlsWorkbook)
return createWorkbookData(sheets)
}
/**
* 处理 CSV 文件
*/
export async function handleCsv(blob: Blob): Promise<IWorkbookData> {
const text = await blob.text()
const rows = text.split(/\r?\n/).map(r => r.split(','))
const sheet: IWorksheetData = buildSheetFrom2DArray('Sheet1', rows)
return createWorkbookData([sheet])
}
预设模式 index.tsx
typescript
import React, { useEffect, useState, useRef } from 'react'
import { Spin } from 'antd'
import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core'
import { UniverSheetsDrawingPreset } from '@univerjs/preset-sheets-drawing'
import sheetsDrawingZhCN from '@univerjs/preset-sheets-drawing/locales/zh-CN'
import { UniverSheetsHyperLinkPreset } from '@univerjs/preset-sheets-hyper-link'
import sheetsHyperLinkZhCN from '@univerjs/preset-sheets-hyper-link/locales/zh-CN'
import sheetsCoreZhCN from '@univerjs/preset-sheets-core/locales/zh-CN'
import { createUniver, LocaleType, mergeLocales } from '@univerjs/presets'
import type { IWorkbookData } from '@univerjs/presets'
import { handleXlsx, handleXls, handleCsv } from './utils'
import '@univerjs/preset-sheets-core/lib/index.css'
interface IProps {
requestUrl: string
height?: string | number
getPreviewFile: (url: string) => Promise<any>
fileType: 'xlsx' | 'xls' | 'csv'
}
const ExcelPreview: React.FC<IProps> = ({ requestUrl, getPreviewFile, fileType, height }) => {
const [loading, setLoading] = useState(false)
const [excelData, setExcelData] = useState<IWorkbookData>()
const instanceRef = useRef<any>(null)
useEffect(() => {
setLoading(true)
getPreviewFile(requestUrl)
.then(async response => {
if (!response) {
setLoading(false)
return
}
if (fileType === 'xlsx') {
const xlsx = await response.arrayBuffer()
const workbookData = await handleXlsx(xlsx)
setExcelData(workbookData)
} else if (fileType === 'xls') {
const xls = await response.arrayBuffer()
const workbookData = await handleXls(xls)
setExcelData(workbookData)
} else {
const csv = await response.blob()
const workbookData = await handleCsv(csv)
setExcelData(workbookData)
}
setLoading(false)
})
.catch(error => {
// eslint-disable-next-line no-console
console.log(error)
setLoading(false)
})
}, [getPreviewFile, fileType, requestUrl])
useEffect(() => {
if (!excelData) return
instanceRef.current.createWorkbook(excelData)
}, [excelData])
useEffect(() => {
const { univerAPI } = createUniver({
locale: LocaleType.ZH_CN,
locales: {
[LocaleType.ZH_CN]: mergeLocales(sheetsCoreZhCN, sheetsHyperLinkZhCN, sheetsDrawingZhCN),
},
presets: [
UniverSheetsCorePreset({
container: 'excel-preview-container-univer',
toolbar: false,
contextMenu: false,
formulaBar: false,
footer: true,
editable: false,
selectionMode: 'text',
}),
UniverSheetsDrawingPreset(),
UniverSheetsHyperLinkPreset(),
],
})
instanceRef.current = univerAPI
return () => {
if (instanceRef.current) {
instanceRef.current.dispose()
instanceRef.current = null
}
}
}, [])
return (
<>
<Spin size="large" spinning={loading}>
<div style={{ width: '100%', height: height || '100%', userSelect: 'text' }} id="excel-preview-container-univer" />
</Spin>
</>
)
}
export default ExcelPreview
utils.ts
typescript
import { IWorkbookData, IWorksheetData, ICellData } from '@univerjs/presets'
import * as XLSX from 'xlsx'
import LuckyExcel from '@zwight/luckyexcel'
import { v4 as uuidv4 } from 'uuid'
const DEFAULT_ROW_COUNT = 1000
const DEFAULT_COLUMN_COUNT = 20
const DEFAULT_COLUMN_WIDTH = 73
const DEFAULT_ROW_HEIGHT = 19
/**
* 生成基础 WorkbookData
*/
function createWorkbookData(sheets: IWorksheetData[]): IWorkbookData {
const sheetOrder = sheets.map(s => s.id)
const sheetsMap: { [sheetId: string]: Partial<IWorksheetData> } = {}
sheets.forEach(s => {
sheetsMap[s.id] = s
})
return {
id: uuidv4(),
name: 'Workbook',
appVersion: '1.0.0',
// locale: 'en-US',
styles: {},
sheetOrder,
sheets: sheetsMap,
// 资源(图片/样式等)。此处先空数组,避免渲染期望字段缺失
resources: [],
defaultStyle: null,
}
}
/**
* 将二维数组转换成 IWorksheetData 的 cellData 结构(行、列均为数字索引)
*/
function arrayToCellData(data: any[][]): { [row: number]: { [col: number]: ICellData } } {
const cellData: { [row: number]: { [col: number]: ICellData } } = {}
data.forEach((row, rowIndex) => {
if (!cellData[rowIndex]) cellData[rowIndex] = {}
row.forEach((value, colIndex) => {
// 仅在有值时填充 cell,避免生成庞大的稀疏表
if (value !== undefined && value !== null && value !== '') {
const cell: ICellData = { v: value }
// 简单类型标记(可选)
if (typeof value === 'number') {
;(cell as any).t = 2 // number
} else if (typeof value === 'boolean') {
;(cell as any).t = 3 // boolean
} else {
;(cell as any).t = 1 // string / others
}
cellData[rowIndex][colIndex] = cell
}
})
})
return cellData
}
/**
* 计算二维数组的行列数(含默认兜底)
*/
function computeDimensions(rows: any[][]): { rowCount: number; columnCount: number } {
const rowCount = Math.max(DEFAULT_ROW_COUNT, rows.length)
const columnCount = Math.max(
DEFAULT_COLUMN_COUNT,
rows.reduce((max, row) => Math.max(max, row.length), 0),
)
return { rowCount, columnCount }
}
/**
* 从二维数组构建 IWorksheetData
*/
function buildSheetFrom2DArray(name: string, rows: any[][]): IWorksheetData {
const { rowCount, columnCount } = computeDimensions(rows)
return {
id: uuidv4(),
name,
rowCount,
columnCount,
defaultColumnWidth: DEFAULT_COLUMN_WIDTH,
defaultRowHeight: DEFAULT_ROW_HEIGHT,
zoomRatio: 1,
scrollTop: 0,
scrollLeft: 0,
hidden: 0,
tabColor: '',
drawings: {},
drawingsOrder: [],
cellData: arrayToCellData(rows),
} as unknown as IWorksheetData
}
/**
* 将 XLSX 解析结果转换为 sheets(所有 sheet 使用 header:1 的二维数组)
*/
function buildSheetsFromXlsxWorkbook(xlsxWorkbook: XLSX.WorkBook): IWorksheetData[] {
return xlsxWorkbook.SheetNames.map(sheetName => {
const rows = XLSX.utils.sheet_to_json<any[]>(xlsxWorkbook.Sheets[sheetName], { header: 1 })
return buildSheetFrom2DArray(sheetName, rows)
})
}
/**
* 仅使用 xlsx 解析(值级别)并返回完整 IWorkbookData
*/
function parseXlsxArrayBufferToWorkbook(buffer: ArrayBuffer): IWorkbookData {
const xlsxWorkbook = XLSX.read(buffer, { type: 'array' })
const sheets: IWorksheetData[] = buildSheetsFromXlsxWorkbook(xlsxWorkbook)
return createWorkbookData(sheets)
}
/**
* 处理 XLSX 文件
*/
export const handleXlsx = async (buffer: ArrayBuffer): Promise<IWorkbookData> => {
function ensureSheetDefaults(sheet: any): IWorksheetData {
const s: any = { ...sheet }
// 计算行列数(若缺失)
if ((s.rowCount == null || s.columnCount == null) && s.cellData) {
const rowIndices = Object.keys(s.cellData)
.map(k => Number(k))
.filter(n => !Number.isNaN(n))
const maxRow = rowIndices.length > 0 ? Math.max(...rowIndices) : -1
let maxCol = -1
rowIndices.forEach(r => {
const cols = s.cellData[r]
if (!cols) return
const colIndices = Object.keys(cols)
.map(k => Number(k))
.filter(n => !Number.isNaN(n))
if (colIndices.length > 0) maxCol = Math.max(maxCol, Math.max(...colIndices))
})
if (s.rowCount == null) s.rowCount = Math.max(DEFAULT_ROW_COUNT, maxRow + 1)
if (s.columnCount == null) s.columnCount = Math.max(DEFAULT_COLUMN_COUNT, maxCol + 1)
}
if (s.rowCount == null) s.rowCount = DEFAULT_ROW_COUNT
if (s.columnCount == null) s.columnCount = DEFAULT_COLUMN_COUNT
if (s.defaultColumnWidth == null) s.defaultColumnWidth = DEFAULT_COLUMN_WIDTH
if (s.defaultRowHeight == null) s.defaultRowHeight = DEFAULT_ROW_HEIGHT
if (s.zoomRatio == null) s.zoomRatio = 1
if (s.scrollTop == null) s.scrollTop = 0
if (s.scrollLeft == null) s.scrollLeft = 0
if (s.hidden == null) s.hidden = 0
if (s.tabColor == null) s.tabColor = ''
if (s.drawings == null) s.drawings = {}
if (s.drawingsOrder == null) s.drawingsOrder = []
return s as IWorksheetData
}
function normalizeExportJsonToWorkbook(exportJson: any): IWorkbookData {
if (!exportJson) throw new Error('Invalid exportJson')
const wb: any = { ...exportJson }
if (!wb.id) wb.id = uuidv4()
if (!wb.name) wb.name = 'Workbook'
if (!wb.styles) wb.styles = {}
if (!wb.resources) wb.resources = []
if (Array.isArray(wb.sheets)) {
const arr = wb.sheets
const sheetOrder: string[] = []
const map: Record<string, any> = {}
arr.forEach((s: any) => {
const id = s.id || uuidv4()
sheetOrder.push(id)
map[id] = ensureSheetDefaults({ ...s, id })
})
wb.sheets = map
if (!wb.sheetOrder) wb.sheetOrder = sheetOrder
} else if (wb.sheets && typeof wb.sheets === 'object') {
if (!wb.sheetOrder) wb.sheetOrder = Object.keys(wb.sheets)
Object.keys(wb.sheets).forEach((id: string) => {
wb.sheets[id] = ensureSheetDefaults({ id, ...wb.sheets[id] })
})
} else {
throw new Error('exportJson.sheets missing')
}
return wb as IWorkbookData
}
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
})
const file = new File([blob], 'import.xlsx', { type: blob.type })
return new Promise<IWorkbookData>((resolve, reject) => {
LuckyExcel.transformExcelToUniver(
file,
(exportJson: any) => {
try {
const wb = normalizeExportJsonToWorkbook(exportJson)
resolve(wb)
} catch (err) {
// 解析结果异常时,回退到 xlsx 仅值解析
try {
resolve(parseXlsxArrayBufferToWorkbook(buffer))
} catch (fallbackErr) {
reject(fallbackErr)
}
}
},
(error: any) => {
// 插件报错时,回退到 xlsx 仅值解析
try {
resolve(parseXlsxArrayBufferToWorkbook(buffer))
} catch (e) {
reject(error || e)
}
},
)
})
}
/**
* 处理 XLS 文件
*/
export function handleXls(buffer: ArrayBuffer): IWorkbookData {
const xlsWorkbook = XLSX.read(buffer, { type: 'array' })
const sheets: IWorksheetData[] = buildSheetsFromXlsxWorkbook(xlsWorkbook)
return createWorkbookData(sheets)
}
/**
* 处理 CSV 文件
*/
export async function handleCsv(blob: Blob): Promise<IWorkbookData> {
const text = await blob.text()
const rows = text.split(/\r?\n/).map(r => r.split(','))
const sheet: IWorksheetData = buildSheetFrom2DArray('Sheet1', rows)
return createWorkbookData([sheet])
}