Files
EmailBill/Application/TransactionStatisticsApplication.cs
SunCheng a7954f55ad feat: remove V1 calendar/budget/stats modules
- 删除 V1 前端页面 (CalendarView, BudgetView, statisticsV1)
- 移除 V1 路由配置 (/calendar, /budget, /)
- 清理路由守卫中的 V1 版本切换逻辑
- 移除设置页面中的版本切换功能
- 更新底部导航和登录重定向到 V2 路由
- 移除 App.vue 中 V1 页面的缓存配置
- 删除后端 TransactionRecordController.GetDailyStatisticsAsync (Obsolete)
- 删除 TransactionStatisticsController.GetBalanceStatisticsAsync
- 保留 V2 仍在使用的共享 API (GetUncoveredCategories, GetArchiveSummary, GetDailyStatistics)
- 保留 V2 使用的全局事件监听机制
- 所有测试通过 (210/210)

Breaking Change: V1 API 端点和路由将不可用
2026-02-14 00:01:44 +08:00

181 lines
7.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Application.Dto.Statistics;
using Service.Transaction;
namespace Application;
/// <summary>
/// 交易统计应用服务接口
/// </summary>
public interface ITransactionStatisticsApplication
{
// === 新统一接口(推荐使用) ===
/// <summary>
/// 按日期范围获取每日统计(新统一接口)
/// </summary>
Task<List<DailyStatisticsDto>> GetDailyStatisticsByRangeAsync(DateTime startDate, DateTime endDate, string? savingClassify = null);
/// <summary>
/// 按日期范围获取汇总统计(新统一接口)
/// </summary>
Task<MonthlyStatistics> GetSummaryByRangeAsync(DateTime startDate, DateTime endDate);
/// <summary>
/// 按日期范围获取分类统计(新统一接口)
/// </summary>
Task<List<CategoryStatistics>> GetCategoryStatisticsByRangeAsync(DateTime startDate, DateTime endDate, TransactionType type);
/// <summary>
/// 获取趋势统计数据
/// </summary>
Task<List<TrendStatistics>> GetTrendStatisticsAsync(int startYear, int startMonth, int monthCount);
// === 旧接口(保留用于向后兼容,建议迁移到新接口) ===
[Obsolete("请使用 GetDailyStatisticsByRangeAsync")]
Task<List<DailyStatisticsDto>> GetDailyStatisticsAsync(int year, int month);
[Obsolete("请使用 GetDailyStatisticsByRangeAsync")]
Task<List<DailyStatisticsDto>> GetWeeklyStatisticsAsync(DateTime startDate, DateTime endDate);
[Obsolete("请使用 GetSummaryByRangeAsync")]
Task<MonthlyStatistics> GetRangeStatisticsAsync(DateTime startDate, DateTime endDate);
[Obsolete("请使用 GetSummaryByRangeAsync")]
Task<MonthlyStatistics> GetMonthlyStatisticsAsync(int year, int month);
[Obsolete("请使用 GetCategoryStatisticsByRangeAsync")]
Task<List<CategoryStatistics>> GetCategoryStatisticsAsync(int year, int month, TransactionType type);
[Obsolete("请使用 GetCategoryStatisticsByRangeAsync")]
Task<List<CategoryStatistics>> GetCategoryStatisticsByDateRangeAsync(string startDate, string endDate, TransactionType type);
Task<(List<ReasonGroupDto> list, int total)> GetReasonGroupsAsync(int pageIndex, int pageSize);
}
/// <summary>
/// 交易统计应用服务实现
/// </summary>
public class TransactionStatisticsApplication(
ITransactionStatisticsService statisticsService,
IConfigService configService
) : ITransactionStatisticsApplication
{
// === 新统一接口实现 ===
/// <summary>
/// 按日期范围获取每日统计(新统一接口)
/// </summary>
public async Task<List<DailyStatisticsDto>> GetDailyStatisticsByRangeAsync(DateTime startDate, DateTime endDate, string? savingClassify = null)
{
// 如果未指定 savingClassify从配置读取
savingClassify ??= await configService.GetConfigByKeyAsync<string>("SavingsCategories");
var statistics = await statisticsService.GetDailyStatisticsByRangeAsync(startDate, endDate, savingClassify);
return statistics.Select(s => new DailyStatisticsDto(
DateTime.Parse(s.Key).Day,
s.Value.count,
s.Value.expense,
s.Value.income,
s.Value.saving
)).ToList();
}
/// <summary>
/// 按日期范围获取汇总统计(新统一接口)
/// </summary>
public async Task<MonthlyStatistics> GetSummaryByRangeAsync(DateTime startDate, DateTime endDate)
{
return await statisticsService.GetSummaryByRangeAsync(startDate, endDate);
}
/// <summary>
/// 按日期范围获取分类统计(新统一接口)
/// </summary>
public async Task<List<CategoryStatistics>> GetCategoryStatisticsByRangeAsync(DateTime startDate, DateTime endDate, TransactionType type)
{
return await statisticsService.GetCategoryStatisticsByDateRangeAsync(startDate, endDate, type);
}
// === 旧接口实现(保留用于向后兼容) ===
public async Task<List<DailyStatisticsDto>> GetDailyStatisticsAsync(int year, int month)
{
var savingClassify = await configService.GetConfigByKeyAsync<string>("SavingsCategories");
var statistics = await statisticsService.GetDailyStatisticsAsync(year, month, savingClassify);
return statistics.Select(s => new DailyStatisticsDto(
DateTime.Parse(s.Key).Day, // 从完整日期字符串 "yyyy-MM-dd" 中提取 day
s.Value.count,
s.Value.expense,
s.Value.income,
s.Value.saving
)).ToList();
}
public async Task<List<DailyStatisticsDto>> GetWeeklyStatisticsAsync(DateTime startDate, DateTime endDate)
{
var savingClassify = await configService.GetConfigByKeyAsync<string>("SavingsCategories");
var statistics = await statisticsService.GetDailyStatisticsByRangeAsync(startDate, endDate, savingClassify);
return statistics.Select(s => new DailyStatisticsDto(
DateTime.Parse(s.Key).Day, // 从完整日期字符串 "yyyy-MM-dd" 中提取 day
s.Value.count,
s.Value.expense,
s.Value.income,
s.Value.saving
)).ToList();
}
public async Task<MonthlyStatistics> GetRangeStatisticsAsync(DateTime startDate, DateTime endDate)
{
var records = await statisticsService.GetDailyStatisticsByRangeAsync(startDate, endDate, null);
var totalExpense = records.Sum(r => r.Value.expense);
var totalIncome = records.Sum(r => r.Value.income);
var totalCount = records.Sum(r => r.Value.count);
var expenseCount = records.Count(r => r.Value.expense > 0);
var incomeCount = records.Count(r => r.Value.income > 0);
return new MonthlyStatistics
{
Year = startDate.Year,
Month = startDate.Month,
TotalExpense = totalExpense,
TotalIncome = totalIncome,
Balance = totalIncome - totalExpense,
ExpenseCount = expenseCount,
IncomeCount = incomeCount,
TotalCount = totalCount
};
}
public async Task<MonthlyStatistics> GetMonthlyStatisticsAsync(int year, int month)
{
return await statisticsService.GetMonthlyStatisticsAsync(year, month);
}
public async Task<List<CategoryStatistics>> GetCategoryStatisticsAsync(int year, int month, TransactionType type)
{
return await statisticsService.GetCategoryStatisticsAsync(year, month, type);
}
public async Task<List<CategoryStatistics>> GetCategoryStatisticsByDateRangeAsync(string startDate, string endDate, TransactionType type)
{
var start = DateTime.Parse(startDate);
var end = DateTime.Parse(endDate);
return await statisticsService.GetCategoryStatisticsByDateRangeAsync(start, end, type);
}
public async Task<List<TrendStatistics>> GetTrendStatisticsAsync(int startYear, int startMonth, int monthCount)
{
return await statisticsService.GetTrendStatisticsAsync(startYear, startMonth, monthCount);
}
public async Task<(List<ReasonGroupDto> list, int total)> GetReasonGroupsAsync(int pageIndex, int pageSize)
{
return await statisticsService.GetReasonGroupsAsync(pageIndex, pageSize);
}
}