feat(dashboard-solduri): Complete dashboard solduri v2 implementation
## Features - US-2001: Create reusable SolduriCompactCard component - US-2004: Solduri section on Desktop (top, without title) - US-2005: Remove MaturityAndDetailsCard from Dashboard - US-2006: Integrate Solduri data from dashboardStore - US-2007: Visual indicators for financial status - US-2008: Refresh button in Dashboard header ## UI Improvements - Desktop: 2x2 grid for solduri cards with larger breakdown fonts - Mobile: Single column layout with auto height - Theme persistence: synchronous initialization to prevent flash - Unified "Bonuri" icon (pi-shopping-bag) across all navigation ## Files Changed - New: SolduriCompactCard.vue - expandable cards for Trezorerie/Clienți/Furnizori/TVA - Modified: DashboardView.vue - integrated solduri section - Modified: index.html - theme init script - Modified: Mobile navigation components - icon consistency Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -128,7 +128,7 @@ export default {
|
||||
// PRINCIPALE: Dashboard, Bonuri
|
||||
const principaleItems = ref([
|
||||
{ to: '/dashboard', icon: 'pi pi-home', label: 'Dashboard', exactMatch: true },
|
||||
{ to: '/data-entry', icon: 'pi pi-receipt', label: 'Bonuri', exactMatch: false }
|
||||
{ to: '/data-entry', icon: 'pi pi-shopping-bag', label: 'Bonuri', exactMatch: false }
|
||||
]);
|
||||
|
||||
// RAPOARTE: Facturi, Balanță, Casa și Banca
|
||||
|
||||
374
src/modules/reports/components/solduri/SolduriCompactCard.vue
Normal file
374
src/modules/reports/components/solduri/SolduriCompactCard.vue
Normal file
@@ -0,0 +1,374 @@
|
||||
<template>
|
||||
<div
|
||||
class="solduri-compact-card"
|
||||
:class="[`solduri-compact-card--${type}`, { 'solduri-compact-card--expanded': isExpanded }]"
|
||||
@click="toggleExpanded"
|
||||
>
|
||||
<!-- Header: Label + Value -->
|
||||
<div class="solduri-compact-card__header">
|
||||
<div class="solduri-compact-card__content">
|
||||
<span class="solduri-compact-card__label">{{ label }}</span>
|
||||
<span class="solduri-compact-card__value" :class="valueColorClass">
|
||||
{{ formatCurrency(total) }}
|
||||
</span>
|
||||
</div>
|
||||
<i
|
||||
class="pi pi-chevron-down solduri-compact-card__chevron"
|
||||
:class="{ 'solduri-compact-card__chevron--expanded': isExpanded }"
|
||||
></i>
|
||||
</div>
|
||||
|
||||
<!-- Expandable Breakdown Section -->
|
||||
<div v-if="isExpanded && hasBreakdown" class="solduri-compact-card__breakdown">
|
||||
<!-- Trezorerie: Casa + Bancă -->
|
||||
<template v-if="type === 'trezorerie'">
|
||||
<!-- Casa Total -->
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">Casa</span>
|
||||
<span class="solduri-compact-card__breakdown-value">{{ formatCurrency(casaTotal) }}</span>
|
||||
</div>
|
||||
<!-- Sub-conturi Casa (imediat sub Casa) -->
|
||||
<template v-if="breakdown?.casa?.items?.length">
|
||||
<div
|
||||
v-for="(item, idx) in breakdown.casa.items"
|
||||
:key="`casa-${idx}`"
|
||||
class="solduri-compact-card__breakdown-subitem"
|
||||
>
|
||||
<span class="solduri-compact-card__breakdown-sublabel">
|
||||
{{ item.nume || `Cont ${item.cont}` }}
|
||||
</span>
|
||||
<span class="solduri-compact-card__breakdown-subvalue">{{ formatCurrency(item.sold) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Bancă Total -->
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">Bancă</span>
|
||||
<span class="solduri-compact-card__breakdown-value">{{ formatCurrency(bancaTotal) }}</span>
|
||||
</div>
|
||||
<!-- Sub-conturi Bancă (imediat sub Bancă) -->
|
||||
<template v-if="breakdown?.banca?.items?.length">
|
||||
<div
|
||||
v-for="(item, idx) in breakdown.banca.items"
|
||||
:key="`banca-${idx}`"
|
||||
class="solduri-compact-card__breakdown-subitem"
|
||||
>
|
||||
<span class="solduri-compact-card__breakdown-sublabel">
|
||||
{{ item.nume || `Cont ${item.cont}` }}
|
||||
</span>
|
||||
<span class="solduri-compact-card__breakdown-subvalue">{{ formatCurrency(item.sold) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- Clienți/Furnizori: Buckets (În termen, Restant) -->
|
||||
<template v-else-if="type === 'clienti' || type === 'furnizori'">
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">În termen</span>
|
||||
<span class="solduri-compact-card__breakdown-value">
|
||||
{{ formatCurrency(breakdown?.in_termen?.total || 0) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">Restant</span>
|
||||
<span class="solduri-compact-card__breakdown-value solduri-compact-card__breakdown-value--warning">
|
||||
{{ formatCurrency(breakdown?.restant?.total || 0) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- Perioade restante -->
|
||||
<template v-if="breakdown?.restant?.perioade">
|
||||
<div
|
||||
v-for="(value, key) in breakdown.restant.perioade"
|
||||
:key="key"
|
||||
class="solduri-compact-card__breakdown-subitem"
|
||||
>
|
||||
<span class="solduri-compact-card__breakdown-sublabel">{{ formatPeriodLabel(key) }}</span>
|
||||
<span class="solduri-compact-card__breakdown-subvalue">{{ formatCurrency(value) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- TVA: Simple display (no breakdown needed) -->
|
||||
<template v-else-if="type === 'tva'">
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">
|
||||
{{ total >= 0 ? 'TVA de recuperat' : 'TVA de plată' }}
|
||||
</span>
|
||||
<span
|
||||
class="solduri-compact-card__breakdown-value"
|
||||
:class="total >= 0 ? 'solduri-compact-card__breakdown-value--success' : 'solduri-compact-card__breakdown-value--danger'"
|
||||
>
|
||||
{{ formatCurrency(Math.abs(total)) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
// Type definitions
|
||||
type CardType = 'trezorerie' | 'clienti' | 'furnizori' | 'tva'
|
||||
|
||||
interface TrezorerieBreakdown {
|
||||
casa?: {
|
||||
total?: number
|
||||
items?: Array<{ nume?: string; cont?: string; sold: number }>
|
||||
}
|
||||
banca?: {
|
||||
total?: number
|
||||
items?: Array<{ nume?: string; cont?: string; sold: number }>
|
||||
}
|
||||
}
|
||||
|
||||
interface ClientiFurnizoriBreakdown {
|
||||
total?: number
|
||||
in_termen?: { total?: number }
|
||||
restant?: {
|
||||
total?: number
|
||||
perioade?: Record<string, number>
|
||||
}
|
||||
}
|
||||
|
||||
type BreakdownType = TrezorerieBreakdown | ClientiFurnizoriBreakdown | null
|
||||
|
||||
// Props
|
||||
const props = defineProps<{
|
||||
type: CardType
|
||||
total: number
|
||||
breakdown?: BreakdownType
|
||||
casaTotal?: number
|
||||
bancaTotal?: number
|
||||
}>()
|
||||
|
||||
// State
|
||||
const isExpanded = ref(false)
|
||||
|
||||
// Computed: Label based on type
|
||||
const label = computed(() => {
|
||||
const labels: Record<CardType, string> = {
|
||||
trezorerie: 'TREZORERIE',
|
||||
clienti: 'CLIENȚI',
|
||||
furnizori: 'FURNIZORI',
|
||||
tva: 'TVA'
|
||||
}
|
||||
return labels[props.type] || props.type.toUpperCase()
|
||||
})
|
||||
|
||||
// Computed: Value color class based on type and value
|
||||
const valueColorClass = computed(() => {
|
||||
if (props.type === 'tva') {
|
||||
return props.total >= 0
|
||||
? 'solduri-compact-card__value--success'
|
||||
: 'solduri-compact-card__value--danger'
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
// Computed: Check if breakdown data exists
|
||||
const hasBreakdown = computed(() => {
|
||||
if (props.type === 'trezorerie') {
|
||||
return props.casaTotal !== undefined || props.bancaTotal !== undefined || props.breakdown
|
||||
}
|
||||
if (props.type === 'clienti' || props.type === 'furnizori') {
|
||||
return props.breakdown !== null && props.breakdown !== undefined
|
||||
}
|
||||
if (props.type === 'tva') {
|
||||
return true // TVA always shows status
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// Methods
|
||||
const toggleExpanded = () => {
|
||||
if (hasBreakdown.value) {
|
||||
isExpanded.value = !isExpanded.value
|
||||
}
|
||||
}
|
||||
|
||||
const formatCurrency = (amount: number | undefined | null): string => {
|
||||
if (amount === undefined || amount === null) return '0 RON'
|
||||
return new Intl.NumberFormat('ro-RO', {
|
||||
style: 'currency',
|
||||
currency: 'RON',
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
}).format(amount)
|
||||
}
|
||||
|
||||
const formatPeriodLabel = (key: string): string => {
|
||||
const labelMap: Record<string, string> = {
|
||||
'7_zile': '7 zile',
|
||||
'14_zile': '14 zile',
|
||||
'30_zile': '30 zile',
|
||||
'60_zile': '60 zile',
|
||||
'90_zile': '90 zile',
|
||||
'peste_90_zile': 'Peste 90 zile'
|
||||
}
|
||||
return labelMap[key] || key
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* SolduriCompactCard - Compact card for 2x2 grid layout */
|
||||
|
||||
.solduri-compact-card {
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-md);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
min-height: 80px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.solduri-compact-card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.solduri-compact-card:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* Header Layout */
|
||||
.solduri-compact-card__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
/* Content */
|
||||
.solduri-compact-card__content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xs);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.solduri-compact-card__label {
|
||||
font-size: var(--text-xs);
|
||||
font-weight: var(--font-semibold);
|
||||
color: var(--color-text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.solduri-compact-card__value {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: var(--font-bold);
|
||||
color: var(--color-text);
|
||||
font-family: var(--font-mono, monospace);
|
||||
line-height: var(--leading-tight);
|
||||
}
|
||||
|
||||
/* Value color modifiers */
|
||||
.solduri-compact-card__value--success {
|
||||
color: var(--green-600);
|
||||
}
|
||||
|
||||
.solduri-compact-card__value--danger {
|
||||
color: var(--red-600);
|
||||
}
|
||||
|
||||
/* Chevron */
|
||||
.solduri-compact-card__chevron {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: var(--text-sm);
|
||||
transition: transform var(--transition-fast);
|
||||
}
|
||||
|
||||
.solduri-compact-card__chevron--expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Breakdown Section */
|
||||
.solduri-compact-card__breakdown {
|
||||
padding-top: var(--space-sm);
|
||||
border-top: 1px solid var(--surface-border);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: var(--space-xs) 0;
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-label {
|
||||
font-size: var(--text-base);
|
||||
color: var(--color-text-secondary);
|
||||
font-weight: var(--font-medium);
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-value {
|
||||
font-size: var(--text-base);
|
||||
font-weight: var(--font-semibold);
|
||||
color: var(--color-text);
|
||||
font-family: var(--font-mono, monospace);
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-value--success {
|
||||
color: var(--green-600);
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-value--danger {
|
||||
color: var(--red-600);
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-value--warning {
|
||||
color: var(--orange-600);
|
||||
}
|
||||
|
||||
/* Sub-items (indented) */
|
||||
.solduri-compact-card__breakdown-subitem {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: var(--space-xs) 0;
|
||||
padding-left: var(--space-md);
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-sublabel {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-subvalue {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--font-medium);
|
||||
color: var(--color-text);
|
||||
font-family: var(--font-mono, monospace);
|
||||
}
|
||||
|
||||
/* Responsive - Mobile */
|
||||
@media (max-width: 768px) {
|
||||
.solduri-compact-card {
|
||||
padding: var(--space-sm);
|
||||
min-height: 70px;
|
||||
}
|
||||
|
||||
.solduri-compact-card__value {
|
||||
font-size: var(--text-base);
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-subitem {
|
||||
padding-left: var(--space-sm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch target compliance - minimum 44x44px */
|
||||
@media (pointer: coarse) {
|
||||
.solduri-compact-card {
|
||||
min-height: 80px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -4,7 +4,9 @@
|
||||
v-if="isMobile"
|
||||
title="Dashboard"
|
||||
:show-menu="true"
|
||||
:actions="mobileTopBarActions"
|
||||
@menu-click="showDrawer = true"
|
||||
@action-click="handleMobileAction"
|
||||
/>
|
||||
|
||||
<!-- Mobile Drawer Menu (replaces old Sidebar) -->
|
||||
@@ -21,6 +23,16 @@
|
||||
<!-- Dashboard Header - only on desktop -->
|
||||
<div v-if="!isMobile" class="page-header">
|
||||
<h1 class="page-title">Dashboard</h1>
|
||||
<Button
|
||||
icon="pi pi-refresh"
|
||||
text
|
||||
rounded
|
||||
class="refresh-btn"
|
||||
:class="{ 'is-loading': isLoading }"
|
||||
@click="handleRefresh"
|
||||
v-tooltip.bottom="'Actualizează datele'"
|
||||
aria-label="Actualizează datele"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Company selection removed - now handled in header only -->
|
||||
@@ -28,8 +40,36 @@
|
||||
<!-- Secțiune Carduri Noi - Adăugare -->
|
||||
<div class="metrics-cards-section" v-if="!isLoading">
|
||||
<!-- Mobile: Swipeable KPI Cards Carousel -->
|
||||
<SwipeableCards v-if="isMobile" :totalCards="4" class="mobile-kpi-carousel">
|
||||
<!-- US-2002: 5 pages - first page is 2x2 grid with solduri, pages 2-5 are original graph cards -->
|
||||
<SwipeableCards v-if="isMobile" :totalCards="5" class="mobile-kpi-carousel">
|
||||
<!-- Page 1: Grid 2x2 cu Solduri Compacte -->
|
||||
<template #card-0>
|
||||
<div class="solduri-grid-2x2">
|
||||
<SolduriCompactCard
|
||||
type="trezorerie"
|
||||
:total="totalTrezorerie"
|
||||
:casaTotal="treasuryData?.breakdown?.casa?.total || 0"
|
||||
:bancaTotal="treasuryData?.breakdown?.banca?.total || 0"
|
||||
:breakdown="treasuryData?.breakdown"
|
||||
/>
|
||||
<SolduriCompactCard
|
||||
type="clienti"
|
||||
:total="netBalanceData?.clienti_total || 0"
|
||||
:breakdown="netBalanceData?.breakdown?.clienti"
|
||||
/>
|
||||
<SolduriCompactCard
|
||||
type="furnizori"
|
||||
:total="netBalanceData?.furnizori_total || 0"
|
||||
:breakdown="netBalanceData?.breakdown?.furnizori"
|
||||
/>
|
||||
<SolduriCompactCard
|
||||
type="tva"
|
||||
:total="tvaTotal"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Page 2: TreasuryDualCard (original graph card) -->
|
||||
<template #card-1>
|
||||
<TreasuryDualCard
|
||||
:casaTotal="treasuryData?.breakdown?.casa?.total || 0"
|
||||
:bancaTotal="treasuryData?.breakdown?.banca?.total || 0"
|
||||
@@ -45,7 +85,8 @@
|
||||
:previousSparklineLabels="previousSparklineLabels"
|
||||
/>
|
||||
</template>
|
||||
<template #card-1>
|
||||
<!-- Page 3: CashFlowMetricCard (original graph card) -->
|
||||
<template #card-2>
|
||||
<CashFlowMetricCard
|
||||
:inflowsValue="monthlyInflows"
|
||||
:outflowsValue="monthlyOutflows"
|
||||
@@ -59,7 +100,8 @@
|
||||
:previousSparklineLabels="previousSparklineLabels"
|
||||
/>
|
||||
</template>
|
||||
<template #card-2>
|
||||
<!-- Page 4: ClientiBalanceCard (original graph card) -->
|
||||
<template #card-3>
|
||||
<ClientiBalanceCard
|
||||
:total="netBalanceData?.clienti_total || 0"
|
||||
:trend="clientiTrend"
|
||||
@@ -70,7 +112,8 @@
|
||||
:breakdown="netBalanceData?.breakdown?.clienti"
|
||||
/>
|
||||
</template>
|
||||
<template #card-3>
|
||||
<!-- Page 5: FurnizoriBalanceCard (original graph card) -->
|
||||
<template #card-4>
|
||||
<FurnizoriBalanceCard
|
||||
:total="netBalanceData?.furnizori_total || 0"
|
||||
:trend="furnizoriTrend"
|
||||
@@ -83,8 +126,33 @@
|
||||
</template>
|
||||
</SwipeableCards>
|
||||
|
||||
<!-- Desktop: Grid layout -->
|
||||
<div v-else class="metrics-row">
|
||||
<!-- US-2004: Desktop Solduri Section (sus, fără titlu) -->
|
||||
<div v-if="!isMobile" class="desktop-solduri-section">
|
||||
<SolduriCompactCard
|
||||
type="trezorerie"
|
||||
:total="totalTrezorerie"
|
||||
:casaTotal="treasuryData?.breakdown?.casa?.total || 0"
|
||||
:bancaTotal="treasuryData?.breakdown?.banca?.total || 0"
|
||||
:breakdown="treasuryData?.breakdown"
|
||||
/>
|
||||
<SolduriCompactCard
|
||||
type="clienti"
|
||||
:total="netBalanceData?.clienti_total || 0"
|
||||
:breakdown="netBalanceData?.breakdown?.clienti"
|
||||
/>
|
||||
<SolduriCompactCard
|
||||
type="furnizori"
|
||||
:total="netBalanceData?.furnizori_total || 0"
|
||||
:breakdown="netBalanceData?.breakdown?.furnizori"
|
||||
/>
|
||||
<SolduriCompactCard
|
||||
type="tva"
|
||||
:total="tvaTotal"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Desktop: Grid layout (carduri grafice originale) -->
|
||||
<div v-if="!isMobile" class="metrics-row">
|
||||
<TreasuryDualCard
|
||||
:casaTotal="treasuryData?.breakdown?.casa?.total || 0"
|
||||
:bancaTotal="treasuryData?.breakdown?.banca?.total || 0"
|
||||
@@ -131,18 +199,6 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Desktop: Rând 2: Analiză comparativă și Date Detaliate (combinat) -->
|
||||
<div v-if="!isMobile" class="comparison-row">
|
||||
<MaturityAndDetailsCard
|
||||
:companyId="companyStore.selectedCompany?.id_firma"
|
||||
@periodChanged="handleMaturityPeriodChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dashboard Content -->
|
||||
<div class="dashboard-content">
|
||||
<!-- Componenta MaturityAndDetailsCard include acum și tabelul detaliat -->
|
||||
</div>
|
||||
|
||||
<!-- Loading State -->
|
||||
@@ -161,13 +217,14 @@
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useToast } from "primevue/usetoast";
|
||||
import Button from "primevue/button";
|
||||
// Import componente noi
|
||||
import MetricCard from "@reports/components/dashboard/cards/MetricCard.vue";
|
||||
import CashFlowMetricCard from "@reports/components/dashboard/cards/CashFlowMetricCard.vue";
|
||||
import MaturityAndDetailsCard from "@reports/components/dashboard/cards/MaturityAndDetailsCard.vue";
|
||||
import ClientiBalanceCard from "@reports/components/dashboard/cards/ClientiBalanceCard.vue";
|
||||
import FurnizoriBalanceCard from "@reports/components/dashboard/cards/FurnizoriBalanceCard.vue";
|
||||
import TreasuryDualCard from "@reports/components/dashboard/cards/TreasuryDualCard.vue";
|
||||
import SolduriCompactCard from "@reports/components/solduri/SolduriCompactCard.vue";
|
||||
// Mobile components
|
||||
import SwipeableCards from "@shared/components/mobile/SwipeableCards.vue";
|
||||
import MobileTopBar from "@shared/components/mobile/MobileTopBar.vue";
|
||||
@@ -205,12 +262,6 @@ const netBalanceData = ref(null);
|
||||
const selectedPeriod = ref("12m");
|
||||
const selectedChartType = ref("line");
|
||||
|
||||
// Handlers pentru schimbare perioadă
|
||||
const handleMaturityPeriodChange = (period) => {
|
||||
console.log("Maturity period changed:", period);
|
||||
// Trigger reload cu noua perioadă
|
||||
};
|
||||
|
||||
// Calculare trend bazată pe date reale din trends.raw
|
||||
const calculateTrend = (metric) => {
|
||||
if (!dashboardStore.trends?.raw) return null;
|
||||
@@ -406,6 +457,18 @@ const treasuryPreviousSparkline = computed(() =>
|
||||
const sparklineLabels = computed(() => getSparklineLabels());
|
||||
const previousSparklineLabels = computed(() => getPreviousSparklineLabels());
|
||||
|
||||
// US-2002: Computed properties for SolduriCompactCard grid
|
||||
const totalTrezorerie = computed(() => {
|
||||
const casaTotal = treasuryData.value?.breakdown?.casa?.total || 0;
|
||||
const bancaTotal = treasuryData.value?.breakdown?.banca?.total || 0;
|
||||
return casaTotal + bancaTotal;
|
||||
});
|
||||
|
||||
const tvaTotal = computed(() => {
|
||||
// TVA from dashboard summary if available, otherwise default to 0
|
||||
return dashboardStore.summary?.tva_sold || 0;
|
||||
});
|
||||
|
||||
// Casa and Bancă specific trends and sparklines
|
||||
const casaTrend = computed(() => {
|
||||
// Calculate trend based on Casa proportion of treasury
|
||||
@@ -522,6 +585,29 @@ const handleLogout = async () => {
|
||||
router.push('/login');
|
||||
};
|
||||
|
||||
// US-2008: Mobile top bar actions with refresh button
|
||||
const mobileTopBarActions = computed(() => [
|
||||
{
|
||||
id: 'refresh',
|
||||
icon: isLoading.value ? 'pi pi-spin pi-refresh' : 'pi pi-refresh',
|
||||
label: 'Actualizează',
|
||||
tooltip: 'Actualizează datele'
|
||||
}
|
||||
]);
|
||||
|
||||
// US-2008: Handle mobile action clicks
|
||||
const handleMobileAction = async (action) => {
|
||||
if (action.id === 'refresh') {
|
||||
await handleRefresh();
|
||||
}
|
||||
};
|
||||
|
||||
// US-2008: Handle refresh button click (shared between mobile and desktop)
|
||||
const handleRefresh = async () => {
|
||||
if (isLoading.value) return; // Prevent multiple clicks during loading
|
||||
await loadDashboardData();
|
||||
};
|
||||
|
||||
// Computed property pentru luna curentă - folosește perioada din period selector
|
||||
const currentMonthLabel = computed(() => {
|
||||
// Prioritate: period selector > dashboard current period > loading
|
||||
@@ -990,6 +1076,30 @@ onUnmounted(() => {
|
||||
padding-bottom: 56px; /* MobileBottomNav height */
|
||||
}
|
||||
|
||||
/* US-2008: Refresh Button Styles */
|
||||
.refresh-btn {
|
||||
color: var(--color-text-secondary);
|
||||
transition: color var(--transition-fast), transform var(--transition-fast);
|
||||
}
|
||||
|
||||
.refresh-btn:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
/* US-2008: Rotating animation during loading */
|
||||
.refresh-btn.is-loading .pi-refresh {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Company Selection */
|
||||
.company-selection {
|
||||
max-width: 500px;
|
||||
@@ -1006,13 +1116,6 @@ onUnmounted(() => {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Dashboard Content */
|
||||
.dashboard-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xl);
|
||||
}
|
||||
|
||||
/* Dashboard Sections */
|
||||
.dashboard-section {
|
||||
background: var(--color-bg);
|
||||
@@ -1273,27 +1376,29 @@ onUnmounted(() => {
|
||||
padding: 0 var(--space-md);
|
||||
}
|
||||
|
||||
/* US-2004: Desktop Solduri Section - 2x2 grid (2 cards per row) */
|
||||
.desktop-solduri-section {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: var(--space-md);
|
||||
margin-bottom: var(--space-lg);
|
||||
}
|
||||
|
||||
/* Metrics Cards Layout - Component-specific grid layouts */
|
||||
.metrics-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
gap: var(--space-md);
|
||||
margin-bottom: var(--space-lg);
|
||||
}
|
||||
|
||||
.analysis-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
gap: var(--space-md);
|
||||
margin-bottom: var(--space-lg);
|
||||
}
|
||||
|
||||
.comparison-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
/* Responsive - All breakpoints consolidated */
|
||||
@media (max-width: 1200px) {
|
||||
@@ -1325,4 +1430,17 @@ onUnmounted(() => {
|
||||
.mobile-kpi-carousel {
|
||||
margin-bottom: var(--space-lg);
|
||||
}
|
||||
|
||||
/* US-2002: Solduri list for mobile first page - 1 card per row */
|
||||
.solduri-grid-2x2 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-xs);
|
||||
}
|
||||
|
||||
/* Touch target compliance - SolduriCompactCard handles its own min-height */
|
||||
.solduri-grid-2x2 > * {
|
||||
/* Height auto - only as tall as content needs */
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user