feat: Enhance Trial Balance PDF export with professional formatting

- Add multi-line header: company name, centered title, centered period
- Implement pagination with page numbers in footer
- Add generation timestamp in footer
- Optimize column width distribution (Cont: 7%, Denumire: 33%, Values: 10% each)
- Align Cont column to left, all numeric columns to right
- Remove debug console.log statements
- Fix company name property (.firma → .name)
- Use full page width for table (281mm on A4 landscape)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-20 03:18:12 +02:00
parent 86900d7750
commit a45dfa826d
3 changed files with 232 additions and 74 deletions

View File

@@ -8,7 +8,7 @@
Balanță de Verificare
</h1>
<p class="page-subtitle">
{{ currentPeriodText }} - {{ companyStore.selectedCompany?.firma || "Selectați companie" }}
{{ currentPeriodText }} - {{ companyStore.selectedCompany?.name || "Selectați companie" }}
</p>
</div>
@@ -106,6 +106,7 @@
:rows="trialBalanceStore.pagination.pageSize"
:total-records="trialBalanceStore.pagination.totalItems"
:lazy="true"
:striped-rows="true"
paginator-template="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
:rows-per-page-options="[25, 50, 100]"
current-page-report-template="Afișare {first} - {last} din {totalRecords} înregistrări"
@@ -137,37 +138,37 @@
<Column field="sold_precedent_debit" header="Sold Prec. D" sortable :style="{ width: '10%' }">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.sold_precedent_debit) }}
<div class="text-right">{{ formatCurrency(slotProps.data.sold_precedent_debit) }}</div>
</template>
</Column>
<Column field="sold_precedent_credit" header="Sold Prec. C" sortable :style="{ width: '10%' }">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.sold_precedent_credit) }}
<div class="text-right">{{ formatCurrency(slotProps.data.sold_precedent_credit) }}</div>
</template>
</Column>
<Column field="rulaj_lunar_debit" header="Rulaj D" sortable :style="{ width: '10%' }">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.rulaj_lunar_debit) }}
<div class="text-right">{{ formatCurrency(slotProps.data.rulaj_lunar_debit) }}</div>
</template>
</Column>
<Column field="rulaj_lunar_credit" header="Rulaj C" sortable :style="{ width: '10%' }">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.rulaj_lunar_credit) }}
<div class="text-right">{{ formatCurrency(slotProps.data.rulaj_lunar_credit) }}</div>
</template>
</Column>
<Column field="sold_final_debit" header="Sold Final D" sortable :style="{ width: '11%' }">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.sold_final_debit) }}
<div class="text-right">{{ formatCurrency(slotProps.data.sold_final_debit) }}</div>
</template>
</Column>
<Column field="sold_final_credit" header="Sold Final C" sortable :style="{ width: '11%' }">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.sold_final_credit) }}
<div class="text-right">{{ formatCurrency(slotProps.data.sold_final_credit) }}</div>
</template>
</Column>
</DataTable>
@@ -376,16 +377,16 @@ const exportExcel = async () => {
return;
}
// Prepare data for export
// Prepare data for export - Use raw numbers (not formatted) so Excel treats them as numbers
const exportData = allData.map((row) => ({
"Cont": row.cont,
"Denumire": row.denumire,
"Sold Precedent D": formatCurrency(row.sold_precedent_debit),
"Sold Precedent C": formatCurrency(row.sold_precedent_credit),
"Rulaj Lunar D": formatCurrency(row.rulaj_lunar_debit),
"Rulaj Lunar C": formatCurrency(row.rulaj_lunar_credit),
"Sold Final D": formatCurrency(row.sold_final_debit),
"Sold Final C": formatCurrency(row.sold_final_credit),
"Sold Precedent D": parseFloat(row.sold_precedent_debit) || 0,
"Sold Precedent C": parseFloat(row.sold_precedent_credit) || 0,
"Rulaj Lunar D": parseFloat(row.rulaj_lunar_debit) || 0,
"Rulaj Lunar C": parseFloat(row.rulaj_lunar_credit) || 0,
"Sold Final D": parseFloat(row.sold_final_debit) || 0,
"Sold Final C": parseFloat(row.sold_final_credit) || 0,
}));
const result = exportToExcel(
@@ -454,23 +455,29 @@ const exportPDF = async () => {
sold_final_credit: row.sold_final_credit,
}));
// Define columns for PDF
// Define columns for PDF with proper configuration
// A4 landscape width: ~297mm total, margins 8mm left+right = 281mm usable
// Use 'auto' width to fill entire page width
const columns = [
{ field: "cont", header: "Cont", type: "text" },
{ field: "denumire", header: "Denumire", type: "text" },
{ field: "sold_precedent_debit", header: "Sold Prec. D", type: "currency" },
{ field: "sold_precedent_credit", header: "Sold Prec. C", type: "currency" },
{ field: "rulaj_lunar_debit", header: "Rulaj D", type: "currency" },
{ field: "rulaj_lunar_credit", header: "Rulaj C", type: "currency" },
{ field: "sold_final_debit", header: "Sold Final D", type: "currency" },
{ field: "sold_final_credit", header: "Sold Final C", type: "currency" },
{ field: "cont", header: "Cont", type: "text", width: 'auto' },
{ field: "denumire", header: "Denumire Cont", type: "text", width: 'auto' },
{ field: "sold_precedent_debit", header: "Sold Prec. D", type: "number", width: 'auto' },
{ field: "sold_precedent_credit", header: "Sold Prec. C", type: "number", width: 'auto' },
{ field: "rulaj_lunar_debit", header: "Rulaj D", type: "number", width: 'auto' },
{ field: "rulaj_lunar_credit", header: "Rulaj C", type: "number", width: 'auto' },
{ field: "sold_final_debit", header: "Sold Final D", type: "number", width: 'auto' },
{ field: "sold_final_credit", header: "Sold Final C", type: "number", width: 'auto' },
];
const result = exportToPDF(
exportData,
columns,
`balanta_verificare_${currentPeriodText.value.replace(/\s+/g, "_")}`,
`Balanță de Verificare - ${currentPeriodText.value} - ${companyStore.selectedCompany?.firma || ""}`
`balanta-verificare-${currentPeriodText.value.replace(/\s+/g, "-")}`,
{
companyName: companyStore.selectedCompany?.name || "",
title: "Balanta de Verificare",
period: currentPeriodText.value
}
);
if (result.success) {
@@ -578,6 +585,28 @@ watch(
margin-bottom: 0.5rem;
}
.text-right {
text-align: right;
}
/* Enhanced striped rows with better contrast */
.table-card :deep(.p-datatable .p-datatable-tbody > tr) {
transition: background-color 0.2s ease;
}
.table-card :deep(.p-datatable .p-datatable-tbody > tr:nth-child(odd)) {
background-color: #ffffff;
}
.table-card :deep(.p-datatable .p-datatable-tbody > tr:nth-child(even)) {
background-color: #f8f9fa;
}
.table-card :deep(.p-datatable .p-datatable-tbody > tr:hover) {
background-color: #e3f2fd !important;
cursor: pointer;
}
/* Responsive design */
@media (max-width: 768px) {
.trial-balance {