Loading backend/src/pointOfInterest/PointOfInterest.service.ts +126 −1 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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> `; } } Loading
backend/src/pointOfInterest/PointOfInterest.service.ts +126 −1 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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> `; } }