index.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import papa from 'papaparse'
  2. import ExcelJS from 'exceljs'
  3. const ibpsExcel = {
  4. // 导入 CSV(保持原逻辑不变)
  5. csv (file) {
  6. return new Promise((resolve, reject) => {
  7. papa.parse(file, {
  8. header: true,
  9. skipEmptyLines: true,
  10. complete: (results) => resolve(results),
  11. error: (err) => reject(err)
  12. })
  13. })
  14. },
  15. // 导入 Excel(支持图片)
  16. async xlsx (file, options = { raw: false }) {
  17. const reader = new FileReader()
  18. return new Promise((resolve, reject) => {
  19. reader.onload = async (e) => {
  20. try {
  21. const buffer = new Uint8Array(e.target.result)
  22. const workbook = new ExcelJS.Workbook()
  23. await workbook.xlsx.load(buffer)
  24. const worksheet = workbook.worksheets[0]
  25. const { header, imagesMap } = this.processSheetMeta(workbook, worksheet)
  26. const results = this.processSheetData(worksheet, header, imagesMap, options)
  27. resolve({ header, results })
  28. } catch (error) {
  29. reject(error)
  30. }
  31. }
  32. reader.readAsArrayBuffer(file)
  33. })
  34. },
  35. // 处理工作表元数据(表头+图片)
  36. processSheetMeta (workbook, worksheet) {
  37. // 处理表头
  38. const header = []
  39. worksheet.getRow(1).eachCell({ includeEmpty: true }, (cell, colNumber) => {
  40. header[colNumber - 1] = cell.text?.trim() || `列${colNumber}`
  41. })
  42. // 处理图片映射
  43. const imagesMap = new Map()
  44. worksheet.getImages().forEach((img, index) => {
  45. const { tl } = img.range
  46. const image = workbook.getImage(img.imageId)
  47. // console.log(img, image)
  48. // 检查图片数据是否存在
  49. if (!image || !image.buffer) {
  50. console.warn(`图片数据不存在或未正确加载,图片ID: ${img.imageId}`)
  51. return
  52. }
  53. // 只处理数据行(行号 >= 2)
  54. const rowIndex = Math.floor(tl.row) - 1 // 转换为结果数组索引
  55. if (rowIndex < 0) return
  56. // 生成唯一键:行索引_列索引_图片索引(避免 imageId 重复)
  57. const colIndex = Math.floor(tl.col)
  58. const mapKey = `${rowIndex}_${colIndex}_${index}`
  59. // 转换图片为 base64
  60. const base64 = this.arrayBufferToBase64(image.buffer)
  61. const imageData = {
  62. name: image.name,
  63. type: image.type,
  64. ext: image.extension,
  65. dimensions: image.size,
  66. data: `data:${this.getMimeType(image)};base64,${base64}`
  67. }
  68. imagesMap.set(mapKey, imageData)
  69. })
  70. return { header, imagesMap }
  71. },
  72. // 处理工作表数据
  73. processSheetData (worksheet, header, imagesMap, options) {
  74. const results = []
  75. worksheet.eachRow((row, rowNumber) => {
  76. if (rowNumber === 1) return // 跳过表头
  77. const rowData = { _images: {}}
  78. // 遍历所有列,确保每列都有属性值
  79. header.forEach((colName, colIndex) => {
  80. const cell = row.getCell(colIndex + 1) // 列索引从 1 开始
  81. const key = colName
  82. // 处理单元格值
  83. rowData[key] = options.raw ? cell.value : cell.text || '' // 为空时赋默认值
  84. // 处理关联图片
  85. const mapKeyPrefix = `${rowNumber - 2}_${colIndex}`
  86. for (const [mapKey, imageData] of imagesMap.entries()) {
  87. if (mapKey.startsWith(mapKeyPrefix)) {
  88. rowData._images[key] = imageData
  89. }
  90. }
  91. })
  92. results.push(rowData)
  93. })
  94. return results
  95. },
  96. // ArrayBuffer 转 Base64
  97. arrayBufferToBase64 (buffer) {
  98. let binary = ''
  99. new Uint8Array(buffer).forEach(byte => {
  100. binary += String.fromCharCode(byte)
  101. })
  102. return btoa(binary)
  103. },
  104. // 获取图片 MIME 类型
  105. getMimeType (image) {
  106. const types = {
  107. png: 'image/png',
  108. jpeg: 'image/jpeg',
  109. gif: 'image/gif',
  110. bmp: 'image/bmp'
  111. }
  112. return types[image.extension] || 'application/octet-stream'
  113. }
  114. }
  115. export default ibpsExcel