feat: 添加预算统计服务增强和日志系统改进
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 24s
Docker Build & Deploy / Deploy to Production (push) Successful in 6s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 2s
Docker Build & Deploy / WeChat Notification (push) Successful in 2s
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 24s
Docker Build & Deploy / Deploy to Production (push) Successful in 6s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 2s
Docker Build & Deploy / WeChat Notification (push) Successful in 2s
1. 新增 BudgetStatsService:将预算统计逻辑从 BudgetService 中提取为独立服务,支持月度和年度统计,包含归档数据支持和硬性预算调整算法 2. 日志系统增强:添加请求ID追踪功能,支持通过请求ID查询关联日志,新增类名筛选功能 3. 日志解析优化:修复类名解析逻辑,正确提取 SourceContext 中的类名信息 4. 代码清理:移除不需要的方法名相关代码,简化日志筛选逻辑
This commit is contained in:
@@ -33,7 +33,8 @@ public class BudgetService(
|
||||
IMessageService messageService,
|
||||
ILogger<BudgetService> logger,
|
||||
IBudgetSavingsService budgetSavingsService,
|
||||
IDateTimeProvider dateTimeProvider
|
||||
IDateTimeProvider dateTimeProvider,
|
||||
IBudgetStatsService budgetStatsService
|
||||
) : IBudgetService
|
||||
{
|
||||
public async Task<List<BudgetResult>> GetListAsync(DateTime referenceDate)
|
||||
@@ -109,17 +110,7 @@ public class BudgetService(
|
||||
|
||||
public async Task<BudgetCategoryStats> GetCategoryStatsAsync(BudgetCategory category, DateTime referenceDate)
|
||||
{
|
||||
var budgets = await GetListAsync(referenceDate);
|
||||
|
||||
var result = new BudgetCategoryStats();
|
||||
|
||||
// 获取月度统计
|
||||
result.Month = await CalculateCategoryStatsAsync(budgets, category, BudgetPeriodType.Month, referenceDate);
|
||||
|
||||
// 获取年度统计
|
||||
result.Year = await CalculateCategoryStatsAsync(budgets, category, BudgetPeriodType.Year, referenceDate);
|
||||
|
||||
return result;
|
||||
return await budgetStatsService.GetCategoryStatsAsync(category, referenceDate);
|
||||
}
|
||||
|
||||
public async Task<List<UncoveredCategoryDetail>> GetUncoveredCategoriesAsync(BudgetCategory category, DateTime? referenceDate = null)
|
||||
@@ -163,179 +154,7 @@ public class BudgetService(
|
||||
return archive?.Summary;
|
||||
}
|
||||
|
||||
private async Task<BudgetStatsDto> CalculateCategoryStatsAsync(
|
||||
List<BudgetResult> budgets,
|
||||
BudgetCategory category,
|
||||
BudgetPeriodType statType,
|
||||
DateTime referenceDate)
|
||||
{
|
||||
var result = new BudgetStatsDto
|
||||
{
|
||||
PeriodType = statType,
|
||||
Rate = 0,
|
||||
Current = 0,
|
||||
Limit = 0,
|
||||
Count = 0
|
||||
};
|
||||
|
||||
// 获取当前分类下所有预算,排除不记额预算
|
||||
var relevant = budgets
|
||||
.Where(b => b.Category == category && !b.NoLimit)
|
||||
.ToList();
|
||||
|
||||
// 月度统计中,只包含月度预算;年度统计中,包含所有预算
|
||||
if (statType == BudgetPeriodType.Month)
|
||||
{
|
||||
relevant = relevant.Where(b => b.Type == BudgetPeriodType.Month).ToList();
|
||||
}
|
||||
|
||||
if (relevant.Count == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Count = relevant.Count;
|
||||
decimal totalCurrent = 0;
|
||||
decimal totalLimit = 0;
|
||||
|
||||
// 是否可以使用趋势统计来计算实际发生额(避免多预算重复计入同一笔账)
|
||||
var transactionType = category switch
|
||||
{
|
||||
BudgetCategory.Expense => TransactionType.Expense,
|
||||
BudgetCategory.Income => TransactionType.Income,
|
||||
_ => TransactionType.None
|
||||
};
|
||||
|
||||
foreach (var budget in relevant)
|
||||
{
|
||||
// 限额折算
|
||||
var itemLimit = budget.Limit;
|
||||
if (statType == BudgetPeriodType.Year && budget.Type == BudgetPeriodType.Month)
|
||||
{
|
||||
// 年度视图下,月度预算折算为年度
|
||||
itemLimit = budget.Limit * 12;
|
||||
}
|
||||
totalLimit += itemLimit;
|
||||
|
||||
// 先逐预算累加当前值(作为后备值)
|
||||
var selectedCategories = string.Join(',', budget.SelectedCategories);
|
||||
var currentAmount = await CalculateCurrentAmountAsync(new()
|
||||
{
|
||||
Name = budget.Name,
|
||||
Type = budget.Type,
|
||||
Limit = budget.Limit,
|
||||
Category = budget.Category,
|
||||
SelectedCategories = selectedCategories,
|
||||
StartDate = new DateTime(referenceDate.Year, referenceDate.Month, 1),
|
||||
IsMandatoryExpense = budget.IsMandatoryExpense
|
||||
}, referenceDate);
|
||||
|
||||
if (statType == BudgetPeriodType.Month)
|
||||
{
|
||||
totalCurrent += currentAmount;
|
||||
}
|
||||
else if (statType == BudgetPeriodType.Year)
|
||||
{
|
||||
// 年度视图下,累加所有预算的当前值
|
||||
totalCurrent += currentAmount;
|
||||
}
|
||||
}
|
||||
|
||||
result.Limit = totalLimit;
|
||||
|
||||
// 计算每日/每月趋势
|
||||
if (transactionType != TransactionType.None)
|
||||
{
|
||||
var hasGlobalBudget = relevant.Any(b => b.SelectedCategories.Length == 0);
|
||||
|
||||
var allClassifies = hasGlobalBudget
|
||||
? []
|
||||
: relevant
|
||||
.SelectMany(b => b.SelectedCategories)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
DateTime startDate, endDate;
|
||||
bool groupByMonth;
|
||||
|
||||
if (statType == BudgetPeriodType.Month)
|
||||
{
|
||||
startDate = new DateTime(referenceDate.Year, referenceDate.Month, 1);
|
||||
endDate = startDate.AddMonths(1).AddDays(-1);
|
||||
groupByMonth = false;
|
||||
}
|
||||
else // Year
|
||||
{
|
||||
startDate = new DateTime(referenceDate.Year, 1, 1);
|
||||
endDate = startDate.AddYears(1).AddDays(-1);
|
||||
groupByMonth = true;
|
||||
}
|
||||
|
||||
var dailyStats = await transactionRecordRepository.GetFilteredTrendStatisticsAsync(
|
||||
startDate,
|
||||
endDate,
|
||||
transactionType,
|
||||
allClassifies,
|
||||
groupByMonth);
|
||||
|
||||
decimal accumulated = 0;
|
||||
decimal lastValidAccumulated = 0;
|
||||
var now = dateTimeProvider.Now;
|
||||
|
||||
if (statType == BudgetPeriodType.Month)
|
||||
{
|
||||
var daysInMonth = DateTime.DaysInMonth(startDate.Year, startDate.Month);
|
||||
for (int i = 1; i <= daysInMonth; i++)
|
||||
{
|
||||
var currentDate = new DateTime(startDate.Year, startDate.Month, i);
|
||||
if (currentDate.Date > now.Date)
|
||||
{
|
||||
result.Trend.Add(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dailyStats.TryGetValue(currentDate.Date, out var amount))
|
||||
{
|
||||
accumulated += amount;
|
||||
lastValidAccumulated = accumulated;
|
||||
}
|
||||
result.Trend.Add(accumulated);
|
||||
}
|
||||
}
|
||||
else // Year
|
||||
{
|
||||
for (int i = 1; i <= 12; i++)
|
||||
{
|
||||
var currentMonthDate = new DateTime(startDate.Year, i, 1);
|
||||
|
||||
if (currentMonthDate.Year > now.Year || (currentMonthDate.Year == now.Year && i > now.Month))
|
||||
{
|
||||
result.Trend.Add(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dailyStats.TryGetValue(currentMonthDate, out var amount))
|
||||
{
|
||||
accumulated += amount;
|
||||
lastValidAccumulated = accumulated;
|
||||
}
|
||||
result.Trend.Add(accumulated);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有有效的趋势数据,使用去重后的实际发生额(趋势的累计值),避免同一账单被多预算重复计入
|
||||
// 否则使用前面逐预算累加的值(作为后备)
|
||||
if (lastValidAccumulated > 0)
|
||||
{
|
||||
totalCurrent = lastValidAccumulated;
|
||||
}
|
||||
}
|
||||
|
||||
result.Current = totalCurrent;
|
||||
result.Rate = totalLimit > 0 ? totalCurrent / totalLimit * 100 : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<string> ArchiveBudgetsAsync(int year, int month)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user