feat: Refactor transaction handling and add new features

- Updated ReasonGroupList.vue to modify classify button behavior for adding new classifications.
- Refactored TransactionDetail.vue to integrate PopupContainer and enhance transaction detail display.
- Improved TransactionDetailDialog.vue with updated classify button functionality.
- Simplified BalanceView.vue by removing manual entry button.
- Enhanced PeriodicRecord.vue to update classify button interactions.
- Removed unused add transaction dialog from TransactionsRecord.vue.
- Added new API endpoints in TransactionRecordController for parsing transactions and handling offsets.
- Introduced BillForm.vue and ManualBillAdd.vue for streamlined bill entry.
- Implemented OneLineBillAdd.vue for intelligent transaction parsing.
- Created GlobalAddBill.vue for a unified bill addition interface.
This commit is contained in:
2026-01-01 14:43:43 +08:00
parent 8dfe7f1688
commit e00b5cffb7
18 changed files with 977 additions and 384 deletions

View File

@@ -132,6 +132,8 @@ public class TransactionRecordController(
Type = dto.Type,
Classify = dto.Classify ?? string.Empty,
ImportFrom = "手动录入",
ImportNo = Guid.NewGuid().ToString("N"),
Card = "手动",
EmailMessageId = 0 // 手动录入的记录EmailMessageId 设为 0
};
@@ -546,6 +548,80 @@ public class TransactionRecordController(
}
}
/// <summary>
/// 一句话录账解析
/// </summary>
[HttpPost]
public async Task<BaseResponse<TransactionParseResult>> ParseOneLine([FromBody] ParseOneLineRequestDto request)
{
if (string.IsNullOrEmpty(request.Text))
{
return BaseResponse<TransactionParseResult>.Fail("请求参数缺失text");
}
try
{
var result = await smartHandleService.ParseOneLineBillAsync(request.Text);
if (result == null)
{
return BaseResponse<TransactionParseResult>.Fail("AI解析失败");
}
return BaseResponse<TransactionParseResult>.Done(result);
}
catch (Exception ex)
{
logger.LogError(ex, "一句话录账解析失败,文本: {Text}", request.Text);
return BaseResponse<TransactionParseResult>.Fail("AI解析失败: " + ex.Message);
}
}
/// <summary>
/// 获取抵账候选列表
/// </summary>
[HttpGet("{id}")]
public async Task<BaseResponse<TransactionRecord[]>> GetCandidatesForOffset(long id)
{
try
{
var current = await transactionRepository.GetByIdAsync(id);
if (current == null)
{
return BaseResponse<TransactionRecord[]>.Done([]);
}
var list = await transactionRepository.GetCandidatesForOffsetAsync(id, current.Amount, current.Type);
return BaseResponse<TransactionRecord[]>.Done(list.ToArray());
}
catch (Exception ex)
{
logger.LogError(ex, "获取抵账候选列表失败交易ID: {TransactionId}", id);
return BaseResponse<TransactionRecord[]>.Fail($"获取抵账候选列表失败: {ex.Message}");
}
}
/// <summary>
/// 抵账(删除两笔交易)
/// </summary>
[HttpPost]
public async Task<IActionResult> OffsetTransactions([FromBody] OffsetTransactionDto dto)
{
var t1 = await transactionRepository.GetByIdAsync(dto.Id1);
var t2 = await transactionRepository.GetByIdAsync(dto.Id2);
if (t1 == null || t2 == null)
{
return NotFound("交易记录不存在");
}
await transactionRepository.DeleteAsync(dto.Id1);
await transactionRepository.DeleteAsync(dto.Id2);
return Ok(new { success = true, message = "抵账成功" });
}
private async Task WriteEventAsync(string eventType, string data)
{
var message = $"event: {eventType}\ndata: {data}\n\n";
@@ -635,3 +711,16 @@ public record BatchUpdateByReasonDto(
public record BillAnalysisRequest(
string UserInput
);
/// <summary>
/// 抵账请求DTO
/// </summary>
public record OffsetTransactionDto(
long Id1,
long Id2
);
public record ParseOneLineRequestDto(
string Text
);