feat(统计报表): 添加年度统计报表功能并显示现金合计
- 将下载全部报表改为下载年度统计报表 - 在类型定义和数据处理中添加 cashFee 字段 - 在报表页面显示现金合计金额 - 添加下载年度统计报表和下载不含天医币报表的接口和功能 - 使用年份选择器替代原有下载按钮
This commit is contained in:
@@ -144,9 +144,33 @@ export const statisticsApi = {
|
||||
* 下载全部月份的收入统计报表
|
||||
* @returns 全部月份的收入统计报表数据
|
||||
*/
|
||||
downloadAllMonthIncomeStatistics: () => {
|
||||
downloadAllMonthIncomeStatistics: (data?: { year: number | string }) => {
|
||||
return defaultRequestClient.download<Blob>('common/statistics/getMonthStatistics', {
|
||||
data: {},
|
||||
data: data || {},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 下载年度统计报表
|
||||
* @param data 请求参数
|
||||
* @param data.year 年份
|
||||
* @returns 年度统计报表数据
|
||||
*/
|
||||
downloadYearStatistics: (data: { year: number | string }) => {
|
||||
return defaultRequestClient.download<Blob>('common/statistics/getYearStatistics', {
|
||||
data,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 下载年度统计报表(不包含天医币)
|
||||
* @param data 请求参数
|
||||
* @param data.year 年份
|
||||
* @returns 年度统计报表数据(不包含天医币)
|
||||
*/
|
||||
downloadYearStatisticsNoPoint: (data: { year: number | string }) => {
|
||||
return defaultRequestClient.download<Blob>('common/statistics/getYearStatisticsNoPoint', {
|
||||
data,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ const routes: RouteRecordRaw[] = [
|
||||
},
|
||||
{
|
||||
meta: {
|
||||
title: '下载全部报表',
|
||||
title: '下载年度报表',
|
||||
keepAlive: true,
|
||||
},
|
||||
name: 'DownloadReports',
|
||||
|
||||
@@ -1,39 +1,86 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Dayjs } from 'dayjs';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { downloadFileFromBlobPart } from '@vben/utils';
|
||||
|
||||
import { Button } from 'ant-design-vue';
|
||||
import { Button, DatePicker } from 'ant-design-vue';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { statisticsApi } from '#/api/statistics';
|
||||
|
||||
// 下载全部报表
|
||||
const downloadAllReportsLoading = ref(false);
|
||||
async function downloadAllReports() {
|
||||
downloadAllReportsLoading.value = true;
|
||||
const year = ref<Dayjs>(dayjs());
|
||||
const downloadYearReportLoading = ref(false);
|
||||
const downloadYearReportNoPointLoading = ref(false);
|
||||
|
||||
const disabledDate = (date: Dayjs) => date.year() > dayjs().year();
|
||||
|
||||
async function downloadYearReport() {
|
||||
if (!year.value) return;
|
||||
downloadYearReportLoading.value = true;
|
||||
try {
|
||||
// 下载全部报表
|
||||
const Blob = await statisticsApi.downloadAllMonthIncomeStatistics();
|
||||
const selectedYear = year.value.year();
|
||||
const Blob = await statisticsApi.downloadYearStatistics({
|
||||
year: selectedYear,
|
||||
});
|
||||
|
||||
downloadFileFromBlobPart({
|
||||
source: Blob,
|
||||
fileName: '财务报表.xlsx',
|
||||
fileName: `${selectedYear}年度统计报表.xlsx`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('下载全部报表失败:', error);
|
||||
console.error('下载年度统计报表失败:', error);
|
||||
} finally {
|
||||
downloadAllReportsLoading.value = false;
|
||||
downloadYearReportLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadYearReportNoPoint() {
|
||||
if (!year.value) return;
|
||||
downloadYearReportNoPointLoading.value = true;
|
||||
try {
|
||||
const selectedYear = year.value.year();
|
||||
const Blob = await statisticsApi.downloadYearStatisticsNoPoint({
|
||||
year: selectedYear,
|
||||
});
|
||||
|
||||
downloadFileFromBlobPart({
|
||||
source: Blob,
|
||||
fileName: `${selectedYear}年度统计报表_不含天医币.xlsx`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('下载年度统计报表(不包含天医币)失败:', error);
|
||||
} finally {
|
||||
downloadYearReportNoPointLoading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<div class="flex h-full rounded-md bg-white p-4">
|
||||
<Button type="primary" :loading="downloadAllReportsLoading" @click="downloadAllReports">
|
||||
下载报表
|
||||
</Button>
|
||||
<div class="flex h-full flex-col rounded-md bg-white">
|
||||
<div class="flex items-center p-4">
|
||||
<DatePicker v-model:value="year" picker="year" :disabled-date="disabledDate" />
|
||||
<Button
|
||||
type="primary"
|
||||
class="ml-2"
|
||||
:loading="downloadYearReportLoading"
|
||||
@click="downloadYearReport"
|
||||
>
|
||||
下载年度统计报表
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
class="ml-2"
|
||||
:loading="downloadYearReportNoPointLoading"
|
||||
@click="downloadYearReportNoPoint"
|
||||
>
|
||||
下载年度统计报表(不包含天医币)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
@@ -21,6 +21,7 @@ export function handleSumAndNoNeedAmortizateMonthData(
|
||||
resultData.push({
|
||||
type,
|
||||
sumFee: resItem.sumFee || 0,
|
||||
cashFee: resItem.cashFee || 0,
|
||||
children: childDictArr.map((childType) => ({
|
||||
title: childType.title,
|
||||
fee: resItem[childType.type] || 0,
|
||||
@@ -86,6 +87,13 @@ export async function handleVipAndCourseMonthData(
|
||||
.reduce((acc: number, cur: IncomeItem) => acc + cur.fee, 0)
|
||||
.toFixed(3),
|
||||
),
|
||||
// 现金合计需要去掉天医币后合计
|
||||
cashFee: Number.parseFloat(
|
||||
currentMonthData.incomes
|
||||
.filter((item: IncomeItem) => item.type !== '天医币')
|
||||
.reduce((acc: number, cur: IncomeItem) => acc + cur.fee, 0)
|
||||
.toFixed(3),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -138,6 +138,7 @@ const vipMonthLoading = ref<boolean | string>(loadingText);
|
||||
const vipMonthData = ref({
|
||||
incomes: [] as IncomeItem[],
|
||||
incomesTotal: 0,
|
||||
cashFee: 0,
|
||||
notyet: 0,
|
||||
already: 0,
|
||||
now: 0,
|
||||
@@ -168,6 +169,7 @@ const courseMonthLoading = ref<boolean | string>(loadingText);
|
||||
const courseMonthData = ref({
|
||||
incomes: [] as IncomeItem[],
|
||||
incomesTotal: 0,
|
||||
cashFee: 0,
|
||||
notyet: 0,
|
||||
already: 0,
|
||||
now: 0,
|
||||
@@ -403,6 +405,9 @@ async function downloadMonthStatistics() {
|
||||
<div class="flex items-center">
|
||||
{{ `合计:${item.sumFee}元` }}
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
{{ `现金合计:${item.cashFee}元` }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -427,6 +432,7 @@ async function downloadMonthStatistics() {
|
||||
<div v-else>
|
||||
<div class="font-bold">上月剩余摊销 {{ vipMonthData.lastNotyet }}元</div>
|
||||
<div class="font-bold">收入 合计{{ vipMonthData.incomesTotal }}元</div>
|
||||
<div class="font-bold">现金合计{{ vipMonthData.cashFee }}元</div>
|
||||
<div
|
||||
v-for="child in vipMonthData.incomes"
|
||||
:key="child.type"
|
||||
@@ -458,6 +464,7 @@ async function downloadMonthStatistics() {
|
||||
<div v-else>
|
||||
<div class="font-bold">上月剩余摊销 {{ courseMonthData.lastNotyet }}元</div>
|
||||
<div class="font-bold">收入 合计{{ courseMonthData.incomesTotal }}元</div>
|
||||
<div class="font-bold">现金合计{{ courseMonthData.cashFee }}元</div>
|
||||
<div
|
||||
v-for="child in courseMonthData.incomes"
|
||||
:key="child.type"
|
||||
|
||||
@@ -4,12 +4,14 @@ export interface NoNeedAmortizateMonthStatistics {
|
||||
zfb: number;
|
||||
tianyibi: number;
|
||||
sumFee: number;
|
||||
cashFee: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface SumAndNoNeedAmortizateMonthDataItem {
|
||||
type: string;
|
||||
sumFee: number;
|
||||
cashFee: number;
|
||||
children: Array<{
|
||||
fee: number;
|
||||
title: string;
|
||||
|
||||
Reference in New Issue
Block a user