JS实现导入Excel表格(包括表格中图片)

855 阅读1分钟

安装依赖

npm i exceljs

实现

import ExcelJS from 'exceljs';

// 触发导入文件
const { ctx }: any = getCurrentInstance();
const importFile = () => {
  ctx.$refs.inputFile.click();
};


//获取导入文件
const getFiles = async () => {
  const file = ctx.$refs.inputFile?.files?.[0];
  if (!file) {
    proxy.$ShowELmessage(proxy, '未选择文件', 'warning');
    return;
  }

  try {
    // 使用 ExcelJS 读取文件
    const workbook = new ExcelJS.Workbook();
    await workbook.xlsx.load(file);

    // 获取第一个工作表
    const sheet = workbook.getWorksheet(1);
    if (!sheet) {
      proxy.$ShowELmessage(proxy, '未找到工作表', 'error');
      return;
    }

    const imageMaps: { [key: number]: string } = {};
    const uploadImagePromises: Promise<void>[] = [];

    // 获取所有图片信息并异步上传图片
    sheet.getImages().forEach(image => {
      const { range, imageId } = image;
      if (range?.tl) {
        const rowNumber = range.tl.nativeRow + 1;
        const imageBuffer = workbook.getImage(Number(imageId)).buffer as Uint8Array;

        const formData = new FormData();
        const file = uint8ArrayToFile(imageBuffer, 'image.png', 'image/png');
        formData.append('file', file);

        // 异步上传图片
        const uploadPromise = uploadFile(formData).then(res => {
          if (res.errcode === 0) {
            imageMaps[rowNumber] = res.p2pdata;
          } else {
            proxy.$ShowELmessage(proxy, `上传第${rowNumber}行图片失败`, 'error');
          }
        });

        uploadImagePromises.push(uploadPromise);
      }
    });

    // 等待所有图片上传完成
    await Promise.all(uploadImagePromises);

    // 读取表格内容并处理数据
    const tableData: PurchaseDetail[] = [];
    sheet.eachRow((row, rowIndex) => {
      if (rowIndex > 1) { // 假设第一行为表头
        tableData.push({
          parameterText: row.getCell(4).value?.toString() || '',
          parameterImg: imageMaps[rowIndex] || '',
        });
      }
    });
    console.log(tableData);
  } catch (error: any) {
    proxy.$ShowELmessage(proxy, `处理文件时出错: ${error.message}`, 'error');
  } finally {
    // 清空文件输入框的值,确保每次选择同一个文件时都能触发 @change 事件
    ctx.$refs.inputFile.value = '';
  }
};


// 辅助函数:将uint8Array转换为File
const uint8ArrayToFile = (uint8Array: Uint8Array, fileName: string, type: string) => {
  // 创建一个 Blob 对象
  const blob = new Blob([uint8Array], { type });

  // 使用 Blob 对象构造一个 File 对象
  const file = new File([blob], fileName || 'file', { type });

  return file;
}