Files
ledgerly/src/main/java/com/example/finance/controller/TransactionController.java
T
rosercode 65c0d8c550 feat: 新增标签体系、微信账单导入与收支记录体验优化
- 标签:新增 t_tag / t_transaction_tag 表与标签 CRUD,支持交易打标签、按标签筛选、批量添加/移除标签、导入账单默认标签,新增标签管理页
- 账单导入:新增微信支付 xlsx 解析器(WechatBillParser),支持支付宝 / 微信按类型导入;解析行保存原始完整数据(raw_data)并可在列表查看
- 收支记录:排序移至顶部并改为服务端排序(交易时间 / 金额,记忆偏好);筛选条件收纳为「更多筛选」弹层;分类筛选显示图标;一键设置支持「计入统计」;导入预览支持关键字 / 类型 / 状态 / 金额筛选
- 数据库:init.sql 新增 raw_data 字段与标签表,新增 init_tags.sql 默认标签种子
- 其他:更新 README 测试账号
2026-09-17 16:47:26 +08:00

212 lines
9.0 KiB
Java

package com.example.finance.controller;
import com.alibaba.excel.EasyExcel;
import com.example.finance.common.PageResult;
import com.example.finance.common.Result;
import com.example.finance.dto.BatchCategoryRequest;
import com.example.finance.dto.BatchTagRequest;
import com.example.finance.dto.TransactionQuery;
import com.example.finance.dto.TransactionRequest;
import com.example.finance.service.TransactionService;
import com.example.finance.vo.TransactionExportVO;
import com.example.finance.vo.TransactionVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
/**
* 交易记录控制器
*
* <p>提供交易记录的分页查询、新增、更新、删除接口</p>
*/
@RestController
@RequestMapping("/api/transaction")
@Tag(name = "交易记录管理", description = "收支交易记录的增删改查相关接口")
public class TransactionController {
private final TransactionService transactionService;
public TransactionController(TransactionService transactionService) {
this.transactionService = transactionService;
}
/**
* 分页查询交易记录
*
* @param request HTTP请求,从中获取用户ID
* @param query 分页查询参数
* @return 分页交易记录列表
*/
@GetMapping("/page")
@Operation(summary = "分页查询交易记录", description = "根据查询条件分页获取当前用户的交易记录")
public Result<PageResult<TransactionVO>> page(HttpServletRequest request,
@Parameter(description = "分页查询参数") TransactionQuery query) {
Long userId = (Long) request.getAttribute("userId");
return Result.success(transactionService.page(userId, query));
}
/**
* 新增交易记录
*
* @param request HTTP请求,从中获取用户ID
* @param transactionRequest 交易记录请求参数
* @return 操作结果
*/
@PostMapping
@Operation(summary = "新增交易记录", description = "为当前用户新增一条交易记录")
public Result<Void> create(HttpServletRequest request, @RequestBody @Valid TransactionRequest transactionRequest) {
Long userId = (Long) request.getAttribute("userId");
transactionService.create(userId, transactionRequest);
return Result.success();
}
/**
* 更新交易记录
*
* @param request HTTP请求,从中获取用户ID
* @param id 交易记录ID
* @param transactionRequest 交易记录请求参数
* @return 操作结果
*/
@PutMapping("/{id}")
@Operation(summary = "更新交易记录", description = "根据交易记录ID更新交易信息")
public Result<Void> update(HttpServletRequest request,
@Parameter(description = "交易记录ID") @PathVariable Long id,
@RequestBody @Valid TransactionRequest transactionRequest) {
Long userId = (Long) request.getAttribute("userId");
transactionService.update(userId, id, transactionRequest);
return Result.success();
}
/**
* 删除交易记录
*
* @param request HTTP请求,从中获取用户ID
* @param id 交易记录ID
* @return 操作结果
*/
@DeleteMapping("/{id}")
@Operation(summary = "删除交易记录", description = "根据交易记录ID删除指定交易记录")
public Result<Void> delete(HttpServletRequest request,
@Parameter(description = "交易记录ID") @PathVariable Long id) {
Long userId = (Long) request.getAttribute("userId");
transactionService.delete(userId, id);
return Result.success();
}
/**
* 切换交易记录的"计入统计"标记
*
* @param request HTTP请求,从中获取用户ID
* @param id 交易记录ID
* @param body 请求体,包含 includeInStats 字段
* @return 操作结果
*/
@PutMapping("/{id}/stats")
@Operation(summary = "切换计入统计标记", description = "切换交易记录是否计入统计(用于表格中开关)")
public Result<Void> toggleStats(HttpServletRequest request,
@Parameter(description = "交易记录ID") @PathVariable Long id,
@RequestBody Map<String, Boolean> body) {
Long userId = (Long) request.getAttribute("userId");
Boolean includeInStats = body != null ? body.get("includeInStats") : null;
transactionService.toggleStats(userId, id, includeInStats);
return Result.success();
}
/**
* 切换交易记录的备注隐藏标记
*
* @param request HTTP请求,从中获取用户ID
* @param id 交易记录ID
* @param body 请求体,包含 remarkHidden 字段
* @return 操作结果
*/
@PutMapping("/{id}/remark-hidden")
@Operation(summary = "切换备注隐藏标记", description = "切换交易记录的备注是否隐藏(用于表格中单元格按钮)")
public Result<Void> toggleRemarkHidden(HttpServletRequest request,
@Parameter(description = "交易记录ID") @PathVariable Long id,
@RequestBody Map<String, Boolean> body) {
Long userId = (Long) request.getAttribute("userId");
Boolean remarkHidden = body != null ? body.get("remarkHidden") : null;
transactionService.toggleRemarkHidden(userId, id, remarkHidden);
return Result.success();
}
/**
* 批量设置交易记录的分类
*
* @param request HTTP请求,从中获取用户ID
* @param body 批量设置请求参数
* @return 实际更新的记录数
*/
@PutMapping("/batch-category")
@Operation(summary = "批量设置分类", description = "将当前表格展示的多条交易记录按类型一键归入所选分类")
public Result<Integer> batchUpdateCategory(HttpServletRequest request,
@RequestBody @Valid BatchCategoryRequest body) {
Long userId = (Long) request.getAttribute("userId");
return Result.success(transactionService.batchUpdateCategory(userId, body));
}
/**
* 批量给交易记录添加/移除标签
*
* @param request HTTP请求,从中获取用户ID
* @param body 批量标签请求参数
* @return 涉及的记录数
*/
@PutMapping("/batch-tags")
@Operation(summary = "批量设置标签", description = "为选中的交易记录添加或移除标签")
public Result<Integer> batchTags(HttpServletRequest request,
@RequestBody @Valid BatchTagRequest body) {
Long userId = (Long) request.getAttribute("userId");
return Result.success(transactionService.batchTags(userId, body));
}
/**
* 导出交易记录为 Excel 文件
*
* @param request HTTP请求,从中获取用户ID
* @param response HTTP响应,用于输出文件流
* @param query 查询条件
* @throws IOException 文件输出异常
*/
@GetMapping("/export")
@Operation(summary = "导出交易记录", description = "根据查询条件导出交易记录为 Excel 文件")
public void export(HttpServletRequest request,
HttpServletResponse response,
@Parameter(description = "查询条件") TransactionQuery query) throws IOException {
Long userId = (Long) request.getAttribute("userId");
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("交易记录_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")), StandardCharsets.UTF_8).replaceAll("\\+", "%20");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
// 查询数据并写入 Excel
List<TransactionExportVO> data = transactionService.export(userId, query);
EasyExcel.write(response.getOutputStream(), TransactionExportVO.class)
.sheet("交易记录")
.doWrite(data);
}
}