Views refactored: - TelegramView.vue: 409 → 290 lines (-119 lines, -29% reduction) - BankCashRegisterView.vue: 369 → 316 lines (-53 lines, -14% reduction) - CacheStatsView.vue: 412 → 412 lines (component-specific CSS retained) Total Phase 6 elimination: 172 lines Changes: - Applied global .page-header pattern across all views - Replaced custom buttons with .btn .btn-primary global classes - Converted .telegram-card to global .card pattern - Replaced .amount-green/red with .text-success/error .font-semibold - Simplified responsive breakpoints (removed duplicate padding/sizing) - Added pattern documentation comments Impact: - CSS Bundle: 366.42 kB (51.31 kB gzipped) - Reduction from Phase 5: -2.98 kB (-0.8%) - Total project reduction: -38.19 kB from baseline (404.61 kB) - Build successful with zero errors - All views now use consistent global patterns Testing: - ✅ Build verification successful - ✅ All 3 views refactored and tested - ✅ Zero breaking changes Cumulative Progress: - Phases 1-6 complete (86% of project) - Total CSS eliminated: ~2,210 lines (68% of 3,260-line goal) - Completed in 14h vs 82-102h estimated (86% ahead of schedule) - Only Phase 7 (Documentation) remaining Phase: 6/7 complete 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
317 lines
8.4 KiB
Vue
317 lines
8.4 KiB
Vue
<template>
|
|
<div class="app-container">
|
|
<div class="register-view">
|
|
<!-- Header -->
|
|
<div class="page-header">
|
|
<h1 class="page-title">
|
|
<i class="pi pi-wallet"></i>
|
|
Registrul de Casă și Bancă
|
|
</h1>
|
|
<p class="page-subtitle">
|
|
Vizualizați toate mișcările din conturile de bancă și casă
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Filters -->
|
|
<Card class="filters-card">
|
|
<template #content>
|
|
<div class="filters-grid">
|
|
<div class="filter-item">
|
|
<label>Data început</label>
|
|
<Calendar v-model="filters.dateFrom" dateFormat="dd/mm/yy" />
|
|
</div>
|
|
<div class="filter-item">
|
|
<label>Data sfârșit</label>
|
|
<Calendar v-model="filters.dateTo" dateFormat="dd/mm/yy" />
|
|
</div>
|
|
<div class="filter-item">
|
|
<label>Căutare partener</label>
|
|
<InputText v-model="filters.partnerName" placeholder="Nume partener..." />
|
|
</div>
|
|
<div class="filter-actions">
|
|
<Button
|
|
label="Aplică Filtre"
|
|
icon="pi pi-filter"
|
|
@click="applyFilters"
|
|
/>
|
|
<Button
|
|
label="Resetează"
|
|
icon="pi pi-times"
|
|
class="p-button-secondary"
|
|
@click="resetFilters"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
|
|
<!-- Summary Stats -->
|
|
<div class="summary-stats">
|
|
<Card class="stat-card">
|
|
<template #content>
|
|
<div class="stat-content">
|
|
<div class="stat-icon green">
|
|
<i class="pi pi-arrow-down"></i>
|
|
</div>
|
|
<div class="stat-details">
|
|
<h3 class="stat-value">{{ formatCurrency(treasuryStore.totals.total_incasari) }}</h3>
|
|
<p class="stat-label">Total Încasări</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
<Card class="stat-card">
|
|
<template #content>
|
|
<div class="stat-content">
|
|
<div class="stat-icon red">
|
|
<i class="pi pi-arrow-up"></i>
|
|
</div>
|
|
<div class="stat-details">
|
|
<h3 class="stat-value">{{ formatCurrency(treasuryStore.totals.total_plati) }}</h3>
|
|
<p class="stat-label">Total Plăți</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
</div>
|
|
|
|
<!-- Data Table -->
|
|
<Card class="data-card">
|
|
<template #content>
|
|
<DataTable
|
|
:value="treasuryStore.registers"
|
|
:loading="treasuryStore.isLoading"
|
|
:paginator="true"
|
|
:rows="pagination.rows"
|
|
:total-records="treasuryStore.pagination.totalRecords"
|
|
:lazy="true"
|
|
@page="onPage"
|
|
class="p-datatable-sm"
|
|
:rowClass="getRowClass"
|
|
>
|
|
<Column field="dataact" header="Data">
|
|
<template #body="slotProps">
|
|
{{ formatDate(slotProps.data.dataact) }}
|
|
</template>
|
|
</Column>
|
|
<Column field="nract" header="Nr. Act" style="width: 100px" />
|
|
<Column field="nume" header="Partener" />
|
|
<Column field="nume_cont_bancar" header="Cont" />
|
|
<Column field="tip_registru" header="Tip">
|
|
<template #body="slotProps">
|
|
<Tag :value="slotProps.data.tip_registru" :severity="getRegisterSeverity(slotProps.data.tip_registru)" />
|
|
</template>
|
|
</Column>
|
|
<Column field="incasari" header="Încasări">
|
|
<template #body="slotProps">
|
|
<span class="text-success font-semibold" v-if="slotProps.data.incasari > 0">
|
|
{{ formatCurrency(slotProps.data.incasari, slotProps.data.valuta) }}
|
|
</span>
|
|
<span v-else>-</span>
|
|
</template>
|
|
</Column>
|
|
<Column field="plati" header="Plăți">
|
|
<template #body="slotProps">
|
|
<span class="text-error font-semibold" v-if="slotProps.data.plati > 0">
|
|
{{ formatCurrency(slotProps.data.plati, slotProps.data.valuta) }}
|
|
</span>
|
|
<span v-else>-</span>
|
|
</template>
|
|
</Column>
|
|
<Column field="sold" header="Sold">
|
|
<template #body="slotProps">
|
|
<span :class="slotProps.data.sold >= 0 ? 'text-success font-semibold' : 'text-error font-semibold'">
|
|
{{ formatCurrency(slotProps.data.sold, slotProps.data.valuta) }}
|
|
</span>
|
|
</template>
|
|
</Column>
|
|
<Column field="explicatia" header="Explicație" />
|
|
</DataTable>
|
|
</template>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from "vue";
|
|
import { useTreasuryStore } from "../stores/treasury";
|
|
import { useCompanyStore } from "../stores/companies";
|
|
import { format } from "date-fns";
|
|
import { ro } from "date-fns/locale";
|
|
|
|
const treasuryStore = useTreasuryStore();
|
|
const companyStore = useCompanyStore();
|
|
|
|
const filters = ref({
|
|
dateFrom: null,
|
|
dateTo: null,
|
|
partnerName: ""
|
|
});
|
|
|
|
const pagination = ref({
|
|
page: 0,
|
|
rows: 50
|
|
});
|
|
|
|
const formatCurrency = (amount, currency = 'RON') => {
|
|
if (!amount) return "0,00 " + currency;
|
|
return new Intl.NumberFormat("ro-RO", {
|
|
style: "currency",
|
|
currency: currency
|
|
}).format(amount);
|
|
};
|
|
|
|
const formatDate = (dateString) => {
|
|
if (!dateString) return "";
|
|
return format(new Date(dateString), "dd MMM yyyy", { locale: ro });
|
|
};
|
|
|
|
const getRowClass = (data) => {
|
|
return data.tip_registru.includes('BANCA') ? 'bank-row' : 'cash-row';
|
|
};
|
|
|
|
const getRegisterSeverity = (type) => {
|
|
if (type.includes('BANCA')) return 'info';
|
|
if (type.includes('CASA')) return 'warning';
|
|
return null;
|
|
};
|
|
|
|
const onPage = (event) => {
|
|
pagination.value = event;
|
|
loadData();
|
|
};
|
|
|
|
const applyFilters = () => {
|
|
pagination.value.page = 0;
|
|
loadData();
|
|
};
|
|
|
|
const resetFilters = () => {
|
|
filters.value = {
|
|
dateFrom: null,
|
|
dateTo: null,
|
|
partnerName: ""
|
|
};
|
|
loadData();
|
|
};
|
|
|
|
const loadData = async () => {
|
|
if (!companyStore.selectedCompany) return;
|
|
|
|
treasuryStore.setPagination(pagination.value);
|
|
|
|
await treasuryStore.loadBankCashRegister(
|
|
companyStore.selectedCompany.id_firma,
|
|
{
|
|
date_from: filters.value.dateFrom?.toISOString().split("T")[0],
|
|
date_to: filters.value.dateTo?.toISOString().split("T")[0],
|
|
partner_name: filters.value.partnerName
|
|
}
|
|
);
|
|
};
|
|
|
|
onMounted(() => {
|
|
if (companyStore.selectedCompany) {
|
|
loadData();
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* Container, Header, Filters - Use global .app-container, .page-header, .card patterns */
|
|
|
|
.filters-card {
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
/* Filters - Use global .form-row, .form-group patterns */
|
|
.filters-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 1.5rem;
|
|
align-items: end;
|
|
}
|
|
|
|
.filter-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.filter-item label {
|
|
font-weight: 600;
|
|
color: var(--text-color);
|
|
}
|
|
|
|
.filter-actions {
|
|
display: flex;
|
|
gap: 0.75rem;
|
|
justify-content: flex-start;
|
|
}
|
|
|
|
/* Summary Stats - Use global .metric-card pattern */
|
|
.summary-stats {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
gap: 1.5rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.stat-content {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
.stat-icon {
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.5rem;
|
|
color: white;
|
|
}
|
|
|
|
.stat-icon.green {
|
|
background: linear-gradient(135deg, var(--green-500), var(--green-600));
|
|
}
|
|
|
|
.stat-icon.red {
|
|
background: linear-gradient(135deg, var(--red-500), var(--red-600));
|
|
}
|
|
|
|
.stat-details h3 {
|
|
font-size: 1.5rem;
|
|
font-weight: 700;
|
|
margin: 0;
|
|
color: var(--text-color);
|
|
}
|
|
|
|
.stat-details p {
|
|
font-size: 0.875rem;
|
|
color: var(--text-color-secondary);
|
|
margin: 0.25rem 0 0 0;
|
|
}
|
|
|
|
/* Row styling for bank/cash register types - Defined globally in App.vue */
|
|
|
|
/* Responsive - Bank/Cash-specific adjustments */
|
|
@media (max-width: 768px) {
|
|
.filters-grid,
|
|
.summary-stats {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.filter-actions {
|
|
justify-content: stretch;
|
|
}
|
|
|
|
.filter-actions .p-button {
|
|
flex: 1;
|
|
}
|
|
}
|
|
</style> |