|
|
@@ -1,190 +0,0 @@
|
|
|
-import ExcelJS from 'exceljs'
|
|
|
-
|
|
|
-/* 导出的参数 */
|
|
|
-export interface IExcel {
|
|
|
- // 文件名称
|
|
|
- fileName?: string
|
|
|
- // 表头数据
|
|
|
- rows: Array<Array<string | number>>
|
|
|
- // 表格数据
|
|
|
- data: Array<Array<any>>
|
|
|
- // 表格列宽
|
|
|
- width?: Array<number>
|
|
|
- // 需要合并的表格
|
|
|
- merge?: Array<any>
|
|
|
-}
|
|
|
-
|
|
|
-export const useExcel = () => {
|
|
|
- /**
|
|
|
- * 导入excel
|
|
|
- * @param file 传入文件
|
|
|
- * @param fileMaxSize number 最大文件大小 单位 MB
|
|
|
- */
|
|
|
- const importExcel = (file: File, fileMaxSize: number = 20) => {
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- if (
|
|
|
- !['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'].includes(
|
|
|
- file.type
|
|
|
- )
|
|
|
- ) {
|
|
|
- reject(new Error('只能选择 excel 文件'))
|
|
|
- return
|
|
|
- }
|
|
|
- if (file.size / 1024 / 1024 > fileMaxSize) {
|
|
|
- reject(new Error('大小不能超过 20MB'))
|
|
|
- return
|
|
|
- }
|
|
|
- const reader = new FileReader()
|
|
|
- reader.onload = e => {
|
|
|
- const workbook = new ExcelJS.Workbook()
|
|
|
- workbook.xlsx.load(e.target?.result as any).then(() => {
|
|
|
- const title: string[] = []
|
|
|
- const list: Record<string, any>[] = []
|
|
|
- workbook.eachSheet(sheet => {
|
|
|
- list.splice(0, list.length)
|
|
|
- sheet.eachRow({ includeEmpty: true }, row => {
|
|
|
- title.splice(0, title.length)
|
|
|
- const item: Record<string, any> = {}
|
|
|
- row.eachCell({ includeEmpty: true }, cell => {
|
|
|
- const key = cell.address.slice(0, -String(cell.row).length)
|
|
|
- title.push(key)
|
|
|
- const isMerged = cell.isMerged && cell.address !== cell.master.address
|
|
|
- item[key] = {
|
|
|
- value: cell.value,
|
|
|
- colspan: isMerged ? 0 : 1,
|
|
|
- rowspan: isMerged ? 0 : 1
|
|
|
- }
|
|
|
- })
|
|
|
- list.push(item)
|
|
|
- })
|
|
|
- // 生成表格的跨行跨列
|
|
|
- sheet.eachRow({ includeEmpty: true }, row => {
|
|
|
- row.eachCell({ includeEmpty: true }, cell => {
|
|
|
- const master = cell.master
|
|
|
- if (cell.isMerged && cell.address !== master.address) {
|
|
|
- const mk = master.address.slice(0, -String(master.row).length)
|
|
|
- const mItem = list[Number(master.row) - 1][mk]
|
|
|
- const rs = Math.abs(Number(cell.row) - Number(master.row)) + 1
|
|
|
- rs > mItem.rowspan && (mItem.rowspan = rs)
|
|
|
- const cs = Math.abs(Number(cell.col) - Number(master.col)) + 1
|
|
|
- cs > mItem.colspan && (mItem.colspan = cs)
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
- })
|
|
|
- resolve({ title, list })
|
|
|
- })
|
|
|
- }
|
|
|
- reader.readAsArrayBuffer(file)
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 导出excel
|
|
|
- */
|
|
|
- const exportExcel = (options: IExcel) => {
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- options = Object.assign(
|
|
|
- {
|
|
|
- fileName: options.fileName || Date.now()
|
|
|
- },
|
|
|
- options
|
|
|
- )
|
|
|
- const workbook = new ExcelJS.Workbook()
|
|
|
- const sheet = workbook.addWorksheet('Sheet1')
|
|
|
- if (!(Array.isArray(options.rows) && Array.isArray(options.rows[0]))) {
|
|
|
- reject(new Error('表头数据必须为二维数组'))
|
|
|
- return
|
|
|
- }
|
|
|
- if (!Array.isArray(options.data)) {
|
|
|
- reject(new Error('表格数据必须为数组'))
|
|
|
- return
|
|
|
- }
|
|
|
- // 设置表格宽度
|
|
|
- const widths =
|
|
|
- Array.isArray(options.width) && options.width.length
|
|
|
- ? options.width
|
|
|
- : Array.from(Array(options.rows[0].length).keys()).map(() => 16)
|
|
|
-
|
|
|
- // 设置表头
|
|
|
- options.rows.forEach(row => {
|
|
|
- sheet.addRow(row)
|
|
|
- })
|
|
|
-
|
|
|
- // 设置列宽
|
|
|
- options.data.forEach(item => {
|
|
|
- sheet.addRow(item)
|
|
|
- })
|
|
|
-
|
|
|
- // 设置列宽
|
|
|
- widths.forEach((width, index) => {
|
|
|
- sheet.getColumn(index + 1).width = width
|
|
|
- })
|
|
|
-
|
|
|
- // 设置样式
|
|
|
- sheet.eachRow({ includeEmpty: true }, (row, rowIndex) => {
|
|
|
- row.height = 20
|
|
|
- row.eachCell({ includeEmpty: true }, cell => {
|
|
|
- cell.border = {
|
|
|
- top: { style: 'thin' },
|
|
|
- left: { style: 'thin' },
|
|
|
- bottom: { style: 'thin' },
|
|
|
- right: { style: 'thin' }
|
|
|
- }
|
|
|
- cell.alignment = {
|
|
|
- vertical: 'middle',
|
|
|
- horizontal: 'center'
|
|
|
- }
|
|
|
- cell.font = { size: 12, bold: rowIndex < options.rows.length }
|
|
|
- })
|
|
|
- })
|
|
|
-
|
|
|
- // 合并单元格
|
|
|
- if (Array.isArray(options.merge)) {
|
|
|
- options.merge.forEach(item => {
|
|
|
- sheet.mergeCells(item)
|
|
|
- })
|
|
|
- }
|
|
|
- // 下载文件
|
|
|
- workbook.xlsx.writeBuffer().then(data => {
|
|
|
- download(data, `${options.fileName}.xlsx`)
|
|
|
- })
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- /* 转为二维数组 */
|
|
|
- const toTwoArray = (list: Record<string, any>[]) => {
|
|
|
- const arr: Array<Array<string | number | null | undefined>> = []
|
|
|
- list.forEach((item: any) => {
|
|
|
- const brr = Object.values(item).map((ite: any) => ite.value)
|
|
|
- arr.push(brr)
|
|
|
- })
|
|
|
- return arr
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 下载文件
|
|
|
- * @param data 二进制数据,如果传入是http地址,则直接下载
|
|
|
- * @param name 文件名
|
|
|
- * @param type 文件类型
|
|
|
- */
|
|
|
- const download = (data: Blob | ArrayBuffer | string, name: string, type?: string) => {
|
|
|
- let url = ''
|
|
|
- if (typeof data === 'string') {
|
|
|
- url = data
|
|
|
- } else {
|
|
|
- const blob = new Blob([data], { type: type || 'application/octet-stream' })
|
|
|
- url = window.URL.createObjectURL(blob)
|
|
|
- }
|
|
|
- const a = document.createElement('a')
|
|
|
- a.href = url
|
|
|
- a.download = name
|
|
|
- a.style.display = 'none'
|
|
|
- document.body.appendChild(a)
|
|
|
- a.click()
|
|
|
- document.body.removeChild(a)
|
|
|
- URL.revokeObjectURL(url)
|
|
|
- }
|
|
|
-
|
|
|
- return { importExcel, toTwoArray, exportExcel, download }
|
|
|
-}
|