fix
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 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 3s
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 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 3s
This commit is contained in:
@@ -21,7 +21,7 @@ public class BudgetStatsService(
|
||||
{
|
||||
public async Task<BudgetCategoryStats> GetCategoryStatsAsync(BudgetCategory category, DateTime referenceDate)
|
||||
{
|
||||
logger.LogInformation("开始计算分类统计信息: Category={Category}, ReferenceDate={ReferenceDate:yyyy-MM-dd}",
|
||||
logger.LogInformation("开始计算分类统计信息: Category={Category}, ReferenceDate={ReferenceDate:yyyy-MM-dd}",
|
||||
category, referenceDate);
|
||||
|
||||
var result = new BudgetCategoryStats();
|
||||
@@ -31,20 +31,20 @@ public class BudgetStatsService(
|
||||
// 获取月度统计
|
||||
logger.LogDebug("开始计算月度统计");
|
||||
result.Month = await CalculateMonthlyCategoryStatsAsync(category, referenceDate);
|
||||
logger.LogInformation("月度统计计算完成: Count={Count}, Limit={Limit}, Current={Current}, Rate={Rate:F2}%",
|
||||
logger.LogInformation("月度统计计算完成: Count={Count}, Limit={Limit}, Current={Current}, Rate={Rate:F2}%",
|
||||
result.Month.Count, result.Month.Limit, result.Month.Current, result.Month.Rate);
|
||||
|
||||
// 获取年度统计
|
||||
logger.LogDebug("开始计算年度统计");
|
||||
result.Year = await CalculateYearlyCategoryStatsAsync(category, referenceDate);
|
||||
logger.LogInformation("年度统计计算完成: Count={Count}, Limit={Limit}, Current={Current}, Rate={Rate:F2}%",
|
||||
logger.LogInformation("年度统计计算完成: Count={Count}, Limit={Limit}, Current={Current}, Rate={Rate:F2}%",
|
||||
result.Year.Count, result.Year.Limit, result.Year.Current, result.Year.Rate);
|
||||
|
||||
logger.LogInformation("分类统计信息计算完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "计算分类统计信息时发生错误: Category={Category}, ReferenceDate={ReferenceDate:yyyy-MM-dd}",
|
||||
logger.LogError(ex, "计算分类统计信息时发生错误: Category={Category}, ReferenceDate={ReferenceDate:yyyy-MM-dd}",
|
||||
category, referenceDate);
|
||||
throw;
|
||||
}
|
||||
@@ -54,7 +54,7 @@ public class BudgetStatsService(
|
||||
|
||||
private async Task<BudgetStatsDto> CalculateMonthlyCategoryStatsAsync(BudgetCategory category, DateTime referenceDate)
|
||||
{
|
||||
logger.LogDebug("开始计算月度分类统计: Category={Category}, ReferenceDate={ReferenceDate:yyyy-MM}",
|
||||
logger.LogDebug("开始计算月度分类统计: Category={Category}, ReferenceDate={ReferenceDate:yyyy-MM}",
|
||||
category, referenceDate);
|
||||
|
||||
var result = new BudgetStatsDto
|
||||
@@ -94,7 +94,7 @@ public class BudgetStatsService(
|
||||
// 使用 GetAllBudgetsWithArchiveAsync 中已经计算好的 Current 值
|
||||
var totalCurrent = budgets.Sum(b => b.Current);
|
||||
logger.LogInformation("【实际值来源】累加各预算的实际值: {TotalCurrent}元(共{Count}个预算)", totalCurrent, budgets.Count);
|
||||
|
||||
|
||||
var transactionType = category switch
|
||||
{
|
||||
BudgetCategory.Expense => TransactionType.Expense,
|
||||
@@ -129,7 +129,7 @@ public class BudgetStatsService(
|
||||
decimal accumulated = 0;
|
||||
var daysInMonth = DateTime.DaysInMonth(startDate.Year, startDate.Month);
|
||||
logger.LogDebug("本月天数: {DaysInMonth}", daysInMonth);
|
||||
|
||||
|
||||
for (var i = 1; i <= daysInMonth; i++)
|
||||
{
|
||||
var currentDate = new DateTime(startDate.Year, startDate.Month, i);
|
||||
@@ -143,21 +143,21 @@ public class BudgetStatsService(
|
||||
if (dailyStats.TryGetValue(currentDate.Date, out var amount))
|
||||
{
|
||||
accumulated += amount;
|
||||
logger.LogTrace("日期 {CurrentDate:yyyy-MM-dd}: 金额={Amount}, 累计={Accumulated}",
|
||||
logger.LogTrace("日期 {CurrentDate:yyyy-MM-dd}: 金额={Amount}, 累计={Accumulated}",
|
||||
currentDate, amount, accumulated);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogTrace("日期 {CurrentDate:yyyy-MM-dd}: 无交易数据,累计={Accumulated}",
|
||||
logger.LogTrace("日期 {CurrentDate:yyyy-MM-dd}: 无交易数据,累计={Accumulated}",
|
||||
currentDate, accumulated);
|
||||
}
|
||||
|
||||
|
||||
// 对每一天的累计值应用硬性预算调整
|
||||
var adjustedAccumulated = accumulated;
|
||||
if (transactionType == TransactionType.Expense)
|
||||
{
|
||||
var mandatoryBudgets = budgets.Where(b => b.IsMandatoryExpense).ToList();
|
||||
|
||||
|
||||
// 检查是否为当前月份
|
||||
var isCurrentMonth = referenceDate.Year == now.Year && referenceDate.Month == now.Month;
|
||||
if (isCurrentMonth && currentDate.Date <= now.Date)
|
||||
@@ -166,31 +166,31 @@ public class BudgetStatsService(
|
||||
// totalMandatoryVirtual是所有硬性预算的虚拟消耗
|
||||
// 但如果硬性预算有实际交易,accumulated中已经包含了,会重复
|
||||
// 所以需要:accumulated + (totalMandatoryVirtual - 硬性预算的实际交易部分)
|
||||
|
||||
|
||||
// 更简单的理解:
|
||||
// - 如果某个硬性预算本月完全没有交易记录,它的虚拟值应该加到accumulated上
|
||||
// - 如果某个硬性预算有部分交易记录,应该补齐到虚拟值
|
||||
// - 实现:取 max(accumulated, totalMandatoryVirtual) 是不对的
|
||||
// - 正确:accumulated + 硬性预算中没有实际交易的那部分的虚拟值
|
||||
|
||||
|
||||
// 由于无法精确区分,采用近似方案:
|
||||
// 计算所有硬性预算的Current总和,这个值已经包含了虚拟消耗(在CalculateCurrentAmountAsync中处理)
|
||||
|
||||
// 计算非硬性预算的交易累计(这部分在accumulated中)
|
||||
// 但accumulated是所有交易的累计,包括硬性预算的实际交易
|
||||
|
||||
|
||||
// 最终简化方案:
|
||||
// dailyStats包含所有实际交易(包括硬性预算的实际交易)
|
||||
// 对于没有实际交易的硬性预算,它们的虚拟消耗没有在dailyStats中
|
||||
// 所以:adjustedAccumulated = accumulated + 没有实际交易的硬性预算的虚拟消耗
|
||||
|
||||
|
||||
// 实用方法:每个硬性预算,取 max(它在dailyStats中的累计, 虚拟值)
|
||||
// 但我们无法从dailyStats中提取单个预算的数据
|
||||
|
||||
|
||||
// 终极简化:如果硬性预算的Current值等于虚拟值,说明没有实际交易
|
||||
// 这种情况下,accumulated中不包含这部分,需要加上虚拟值
|
||||
// 如果Current值大于虚拟值,说明有实际交易,accumulated中已包含,不需要调整
|
||||
|
||||
|
||||
decimal mandatoryAdjustment = 0;
|
||||
foreach (var budget in mandatoryBudgets)
|
||||
{
|
||||
@@ -205,16 +205,16 @@ public class BudgetStatsService(
|
||||
var dayOfYear = currentDate.DayOfYear;
|
||||
dailyVirtual = budget.Limit * dayOfYear / daysInYear;
|
||||
}
|
||||
|
||||
|
||||
// 如果budget.Current约等于整月的虚拟值,说明没有实际交易
|
||||
// 但Current是整个月的,dailyVirtual是到当前天的
|
||||
// 需要判断该预算是否有实际交易记录
|
||||
// 简化:假设如果硬性预算的Current等于虚拟值(误差<1元),就没有实际交易
|
||||
|
||||
var monthlyVirtual = budget.Type == BudgetPeriodType.Month
|
||||
|
||||
var monthlyVirtual = budget.Type == BudgetPeriodType.Month
|
||||
? budget.Limit * now.Day / daysInMonth
|
||||
: budget.Limit * now.DayOfYear / (DateTime.IsLeapYear(now.Year) ? 366 : 365);
|
||||
|
||||
|
||||
if (Math.Abs(budget.Current - monthlyVirtual) < 1)
|
||||
{
|
||||
// 没有实际交易,需要添加虚拟消耗
|
||||
@@ -223,14 +223,14 @@ public class BudgetStatsService(
|
||||
currentDate, budget.Name, dailyVirtual);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
adjustedAccumulated += mandatoryAdjustment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result.Trend.Add(adjustedAccumulated);
|
||||
}
|
||||
|
||||
|
||||
logger.LogDebug("趋势图数据计算完成(已应用硬性预算调整)");
|
||||
}
|
||||
else
|
||||
@@ -265,7 +265,7 @@ public class BudgetStatsService(
|
||||
logger.LogInformation("【使用率】{Current}元 ÷ {Limit}元 × 100% = {Rate:F2}%", result.Current, totalLimit, result.Rate);
|
||||
|
||||
// 5. 生成预算明细汇总日志
|
||||
var budgetDetails = budgets.Select(b =>
|
||||
var budgetDetails = budgets.Select(b =>
|
||||
{
|
||||
var limit = CalculateBudgetLimit(b, BudgetPeriodType.Month, referenceDate);
|
||||
var prefix = b.IsArchive ? $"({b.ArchiveMonth}月归档)" : "";
|
||||
@@ -285,7 +285,7 @@ public class BudgetStatsService(
|
||||
|
||||
private async Task<BudgetStatsDto> CalculateYearlyCategoryStatsAsync(BudgetCategory category, DateTime referenceDate)
|
||||
{
|
||||
logger.LogDebug("开始计算年度分类统计: Category={Category}, ReferenceDate={ReferenceDate:yyyy}",
|
||||
logger.LogDebug("开始计算年度分类统计: Category={Category}, ReferenceDate={ReferenceDate:yyyy}",
|
||||
category, referenceDate);
|
||||
|
||||
var result = new BudgetStatsDto
|
||||
@@ -338,7 +338,7 @@ public class BudgetStatsService(
|
||||
|
||||
// 计算当前实际值,考虑硬性预算的特殊逻辑
|
||||
var totalCurrent = budgets.Sum(b => b.Current);
|
||||
logger.LogInformation("【实际值来源】累加各预算的实际值: {TotalCurrent}元(共{Count}个预算)",
|
||||
logger.LogInformation("【实际值来源】累加各预算的实际值: {TotalCurrent}元(共{Count}个预算)",
|
||||
totalCurrent, budgets.Count);
|
||||
|
||||
var now = dateTimeProvider.Now;
|
||||
@@ -380,21 +380,21 @@ public class BudgetStatsService(
|
||||
if (dailyStats.TryGetValue(currentMonthDate, out var amount))
|
||||
{
|
||||
accumulated += amount;
|
||||
logger.LogTrace("月份 {Month:yyyy-MM}: 金额={Amount}, 累计={Accumulated}",
|
||||
logger.LogTrace("月份 {Month:yyyy-MM}: 金额={Amount}, 累计={Accumulated}",
|
||||
currentMonthDate, amount, accumulated);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogTrace("月份 {Month:yyyy-MM}: 无交易数据,累计={Accumulated}",
|
||||
logger.LogTrace("月份 {Month:yyyy-MM}: 无交易数据,累计={Accumulated}",
|
||||
currentMonthDate, accumulated);
|
||||
}
|
||||
|
||||
|
||||
// 对每个月的累计值应用硬性预算调整
|
||||
var adjustedAccumulated = accumulated;
|
||||
if (transactionType == TransactionType.Expense)
|
||||
{
|
||||
var mandatoryBudgets = budgets.Where(b => b.IsMandatoryExpense).ToList();
|
||||
|
||||
|
||||
// 检查是否为当前年份
|
||||
var isCurrentYear = referenceDate.Year == now.Year;
|
||||
if (isCurrentYear && currentMonthDate <= now)
|
||||
@@ -403,7 +403,7 @@ public class BudgetStatsService(
|
||||
foreach (var budget in mandatoryBudgets)
|
||||
{
|
||||
decimal monthlyVirtual = 0;
|
||||
|
||||
|
||||
if (budget.Type == BudgetPeriodType.Month)
|
||||
{
|
||||
// 月度硬性预算:如果该月已完成,累加整月;如果是当前月,按天数比例
|
||||
@@ -424,12 +424,12 @@ public class BudgetStatsService(
|
||||
var dayOfYear = i < now.Month ? lastDayOfMonth.DayOfYear : now.DayOfYear;
|
||||
monthlyVirtual = budget.Limit * dayOfYear / daysInYear;
|
||||
}
|
||||
|
||||
|
||||
// 判断该硬性预算是否有实际交易
|
||||
var yearlyVirtual = budget.Type == BudgetPeriodType.Month
|
||||
var yearlyVirtual = budget.Type == BudgetPeriodType.Month
|
||||
? budget.Limit * now.Month + (budget.Limit * now.Day / DateTime.DaysInMonth(now.Year, now.Month)) - budget.Limit
|
||||
: budget.Limit * now.DayOfYear / (DateTime.IsLeapYear(now.Year) ? 366 : 365);
|
||||
|
||||
|
||||
if (Math.Abs(budget.Current - yearlyVirtual) < 1)
|
||||
{
|
||||
// 没有实际交易,需要添加虚拟消耗
|
||||
@@ -438,11 +438,11 @@ public class BudgetStatsService(
|
||||
currentMonthDate, budget.Name, monthlyVirtual);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
adjustedAccumulated += mandatoryAdjustment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result.Trend.Add(adjustedAccumulated);
|
||||
}
|
||||
|
||||
@@ -480,7 +480,7 @@ public class BudgetStatsService(
|
||||
logger.LogInformation("【使用率】{Current}元 ÷ {Limit}元 × 100% = {Rate:F2}%", result.Current, totalLimit, result.Rate);
|
||||
|
||||
// 5. 生成预算明细汇总日志
|
||||
var budgetDetails = budgets.Select(b =>
|
||||
var budgetDetails = budgets.Select(b =>
|
||||
{
|
||||
var limit = CalculateBudgetLimit(b, BudgetPeriodType.Year, referenceDate);
|
||||
var prefix = b.IsArchive ? "(归档)" : b.RemainingMonths > 0 ? $"(剩余{b.RemainingMonths}月)" : "";
|
||||
@@ -503,7 +503,7 @@ public class BudgetStatsService(
|
||||
BudgetPeriodType statType,
|
||||
DateTime referenceDate)
|
||||
{
|
||||
logger.LogDebug("开始获取预算数据: Category={Category}, StatType={StatType}, ReferenceDate={ReferenceDate:yyyy-MM-dd}",
|
||||
logger.LogDebug("开始获取预算数据: Category={Category}, StatType={StatType}, ReferenceDate={ReferenceDate:yyyy-MM-dd}",
|
||||
category, statType, referenceDate);
|
||||
|
||||
var result = new List<BudgetStatsItem>();
|
||||
@@ -516,7 +516,7 @@ public class BudgetStatsService(
|
||||
if (statType == BudgetPeriodType.Year)
|
||||
{
|
||||
logger.LogDebug("年度统计:开始获取整年的预算数据");
|
||||
|
||||
|
||||
// 获取当前有效的预算(用于当前月及未来月)
|
||||
var currentBudgets = await budgetRepository.GetAllAsync();
|
||||
var currentBudgetsDict = currentBudgets
|
||||
@@ -526,7 +526,7 @@ public class BudgetStatsService(
|
||||
|
||||
// 用于跟踪已处理的预算ID,避免重复
|
||||
var processedBudgetIds = new HashSet<long>();
|
||||
|
||||
|
||||
// 1. 处理历史归档月份(1月到当前月-1)
|
||||
if (referenceDate.Year == now.Year && now.Month > 1)
|
||||
{
|
||||
@@ -585,7 +585,7 @@ public class BudgetStatsService(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 2. 处理当前月及未来月(使用当前预算)
|
||||
logger.LogDebug("开始处理当前及未来月份预算");
|
||||
foreach (var budget in currentBudgetsDict.Values)
|
||||
@@ -675,7 +675,7 @@ public class BudgetStatsService(
|
||||
// 获取归档数据
|
||||
logger.LogDebug("开始获取归档数据: Year={Year}, Month={Month}", year, month);
|
||||
var archive = await budgetArchiveRepository.GetArchiveAsync(year, month);
|
||||
|
||||
|
||||
if (archive != null)
|
||||
{
|
||||
var itemCount = archive.Content.Count();
|
||||
@@ -714,7 +714,7 @@ public class BudgetStatsService(
|
||||
var budgets = await budgetRepository.GetAllAsync();
|
||||
var budgetCount = budgets.Count();
|
||||
logger.LogDebug("获取到 {BudgetCount} 个预算", budgetCount);
|
||||
|
||||
|
||||
foreach (var budget in budgets)
|
||||
{
|
||||
if (budget.Category == category && ShouldIncludeBudget(budget, statType))
|
||||
@@ -845,7 +845,7 @@ public class BudgetStatsService(
|
||||
|
||||
logger.LogInformation("预算 {BudgetName} 限额计算: 原始预算={OriginalLimit}, 计算后限额={CalculatedLimit}, 算法: {Algorithm}",
|
||||
budget.Name, budget.Limit, itemLimit, algorithmDescription);
|
||||
|
||||
|
||||
return itemLimit;
|
||||
}
|
||||
|
||||
@@ -888,13 +888,13 @@ public class BudgetStatsService(
|
||||
|
||||
private decimal ApplyMandatoryBudgetAdjustment(List<BudgetStatsItem> budgets, decimal currentTotal, DateTime referenceDate, BudgetPeriodType statType)
|
||||
{
|
||||
logger.LogDebug("开始应用硬性预算调整: 当前总计={CurrentTotal}, 统计类型={StatType}, 参考日期={ReferenceDate:yyyy-MM-dd}",
|
||||
logger.LogDebug("开始应用硬性预算调整: 当前总计={CurrentTotal}, 统计类型={StatType}, 参考日期={ReferenceDate:yyyy-MM-dd}",
|
||||
currentTotal, statType, referenceDate);
|
||||
|
||||
var now = dateTimeProvider.Now;
|
||||
var adjustedTotal = currentTotal;
|
||||
var mandatoryBudgets = budgets.Where(b => b.IsMandatoryExpense).ToList();
|
||||
|
||||
|
||||
logger.LogDebug("找到 {MandatoryCount} 个硬性预算", mandatoryBudgets.Count);
|
||||
|
||||
var mandatoryIndex = 0;
|
||||
@@ -906,14 +906,14 @@ public class BudgetStatsService(
|
||||
if (statType == BudgetPeriodType.Month)
|
||||
{
|
||||
isCurrentPeriod = referenceDate.Year == now.Year && referenceDate.Month == now.Month;
|
||||
logger.LogInformation("硬性预算 {MandatoryIndex}/{MandatoryCount}: {BudgetName} - 检查月度周期: 参考月份={RefMonth}, 当前月份={CurrentMonth}, 是否为当前周期={IsCurrent}",
|
||||
mandatoryIndex, mandatoryBudgets.Count, budget.Name,
|
||||
logger.LogInformation("硬性预算 {MandatoryIndex}/{MandatoryCount}: {BudgetName} - 检查月度周期: 参考月份={RefMonth}, 当前月份={CurrentMonth}, 是否为当前周期={IsCurrent}",
|
||||
mandatoryIndex, mandatoryBudgets.Count, budget.Name,
|
||||
referenceDate.ToString("yyyy-MM"), now.ToString("yyyy-MM"), isCurrentPeriod);
|
||||
}
|
||||
else // Year
|
||||
{
|
||||
isCurrentPeriod = referenceDate.Year == now.Year;
|
||||
logger.LogInformation("硬性预算 {MandatoryIndex}/{MandatoryCount}: {BudgetName} - 检查年度周期: 参考年份={RefYear}, 当前年份={CurrentYear}, 是否为当前周期={IsCurrent}",
|
||||
logger.LogInformation("硬性预算 {MandatoryIndex}/{MandatoryCount}: {BudgetName} - 检查年度周期: 参考年份={RefYear}, 当前年份={CurrentYear}, 是否为当前周期={IsCurrent}",
|
||||
mandatoryIndex, mandatoryBudgets.Count, budget.Name,
|
||||
referenceDate.Year, now.Year, isCurrentPeriod);
|
||||
}
|
||||
@@ -923,7 +923,7 @@ public class BudgetStatsService(
|
||||
// 计算硬性预算的应累加值
|
||||
decimal mandatoryAccumulation = 0;
|
||||
var accumulationAlgorithm = "";
|
||||
|
||||
|
||||
if (budget.Type == BudgetPeriodType.Month)
|
||||
{
|
||||
// 月度硬性预算按天数比例累加
|
||||
@@ -931,7 +931,7 @@ public class BudgetStatsService(
|
||||
var daysElapsed = now.Day;
|
||||
mandatoryAccumulation = budget.Limit * daysElapsed / daysInMonth;
|
||||
accumulationAlgorithm = $"月度硬性预算按天数比例: {budget.Limit} × {daysElapsed} ÷ {daysInMonth} = {mandatoryAccumulation:F2}";
|
||||
logger.LogDebug("月度硬性预算 {BudgetName}: 限额={Limit}, 本月天数={DaysInMonth}, 已过天数={DaysElapsed}, 应累加值={Accumulation}",
|
||||
logger.LogDebug("月度硬性预算 {BudgetName}: 限额={Limit}, 本月天数={DaysInMonth}, 已过天数={DaysElapsed}, 应累加值={Accumulation}",
|
||||
budget.Name, budget.Limit, daysInMonth, daysElapsed, mandatoryAccumulation);
|
||||
}
|
||||
else if (budget.Type == BudgetPeriodType.Year)
|
||||
@@ -941,7 +941,7 @@ public class BudgetStatsService(
|
||||
var daysElapsed = now.DayOfYear;
|
||||
mandatoryAccumulation = budget.Limit * daysElapsed / daysInYear;
|
||||
accumulationAlgorithm = $"年度硬性预算按天数比例: {budget.Limit} × {daysElapsed} ÷ {daysInYear} = {mandatoryAccumulation:F2}";
|
||||
logger.LogDebug("年度硬性预算 {BudgetName}: 限额={Limit}, 本年天数={DaysInYear}, 已过天数={DaysElapsed}, 应累加值={Accumulation}",
|
||||
logger.LogDebug("年度硬性预算 {BudgetName}: 限额={Limit}, 本年天数={DaysInYear}, 已过天数={DaysElapsed}, 应累加值={Accumulation}",
|
||||
budget.Name, budget.Limit, daysInYear, daysElapsed, mandatoryAccumulation);
|
||||
}
|
||||
|
||||
@@ -958,7 +958,7 @@ public class BudgetStatsService(
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogDebug("硬性预算 {BudgetName} 未触发调整: 当前总计={CurrentTotal} >= 应累加值={MandatoryAccumulation}",
|
||||
logger.LogDebug("硬性预算 {BudgetName} 未触发调整: 当前总计={CurrentTotal} >= 应累加值={MandatoryAccumulation}",
|
||||
budget.Name, adjustedTotal, mandatoryAccumulation);
|
||||
}
|
||||
}
|
||||
@@ -1029,7 +1029,7 @@ public class BudgetStatsService(
|
||||
var budgetLimit = CalculateBudgetLimit(budget, BudgetPeriodType.Month, referenceDate);
|
||||
var typeLabel = budget.IsMandatoryExpense ? "硬性" : "普通";
|
||||
var archiveLabel = budget.IsArchive ? $" ({budget.ArchiveMonth}月归档)" : "";
|
||||
|
||||
|
||||
description.AppendLine($"""
|
||||
<tr>
|
||||
<td>{budget.Name}{archiveLabel}</td>
|
||||
@@ -1138,8 +1138,8 @@ public class BudgetStatsService(
|
||||
{
|
||||
var budgetLimit = CalculateBudgetLimit(budget, BudgetPeriodType.Year, referenceDate);
|
||||
var typeStr = budget.IsCurrentMonth ? "当前月" : "未来月";
|
||||
var calcStr = budget.IsCurrentMonth
|
||||
? $"1月×{budget.Limit:N0}"
|
||||
var calcStr = budget.IsCurrentMonth
|
||||
? $"1月×{budget.Limit:N0}"
|
||||
: $"{budget.RemainingMonths}月×{budget.Limit:N0}";
|
||||
|
||||
description.AppendLine($"""
|
||||
@@ -1195,7 +1195,7 @@ public class BudgetStatsService(
|
||||
description.AppendLine($"<h3>计算公式</h3>");
|
||||
description.AppendLine($"<p><strong>年度预算额度合计:</strong>");
|
||||
var limitParts = new List<string>();
|
||||
|
||||
|
||||
// 归档月度预算部分
|
||||
foreach (var group in archivedMonthlyBudgets.GroupBy(b => b.Id))
|
||||
{
|
||||
@@ -1204,7 +1204,7 @@ public class BudgetStatsService(
|
||||
var groupTotalLimit = first.Limit * count;
|
||||
limitParts.Add($"{first.Name}(归档{count}月×{first.Limit:N0}={groupTotalLimit:N0})");
|
||||
}
|
||||
|
||||
|
||||
// 当前月度预算部分
|
||||
foreach (var budget in currentMonthlyBudgets)
|
||||
{
|
||||
@@ -1218,18 +1218,18 @@ public class BudgetStatsService(
|
||||
limitParts.Add($"{budget.Name}(剩余{budget.RemainingMonths}月×{budget.Limit:N0}={budgetLimit:N0})");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 年度预算部分
|
||||
foreach (var budget in archivedYearlyBudgets.Concat(currentYearlyBudgets))
|
||||
{
|
||||
limitParts.Add($"{budget.Name}({budget.Limit:N0})");
|
||||
}
|
||||
|
||||
|
||||
description.AppendLine($"{string.Join(" + ", limitParts)} = <span class='{(category == BudgetCategory.Expense ? "expense-value" : "income-value")}'><strong>{totalLimit:N0}</strong></span></p>");
|
||||
|
||||
description.AppendLine($"<p><strong>实际{categoryName}合计:</strong>");
|
||||
var currentParts = new List<string>();
|
||||
|
||||
|
||||
// 归档月度预算的实际值
|
||||
foreach (var group in archivedMonthlyBudgets.GroupBy(b => b.Id))
|
||||
{
|
||||
@@ -1237,13 +1237,13 @@ public class BudgetStatsService(
|
||||
var groupTotalCurrent = group.Sum(b => b.Current);
|
||||
currentParts.Add($"{first.Name}(归档{groupTotalCurrent:N1})");
|
||||
}
|
||||
|
||||
|
||||
// 年度预算的实际值
|
||||
foreach (var budget in archivedYearlyBudgets.Concat(currentYearlyBudgets))
|
||||
{
|
||||
currentParts.Add($"{budget.Name}({budget.Current:N1})");
|
||||
}
|
||||
|
||||
|
||||
description.AppendLine($"{string.Join(" + ", currentParts)} = <span class='{(category == BudgetCategory.Expense ? "expense-value" : "income-value")}'><strong>{totalCurrent:N1}</strong></span></p>");
|
||||
|
||||
var rate = totalLimit > 0 ? totalCurrent / totalLimit * 100 : 0;
|
||||
|
||||
Reference in New Issue
Block a user