Merge pull request #4210 from MaximilianKrambach/agendalistpdf
agenda pdf export
This commit is contained in:
commit
d705b2a137
@ -468,6 +468,14 @@ export class PdfDocumentService {
|
|||||||
tableHeader: {
|
tableHeader: {
|
||||||
bold: true,
|
bold: true,
|
||||||
fillColor: 'white'
|
fillColor: 'white'
|
||||||
|
},
|
||||||
|
listParent: {
|
||||||
|
fontSize: 14,
|
||||||
|
margin: [0, 5]
|
||||||
|
},
|
||||||
|
listChild: {
|
||||||
|
fontSize: 12,
|
||||||
|
margin: [0, 5]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -110,10 +110,17 @@
|
|||||||
<span translate>Sort</span>
|
<span translate>Sort</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- csv export -->
|
||||||
<button mat-menu-item (click)="csvExportItemList()">
|
<button mat-menu-item (click)="csvExportItemList()">
|
||||||
<mat-icon>archive</mat-icon>
|
<mat-icon>archive</mat-icon>
|
||||||
<span translate>Export as CSV</span>
|
<span translate>Export as CSV</span>
|
||||||
</button>
|
</button>
|
||||||
|
<!-- PDF export -->
|
||||||
|
<button mat-menu-item (click)="onDownloadPdf()">
|
||||||
|
<mat-icon>picture_as_pdf</mat-icon>
|
||||||
|
<span translate>Export as PDF</span>
|
||||||
|
</button>
|
||||||
|
<!-- Import -->
|
||||||
<button mat-menu-item *osPerms="'agenda.can_manage'" routerLink="import">
|
<button mat-menu-item *osPerms="'agenda.can_manage'" routerLink="import">
|
||||||
<mat-icon>save_alt</mat-icon>
|
<mat-icon>save_alt</mat-icon>
|
||||||
<span translate>Import</span><span> ...</span>
|
<span translate>Import</span><span> ...</span>
|
||||||
|
@ -11,9 +11,11 @@ import { PromptService } from '../../../../core/services/prompt.service';
|
|||||||
import { ViewItem } from '../../models/view-item';
|
import { ViewItem } from '../../models/view-item';
|
||||||
|
|
||||||
import { AgendaCsvExportService } from '../../services/agenda-csv-export.service';
|
import { AgendaCsvExportService } from '../../services/agenda-csv-export.service';
|
||||||
|
import { AgendaPdfService } from '../../services/agenda-pdf.service';
|
||||||
import { ConfigService } from 'app/core/services/config.service';
|
import { ConfigService } from 'app/core/services/config.service';
|
||||||
import { DurationService } from 'app/core/services/duration.service';
|
import { DurationService } from 'app/core/services/duration.service';
|
||||||
import { ItemInfoDialogComponent } from '../item-info-dialog/item-info-dialog.component';
|
import { ItemInfoDialogComponent } from '../item-info-dialog/item-info-dialog.component';
|
||||||
|
import { PdfDocumentService } from 'app/core/services/pdf-document.service';
|
||||||
import { ViewportService } from 'app/core/services/viewport.service';
|
import { ViewportService } from 'app/core/services/viewport.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,6 +54,8 @@ export class AgendaListComponent extends ListViewBaseComponent<ViewItem> impleme
|
|||||||
* @param durationService Converts numbers to readable duration strings
|
* @param durationService Converts numbers to readable duration strings
|
||||||
* @param csvExport Handles the exporting into csv
|
* @param csvExport Handles the exporting into csv
|
||||||
* @param filterService: service for filtering data
|
* @param filterService: service for filtering data
|
||||||
|
* @param agendaPdfService: service for preparing a pdf of the agenda
|
||||||
|
* @param pdfService: Service for exporting a pdf
|
||||||
*/
|
*/
|
||||||
public constructor(
|
public constructor(
|
||||||
titleService: Title,
|
titleService: Title,
|
||||||
@ -66,7 +70,9 @@ export class AgendaListComponent extends ListViewBaseComponent<ViewItem> impleme
|
|||||||
public vp: ViewportService,
|
public vp: ViewportService,
|
||||||
public durationService: DurationService,
|
public durationService: DurationService,
|
||||||
private csvExport: AgendaCsvExportService,
|
private csvExport: AgendaCsvExportService,
|
||||||
public filterService: AgendaFilterListService
|
public filterService: AgendaFilterListService,
|
||||||
|
private agendaPdfService: AgendaPdfService,
|
||||||
|
private pdfService: PdfDocumentService
|
||||||
) {
|
) {
|
||||||
super(titleService, translate, matSnackBar);
|
super(titleService, translate, matSnackBar);
|
||||||
|
|
||||||
@ -227,4 +233,13 @@ export class AgendaListComponent extends ListViewBaseComponent<ViewItem> impleme
|
|||||||
public csvExportItemList(): void {
|
public csvExportItemList(): void {
|
||||||
this.csvExport.exportItemList(this.dataSource.filteredData);
|
this.csvExport.exportItemList(this.dataSource.filteredData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers the export of the agenda. Currently filtered items and 'hidden'
|
||||||
|
* items will not be exported
|
||||||
|
*/
|
||||||
|
public onDownloadPdf(): void {
|
||||||
|
const filename = this.translate.instant('Agenda');
|
||||||
|
this.pdfService.download(this.agendaPdfService.agendaListToDocDef(this.dataSource.filteredData), filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,10 +67,7 @@ export class ViewItem extends BaseViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get verboseCsvType(): string {
|
public get verboseCsvType(): string {
|
||||||
if (this.item) {
|
return this.item ? this.item.verboseCsvType : '';
|
||||||
return this.item.verboseCsvType;
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AgendaPdfService } from './agenda-pdf.service';
|
||||||
|
import { E2EImportsModule } from 'e2e-imports.module';
|
||||||
|
|
||||||
|
describe('AgendaPdfService', () => {
|
||||||
|
beforeEach(() =>
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [E2EImportsModule]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
const service: AgendaPdfService = TestBed.get(AgendaPdfService);
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
103
client/src/app/site/agenda/services/agenda-pdf.service.ts
Normal file
103
client/src/app/site/agenda/services/agenda-pdf.service.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { TreeService, OSTreeNode } from 'app/core/services/tree.service';
|
||||||
|
import { ViewItem } from '../models/view-item';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pdfMake structure for a content line in the pdf document.
|
||||||
|
*/
|
||||||
|
interface AgendaTreePdfEntry {
|
||||||
|
style: string;
|
||||||
|
columns: { width?: number; text: string }[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a list of agenda items to pdf, indenting according to a hierarchy tree.
|
||||||
|
* Provides the public method `agendaListToDocDef(items: ViewItems[])` which should be convenient to use.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const pdfMakeCompatibleDocDef = this.AgendaPdfService.agendaListToDocDef(this.dataSource.data);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AgendaPdfService {
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param translate handle translations
|
||||||
|
* @param treeService create hierarchy between items
|
||||||
|
*/
|
||||||
|
public constructor(private translate: TranslateService, private treeService: TreeService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates pdfMake definitions for a agenda list pdf from the given agenda items
|
||||||
|
*
|
||||||
|
* @param items A list of viewItems to be included in this agenda list. Items with the property 'hidden'
|
||||||
|
* will be ignored, all other items will be sorted by their parents and weight
|
||||||
|
* @returns definitions ready to be opened or exported via {@link PdfDocumentService}
|
||||||
|
*/
|
||||||
|
public agendaListToDocDef(items: ViewItem[]): object {
|
||||||
|
const tree: OSTreeNode<ViewItem>[] = this.treeService.makeTree(items, 'weight', 'parent_id');
|
||||||
|
const title = {
|
||||||
|
text: this.translate.instant('Agenda'),
|
||||||
|
style: 'title'
|
||||||
|
};
|
||||||
|
const entries = this.createEntries(tree);
|
||||||
|
return [title, entries];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traverses the given nodeTree and creates an array of entries for all items
|
||||||
|
*
|
||||||
|
* @param tree
|
||||||
|
* @returns hierarchical pdfMake definitions for topic entries
|
||||||
|
*/
|
||||||
|
private createEntries(tree: OSTreeNode<ViewItem>[]): AgendaTreePdfEntry[] {
|
||||||
|
const content: AgendaTreePdfEntry[] = [];
|
||||||
|
tree.forEach(treeitem => content.push(...this.parseItem(treeitem, 0)));
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an entry line and triggers parsing of any children
|
||||||
|
* (TODO: Check assumption: items with 'is_hidden' are not to be exported)
|
||||||
|
*
|
||||||
|
* @param nodeItem the item for the head line
|
||||||
|
* @param level: The hierarchy index (beginning at 0 for top level agenda topics)
|
||||||
|
* @returns pdfMake definitions for the number/title strings, indented according to hierarchy
|
||||||
|
*/
|
||||||
|
private parseItem(nodeItem: OSTreeNode<ViewItem>, level: number): AgendaTreePdfEntry[] {
|
||||||
|
const itemList: AgendaTreePdfEntry[] = [];
|
||||||
|
if (!nodeItem.item.item.is_hidden) {
|
||||||
|
// don't include hidden items and their subitems
|
||||||
|
const resultString: AgendaTreePdfEntry = {
|
||||||
|
style: level ? 'listChild' : 'listParent',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
width: level * 15,
|
||||||
|
text: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
width: 60,
|
||||||
|
text: nodeItem.item.itemNumber
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: nodeItem.item.getTitle()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
itemList.push(resultString);
|
||||||
|
if (nodeItem.children && nodeItem.children.length) {
|
||||||
|
nodeItem.children.forEach(child => {
|
||||||
|
itemList.push(...this.parseItem(child, level + 1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return itemList;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user