call list pdf export
This commit is contained in:
parent
448ea6df28
commit
181d00ea94
@ -119,23 +119,36 @@ export class PdfDocumentService {
|
|||||||
* @param documentContent the content of the pdf as object
|
* @param documentContent the content of the pdf as object
|
||||||
* @param metadata
|
* @param metadata
|
||||||
* @param imageUrls Array of optional images (url, placeholder) to be inserted
|
* @param imageUrls Array of optional images (url, placeholder) to be inserted
|
||||||
|
* @param customMargins optionally overrides the margins
|
||||||
|
* @param landscape optional landscape page orientation instead of default portrait
|
||||||
* @returns the pdf document definition ready to export
|
* @returns the pdf document definition ready to export
|
||||||
*/
|
*/
|
||||||
private async getStandardPaper(documentContent: object, metadata?: object, imageUrls?: string[]): Promise<object> {
|
private async getStandardPaper(
|
||||||
|
documentContent: object,
|
||||||
|
metadata?: object,
|
||||||
|
imageUrls?: string[],
|
||||||
|
customMargins?: [number, number, number, number],
|
||||||
|
landscape?: boolean
|
||||||
|
): Promise<object> {
|
||||||
this.initFonts();
|
this.initFonts();
|
||||||
this.imageUrls = imageUrls ? imageUrls : [];
|
this.imageUrls = imageUrls ? imageUrls : [];
|
||||||
pdfMake.vfs = await this.initVfs();
|
pdfMake.vfs = await this.initVfs();
|
||||||
const result = {
|
const result = {
|
||||||
pageSize: 'A4',
|
pageSize: 'A4',
|
||||||
pageMargins: [75, 90, 75, 75],
|
pageOrientation: landscape ? landscape : 'portrait',
|
||||||
|
pageMargins: customMargins || [75, 90, 75, 75],
|
||||||
defaultStyle: {
|
defaultStyle: {
|
||||||
font: 'PdfFont',
|
font: 'PdfFont',
|
||||||
fontSize: this.configService.instant('general_export_pdf_fontsize')
|
fontSize: this.configService.instant('general_export_pdf_fontsize')
|
||||||
},
|
},
|
||||||
header: this.getHeader(),
|
header: this.getHeader(customMargins ? [customMargins[0], customMargins[2]] : null),
|
||||||
// TODO: option for no footer, wherever this can be defined
|
// TODO: option for no footer, wherever this can be defined
|
||||||
footer: (currentPage, pageCount) => {
|
footer: (currentPage, pageCount) => {
|
||||||
return this.getFooter(currentPage, pageCount);
|
return this.getFooter(
|
||||||
|
currentPage,
|
||||||
|
pageCount,
|
||||||
|
customMargins ? [customMargins[0], customMargins[2]] : null
|
||||||
|
);
|
||||||
},
|
},
|
||||||
info: metadata,
|
info: metadata,
|
||||||
content: documentContent,
|
content: documentContent,
|
||||||
@ -188,9 +201,10 @@ export class PdfDocumentService {
|
|||||||
/**
|
/**
|
||||||
* Creates the header doc definition for normal PDF documents
|
* Creates the header doc definition for normal PDF documents
|
||||||
*
|
*
|
||||||
|
* @param lrMargin optional margin overrides
|
||||||
* @returns an object that contains the necessary header definition
|
* @returns an object that contains the necessary header definition
|
||||||
*/
|
*/
|
||||||
private getHeader(): object {
|
private getHeader(lrMargin?: [number, number]): object {
|
||||||
// check for the required logos
|
// check for the required logos
|
||||||
let logoHeaderLeftUrl = this.configService.instant<any>('logo_pdf_header_L').path;
|
let logoHeaderLeftUrl = this.configService.instant<any>('logo_pdf_header_L').path;
|
||||||
let logoHeaderRightUrl = this.configService.instant<any>('logo_pdf_header_R').path;
|
let logoHeaderRightUrl = this.configService.instant<any>('logo_pdf_header_R').path;
|
||||||
@ -247,11 +261,13 @@ export class PdfDocumentService {
|
|||||||
});
|
});
|
||||||
this.imageUrls.push(logoHeaderRightUrl);
|
this.imageUrls.push(logoHeaderRightUrl);
|
||||||
}
|
}
|
||||||
|
const margin = [lrMargin ? lrMargin[0] : 75, 30, lrMargin ? lrMargin[0] : 75, 10];
|
||||||
|
// pdfmake order: [left, top, right, bottom]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
color: '#555',
|
color: '#555',
|
||||||
fontSize: 9,
|
fontSize: 9,
|
||||||
margin: [75, 30, 75, 10], // [left, top, right, bottom]
|
margin: margin,
|
||||||
columns: columns,
|
columns: columns,
|
||||||
columnGap: 10
|
columnGap: 10
|
||||||
};
|
};
|
||||||
@ -265,9 +281,10 @@ export class PdfDocumentService {
|
|||||||
*
|
*
|
||||||
* @param currentPage holds the number of the current page
|
* @param currentPage holds the number of the current page
|
||||||
* @param pageCount holds the page count
|
* @param pageCount holds the page count
|
||||||
|
* @param lrMargin optionally overriding the margins
|
||||||
* @returns the footer doc definition
|
* @returns the footer doc definition
|
||||||
*/
|
*/
|
||||||
private getFooter(currentPage: number, pageCount: number): object {
|
private getFooter(currentPage: number, pageCount: number, lrMargin?: [number, number]): object {
|
||||||
const columns = [];
|
const columns = [];
|
||||||
let logoContainerWidth: string;
|
let logoContainerWidth: string;
|
||||||
let pageNumberPosition: string;
|
let pageNumberPosition: string;
|
||||||
@ -330,8 +347,9 @@ export class PdfDocumentService {
|
|||||||
this.imageUrls.push(logoFooterRightUrl);
|
this.imageUrls.push(logoFooterRightUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const margin = [lrMargin ? lrMargin[0] : 75, 0, lrMargin ? lrMargin[0] : 75, 10];
|
||||||
return {
|
return {
|
||||||
margin: [75, 0, 75, 10],
|
margin: margin,
|
||||||
columns: columns,
|
columns: columns,
|
||||||
columnGap: 10
|
columnGap: 10
|
||||||
};
|
};
|
||||||
@ -359,6 +377,18 @@ export class PdfDocumentService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads a pdf in landscape orientation
|
||||||
|
*
|
||||||
|
* @param docDefinition the structure of the PDF document
|
||||||
|
* @param filename the name of the file to use
|
||||||
|
* @param metadata
|
||||||
|
*/
|
||||||
|
public downloadLandscape(docDefinition: object, filename: string, metadata?: object): void {
|
||||||
|
this.getStandardPaper(docDefinition, metadata, null, [50, 80, 50, 75], true).then(doc => {
|
||||||
|
this.createPdf(doc, filename);
|
||||||
|
});
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Downloads a pdf with the ballot papet page definitions.
|
* Downloads a pdf with the ballot papet page definitions.
|
||||||
*
|
*
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
<h2 translate>Call list</h2>
|
<h2 translate>Call list</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Export -->
|
<!-- Export menu -->
|
||||||
<div class="menu-slot">
|
<div class="menu-slot">
|
||||||
<button mat-icon-button (click)="csvExportCallList()">
|
<button type="button" mat-icon-button [matMenuTriggerFor]="downloadMenu">
|
||||||
<mat-icon>archive</mat-icon>
|
<mat-icon>more_vert</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</os-head-bar>
|
</os-head-bar>
|
||||||
@ -15,7 +15,25 @@
|
|||||||
<mat-card>
|
<mat-card>
|
||||||
<button mat-button (click)="expandCollapseAll(true)">{{ 'Expand all' | translate }}</button>
|
<button mat-button (click)="expandCollapseAll(true)">{{ 'Expand all' | translate }}</button>
|
||||||
<button mat-button (click)="expandCollapseAll(false)">{{ 'Collapse all' | translate }}</button>
|
<button mat-button (click)="expandCollapseAll(false)">{{ 'Collapse all' | translate }}</button>
|
||||||
<os-sorting-tree #sorter (sort)="sort($event)" parentIdKey="sort_parent_id"
|
<os-sorting-tree
|
||||||
weightKey="weight" [modelsObservable]="motionsObservable" [expandCollapseAll]="expandCollapse">
|
#sorter
|
||||||
|
(sort)="sort($event)"
|
||||||
|
parentIdKey="sort_parent_id"
|
||||||
|
weightKey="weight"
|
||||||
|
[modelsObservable]="motionsObservable"
|
||||||
|
[expandCollapseAll]="expandCollapse"
|
||||||
|
>
|
||||||
</os-sorting-tree>
|
</os-sorting-tree>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|
||||||
|
<mat-menu #downloadMenu="matMenu">
|
||||||
|
<button mat-menu-item (click)="pdfExportCallList()">
|
||||||
|
<mat-icon>picture_as_pdf</mat-icon>
|
||||||
|
<span translate>Export (PDF)</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button mat-menu-item (click)="csvExportCallList()">
|
||||||
|
<mat-icon>archive</mat-icon>
|
||||||
|
<span translate>Export (CSV)</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
@ -7,9 +7,11 @@ import { Observable } from 'rxjs';
|
|||||||
|
|
||||||
import { BaseViewComponent } from '../../../base/base-view';
|
import { BaseViewComponent } from '../../../base/base-view';
|
||||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||||
|
import { MotionCsvExportService } from '../../services/motion-csv-export.service';
|
||||||
|
import { MotionPdfExportService } from '../../services/motion-pdf-export.service';
|
||||||
|
|
||||||
import { ViewMotion } from '../../models/view-motion';
|
import { ViewMotion } from '../../models/view-motion';
|
||||||
import { OSTreeSortEvent } from 'app/shared/components/sorting-tree/sorting-tree.component';
|
import { OSTreeSortEvent } from 'app/shared/components/sorting-tree/sorting-tree.component';
|
||||||
import { MotionCsvExportService } from '../../services/motion-csv-export.service';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort view for the call list.
|
* Sort view for the call list.
|
||||||
@ -46,7 +48,8 @@ export class CallListComponent extends BaseViewComponent {
|
|||||||
translate: TranslateService,
|
translate: TranslateService,
|
||||||
matSnackBar: MatSnackBar,
|
matSnackBar: MatSnackBar,
|
||||||
private motionRepo: MotionRepositoryService,
|
private motionRepo: MotionRepositoryService,
|
||||||
private motionCsvExport: MotionCsvExportService
|
private motionCsvExport: MotionCsvExportService,
|
||||||
|
private motionPdfExport: MotionPdfExportService
|
||||||
) {
|
) {
|
||||||
super(title, translate, matSnackBar);
|
super(title, translate, matSnackBar);
|
||||||
|
|
||||||
@ -83,4 +86,11 @@ export class CallListComponent extends BaseViewComponent {
|
|||||||
public csvExportCallList(): void {
|
public csvExportCallList(): void {
|
||||||
this.motionCsvExport.exportCallList(this.motions);
|
this.motionCsvExport.exportCallList(this.motions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a pdf export of the call list
|
||||||
|
*/
|
||||||
|
public pdfExportCallList(): void {
|
||||||
|
this.motionPdfExport.exportPdfCallList(this.motions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,4 +70,18 @@ export class MotionPdfExportService {
|
|||||||
};
|
};
|
||||||
this.pdfDocumentService.download(doc, filename, metadata);
|
this.pdfDocumentService.download(doc, filename, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports a table of the motions in order of their call list
|
||||||
|
*
|
||||||
|
* @param motions the motions to export
|
||||||
|
*/
|
||||||
|
public exportPdfCallList(motions: ViewMotion[]): void {
|
||||||
|
const doc = this.motionPdfService.callListToDoc(motions);
|
||||||
|
const filename = this.translate.instant('Call list');
|
||||||
|
const metadata = {
|
||||||
|
title: filename
|
||||||
|
};
|
||||||
|
this.pdfDocumentService.downloadLandscape(doc, filename, metadata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ import { Injectable } from '@angular/core';
|
|||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { ViewMotion, LineNumberingMode, ChangeRecoMode } from '../models/view-motion';
|
|
||||||
import { MotionRepositoryService } from '../../../core/repositories/motions/motion-repository.service';
|
|
||||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
|
||||||
import { ChangeRecommendationRepositoryService } from '../../../core/repositories/motions/change-recommendation-repository.service';
|
import { ChangeRecommendationRepositoryService } from '../../../core/repositories/motions/change-recommendation-repository.service';
|
||||||
import { ViewUnifiedChange } from '../models/view-unified-change';
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||||
|
import { MotionRepositoryService } from '../../../core/repositories/motions/motion-repository.service';
|
||||||
import { HtmlToPdfService } from 'app/core/ui-services/html-to-pdf.service';
|
import { HtmlToPdfService } from 'app/core/ui-services/html-to-pdf.service';
|
||||||
|
import { ViewMotion, LineNumberingMode, ChangeRecoMode } from '../models/view-motion';
|
||||||
|
import { ViewUnifiedChange } from '../models/view-unified-change';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a motion to pdf. Can be used from the motion detail view or executed on a list of motions
|
* Converts a motion to pdf. Can be used from the motion detail view or executed on a list of motions
|
||||||
@ -413,4 +413,88 @@ export class MotionPdfService {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates pdfMake definitions for the call list of given motions
|
||||||
|
*
|
||||||
|
* @param motions A list of motions
|
||||||
|
* @returns definitions ready to be opened or exported via {@link PdfDocumentService}
|
||||||
|
*/
|
||||||
|
public callListToDoc(motions: ViewMotion[]): object {
|
||||||
|
motions.sort((a, b) => a.callListWeight - b.callListWeight);
|
||||||
|
const title = {
|
||||||
|
text: this.translate.instant('Call list'),
|
||||||
|
style: 'title'
|
||||||
|
};
|
||||||
|
const callListTableBody: object[] = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: this.translate.instant('Called'),
|
||||||
|
style: 'tableHeader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.translate.instant('Called with'),
|
||||||
|
style: 'tableHeader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.translate.instant('Submitters'),
|
||||||
|
style: 'tableHeader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.translate.instant('Title'),
|
||||||
|
style: 'tableHeader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.translate.instant('Recommendation'),
|
||||||
|
style: 'tableHeader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.translate.instant('Motion block'),
|
||||||
|
style: 'tableHeader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
const callListRows = motions.map(motion => this.createCallListRow(motion));
|
||||||
|
const table: object = {
|
||||||
|
table: {
|
||||||
|
widths: ['auto', 'auto', 'auto', '*', 'auto', 'auto'],
|
||||||
|
headerRows: 1,
|
||||||
|
body: callListTableBody.concat(callListRows)
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
hLineWidth: rowIndex => {
|
||||||
|
return rowIndex === 1;
|
||||||
|
},
|
||||||
|
vLineWidth: () => {
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
fillColor: rowIndex => {
|
||||||
|
return rowIndex % 2 === 0 ? '#EEEEEE' : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return [title, table];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the pdfMake definitions for a row of the call List table
|
||||||
|
*
|
||||||
|
* @param motion
|
||||||
|
* @returns pdfmakre definitions
|
||||||
|
*/
|
||||||
|
private createCallListRow(motion: ViewMotion): object {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: motion.sort_parent_id ? '' : motion.identifierOrTitle
|
||||||
|
},
|
||||||
|
{ text: motion.sort_parent_id ? motion.identifierOrTitle : '' },
|
||||||
|
{ text: motion.submitters.length ? motion.submitters.map(s => s.short_name).join(', ') : '' },
|
||||||
|
{ text: motion.title },
|
||||||
|
{
|
||||||
|
text: motion.recommendation ? this.translate.instant(motion.recommendation.recommendation_label) : ''
|
||||||
|
},
|
||||||
|
{ text: motion.motion_block ? motion.motion_block.title : '' }
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user