feat: 添加存款分类设置功能,优化预算管理界面
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 26s
Docker Build & Deploy / Deploy to Production (push) Successful in 8s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 26s
Docker Build & Deploy / Deploy to Production (push) Successful in 8s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
[Route("api/[controller]/[action]")]
|
||||
public class BudgetController(
|
||||
IBudgetService budgetService,
|
||||
IConfigService configService,
|
||||
ILogger<BudgetController> logger) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
@@ -23,6 +24,10 @@ public class BudgetController(
|
||||
dtos.Add(BudgetDto.FromEntity(budget, currentAmount, referenceDate));
|
||||
}
|
||||
|
||||
// 创造虚拟的存款预算
|
||||
dtos.Add(await GetVirtualSavingsDtoAsync(BudgetPeriodType.Month, referenceDate));
|
||||
dtos.Add(await GetVirtualSavingsDtoAsync(BudgetPeriodType.Year, referenceDate));
|
||||
|
||||
return dtos.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -40,6 +45,15 @@ public class BudgetController(
|
||||
{
|
||||
try
|
||||
{
|
||||
if (id == -1)
|
||||
{
|
||||
return (await GetVirtualSavingsDtoAsync(BudgetPeriodType.Year, referenceDate)).Ok();
|
||||
}
|
||||
if (id == -2)
|
||||
{
|
||||
return (await GetVirtualSavingsDtoAsync(BudgetPeriodType.Month, referenceDate)).Ok();
|
||||
}
|
||||
|
||||
var budget = await budgetService.GetByIdAsync(id);
|
||||
if (budget == null) return "预算不存在".Fail<BudgetDto>();
|
||||
|
||||
@@ -147,6 +161,84 @@ public class BudgetController(
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<BudgetDto> GetVirtualSavingsDtoAsync(BudgetPeriodType periodType, DateTime? referenceDate = null)
|
||||
{
|
||||
var allBudgets = await budgetService.GetAllAsync();
|
||||
var date = referenceDate ?? DateTime.Now;
|
||||
|
||||
decimal incomeLimitAtPeriod = 0;
|
||||
decimal expenseLimitAtPeriod = 0;
|
||||
|
||||
var savingsCategories = await configService.GetConfigByKeyAsync<string>("SavingsCategories") ?? string.Empty;
|
||||
var selectedCategoryList = savingsCategories.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (var b in allBudgets)
|
||||
{
|
||||
if (b.IsStopped || b.Category == BudgetCategory.Savings) continue;
|
||||
|
||||
// 如果设置了存款分类,并且预算有指定分类,则只统计相关的预算
|
||||
if (selectedCategoryList.Length > 0)
|
||||
{
|
||||
var budgetCategories = b.SelectedCategories.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (budgetCategories.Length > 0 && !budgetCategories.Intersect(selectedCategoryList).Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 折算系数:根据当前请求的 periodType (Year 或 Month),将预算 b 的 Limit 折算过来
|
||||
decimal factor = 1.0m;
|
||||
|
||||
if (periodType == BudgetPeriodType.Year)
|
||||
{
|
||||
factor = b.Type switch
|
||||
{
|
||||
BudgetPeriodType.Month => 12,
|
||||
BudgetPeriodType.Week => 52,
|
||||
BudgetPeriodType.Year => 1,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
else if (periodType == BudgetPeriodType.Month)
|
||||
{
|
||||
factor = b.Type switch
|
||||
{
|
||||
BudgetPeriodType.Month => 1,
|
||||
BudgetPeriodType.Week => 52m / 12m,
|
||||
BudgetPeriodType.Year => 1m / 12m,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
factor = 0; // 其他周期暂不计算虚拟存款
|
||||
}
|
||||
|
||||
if (b.Category == BudgetCategory.Income) incomeLimitAtPeriod += b.Limit * factor;
|
||||
else if (b.Category == BudgetCategory.Expense) expenseLimitAtPeriod += b.Limit * factor;
|
||||
}
|
||||
|
||||
var virtualBudget = new BudgetRecord
|
||||
{
|
||||
Id = periodType == BudgetPeriodType.Year ? -1 : -2,
|
||||
Name = periodType == BudgetPeriodType.Year ? "年度存款" : "月度存款",
|
||||
Category = BudgetCategory.Savings,
|
||||
Type = periodType,
|
||||
Limit = incomeLimitAtPeriod - expenseLimitAtPeriod,
|
||||
StartDate = periodType == BudgetPeriodType.Year ? new DateTime(date.Year, 1, 1) : new DateTime(date.Year, date.Month, 1),
|
||||
SelectedCategories = savingsCategories
|
||||
};
|
||||
|
||||
// 计算实际发生的 收入 - 支出
|
||||
var incomeHelper = new BudgetRecord { Category = BudgetCategory.Income, Type = periodType, StartDate = virtualBudget.StartDate, SelectedCategories = savingsCategories };
|
||||
var expenseHelper = new BudgetRecord { Category = BudgetCategory.Expense, Type = periodType, StartDate = virtualBudget.StartDate, SelectedCategories = savingsCategories };
|
||||
|
||||
var actualIncome = await budgetService.CalculateCurrentAmountAsync(incomeHelper, date);
|
||||
var actualExpense = await budgetService.CalculateCurrentAmountAsync(expenseHelper, date);
|
||||
|
||||
return BudgetDto.FromEntity(virtualBudget, actualIncome - actualExpense, date);
|
||||
}
|
||||
|
||||
private async Task<string> ValidateBudgetSelectedCategoriesAsync(BudgetRecord record)
|
||||
{
|
||||
var allBudgets = await budgetService.GetAllAsync();
|
||||
|
||||
Reference in New Issue
Block a user