Procházet zdrojové kódy

新增基于exceljs的导入方法

cfort před 1 rokem
rodič
revize
83bd44c5bf
1 změnil soubory, kde provedl 135 přidání a 0 odebrání
  1. 135 0
      src/plugins/excel/index.js

+ 135 - 0
src/plugins/excel/index.js

@@ -0,0 +1,135 @@
+import papa from 'papaparse'
+import ExcelJS from 'exceljs'
+
+const ibpsExcel = {
+    // 导入 CSV(保持原逻辑不变)
+    csv (file) {
+        return new Promise((resolve, reject) => {
+            papa.parse(file, {
+                header: true,
+                skipEmptyLines: true,
+                complete: (results) => resolve(results),
+                error: (err) => reject(err)
+            })
+        })
+    },
+
+    // 导入 Excel(支持图片)
+    async xlsx (file, options = { raw: false }) {
+        const reader = new FileReader()
+        return new Promise((resolve, reject) => {
+            reader.onload = async (e) => {
+                try {
+                    const buffer = new Uint8Array(e.target.result)
+                    const workbook = new ExcelJS.Workbook()
+                    await workbook.xlsx.load(buffer)
+
+                    const worksheet = workbook.worksheets[0]
+                    const { header, imagesMap } = this.processSheetMeta(workbook, worksheet)
+                    const results = this.processSheetData(worksheet, header, imagesMap, options)
+                    resolve({ header, results })
+                } catch (error) {
+                    reject(error)
+                }
+            }
+            reader.readAsArrayBuffer(file)
+        })
+    },
+
+    // 处理工作表元数据(表头+图片)
+    processSheetMeta (workbook, worksheet) {
+    // 处理表头
+        const header = []
+        worksheet.getRow(1).eachCell({ includeEmpty: true }, (cell, colNumber) => {
+            header[colNumber - 1] = cell.text?.trim() || `列${colNumber}`
+        })
+
+        // 处理图片映射
+        const imagesMap = new Map()
+        worksheet.getImages().forEach((img, index) => {
+            const { tl } = img.range
+            const image = workbook.getImage(img.imageId)
+            // console.log(img, image)
+
+            // 检查图片数据是否存在
+            if (!image || !image.buffer) {
+                console.warn(`图片数据不存在或未正确加载,图片ID: ${img.imageId}`)
+                return
+            }
+
+            // 只处理数据行(行号 >= 2)
+            const rowIndex = Math.floor(tl.row) - 1 // 转换为结果数组索引
+            if (rowIndex < 0) return
+
+            // 生成唯一键:行索引_列索引_图片索引(避免 imageId 重复)
+            const colIndex = Math.floor(tl.col)
+            const mapKey = `${rowIndex}_${colIndex}_${index}`
+
+            // 转换图片为 base64
+            const base64 = this.arrayBufferToBase64(image.buffer)
+            const imageData = {
+                name: image.name,
+                type: image.type,
+                ext: image.extension,
+                dimensions: image.size,
+                data: `data:${this.getMimeType(image)};base64,${base64}`
+            }
+
+            imagesMap.set(mapKey, imageData)
+        })
+
+        return { header, imagesMap }
+    },
+
+    // 处理工作表数据
+    processSheetData (worksheet, header, imagesMap, options) {
+        const results = []
+        worksheet.eachRow((row, rowNumber) => {
+            if (rowNumber === 1) return // 跳过表头
+
+            const rowData = { _images: {}}
+
+            // 遍历所有列,确保每列都有属性值
+            header.forEach((colName, colIndex) => {
+                const cell = row.getCell(colIndex + 1) // 列索引从 1 开始
+                const key = colName
+
+                // 处理单元格值
+                rowData[key] = options.raw ? cell.value : cell.text || '' // 为空时赋默认值
+
+                // 处理关联图片
+                const mapKeyPrefix = `${rowNumber - 2}_${colIndex}`
+                for (const [mapKey, imageData] of imagesMap.entries()) {
+                    if (mapKey.startsWith(mapKeyPrefix)) {
+                        rowData._images[key] = imageData
+                    }
+                }
+            })
+
+            results.push(rowData)
+        })
+        return results
+    },
+
+    // ArrayBuffer 转 Base64
+    arrayBufferToBase64 (buffer) {
+        let binary = ''
+        new Uint8Array(buffer).forEach(byte => {
+            binary += String.fromCharCode(byte)
+        })
+        return btoa(binary)
+    },
+
+    // 获取图片 MIME 类型
+    getMimeType (image) {
+        const types = {
+            png: 'image/png',
+            jpeg: 'image/jpeg',
+            gif: 'image/gif',
+            bmp: 'image/bmp'
+        }
+        return types[image.extension] || 'application/octet-stream'
+    }
+}
+
+export default ibpsExcel