Files
CRM_Montzar/apps/web/src/views/treasury/TreasuryHomeView.vue
T

163 lines
6.0 KiB
Vue
Raw Normal View History

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import {
Alert as AAlert,
Card as ACard,
Col as ACol,
Divider as ADivider,
Empty as AEmpty,
Flex as AFlex,
List as AList,
Row as ARow,
Statistic as AStatistic,
Typography,
} from 'ant-design-vue';
import { api } from '@/lib/api';
import type { TreasuryDashboardDto } from '@mento/shared';
import TreasuryNav from '@/components/treasury/TreasuryNav.vue';
import { toman } from './treasury-format';
const { Title: ATypographyTitle, Text: ATypographyText } = Typography;
const AListItem = AList.Item;
const AListItemMeta = AList.Item.Meta;
const data = ref<TreasuryDashboardDto | null>(null);
const error = ref('');
const cards = [
{ key: 'bookedIncome', label: 'درآمد ثبت‌شده', hint: 'تعهدی' },
{ key: 'actualReceipts', label: 'دریافت واقعی', hint: 'ورود به حساب' },
{ key: 'bookedExpense', label: 'هزینه ثبت‌شده', hint: 'تعهدی' },
{ key: 'actualPayments', label: 'پرداخت واقعی', hint: 'خروج از حساب' },
{ key: 'operatingProfit', label: 'سود یا زیان عملیاتی', hint: 'درآمد ثبت‌شده − هزینه ثبت‌شده' },
{ key: 'receivables', label: 'مطالبات وصول‌نشده', hint: 'درآمد بدون دریافت کامل' },
{ key: 'payables', label: 'تعهدات پرداخت', hint: 'هزینه بدون پرداخت کامل' },
{ key: 'totalBalance', label: 'موجودی حساب‌ها', hint: 'صندوق و بانک' },
] as const;
onMounted(async () => {
try {
const res = await api.get<TreasuryDashboardDto>('/treasury/dashboard');
data.value = res.data;
} catch {
error.value = 'بارگذاری داشبورد مالی ناموفق بود.';
}
});
</script>
<template>
<div>
<a-flex vertical :gap="16">
<div>
<a-typography-title :level="3" :style="{ margin: 0 }">مدیریت مالی</a-typography-title>
<a-typography-text type="secondary">
دفتر داخلی درآمد، هزینه و موجودی حساب. این بخش جایگزین فاکتور فروش یا حسابداری رسمی نیست.
</a-typography-text>
</div>
<TreasuryNav />
<a-alert v-if="error" type="error" show-icon :message="error" />
<template v-if="data">
<a-row :gutter="[16, 16]">
<a-col
v-for="card in cards"
:key="card.key"
:xs="24"
:sm="12"
:md="8"
:xl="6"
>
<a-card :bordered="false">
<a-statistic :title="card.label" :value="toman(data[card.key])" />
<a-typography-text type="secondary">{{ card.hint }}</a-typography-text>
</a-card>
</a-col>
</a-row>
<a-card :bordered="false">
<a-row :gutter="[16, 16]">
<a-col :xs="24" :lg="12">
<a-divider orientation="right">اقساط نزدیک یا معوق</a-divider>
<a-empty
v-if="!data.upcomingInstallments.length"
description="قسط بازی نیست."
/>
<a-list
v-else
item-layout="horizontal"
:data-source="data.upcomingInstallments"
>
<template #renderItem="{ item }">
<a-list-item>
<a-list-item-meta>
<template #title>قسط {{ item.position }}</template>
<template #description>
{{ item.status === 'overdue' ? 'معوق' : 'باز' }} · مانده {{ toman(item.remaining) }}
</template>
</a-list-item-meta>
<template #actions>
<a-typography-text strong>{{ toman(item.amount) }}</a-typography-text>
</template>
</a-list-item>
</template>
</a-list>
</a-col>
<a-col :xs="24" :lg="12">
<a-divider orientation="right">پرداخت‌های آینده</a-divider>
<a-empty
v-if="!data.upcomingPayables.length"
description="تعهد پرداخت بازی نیست."
/>
<a-list
v-else
item-layout="horizontal"
:data-source="data.upcomingPayables"
>
<template #renderItem="{ item }">
<a-list-item>
<a-list-item-meta>
<template #title>{{ item.title }}</template>
<template #description>مانده {{ toman(item.remaining) }}</template>
</a-list-item-meta>
<template #actions>
<a-typography-text strong>{{ toman(item.amount) }}</a-typography-text>
</template>
</a-list-item>
</template>
</a-list>
</a-col>
</a-row>
<a-divider orientation="right">آخرین اسناد</a-divider>
<a-empty
v-if="!data.recent.length"
description="هنوز سندی ثبت نشده است."
/>
<a-list
v-else
item-layout="horizontal"
:data-source="data.recent"
>
<template #renderItem="{ item }">
<a-list-item>
<a-list-item-meta>
<template #title>{{ item.title }}</template>
<template #description>
{{ item.kind === 'income' ? 'درآمد' : 'هزینه' }} · {{ item.status }}
</template>
</a-list-item-meta>
<template #actions>
<a-typography-text strong>{{ toman(item.amount) }}</a-typography-text>
</template>
</a-list-item>
</template>
</a-list>
</a-card>
</template>
</a-flex>
</div>
</template>