feat(dashboard): fix logout flow and redesign executive dashboard with real live data, charts and feeds
deploy-chabokan / deploy (push) Canceled after 0s
deploy-chabokan / deploy (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router';
|
||||
import { parseDateToJalali } from '@/utils/jalali';
|
||||
|
||||
const props = defineProps({
|
||||
transactions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
warehouseFlow: {
|
||||
type: Object,
|
||||
default: () => ({ inCount: 0, outCount: 0, inQuantity: 0, outQuantity: 0 })
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
function viewAllTransactions() {
|
||||
router.push('/warehouse-items/transactions');
|
||||
}
|
||||
|
||||
function createTransaction() {
|
||||
router.push('/warehouse-items/create-transaction');
|
||||
}
|
||||
|
||||
function formatJalaliDate(dateVal) {
|
||||
if (!dateVal) return '—';
|
||||
const j = parseDateToJalali(dateVal);
|
||||
if (!j) return '—';
|
||||
return `${j.jy}/${String(j.jm).padStart(2, '0')}/${String(j.jd).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
const formatNumber = (num) => {
|
||||
if (num === null || num === undefined) return '۰';
|
||||
return Number(num).toLocaleString('fa-IR');
|
||||
};
|
||||
</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 flex flex-col justify-between">
|
||||
<div>
|
||||
<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>
|
||||
<Button
|
||||
label="مشاهده همه"
|
||||
icon="pi pi-arrow-left"
|
||||
iconPos="right"
|
||||
size="small"
|
||||
text
|
||||
class="text-xs"
|
||||
@click="viewAllTransactions"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Flow stats summary banner -->
|
||||
<div class="grid grid-cols-2 gap-3 mb-4">
|
||||
<div class="p-3 rounded-xl bg-emerald-50/60 dark:bg-emerald-950/20 border border-emerald-200/50 dark:border-emerald-800/30 flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-8 h-8 rounded-lg bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 flex items-center justify-center">
|
||||
<i class="pi pi-arrow-down-left text-sm"></i>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-[11px] text-muted-color block">مجموع ورودی</span>
|
||||
<span class="text-xs font-bold text-emerald-700 dark:text-emerald-400">
|
||||
{{ formatNumber(warehouseFlow.inQuantity) }} واحد
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-xs font-medium text-emerald-600 dark:text-emerald-400">
|
||||
{{ formatNumber(warehouseFlow.inCount) }} تراکنش
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="p-3 rounded-xl bg-rose-50/60 dark:bg-rose-950/20 border border-rose-200/50 dark:border-rose-800/30 flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-8 h-8 rounded-lg bg-rose-500/10 text-rose-600 dark:text-rose-400 flex items-center justify-center">
|
||||
<i class="pi pi-arrow-up-right text-sm"></i>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-[11px] text-muted-color block">مجموع خروجی</span>
|
||||
<span class="text-xs font-bold text-rose-700 dark:text-rose-400">
|
||||
{{ formatNumber(warehouseFlow.outQuantity) }} واحد
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-xs font-medium text-rose-600 dark:text-rose-400">
|
||||
{{ formatNumber(warehouseFlow.outCount) }} تراکنش
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading -->
|
||||
<div v-if="loading" class="py-10 flex items-center justify-center">
|
||||
<i class="pi pi-spin pi-spinner text-primary text-2xl"></i>
|
||||
</div>
|
||||
|
||||
<!-- Empty -->
|
||||
<div v-else-if="!transactions || transactions.length === 0" class="py-10 flex flex-col items-center justify-center text-muted-color">
|
||||
<i class="pi pi-history text-4xl mb-2 opacity-40"></i>
|
||||
<span class="text-sm">تراکنش انباری ثبت نشده است</span>
|
||||
<Button label="ثبت اولین تراکنش" icon="pi pi-plus" size="small" class="mt-3" @click="createTransaction" />
|
||||
</div>
|
||||
|
||||
<!-- Transactions List -->
|
||||
<ul v-else class="list-none p-0 m-0 divide-y divide-surface-100 dark:divide-surface-800">
|
||||
<li
|
||||
v-for="tx in transactions"
|
||||
:key="tx._id"
|
||||
class="py-3 flex items-center justify-between gap-3 hover:bg-surface-50 dark:hover:bg-surface-800/50 px-2 rounded-xl transition-colors duration-150"
|
||||
>
|
||||
<div class="flex items-center gap-3 min-w-0">
|
||||
<div
|
||||
:class="[
|
||||
'w-9 h-9 rounded-xl flex items-center justify-center shrink-0 font-bold text-xs',
|
||||
tx.type === 'IN'
|
||||
? 'bg-emerald-100 dark:bg-emerald-500/20 text-emerald-600 dark:text-emerald-400'
|
||||
: 'bg-rose-100 dark:bg-rose-500/20 text-rose-600 dark:text-rose-400'
|
||||
]"
|
||||
>
|
||||
<i :class="['pi text-xs', tx.type === 'IN' ? 'pi-arrow-down' : 'pi-arrow-up']"></i>
|
||||
</div>
|
||||
|
||||
<div class="truncate">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-semibold text-surface-900 dark:text-surface-100 text-sm truncate">
|
||||
{{ tx.itemName }}
|
||||
</span>
|
||||
<span
|
||||
:class="[
|
||||
'px-1.5 py-0.2 rounded text-[10px] font-bold',
|
||||
tx.type === 'IN'
|
||||
? 'bg-emerald-100 dark:bg-emerald-900/40 text-emerald-700 dark:text-emerald-300'
|
||||
: 'bg-rose-100 dark:bg-rose-900/40 text-rose-700 dark:text-rose-300'
|
||||
]"
|
||||
>
|
||||
{{ tx.type === 'IN' ? 'ورود' : 'خروج' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-[11px] text-muted-color flex items-center gap-2 mt-0.5">
|
||||
<span>انبار: {{ tx.warehouseName }}</span>
|
||||
<span>•</span>
|
||||
<span>توسط: {{ tx.actorName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-left shrink-0">
|
||||
<div
|
||||
:class="[
|
||||
'font-bold text-sm font-mono',
|
||||
tx.type === 'IN' ? 'text-emerald-600 dark:text-emerald-400' : 'text-rose-600 dark:text-rose-400'
|
||||
]"
|
||||
>
|
||||
{{ tx.type === 'IN' ? '+' : '-' }}{{ formatNumber(tx.quantity) }} {{ tx.unit }}
|
||||
</div>
|
||||
<span class="text-[10px] text-muted-color font-mono block">
|
||||
{{ formatJalaliDate(tx.date) }}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user