refactor: 统一用户上下文、导入顺序与日志规范
- 控制器移除 HttpServletRequest/HttpServletResponse 参数,新增 util/UserContext 统一获取当前用户 ID 与响应对象,导出接口改用 UserContext.getResponse() - 引入 Spotless 统一 Java 导入顺序(java/javax → 第三方库 → cn.rosercode),并全量重排 - 日志统一改用 Lombok @Slf4j,替换手写 LoggerFactory - 补充关键业务日志:登录/注册、交易增删改与批量操作、账单解析导入、DeepSeek 调用耗时与失败、AI 配置与连接测试、通知发送、分类/标签/规则变更 - 全局异常处理补充日志,未捕获异常由 e.printStackTrace() 改为 log.error 记录堆栈 - README 补充功能特性、技术栈与目录结构说明
This commit is contained in:
@@ -1,11 +1,5 @@
|
||||
package cn.rosercode.finance.client;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
@@ -17,12 +11,21 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
|
||||
/**
|
||||
* DeepSeek 客户端,封装 Chat Completions 接口的 HTTP 调用与响应解析。
|
||||
*
|
||||
* @date 2026-09-17 17:52:17
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DeepSeekClient {
|
||||
|
||||
/** 单次请求的读取超时时间 */
|
||||
@@ -63,6 +66,7 @@ public class DeepSeekClient {
|
||||
// 兼容以斜杠结尾的 baseUrl
|
||||
String normalized = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
|
||||
String url = normalized + "/chat/completions";
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
// 构造请求体,强制返回 JSON 对象
|
||||
Map<String, Object> body = new LinkedHashMap<>();
|
||||
@@ -79,6 +83,7 @@ public class DeepSeekClient {
|
||||
try {
|
||||
requestBody = objectMapper.writeValueAsString(body);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("构建 AI 请求体失败: model={}, error={}", model, e.getMessage());
|
||||
throw new BusinessException("构建 AI 请求失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
@@ -93,14 +98,18 @@ public class DeepSeekClient {
|
||||
try {
|
||||
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
log.error("调用 DeepSeek 失败: model={}, error={}", model, e.getMessage());
|
||||
throw new BusinessException("调用 DeepSeek 失败: " + e.getMessage());
|
||||
} catch (InterruptedException e) {
|
||||
// 恢复中断标记,避免吞掉中断信号
|
||||
Thread.currentThread().interrupt();
|
||||
log.warn("调用 DeepSeek 被中断: model={}", model);
|
||||
throw new BusinessException("调用 DeepSeek 被中断");
|
||||
}
|
||||
|
||||
if (response.statusCode() != 200) {
|
||||
log.warn("DeepSeek 返回异常状态: model={}, status={}, body={}",
|
||||
model, response.statusCode(), truncate(response.body()));
|
||||
throw new BusinessException("DeepSeek 返回异常(" + response.statusCode() + "): " + truncate(response.body()));
|
||||
}
|
||||
|
||||
@@ -119,6 +128,8 @@ public class DeepSeekClient {
|
||||
result.setTotalTokens(usage.path("total_tokens").asInt(0));
|
||||
// DeepSeek 用 prompt_cache_hit_tokens 表示缓存命中的输入 token
|
||||
result.setCachedTokens(usage.path("prompt_cache_hit_tokens").asInt(0));
|
||||
log.info("DeepSeek 调用完成: model={}, 耗时={}ms, tokens={}", model,
|
||||
System.currentTimeMillis() - start, result.getTotalTokens());
|
||||
return result;
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new BusinessException("解析 DeepSeek 响应失败: " + e.getMessage());
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package cn.rosercode.finance.common;
|
||||
|
||||
import cn.rosercode.finance.config.SpaRouteSupport;
|
||||
import java.io.IOException;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
@@ -11,13 +13,14 @@ import org.springframework.web.context.request.async.AsyncRequestNotUsableExcept
|
||||
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
|
||||
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
||||
|
||||
import java.io.IOException;
|
||||
import cn.rosercode.finance.config.SpaRouteSupport;
|
||||
|
||||
/**
|
||||
* 全局异常处理器。
|
||||
* <p>统一捕获并处理控制器层抛出的各类异常,将其转换为标准化的 JSON 响应返回给前端。</p>
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
@@ -28,6 +31,7 @@ public class GlobalExceptionHandler {
|
||||
*/
|
||||
@ExceptionHandler(BusinessException.class)
|
||||
public Result<Void> handleBusinessException(BusinessException e) {
|
||||
log.warn("业务异常[{}]: {}", e.getCode(), e.getMessage());
|
||||
return Result.error(e.getCode(), e.getMessage());
|
||||
}
|
||||
|
||||
@@ -53,6 +57,7 @@ public class GlobalExceptionHandler {
|
||||
public Result<Void> handleValidationException(MethodArgumentNotValidException e) {
|
||||
// 提取第一个校验错误信息
|
||||
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
|
||||
log.warn("参数校验失败: {}", message);
|
||||
return Result.error(400, message);
|
||||
}
|
||||
|
||||
@@ -108,8 +113,8 @@ public class GlobalExceptionHandler {
|
||||
if (notConfigured != null) {
|
||||
return Result.error(notConfigured.getCode(), notConfigured.getMessage());
|
||||
}
|
||||
// 打印异常堆栈信息,便于排查问题
|
||||
e.printStackTrace();
|
||||
// 记录异常堆栈,便于排查问题
|
||||
log.error("服务器内部错误: {}", e.getMessage(), e);
|
||||
return Result.error(500, "服务器内部错误: " + e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package cn.rosercode.finance.common;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 分页查询结果封装类。
|
||||
* <p>用于封装分页查询的返回结果,包含数据列表、总记录数、当前页码和每页大小。</p>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package cn.rosercode.finance.config;
|
||||
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package cn.rosercode.finance.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.ServletException;
|
||||
@@ -9,10 +13,6 @@ import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 前端单页应用路由回退控制器。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package cn.rosercode.finance.config;
|
||||
|
||||
import cn.rosercode.finance.interceptor.AccessLogInterceptor;
|
||||
import cn.rosercode.finance.interceptor.JwtInterceptor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import cn.rosercode.finance.interceptor.AccessLogInterceptor;
|
||||
import cn.rosercode.finance.interceptor.JwtInterceptor;
|
||||
|
||||
/**
|
||||
* Web MVC 配置类。
|
||||
* <p>配置拦截器、跨域策略等 Web 层相关设置。</p>
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package cn.rosercode.finance.config.app;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 应用级运行时配置的本地文件存储。
|
||||
*
|
||||
@@ -19,10 +18,9 @@ import java.nio.file.Paths;
|
||||
* @date 2026-09-18 12:09:22
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AppConfigStore {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AppConfigStore.class);
|
||||
|
||||
/** 配置目录 */
|
||||
private static final String CONFIG_DIR = "config";
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package cn.rosercode.finance.config.datasource;
|
||||
|
||||
import cn.rosercode.finance.service.DatabaseService;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.rosercode.finance.service.DatabaseService;
|
||||
|
||||
/**
|
||||
* 数据库启动引导器。
|
||||
*
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package cn.rosercode.finance.config.datasource;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 数据库配置的本地文件存储。
|
||||
*
|
||||
@@ -20,10 +19,9 @@ import java.util.Optional;
|
||||
* @date 2026-09-18 11:00:14
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DatabaseConfigStore {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DatabaseConfigStore.class);
|
||||
|
||||
/** 配置文件相对工作目录的位置 */
|
||||
private static final String CONFIG_DIR = "config";
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package cn.rosercode.finance.config.datasource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
|
||||
/**
|
||||
* 动态数据源,支持在运行时切换底层真实数据源。
|
||||
@@ -19,10 +18,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*
|
||||
* @date 2026-09-18 11:00:28
|
||||
*/
|
||||
@Slf4j
|
||||
public class DynamicDataSource extends AbstractRoutingDataSource {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DynamicDataSource.class);
|
||||
|
||||
/** 自行维护的目标数据源映射,用于运行时增量注册与切换 */
|
||||
private final Map<Object, Object> targetDataSources = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package cn.rosercode.finance.config.datasource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* 数据库表结构初始化器。
|
||||
*
|
||||
@@ -17,10 +16,9 @@ import javax.sql.DataSource;
|
||||
* @date 2026-09-18 11:00:46
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SchemaInitializer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SchemaInitializer.class);
|
||||
|
||||
/** MySQL 建表脚本 */
|
||||
private static final String MYSQL_SCRIPT = "sql/init.sql";
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.config.datasource;
|
||||
|
||||
import cn.rosercode.finance.common.DatabaseNotConfiguredException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Logger;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import cn.rosercode.finance.common.DatabaseNotConfiguredException;
|
||||
|
||||
/**
|
||||
* 未配置数据库时使用的占位数据源。
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.AiApplyRequest;
|
||||
import cn.rosercode.finance.dto.AiCategoryRequest;
|
||||
@@ -18,6 +31,7 @@ import cn.rosercode.finance.service.AiRecordService;
|
||||
import cn.rosercode.finance.service.AiSuggestionService;
|
||||
import cn.rosercode.finance.service.AiTagService;
|
||||
import cn.rosercode.finance.service.AiUsageService;
|
||||
import cn.rosercode.finance.util.UserContext;
|
||||
import cn.rosercode.finance.vo.AiCategoryResultVO;
|
||||
import cn.rosercode.finance.vo.AiConfigVO;
|
||||
import cn.rosercode.finance.vo.AiQueryResultVO;
|
||||
@@ -25,19 +39,6 @@ import cn.rosercode.finance.vo.AiRecordResultVO;
|
||||
import cn.rosercode.finance.vo.AiSuggestionVO;
|
||||
import cn.rosercode.finance.vo.AiTagResultVO;
|
||||
import cn.rosercode.finance.vo.AiUsageResultVO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 控制器
|
||||
@@ -77,27 +78,25 @@ public class AiController {
|
||||
/**
|
||||
* 获取当前用户的 AI 配置
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @return AI 配置(API Key 脱敏)
|
||||
*/
|
||||
@GetMapping("/config")
|
||||
@Operation(summary = "获取 AI 配置", description = "获取当前用户的 AI 智能建议配置,API Key 已脱敏")
|
||||
public Result<AiConfigVO> getConfig(HttpServletRequest request) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<AiConfigVO> getConfig() {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiConfigService.getConfig(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存当前用户的 AI 配置
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param configRequest 配置保存请求
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/config")
|
||||
@Operation(summary = "保存 AI 配置", description = "更新当前用户的 AI 配置,API Key 留空表示不修改")
|
||||
public Result<Void> saveConfig(HttpServletRequest request, @RequestBody AiConfigRequest configRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Void> saveConfig(@RequestBody AiConfigRequest configRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
aiConfigService.saveConfig(userId, configRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -105,13 +104,12 @@ public class AiController {
|
||||
/**
|
||||
* 测试 DeepSeek 连通性
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/config/test")
|
||||
@Operation(summary = "测试连接", description = "使用当前配置向 DeepSeek 发送一条测试请求")
|
||||
public Result<Void> testConfig(HttpServletRequest request) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Void> testConfig() {
|
||||
Long userId = UserContext.getUserId();
|
||||
aiConfigService.testConnection(userId);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -119,150 +117,130 @@ public class AiController {
|
||||
/**
|
||||
* 生成分类与标签建议
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param suggestRequest 建议请求,携带记录ID列表
|
||||
* @return 逐条建议列表
|
||||
*/
|
||||
@PostMapping("/suggest")
|
||||
@Operation(summary = "生成 AI 建议", description = "根据交易记录内容生成分类与标签建议")
|
||||
public Result<List<AiSuggestionVO>> suggest(HttpServletRequest request,
|
||||
@RequestBody @Valid AiSuggestRequest suggestRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<List<AiSuggestionVO>> suggest(@RequestBody @Valid AiSuggestRequest suggestRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiSuggestionService.suggest(userId, suggestRequest.getIds(), suggestRequest.getScope()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表单当前内容推荐分类与标签
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param suggestOneRequest 建议请求,携带表单当前内容
|
||||
* @return 单条建议结果
|
||||
*/
|
||||
@PostMapping("/suggest-one")
|
||||
@Operation(summary = "单条记录 AI 建议", description = "根据表单当前内容推荐分类与标签,供新增或编辑时参考")
|
||||
public Result<AiSuggestionVO> suggestOne(HttpServletRequest request,
|
||||
@RequestBody @Valid AiSuggestOneRequest suggestOneRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<AiSuggestionVO> suggestOne(@RequestBody @Valid AiSuggestOneRequest suggestOneRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiSuggestionService.suggestOne(userId, suggestOneRequest));
|
||||
}
|
||||
|
||||
/**
|
||||
* 一键应用 AI 建议
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param applyRequest 应用请求,携带逐条建议
|
||||
* @return 实际发生变更的记录数
|
||||
*/
|
||||
@PostMapping("/apply")
|
||||
@Operation(summary = "应用 AI 建议", description = "覆盖分类并追加标签,一键写入建议")
|
||||
public Result<Integer> apply(HttpServletRequest request,
|
||||
@RequestBody @Valid AiApplyRequest applyRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Integer> apply(@RequestBody @Valid AiApplyRequest applyRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiSuggestionService.apply(userId, applyRequest));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 AI 使用情况
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param limit 最近明细条数,默认 20
|
||||
* @return 累计汇总与最近调用明细
|
||||
*/
|
||||
@GetMapping("/usage")
|
||||
@Operation(summary = "获取 AI 使用情况", description = "获取当前用户 AI 调用的累计汇总与最近调用明细")
|
||||
public Result<AiUsageResultVO> usage(HttpServletRequest request,
|
||||
@RequestParam(defaultValue = "20") int limit) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<AiUsageResultVO> usage(@RequestParam(defaultValue = "20") int limit) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiUsageService.getUsage(userId, limit));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析自然语言查询为筛选条件
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param queryRequest 查询请求,携带自然语言语句
|
||||
* @return 结构化筛选条件
|
||||
*/
|
||||
@PostMapping("/query")
|
||||
@Operation(summary = "自然语言查询解析", description = "将自然语言查询解析为交易筛选条件,供用户确认后应用")
|
||||
public Result<AiQueryResultVO> query(HttpServletRequest request,
|
||||
@RequestBody @Valid AiQueryRequest queryRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<AiQueryResultVO> query(@RequestBody @Valid AiQueryRequest queryRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiQueryService.parse(userId, queryRequest.getQuery()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析自然语言记账内容为交易记录
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param recordRequest 记账请求,携带自然语言语句
|
||||
* @return 结构化交易记录
|
||||
*/
|
||||
@PostMapping("/record")
|
||||
@Operation(summary = "自然语言记账解析", description = "将自然语言记账内容解析为交易记录,供用户确认后保存")
|
||||
public Result<AiRecordResultVO> record(HttpServletRequest request,
|
||||
@RequestBody @Valid AiRecordRequest recordRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<AiRecordResultVO> record(@RequestBody @Valid AiRecordRequest recordRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiRecordService.parse(userId, recordRequest.getText()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据自然语言描述生成分类
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param categoryRequest 生成请求,携带分类用途描述
|
||||
* @return 分类建议
|
||||
*/
|
||||
@PostMapping("/category")
|
||||
@Operation(summary = "AI 生成分类", description = "根据自然语言描述生成分类名称、类型与图标")
|
||||
public Result<AiCategoryResultVO> generateCategory(HttpServletRequest request,
|
||||
@RequestBody @Valid AiCategoryRequest categoryRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<AiCategoryResultVO> generateCategory(@RequestBody @Valid AiCategoryRequest categoryRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiCategoryService.parse(userId, categoryRequest.getText()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据自然语言描述生成标签
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param tagRequest 生成请求,携带标签用途描述
|
||||
* @return 标签建议
|
||||
*/
|
||||
@PostMapping("/tag")
|
||||
@Operation(summary = "AI 生成标签", description = "根据自然语言描述生成标签名称与颜色")
|
||||
public Result<AiTagResultVO> generateTag(HttpServletRequest request,
|
||||
@RequestBody @Valid AiTagRequest tagRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<AiTagResultVO> generateTag(@RequestBody @Valid AiTagRequest tagRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiTagService.parse(userId, tagRequest.getText()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分类名称推荐 Emoji 图标
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param decorateRequest 建议请求,携带分类名称与收支类型
|
||||
* @return 推荐的 Emoji
|
||||
*/
|
||||
@PostMapping("/emoji")
|
||||
@Operation(summary = "AI 推荐分类图标", description = "根据分类名称与收支类型推荐一个 Emoji")
|
||||
public Result<String> suggestEmoji(HttpServletRequest request,
|
||||
@RequestBody @Valid AiDecorateRequest decorateRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<String> suggestEmoji(@RequestBody @Valid AiDecorateRequest decorateRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiDecorationService.suggestEmoji(userId, decorateRequest.getName(), decorateRequest.getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据标签名称推荐颜色
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param decorateRequest 建议请求,携带标签名称
|
||||
* @return 推荐的十六进制颜色
|
||||
*/
|
||||
@PostMapping("/color")
|
||||
@Operation(summary = "AI 推荐标签颜色", description = "根据标签名称推荐一个十六进制颜色")
|
||||
public Result<String> suggestColor(HttpServletRequest request,
|
||||
@RequestBody @Valid AiDecorateRequest decorateRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<String> suggestColor(@RequestBody @Valid AiDecorateRequest decorateRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(aiDecorationService.suggestColor(userId, decorateRequest.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.config.app.AppConfig;
|
||||
import cn.rosercode.finance.config.app.AppConfigStore;
|
||||
import cn.rosercode.finance.dto.LogRetentionRequest;
|
||||
import cn.rosercode.finance.dto.NotificationUrlRequest;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -13,6 +8,12 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.config.app.AppConfig;
|
||||
import cn.rosercode.finance.config.app.AppConfigStore;
|
||||
import cn.rosercode.finance.dto.LogRetentionRequest;
|
||||
import cn.rosercode.finance.dto.NotificationUrlRequest;
|
||||
|
||||
/**
|
||||
* 应用配置控制器
|
||||
*
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.BillImportRequest;
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
import cn.rosercode.finance.service.BillImportService;
|
||||
import cn.rosercode.finance.vo.BillImportResultVO;
|
||||
import cn.rosercode.finance.vo.BillParseResultVO;
|
||||
import java.io.IOException;
|
||||
|
||||
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.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -19,7 +13,14 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.BillImportRequest;
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
import cn.rosercode.finance.service.BillImportService;
|
||||
import cn.rosercode.finance.util.UserContext;
|
||||
import cn.rosercode.finance.vo.BillImportResultVO;
|
||||
import cn.rosercode.finance.vo.BillParseResultVO;
|
||||
|
||||
/**
|
||||
* 账单导入控制器
|
||||
@@ -42,7 +43,6 @@ public class BillImportController {
|
||||
/**
|
||||
* 解析账单文件(不落库)
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param file 账单文件(支持 csv/xlsx 或 zip 压缩包)
|
||||
* @param billType 账单类型,如 ALIPAY
|
||||
* @param password 压缩包解压密码,未加密时可不传
|
||||
@@ -51,11 +51,10 @@ public class BillImportController {
|
||||
*/
|
||||
@PostMapping("/parse")
|
||||
@Operation(summary = "解析账单文件", description = "解析账单文件(支持 zip 压缩包)并返回预览数据,不写入数据库")
|
||||
public Result<BillParseResultVO> parse(HttpServletRequest request,
|
||||
@Parameter(description = "账单文件") @RequestParam("file") MultipartFile file,
|
||||
public Result<BillParseResultVO> parse(@Parameter(description = "账单文件") @RequestParam("file") MultipartFile file,
|
||||
@Parameter(description = "账单类型,如 ALIPAY") @RequestParam("billType") String billType,
|
||||
@Parameter(description = "压缩包解压密码") @RequestParam(value = "password", required = false) String password) throws IOException {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new BusinessException("请选择账单文件");
|
||||
}
|
||||
@@ -65,15 +64,13 @@ public class BillImportController {
|
||||
/**
|
||||
* 确认导入用户勾选的账单行
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param body 导入请求(默认分类与勾选行)
|
||||
* @param body 导入请求(默认分类与勾选行)
|
||||
* @return 导入结果统计
|
||||
*/
|
||||
@PostMapping("/confirm")
|
||||
@Operation(summary = "确认导入账单", description = "将用户勾选的账单行写入交易记录,按交易号去重")
|
||||
public Result<BillImportResultVO> confirm(HttpServletRequest request,
|
||||
@RequestBody @Valid BillImportRequest body) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<BillImportResultVO> confirm(@RequestBody @Valid BillImportRequest body) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(billImportService.confirm(userId, body));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.CategoryRequest;
|
||||
import cn.rosercode.finance.service.CategoryService;
|
||||
import cn.rosercode.finance.vo.CategoryVO;
|
||||
import java.util.List;
|
||||
|
||||
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.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -19,7 +16,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.CategoryRequest;
|
||||
import cn.rosercode.finance.service.CategoryService;
|
||||
import cn.rosercode.finance.util.UserContext;
|
||||
import cn.rosercode.finance.vo.CategoryVO;
|
||||
|
||||
/**
|
||||
* 分类控制器
|
||||
@@ -40,15 +41,13 @@ public class CategoryController {
|
||||
/**
|
||||
* 获取分类列表
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param type 分类类型(可选),用于按类型筛选
|
||||
* @return 分类列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取分类列表", description = "获取当前用户的全部分类,支持按类型筛选")
|
||||
public Result<List<CategoryVO>> list(HttpServletRequest request,
|
||||
@Parameter(description = "分类类型,可选值:income/expense") @RequestParam(required = false) String type) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<List<CategoryVO>> list(@Parameter(description = "分类类型,可选值:income/expense") @RequestParam(required = false) String type) {
|
||||
Long userId = UserContext.getUserId();
|
||||
if (type != null && !type.isEmpty()) {
|
||||
return Result.success(categoryService.listByType(userId, type));
|
||||
}
|
||||
@@ -58,14 +57,13 @@ public class CategoryController {
|
||||
/**
|
||||
* 创建分类
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param categoryRequest 分类请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping
|
||||
@Operation(summary = "创建分类", description = "为当前用户创建新的收支分类")
|
||||
public Result<Void> create(HttpServletRequest request, @RequestBody @Valid CategoryRequest categoryRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Void> create(@RequestBody @Valid CategoryRequest categoryRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
categoryService.create(userId, categoryRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -73,17 +71,15 @@ public class CategoryController {
|
||||
/**
|
||||
* 更新分类
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param id 分类ID
|
||||
* @param categoryRequest 分类请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "更新分类", description = "根据分类ID更新分类信息")
|
||||
public Result<Void> update(HttpServletRequest request,
|
||||
@Parameter(description = "分类ID") @PathVariable Long id,
|
||||
public Result<Void> update(@Parameter(description = "分类ID") @PathVariable Long id,
|
||||
@RequestBody @Valid CategoryRequest categoryRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
categoryService.update(userId, id, categoryRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -91,15 +87,13 @@ public class CategoryController {
|
||||
/**
|
||||
* 删除分类
|
||||
*
|
||||
* @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");
|
||||
public Result<Void> delete(@Parameter(description = "分类ID") @PathVariable Long id) {
|
||||
Long userId = UserContext.getUserId();
|
||||
categoryService.delete(userId, id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.DatabaseConfigRequest;
|
||||
import cn.rosercode.finance.service.DatabaseService;
|
||||
import cn.rosercode.finance.vo.DatabaseStatusVO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.DatabaseConfigRequest;
|
||||
import cn.rosercode.finance.service.DatabaseService;
|
||||
import cn.rosercode.finance.vo.DatabaseStatusVO;
|
||||
|
||||
/**
|
||||
* 数据库配置控制器。
|
||||
*
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import cn.rosercode.finance.common.PageResult;
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.LogQuery;
|
||||
@@ -8,13 +16,6 @@ import cn.rosercode.finance.service.LogService;
|
||||
import cn.rosercode.finance.vo.AppLogVO;
|
||||
import cn.rosercode.finance.vo.HttpLogVO;
|
||||
import cn.rosercode.finance.vo.LoginLogVO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
/**
|
||||
* 系统日志控制器
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.NotificationChannelRequest;
|
||||
import cn.rosercode.finance.dto.NotificationConfigRequest;
|
||||
import cn.rosercode.finance.service.NotificationChannelService;
|
||||
import cn.rosercode.finance.service.NotificationConfigService;
|
||||
import cn.rosercode.finance.service.NotificationService;
|
||||
import cn.rosercode.finance.vo.NotificationChannelVO;
|
||||
import cn.rosercode.finance.vo.NotificationConfigVO;
|
||||
import cn.rosercode.finance.vo.NotificationLogVO;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -22,7 +14,16 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.NotificationChannelRequest;
|
||||
import cn.rosercode.finance.dto.NotificationConfigRequest;
|
||||
import cn.rosercode.finance.service.NotificationChannelService;
|
||||
import cn.rosercode.finance.service.NotificationConfigService;
|
||||
import cn.rosercode.finance.service.NotificationService;
|
||||
import cn.rosercode.finance.util.UserContext;
|
||||
import cn.rosercode.finance.vo.NotificationChannelVO;
|
||||
import cn.rosercode.finance.vo.NotificationConfigVO;
|
||||
import cn.rosercode.finance.vo.NotificationLogVO;
|
||||
|
||||
/**
|
||||
* 通知控制器
|
||||
@@ -51,28 +52,25 @@ public class NotificationController {
|
||||
/**
|
||||
* 获取当前用户的通知配置。
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @return 通知配置
|
||||
*/
|
||||
@GetMapping("/config")
|
||||
@Operation(summary = "获取通知配置", description = "获取当前用户的账单导入提醒周期配置")
|
||||
public Result<NotificationConfigVO> getConfig(HttpServletRequest request) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<NotificationConfigVO> getConfig() {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(notificationConfigService.getConfig(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存当前用户的通知配置。
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param configRequest 配置保存请求
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/config")
|
||||
@Operation(summary = "保存通知配置", description = "更新当前用户的提醒周期与发送时间")
|
||||
public Result<Void> saveConfig(HttpServletRequest request,
|
||||
@RequestBody NotificationConfigRequest configRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Void> saveConfig(@RequestBody NotificationConfigRequest configRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
notificationConfigService.saveConfig(userId, configRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -80,44 +78,40 @@ public class NotificationController {
|
||||
/**
|
||||
* 查询当前用户的通知渠道。
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @return 渠道列表
|
||||
*/
|
||||
@GetMapping("/channels")
|
||||
@Operation(summary = "查询通知渠道", description = "查询当前用户配置的所有推送渠道")
|
||||
public Result<List<NotificationChannelVO>> listChannels(HttpServletRequest request) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<List<NotificationChannelVO>> listChannels() {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(notificationChannelService.listChannels(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增通知渠道。
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param channelRequest 渠道保存请求
|
||||
* @return 新渠道ID
|
||||
*/
|
||||
@PostMapping("/channels")
|
||||
@Operation(summary = "新增通知渠道", description = "新增邮箱或 Server 酱推送渠道")
|
||||
public Result<Long> createChannel(HttpServletRequest request,
|
||||
@RequestBody NotificationChannelRequest channelRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Long> createChannel(@RequestBody NotificationChannelRequest channelRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(notificationChannelService.createChannel(userId, channelRequest));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改通知渠道。
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param id 渠道ID
|
||||
* @param channelRequest 渠道保存请求
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/channels/{id}")
|
||||
@Operation(summary = "修改通知渠道", description = "更新指定渠道的名称、开关与配置")
|
||||
public Result<Void> updateChannel(HttpServletRequest request, @PathVariable Long id,
|
||||
public Result<Void> updateChannel(@PathVariable Long id,
|
||||
@RequestBody NotificationChannelRequest channelRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
notificationChannelService.updateChannel(userId, id, channelRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -125,14 +119,13 @@ public class NotificationController {
|
||||
/**
|
||||
* 删除通知渠道。
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param id 渠道ID
|
||||
* @param id 渠道ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@DeleteMapping("/channels/{id}")
|
||||
@Operation(summary = "删除通知渠道", description = "删除指定的推送渠道")
|
||||
public Result<Void> deleteChannel(HttpServletRequest request, @PathVariable Long id) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Void> deleteChannel(@PathVariable Long id) {
|
||||
Long userId = UserContext.getUserId();
|
||||
notificationChannelService.deleteChannel(userId, id);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -140,14 +133,13 @@ public class NotificationController {
|
||||
/**
|
||||
* 测试指定渠道。
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param id 渠道ID
|
||||
* @param id 渠道ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/channels/{id}/test")
|
||||
@Operation(summary = "测试通知渠道", description = "向指定渠道发送一条测试消息")
|
||||
public Result<Void> testChannel(HttpServletRequest request, @PathVariable Long id) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Void> testChannel(@PathVariable Long id) {
|
||||
Long userId = UserContext.getUserId();
|
||||
notificationService.sendTest(userId, id);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -155,28 +147,25 @@ public class NotificationController {
|
||||
/**
|
||||
* 立即发送账单导入提醒。
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @return 发送成功的渠道数
|
||||
*/
|
||||
@PostMapping("/send-now")
|
||||
@Operation(summary = "立即发送提醒", description = "跳过周期设置,立即向所有已启用渠道发送账单导入提醒")
|
||||
public Result<Integer> sendNow(HttpServletRequest request) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Integer> sendNow() {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(notificationService.sendReminderNow(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询最近的发送日志。
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param limit 条数上限,默认 20
|
||||
* @param limit 条数上限,默认 20
|
||||
* @return 日志列表
|
||||
*/
|
||||
@GetMapping("/logs")
|
||||
@Operation(summary = "查询发送日志", description = "查询当前用户最近的提醒发送结果")
|
||||
public Result<List<NotificationLogVO>> listLogs(HttpServletRequest request,
|
||||
@RequestParam(defaultValue = "20") int limit) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<List<NotificationLogVO>> listLogs(@RequestParam(defaultValue = "20") int limit) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(notificationService.listLogs(userId, limit));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.RuleRequest;
|
||||
import cn.rosercode.finance.service.RuleService;
|
||||
import cn.rosercode.finance.vo.RuleVO;
|
||||
import java.util.List;
|
||||
|
||||
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.validation.Valid;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
@@ -19,7 +16,11 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.RuleRequest;
|
||||
import cn.rosercode.finance.service.RuleService;
|
||||
import cn.rosercode.finance.util.UserContext;
|
||||
import cn.rosercode.finance.vo.RuleVO;
|
||||
|
||||
/**
|
||||
* 规则控制器
|
||||
@@ -42,27 +43,25 @@ public class RuleController {
|
||||
/**
|
||||
* 获取规则列表
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @return 规则列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取规则列表", description = "获取当前用户的全部规则,按优先级排序")
|
||||
public Result<List<RuleVO>> list(HttpServletRequest request) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<List<RuleVO>> list() {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(ruleService.list(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建规则
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param ruleRequest 规则请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping
|
||||
@Operation(summary = "创建规则", description = "为当前用户创建新的分类与标签规则")
|
||||
public Result<Void> create(HttpServletRequest request, @RequestBody @Valid RuleRequest ruleRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Void> create(@RequestBody @Valid RuleRequest ruleRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
ruleService.create(userId, ruleRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -70,17 +69,15 @@ public class RuleController {
|
||||
/**
|
||||
* 更新规则
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param id 规则ID
|
||||
* @param ruleRequest 规则请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "更新规则", description = "根据规则ID更新规则信息")
|
||||
public Result<Void> update(HttpServletRequest request,
|
||||
@Parameter(description = "规则ID") @PathVariable Long id,
|
||||
public Result<Void> update(@Parameter(description = "规则ID") @PathVariable Long id,
|
||||
@RequestBody @Valid RuleRequest ruleRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
ruleService.update(userId, id, ruleRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -88,15 +85,13 @@ public class RuleController {
|
||||
/**
|
||||
* 删除规则
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param id 规则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");
|
||||
public Result<Void> delete(@Parameter(description = "规则ID") @PathVariable Long id) {
|
||||
Long userId = UserContext.getUserId();
|
||||
ruleService.delete(userId, id);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -104,17 +99,15 @@ public class RuleController {
|
||||
/**
|
||||
* 启用或停用规则
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param id 规则ID
|
||||
* @param enabled 是否启用
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/{id}/enabled")
|
||||
@Operation(summary = "启用/停用规则", description = "切换指定规则的启用状态")
|
||||
public Result<Void> toggleEnabled(HttpServletRequest request,
|
||||
@Parameter(description = "规则ID") @PathVariable Long id,
|
||||
public Result<Void> toggleEnabled(@Parameter(description = "规则ID") @PathVariable Long id,
|
||||
@RequestBody RuleEnabledRequest enabled) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
ruleService.toggleEnabled(userId, id, enabled.getEnabled());
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.StatisticsQuery;
|
||||
import cn.rosercode.finance.dto.StatisticsRangeQuery;
|
||||
import cn.rosercode.finance.enums.StatisticsDimension;
|
||||
import cn.rosercode.finance.service.StatisticsService;
|
||||
import cn.rosercode.finance.vo.CategoryStatisticsVO;
|
||||
import cn.rosercode.finance.vo.MonthlyStatisticsVO;
|
||||
import cn.rosercode.finance.vo.StatisticsGroupVO;
|
||||
import cn.rosercode.finance.vo.StatisticsSummaryVO;
|
||||
import cn.rosercode.finance.vo.TrendStatisticsVO;
|
||||
import java.util.List;
|
||||
|
||||
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.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.StatisticsQuery;
|
||||
import cn.rosercode.finance.dto.StatisticsRangeQuery;
|
||||
import cn.rosercode.finance.enums.StatisticsDimension;
|
||||
import cn.rosercode.finance.service.StatisticsService;
|
||||
import cn.rosercode.finance.util.UserContext;
|
||||
import cn.rosercode.finance.vo.CategoryStatisticsVO;
|
||||
import cn.rosercode.finance.vo.MonthlyStatisticsVO;
|
||||
import cn.rosercode.finance.vo.StatisticsGroupVO;
|
||||
import cn.rosercode.finance.vo.StatisticsSummaryVO;
|
||||
import cn.rosercode.finance.vo.TrendStatisticsVO;
|
||||
|
||||
/**
|
||||
* 统计控制器
|
||||
@@ -41,77 +42,70 @@ public class StatisticsController {
|
||||
/**
|
||||
* 获取月度统计数据
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param query 统计查询参数
|
||||
* @return 月度统计结果
|
||||
*/
|
||||
@GetMapping("/monthly")
|
||||
@Operation(summary = "获取月度统计数据", description = "获取当前用户指定月份的收支统计汇总数据")
|
||||
public Result<MonthlyStatisticsVO> monthly(HttpServletRequest request, @Valid
|
||||
public Result<MonthlyStatisticsVO> monthly(@Valid
|
||||
@Parameter(description = "统计查询参数") StatisticsQuery query) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(statisticsService.getMonthlyStatistics(userId, query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类统计数据
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param query 统计查询参数
|
||||
* @return 分类统计列表
|
||||
*/
|
||||
@GetMapping("/category")
|
||||
@Operation(summary = "获取分类统计数据", description = "获取当前用户指定月份按分类维度的统计数据")
|
||||
public Result<List<CategoryStatisticsVO>> category(HttpServletRequest request, @Valid
|
||||
public Result<List<CategoryStatisticsVO>> category(@Valid
|
||||
@Parameter(description = "统计查询参数") StatisticsQuery query) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(statisticsService.getCategoryStatistics(userId, query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取趋势统计数据
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param query 统计查询参数
|
||||
* @return 趋势统计列表
|
||||
*/
|
||||
@GetMapping("/trend")
|
||||
@Operation(summary = "获取趋势统计数据", description = "获取当前用户指定时间范围内的收支趋势数据")
|
||||
public Result<List<TrendStatisticsVO>> trend(HttpServletRequest request, @Valid
|
||||
public Result<List<TrendStatisticsVO>> trend(@Valid
|
||||
@Parameter(description = "统计查询参数") StatisticsQuery query) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(statisticsService.getTrendStatistics(userId, query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定时间范围的统计概览
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param query 时间范围查询参数
|
||||
* @param query 时间范围查询参数
|
||||
* @return 统计概览
|
||||
*/
|
||||
@GetMapping("/summary")
|
||||
@Operation(summary = "获取统计概览", description = "获取当前用户指定时间范围的收支汇总、日均、最大单笔与平均每笔")
|
||||
public Result<StatisticsSummaryVO> summary(HttpServletRequest request,
|
||||
@Parameter(description = "时间范围查询参数") StatisticsRangeQuery query) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<StatisticsSummaryVO> summary(@Parameter(description = "时间范围查询参数") StatisticsRangeQuery query) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(statisticsService.getSummary(userId, query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按维度获取分组统计数据
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param dimension 统计维度(day/week/month/quarter/year/paymentMethod/category/type)
|
||||
* @param query 时间范围查询参数
|
||||
* @return 分组统计列表
|
||||
*/
|
||||
@GetMapping("/group")
|
||||
@Operation(summary = "获取分组统计数据", description = "按指定维度对时间范围内的交易进行分组统计")
|
||||
public Result<List<StatisticsGroupVO>> group(HttpServletRequest request,
|
||||
@Parameter(description = "统计维度") @RequestParam("dimension") String dimension,
|
||||
public Result<List<StatisticsGroupVO>> group(@Parameter(description = "统计维度") @RequestParam("dimension") String dimension,
|
||||
@Parameter(description = "时间范围查询参数") StatisticsRangeQuery query) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(statisticsService.getGroup(userId, query, StatisticsDimension.from(dimension)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.TagRequest;
|
||||
import cn.rosercode.finance.service.TagService;
|
||||
import cn.rosercode.finance.vo.TagVO;
|
||||
import java.util.List;
|
||||
|
||||
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.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -18,7 +15,11 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.TagRequest;
|
||||
import cn.rosercode.finance.service.TagService;
|
||||
import cn.rosercode.finance.util.UserContext;
|
||||
import cn.rosercode.finance.vo.TagVO;
|
||||
|
||||
/**
|
||||
* 标签控制器
|
||||
@@ -41,27 +42,25 @@ public class TagController {
|
||||
/**
|
||||
* 获取标签列表
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @return 标签列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取标签列表", description = "获取当前用户的全部标签")
|
||||
public Result<List<TagVO>> list(HttpServletRequest request) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<List<TagVO>> list() {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(tagService.list(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建标签
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param tagRequest 标签请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping
|
||||
@Operation(summary = "创建标签", description = "为当前用户创建新的标签")
|
||||
public Result<Void> create(HttpServletRequest request, @RequestBody @Valid TagRequest tagRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Void> create(@RequestBody @Valid TagRequest tagRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
tagService.create(userId, tagRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -69,17 +68,15 @@ public class TagController {
|
||||
/**
|
||||
* 更新标签
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param id 标签ID
|
||||
* @param tagRequest 标签请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "更新标签", description = "根据标签ID更新标签信息")
|
||||
public Result<Void> update(HttpServletRequest request,
|
||||
@Parameter(description = "标签ID") @PathVariable Long id,
|
||||
public Result<Void> update(@Parameter(description = "标签ID") @PathVariable Long id,
|
||||
@RequestBody @Valid TagRequest tagRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
tagService.update(userId, id, tagRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -87,15 +84,13 @@ public class TagController {
|
||||
/**
|
||||
* 删除标签
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param id 标签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");
|
||||
public Result<Void> delete(@Parameter(description = "标签ID") @PathVariable Long id) {
|
||||
Long userId = UserContext.getUserId();
|
||||
tagService.delete(userId, id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
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;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.ExcelWriter;
|
||||
import com.alibaba.excel.write.metadata.WriteSheet;
|
||||
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
|
||||
import cn.rosercode.finance.common.PageResult;
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.BatchCategoryRequest;
|
||||
import cn.rosercode.finance.dto.BatchDeleteRequest;
|
||||
import cn.rosercode.finance.dto.BatchTagRequest;
|
||||
import cn.rosercode.finance.dto.TransactionQuery;
|
||||
import cn.rosercode.finance.dto.TransactionRequest;
|
||||
import cn.rosercode.finance.exporter.TransactionExportSheetHandler;
|
||||
import cn.rosercode.finance.service.TransactionService;
|
||||
import cn.rosercode.finance.vo.TransactionExportVO;
|
||||
import cn.rosercode.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.apache.poi.ss.usermodel.Sheet;
|
||||
@@ -32,13 +28,18 @@ 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;
|
||||
import cn.rosercode.finance.common.PageResult;
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.BatchCategoryRequest;
|
||||
import cn.rosercode.finance.dto.BatchDeleteRequest;
|
||||
import cn.rosercode.finance.dto.BatchTagRequest;
|
||||
import cn.rosercode.finance.dto.TransactionQuery;
|
||||
import cn.rosercode.finance.dto.TransactionRequest;
|
||||
import cn.rosercode.finance.exporter.TransactionExportSheetHandler;
|
||||
import cn.rosercode.finance.service.TransactionService;
|
||||
import cn.rosercode.finance.util.UserContext;
|
||||
import cn.rosercode.finance.vo.TransactionExportVO;
|
||||
import cn.rosercode.finance.vo.TransactionVO;
|
||||
|
||||
/**
|
||||
* 交易记录控制器
|
||||
@@ -70,29 +71,26 @@ public class TransactionController {
|
||||
/**
|
||||
* 分页查询交易记录
|
||||
*
|
||||
* @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");
|
||||
public Result<PageResult<TransactionVO>> page(@Parameter(description = "分页查询参数") TransactionQuery query) {
|
||||
Long userId = UserContext.getUserId();
|
||||
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");
|
||||
public Result<Void> create(@RequestBody @Valid TransactionRequest transactionRequest) {
|
||||
Long userId = UserContext.getUserId();
|
||||
transactionService.create(userId, transactionRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -100,17 +98,15 @@ public class TransactionController {
|
||||
/**
|
||||
* 更新交易记录
|
||||
*
|
||||
* @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,
|
||||
public Result<Void> update(@Parameter(description = "交易记录ID") @PathVariable Long id,
|
||||
@RequestBody @Valid TransactionRequest transactionRequest) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
transactionService.update(userId, id, transactionRequest);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -118,15 +114,13 @@ public class TransactionController {
|
||||
/**
|
||||
* 删除交易记录
|
||||
*
|
||||
* @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");
|
||||
public Result<Void> delete(@Parameter(description = "交易记录ID") @PathVariable Long id) {
|
||||
Long userId = UserContext.getUserId();
|
||||
transactionService.delete(userId, id);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -134,32 +128,28 @@ public class TransactionController {
|
||||
/**
|
||||
* 批量删除交易记录
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param body 批量删除请求(记录ID列表)
|
||||
* @param body 批量删除请求(记录ID列表)
|
||||
* @return 实际删除的记录数
|
||||
*/
|
||||
@DeleteMapping("/batch")
|
||||
@Operation(summary = "批量删除交易记录", description = "根据记录ID列表批量删除当前用户的交易记录")
|
||||
public Result<Integer> batchDelete(HttpServletRequest request,
|
||||
@RequestBody @Valid BatchDeleteRequest body) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<Integer> batchDelete(@RequestBody @Valid BatchDeleteRequest body) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(transactionService.batchDelete(userId, body.getIds()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换交易记录的"计入统计"标记
|
||||
*
|
||||
* @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,
|
||||
public Result<Void> toggleStats(@Parameter(description = "交易记录ID") @PathVariable Long id,
|
||||
@RequestBody Map<String, Boolean> body) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
Boolean includeInStats = body != null ? body.get("includeInStats") : null;
|
||||
transactionService.toggleStats(userId, id, includeInStats);
|
||||
return Result.success();
|
||||
@@ -168,17 +158,15 @@ public class TransactionController {
|
||||
/**
|
||||
* 切换交易记录的备注隐藏标记
|
||||
*
|
||||
* @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,
|
||||
public Result<Void> toggleRemarkHidden(@Parameter(description = "交易记录ID") @PathVariable Long id,
|
||||
@RequestBody Map<String, Boolean> body) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
Long userId = UserContext.getUserId();
|
||||
Boolean remarkHidden = body != null ? body.get("remarkHidden") : null;
|
||||
transactionService.toggleRemarkHidden(userId, id, remarkHidden);
|
||||
return Result.success();
|
||||
@@ -187,47 +175,40 @@ public class TransactionController {
|
||||
/**
|
||||
* 批量设置交易记录的分类
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param body 批量设置请求参数
|
||||
* @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");
|
||||
public Result<Integer> batchUpdateCategory(@RequestBody @Valid BatchCategoryRequest body) {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(transactionService.batchUpdateCategory(userId, body));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量给交易记录添加/移除标签
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @param body 批量标签请求参数
|
||||
* @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");
|
||||
public Result<Integer> batchTags(@RequestBody @Valid BatchTagRequest body) {
|
||||
Long userId = UserContext.getUserId();
|
||||
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");
|
||||
public void export(@Parameter(description = "查询条件") TransactionQuery query) throws IOException {
|
||||
Long userId = UserContext.getUserId();
|
||||
HttpServletResponse response = UserContext.getResponse();
|
||||
|
||||
// 设置响应头
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
|
||||
@@ -1,17 +1,7 @@
|
||||
package cn.rosercode.finance.controller;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.LoginRequest;
|
||||
import cn.rosercode.finance.dto.RegisterRequest;
|
||||
import cn.rosercode.finance.dto.RegistrationUpdateRequest;
|
||||
import cn.rosercode.finance.service.RegistrationService;
|
||||
import cn.rosercode.finance.service.UserService;
|
||||
import cn.rosercode.finance.vo.LoginVO;
|
||||
import cn.rosercode.finance.vo.RegistrationStatusVO;
|
||||
import cn.rosercode.finance.vo.UserVO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -20,6 +10,17 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.rosercode.finance.common.Result;
|
||||
import cn.rosercode.finance.dto.LoginRequest;
|
||||
import cn.rosercode.finance.dto.RegisterRequest;
|
||||
import cn.rosercode.finance.dto.RegistrationUpdateRequest;
|
||||
import cn.rosercode.finance.service.RegistrationService;
|
||||
import cn.rosercode.finance.service.UserService;
|
||||
import cn.rosercode.finance.util.UserContext;
|
||||
import cn.rosercode.finance.vo.LoginVO;
|
||||
import cn.rosercode.finance.vo.RegistrationStatusVO;
|
||||
import cn.rosercode.finance.vo.UserVO;
|
||||
|
||||
/**
|
||||
* 用户控制器
|
||||
*
|
||||
@@ -90,13 +91,12 @@ public class UserController {
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
*
|
||||
* @param request HTTP请求,从中获取用户ID
|
||||
* @return 用户信息
|
||||
*/
|
||||
@GetMapping("/info")
|
||||
@Operation(summary = "获取当前用户信息", description = "获取已登录用户的详细信息")
|
||||
public Result<UserVO> info(HttpServletRequest request) {
|
||||
Long userId = (Long) request.getAttribute("userId");
|
||||
public Result<UserVO> info() {
|
||||
Long userId = UserContext.getUserId();
|
||||
return Result.success(userService.getUserInfo(userId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package cn.rosercode.finance.converter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
import cn.rosercode.finance.entity.AiUsage;
|
||||
import cn.rosercode.finance.entity.Category;
|
||||
import cn.rosercode.finance.entity.HttpLog;
|
||||
@@ -20,11 +26,6 @@ import cn.rosercode.finance.vo.RuleVO;
|
||||
import cn.rosercode.finance.vo.TagVO;
|
||||
import cn.rosercode.finance.vo.TransactionVO;
|
||||
import cn.rosercode.finance.vo.UserVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 实体与视图对象之间的转换器,由 MapStruct 在编译期生成实现。
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import cn.rosercode.finance.vo.AiNewTagVO;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import cn.rosercode.finance.vo.AiNewTagVO;
|
||||
|
||||
/**
|
||||
* AI 建议应用请求DTO,携带逐条记录的建议分类与标签,用于一键写入。
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 单条记录 AI 建议请求 DTO,携带表单当前内容用于生成分类与标签建议。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 建议请求DTO,携带需要分析分类与标签的交易记录ID列表。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 批量设置分类请求 DTO,用于将当前表格展示的多条交易记录一键归入分类。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 批量删除交易记录请求DTO,用于一次性删除多条收支记录。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 批量设置标签请求DTO,用于为多条交易记录添加或移除标签。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 账单导入请求 DTO,用于「后导入」阶段接收前端回传的勾选行。
|
||||
*
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import cn.rosercode.finance.config.datasource.DataSourceType;
|
||||
import lombok.Data;
|
||||
|
||||
import cn.rosercode.finance.config.datasource.DataSourceType;
|
||||
|
||||
/**
|
||||
* 数据库配置请求对象,用于提交 MySQL 或 SQLite 的连接信息。
|
||||
*
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 通知渠道保存请求DTO,用于新增或修改消息推送渠道。
|
||||
*
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 规则请求DTO,用于接收创建或更新自定义分类与标签规则时提交的信息。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 统计查询 DTO,用于按时间区间及可选过滤条件进行统计。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 交易查询DTO,用于接收交易记录分页查询的筛选条件
|
||||
*/
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package cn.rosercode.finance.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 交易请求DTO,用于接收创建或更新交易记录时提交的信息
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* AI 配置实体类,对应数据库表 t_ai_config,用于记录用户的 AI 智能建议配置。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* AI 使用记录实体类,对应数据库表 t_ai_usage,记录每次调用 DeepSeek 的用量与结果。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 分类实体类,对应数据库表 t_category,用于记录收支分类信息
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* HTTP 访问日志实体类,对应数据库表 t_http_log,记录每次接口请求的方法、路径、状态与耗时。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 登录日志实体类,对应数据库表 t_login_log,记录每次登录尝试的结果。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 通知渠道实体类,对应数据库表 t_notification_channel,用于记录用户配置的消息推送渠道。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 通知配置实体类,对应数据库表 t_notification_config,用于记录用户的账单导入提醒周期。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 通知日志实体类,对应数据库表 t_notification_log,用于记录每次提醒的发送结果。
|
||||
*
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 自定义分类与标签规则实体类,对应数据库表 t_rule。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 规则标签关联实体类,对应数据库表 t_rule_tag,表示规则与标签的多对多关系。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 标签实体类,对应数据库表 t_tag,用于记录用户自定义标签。
|
||||
*
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 交易记录实体类,对应数据库表 t_transaction,用于记录每笔收支交易
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 交易标签关联实体类,对应数据库表 t_transaction_tag,维护交易与标签的多对多关系。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 用户实体类,对应数据库表 t_user
|
||||
*/
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
package cn.rosercode.finance.importer;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -24,6 +15,16 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
|
||||
/**
|
||||
* 支付宝账单解析器。
|
||||
*
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
package cn.rosercode.finance.importer;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import net.lingala.zip4j.ZipFile;
|
||||
import net.lingala.zip4j.exception.ZipException;
|
||||
import net.lingala.zip4j.model.FileHeader;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -13,6 +7,13 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import net.lingala.zip4j.ZipFile;
|
||||
import net.lingala.zip4j.exception.ZipException;
|
||||
import net.lingala.zip4j.model.FileHeader;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
|
||||
/**
|
||||
* 账单压缩包解压工具。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.importer;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
|
||||
/**
|
||||
* 账单解析器接口,定义不同账单来源的解析行为。
|
||||
*
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
package cn.rosercode.finance.importer;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
@@ -25,6 +13,19 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
|
||||
/**
|
||||
* 交通银行账单解析器。
|
||||
*
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
package cn.rosercode.finance.importer;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
@@ -27,6 +18,16 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
|
||||
/**
|
||||
* 招商银行账单解析器。
|
||||
*
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
package cn.rosercode.finance.importer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.pdfbox.Loader;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.text.PDFTextStripper;
|
||||
import org.apache.pdfbox.text.TextPosition;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
@@ -22,6 +13,15 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.pdfbox.Loader;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.text.PDFTextStripper;
|
||||
import org.apache.pdfbox.text.TextPosition;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* 招商银行「交易流水」PDF 解析器。
|
||||
*
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
package cn.rosercode.finance.importer;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -24,6 +15,16 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
|
||||
/**
|
||||
* 美团账单解析器。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package cn.rosercode.finance.importer;
|
||||
|
||||
import cn.rosercode.finance.vo.TagVO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import cn.rosercode.finance.vo.TagVO;
|
||||
|
||||
/**
|
||||
* 账单解析结果行,作为「先解析、后导入」流程中解析阶段的中间对象。
|
||||
*
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
package cn.rosercode.finance.importer;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
@@ -23,6 +11,19 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
|
||||
/**
|
||||
* 微信支付账单解析器。
|
||||
*
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package cn.rosercode.finance.interceptor;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import cn.rosercode.finance.entity.HttpLog;
|
||||
import cn.rosercode.finance.service.LogService;
|
||||
import cn.rosercode.finance.util.RequestUtils;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
/**
|
||||
* HTTP 访问日志拦截器。
|
||||
@@ -19,10 +19,9 @@ import org.springframework.web.servlet.HandlerInterceptor;
|
||||
* @date 2026-09-18 16:53:21
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AccessLogInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AccessLogInterceptor.class);
|
||||
|
||||
/** 请求属性名:请求开始时间 */
|
||||
private static final String START_TIME_ATTR = "accessLogStartTime";
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package cn.rosercode.finance.interceptor;
|
||||
|
||||
import cn.rosercode.finance.config.datasource.DataSourceContextHolder;
|
||||
import cn.rosercode.finance.util.JwtUtil;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import cn.rosercode.finance.config.datasource.DataSourceContextHolder;
|
||||
import cn.rosercode.finance.util.JwtUtil;
|
||||
|
||||
/**
|
||||
* JWT 认证拦截器。
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.AiConfig;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.AiConfig;
|
||||
|
||||
/**
|
||||
* AI 配置Mapper接口,继承MyBatis-Plus的BaseMapper,提供AI配置表的基础CRUD操作。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.AiUsage;
|
||||
import cn.rosercode.finance.vo.AiUsageSummaryVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import cn.rosercode.finance.entity.AiUsage;
|
||||
import cn.rosercode.finance.vo.AiUsageSummaryVO;
|
||||
|
||||
/**
|
||||
* AI 使用记录Mapper接口,继承MyBatis-Plus的BaseMapper,并提供汇总统计查询。
|
||||
*
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.Category;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.Category;
|
||||
|
||||
/**
|
||||
* 分类Mapper接口,继承MyBatis-Plus的BaseMapper,提供分类表的基础CRUD操作
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.HttpLog;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.HttpLog;
|
||||
|
||||
/**
|
||||
* HTTP 访问日志Mapper接口,继承MyBatis-Plus的BaseMapper,提供访问日志表的基础CRUD操作。
|
||||
*
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.LoginLog;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.LoginLog;
|
||||
|
||||
/**
|
||||
* 登录日志Mapper接口,继承MyBatis-Plus的BaseMapper,提供登录日志表的基础CRUD操作。
|
||||
*
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.NotificationChannel;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.NotificationChannel;
|
||||
|
||||
/**
|
||||
* 通知渠道Mapper接口,继承MyBatis-Plus的BaseMapper,提供通知渠道表的基础CRUD操作。
|
||||
*
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.NotificationConfig;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.NotificationConfig;
|
||||
|
||||
/**
|
||||
* 通知配置Mapper接口,继承MyBatis-Plus的BaseMapper,提供通知配置表的基础CRUD操作。
|
||||
*
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.NotificationLog;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.NotificationLog;
|
||||
|
||||
/**
|
||||
* 通知日志Mapper接口,继承MyBatis-Plus的BaseMapper,提供通知日志表的基础CRUD操作。
|
||||
*
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.Rule;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.Rule;
|
||||
|
||||
/**
|
||||
* 规则Mapper接口,继承MyBatis-Plus的BaseMapper,提供规则表的基础CRUD操作。
|
||||
*
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.RuleTag;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.RuleTag;
|
||||
|
||||
/**
|
||||
* 规则标签关联Mapper接口,继承MyBatis-Plus的BaseMapper,提供规则标签关联表的基础CRUD操作。
|
||||
*
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.Tag;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.Tag;
|
||||
|
||||
/**
|
||||
* 标签Mapper接口,继承MyBatis-Plus的BaseMapper,提供标签表的基础CRUD操作。
|
||||
*
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.Transaction;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import cn.rosercode.finance.entity.Transaction;
|
||||
|
||||
/**
|
||||
* 交易记录Mapper接口,继承MyBatis-Plus的BaseMapper,提供交易记录表的基础CRUD操作
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.TransactionTag;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import cn.rosercode.finance.entity.TransactionTag;
|
||||
|
||||
/**
|
||||
* 交易标签关联Mapper接口,继承MyBatis-Plus的BaseMapper,提供关联表的基础CRUD操作。
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.rosercode.finance.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import cn.rosercode.finance.entity.User;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import cn.rosercode.finance.entity.User;
|
||||
|
||||
/**
|
||||
* 用户Mapper接口,继承MyBatis-Plus的BaseMapper,提供用户表的基础CRUD操作
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package cn.rosercode.finance.notification;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
@@ -14,6 +10,11 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
|
||||
/**
|
||||
* HTTP 通知发送器抽象基类。
|
||||
*
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package cn.rosercode.finance.notification;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import cn.rosercode.finance.enums.NotificationChannelType;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import org.springframework.mail.MailException;
|
||||
@@ -9,8 +10,8 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import cn.rosercode.finance.enums.NotificationChannelType;
|
||||
|
||||
/**
|
||||
* 邮箱通知发送器,通过 SMTP 发送纯文本邮件(兼容 QQ 邮箱)。
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package cn.rosercode.finance.notification;
|
||||
|
||||
import cn.rosercode.finance.enums.NotificationChannelType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import cn.rosercode.finance.enums.NotificationChannelType;
|
||||
|
||||
/**
|
||||
* 通知发送器接口,定义不同渠道的消息推送能力。
|
||||
*
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package cn.rosercode.finance.notification;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import cn.rosercode.finance.enums.NotificationChannelType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import cn.rosercode.finance.enums.NotificationChannelType;
|
||||
|
||||
/**
|
||||
* 通知发送器工厂,按渠道类型分发到对应的发送器实现。
|
||||
*
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package cn.rosercode.finance.notification;
|
||||
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import cn.rosercode.finance.enums.NotificationChannelType;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
import cn.rosercode.finance.enums.NotificationChannelType;
|
||||
|
||||
/**
|
||||
* Server 酱通知发送器,通过 Server 酱 Turbo 接口将消息推送到个人微信。
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package cn.rosercode.finance.scheduler;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.rosercode.finance.config.app.AppConfig;
|
||||
import cn.rosercode.finance.config.app.AppConfigStore;
|
||||
import cn.rosercode.finance.entity.HttpLog;
|
||||
import cn.rosercode.finance.entity.LoginLog;
|
||||
import cn.rosercode.finance.mapper.HttpLogMapper;
|
||||
import cn.rosercode.finance.mapper.LoginLogMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 日志清理调度器。
|
||||
@@ -23,10 +23,9 @@ import java.time.LocalDateTime;
|
||||
* @date 2026-09-18 17:15:49
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class LogCleanupScheduler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LogCleanupScheduler.class);
|
||||
|
||||
private final AppConfigStore appConfigStore;
|
||||
private final HttpLogMapper httpLogMapper;
|
||||
private final LoginLogMapper loginLogMapper;
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
package cn.rosercode.finance.scheduler;
|
||||
|
||||
import cn.rosercode.finance.entity.NotificationChannel;
|
||||
import cn.rosercode.finance.entity.NotificationConfig;
|
||||
import cn.rosercode.finance.enums.NotificationFrequency;
|
||||
import cn.rosercode.finance.mapper.NotificationConfigMapper;
|
||||
import cn.rosercode.finance.service.NotificationChannelService;
|
||||
import cn.rosercode.finance.service.NotificationService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
@@ -19,6 +7,18 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.rosercode.finance.entity.NotificationChannel;
|
||||
import cn.rosercode.finance.entity.NotificationConfig;
|
||||
import cn.rosercode.finance.enums.NotificationFrequency;
|
||||
import cn.rosercode.finance.mapper.NotificationConfigMapper;
|
||||
import cn.rosercode.finance.service.NotificationChannelService;
|
||||
import cn.rosercode.finance.service.NotificationService;
|
||||
|
||||
/**
|
||||
* 通知调度器。
|
||||
*
|
||||
@@ -28,10 +28,9 @@ import java.util.List;
|
||||
* @date 2026-09-18 12:38:30
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class NotificationScheduler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(NotificationScheduler.class);
|
||||
|
||||
/** 时间格式 */
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cn.rosercode.finance.dto.AiApplyRequest;
|
||||
import cn.rosercode.finance.dto.AiSuggestOneRequest;
|
||||
import cn.rosercode.finance.vo.AiSuggestionVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 建议服务接口,提供交易记录的分类与标签智能建议及应用能力。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import cn.rosercode.finance.util.AppLogUtils;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
@@ -18,6 +13,12 @@ import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import cn.rosercode.finance.util.AppLogUtils;
|
||||
|
||||
/**
|
||||
* 应用运行日志实时推送服务。
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import cn.rosercode.finance.dto.BillImportRequest;
|
||||
import cn.rosercode.finance.enums.BillType;
|
||||
import cn.rosercode.finance.vo.BillImportResultVO;
|
||||
import cn.rosercode.finance.vo.BillParseResultVO;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 账单导入服务,负责「先解析、后导入」两阶段的业务逻辑。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cn.rosercode.finance.dto.CategoryRequest;
|
||||
import cn.rosercode.finance.vo.CategoryVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分类服务接口,提供收支分类的增删改查操作。
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cn.rosercode.finance.dto.NotificationChannelRequest;
|
||||
import cn.rosercode.finance.entity.NotificationChannel;
|
||||
import cn.rosercode.finance.vo.NotificationChannelVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通知渠道服务接口,负责用户消息推送渠道的增删改查。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cn.rosercode.finance.entity.NotificationChannel;
|
||||
import cn.rosercode.finance.vo.NotificationLogVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通知发送服务接口,负责消息的实际推送与发送日志记录。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 规则匹配上下文,承载单条交易的匹配所需信息。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 规则匹配结果,承载命中规则后建议应用的分类与标签。
|
||||
*
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cn.rosercode.finance.dto.RuleRequest;
|
||||
import cn.rosercode.finance.vo.RuleVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 规则服务,负责自定义分类与标签规则的增删改查及匹配。
|
||||
*
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cn.rosercode.finance.dto.StatisticsQuery;
|
||||
import cn.rosercode.finance.dto.StatisticsRangeQuery;
|
||||
import cn.rosercode.finance.enums.StatisticsDimension;
|
||||
@@ -9,8 +11,6 @@ import cn.rosercode.finance.vo.StatisticsGroupVO;
|
||||
import cn.rosercode.finance.vo.StatisticsSummaryVO;
|
||||
import cn.rosercode.finance.vo.TrendStatisticsVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 统计服务接口,提供月度收支统计、分类统计和趋势分析功能。
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cn.rosercode.finance.dto.TagRequest;
|
||||
import cn.rosercode.finance.vo.TagVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 标签服务接口,提供标签的增删改查操作。
|
||||
*
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package cn.rosercode.finance.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cn.rosercode.finance.common.PageResult;
|
||||
import cn.rosercode.finance.dto.BatchCategoryRequest;
|
||||
import cn.rosercode.finance.dto.BatchTagRequest;
|
||||
@@ -8,8 +10,6 @@ import cn.rosercode.finance.dto.TransactionRequest;
|
||||
import cn.rosercode.finance.vo.TransactionExportVO;
|
||||
import cn.rosercode.finance.vo.TransactionVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 交易记录服务接口,提供收支记录的分页查询、增删改操作。
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package cn.rosercode.finance.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import cn.rosercode.finance.client.DeepSeekClient;
|
||||
import cn.rosercode.finance.client.DeepSeekResponse;
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
@@ -9,12 +16,6 @@ import cn.rosercode.finance.service.AiCategoryService;
|
||||
import cn.rosercode.finance.service.AiConfigService;
|
||||
import cn.rosercode.finance.service.AiUsageService;
|
||||
import cn.rosercode.finance.vo.AiCategoryResultVO;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 生成分类服务实现类,根据自然语言描述生成分类名称、类型与图标。
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package cn.rosercode.finance.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import cn.rosercode.finance.client.DeepSeekClient;
|
||||
import cn.rosercode.finance.client.DeepSeekResponse;
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
@@ -11,8 +15,6 @@ import cn.rosercode.finance.mapper.AiConfigMapper;
|
||||
import cn.rosercode.finance.service.AiConfigService;
|
||||
import cn.rosercode.finance.service.AiUsageService;
|
||||
import cn.rosercode.finance.vo.AiConfigVO;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* AI 配置服务实现类,处理用户级 AI 配置的读写与连通性测试。
|
||||
@@ -20,6 +22,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
* @date 2026-09-17 17:52:22
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AiConfigServiceImpl implements AiConfigService {
|
||||
|
||||
/** 默认 API 基础地址 */
|
||||
@@ -89,6 +92,7 @@ public class AiConfigServiceImpl implements AiConfigService {
|
||||
} else {
|
||||
aiConfigMapper.updateById(config);
|
||||
}
|
||||
log.info("保存 AI 配置: userId={}, enabled={}, model={}", userId, config.getEnabled(), config.getModel());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,10 +125,13 @@ public class AiConfigServiceImpl implements AiConfigService {
|
||||
// 失败也记录一次使用,便于排查问题
|
||||
aiUsageService.recordFailure(userId, AiCallType.TEST, config.getModel(), 0,
|
||||
System.currentTimeMillis() - start, e.getMessage());
|
||||
log.warn("AI 连接测试失败: userId={}, model={}, error={}", userId, config.getModel(), e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
aiUsageService.recordSuccess(userId, AiCallType.TEST, config.getModel(), 0,
|
||||
response, System.currentTimeMillis() - start);
|
||||
log.info("AI 连接测试成功: userId={}, model={}, 耗时={}ms", userId, config.getModel(),
|
||||
System.currentTimeMillis() - start);
|
||||
if (isBlank(response.getContent())) {
|
||||
throw new BusinessException("连接成功但未返回内容");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package cn.rosercode.finance.service.impl;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import cn.rosercode.finance.client.DeepSeekClient;
|
||||
import cn.rosercode.finance.client.DeepSeekResponse;
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
@@ -8,12 +15,6 @@ import cn.rosercode.finance.enums.AiCallType;
|
||||
import cn.rosercode.finance.service.AiConfigService;
|
||||
import cn.rosercode.finance.service.AiDecorationService;
|
||||
import cn.rosercode.finance.service.AiUsageService;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* AI 装饰建议服务实现类,根据分类/标签名称调用模型生成 Emoji 与配色建议。
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
package cn.rosercode.finance.service.impl;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import cn.rosercode.finance.client.DeepSeekClient;
|
||||
import cn.rosercode.finance.client.DeepSeekResponse;
|
||||
import cn.rosercode.finance.common.BusinessException;
|
||||
@@ -14,18 +27,6 @@ import cn.rosercode.finance.service.AiConfigService;
|
||||
import cn.rosercode.finance.service.AiQueryService;
|
||||
import cn.rosercode.finance.service.AiUsageService;
|
||||
import cn.rosercode.finance.vo.AiQueryResultVO;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* AI 自然语言查询服务实现类,负责提示词组装、日期推算与名称映射。
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user