using Service.Transaction; namespace WebApi.Controllers; /// /// 交易统计控制器 /// [ApiController] [Route("api/[controller]/[action]")] public class TransactionStatisticsController( ITransactionRecordRepository transactionRepository, ITransactionStatisticsService transactionStatisticsService, ILogger logger, IConfigService configService ) : ControllerBase { /// /// 获取累积余额统计数据(用于余额卡片图表) /// [HttpGet] public async Task>> GetBalanceStatisticsAsync( [FromQuery] int year, [FromQuery] int month ) { try { // 获取存款分类 var savingClassify = await configService.GetConfigByKeyAsync("SavingsCategories"); // 获取每日统计数据 var statistics = await transactionStatisticsService.GetDailyStatisticsAsync(year, month, savingClassify); // 按日期排序并计算累积余额 var sortedStats = statistics.OrderBy(s => s.Key).ToList(); var result = new List(); decimal cumulativeBalance = 0; foreach (var item in sortedStats) { var dailyBalance = item.Value.income - item.Value.expense; cumulativeBalance += dailyBalance; result.Add(new BalanceStatisticsDto( item.Key, cumulativeBalance )); } return result.Ok(); } catch (Exception ex) { logger.LogError(ex, "获取累积余额统计失败,年份: {Year}, 月份: {Month}", year, month); return $"获取累积余额统计失败: {ex.Message}".Fail>(); } } /// /// 获取指定月份每天的消费统计 /// [HttpGet] public async Task>> GetDailyStatisticsAsync( [FromQuery] int year, [FromQuery] int month ) { try { // 获取存款分类 var savingClassify = await configService.GetConfigByKeyAsync("SavingsCategories"); var statistics = await transactionStatisticsService.GetDailyStatisticsAsync(year, month, savingClassify); var result = statistics.Select(s => new DailyStatisticsDto( s.Key, s.Value.count, s.Value.expense, s.Value.income, s.Value.saving )).ToList(); return result.Ok(); } catch (Exception ex) { logger.LogError(ex, "获取日历统计数据失败,年份: {Year}, 月份: {Month}", year, month); return $"获取日历统计数据失败: {ex.Message}".Fail>(); } } /// /// 获取周统计数据 /// [HttpGet] public async Task>> GetWeeklyStatisticsAsync( [FromQuery] DateTime startDate, [FromQuery] DateTime endDate ) { try { // 获取存款分类 var savingClassify = await configService.GetConfigByKeyAsync("SavingsCategories"); var statistics = await transactionStatisticsService.GetDailyStatisticsByRangeAsync(startDate, endDate, savingClassify); var result = statistics.Select(s => new DailyStatisticsDto( s.Key, s.Value.count, s.Value.expense, s.Value.income, s.Value.saving )).ToList(); return result.Ok(); } catch (Exception ex) { logger.LogError(ex, "获取周统计数据失败,开始日期: {StartDate}, 结束日期: {EndDate}", startDate, endDate); return $"获取周统计数据失败: {ex.Message}".Fail>(); } } /// /// 获取指定日期范围的统计汇总数据 /// [HttpGet] public async Task> GetRangeStatisticsAsync( [FromQuery] DateTime startDate, [FromQuery] DateTime endDate ) { try { // 通过日期范围查询数据 var records = await transactionRepository.QueryAsync( startDate: startDate, endDate: endDate, pageSize: int.MaxValue); var statistics = new MonthlyStatistics { Year = startDate.Year, Month = startDate.Month }; foreach (var record in records) { var amount = Math.Abs(record.Amount); if (record.Type == TransactionType.Expense) { statistics.TotalExpense += amount; statistics.ExpenseCount++; } else if (record.Type == TransactionType.Income) { statistics.TotalIncome += amount; statistics.IncomeCount++; } } statistics.Balance = statistics.TotalIncome - statistics.TotalExpense; statistics.TotalCount = records.Count; return statistics.Ok(); } catch (Exception ex) { logger.LogError(ex, "获取时间范围统计数据失败,开始日期: {StartDate}, 结束日期: {EndDate}", startDate, endDate); return $"获取时间范围统计数据失败: {ex.Message}".Fail(); } } /// /// 获取月度统计数据 /// [HttpGet] public async Task> GetMonthlyStatisticsAsync( [FromQuery] int year, [FromQuery] int month ) { try { var statistics = await transactionStatisticsService.GetMonthlyStatisticsAsync(year, month); return statistics.Ok(); } catch (Exception ex) { logger.LogError(ex, "获取月度统计数据失败,年份: {Year}, 月份: {Month}", year, month); return $"获取月度统计数据失败: {ex.Message}".Fail(); } } /// /// 获取分类统计数据 /// [HttpGet] public async Task>> GetCategoryStatisticsAsync( [FromQuery] int year, [FromQuery] int month, [FromQuery] TransactionType type ) { try { var statistics = await transactionStatisticsService.GetCategoryStatisticsAsync(year, month, type); return statistics.Ok(); } catch (Exception ex) { logger.LogError(ex, "获取分类统计数据失败,年份: {Year}, 月份: {Month}, 类型: {Type}", year, month, type); return $"获取分类统计数据失败: {ex.Message}".Fail>(); } } /// /// 按日期范围获取分类统计数据 /// [HttpGet] public async Task>> GetCategoryStatisticsByDateRangeAsync( [FromQuery] string startDate, [FromQuery] string endDate, [FromQuery] TransactionType type ) { try { if (!DateTime.TryParse(startDate, out var start)) { return "开始日期格式错误".Fail>(); } if (!DateTime.TryParse(endDate, out var end)) { return "结束日期格式错误".Fail>(); } var statistics = await transactionStatisticsService.GetCategoryStatisticsByDateRangeAsync(start, end, type); return statistics.Ok(); } catch (Exception ex) { logger.LogError(ex, "获取分类统计数据失败,开始日期: {StartDate}, 结束日期: {EndDate}, 类型: {Type}", startDate, endDate, type); return $"获取分类统计数据失败: {ex.Message}".Fail>(); } } /// /// 获取趋势统计数据 /// [HttpGet] public async Task>> GetTrendStatisticsAsync( [FromQuery] int startYear, [FromQuery] int startMonth, [FromQuery] int monthCount = 6 ) { try { var statistics = await transactionStatisticsService.GetTrendStatisticsAsync(startYear, startMonth, monthCount); return statistics.Ok(); } catch (Exception ex) { logger.LogError(ex, "获取趋势统计数据失败,开始年份: {Year}, 开始月份: {Month}, 月份数: {Count}", startYear, startMonth, monthCount); return $"获取趋势统计数据失败: {ex.Message}".Fail>(); } } /// /// 获取按交易摘要分组的统计信息(支持分页) /// [HttpGet] public async Task> GetReasonGroupsAsync( [FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 20) { try { var (list, total) = await transactionStatisticsService.GetReasonGroupsAsync(pageIndex, pageSize); return new PagedResponse { Success = true, Data = list.ToArray(), Total = total }; } catch (Exception ex) { logger.LogError(ex, "获取交易摘要分组失败"); return PagedResponse.Fail($"获取交易摘要分组失败: {ex.Message}"); } } } /// /// 日历统计响应DTO /// public record DailyStatisticsDto( string Date, int Count, decimal Expense, decimal Income, decimal Balance ); /// /// 累积余额统计DTO /// public record BalanceStatisticsDto( string Date, decimal CumulativeBalance );