|
|
|
|
@@ -7,93 +7,119 @@
|
|
|
|
|
/>
|
|
|
|
|
<div class="colums">
|
|
|
|
|
<div class="row justify-end">
|
|
|
|
|
<q-btn-dropdown
|
|
|
|
|
ref="dropdownRef"
|
|
|
|
|
class="q-ma-sm"
|
|
|
|
|
color="primary"
|
|
|
|
|
:label="$t('selectDates')"
|
|
|
|
|
@show="loadSettings"
|
|
|
|
|
>
|
|
|
|
|
<DateDaySelect @update:dates="updateReport" />
|
|
|
|
|
<div class="column justify-end q-pa-md">
|
|
|
|
|
<div class="row q-ma-md">
|
|
|
|
|
<q-input
|
|
|
|
|
class="col-7"
|
|
|
|
|
label-color="primary"
|
|
|
|
|
:label="$t('filterEventName')"
|
|
|
|
|
:hint="$t('hintFilterEventName')"
|
|
|
|
|
type="text"
|
|
|
|
|
v-model:model-value="filter"
|
|
|
|
|
></q-input>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="row q-ma-md">
|
|
|
|
|
<q-select
|
|
|
|
|
class="col-7"
|
|
|
|
|
:label="$t('filterByColumnValue')"
|
|
|
|
|
dense
|
|
|
|
|
v-model="group"
|
|
|
|
|
:options="groups"
|
|
|
|
|
option-label="name"
|
|
|
|
|
option-value="id"
|
|
|
|
|
multiple
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="column">
|
|
|
|
|
<q-btn-dropdown
|
|
|
|
|
no-caps
|
|
|
|
|
ref="dropdownRef"
|
|
|
|
|
class="q-ma-sm"
|
|
|
|
|
color="primary"
|
|
|
|
|
:label="$t('selectDates')"
|
|
|
|
|
@show="loadSettings"
|
|
|
|
|
>
|
|
|
|
|
<DateDaySelect @update:dates="updateReport" />
|
|
|
|
|
<div class="column justify-end q-pa-md">
|
|
|
|
|
<div class="row q-ma-md">
|
|
|
|
|
<q-input
|
|
|
|
|
class="col-7"
|
|
|
|
|
label-color="primary"
|
|
|
|
|
:label="$t('filterEventName')"
|
|
|
|
|
:hint="$t('hintFilterEventName')"
|
|
|
|
|
type="text"
|
|
|
|
|
v-model:model-value="filter"
|
|
|
|
|
></q-input>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="row q-ma-md">
|
|
|
|
|
<q-select
|
|
|
|
|
class="col-7"
|
|
|
|
|
:label="$t('filterByColumnValue')"
|
|
|
|
|
dense
|
|
|
|
|
v-model="group"
|
|
|
|
|
:options="groups"
|
|
|
|
|
option-label="name"
|
|
|
|
|
option-value="id"
|
|
|
|
|
multiple
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="row justify-end">
|
|
|
|
|
<q-btn dense class="q-ma-md" color="primary" no-caps @click="applyDateChoice">{{
|
|
|
|
|
$t('apply')
|
|
|
|
|
}}</q-btn>
|
|
|
|
|
<div class="row justify-end">
|
|
|
|
|
<q-btn dense class="q-ma-md" color="primary" no-caps @click="applyDateChoice">{{
|
|
|
|
|
$t('apply')
|
|
|
|
|
}}</q-btn>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</q-btn-dropdown>
|
|
|
|
|
<div class="column q-ma-sm" v-if="amounts.length">
|
|
|
|
|
<q-btn
|
|
|
|
|
dense
|
|
|
|
|
no-caps
|
|
|
|
|
class="q-ma-sm"
|
|
|
|
|
color="grey-9"
|
|
|
|
|
icon="print"
|
|
|
|
|
:label="$t('print')"
|
|
|
|
|
@click="printReport"
|
|
|
|
|
/>
|
|
|
|
|
<q-btn
|
|
|
|
|
dense
|
|
|
|
|
no-caps
|
|
|
|
|
color="secondary"
|
|
|
|
|
icon="picture_as_pdf"
|
|
|
|
|
:label="$t('exportPdf')"
|
|
|
|
|
@click="downloadPDF"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</q-btn-dropdown>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="row justify-center q-ma-xs">
|
|
|
|
|
<h3 class="col-12 text-center text-primary text-bold">{{ $t('report') }}</h3>
|
|
|
|
|
<ReportStat :amounts="amounts" />
|
|
|
|
|
</div>
|
|
|
|
|
<div id="report-content" ref="reportExportRef">
|
|
|
|
|
<div class="row justify-center q-ma-xs">
|
|
|
|
|
<h3 class="col-12 text-center text-primary text-bold">{{ $t('report') }}</h3>
|
|
|
|
|
<ReportStat :amounts="amounts" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="row justify-center">
|
|
|
|
|
<div
|
|
|
|
|
v-if="attendees !== undefined"
|
|
|
|
|
:class="
|
|
|
|
|
nonAttendees !== undefined ? 'col-12 col-sm-5 col-md-5 q-pa-md' : 'col-12 col-md-8 col-lg-5'
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
<q-table
|
|
|
|
|
flat
|
|
|
|
|
dense
|
|
|
|
|
:no-data-label="$t('noDataAvailable')"
|
|
|
|
|
:loading-label="$t('loading')"
|
|
|
|
|
:rows-per-page-label="$t('recordsPerPage')"
|
|
|
|
|
:rows-per-page-options="[0]"
|
|
|
|
|
:title="$t('attendees')"
|
|
|
|
|
title-class="text-bold text-primary"
|
|
|
|
|
:rows="attendees"
|
|
|
|
|
:columns="columns"
|
|
|
|
|
<div class="row justify-center">
|
|
|
|
|
<div
|
|
|
|
|
v-if="attendees !== undefined"
|
|
|
|
|
:class="
|
|
|
|
|
nonAttendees !== undefined
|
|
|
|
|
? 'col-12 col-sm-5 col-md-5 q-pa-md'
|
|
|
|
|
: 'col-12 col-md-8 col-lg-5'
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
</q-table>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
v-if="nonAttendees !== undefined"
|
|
|
|
|
:class="
|
|
|
|
|
attendees !== undefined ? 'col-12 col-sm-5 col-md-5 q-pa-md' : 'col-12 col-md-8 col-lg-5'
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
<q-table
|
|
|
|
|
flat
|
|
|
|
|
dense
|
|
|
|
|
:title="$t('noneAttendees')"
|
|
|
|
|
:no-data-label="$t('noDataAvailable')"
|
|
|
|
|
:loading-label="$t('loading')"
|
|
|
|
|
:rows-per-page-label="$t('recordsPerPage')"
|
|
|
|
|
:rows-per-page-options="[0]"
|
|
|
|
|
title-class="text-bold text-primary"
|
|
|
|
|
:rows="nonAttendees"
|
|
|
|
|
:columns="columns"
|
|
|
|
|
<q-table
|
|
|
|
|
flat
|
|
|
|
|
dense
|
|
|
|
|
:no-data-label="$t('noDataAvailable')"
|
|
|
|
|
:loading-label="$t('loading')"
|
|
|
|
|
:rows-per-page-label="$t('recordsPerPage')"
|
|
|
|
|
:rows-per-page-options="[0]"
|
|
|
|
|
:title="$t('attendees')"
|
|
|
|
|
title-class="text-bold text-primary"
|
|
|
|
|
:rows="attendees"
|
|
|
|
|
:columns="columns"
|
|
|
|
|
>
|
|
|
|
|
</q-table>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
v-if="nonAttendees !== undefined"
|
|
|
|
|
:class="
|
|
|
|
|
attendees !== undefined ? 'col-12 col-sm-5 col-md-5 q-pa-md' : 'col-12 col-md-8 col-lg-5'
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
</q-table>
|
|
|
|
|
<q-table
|
|
|
|
|
flat
|
|
|
|
|
dense
|
|
|
|
|
:title="$t('noneAttendees')"
|
|
|
|
|
:no-data-label="$t('noDataAvailable')"
|
|
|
|
|
:loading-label="$t('loading')"
|
|
|
|
|
:rows-per-page-label="$t('recordsPerPage')"
|
|
|
|
|
:rows-per-page-options="[0]"
|
|
|
|
|
title-class="text-bold text-primary"
|
|
|
|
|
:rows="nonAttendees"
|
|
|
|
|
:columns="columns"
|
|
|
|
|
>
|
|
|
|
|
</q-table>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
@@ -104,11 +130,12 @@ import DateDaySelect from 'src/components/DateDaySelect.vue';
|
|
|
|
|
import { computed, onMounted, ref } from 'vue';
|
|
|
|
|
import { useNotify } from 'src/vueLib/general/useNotify';
|
|
|
|
|
import { i18n } from 'src/boot/lang';
|
|
|
|
|
import { databaseName } from 'src/vueLib/models/settings';
|
|
|
|
|
import { appName, databaseName } from 'src/vueLib/models/settings';
|
|
|
|
|
import type { Amount } from 'src/vueLib/models/report';
|
|
|
|
|
import ReportStat from 'src/components/ReportStat.vue';
|
|
|
|
|
import type { Group, Groups } from 'src/vueLib/models/group';
|
|
|
|
|
import { getLocalPageDefaults, setLocalPageDefaults } from 'src/localstorage/localStorage';
|
|
|
|
|
import html2pdf from 'html2pdf.js';
|
|
|
|
|
|
|
|
|
|
const filter = ref<string>('');
|
|
|
|
|
const group = ref<Group[]>([]);
|
|
|
|
|
@@ -120,6 +147,7 @@ const { NotifyResponse } = useNotify();
|
|
|
|
|
const dropdownRef = ref();
|
|
|
|
|
const loading = ref(false);
|
|
|
|
|
const amounts = ref<Amount[]>([]);
|
|
|
|
|
const reportExportRef = ref<HTMLElement | null>(null);
|
|
|
|
|
|
|
|
|
|
const columns = computed(() => [
|
|
|
|
|
{
|
|
|
|
|
@@ -233,4 +261,99 @@ function applyDateChoice() {
|
|
|
|
|
function updateReport(dates: string[]) {
|
|
|
|
|
allDates.value = dates;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function printReport() {
|
|
|
|
|
window.print();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function downloadPDF() {
|
|
|
|
|
const element = reportExportRef.value;
|
|
|
|
|
if (!element) return;
|
|
|
|
|
// Generate date string (YYYY-MM-DD)
|
|
|
|
|
const today = new Date().toISOString().split('T')[0];
|
|
|
|
|
|
|
|
|
|
// Optionally, add time for more precision (HH-mm)
|
|
|
|
|
const time = new Date()
|
|
|
|
|
.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })
|
|
|
|
|
.replace(':', '-');
|
|
|
|
|
const options = {
|
|
|
|
|
margin: [10, 10, 10, 10] as [number, number, number, number],
|
|
|
|
|
filename: appName.value + `${today}_${time}.pdf`,
|
|
|
|
|
image: {
|
|
|
|
|
type: 'jpeg' as const,
|
|
|
|
|
quality: 1.0, // Set quality to 100%
|
|
|
|
|
},
|
|
|
|
|
html2canvas: {
|
|
|
|
|
scale: 4, // Increase this (2 is standard, 4 is crisp/retina)
|
|
|
|
|
useCORS: true,
|
|
|
|
|
letterRendering: true, // Improves text spacing
|
|
|
|
|
dpi: 300, // Standard print resolution
|
|
|
|
|
},
|
|
|
|
|
jsPDF: {
|
|
|
|
|
unit: 'mm' as const,
|
|
|
|
|
format: 'a4' as const,
|
|
|
|
|
orientation: 'portrait' as const,
|
|
|
|
|
compress: true, // Keeps file size manageable despite high scale
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
await html2pdf()
|
|
|
|
|
.set(options)
|
|
|
|
|
.from(element)
|
|
|
|
|
.save()
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
console.error('PDF Generation failed:', error);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
@media print {
|
|
|
|
|
/* 1. Hide the URL, Date, and Page Title */
|
|
|
|
|
@page {
|
|
|
|
|
margin: 0; /* This is what removes the URL and headers/footers */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
padding: 1.5cm; /* Add padding here so the content isn't at the very edge */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 2. Hide UI elements */
|
|
|
|
|
.q-btn,
|
|
|
|
|
.q-btn-dropdown,
|
|
|
|
|
.q-header,
|
|
|
|
|
.q-drawer,
|
|
|
|
|
.q-footer,
|
|
|
|
|
.q-notifications {
|
|
|
|
|
display: none !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 3. Ensure the layout uses full width */
|
|
|
|
|
.q-page-container {
|
|
|
|
|
padding: 0 !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Remove shadows for cleaner printing */
|
|
|
|
|
.q-card,
|
|
|
|
|
.q-table__card {
|
|
|
|
|
box-shadow: none !important;
|
|
|
|
|
border: 1px solid #ddd !important;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* This ensures the PDF version has a white background and visible text */
|
|
|
|
|
#report-content {
|
|
|
|
|
background: white;
|
|
|
|
|
color: black;
|
|
|
|
|
padding: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Force tables to expand to full width in the PDF */
|
|
|
|
|
#report-content .q-table__container {
|
|
|
|
|
width: 100% !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If you want to force a page break before the tables */
|
|
|
|
|
.pdf-page-break {
|
|
|
|
|
page-break-before: always;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|