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