Commit a97dcb67 authored by Lorenzo Trujillo Rojas's avatar Lorenzo Trujillo Rojas
Browse files

Merge branch 'main' into 'main'

Se agrega endpoint para generar el pdf.

See merge request ltrpro/pueblosmagicosconia!64
parents ab0c852f ed9c1320
Loading
Loading
Loading
Loading
+673 −68

File changed.

Preview size limit exceeded, changes collapsed.

+1 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
    "mysql2": "^3.9.2",
    "network": "^0.7.0",
    "nodemailer": "^6.9.15",
    "puppeteer": "^23.3.0",
    "qrcode": "^1.5.4",
    "reflect-metadata": "^0.2.0",
    "rxjs": "^7.8.1",
+18 −1
Original line number Diff line number Diff line
@@ -9,10 +9,11 @@ import {
  Query,
  StreamableFile,
  UseGuards,
  Res
} from '@nestjs/common';
import { PointOfInterestService } from './PointOfInterest.service';
import { CreatePointAndTradDto } from './dto/create-pointAndTraduction.dto';
import { ApiBearerAuth, ApiConsumes, ApiParam, ApiQuery, ApiTags } from '@nestjs/swagger';
import { ApiBearerAuth, ApiBody, ApiConsumes, ApiParam, ApiQuery, ApiTags } from '@nestjs/swagger';
import { Roles } from 'src/auth/role.decorator';
import { ADMIN_ROLES } from 'src/shared/enum/admin-role.enum';
import { fileInterceptor } from 'src/shared/interceptors/file-save.interceptor';
@@ -59,4 +60,20 @@ export class PointOfInterestController {
  async findOne(@Param('idPoint') idPoint: number, @Query('lang') lang: string) {
    return await this.pointService.findOne(idPoint, lang as LANGUAGES);
  }

  @ApiParam({ name: 'idPlace', type: Number })
  @ApiQuery({ name: 'pointsId', type: String })
  @Get('/place/:idPlace/point/generate')
  async generatePdf(@Param('idPlace') idPlace: number, @Query('pointsId') pointsIdString: string, @Res() res) {
    const pointsId = pointsIdString.split(',').map(Number);
    const pdfBuffer = await this.pointService.generatePdf(idPlace, pointsId);

    res.set({
      'Content-Type': 'application/pdf',
      'Content-Disposition': 'attachment; filename=tarjetas.pdf',
      'Content-Length': pdfBuffer.length,
    });

    res.send(pdfBuffer);
  }
}
+126 −1
Original line number Diff line number Diff line
@@ -10,10 +10,12 @@ import { CreatePointTradDto } from './dto/create-pointTrad.dto';
import { LANGUAGES } from 'src/shared/enum/languages.enum';
import { getPointDto } from './dto/getPoint.dto';
import { ServerConstants } from 'src/constants/server.contants';
import { createReadStream } from 'fs';
import { createReadStream, readFileSync } from 'fs';
import { join } from 'path';
import { generateQRCode } from './utils/qrcode';
import { Place } from 'src/place/entities/place.entity';
import puppeteer from 'puppeteer';
import { printPointInfo } from './dto/printPointInfo.dto';

@Injectable()
export class PointOfInterestService {
@@ -143,4 +145,127 @@ export class PointOfInterestService {
    };
    return point;
  }

  async findAllByIds(idPlace:number, pointsId: number[]): Promise<printPointInfo[]> {
    const place = await this.placeService.findOne(idPlace);
    if (!place) {
      throw new BadRequestException('Place not found');
    }
    let points: printPointInfo[] = await Promise.all(pointsId.map(async (idPoint)=>{
      let point = await this.dataSource
      .getRepository(PointOfInterest)
      .createQueryBuilder('point')
      .leftJoin('point.idPlace', 'place')
      .select([
        'point.idPoint as idPoint',
        'place.name as namePlace',
        'point.name as name',
      ])
      .where('place.idPlace = :idPlace', { idPlace })
      .andWhere('point.idPoint = :idPoint', {idPoint})
      .getRawOne();
      return point;
    }))
    return points;
  }

  async generatePdf(idPlace:number, pointsId: number[]): Promise<Buffer> {
    const points = await this.findAllByIds(idPlace, pointsId);
    const htmlContent = this.generateHtml(points);
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    
    await page.setContent(htmlContent);
    const pdfBuffer = await page.pdf({
      format: 'A4',
      margin: { top: '10mm', bottom: '10mm', left: '10mm', right: '10mm' }, // Márgenes
    });
  
    await browser.close();
  
    return Buffer.from(pdfBuffer);
  }

  private generateHtml(points: printPointInfo[]): string {
    let cardsHtml = '';

    for(const point of points) {
      const filePath = join(ServerConstants.ROOT_STATIC_PATH, 'qr', point.idPoint.toString() + '.png');
      
      cardsHtml += `
        <div class="card">
          <img class="background" src="data:image/jpeg;base64,${
            readFileSync('./src/pointOfInterest/utils/zac.jpeg').toString('base64')
          }"/>
          <div class="content">
            <h3>${point.namePlace}</h3>
            <p>${point.name}</p>
          </div>
          <img src="data:image/jpeg;base64,${
            readFileSync(filePath).toString('base64')
          }" class="qr-code"/>
        </div>
      `;
    }

    return `
      <!DOCTYPE html>
      <html>
      <head>
        <title>Tarjetas en PDF</title>
        <style>
          body {
            font-family: Arial, sans-serif;
          }
          .card {
            width: 16cm;
            height: 8cm;
            page-break-inside: avoid;
            position: relative;
          }

          .content{
            margin: 2cm;
          }

          .qr-code{
            width: 4cm;
            height: 4cm;
            position: absolute;
            right: 1.5cm;
            top: 0;
            bottom: 0;
            margin: auto 0;
            border: 3px solid black;
            border-radius: 8px;
          }

          .background {
            height: 100%;
            width: 100%;
            object-fit: contain;
            position: absolute;
            z-index: -1;
          }

          @page {
            size: A4;
            margin: 10mm;
          }
          .page {
            display: flex;
            flex-wrap: wrap;
            justify-content: space-between;
            height: calc(100vh - 20mm);
          }
        </style>
      </head>
      <body>
        <div class="page">
          ${cardsHtml}
        </div>
      </body>
      </html>
    `;
  }
}
+5 −0
Original line number Diff line number Diff line
export class printPointInfo {
  idPoint: number;
  namePlace: string;
  name: string;
}
 No newline at end of file
Loading