重构账单查询sql
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 26s
Docker Build & Deploy / Deploy to Production (push) Successful in 7s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 2s
Docker Build & Deploy / WeChat Notification (push) Successful in 2s

This commit is contained in:
SunCheng
2026-01-28 10:58:15 +08:00
parent 5c9d7c5db1
commit b71eadd4f9
19 changed files with 1433 additions and 730 deletions

View File

@@ -0,0 +1,56 @@
# API CONTROLLERS KNOWLEDGE BASE
**Generated:** 2026-01-28
**Parent:** EmailBill/AGENTS.md
## OVERVIEW
REST API controllers using ASP.NET Core with DTO patterns and standardized responses.
## STRUCTURE
```
WebApi/Controllers/
├── Dto/ # Data transfer objects
│ ├── BaseResponse.cs # Standard response wrapper
│ ├── LoginRequest/Response.cs # Authentication DTOs
│ ├── BudgetDto.cs # Budget data transfer
│ ├── EmailMessageDto.cs # Email data transfer
│ └── PagedResponse.cs # Pagination wrapper
├── AuthController.cs # Authentication endpoints
├── BudgetController.cs # Budget management
├── TransactionRecordController.cs # Transaction CRUD
├── EmailMessageController.cs # Email processing
├── MessageRecordController.cs # Message handling
└── [Other controllers] # Feature-specific endpoints
```
## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| Authentication | AuthController.cs | JWT login, token refresh |
| Budget APIs | BudgetController.cs | Budget CRUD, statistics |
| Transaction APIs | TransactionRecordController.cs | Financial transactions |
| Email APIs | EmailMessageController.cs | Email processing |
| DTO patterns | Dto/ | Request/response models |
| Standard responses | BaseResponse.cs, PagedResponse.cs | Consistent API format |
## CONVENTIONS
- Controllers inherit from ControllerBase
- Route attributes: [ApiController], [Route("api/[controller]")]
- All actions return Task<IActionResult> or Task<BaseResponse<T>>
- Use DTOs for all request/response data
- HTTP verb attributes: [HttpGet], [HttpPost], [HttpPut], [HttpDelete]
- Validation via model state and attributes
## ANTI-PATTERNS (THIS LAYER)
- Never return domain entities directly
- Don't access repositories from controllers (use services)
- Avoid business logic in controllers
- No synchronous I/O operations
- Don't skip authentication/authorization where needed
## UNIQUE STYLES
- BaseResponse<T> wrapper for consistent API format
- PagedResponse<T> for list endpoints
- Chinese error messages for user-facing errors
- JWT-based authentication patterns
- Swagger/OpenAPI documentation via attributes

View File

@@ -4,6 +4,7 @@ namespace WebApi.Controllers;
[Route("api/[controller]/[action]")]
public class TransactionRecordController(
ITransactionRecordRepository transactionRepository,
ITransactionStatisticsService transactionStatisticsService,
ISmartHandleService smartHandleService,
ILogger<TransactionRecordController> logger,
IConfigService configService
@@ -34,27 +35,27 @@ public class TransactionRecordController(
: classify.Split(',', StringSplitOptions.RemoveEmptyEntries);
TransactionType? transactionType = type.HasValue ? (TransactionType)type.Value : null;
var list = await transactionRepository.GetPagedListAsync(
pageIndex,
pageSize,
searchKeyword,
classifies,
transactionType,
year,
month,
startDate,
endDate,
reason,
sortByAmount);
var total = await transactionRepository.GetTotalCountAsync(
searchKeyword,
classifies,
transactionType,
year,
month,
startDate,
endDate,
reason);
var list = await transactionRepository.QueryAsync(
year: year,
month: month,
startDate: startDate,
endDate: endDate,
type: transactionType,
classifies: classifies,
searchKeyword: searchKeyword,
reason: reason,
pageIndex: pageIndex,
pageSize: pageSize,
sortByAmount: sortByAmount);
var total = await transactionRepository.CountAsync(
year: year,
month: month,
startDate: startDate,
endDate: endDate,
type: transactionType,
classifies: classifies,
searchKeyword: searchKeyword,
reason: reason);
return new PagedResponse<TransactionRecord>
{
@@ -267,7 +268,7 @@ public class TransactionRecordController(
var savingClassify = await configService.GetConfigByKeyAsync<string>("SavingsCategories");
// 获取每日统计数据
var statistics = await transactionRepository.GetDailyStatisticsAsync(year, month, savingClassify);
var statistics = await transactionStatisticsService.GetDailyStatisticsAsync(year, month, savingClassify);
// 按日期排序并计算累积余额
var sortedStats = statistics.OrderBy(s => s.Key).ToList();
@@ -308,7 +309,7 @@ public class TransactionRecordController(
// 获取存款分类
var savingClassify = await configService.GetConfigByKeyAsync<string>("SavingsCategories");
var statistics = await transactionRepository.GetDailyStatisticsAsync(year, month, savingClassify);
var statistics = await transactionStatisticsService.GetDailyStatisticsAsync(year, month, savingClassify);
var result = statistics.Select(s => new DailyStatisticsDto(
s.Key,
s.Value.count,
@@ -339,7 +340,7 @@ public class TransactionRecordController(
{
try
{
var statistics = await transactionRepository.GetMonthlyStatisticsAsync(year, month);
var statistics = await transactionStatisticsService.GetMonthlyStatisticsAsync(year, month);
return statistics.Ok();
}
catch (Exception ex)
@@ -361,7 +362,7 @@ public class TransactionRecordController(
{
try
{
var statistics = await transactionRepository.GetCategoryStatisticsAsync(year, month, type);
var statistics = await transactionStatisticsService.GetCategoryStatisticsAsync(year, month, type);
return statistics.Ok();
}
catch (Exception ex)
@@ -383,7 +384,7 @@ public class TransactionRecordController(
{
try
{
var statistics = await transactionRepository.GetTrendStatisticsAsync(startYear, startMonth, monthCount);
var statistics = await transactionStatisticsService.GetTrendStatisticsAsync(startYear, startMonth, monthCount);
return statistics.Ok();
}
catch (Exception ex)
@@ -439,7 +440,7 @@ public class TransactionRecordController(
var startDate = targetDate.Date;
var endDate = startDate.AddDays(1);
var records = await transactionRepository.GetByDateRangeAsync(startDate, endDate);
var records = await transactionRepository.QueryAsync(startDate: startDate, endDate: endDate);
return records.Ok();
}
@@ -458,7 +459,7 @@ public class TransactionRecordController(
{
try
{
var count = await transactionRepository.GetUnclassifiedCountAsync();
var count = (int)await transactionRepository.CountAsync();
return count.Ok();
}
catch (Exception ex)
@@ -627,7 +628,7 @@ public class TransactionRecordController(
{
try
{
var (list, total) = await transactionRepository.GetReasonGroupsAsync(pageIndex, pageSize);
var (list, total) = await transactionStatisticsService.GetReasonGroupsAsync(pageIndex, pageSize);
return new PagedResponse<ReasonGroupDto>
{
Success = true,