From 8a9295c309b10b813c2cc9e645e1a8ee3ea9591f Mon Sep 17 00:00:00 2001 From: Bastian Wagner Date: Fri, 13 Mar 2026 21:19:52 +0100 Subject: [PATCH] PDF Download --- api/package-lock.json | 102 ------- api/src/app.module.ts | 6 +- api/src/model/dto/key-handover.dto.ts | 2 +- api/src/modules/key/key.controller.ts | 50 +++- api/src/modules/key/key.module.ts | 4 +- api/src/modules/key/key.service.ts | 20 +- .../key-handover-pdf.service.ts | 250 ------------------ api/src/shared/pdf/minio/minio.service.ts | 30 --- api/src/shared/pdf/pdf.module.ts | 12 - .../storage/services/pdf/pdf.service.ts | 52 ++++ api/src/shared/storage/storage.module.ts | 13 + api/src/shared/storage/storage.service.ts | 11 + .../create-handover-pdf-dialog.component.ts | 1 - .../handover-dialog.component.ts | 23 +- client/src/app/shared/api.service.ts | 16 ++ client/src/assets/img/pdf.png | Bin 0 -> 573 bytes client/src/styles.scss | 13 + 17 files changed, 182 insertions(+), 423 deletions(-) delete mode 100644 api/src/shared/pdf/key-handover-pdf/key-handover-pdf.service.ts delete mode 100644 api/src/shared/pdf/minio/minio.service.ts delete mode 100644 api/src/shared/pdf/pdf.module.ts create mode 100644 api/src/shared/storage/services/pdf/pdf.service.ts create mode 100644 api/src/shared/storage/storage.module.ts create mode 100644 api/src/shared/storage/storage.service.ts create mode 100644 client/src/assets/img/pdf.png diff --git a/api/package-lock.json b/api/package-lock.json index 6cf53dc..7af98e6 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -186,24 +186,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@angular-devkit/schematics-cli/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@angular-devkit/schematics-cli/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -211,22 +193,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@angular-devkit/schematics-cli/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@angular-devkit/schematics-cli/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -282,24 +248,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@angular-devkit/schematics/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@angular-devkit/schematics/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -307,22 +255,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@angular-devkit/schematics/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@angular-devkit/schematics/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -3609,24 +3541,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@nestjs/schematics/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@nestjs/schematics/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -3634,22 +3548,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@nestjs/schematics/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@nestjs/schematics/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", diff --git a/api/src/app.module.ts b/api/src/app.module.ts index 73f718e..b3cbd8d 100644 --- a/api/src/app.module.ts +++ b/api/src/app.module.ts @@ -11,12 +11,10 @@ import { KeyModule } from './modules/key/key.module'; import { CustomerModule } from './modules/customer/customer.module'; import { CylinderModule } from './modules/cylinder/cylinder.module'; import { SystemModule } from './modules/system/system.module'; -import { CacheInterceptor, CacheModule } from '@nestjs/cache-manager'; -import { APP_INTERCEPTOR } from '@nestjs/core'; import { MailModule } from './modules/mail/mail.module'; import { LogModule } from './modules/log/log.module'; import { SseModule } from './modules/realtime/sse/sse.module'; -import { PdfModule } from './shared/pdf/pdf.module'; +import { StorageModule } from './shared/storage/storage.module'; @Module({ imports: [ @@ -36,7 +34,7 @@ import { PdfModule } from './shared/pdf/pdf.module'; MailModule, LogModule, SseModule, - PdfModule + StorageModule ], controllers: [AppController], providers: [ diff --git a/api/src/model/dto/key-handover.dto.ts b/api/src/model/dto/key-handover.dto.ts index 7361c40..ce48ce0 100644 --- a/api/src/model/dto/key-handover.dto.ts +++ b/api/src/model/dto/key-handover.dto.ts @@ -1,4 +1,4 @@ -export class KeyHandoverDto { +export class KeyHandoverPDFDataDto { handoverId!: string; handoverDate!: Date; place!: string; diff --git a/api/src/modules/key/key.controller.ts b/api/src/modules/key/key.controller.ts index 67250c5..3f2b2a9 100644 --- a/api/src/modules/key/key.controller.ts +++ b/api/src/modules/key/key.controller.ts @@ -16,14 +16,12 @@ import { KeyService } from './key.service'; import { AuthenticatedRequest } from 'src/model/interface/authenticated-request.interface'; import { AuthGuard } from 'src/core/guards/auth.guard'; import { Key } from 'src/model/entitites'; -import { interval, map, Observable } from 'rxjs'; -import { KeyHandoverPdfService } from 'src/shared/pdf/key-handover-pdf/key-handover-pdf.service'; -import { KeyHandoverDto } from 'src/model/dto/key-handover.dto'; +import { KeyHandoverPDFDataDto } from 'src/model/dto/key-handover.dto'; @Controller('key') export class KeyController { - constructor(private service: KeyService, private pdfService: KeyHandoverPdfService) {} + constructor(private service: KeyService) {} @UseGuards(AuthGuard) @Get() @@ -84,11 +82,45 @@ export class KeyController { } @Post('pdf') - async generatePdf(@Body() dto: KeyHandoverDto, @Res() res: Response) { - const pdfBuffer = await this.service.fetchPdf(dto); + async generatePdf(@Body() dto: KeyHandoverPDFDataDto, @Res() res: Response) { + const { pdf, response } = await this.service.createPdf(dto); - res.setHeader('Content-Type', 'application/pdf'); - res.setHeader('Content-Disposition', 'inline; filename="uebergabe.pdf"'); - res.send(pdfBuffer); + res.setHeader( + 'Content-Type', + response.headers['content-type'] ?? 'application/pdf', + ); + + if (response.headers['content-length']) { + res.setHeader('Content-Length', response.headers['content-length']); + } + + if (response.headers['content-disposition']) { + res.setHeader('Content-Disposition', response.headers['content-disposition']); + } else { + res.setHeader('Content-Disposition', `inline; filename="uebergabe.pdf"`); + } + + res.end(pdf); + } + + @Get(':id/handover/pdf') + async getHandoverPDF(@Param('id') id: string, @Res() res: Response) { + const { pdf, response } = await this.service.getPdf(id); + res.setHeader( + 'Content-Type', + response.headers['content-type'] ?? 'application/pdf', + ); + + if (response.headers['content-length']) { + res.setHeader('Content-Length', response.headers['content-length']); + } + + if (response.headers['content-disposition']) { + res.setHeader('Content-Disposition', response.headers['content-disposition']); + } else { + res.setHeader('Content-Disposition', `inline; filename="uebergabe.pdf"`); + } + + res.end(pdf); } } diff --git a/api/src/modules/key/key.module.ts b/api/src/modules/key/key.module.ts index f78b135..87c3115 100644 --- a/api/src/modules/key/key.module.ts +++ b/api/src/modules/key/key.module.ts @@ -7,12 +7,12 @@ import { SharedServiceModule } from 'src/shared/service/shared.service.module'; import { ConfigService } from '@nestjs/config'; import { MailModule } from '../mail/mail.module'; import { SseModule } from '../realtime/sse/sse.module'; -import { PdfModule } from 'src/shared/pdf/pdf.module'; import { HttpModule } from '@nestjs/axios'; +import { StorageModule } from 'src/shared/storage/storage.module'; @Module({ controllers: [KeyController], providers: [KeyService, ConfigService], - imports: [DatabaseModule, AuthModule, SharedServiceModule, MailModule, SseModule, PdfModule, HttpModule], + imports: [DatabaseModule, AuthModule, SharedServiceModule, MailModule, SseModule, HttpModule, StorageModule], }) export class KeyModule {} diff --git a/api/src/modules/key/key.service.ts b/api/src/modules/key/key.service.ts index 760edfc..bafe55a 100644 --- a/api/src/modules/key/key.service.ts +++ b/api/src/modules/key/key.service.ts @@ -12,9 +12,11 @@ import { FindOperator, IsNull, Not } from 'typeorm'; import { ConfigService } from '@nestjs/config'; import { MailService } from '../mail/mail.service'; import { SseService } from '../realtime/sse/sse.service'; -import { KeyHandoverDto } from 'src/model/dto/key-handover.dto'; +import { KeyHandoverPDFDataDto } from 'src/model/dto/key-handover.dto'; import { firstValueFrom } from 'rxjs'; import { HttpService } from '@nestjs/axios'; +import { PdfService } from 'src/shared/storage/services/pdf/pdf.service'; +import { AxiosResponse } from 'axios'; @Injectable() export class KeyService { @@ -27,7 +29,8 @@ export class KeyService { private readonly configService: ConfigService, private readonly mailService: MailService, private readonly sseService: SseService, - private readonly httpService: HttpService + private readonly httpService: HttpService, + private readonly pdfService: PdfService ) { console.log("INIT KEYSERVICE") } @@ -234,13 +237,12 @@ export class KeyService { return k; } - async fetchPdf(dto: KeyHandoverDto): Promise { - const response = await firstValueFrom( - this.httpService.post('http://192.168.30.101:3500/pdf/keyhandover',dto, { - responseType: 'arraybuffer', - }), - ); + async createPdf(dto: KeyHandoverPDFDataDto): Promise<{ pdf: Buffer, response: AxiosResponse}> { + const x = await this.pdfService.generatePDF(dto) + return x; + } - return Buffer.from(response.data); + async getPdf(handoverId: string): Promise<{ pdf: Buffer, response: AxiosResponse}> { + return this.pdfService.getPDFByHandoverKey(handoverId); } } diff --git a/api/src/shared/pdf/key-handover-pdf/key-handover-pdf.service.ts b/api/src/shared/pdf/key-handover-pdf/key-handover-pdf.service.ts deleted file mode 100644 index 36e7351..0000000 --- a/api/src/shared/pdf/key-handover-pdf/key-handover-pdf.service.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { KeyHandoverDto } from 'src/model/dto/key-handover.dto'; -import * as puppeteer from 'puppeteer'; -import { MinioService } from '../minio/minio.service'; -import { KeyHandoutRepository } from 'src/model/repositories/key-handout.repository'; -import { KeyHandout } from 'src/model/entitites'; -import { ConfigService } from '@nestjs/config'; - -@Injectable() -export class KeyHandoverPdfService { - - constructor(private readonly minioService: MinioService, private handoverRepo: KeyHandoutRepository, private configService: ConfigService) {} - - async generatePdf(dto: KeyHandoverDto): Promise { - const browser = await puppeteer.launch({ - headless: true, - executablePath: '/usr/bin/chromium', - args: ['--no-sandbox', '--disable-setuid-sandbox'], - }); - - try { - const page = await browser.newPage(); - - const html = this.buildHtml(dto); - - await page.setContent(html, { - waitUntil: 'networkidle0', - }); - - const pdf = await page.pdf({ - format: 'A4', - printBackground: true, - margin: { - top: '20mm', - right: '15mm', - bottom: '20mm', - left: '15mm', - }, - displayHeaderFooter: true, - headerTemplate: `
`, - footerTemplate: ` -
- Übergabeprotokoll - ${new Date().toLocaleString()} -
- `, - }); - - const buffer = Buffer.from(pdf); - - const bucket = this.configService.get('MINIOBUCKET'); - const key = `handover-forms/${Date.now()}-schluesseluebergabe.pdf`; - await this.minioService.uploadPdf(bucket, key, buffer); - await this.saveKeyToHandover(dto.handoverId, key) - return buffer; - } finally { - await browser.close(); - } - } - - private async saveKeyToHandover(handoverId: string, fileKey: string) { - const handover: KeyHandout = await this.handoverRepo.findOneBy({ id: handoverId }); - if (!handover) { return; } - handover.pdfFormKey = fileKey; - this.handoverRepo.save(handover); - } - - private buildHtml(dto: KeyHandoverDto): string { - return ` - - - - - Übergabeprotokoll - - - -

Übergabeprotokoll

- -
-
Übergabedaten
-
- Datum der Übergabe: - ${this.escapeHtml(new Date(dto.handoverDate).toLocaleDateString())} -
- -
- -
-
Übergeber
-
- Name: - ${this.escapeHtml(dto.giverName)} -
-
- Adresse: - ${this.escapeHtml(dto.giverAddress ?? '-')} -
-
- -
-
Empfänger
-
- Name: - ${this.escapeHtml(dto.receiverName)} -
-
- Adresse: - ${this.escapeHtml(dto.receiverAddress ?? '-')} -
-
- -
-
Schlüsselangaben
- -
- Schlüsselnummer: - ${this.escapeHtml(dto.keyNumber ?? '-')} -
- -
- Objekt / Raum: - ${this.escapeHtml(dto.objectDescription ?? '-')} -
-
- Bemerkungen: -
-
${this.escapeHtml(dto.notes ?? '-')}
- -
- -
- Hiermit bestätigt der Empfänger den Erhalt der oben aufgeführten Schlüssel. -
- Mit ihrer Unterschrift bestätigen beide Parteien die ordnungsgemäße Übergabe. -
- -
-
-
Unterschrift Übergeber
-
-
-
Unterschrift Empfänger
-
-
- - - `; - } - - private escapeHtml(value: string): string { - if (!value) { return ""; } - return value - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); - } -} diff --git a/api/src/shared/pdf/minio/minio.service.ts b/api/src/shared/pdf/minio/minio.service.ts deleted file mode 100644 index ec51499..0000000 --- a/api/src/shared/pdf/minio/minio.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; -import { ConfigService } from '@nestjs/config'; - -@Injectable() -export class MinioService { - - constructor(private configService: ConfigService) {} - - private readonly client = new S3Client({ - region: 'us-east-1', - endpoint: this.configService.get('MINIOHOST'), - credentials: { - accessKeyId: this.configService.get('MINIOUSER'), - secretAccessKey: this.configService.get('MINIOACCESSKEY'), - }, - forcePathStyle: true, - }); - - async uploadPdf(bucket: string, key: string, pdfBuffer: Buffer): Promise { - await this.client.send( - new PutObjectCommand({ - Bucket: bucket, - Key: key, - Body: pdfBuffer, - ContentType: 'application/pdf', - }), - ); - } -} diff --git a/api/src/shared/pdf/pdf.module.ts b/api/src/shared/pdf/pdf.module.ts deleted file mode 100644 index 6c6b2de..0000000 --- a/api/src/shared/pdf/pdf.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Module } from '@nestjs/common'; -import { KeyHandoverPdfService } from './key-handover-pdf/key-handover-pdf.service'; -import { MinioService } from './minio/minio.service'; -import { ConfigModule } from '@nestjs/config'; -import { DatabaseModule } from '../database/database.module'; - -@Module({ - providers: [KeyHandoverPdfService, MinioService], - imports: [ConfigModule, DatabaseModule], - exports: [KeyHandoverPdfService] -}) -export class PdfModule {} diff --git a/api/src/shared/storage/services/pdf/pdf.service.ts b/api/src/shared/storage/services/pdf/pdf.service.ts new file mode 100644 index 0000000..a9678b9 --- /dev/null +++ b/api/src/shared/storage/services/pdf/pdf.service.ts @@ -0,0 +1,52 @@ +import { HttpService } from '@nestjs/axios'; +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { AxiosResponse } from 'axios'; +import { firstValueFrom } from 'rxjs'; +import { KeyHandoverPDFDataDto } from 'src/model/dto/key-handover.dto'; +import { KeyHandoutRepository } from 'src/model/repositories/key-handout.repository'; + +@Injectable() +export class PdfService { + + private readonly STORAGESERVER = this.configService.get('STORAGE_HOST') + + constructor( + private readonly configService: ConfigService, + private readonly httpService: HttpService, + private readonly handoverRepo: KeyHandoutRepository + ) { } + + public async generatePDF(dto: KeyHandoverPDFDataDto): Promise<{ pdf: Buffer, response: AxiosResponse}> { + const h = await this.handoverRepo.findOneByOrFail({ id: dto.handoverId }); + const response = await this.post(`${this.STORAGESERVER}/pdf/keyhandover`, dto); + console.log(response) + if (response?.data == null) { return; } + h.pdfFormKey = response.data; + await this.handoverRepo.save(h); + return this.getPDFByHandoverKey(response.data) + + } + + public async getPDFByHandoverKey(key: string): Promise<{ pdf: Buffer, response: AxiosResponse}> { + return new Promise(resolve => { + this.httpService.get(`${this.STORAGESERVER}/pdf/keyhandover/${key}`, { + responseType: 'arraybuffer', + }).subscribe({ + next: pdf => { + const pdfBuffer = Buffer.from(pdf.data); + resolve({ pdf: pdfBuffer, response: pdf}) + }, + error: e => console.log(e) + }) + }) + } + + private async post(url: string, data: any): Promise { + return new Promise(resolve => { + this.httpService.post(url, data).subscribe({ + next: data => resolve(data) + }) + }) + } +} diff --git a/api/src/shared/storage/storage.module.ts b/api/src/shared/storage/storage.module.ts new file mode 100644 index 0000000..5011069 --- /dev/null +++ b/api/src/shared/storage/storage.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { StorageService } from './storage.service'; +import { HttpModule } from '@nestjs/axios'; +import { ConfigModule } from '@nestjs/config'; +import { PdfService } from './services/pdf/pdf.service'; +import { DatabaseModule } from '../database/database.module'; + +@Module({ + imports: [HttpModule, ConfigModule, DatabaseModule], + providers: [StorageService, PdfService ], + exports: [ StorageService, PdfService ] +}) +export class StorageModule {} diff --git a/api/src/shared/storage/storage.service.ts b/api/src/shared/storage/storage.service.ts new file mode 100644 index 0000000..0446175 --- /dev/null +++ b/api/src/shared/storage/storage.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; + +@Injectable() +export class StorageService { + constructor(private readonly configService: ConfigService) { + console.log(configService.get('STORAGE_HOST')) + } + + +} diff --git a/client/src/app/modules/keys/components/create-handover-pdf-dialog/create-handover-pdf-dialog.component.ts b/client/src/app/modules/keys/components/create-handover-pdf-dialog/create-handover-pdf-dialog.component.ts index 20799a0..68cd2bc 100644 --- a/client/src/app/modules/keys/components/create-handover-pdf-dialog/create-handover-pdf-dialog.component.ts +++ b/client/src/app/modules/keys/components/create-handover-pdf-dialog/create-handover-pdf-dialog.component.ts @@ -37,7 +37,6 @@ export class CreateHandoverPdfDialogComponent { }); ngOnInit() { - console.log(this.data) this.patchInitialData(); } diff --git a/client/src/app/modules/keys/components/handover-dialog/handover-dialog.component.ts b/client/src/app/modules/keys/components/handover-dialog/handover-dialog.component.ts index 6372845..6f9cf8f 100644 --- a/client/src/app/modules/keys/components/handover-dialog/handover-dialog.component.ts +++ b/client/src/app/modules/keys/components/handover-dialog/handover-dialog.component.ts @@ -80,7 +80,18 @@ export class HandoverDialogComponent extends AgGridContainerComponent { , sort: 'desc' , cellRenderer: (data: any) => this.datePipe.transform(new Date(data.value)) }, - + { + colId: 'download', + headerName: 'PDF', + field: 'pdfFormKey', + width: 60, + tooltipValueGetter: () => 'Übergabeprotokoll herunterladen', + cellRenderer: () => '', + cellClass: (data: any) => data.value ? 'download-pdf' : '', + onCellClicked: (event) => { + this.downloadHandoverPDF(event.value) + }, + } ] } @@ -94,7 +105,7 @@ export class HandoverDialogComponent extends AgGridContainerComponent { key: new FormControl(this.data), direction: new FormControl('out', Validators.required), timestamp: new FormControl(new Date(), Validators.required), - handoverDocument: new FormControl(false) + handoverDocument: new FormControl(true) }); ngOnInit() { @@ -104,7 +115,6 @@ export class HandoverDialogComponent extends AgGridContainerComponent { loadData() { this.isLoading = true; const promises: Observable[] = [ - this.getHandovers(), from(this.loadCustomers()) ]; @@ -218,6 +228,13 @@ export class HandoverDialogComponent extends AgGridContainerComponent { onGridReady(params: GridReadyEvent) { this.gridApi = params.api; this.gridApi.addEventListener("cellEditingStopped", evt => {}) + this.getHandovers(); + //this.downloadHandoverPDF('5b1f92d9-c66c-49ad-b654-b9a9a6a59752') + } + + downloadHandoverPDF(key: string) { + if (!key) { return; } + this.api.getHandoverPdf(key) } } diff --git a/client/src/app/shared/api.service.ts b/client/src/app/shared/api.service.ts index 250e533..9c3685e 100644 --- a/client/src/app/shared/api.service.ts +++ b/client/src/app/shared/api.service.ts @@ -482,4 +482,20 @@ export class ApiService { }) } + + getHandoverPdf(handoverId: string) { + return new Promise(resolve => { + this.http.get(`/api/key/${handoverId}/handover/pdf`,{ + responseType: 'blob', + }).subscribe((blob) => { + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'schluesseluebergabe.pdf'; + a.click(); + URL.revokeObjectURL(url); + resolve(null) + }); + }) + } } diff --git a/client/src/assets/img/pdf.png b/client/src/assets/img/pdf.png new file mode 100644 index 0000000000000000000000000000000000000000..d2647a81bbe88258a64513c23823514b4ac51788 GIT binary patch literal 573 zcmV-D0>b@?P)N%CP%^J`i2Z(j3oU-Win^m}adesA@FarK0C z^@e!$hk5plfA)@n_L7D6my7n8jQ5(3_nVLRossvTmG`2T_oSKls-O6)q4=<;`M9w8 zxv=@Wv-!NV`n|RKy|((kw)(@o`o+Kd(aikU()`!c{Mpp}+t&Qx-2CC){p#rc@9qBb z@&5Gk{`mL*`uhL>|LI8#*#H0l1$0tQQvf`;z{#4KLs|d;0MbcBK~y-)ozd40f-n?- z;i4!?wJyYk;>3k}i<|dz}_%Mm}PxHLi!EV7jr#VoR}k(5W_Te z3hcJVrPH_$*N>`VPp3^93`lp=I1@6SDR!-vr@>)$(_GNrE4F2|7+dtp!~yE5uh^_Z zPBdq!JYV-^sc`)3np_a_)EOVRNpz_I;Qr=UKxEHF9|%k#3JARcp