using Application.Dto.Transaction; using Service.AI; using Application; namespace WebApi.Controllers; [ApiController] [Route("api/[controller]/[action]")] public class TransactionRecordController( ITransactionApplication transactionApplication, ITransactionRecordRepository transactionRepository, ILogger logger ) : ControllerBase { /// /// 获取交易记录列表(分页) /// [HttpGet] public async Task> GetListAsync( [FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 20, [FromQuery] string? searchKeyword = null, [FromQuery] string? classify = null, [FromQuery] int? type = null, [FromQuery] int? year = null, [FromQuery] int? month = null, [FromQuery] DateTime? startDate = null, [FromQuery] DateTime? endDate = null, [FromQuery] string? reason = null, [FromQuery] bool sortByAmount = false ) { var request = new TransactionQueryRequest { PageIndex = pageIndex, PageSize = pageSize, SearchKeyword = searchKeyword, Classify = classify, Type = type, Year = year, Month = month, StartDate = startDate, EndDate = endDate, Reason = reason, SortByAmount = sortByAmount }; var result = await transactionApplication.GetListAsync(request); return new PagedResponse { Success = true, Data = result.Data, Total = result.Total }; } /// /// 获取待确认分类的交易记录列表 /// [HttpGet] public async Task>> GetUnconfirmedListAsync() { var list = await transactionApplication.GetUnconfirmedListAsync(); return list.Ok(); } /// /// 全部确认待确认的交易分类 /// [HttpPost] public async Task> ConfirmAllUnconfirmedAsync([FromBody] ConfirmAllUnconfirmedRequest request) { var count = await transactionApplication.ConfirmAllUnconfirmedAsync(request.Ids); return count.Ok(); } /// /// 根据ID获取交易记录详情 /// [HttpGet("{id}")] public async Task> GetByIdAsync(long id) { var transaction = await transactionApplication.GetByIdAsync(id); return transaction.Ok(); } /// /// 根据邮件ID获取交易记录列表 /// [HttpGet("{emailId}")] public async Task>> GetByEmailIdAsync(long emailId) { var transactions = await transactionApplication.GetByEmailIdAsync(emailId); return transactions.Ok(); } /// /// 创建交易记录 /// [HttpPost] public async Task CreateAsync([FromBody] CreateTransactionRequest request) { await transactionApplication.CreateAsync(request); return BaseResponse.Done(); } /// /// 更新交易记录 /// [HttpPost] public async Task UpdateAsync([FromBody] UpdateTransactionRequest request) { await transactionApplication.UpdateAsync(request); return BaseResponse.Done(); } /// /// 删除交易记录 /// [HttpPost] public async Task DeleteByIdAsync([FromQuery] long id) { await transactionApplication.DeleteByIdAsync(id); return BaseResponse.Done(); } /// /// 智能分析账单(流式输出) /// [HttpPost] public async Task AnalyzeBillAsync([FromBody] BillAnalysisRequest request) { // SSE响应头设置(保留在Controller) Response.ContentType = "text/event-stream"; Response.Headers.Append("Cache-Control", "no-cache"); Response.Headers.Append("Connection", "keep-alive"); if (string.IsNullOrWhiteSpace(request.UserInput)) { await WriteEventAsync("
请输入分析内容
"); return; } // 调用Application,传递回调 await transactionApplication.AnalyzeBillAsync( request.UserInput, async chunk => { try { await WriteEventAsync(chunk); } catch (Exception e) { logger.LogError(e, "流式写入账单分析结果失败"); } }); } /// /// 获取指定日期的交易记录 /// [HttpGet] public async Task>> GetByDateAsync([FromQuery] string date) { var dateTime = DateTime.Parse(date); var records = await transactionApplication.GetByDateAsync(dateTime); return records.Ok(); } /// /// 获取未分类的账单数量 /// [HttpGet] public async Task> GetUnclassifiedCountAsync() { var count = await transactionApplication.GetUnclassifiedCountAsync(); return count.Ok(); } /// /// 获取未分类的账单列表 /// [HttpGet] public async Task>> GetUnclassifiedAsync([FromQuery] int pageSize = 10) { var records = await transactionApplication.GetUnclassifiedAsync(pageSize); return records.Ok(); } /// /// 智能分类 - 使用AI对账单进行分类(流式响应) /// [HttpPost] public async Task SmartClassifyAsync([FromBody] SmartClassifyRequest request) { // SSE响应头设置(保留在Controller) Response.ContentType = "text/event-stream"; Response.Headers.Append("Cache-Control", "no-cache"); Response.Headers.Append("Connection", "keep-alive"); // 验证账单ID列表 if (request.TransactionIds == null || request.TransactionIds.Count == 0) { await WriteEventAsync("error", "请提供要分类的账单ID"); return; } // 调用Application,传递回调 await transactionApplication.SmartClassifyAsync( request.TransactionIds.ToArray(), async chunk => { try { var (eventType, content) = chunk; await TrySetUnconfirmedAsync(eventType, content); await WriteEventAsync(eventType, content); } catch (Exception e) { logger.LogError(e, "流式写入智能分类结果失败"); } }); await Response.Body.FlushAsync(); } /// /// Controller专属逻辑:解析AI返回的JSON并更新交易记录的UnconfirmedClassify字段 /// private async Task TrySetUnconfirmedAsync(string eventType, string content) { if (eventType != "data") { return; } try { var jsonObject = JsonSerializer.Deserialize(content); var id = jsonObject?["id"]?.GetValue() ?? 0; var classify = jsonObject?["Classify"]?.GetValue() ?? string.Empty; var typeValue = jsonObject?["Type"]?.GetValue() ?? -1; if (id == 0 || typeValue == -1 || string.IsNullOrEmpty(classify)) { logger.LogWarning("解析智能分类结果时,发现无效数据,内容: {Content}", content); return; } var record = await transactionRepository.GetByIdAsync(id); if (record == null) { logger.LogWarning("解析智能分类结果时,未找到对应的交易记录,ID: {Id}", id); return; } record.UnconfirmedClassify = classify; record.UnconfirmedType = (TransactionType)typeValue; var success = await transactionRepository.UpdateAsync(record); if (!success) { logger.LogWarning("解析智能分类结果时,更新交易记录失败,ID: {Id}", id); } } catch (Exception ex) { logger.LogError(ex, "解析智能分类结果失败,内容: {Content}", content); } } /// /// 批量更新账单分类 /// [HttpPost] public async Task BatchUpdateClassifyAsync([FromBody] List items) { var count = await transactionApplication.BatchUpdateClassifyAsync(items); return $"批量更新完成,成功 {count} 条".Ok(); } /// /// 按摘要批量更新分类 /// [HttpPost] public async Task> BatchUpdateByReasonAsync([FromBody] BatchUpdateByReasonRequest request) { var count = await transactionApplication.BatchUpdateByReasonAsync(request); return count.Ok($"成功更新 {count} 条记录"); } /// /// 一句话录账解析 /// [HttpPost] public async Task> ParseOneLine([FromBody] ParseOneLineRequest request) { var result = await transactionApplication.ParseOneLineAsync(request.Text); return result.Ok(); } /// /// SSE辅助方法:写入事件(带类型) /// private async Task WriteEventAsync(string eventType, string data) { var message = $"event: {eventType}\ndata: {data}\n\n"; await Response.WriteAsync(message); await Response.Body.FlushAsync(); } /// /// SSE辅助方法:写入数据 /// private async Task WriteEventAsync(string data) { var message = $"data: {data}\n\n"; await Response.WriteAsync(message); await Response.Body.FlushAsync(); } } /// /// 智能分类请求DTO /// public record SmartClassifyRequest( List? TransactionIds = null ); /// /// 账单分析请求DTO /// public record BillAnalysisRequest( string UserInput );