2025-12-25 11:20:56 +08:00
|
|
|
|
namespace WebApi.Controllers;
|
|
|
|
|
|
|
|
|
|
|
|
[ApiController]
|
|
|
|
|
|
[Route("api/[controller]/[action]")]
|
|
|
|
|
|
public class TransactionCategoryController(
|
|
|
|
|
|
ITransactionCategoryRepository categoryRepository,
|
2026-01-01 15:20:59 +08:00
|
|
|
|
ITransactionRecordRepository transactionRecordRepository,
|
2026-01-07 19:55:00 +08:00
|
|
|
|
ILogger<TransactionCategoryController> logger,
|
|
|
|
|
|
IBudgetRepository budgetRepository
|
2025-12-25 11:20:56 +08:00
|
|
|
|
) : ControllerBase
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
2025-12-26 15:21:31 +08:00
|
|
|
|
/// 获取分类列表(支持按类型筛选)
|
2025-12-25 11:20:56 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpGet]
|
2025-12-26 15:21:31 +08:00
|
|
|
|
public async Task<BaseResponse<List<TransactionCategory>>> GetListAsync([FromQuery] TransactionType? type = null)
|
2025-12-25 11:20:56 +08:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-12-26 15:21:31 +08:00
|
|
|
|
List<TransactionCategory> categories;
|
|
|
|
|
|
if (type.HasValue)
|
2025-12-25 11:20:56 +08:00
|
|
|
|
{
|
2025-12-26 15:21:31 +08:00
|
|
|
|
categories = await categoryRepository.GetCategoriesByTypeAsync(type.Value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
2025-12-25 11:20:56 +08:00
|
|
|
|
{
|
2025-12-26 15:21:31 +08:00
|
|
|
|
categories = (await categoryRepository.GetAllAsync()).ToList();
|
|
|
|
|
|
}
|
2026-01-30 10:41:19 +08:00
|
|
|
|
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return categories.Ok();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2025-12-26 15:21:31 +08:00
|
|
|
|
logger.LogError(ex, "获取分类列表失败");
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return $"获取分类列表失败: {ex.Message}".Fail<List<TransactionCategory>>();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 根据ID获取分类详情
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpGet("{id}")]
|
|
|
|
|
|
public async Task<BaseResponse<TransactionCategory>> GetByIdAsync(long id)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var category = await categoryRepository.GetByIdAsync(id);
|
|
|
|
|
|
if (category == null)
|
|
|
|
|
|
{
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return "分类不存在".Fail<TransactionCategory>();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return category.Ok();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogError(ex, "获取分类详情失败, Id: {Id}", id);
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return $"获取分类详情失败: {ex.Message}".Fail<TransactionCategory>();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建分类
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpPost]
|
|
|
|
|
|
public async Task<BaseResponse<long>> CreateAsync([FromBody] CreateCategoryDto dto)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 检查同名分类
|
2025-12-26 15:21:31 +08:00
|
|
|
|
var existing = await categoryRepository.GetByNameAndTypeAsync(dto.Name, dto.Type);
|
2025-12-25 11:20:56 +08:00
|
|
|
|
if (existing != null)
|
|
|
|
|
|
{
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return "已存在相同名称的分类".Fail<long>();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var category = new TransactionCategory
|
|
|
|
|
|
{
|
|
|
|
|
|
Name = dto.Name,
|
2025-12-26 15:21:31 +08:00
|
|
|
|
Type = dto.Type
|
2025-12-25 11:20:56 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var result = await categoryRepository.AddAsync(category);
|
|
|
|
|
|
if (result)
|
|
|
|
|
|
{
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return category.Id.Ok();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
2026-01-18 22:04:56 +08:00
|
|
|
|
|
|
|
|
|
|
return "创建分类失败".Fail<long>();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogError(ex, "创建分类失败, Dto: {@Dto}", dto);
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return $"创建分类失败: {ex.Message}".Fail<long>();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新分类
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpPost]
|
|
|
|
|
|
public async Task<BaseResponse> UpdateAsync([FromBody] UpdateCategoryDto dto)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var category = await categoryRepository.GetByIdAsync(dto.Id);
|
|
|
|
|
|
if (category == null)
|
|
|
|
|
|
{
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return "分类不存在".Fail();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果修改了名称,检查同名
|
|
|
|
|
|
if (category.Name != dto.Name)
|
|
|
|
|
|
{
|
2025-12-26 15:21:31 +08:00
|
|
|
|
var existing = await categoryRepository.GetByNameAndTypeAsync(dto.Name, category.Type);
|
2025-12-25 11:20:56 +08:00
|
|
|
|
if (existing != null && existing.Id != dto.Id)
|
|
|
|
|
|
{
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return "已存在相同名称的分类".Fail();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
2026-01-01 15:20:59 +08:00
|
|
|
|
|
|
|
|
|
|
// 同步更新交易记录中的分类名称
|
|
|
|
|
|
await transactionRecordRepository.UpdateCategoryNameAsync(category.Name, dto.Name, category.Type);
|
2026-01-07 19:55:00 +08:00
|
|
|
|
await budgetRepository.UpdateBudgetCategoryNameAsync(category.Name, dto.Name, category.Type);
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
category.Name = dto.Name;
|
|
|
|
|
|
category.UpdateTime = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
|
|
var success = await categoryRepository.UpdateAsync(category);
|
|
|
|
|
|
if (success)
|
|
|
|
|
|
{
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return "更新分类成功".Ok();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
2026-01-18 22:04:56 +08:00
|
|
|
|
|
|
|
|
|
|
return "更新分类失败".Fail();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogError(ex, "更新分类失败, Dto: {@Dto}", dto);
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return $"更新分类失败: {ex.Message}".Fail();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 删除分类
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpPost]
|
|
|
|
|
|
public async Task<BaseResponse> DeleteAsync([FromQuery] long id)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 检查是否被使用
|
|
|
|
|
|
var inUse = await categoryRepository.IsCategoryInUseAsync(id);
|
|
|
|
|
|
if (inUse)
|
|
|
|
|
|
{
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return "该分类已被使用,无法删除".Fail();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var success = await categoryRepository.DeleteAsync(id);
|
|
|
|
|
|
if (success)
|
|
|
|
|
|
{
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return BaseResponse.Done();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
2026-01-18 22:04:56 +08:00
|
|
|
|
|
|
|
|
|
|
return "删除分类失败,分类不存在".Fail();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogError(ex, "删除分类失败, Id: {Id}", id);
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return $"删除分类失败: {ex.Message}".Fail();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 批量创建分类(用于初始化)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpPost]
|
|
|
|
|
|
public async Task<BaseResponse<int>> BatchCreateAsync([FromBody] List<CreateCategoryDto> dtoList)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var categories = dtoList.Select(dto => new TransactionCategory
|
|
|
|
|
|
{
|
|
|
|
|
|
Name = dto.Name,
|
2025-12-26 15:21:31 +08:00
|
|
|
|
Type = dto.Type
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
var result = await categoryRepository.AddRangeAsync(categories);
|
|
|
|
|
|
if (result)
|
|
|
|
|
|
{
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return categories.Count.Ok();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
2026-01-18 22:04:56 +08:00
|
|
|
|
|
|
|
|
|
|
return "批量创建分类失败".Fail<int>();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogError(ex, "批量创建分类失败, Count: {Count}", dtoList.Count);
|
2026-01-04 16:43:32 +08:00
|
|
|
|
return $"批量创建分类失败: {ex.Message}".Fail<int>();
|
2025-12-25 11:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建分类DTO
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public record CreateCategoryDto(
|
|
|
|
|
|
string Name,
|
2025-12-26 15:21:31 +08:00
|
|
|
|
TransactionType Type
|
2025-12-25 11:20:56 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新分类DTO
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public record UpdateCategoryDto(
|
|
|
|
|
|
long Id,
|
2025-12-26 15:21:31 +08:00
|
|
|
|
string Name
|
2025-12-25 11:20:56 +08:00
|
|
|
|
);
|