Previously, totals were computed client-side from only the current page data, which gave incorrect results when paginating. Now the backend calculates totals across ALL filtered records and returns them in the API response. - Invoice: Add total_sold_all field for sum of all filtered invoice balances - Treasury: Add sold_precedent_all, total_incasari_all, total_plati_all, sold_final_all - Trial Balance: Add 6-column totals (debit/credit for each balance type) - Frontend stores and views updated to use backend totals 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
743 lines
20 KiB
Vue
743 lines
20 KiB
Vue
<template>
|
|
<div class="app-container">
|
|
<div class="trial-balance">
|
|
<!-- Page Header -->
|
|
<div class="page-header">
|
|
<h1 class="page-title">
|
|
<i class="pi pi-calculator"></i>
|
|
Balanță de Verificare
|
|
</h1>
|
|
<p class="page-subtitle">
|
|
{{ currentPeriodText }} -
|
|
{{ companyStore.selectedCompany?.name || "Selectați companie" }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Company Selection -->
|
|
<Card v-if="!companyStore.selectedCompany" class="company-selection-card">
|
|
<template #content>
|
|
<div class="company-selection">
|
|
<p class="text-color-secondary mb-3">
|
|
Selectați o companie pentru a vizualiza balanța de verificare:
|
|
</p>
|
|
<Dropdown
|
|
v-model="selectedCompanyId"
|
|
:options="companyStore.companyListFormatted"
|
|
option-label="displayName"
|
|
option-value="id_firma"
|
|
placeholder="Alegeți compania"
|
|
class="w-full"
|
|
@change="handleCompanyChange"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
|
|
<!-- Filters Section -->
|
|
<Card v-if="companyStore.selectedCompany" class="filters-card">
|
|
<template #content>
|
|
<div class="form">
|
|
<div class="form-row">
|
|
<!-- Cont Filter -->
|
|
<div class="form-col">
|
|
<div class="form-group">
|
|
<label class="form-label">Număr Cont</label>
|
|
<InputText
|
|
v-model="localFilters.cont"
|
|
placeholder="Ex: 512, 4111"
|
|
class="w-full"
|
|
@input="handleFilterChange"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Denumire Filter -->
|
|
<div class="form-col search-col">
|
|
<div class="form-group">
|
|
<label class="form-label">Denumire Cont</label>
|
|
<InputText
|
|
v-model="localFilters.denumire"
|
|
placeholder="Căutare după denumire..."
|
|
class="w-full"
|
|
@input="handleSearchChange"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-actions">
|
|
<Button
|
|
icon="pi pi-filter-slash"
|
|
label="Resetează Filtre"
|
|
class="p-button-outlined p-button-secondary"
|
|
@click="clearFilters"
|
|
/>
|
|
<Button
|
|
icon="pi pi-file-excel"
|
|
label="Export Excel"
|
|
class="p-button-outlined p-button-success"
|
|
@click="exportExcel"
|
|
:disabled="!trialBalanceStore.hasData"
|
|
/>
|
|
<Button
|
|
icon="pi pi-file-pdf"
|
|
label="Export PDF"
|
|
class="p-button-outlined p-button-danger"
|
|
@click="exportPDF"
|
|
:disabled="!trialBalanceStore.hasData"
|
|
/>
|
|
<Button
|
|
icon="pi pi-refresh"
|
|
label="Actualizează"
|
|
:loading="trialBalanceStore.isLoading"
|
|
@click="refreshData"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
|
|
<!-- Summary Totals - 2 rows (Debit/Credit) for visual balance verification -->
|
|
<!-- Totaluri din TOATE înregistrările filtrate (nu doar pagina curentă) -->
|
|
<div v-if="companyStore.selectedCompany && trialBalanceStore.hasData" class="totals-table-container">
|
|
<table class="totals-table">
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th>Sold Precedent</th>
|
|
<th>Rulaj Lunar</th>
|
|
<th>Sold Final</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td class="row-label">Debit</td>
|
|
<td class="numeric">{{ formatCurrency(trialBalanceStore.totals.total_sold_precedent_debit) }}</td>
|
|
<td class="numeric">{{ formatCurrency(trialBalanceStore.totals.total_rulaj_lunar_debit) }}</td>
|
|
<td class="numeric">{{ formatCurrency(trialBalanceStore.totals.total_sold_final_debit) }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="row-label">Credit</td>
|
|
<td class="numeric">{{ formatCurrency(trialBalanceStore.totals.total_sold_precedent_credit) }}</td>
|
|
<td class="numeric">{{ formatCurrency(trialBalanceStore.totals.total_rulaj_lunar_credit) }}</td>
|
|
<td class="numeric">{{ formatCurrency(trialBalanceStore.totals.total_sold_final_credit) }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Trial Balance Table -->
|
|
<Card v-if="companyStore.selectedCompany" class="table-card">
|
|
<template #content>
|
|
<DataTable
|
|
:value="trialBalanceStore.trialBalanceData"
|
|
:loading="trialBalanceStore.isLoading"
|
|
:paginator="true"
|
|
: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"
|
|
responsive-layout="scroll"
|
|
@page="onPageChange"
|
|
@sort="onSort"
|
|
>
|
|
<template #empty>
|
|
<div class="table-empty">
|
|
<i class="pi pi-info-circle table-empty-icon"></i>
|
|
<p class="table-empty-message">
|
|
Nu au fost găsite date pentru perioada selectată
|
|
</p>
|
|
</div>
|
|
</template>
|
|
|
|
<template #loading>
|
|
<div class="loading-state">
|
|
<ProgressSpinner />
|
|
<p>Se încarcă balanța de verificare...</p>
|
|
</div>
|
|
</template>
|
|
|
|
<Column
|
|
field="cont"
|
|
header="Cont"
|
|
sortable
|
|
:style="{ width: '8%' }"
|
|
>
|
|
<template #body="slotProps">
|
|
<strong>{{ slotProps.data.cont }}</strong>
|
|
</template>
|
|
</Column>
|
|
|
|
<Column
|
|
field="denumire"
|
|
header="Denumire Cont"
|
|
sortable
|
|
:style="{ width: '20%' }"
|
|
/>
|
|
|
|
<Column
|
|
field="sold_precedent_debit"
|
|
header="Sold Prec. D"
|
|
sortable
|
|
:style="{ width: '10%' }"
|
|
>
|
|
<template #body="slotProps">
|
|
<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">
|
|
<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">
|
|
<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">
|
|
<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">
|
|
<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">
|
|
<div class="text-right">
|
|
{{ formatCurrency(slotProps.data.sold_final_credit) }}
|
|
</div>
|
|
</template>
|
|
</Column>
|
|
</DataTable>
|
|
</template>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted, watch } from "vue";
|
|
import { useToast } from "primevue/usetoast";
|
|
import { useCompanyStore } from "../stores/companies";
|
|
import { useTrialBalanceStore } from "../stores/trialBalance";
|
|
import { useAccountingPeriodStore } from "../stores/accountingPeriod";
|
|
import { exportToExcel, exportToPDF } from "../utils/exportUtils";
|
|
|
|
const toast = useToast();
|
|
const companyStore = useCompanyStore();
|
|
const trialBalanceStore = useTrialBalanceStore();
|
|
const periodStore = useAccountingPeriodStore();
|
|
|
|
// State
|
|
const selectedCompanyId = ref(companyStore.selectedCompany?.id_firma || null);
|
|
|
|
const localFilters = ref({
|
|
cont: "",
|
|
denumire: "",
|
|
});
|
|
|
|
// Computed
|
|
const currentPeriodText = computed(() => {
|
|
// Use the global period store
|
|
return periodStore.selectedPeriod?.display_name || "";
|
|
});
|
|
|
|
// Methods
|
|
const formatCurrency = (amount) => {
|
|
if (!amount || amount === 0) return "0,00";
|
|
return new Intl.NumberFormat("ro-RO", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2,
|
|
}).format(amount);
|
|
};
|
|
|
|
const handleCompanyChange = async () => {
|
|
if (!selectedCompanyId.value) return;
|
|
|
|
const company = companyStore.getCompanyById(selectedCompanyId.value);
|
|
if (company) {
|
|
companyStore.setSelectedCompany(company);
|
|
await loadTrialBalance();
|
|
}
|
|
};
|
|
|
|
const handleFilterChange = async () => {
|
|
await applyFilters();
|
|
};
|
|
|
|
const handleSearchChange = (() => {
|
|
let timeout;
|
|
return () => {
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(async () => {
|
|
await applyFilters();
|
|
}, 500);
|
|
};
|
|
})();
|
|
|
|
const applyFilters = async () => {
|
|
if (!companyStore.selectedCompany) return;
|
|
|
|
await trialBalanceStore.applyFilters(
|
|
{
|
|
cont: localFilters.value.cont,
|
|
denumire: localFilters.value.denumire,
|
|
},
|
|
companyStore.selectedCompany.id_firma,
|
|
);
|
|
};
|
|
|
|
const clearFilters = async () => {
|
|
localFilters.value = {
|
|
cont: "",
|
|
denumire: "",
|
|
};
|
|
await trialBalanceStore.clearFilters(companyStore.selectedCompany.id_firma);
|
|
};
|
|
|
|
const refreshData = async () => {
|
|
await loadTrialBalance();
|
|
toast.add({
|
|
severity: "success",
|
|
summary: "Actualizare reușită",
|
|
detail: "Balanța de verificare a fost actualizată cu succes",
|
|
life: 3000,
|
|
});
|
|
};
|
|
|
|
const loadTrialBalance = async () => {
|
|
if (!companyStore.selectedCompany) return;
|
|
|
|
try {
|
|
await trialBalanceStore.fetchTrialBalance(
|
|
companyStore.selectedCompany.id_firma,
|
|
);
|
|
} catch (error) {
|
|
console.error("Failed to load trial balance:", error);
|
|
toast.add({
|
|
severity: "error",
|
|
summary: "Eroare",
|
|
detail: "Nu s-a putut încărca balanța de verificare",
|
|
life: 5000,
|
|
});
|
|
}
|
|
};
|
|
|
|
const onPageChange = async (event) => {
|
|
if (!companyStore.selectedCompany) return;
|
|
|
|
await trialBalanceStore.changePage(
|
|
event.page + 1,
|
|
companyStore.selectedCompany.id_firma,
|
|
);
|
|
};
|
|
|
|
const onSort = async (event) => {
|
|
if (!companyStore.selectedCompany) return;
|
|
|
|
const sortBy = event.sortField?.toUpperCase() || "CONT";
|
|
const sortOrder = event.sortOrder === 1 ? "asc" : "desc";
|
|
|
|
await trialBalanceStore.sort(
|
|
sortBy,
|
|
sortOrder,
|
|
companyStore.selectedCompany.id_firma,
|
|
);
|
|
};
|
|
|
|
// Export methods - Fetch ALL data (not just current page)
|
|
const fetchAllTrialBalanceData = async () => {
|
|
if (!companyStore.selectedCompany) return [];
|
|
|
|
try {
|
|
const params = {
|
|
company: companyStore.selectedCompany.id_firma,
|
|
luna: trialBalanceStore.filters.luna,
|
|
an: trialBalanceStore.filters.an,
|
|
page: 1,
|
|
page_size: 999999, // Get all data
|
|
sort_by: trialBalanceStore.sorting.sortBy,
|
|
sort_order: trialBalanceStore.sorting.sortOrder,
|
|
};
|
|
|
|
// Add optional filters
|
|
if (trialBalanceStore.filters.cont) {
|
|
params.cont_filter = trialBalanceStore.filters.cont;
|
|
}
|
|
if (trialBalanceStore.filters.denumire) {
|
|
params.denumire_filter = trialBalanceStore.filters.denumire;
|
|
}
|
|
|
|
const apiService = (await import("../services/api")).apiService;
|
|
const response = await apiService.get("/trial-balance/", { params });
|
|
|
|
if (response.data.success) {
|
|
return response.data.data.items || [];
|
|
}
|
|
return [];
|
|
} catch (error) {
|
|
console.error("Failed to fetch all trial balance data:", error);
|
|
return [];
|
|
}
|
|
};
|
|
|
|
const exportExcel = async () => {
|
|
if (!trialBalanceStore.hasData) {
|
|
toast.add({
|
|
severity: "warn",
|
|
summary: "Nu există date",
|
|
detail: "Nu există date de exportat",
|
|
life: 3000,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Fetch ALL data for export (not just current page)
|
|
toast.add({
|
|
severity: "info",
|
|
summary: "Se pregătește exportul",
|
|
detail: "Se încarcă toate datele...",
|
|
life: 2000,
|
|
});
|
|
|
|
const allData = await fetchAllTrialBalanceData();
|
|
|
|
if (allData.length === 0) {
|
|
toast.add({
|
|
severity: "error",
|
|
summary: "Eroare",
|
|
detail: "Nu s-au putut prelua datele pentru export",
|
|
life: 3000,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// 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": 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(
|
|
exportData,
|
|
`balanta_verificare_${currentPeriodText.value.replace(/\s+/g, "_")}`,
|
|
"Balanță de Verificare",
|
|
);
|
|
|
|
if (result.success) {
|
|
toast.add({
|
|
severity: "success",
|
|
summary: "Export reușit",
|
|
detail: `${allData.length} înregistrări exportate cu succes`,
|
|
life: 3000,
|
|
});
|
|
} else {
|
|
toast.add({
|
|
severity: "error",
|
|
summary: "Eroare la export",
|
|
detail: "Nu s-a putut genera fișierul Excel",
|
|
life: 3000,
|
|
});
|
|
}
|
|
};
|
|
|
|
const exportPDF = async () => {
|
|
if (!trialBalanceStore.hasData) {
|
|
toast.add({
|
|
severity: "warn",
|
|
summary: "Nu există date",
|
|
detail: "Nu există date de exportat",
|
|
life: 3000,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Fetch ALL data for export (not just current page)
|
|
toast.add({
|
|
severity: "info",
|
|
summary: "Se pregătește exportul",
|
|
detail: "Se încarcă toate datele...",
|
|
life: 2000,
|
|
});
|
|
|
|
const allData = await fetchAllTrialBalanceData();
|
|
|
|
if (allData.length === 0) {
|
|
toast.add({
|
|
severity: "error",
|
|
summary: "Eroare",
|
|
detail: "Nu s-au putut prelua datele pentru export",
|
|
life: 3000,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Prepare data for export
|
|
const exportData = allData.map((row) => ({
|
|
cont: row.cont,
|
|
denumire: row.denumire,
|
|
sold_precedent_debit: row.sold_precedent_debit,
|
|
sold_precedent_credit: row.sold_precedent_credit,
|
|
rulaj_lunar_debit: row.rulaj_lunar_debit,
|
|
rulaj_lunar_credit: row.rulaj_lunar_credit,
|
|
sold_final_debit: row.sold_final_debit,
|
|
sold_final_credit: row.sold_final_credit,
|
|
}));
|
|
|
|
// 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", 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, "-")}`,
|
|
{
|
|
companyName: companyStore.selectedCompany?.name || "",
|
|
title: "Balanta de Verificare",
|
|
period: currentPeriodText.value,
|
|
},
|
|
);
|
|
|
|
if (result.success) {
|
|
toast.add({
|
|
severity: "success",
|
|
summary: "Export reușit",
|
|
detail: `${allData.length} înregistrări exportate cu succes`,
|
|
life: 3000,
|
|
});
|
|
} else {
|
|
toast.add({
|
|
severity: "error",
|
|
summary: "Eroare la export",
|
|
detail: "Nu s-a putut genera fișierul PDF",
|
|
life: 3000,
|
|
});
|
|
}
|
|
};
|
|
|
|
// Lifecycle
|
|
onMounted(async () => {
|
|
// Load companies if not loaded
|
|
if (!companyStore.hasCompanies) {
|
|
await companyStore.loadCompanies();
|
|
}
|
|
|
|
// FIX: Sync period from global periodStore BEFORE loading data
|
|
// This ensures Trial Balance shows the correct period when navigating
|
|
// from other views (e.g., Invoices with November selected)
|
|
if (periodStore.selectedPeriod) {
|
|
trialBalanceStore.filters.luna = periodStore.selectedPeriod.luna;
|
|
trialBalanceStore.filters.an = periodStore.selectedPeriod.an;
|
|
}
|
|
|
|
// Load trial balance if company is selected
|
|
if (companyStore.selectedCompany) {
|
|
await loadTrialBalance();
|
|
}
|
|
});
|
|
|
|
// Watch for company changes
|
|
watch(
|
|
() => companyStore.selectedCompany,
|
|
async (newCompany) => {
|
|
if (newCompany) {
|
|
await loadTrialBalance();
|
|
}
|
|
},
|
|
);
|
|
|
|
// Watch for period changes - sync luna/an with trial balance store
|
|
watch(
|
|
() => periodStore.selectedPeriod,
|
|
async (newPeriod) => {
|
|
if (newPeriod && companyStore.selectedCompany) {
|
|
await trialBalanceStore.changePeriod(
|
|
newPeriod.luna,
|
|
newPeriod.an,
|
|
companyStore.selectedCompany.id_firma
|
|
);
|
|
}
|
|
},
|
|
);
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* ===== Page-Specific Styles Only ===== */
|
|
/* Uses shared CSS: dashboard.css (.page-header, .page-title, .page-subtitle) */
|
|
/* Uses shared CSS: forms.css (.form-actions) */
|
|
/* Uses shared CSS: tables.css (.table-empty, .loading-state) */
|
|
/* Uses shared CSS: primevue-overrides.css (DataTable striped rows, hover) */
|
|
|
|
/* Page Container */
|
|
.trial-balance {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
padding: var(--space-xl);
|
|
}
|
|
|
|
/* Card Spacing */
|
|
.company-selection-card,
|
|
.filters-card,
|
|
.table-card {
|
|
margin-bottom: var(--space-xl);
|
|
}
|
|
|
|
/* Search field takes 2 columns in form grid */
|
|
.search-col {
|
|
grid-column: span 2;
|
|
}
|
|
|
|
/* Text alignment utility - page specific */
|
|
.text-right {
|
|
text-align: right;
|
|
}
|
|
|
|
/* Totals Table for Trial Balance - 2 rows (Debit/Credit) */
|
|
.totals-table-container {
|
|
margin-bottom: var(--space-lg);
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.totals-table {
|
|
border-collapse: collapse;
|
|
font-size: 0.9rem;
|
|
background: var(--surface-card);
|
|
border-radius: var(--border-radius);
|
|
overflow: hidden;
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
.totals-table th,
|
|
.totals-table td {
|
|
padding: 0.5rem 1rem;
|
|
text-align: right;
|
|
}
|
|
|
|
.totals-table th {
|
|
background: var(--surface-100);
|
|
font-weight: 600;
|
|
color: var(--text-color-secondary);
|
|
}
|
|
|
|
.totals-table .row-label {
|
|
text-align: left;
|
|
font-weight: 600;
|
|
background: var(--surface-50);
|
|
}
|
|
|
|
.totals-table .numeric {
|
|
font-family: var(--font-mono, 'Roboto Mono', monospace);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
.totals-table tbody tr:first-child td {
|
|
border-bottom: 1px solid var(--surface-border);
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 768px) {
|
|
.trial-balance {
|
|
padding: var(--space-md);
|
|
}
|
|
|
|
.search-col {
|
|
grid-column: span 1;
|
|
}
|
|
}
|
|
</style>
|