From d2b2158b30878a5b9b9003fc6db2538f000ca595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E8=AF=9A?= Date: Sun, 11 Jan 2026 12:33:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E6=9C=AA=E8=A2=AB=E9=A2=84=E7=AE=97=E8=A6=86=E7=9B=96=E7=9A=84?= =?UTF-8?q?=E5=88=86=E7=B1=BB=E7=BB=9F=E8=AE=A1=E4=BF=A1=E6=81=AF=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=EF=BC=9B=E6=9B=B4=E6=96=B0=E5=89=8D=E7=AB=AF=E4=BB=A5?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E6=9C=AA=E8=A6=86=E7=9B=96=E5=88=86=E7=B1=BB?= =?UTF-8?q?=E7=9A=84=E8=AF=A6=E7=BB=86=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Service/BudgetService.cs | 48 ++++++++++- Web/src/api/budget.js | 13 ++- Web/src/views/BudgetView.vue | 110 +++++++++++++++++++++++-- WebApi/Controllers/BudgetController.cs | 18 ++++ 4 files changed, 181 insertions(+), 8 deletions(-) diff --git a/Service/BudgetService.cs b/Service/BudgetService.cs index 43c8a42..6a162f0 100644 --- a/Service/BudgetService.cs +++ b/Service/BudgetService.cs @@ -12,6 +12,11 @@ public interface IBudgetService /// 获取指定分类的统计信息(月度和年度) /// Task GetCategoryStatsAsync(BudgetCategory category, DateTime? referenceDate = null); + + /// + /// 获取未被预算覆盖的分类统计信息 + /// + Task> GetUncoveredCategoriesAsync(BudgetCategory category, DateTime? referenceDate = null); } public class BudgetService( @@ -146,6 +151,41 @@ public class BudgetService( return result; } + public async Task> GetUncoveredCategoriesAsync(BudgetCategory category, DateTime? referenceDate = null) + { + var date = referenceDate ?? DateTime.Now; + var transactionType = category switch + { + BudgetCategory.Expense => TransactionType.Expense, + BudgetCategory.Income => TransactionType.Income, + _ => TransactionType.None + }; + + if (transactionType == TransactionType.None) return new List(); + + // 1. 获取所有预算 + var budgets = (await budgetRepository.GetAllAsync()).ToList(); + var coveredCategories = budgets + .Where(b => b.Category == category) + .SelectMany(b => b.SelectedCategories.Split(',', StringSplitOptions.RemoveEmptyEntries)) + .ToHashSet(); + + // 2. 获取分类统计 + var stats = await transactionRecordRepository.GetCategoryStatisticsAsync(date.Year, date.Month, transactionType); + + // 3. 过滤未覆盖的 + return stats + .Where(s => !coveredCategories.Contains(s.Classify)) + .Select(s => new UncoveredCategoryDetail + { + Category = s.Classify, + TransactionCount = s.Count, + TotalAmount = s.Amount + }) + .OrderByDescending(x => x.TotalAmount) + .ToList(); + } + private async Task CalculateCategoryStatsAsync( List budgets, BudgetCategory category, @@ -673,4 +713,10 @@ public class BudgetCategoryStats /// 年度统计 /// public BudgetStatsDto Year { get; set; } = new(); -} \ No newline at end of file +} +public class UncoveredCategoryDetail +{ + public string Category { get; set; } = string.Empty; + public int TransactionCount { get; set; } + public decimal TotalAmount { get; set; } +} diff --git a/Web/src/api/budget.js b/Web/src/api/budget.js index ebbaae2..0b49aba 100644 --- a/Web/src/api/budget.js +++ b/Web/src/api/budget.js @@ -72,7 +72,18 @@ export function getCategoryStats(category, referenceDate) { params: { category, referenceDate } }) } - +/** + * 获取未被预算覆盖的分类统计信息 + * @param {number} category 预算分类 + * @param {string} referenceDate 参考日期 + */ +export function getUncoveredCategories(category, referenceDate) { + return request({ + url: '/Budget/GetUncoveredCategories', + method: 'get', + params: { category, referenceDate } + }) +} /** * 归档预算 * @param {number} year 年份 diff --git a/Web/src/views/BudgetView.vue b/Web/src/views/BudgetView.vue index d6934ee..5f935c9 100644 --- a/Web/src/views/BudgetView.vue +++ b/Web/src/views/BudgetView.vue @@ -2,7 +2,15 @@