Tạo và tải xuống tệp Excel với Koa

Mã phía máy chủ

> pnpm add -w exceljs

async downloadExcel(ctx) {
    const category = ctx.request.body.categoryId || 'user';

    const workbook = new ExcelJs.Workbook();
    workbook.creator = 'ABC';
    workbook.lastModifiedBy = 'ABC';
    workbook.created = new Date();
    workbook.modified = new Date();
    workbook.lastPrinted = new Date();

    const sheet = workbook.addWorksheet('Dữ liệu', { properties: { tabColor: { argb: 'FFC0CB' } } });

    sheet.columns = this._getColumnDefinitions(category);
    const filePath = `./${category}.xlsx`;
    try {
      await workbook.xlsx.writeFile(filePath);
    } catch (err) {
      return this.sendResponse(ctx, null, { message: 'Tạo mẫu thất bại' });
    }
    ctx.set(`Content-Disposition`, `attachment; filename=${category}.xlsx`);
    ctx.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    ctx.body = fs.createReadStream(filePath);
}

_getColumnDefinitions(category) {
    switch (category) {
      case 'user':
        return [
          {
            header: 'Mã số',
            key: 'userId',
            width: 15
          },
          {
            header: 'Email cá nhân',
            key: 'emailAddr',
            width: 35
          },
          {
            header: 'Số điện thoại',
            key: 'phoneNum',
            width: 15
          },
          {
            header: 'Tên',
            key: 'firstName',
            width: 15
          },
          {
            header: 'Họ',
            key: 'lastName',
            width: 15
          },
          {
            header: 'Tuổi',
            key: 'age',
            width: 10
          },
          {
            header: 'Địa chỉ',
            key: 'address',
            width: 40
          },
          {
            header: 'Trường học',
            key: 'schoolName',
            width: 25
          },
          {
            header: 'Lớp',
            key: 'classLevel',
            width: 10
          },
          {
            header: 'Cấp độ',
            key: 'level',
            width: 10
          },
          {
            header: 'Điểm thưởng',
            key: 'points',
            width: 10
          },
          {
            header: 'Ảnh đại diện',
            key: 'avatarUrl',
            width: 20
          },
          {
            header: 'Chức danh',
            key: 'title',
            width: 20
          },
        ];
      default:
        return [];
    }
}
    

Mã phía máy khách


<!DOCTYPE html>
<html lang="vi">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Ứng dụng thử nghiệm</title>
  </head>
  <body>
    <script src="./node_modules/axios/dist/axios.min.js"></script>
    <script>
      axios.get('api/excel-download', { responseType: 'arraybuffer' })
          .then((response) => {
            const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
            const url = window.URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = url;
            link.download = 'danh_sach.xlsx';
            document.body.appendChild(link);
            link.click();
            window.URL.revokeObjectURL(url);
          })
          .catch((error) => {
            console.error(error);
          });
    </script>
  </body>
</html>
    

Các vấn đề phát sinh

- Sai định dạng khi tải về, cần kiểm tra `type` là `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`. - Đọc file không đúng cách có thể dẫn đến việc không mở được file. Sử dụng `axios` với `responseType: 'arraybuffer'` để đảm bảo đọc chính xác. - Các hộp chọn không hỗ trợ kiểu key-value trực tiếp, nên nếu muốn xác thực giá trị phải thêm các bộ kiểm tra riêng lẻ trong vòng lặp.

Thẻ: Koa ExcelJS Axios blob nodejs

Đăng vào ngày 5 tháng 7 lúc 08:26