feat(dashboard): fix logout flow and redesign executive dashboard with real live data, charts and feeds
deploy-chabokan / deploy (push) Canceled after 0s

This commit is contained in:
2026-08-30 09:29:26 +03:30
parent b0980f1448
commit 9ec5e22138
9 changed files with 909 additions and 123 deletions
@@ -0,0 +1,117 @@
<script setup>
import { useLayout } from '@/layout/composables/layout';
import { computed, onMounted, ref, watch } from 'vue';
const props = defineProps({
statusStats: {
type: Array,
default: () => []
},
loading: {
type: Boolean,
default: false
}
});
const { isDarkTheme } = useLayout();
const chartData = ref(null);
const chartOptions = ref(null);
const defaultColors = ['#10b981', '#3b82f6', '#f59e0b', '#8b5cf6', '#ec4899', '#06b6d4', '#64748b'];
function updateChart() {
const statuses = props.statusStats || [];
const labels = statuses.length > 0 ? statuses.map((s) => s.name) : ['نامشخص'];
const data = statuses.length > 0 ? statuses.map((s) => s.count) : [0];
const colors = statuses.map((s, i) => s.color || defaultColors[i % defaultColors.length]);
chartData.value = {
labels: labels,
datasets: [
{
data: data,
backgroundColor: colors,
borderWidth: 2,
borderColor: isDarkTheme.value ? '#18181b' : '#ffffff'
}
]
};
chartOptions.value = {
maintainAspectRatio: false,
responsive: true,
plugins: {
legend: {
position: 'bottom',
rtl: true,
labels: {
usePointStyle: true,
pointStyle: 'circle',
padding: 16,
font: {
family: 'Estedad',
size: 12
}
}
},
tooltip: {
rtl: true,
titleFont: { family: 'Estedad', size: 13 },
bodyFont: { family: 'Estedad', size: 12 },
callbacks: {
label: function (context) {
const count = context.parsed;
const statusItem = statuses[context.dataIndex];
const pct = statusItem?.percentage !== undefined ? ` (${statusItem.percentage}٪)` : '';
return `${context.label}: ${Number(count).toLocaleString('fa-IR')} ملک${pct}`;
}
}
}
},
cutout: '65%'
};
}
watch(() => props.statusStats, () => {
updateChart();
}, { deep: true });
watch(isDarkTheme, () => {
updateChart();
});
onMounted(() => {
updateChart();
});
</script>
<template>
<div class="card h-full p-5 border border-surface-200 dark:border-surface-800 rounded-2xl bg-surface-0 dark:bg-surface-900">
<div class="flex justify-between items-center mb-4">
<div>
<h3 class="font-bold text-lg text-surface-900 dark:text-surface-0 mb-1">وضعیت اسناد و املاک</h3>
<p class="text-xs text-muted-color">تفکیک املاک بر اساس وضعیت سند و مالکیت</p>
</div>
<div class="flex items-center gap-2">
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium bg-emerald-50 dark:bg-emerald-950/40 text-emerald-600 dark:text-emerald-400">
<i class="pi pi-check-circle text-[10px]"></i>
وضعیت‌ها
</span>
</div>
</div>
<div v-if="loading" class="h-72 flex items-center justify-center">
<i class="pi pi-spin pi-spinner text-primary text-3xl"></i>
</div>
<div v-else-if="!statusStats || statusStats.length === 0" class="h-72 flex flex-col items-center justify-center text-muted-color">
<i class="pi pi-chart-pie text-4xl mb-2 opacity-40"></i>
<span class="text-sm">اطلاعات وضعیت املاک ثبت نشده است</span>
</div>
<div v-else class="h-72">
<Chart type="doughnut" :data="chartData" :options="chartOptions" class="h-full w-full" />
</div>
</div>
</template>