refactor(ui): aligne les composants de donnees sur le design system
Cartes, en-tetes, champs de filtre, tableaux, badges, paginations et indicateurs de chargement des tableaux de bord etaient proches mais jamais identiques (bordure presente ou absente, paddings et arrondis variables). Ils utilisent maintenant les classes communes. Les colonnes tronquees des tableaux sont elargies et les sept filtres des depenses tiennent sur une ligne, la largeur retrouvee le permettant. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg p-4">
|
<div class="card card-body">
|
||||||
<h3 class="text-sm font-medium text-gray-300 mb-4">Repartition par categorie</h3>
|
<h3 class="card-title block mb-4">Repartition par categorie</h3>
|
||||||
<div class="h-64">
|
<div class="h-64">
|
||||||
<Doughnut
|
<Doughnut
|
||||||
v-if="chartData.labels.length > 0"
|
v-if="chartData.labels.length > 0"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg overflow-hidden">
|
<div class="card">
|
||||||
<div class="px-4 py-3 border-b border-gray-700 flex items-center justify-between">
|
<div class="card-header">
|
||||||
<h3 class="text-sm font-medium text-gray-300">
|
<h3 class="card-title">
|
||||||
Detail des depenses
|
Detail des depenses
|
||||||
<span class="text-gray-500 font-normal ml-2">({{ depenses.length }} resultats)</span>
|
<span class="text-gray-500 font-normal ml-2">({{ depenses.length }} resultats)</span>
|
||||||
</h3>
|
</h3>
|
||||||
@@ -25,65 +25,64 @@
|
|||||||
Aucune depense trouvee avec les filtres actuels.
|
Aucune depense trouvee avec les filtres actuels.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="overflow-x-auto">
|
<div v-else class="table-wrap">
|
||||||
<table class="w-full text-sm">
|
<table class="table">
|
||||||
<thead class="bg-gray-800/50">
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-400 uppercase">Date</th>
|
<th>Date</th>
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-400 uppercase">Immeuble</th>
|
<th>Immeuble</th>
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-400 uppercase">Lot</th>
|
<th>Lot</th>
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-400 uppercase">Categorie</th>
|
<th>Categorie</th>
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-400 uppercase">Fournisseur</th>
|
<th>Fournisseur</th>
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-400 uppercase">Description</th>
|
<th>Description</th>
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-400 uppercase">Tag</th>
|
<th>Tag</th>
|
||||||
<th class="px-3 py-2 text-right text-xs font-medium text-gray-400 uppercase">Debit</th>
|
<th class="text-right">Debit</th>
|
||||||
<th class="px-3 py-2 text-right text-xs font-medium text-gray-400 uppercase">Credit</th>
|
<th class="text-right">Credit</th>
|
||||||
<th class="px-3 py-2 w-10"></th>
|
<th class="w-10"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="divide-y divide-gray-800">
|
<tbody>
|
||||||
<tr
|
<tr
|
||||||
v-for="dep in paginatedDepenses"
|
v-for="dep in paginatedDepenses"
|
||||||
:key="dep.id"
|
:key="dep.id"
|
||||||
class="hover:bg-gray-800/50"
|
|
||||||
>
|
>
|
||||||
<td class="px-3 py-2 text-gray-300 whitespace-nowrap">
|
<td class="text-gray-300 whitespace-nowrap">
|
||||||
{{ formatDate(dep.document_date) }}
|
{{ formatDate(dep.document_date) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-3 py-2 text-gray-400 whitespace-nowrap">
|
<td class="text-gray-400 whitespace-nowrap">
|
||||||
{{ dep.immeuble_code }}
|
{{ dep.immeuble_code }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-3 py-2 text-gray-400">
|
<td class="text-gray-400">
|
||||||
{{ dep.lot_numero || '-' }}
|
{{ dep.lot_numero || '-' }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-3 py-2 text-gray-300">
|
<td class="text-gray-300">
|
||||||
<div class="text-xs text-gray-500">{{ formatCategorie(dep.categorie) }}</div>
|
<div class="text-xs text-gray-500">{{ formatCategorie(dep.categorie) }}</div>
|
||||||
<div v-if="dep.sous_categorie" class="text-xs text-gray-400 truncate max-w-[150px]">
|
<div v-if="dep.sous_categorie" class="text-xs text-gray-400 truncate max-w-[220px]">
|
||||||
{{ dep.sous_categorie }}
|
{{ dep.sous_categorie }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-3 py-2 text-white truncate max-w-[150px]">
|
<td class="text-white truncate max-w-[240px]">
|
||||||
{{ dep.fournisseur || '-' }}
|
{{ dep.fournisseur || '-' }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-3 py-2 text-gray-400 truncate max-w-[200px]">
|
<td class="text-gray-400 truncate max-w-[360px]">
|
||||||
{{ dep.description || '-' }}
|
{{ dep.description || '-' }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-3 py-2">
|
<td>
|
||||||
<span
|
<span
|
||||||
v-if="dep.tag_nom"
|
v-if="dep.tag_nom"
|
||||||
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-500/20 text-blue-400"
|
class="badge badge-info"
|
||||||
>
|
>
|
||||||
{{ dep.tag_nom }}
|
{{ dep.tag_nom }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="text-gray-600">-</span>
|
<span v-else class="text-gray-600">-</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-3 py-2 text-right text-red-400 font-mono whitespace-nowrap">
|
<td class="text-right text-red-400 font-mono whitespace-nowrap">
|
||||||
{{ dep.debit > 0 ? formatCurrency(dep.debit) : '-' }}
|
{{ dep.debit > 0 ? formatCurrency(dep.debit) : '-' }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-3 py-2 text-right text-green-400 font-mono whitespace-nowrap">
|
<td class="text-right text-green-400 font-mono whitespace-nowrap">
|
||||||
{{ dep.credit > 0 ? formatCurrency(dep.credit) : '-' }}
|
{{ dep.credit > 0 ? formatCurrency(dep.credit) : '-' }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-3 py-2 text-center">
|
<td class="text-center">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ path: '/documents/' + dep.document_id + '/edit', query: { highlight: 'operation', fournisseur: dep.fournisseur, description: dep.description } }"
|
:to="{ path: '/documents/' + dep.document_id + '/edit', query: { highlight: 'operation', fournisseur: dep.fournisseur, description: dep.description } }"
|
||||||
class="text-gray-500 hover:text-blue-400 transition-colors"
|
class="text-gray-500 hover:text-blue-400 transition-colors"
|
||||||
@@ -108,14 +107,14 @@
|
|||||||
<button
|
<button
|
||||||
@click="currentPage = 1"
|
@click="currentPage = 1"
|
||||||
:disabled="currentPage === 1"
|
:disabled="currentPage === 1"
|
||||||
class="px-2 py-1 text-xs rounded bg-gray-800 text-gray-400 hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn btn-sm btn-secondary"
|
||||||
>
|
>
|
||||||
<<
|
<<
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="currentPage--"
|
@click="currentPage--"
|
||||||
:disabled="currentPage === 1"
|
:disabled="currentPage === 1"
|
||||||
class="px-2 py-1 text-xs rounded bg-gray-800 text-gray-400 hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn btn-sm btn-secondary"
|
||||||
>
|
>
|
||||||
<
|
<
|
||||||
</button>
|
</button>
|
||||||
@@ -125,14 +124,14 @@
|
|||||||
<button
|
<button
|
||||||
@click="currentPage++"
|
@click="currentPage++"
|
||||||
:disabled="currentPage === totalPages"
|
:disabled="currentPage === totalPages"
|
||||||
class="px-2 py-1 text-xs rounded bg-gray-800 text-gray-400 hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn btn-sm btn-secondary"
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="currentPage = totalPages"
|
@click="currentPage = totalPages"
|
||||||
:disabled="currentPage === totalPages"
|
:disabled="currentPage === totalPages"
|
||||||
class="px-2 py-1 text-xs rounded bg-gray-800 text-gray-400 hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn btn-sm btn-secondary"
|
||||||
>
|
>
|
||||||
>>
|
>>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg p-4 space-y-4">
|
<div class="card card-body space-y-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h3 class="text-sm font-medium text-gray-300">Filtres</h3>
|
<h3 class="card-title">Filtres</h3>
|
||||||
<button
|
<button
|
||||||
v-if="hasActiveFilters"
|
v-if="hasActiveFilters"
|
||||||
@click="resetFilters"
|
@click="resetFilters"
|
||||||
@@ -11,14 +11,14 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3">
|
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 2xl:grid-cols-7 gap-3">
|
||||||
<!-- Immeuble -->
|
<!-- Immeuble -->
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-xs text-gray-400 mb-1">Immeuble</label>
|
<label class="block text-xs text-gray-400 mb-1">Immeuble</label>
|
||||||
<select
|
<select
|
||||||
v-model="filters.immeuble_id"
|
v-model="filters.immeuble_id"
|
||||||
@change="onImmeubleChange"
|
@change="onImmeubleChange"
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
>
|
>
|
||||||
<option :value="null">Tous</option>
|
<option :value="null">Tous</option>
|
||||||
<option v-for="imm in immeubles" :key="imm.id" :value="imm.id">
|
<option v-for="imm in immeubles" :key="imm.id" :value="imm.id">
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<select
|
<select
|
||||||
v-model="filters.lot_id"
|
v-model="filters.lot_id"
|
||||||
@change="emitFilters"
|
@change="emitFilters"
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
:disabled="!filters.immeuble_id"
|
:disabled="!filters.immeuble_id"
|
||||||
>
|
>
|
||||||
<option :value="null">Tous</option>
|
<option :value="null">Tous</option>
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
<select
|
<select
|
||||||
v-model="filters.categorie"
|
v-model="filters.categorie"
|
||||||
@change="emitFilters"
|
@change="emitFilters"
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
>
|
>
|
||||||
<option :value="null">Toutes</option>
|
<option :value="null">Toutes</option>
|
||||||
<option v-for="cat in categories" :key="cat" :value="cat">
|
<option v-for="cat in categories" :key="cat" :value="cat">
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
<select
|
<select
|
||||||
v-model="filters.tag_id"
|
v-model="filters.tag_id"
|
||||||
@change="emitFilters"
|
@change="emitFilters"
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
>
|
>
|
||||||
<option :value="null">Tous</option>
|
<option :value="null">Tous</option>
|
||||||
<option v-for="tag in tags" :key="tag.id" :value="tag.id">
|
<option v-for="tag in tags" :key="tag.id" :value="tag.id">
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
type="date"
|
type="date"
|
||||||
v-model="filters.date_debut"
|
v-model="filters.date_debut"
|
||||||
@change="emitFilters"
|
@change="emitFilters"
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -91,21 +91,21 @@
|
|||||||
type="date"
|
type="date"
|
||||||
v-model="filters.date_fin"
|
v-model="filters.date_fin"
|
||||||
@change="emitFilters"
|
@change="emitFilters"
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Fournisseur (recherche) -->
|
<!-- Fournisseur (recherche) -->
|
||||||
<div class="max-w-xs">
|
<div>
|
||||||
<label class="block text-xs text-gray-400 mb-1">Fournisseur</label>
|
<label class="block text-xs text-gray-400 mb-1">Fournisseur</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
v-model="filters.fournisseur"
|
v-model="filters.fournisseur"
|
||||||
@input="emitFilters"
|
@input="emitFilters"
|
||||||
placeholder="Rechercher..."
|
placeholder="Rechercher..."
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div
|
<div
|
||||||
v-for="kpi in kpis"
|
v-for="kpi in kpis"
|
||||||
:key="kpi.key"
|
:key="kpi.key"
|
||||||
class="bg-gray-900 rounded-lg p-4"
|
class="card card-body"
|
||||||
>
|
>
|
||||||
<div class="text-xs text-gray-400 mb-1">{{ kpi.label }}</div>
|
<div class="text-xs text-gray-400 mb-1">{{ kpi.label }}</div>
|
||||||
<div class="text-xl font-bold" :class="kpi.colorClass || 'text-white'">
|
<div class="text-xl font-bold" :class="kpi.colorClass || 'text-white'">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg p-4">
|
<div class="card card-body">
|
||||||
<h3 class="text-sm font-medium text-gray-300 mb-4">Evolution mensuelle</h3>
|
<h3 class="card-title block mb-4">Evolution mensuelle</h3>
|
||||||
<div class="h-64">
|
<div class="h-64">
|
||||||
<Bar
|
<Bar
|
||||||
v-if="chartData.labels.length > 0"
|
v-if="chartData.labels.length > 0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg p-4">
|
<div class="card card-body">
|
||||||
<h3 class="text-sm font-medium text-gray-300 mb-4">Top fournisseurs</h3>
|
<h3 class="card-title block mb-4">Top fournisseurs</h3>
|
||||||
<div class="h-64">
|
<div class="h-64">
|
||||||
<Bar
|
<Bar
|
||||||
v-if="chartData.labels.length > 0"
|
v-if="chartData.labels.length > 0"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||||
<!-- Revenus -->
|
<!-- Revenus -->
|
||||||
<div class="relative bg-gray-900 rounded-lg p-4 border border-gray-700 overflow-hidden">
|
<div class="card card-body relative">
|
||||||
<!-- Sparkline background -->
|
<!-- Sparkline background -->
|
||||||
<svg
|
<svg
|
||||||
v-if="data.revenus_history?.length"
|
v-if="data.revenus_history?.length"
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Depenses -->
|
<!-- Depenses -->
|
||||||
<div class="relative bg-gray-900 rounded-lg p-4 border border-gray-700 overflow-hidden">
|
<div class="card card-body relative">
|
||||||
<!-- Sparkline background -->
|
<!-- Sparkline background -->
|
||||||
<svg
|
<svg
|
||||||
v-if="data.depenses_history?.length"
|
v-if="data.depenses_history?.length"
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Impayes -->
|
<!-- Impayes -->
|
||||||
<div class="relative bg-gray-900 rounded-lg p-4 border border-gray-700 overflow-hidden">
|
<div class="card card-body relative">
|
||||||
<!-- Sparkline background -->
|
<!-- Sparkline background -->
|
||||||
<svg
|
<svg
|
||||||
v-if="data.impayes_history?.length"
|
v-if="data.impayes_history?.length"
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Solde -->
|
<!-- Solde -->
|
||||||
<div class="relative bg-gray-900 rounded-lg p-4 border border-gray-700 overflow-hidden">
|
<div class="card card-body relative">
|
||||||
<!-- Sparkline background -->
|
<!-- Sparkline background -->
|
||||||
<svg
|
<svg
|
||||||
v-if="data.solde_history?.length"
|
v-if="data.solde_history?.length"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg overflow-hidden border border-gray-700">
|
<div class="card">
|
||||||
<div class="px-4 py-3 border-b border-gray-700 flex items-center justify-between">
|
<div class="card-header">
|
||||||
<h2 class="text-sm font-medium text-gray-300">Vos immeubles</h2>
|
<h2 class="card-title">Vos immeubles</h2>
|
||||||
<button
|
<button
|
||||||
@click="$emit('view-all')"
|
@click="$emit('view-all')"
|
||||||
class="text-xs text-blue-400 hover:text-blue-300 transition-colors"
|
class="text-xs text-blue-400 hover:text-blue-300 transition-colors"
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="loading" class="p-8 text-center text-gray-500">
|
<div v-if="loading" class="p-8 text-center text-gray-500">
|
||||||
<div class="inline-block animate-spin rounded-full h-6 w-6 border-2 border-gray-600 border-t-blue-400"></div>
|
<div class="spinner h-6 w-6"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="immeubles.length === 0" class="p-8 text-center text-gray-500">
|
<div v-else-if="immeubles.length === 0" class="p-8 text-center text-gray-500">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg overflow-hidden border border-gray-700">
|
<div class="card">
|
||||||
<div class="px-4 py-3 border-b border-gray-700 flex items-center justify-between">
|
<div class="card-header">
|
||||||
<h2 class="text-sm font-medium text-gray-300">Evolution mensuelle</h2>
|
<h2 class="card-title">Evolution mensuelle</h2>
|
||||||
<div class="flex items-center gap-3 text-xs">
|
<div class="flex items-center gap-3 text-xs">
|
||||||
<span class="flex items-center gap-1">
|
<span class="flex items-center gap-1">
|
||||||
<span class="w-2 h-2 rounded-full bg-green-400"></span>
|
<span class="w-2 h-2 rounded-full bg-green-400"></span>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="loading" class="p-8 text-center text-gray-500">
|
<div v-if="loading" class="p-8 text-center text-gray-500">
|
||||||
<div class="inline-block animate-spin rounded-full h-6 w-6 border-2 border-gray-600 border-t-blue-400"></div>
|
<div class="spinner h-6 w-6"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="trends.length === 0" class="p-8 text-center text-gray-500">
|
<div v-else-if="trends.length === 0" class="p-8 text-center text-gray-500">
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg overflow-hidden border border-gray-700">
|
<div class="card">
|
||||||
<div class="px-4 py-3 border-b border-gray-700 flex items-center justify-between">
|
<div class="card-header">
|
||||||
<h2 class="text-sm font-medium text-gray-300">Derniers loyers</h2>
|
<h2 class="card-title">Derniers loyers</h2>
|
||||||
<span class="text-xs text-gray-500">{{ revenus.length }} entrees</span>
|
<span class="text-xs text-gray-500">{{ revenus.length }} entrees</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="loading" class="p-8 text-center text-gray-500">
|
<div v-if="loading" class="p-8 text-center text-gray-500">
|
||||||
<div class="inline-block animate-spin rounded-full h-6 w-6 border-2 border-gray-600 border-t-blue-400"></div>
|
<div class="spinner h-6 w-6"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="revenus.length === 0" class="p-8 text-center text-gray-500">
|
<div v-else-if="revenus.length === 0" class="p-8 text-center text-gray-500">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg p-4 border border-gray-700">
|
<div class="card card-body">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<h3 class="text-sm font-medium text-white">Filtres</h3>
|
<h3 class="text-sm font-medium text-white">Filtres</h3>
|
||||||
<button
|
<button
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<select
|
<select
|
||||||
v-model="filters.immeuble_id"
|
v-model="filters.immeuble_id"
|
||||||
@change="emitFilters"
|
@change="emitFilters"
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
>
|
>
|
||||||
<option :value="null">Tous</option>
|
<option :value="null">Tous</option>
|
||||||
<option
|
<option
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
<select
|
<select
|
||||||
v-model="filters.type_ligne"
|
v-model="filters.type_ligne"
|
||||||
@change="emitFilters"
|
@change="emitFilters"
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
>
|
>
|
||||||
<option :value="null">Tous</option>
|
<option :value="null">Tous</option>
|
||||||
<option value="loyer">Loyer</option>
|
<option value="loyer">Loyer</option>
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
type="date"
|
type="date"
|
||||||
v-model="filters.date_debut"
|
v-model="filters.date_debut"
|
||||||
@change="emitFilters"
|
@change="emitFilters"
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
type="date"
|
type="date"
|
||||||
v-model="filters.date_fin"
|
v-model="filters.date_fin"
|
||||||
@change="emitFilters"
|
@change="emitFilters"
|
||||||
class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-white focus:outline-none focus:border-blue-500"
|
class="input"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
v-model="filters.impayes_only"
|
v-model="filters.impayes_only"
|
||||||
@change="emitFilters"
|
@change="emitFilters"
|
||||||
class="w-4 h-4 rounded bg-gray-800 border-gray-700 text-amber-500 focus:ring-amber-500 focus:ring-offset-gray-900"
|
class="w-4 h-4 rounded border-gray-700 accent-blue-500 [color-scheme:dark]"
|
||||||
/>
|
/>
|
||||||
<span class="text-sm text-gray-300">Impayes uniquement</span>
|
<span class="text-sm text-gray-300">Impayes uniquement</span>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg p-4 border border-gray-700">
|
<div class="card card-body">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<h3 class="text-sm font-medium text-white">Revenus par immeuble</h3>
|
<h3 class="text-sm font-medium text-white">Revenus par immeuble</h3>
|
||||||
<span class="text-xs text-gray-500">{{ data.length }} immeubles</span>
|
<span class="text-xs text-gray-500">{{ data.length }} immeubles</span>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
|
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
|
||||||
<!-- Total Revenus -->
|
<!-- Total Revenus -->
|
||||||
<div class="bg-gray-900 rounded-lg p-4 border border-gray-700">
|
<div class="card card-body">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<span class="text-xs text-gray-400 uppercase tracking-wide">Total Revenus</span>
|
<span class="text-xs text-gray-400 uppercase tracking-wide">Total Revenus</span>
|
||||||
<svg class="w-4 h-4 text-green-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg class="w-4 h-4 text-green-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Regles -->
|
<!-- Regles -->
|
||||||
<div class="bg-gray-900 rounded-lg p-4 border border-gray-700">
|
<div class="card card-body">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<span class="text-xs text-gray-400 uppercase tracking-wide">Regles</span>
|
<span class="text-xs text-gray-400 uppercase tracking-wide">Regles</span>
|
||||||
<svg class="w-4 h-4 text-blue-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg class="w-4 h-4 text-blue-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Impayes -->
|
<!-- Impayes -->
|
||||||
<div class="bg-gray-900 rounded-lg p-4 border border-gray-700">
|
<div class="card card-body">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<span class="text-xs text-gray-400 uppercase tracking-wide">Impayes</span>
|
<span class="text-xs text-gray-400 uppercase tracking-wide">Impayes</span>
|
||||||
<div
|
<div
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Taux Recouvrement -->
|
<!-- Taux Recouvrement -->
|
||||||
<div class="bg-gray-900 rounded-lg p-4 border border-gray-700">
|
<div class="card card-body">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<span class="text-xs text-gray-400 uppercase tracking-wide">Recouvrement</span>
|
<span class="text-xs text-gray-400 uppercase tracking-wide">Recouvrement</span>
|
||||||
<svg class="w-4 h-4 text-purple-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg class="w-4 h-4 text-purple-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Locataires Actifs -->
|
<!-- Locataires Actifs -->
|
||||||
<div class="bg-gray-900 rounded-lg p-4 border border-gray-700">
|
<div class="card card-body">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<span class="text-xs text-gray-400 uppercase tracking-wide">Locataires</span>
|
<span class="text-xs text-gray-400 uppercase tracking-wide">Locataires</span>
|
||||||
<svg class="w-4 h-4 text-cyan-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg class="w-4 h-4 text-cyan-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Lots Occupes -->
|
<!-- Lots Occupes -->
|
||||||
<div class="bg-gray-900 rounded-lg p-4 border border-gray-700">
|
<div class="card card-body">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<span class="text-xs text-gray-400 uppercase tracking-wide">Lots</span>
|
<span class="text-xs text-gray-400 uppercase tracking-wide">Lots</span>
|
||||||
<svg class="w-4 h-4 text-pink-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg class="w-4 h-4 text-pink-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg p-4 border border-gray-700">
|
<div class="card card-body">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<h3 class="text-sm font-medium text-white">Evolution mensuelle des revenus</h3>
|
<h3 class="text-sm font-medium text-white">Evolution mensuelle des revenus</h3>
|
||||||
<div class="flex items-center gap-4 text-xs">
|
<div class="flex items-center gap-4 text-xs">
|
||||||
|
|||||||
@@ -1,23 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg border border-gray-700 overflow-hidden">
|
<div class="card">
|
||||||
<div class="p-4 border-b border-gray-700">
|
<div class="card-header">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center gap-2">
|
||||||
<div class="flex items-center gap-2">
|
<h3 class="card-title">Detail des revenus</h3>
|
||||||
<h3 class="text-sm font-medium text-white">Detail des revenus</h3>
|
<span class="text-xs text-gray-500">({{ revenus.length }} lignes)</span>
|
||||||
<span class="text-xs text-gray-500">({{ revenus.length }} lignes)</span>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
@click="exportCsv"
|
|
||||||
class="text-xs text-blue-400 hover:text-blue-300 transition-colors"
|
|
||||||
>
|
|
||||||
Exporter CSV
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
@click="exportCsv"
|
||||||
|
class="text-xs text-blue-400 hover:text-blue-300 transition-colors"
|
||||||
|
>
|
||||||
|
Exporter CSV
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Loading -->
|
<!-- Loading -->
|
||||||
<div v-if="isLoading" class="p-8 text-center text-gray-500">
|
<div v-if="isLoading" class="empty-state">
|
||||||
<svg class="animate-spin h-6 w-6 mx-auto mb-2" fill="none" viewBox="0 0 24 24">
|
<svg class="animate-spin h-6 w-6 mx-auto mb-2 text-blue-400" fill="none" viewBox="0 0 24 24">
|
||||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -25,60 +23,59 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Table -->
|
<!-- Table -->
|
||||||
<div v-else-if="revenus.length > 0" class="overflow-x-auto">
|
<div v-else-if="revenus.length > 0" class="table-wrap">
|
||||||
<table class="w-full text-sm">
|
<table class="table">
|
||||||
<thead class="bg-gray-800/50 text-gray-400 text-xs uppercase">
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-4 py-3 text-left">Date</th>
|
<th>Date</th>
|
||||||
<th class="px-4 py-3 text-left">Locataire</th>
|
<th>Locataire</th>
|
||||||
<th class="px-4 py-3 text-left">Lot</th>
|
<th>Lot</th>
|
||||||
<th class="px-4 py-3 text-left">Type</th>
|
<th>Type</th>
|
||||||
<th class="px-4 py-3 text-right">Loyers</th>
|
<th class="text-right">Loyers</th>
|
||||||
<th class="px-4 py-3 text-right">Taxes</th>
|
<th class="text-right">Taxes</th>
|
||||||
<th class="px-4 py-3 text-right">Total</th>
|
<th class="text-right">Total</th>
|
||||||
<th class="px-4 py-3 text-right">Regle</th>
|
<th class="text-right">Regle</th>
|
||||||
<th class="px-4 py-3 text-right">Impaye</th>
|
<th class="text-right">Impaye</th>
|
||||||
<th class="px-4 py-3 w-10"></th>
|
<th class="w-10"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="divide-y divide-gray-800">
|
<tbody>
|
||||||
<tr
|
<tr
|
||||||
v-for="revenu in paginatedRevenus"
|
v-for="revenu in paginatedRevenus"
|
||||||
:key="revenu.id"
|
:key="revenu.id"
|
||||||
class="hover:bg-gray-800/30 transition-colors"
|
|
||||||
>
|
>
|
||||||
<td class="px-4 py-3 text-gray-300 whitespace-nowrap">
|
<td class="text-gray-300 whitespace-nowrap">
|
||||||
{{ formatDate(revenu.document_date) }}
|
{{ formatDate(revenu.document_date) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-white font-medium max-w-[200px] truncate" :title="revenu.locataire_nom">
|
<td class="text-white font-medium max-w-[280px] truncate" :title="revenu.locataire_nom">
|
||||||
{{ revenu.locataire_nom }}
|
{{ revenu.locataire_nom }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-gray-400 whitespace-nowrap" :title="getImmeubleName(revenu)">
|
<td class="text-gray-400 whitespace-nowrap" :title="getImmeubleName(revenu)">
|
||||||
{{ getImmeubleName(revenu) }} / {{ revenu.lot_numero }}
|
{{ getImmeubleName(revenu) }} / {{ revenu.lot_numero }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3">
|
<td>
|
||||||
<span :class="getTypeBadgeClass(revenu.type_ligne)">
|
<span :class="getTypeBadgeClass(revenu.type_ligne)">
|
||||||
{{ revenu.type_ligne }}
|
{{ revenu.type_ligne }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-right text-gray-300 whitespace-nowrap">
|
<td class="text-right text-gray-300 whitespace-nowrap">
|
||||||
{{ formatAmount(revenu.loyers) }}
|
{{ formatAmount(revenu.loyers) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-right text-gray-400 whitespace-nowrap">
|
<td class="text-right text-gray-400 whitespace-nowrap">
|
||||||
{{ formatAmount(revenu.taxes) }}
|
{{ formatAmount(revenu.taxes) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-right text-green-400 font-medium whitespace-nowrap">
|
<td class="text-right text-green-400 font-medium whitespace-nowrap">
|
||||||
{{ formatAmount(revenu.total) }}
|
{{ formatAmount(revenu.total) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-right text-blue-400 whitespace-nowrap">
|
<td class="text-right text-blue-400 whitespace-nowrap">
|
||||||
{{ formatAmount(revenu.regles) }}
|
{{ formatAmount(revenu.regles) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-right whitespace-nowrap">
|
<td class="text-right whitespace-nowrap">
|
||||||
<span :class="revenu.impayes > 0 ? 'text-amber-400 font-medium' : 'text-gray-500'">
|
<span :class="revenu.impayes > 0 ? 'text-amber-400 font-medium' : 'text-gray-500'">
|
||||||
{{ formatAmount(revenu.impayes) }}
|
{{ formatAmount(revenu.impayes) }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-center">
|
<td class="text-center">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ path: '/documents/' + revenu.document_id + '/edit', query: { highlight: 'locataire', lot_numero: revenu.lot_numero, locataire_nom: revenu.locataire_nom } }"
|
:to="{ path: '/documents/' + revenu.document_id + '/edit', query: { highlight: 'locataire', lot_numero: revenu.lot_numero, locataire_nom: revenu.locataire_nom } }"
|
||||||
class="text-gray-500 hover:text-blue-400 transition-colors"
|
class="text-gray-500 hover:text-blue-400 transition-colors"
|
||||||
@@ -95,12 +92,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty state -->
|
<!-- Empty state -->
|
||||||
<div v-else class="p-8 text-center text-gray-500">
|
<div v-else class="empty-state">
|
||||||
Aucun revenu trouve
|
Aucun revenu trouve
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
<div v-if="revenus.length > pageSize" class="p-4 border-t border-gray-700 flex items-center justify-between">
|
<div v-if="revenus.length > pageSize" class="card-header border-b-0 border-t border-gray-700">
|
||||||
<div class="text-xs text-gray-500">
|
<div class="text-xs text-gray-500">
|
||||||
Affichage {{ startIndex + 1 }} - {{ endIndex }} sur {{ revenus.length }}
|
Affichage {{ startIndex + 1 }} - {{ endIndex }} sur {{ revenus.length }}
|
||||||
</div>
|
</div>
|
||||||
@@ -108,14 +105,14 @@
|
|||||||
<button
|
<button
|
||||||
@click="currentPage = 1"
|
@click="currentPage = 1"
|
||||||
:disabled="currentPage === 1"
|
:disabled="currentPage === 1"
|
||||||
class="px-2 py-1 text-xs rounded bg-gray-800 text-gray-400 hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn btn-sm btn-secondary"
|
||||||
>
|
>
|
||||||
«
|
«
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="currentPage--"
|
@click="currentPage--"
|
||||||
:disabled="currentPage === 1"
|
:disabled="currentPage === 1"
|
||||||
class="px-2 py-1 text-xs rounded bg-gray-800 text-gray-400 hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn btn-sm btn-secondary"
|
||||||
>
|
>
|
||||||
‹
|
‹
|
||||||
</button>
|
</button>
|
||||||
@@ -125,14 +122,14 @@
|
|||||||
<button
|
<button
|
||||||
@click="currentPage++"
|
@click="currentPage++"
|
||||||
:disabled="currentPage === totalPages"
|
:disabled="currentPage === totalPages"
|
||||||
class="px-2 py-1 text-xs rounded bg-gray-800 text-gray-400 hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn btn-sm btn-secondary"
|
||||||
>
|
>
|
||||||
›
|
›
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="currentPage = totalPages"
|
@click="currentPage = totalPages"
|
||||||
:disabled="currentPage === totalPages"
|
:disabled="currentPage === totalPages"
|
||||||
class="px-2 py-1 text-xs rounded bg-gray-800 text-gray-400 hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
class="btn btn-sm btn-secondary"
|
||||||
>
|
>
|
||||||
»
|
»
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-900 rounded-lg p-4 border border-gray-700">
|
<div class="card card-body">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<h3 class="text-sm font-medium text-white">Locataires avec impayes</h3>
|
<h3 class="text-sm font-medium text-white">Locataires avec impayes</h3>
|
||||||
|
|||||||
Reference in New Issue
Block a user