<script lang="ts" setup>
|
import type { FinStatisticsApi } from '#/api/erp/finance/statistics';
|
|
import { computed, onMounted, ref } from 'vue';
|
|
import { Page } from '@vben/common-ui';
|
import { erpNumberFormatter } from '@vben/utils';
|
|
import { Button, Card, DatePicker, Col, Row, Spin, Tag } from 'ant-design-vue';
|
|
import {
|
getStatisticsOverview,
|
getStatisticsTrend,
|
} from '#/api/erp/finance/statistics';
|
|
import TrendChart from './modules/trend-chart.vue';
|
|
/** 财务报表 / 会计核算看板 */
|
defineOptions({ name: 'FinStatistics' });
|
|
const loading = ref(false);
|
const overview = ref<FinStatisticsApi.StatisticsOverview>();
|
const trendList = ref<FinStatisticsApi.StatisticsTrend[]>([]);
|
|
/** 查询条件:默认本年 1 月至当前月 */
|
const startMonth = ref<string>();
|
const endMonth = ref<string>();
|
|
/** 顶部收支概览卡片 */
|
const incomeCards = computed(() => [
|
{
|
title: '收款金额',
|
value: overview.value?.receiptPrice ?? 0,
|
color: '#18a058',
|
tip: 'ERP 已审核收款单合计',
|
},
|
{
|
title: '付款金额',
|
value: overview.value?.paymentPrice ?? 0,
|
color: '#d03050',
|
tip: 'ERP 已审核付款单合计',
|
},
|
{
|
title: '净利润',
|
value: overview.value?.netProfit ?? 0,
|
color: '#2f7df6',
|
tip: '收款金额 - 付款金额',
|
},
|
{
|
title: '销售订单金额',
|
value: overview.value?.saleOrderPrice ?? 0,
|
color: '#7c3aed',
|
tip: 'ERP 已审核销售订单合计',
|
},
|
{
|
title: '采购订单金额',
|
value: overview.value?.purchaseOrderPrice ?? 0,
|
color: '#f59e0b',
|
tip: 'ERP 已审核采购订单合计',
|
},
|
]);
|
|
/** 资产概览卡片 */
|
const assetCards = computed(() => [
|
{
|
title: '固定资产净值',
|
value: overview.value?.fixedAssetNetValue ?? 0,
|
sub: `原值 ${formatAmount(overview.value?.fixedAssetOriginalValue)} / 累计折旧 ${formatAmount(overview.value?.fixedAssetAccumulatedDepreciation)}`,
|
color: '#2f7df6',
|
},
|
{
|
title: '无形资产净值',
|
value: overview.value?.intangibleAssetNetValue ?? 0,
|
sub: `原值 ${formatAmount(overview.value?.intangibleAssetOriginalValue)} / 累计摊销 ${formatAmount(overview.value?.intangibleAssetAccumulatedAmortization)}`,
|
color: '#18a058',
|
},
|
{
|
title: '资产净值合计',
|
value: overview.value?.totalAssetNetValue ?? 0,
|
sub: '固定资产净值 + 无形资产净值',
|
color: '#7c3aed',
|
},
|
]);
|
|
/** 凭证概览 */
|
const voucherCards = computed(() => [
|
{
|
title: '会计科目',
|
value: overview.value?.subjectCount ?? 0,
|
color: '#2f7df6',
|
},
|
{
|
title: '凭证总数',
|
value: overview.value?.voucherCount ?? 0,
|
color: '#7c3aed',
|
},
|
{
|
title: '未过账',
|
value: overview.value?.voucherUnpostedCount ?? 0,
|
color: '#f59e0b',
|
},
|
{
|
title: '已过账',
|
value: overview.value?.voucherPostedCount ?? 0,
|
color: '#18a058',
|
},
|
{
|
title: '已作废',
|
value: overview.value?.voucherCancelledCount ?? 0,
|
color: '#d03050',
|
},
|
]);
|
|
/** 统计期间展示文案 */
|
const periodText = computed(() => {
|
if (!overview.value) {
|
return '';
|
}
|
return `${overview.value.startDate} ~ ${overview.value.endDate}`;
|
});
|
|
function formatAmount(value?: number) {
|
return erpNumberFormatter(value ?? 0, 2);
|
}
|
|
/** 加载看板数据 */
|
async function loadData() {
|
loading.value = true;
|
try {
|
const params: FinStatisticsApi.StatisticsParams = {
|
startMonth: startMonth.value,
|
endMonth: endMonth.value,
|
};
|
const [overviewData, trendData] = await Promise.all([
|
getStatisticsOverview(params),
|
getStatisticsTrend(params),
|
]);
|
overview.value = overviewData;
|
trendList.value = trendData ?? [];
|
} finally {
|
loading.value = false;
|
}
|
}
|
|
/** 重置为默认期间(本年 1 月至当前月) */
|
function handleReset() {
|
startMonth.value = undefined;
|
endMonth.value = undefined;
|
loadData();
|
}
|
|
onMounted(loadData);
|
</script>
|
|
<template>
|
<Page>
|
<Spin :spinning="loading">
|
<div class="flex flex-col gap-4">
|
<!-- 查询条件 -->
|
<Card :body-style="{ padding: '12px 16px' }" class="shadow-sm">
|
<div class="flex flex-wrap items-center gap-3">
|
<span class="font-medium">统计期间:</span>
|
<DatePicker
|
v-model:value="startMonth"
|
picker="month"
|
format="YYYY-MM"
|
value-format="YYYY-MM"
|
placeholder="起始月份"
|
style="width: 160px"
|
/>
|
<span>~</span>
|
<DatePicker
|
v-model:value="endMonth"
|
picker="month"
|
format="YYYY-MM"
|
value-format="YYYY-MM"
|
placeholder="结束月份"
|
style="width: 160px"
|
/>
|
<Button type="primary" @click="loadData">查询</Button>
|
<Button @click="handleReset">重置</Button>
|
<Tag color="blue" class="ml-auto">
|
数据来源:ERP 已审核单据 + 本模块已过账凭证 / 资产
|
</Tag>
|
</div>
|
</Card>
|
|
<!-- 收支概览 -->
|
<div>
|
<div class="mb-2 text-muted-foreground">
|
收支与购销概览
|
<span v-if="periodText">({{ periodText }})</span>
|
</div>
|
<div
|
class="grid grid-cols-5 gap-4 max-xl:grid-cols-3 max-sm:grid-cols-1"
|
>
|
<Card
|
v-for="item in incomeCards"
|
:key="item.title"
|
:body-style="{ padding: '12px 16px 16px' }"
|
class="h-full shadow-sm"
|
:style="{ borderTop: `3px solid ${item.color}` }"
|
>
|
<div class="mb-2 text-muted-foreground">{{ item.title }}</div>
|
<div
|
class="text-2xl font-bold"
|
:style="{ color: item.color }"
|
>
|
{{ formatAmount(item.value) }}
|
</div>
|
<div class="mt-2 text-xs text-muted-foreground">
|
{{ item.tip }}
|
</div>
|
</Card>
|
</div>
|
</div>
|
|
<!-- 资产与凭证概览 -->
|
<Row :gutter="16">
|
<Col :lg="12" :md="24" :sm="24" :xs="24">
|
<div class="mb-2 text-muted-foreground">资产概览(时点数)</div>
|
<div class="grid grid-cols-3 gap-4 max-sm:grid-cols-1">
|
<Card
|
v-for="item in assetCards"
|
:key="item.title"
|
:body-style="{ padding: '12px 16px 16px' }"
|
class="h-full shadow-sm"
|
:style="{ borderTop: `3px solid ${item.color}` }"
|
>
|
<div class="mb-2 text-muted-foreground">{{ item.title }}</div>
|
<div
|
class="text-2xl font-bold"
|
:style="{ color: item.color }"
|
>
|
{{ formatAmount(item.value) }}
|
</div>
|
<div class="mt-2 text-xs text-muted-foreground">
|
{{ item.sub }}
|
</div>
|
</Card>
|
</div>
|
</Col>
|
<Col :lg="12" :md="24" :sm="24" :xs="24">
|
<div class="mb-2 text-muted-foreground">凭证概览</div>
|
<div class="grid grid-cols-5 gap-4 max-sm:grid-cols-2">
|
<Card
|
v-for="item in voucherCards"
|
:key="item.title"
|
:body-style="{ padding: '12px 16px 16px' }"
|
class="h-full shadow-sm"
|
:style="{ borderTop: `3px solid ${item.color}` }"
|
>
|
<div class="mb-2 truncate text-muted-foreground">
|
{{ item.title }}
|
</div>
|
<div
|
class="text-2xl font-bold"
|
:style="{ color: item.color }"
|
>
|
{{ item.value }}
|
</div>
|
</Card>
|
</div>
|
</Col>
|
</Row>
|
|
<!-- 月度趋势 -->
|
<TrendChart :list="trendList" :loading="loading" />
|
</div>
|
</Spin>
|
</Page>
|
</template>
|