diff --git a/Dockerfile b/Dockerfile index 842060dd..b9d182a5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM openjdk:17 # 维护者信息 -MAINTAINER youlai +LABEL maintainer="youlai " # 设置时区(Debian直接使用环境变量) ENV TZ=Asia/Shanghai diff --git a/sql/mysql/youlai_admin.sql b/sql/mysql/youlai_admin.sql index 6aa3c3f7..4b0d1f95 100644 --- a/sql/mysql/youlai_admin.sql +++ b/sql/mysql/youlai_admin.sql @@ -138,8 +138,8 @@ CREATE TABLE `sys_menu` ( -- ---------------------------- -- 顶级目录(1-9):系统/代码生成/AI助手/文档/接口文档/组件/演示/多级/路由 INSERT INTO `sys_menu` VALUES (1, 0, '0', '系统管理', 'C', '', '/system', 'Layout', NULL, NULL, NULL, 1, 1, 'system', '/system/user', now(), now(), NULL); -INSERT INTO `sys_menu` VALUES (2, 0, '0', '代码生成', 'C', '', '/gen', 'Layout', NULL, NULL, NULL, 1, 2, 'code', '/gen/index', now(), now(), NULL); -INSERT INTO `sys_menu` VALUES (3, 0, '0', 'AI助手', 'C', '', '/ai', 'Layout', NULL, NULL, NULL, 1, 3, 'platform', '/ai/command-record', now(), now(), NULL); +INSERT INTO `sys_menu` VALUES (2, 0, '0', '代码生成', 'C', '', '/codegen', 'Layout', NULL, NULL, NULL, 1, 2, 'code', '/codegen/index', now(), now(), NULL); +INSERT INTO `sys_menu` VALUES (3, 0, '0', 'AI助手', 'C', '', '/ai', 'Layout', NULL, NULL, NULL, 1, 3, 'ai', '/ai/command-record', now(), now(), NULL); INSERT INTO `sys_menu` VALUES (4, 0, '0', '平台文档', 'C', '', '/doc', 'Layout', NULL, NULL, NULL, 1, 4, 'document', '', now(), now(), NULL); INSERT INTO `sys_menu` VALUES (5, 0, '0', '接口文档', 'C', '', '/api', 'Layout', NULL, NULL, NULL, 1, 5, 'api', '', now(), now(), NULL); INSERT INTO `sys_menu` VALUES (6, 0, '0', '组件封装', 'C', '', '/component', 'Layout', NULL, NULL, NULL, 1, 6, 'menu', '', now(), now(), NULL); @@ -205,7 +205,7 @@ INSERT INTO `sys_menu` VALUES (2805, 280, '0,1,280', '通知发布', 'B', NULL, INSERT INTO `sys_menu` VALUES (2806, 280, '0,1,280', '通知撤回', 'B', NULL, '', NULL, 'sys:notice:revoke', 0, 1, 1, 6, '', NULL, now(), now(), NULL); -- 代码生成 -INSERT INTO `sys_menu` VALUES (310, 2, '0,2', '代码生成', 'M', 'Gen', 'gen', 'gen/index', NULL, NULL, 1, 1, 1, 'code', NULL, now(), now(), NULL); +INSERT INTO `sys_menu` VALUES (310, 2, '0,2', '代码生成', 'M', 'Codegen', 'codegen', 'codegen/index', NULL, NULL, 1, 1, 1, 'code', NULL, now(), now(), NULL); -- AI 助手 INSERT INTO `sys_menu` VALUES (401, 3, '0,3', 'AI命令记录', 'M', 'AiCommandRecord', 'command-record', 'ai/command-record/index', NULL, NULL, 1, 1, 1, 'document', NULL, now(), now(), NULL); @@ -537,8 +537,8 @@ INSERT INTO `sys_user_notice` VALUES (10, 10, 2, 1, NULL, now(), now(), 0); -- ---------------------------- -- AI 命令记录表 -- ---------------------------- -DROP TABLE IF EXISTS `ai_command_record`; -CREATE TABLE `ai_command_record` ( +DROP TABLE IF EXISTS `ai_assistant_record`; +CREATE TABLE `ai_assistant_record` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', `user_id` bigint DEFAULT NULL COMMENT '用户ID', `username` varchar(64) DEFAULT NULL COMMENT '用户名', @@ -565,40 +565,6 @@ CREATE TABLE `ai_command_record` ( KEY `idx_create_time` (`create_time`), KEY `idx_provider` (`ai_provider`), KEY `idx_model` (`ai_model`), - KEY `idx_parse_success` (`parse_status`), + KEY `idx_parse_status` (`parse_status`), KEY `idx_execute_status` (`execute_status`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='AI 命令记录表'; - --- ---------------------------- --- 租户表(多租户模式) --- ---------------------------- -DROP TABLE IF EXISTS `sys_tenant`; -CREATE TABLE `sys_tenant` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '租户ID', - `name` varchar(100) NOT NULL COMMENT '租户名称', - `code` varchar(50) NOT NULL COMMENT '租户编码(唯一)', - `contact_name` varchar(50) DEFAULT NULL COMMENT '联系人姓名', - `contact_phone` varchar(20) DEFAULT NULL COMMENT '联系人电话', - `contact_email` varchar(100) DEFAULT NULL COMMENT '联系人邮箱', - `domain` varchar(100) DEFAULT NULL COMMENT '租户域名(用于域名识别)', - `logo` varchar(255) DEFAULT NULL COMMENT '租户Logo', - `status` tinyint DEFAULT '1' COMMENT '状态(1-正常 0-禁用)', - `remark` varchar(500) DEFAULT NULL COMMENT '备注', - `expire_time` datetime DEFAULT NULL COMMENT '过期时间(NULL表示永不过期)', - `create_time` datetime COMMENT '创建时间', - `update_time` datetime COMMENT '更新时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_code` (`code`), - UNIQUE KEY `uk_domain` (`domain`), - KEY `idx_status` (`status`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='系统租户表'; - --- ---------------------------- --- Records of sys_tenant --- ---------------------------- -INSERT INTO `sys_tenant` VALUES (1, '默认租户', 'DEFAULT', '系统管理员', '18812345678', 'admin@youlai.tech', NULL, NULL, 1, '系统默认租户', NULL, now(), now()); -INSERT INTO `sys_tenant` VALUES (2, '演示租户', 'DEMO', '演示用户', '18812345679', 'demo@youlai.tech', 'demo.youlai.tech', NULL, 1, '演示租户', NULL, now(), now()); - - - -SET FOREIGN_KEY_CHECKS = 1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='AI 助手行为记录表(解析、执行、审计)'; diff --git a/src/main/java/com/youlai/boot/auth/controller/AuthController.java b/src/main/java/com/youlai/boot/auth/controller/AuthController.java index 1cb5a579..61dc05e0 100644 --- a/src/main/java/com/youlai/boot/auth/controller/AuthController.java +++ b/src/main/java/com/youlai/boot/auth/controller/AuthController.java @@ -1,12 +1,12 @@ package com.youlai.boot.auth.controller; -import com.youlai.boot.auth.model.vo.CaptchaVO; +import com.youlai.boot.auth.model.vo.CaptchaVo; import com.youlai.boot.auth.model.dto.LoginRequest; -import com.youlai.boot.auth.model.dto.WxMiniAppPhoneLoginDTO; +import com.youlai.boot.auth.model.dto.WxMiniAppPhoneLoginDto; import com.youlai.boot.common.enums.LogModuleEnum; import com.youlai.boot.core.web.Result; import com.youlai.boot.auth.service.AuthService; -import com.youlai.boot.auth.model.dto.WxMiniAppCodeLoginDTO; +import com.youlai.boot.auth.model.dto.WxMiniAppCodeLoginDto; import com.youlai.boot.common.annotation.Log; import com.youlai.boot.security.model.AuthenticationToken; import io.swagger.v3.oas.annotations.Operation; @@ -37,8 +37,8 @@ public class AuthController { @Operation(summary = "获取验证码") @GetMapping("/captcha") - public Result getCaptcha() { - CaptchaVO captcha = authService.getCaptcha(); + public Result getCaptcha() { + CaptchaVo captcha = authService.getCaptcha(); return Result.success(captcha); } @@ -84,15 +84,15 @@ public class AuthController { @Operation(summary = "微信小程序登录(Code)") @PostMapping("/wx/miniapp/code-login") - public Result loginByWxMiniAppCode(@RequestBody @Valid WxMiniAppCodeLoginDTO loginDTO) { - AuthenticationToken token = authService.loginByWxMiniAppCode(loginDTO); + public Result loginByWxMiniAppCode(@RequestBody @Valid WxMiniAppCodeLoginDto loginDto) { + AuthenticationToken token = authService.loginByWxMiniAppCode(loginDto); return Result.success(token); } @Operation(summary = "微信小程序登录(手机号)") @PostMapping("/wx/miniapp/phone-login") - public Result loginByWxMiniAppPhone(@RequestBody @Valid WxMiniAppPhoneLoginDTO loginDTO) { - AuthenticationToken token = authService.loginByWxMiniAppPhone(loginDTO); + public Result loginByWxMiniAppPhone(@RequestBody @Valid WxMiniAppPhoneLoginDto loginDto) { + AuthenticationToken token = authService.loginByWxMiniAppPhone(loginDto); return Result.success(token); } diff --git a/src/main/java/com/youlai/boot/auth/model/dto/WxMiniAppCodeLoginDTO.java b/src/main/java/com/youlai/boot/auth/model/dto/WxMiniAppCodeLoginDTO.java index 69c653fb..b31c41c8 100644 --- a/src/main/java/com/youlai/boot/auth/model/dto/WxMiniAppCodeLoginDTO.java +++ b/src/main/java/com/youlai/boot/auth/model/dto/WxMiniAppCodeLoginDTO.java @@ -13,7 +13,7 @@ import jakarta.validation.constraints.NotBlank; */ @Schema(description = "微信小程序Code登录请求参数") @Data -public class WxMiniAppCodeLoginDTO { +public class WxMiniAppCodeLoginDto { @Schema(description = "微信小程序登录时获取的code", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "code不能为空") diff --git a/src/main/java/com/youlai/boot/auth/model/dto/WxMiniAppPhoneLoginDTO.java b/src/main/java/com/youlai/boot/auth/model/dto/WxMiniAppPhoneLoginDTO.java index a881f271..48c7ccea 100644 --- a/src/main/java/com/youlai/boot/auth/model/dto/WxMiniAppPhoneLoginDTO.java +++ b/src/main/java/com/youlai/boot/auth/model/dto/WxMiniAppPhoneLoginDTO.java @@ -13,7 +13,7 @@ import jakarta.validation.constraints.NotBlank; */ @Schema(description = "微信小程序手机号登录请求参数") @Data -public class WxMiniAppPhoneLoginDTO { +public class WxMiniAppPhoneLoginDto { @Schema(description = "微信小程序登录时获取的code", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "code不能为空") diff --git a/src/main/java/com/youlai/boot/auth/model/vo/CaptchaVO.java b/src/main/java/com/youlai/boot/auth/model/vo/CaptchaVO.java index a81fb3c6..f7db81e2 100644 --- a/src/main/java/com/youlai/boot/auth/model/vo/CaptchaVO.java +++ b/src/main/java/com/youlai/boot/auth/model/vo/CaptchaVO.java @@ -13,7 +13,7 @@ import lombok.Data; @Schema(description = "验证码信息") @Data @Builder -public class CaptchaVO { +public class CaptchaVo { @Schema(description = "验证码缓存 ID") private String captchaId; diff --git a/src/main/java/com/youlai/boot/auth/service/AuthService.java b/src/main/java/com/youlai/boot/auth/service/AuthService.java index 5fe2eadf..f0b6811c 100644 --- a/src/main/java/com/youlai/boot/auth/service/AuthService.java +++ b/src/main/java/com/youlai/boot/auth/service/AuthService.java @@ -1,9 +1,9 @@ package com.youlai.boot.auth.service; -import com.youlai.boot.auth.model.vo.CaptchaVO; -import com.youlai.boot.auth.model.dto.WxMiniAppPhoneLoginDTO; +import com.youlai.boot.auth.model.vo.CaptchaVo; +import com.youlai.boot.auth.model.dto.WxMiniAppPhoneLoginDto; import com.youlai.boot.security.model.AuthenticationToken; -import com.youlai.boot.auth.model.dto.WxMiniAppCodeLoginDTO; +import com.youlai.boot.auth.model.dto.WxMiniAppCodeLoginDto; /** * 认证服务接口 @@ -32,7 +32,7 @@ public interface AuthService { * * @return 验证码 */ - CaptchaVO getCaptcha(); + CaptchaVo getCaptcha(); /** * 刷新令牌 @@ -53,18 +53,18 @@ public interface AuthService { /** * 微信小程序Code登录 * - * @param loginDTO 登录参数 + * @param loginDto 登录参数 * @return 访问令牌 */ - AuthenticationToken loginByWxMiniAppCode(WxMiniAppCodeLoginDTO loginDTO); + AuthenticationToken loginByWxMiniAppCode(WxMiniAppCodeLoginDto loginDto); /** * 微信小程序手机号登录 * - * @param loginDTO 登录参数 + * @param loginDto 登录参数 * @return 访问令牌 */ - AuthenticationToken loginByWxMiniAppPhone(WxMiniAppPhoneLoginDTO loginDTO); + AuthenticationToken loginByWxMiniAppPhone(WxMiniAppPhoneLoginDto loginDto); /** * 发送短信验证码 diff --git a/src/main/java/com/youlai/boot/auth/service/impl/AuthServiceImpl.java b/src/main/java/com/youlai/boot/auth/service/impl/AuthServiceImpl.java index dc32af31..2070efd4 100644 --- a/src/main/java/com/youlai/boot/auth/service/impl/AuthServiceImpl.java +++ b/src/main/java/com/youlai/boot/auth/service/impl/AuthServiceImpl.java @@ -5,9 +5,9 @@ import cn.hutool.captcha.CaptchaUtil; import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; -import com.youlai.boot.auth.model.dto.WxMiniAppCodeLoginDTO; -import com.youlai.boot.auth.model.dto.WxMiniAppPhoneLoginDTO; -import com.youlai.boot.auth.model.vo.CaptchaVO; +import com.youlai.boot.auth.model.dto.WxMiniAppCodeLoginDto; +import com.youlai.boot.auth.model.dto.WxMiniAppPhoneLoginDto; +import com.youlai.boot.auth.model.vo.CaptchaVo; import com.youlai.boot.auth.service.AuthService; import com.youlai.boot.common.constant.RedisConstants; import com.youlai.boot.common.constant.SecurityConstants; @@ -70,6 +70,11 @@ public class AuthServiceImpl implements AuthService { new UsernamePasswordAuthenticationToken(username.trim(), password); // 2. 执行认证(认证中) + // 说明:这里的认证流程由 Spring Security 提供的 AuthenticationManager 执行。 + // 默认情况下会委托给 DaoAuthenticationProvider: + // 1) retrieveUser(...):内部通过 UserDetailsService.loadUserByUsername(...) 获取用户信息(本项目为 SysUserDetailsService 实现) + // 2) additionalAuthenticationChecks(...):对比请求密码与用户存储密码(由 PasswordEncoder 完成匹配) + // 认证通过后返回已认证的 Authentication(principal 为 SysUserDetails,authorities 为角色/权限集合)。 Authentication authentication = authenticationManager.authenticate(authenticationToken); // 3. 认证成功后生成 JWT 令牌,并存入 Security 上下文,供登录日志 AOP 使用(已认证) @@ -166,7 +171,7 @@ public class AuthServiceImpl implements AuthService { * @return 验证码 */ @Override - public CaptchaVO getCaptcha() { + public CaptchaVo getCaptcha() { String captchaType = captchaProperties.getType(); int width = captchaProperties.getWidth(); @@ -202,7 +207,7 @@ public class AuthServiceImpl implements AuthService { TimeUnit.SECONDS ); - return CaptchaVO.builder() + return CaptchaVo.builder() .captchaId(captchaId) .captchaBase64(imageBase64Data) .build(); @@ -222,13 +227,13 @@ public class AuthServiceImpl implements AuthService { /** * 微信小程序Code登录 * - * @param loginDTO 登录参数 + * @param loginDto 登录参数 * @return 访问令牌 */ @Override - public AuthenticationToken loginByWxMiniAppCode(WxMiniAppCodeLoginDTO loginDTO) { + public AuthenticationToken loginByWxMiniAppCode(WxMiniAppCodeLoginDto loginDto) { // 1. 创建微信小程序认证令牌(未认证) - WxMiniAppCodeAuthenticationToken authenticationToken = new WxMiniAppCodeAuthenticationToken(loginDTO.getCode()); + WxMiniAppCodeAuthenticationToken authenticationToken = new WxMiniAppCodeAuthenticationToken(loginDto.getCode()); // 2. 执行认证(认证中) Authentication authentication = authenticationManager.authenticate(authenticationToken); @@ -243,16 +248,16 @@ public class AuthServiceImpl implements AuthService { /** * 微信小程序手机号登录 * - * @param loginDTO 登录参数 + * @param loginDto 登录参数 * @return 访问令牌 */ @Override - public AuthenticationToken loginByWxMiniAppPhone(WxMiniAppPhoneLoginDTO loginDTO) { + public AuthenticationToken loginByWxMiniAppPhone(WxMiniAppPhoneLoginDto loginDto) { // 创建微信小程序手机号认证Token WxMiniAppPhoneAuthenticationToken authenticationToken = new WxMiniAppPhoneAuthenticationToken( - loginDTO.getCode(), - loginDTO.getEncryptedData(), - loginDTO.getIv() + loginDto.getCode(), + loginDto.getEncryptedData(), + loginDto.getIv() ); // 执行认证 diff --git a/src/main/java/com/youlai/boot/common/base/BaseVO.java b/src/main/java/com/youlai/boot/common/base/BaseVO.java deleted file mode 100644 index bd1f540f..00000000 --- a/src/main/java/com/youlai/boot/common/base/BaseVO.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.youlai.boot.common.base; - -import lombok.Data; -import lombok.ToString; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 视图对象基类 - * - * @author haoxr - * @since 2022/10/22 - */ -@Data -@ToString -public class BaseVO implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; -} diff --git a/src/main/java/com/youlai/boot/core/web/ResultCode.java b/src/main/java/com/youlai/boot/core/web/ResultCode.java index d7ea897b..f40f506c 100644 --- a/src/main/java/com/youlai/boot/core/web/ResultCode.java +++ b/src/main/java/com/youlai/boot/core/web/ResultCode.java @@ -43,7 +43,7 @@ public enum ResultCode implements IResultCode, Serializable { VERIFICATION_CODE_INPUT_ERROR("A0130", "校验码输入错误"), SMS_VERIFICATION_CODE_INPUT_ERROR("A0131", "短信校验码输入错误"), EMAIL_VERIFICATION_CODE_INPUT_ERROR("A0132", "邮件校验码输入错误"), - VOICE_VERIFICATION_CODE_INPUT_ERROR("A0133", "语音校验码输入错误"), + VoICE_VERIFICATION_CODE_INPUT_ERROR("A0133", "语音校验码输入错误"), USER_CERTIFICATE_EXCEPTION("A0140", "用户证件异常"), USER_CERTIFICATE_TYPE_NOT_SELECTED("A0141", "用户证件类型未选择"), @@ -262,7 +262,7 @@ public enum ResultCode implements IResultCode, Serializable { /** 二级宏观错误码 */ NOTIFICATION_SERVICE_ERROR("C0500", "通知服务出错"), SMS_REMINDER_SERVICE_FAILED("C0501", "短信提醒服务失败"), - VOICE_REMINDER_SERVICE_FAILED("C0502", "语音提醒服务失败"), + VoICE_REMINDER_SERVICE_FAILED("C0502", "语音提醒服务失败"), EMAIL_REMINDER_SERVICE_FAILED("C0503", "邮件提醒服务失败"); diff --git a/src/main/java/com/youlai/boot/platform/ai/controller/AiAssistantController.java b/src/main/java/com/youlai/boot/platform/ai/controller/AiAssistantController.java new file mode 100644 index 00000000..72744ed2 --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/ai/controller/AiAssistantController.java @@ -0,0 +1,109 @@ +package com.youlai.boot.platform.ai.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.youlai.boot.core.web.PageResult; +import com.youlai.boot.core.web.Result; +import com.youlai.boot.platform.ai.model.dto.AiExecuteRequestDto; +import com.youlai.boot.platform.ai.model.dto.AiParseRequestDto; +import com.youlai.boot.platform.ai.model.dto.AiParseResponseDto; +import com.youlai.boot.platform.ai.model.query.AiAssistantPageQuery; +import com.youlai.boot.platform.ai.model.vo.AiAssistantRecordVo; +import com.youlai.boot.platform.ai.service.AiAssistantRecordService; +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 lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * AI 助手控制器 + *

+ * 负责 AI 命令的解析、执行、记录管理及回滚操作, + * 表示一次 AI 助手完整的指令生命周期。 + * + * @author Ray.Hao + * @since 3.0.0 + */ +@Tag(name = "AI 助手接口") +@RestController +@RequestMapping("/api/v1/ai/assistant") +@RequiredArgsConstructor +@Slf4j +public class AiAssistantController { + + private final AiAssistantRecordService aiAssistantRecordService; + + @Operation(summary = "解析自然语言命令") + @PostMapping("/parse") + public Result parseCommand( + @RequestBody AiParseRequestDto request, + HttpServletRequest httpRequest + ) { + log.info("收到 AI 命令解析请求: {}", request.getCommand()); + try { + AiParseResponseDto response = aiAssistantRecordService.parseCommand(request, httpRequest); + return Result.success(response); + } catch (Exception e) { + log.error("命令解析失败", e); + return Result.success(AiParseResponseDto.builder() + .success(false) + .error(e.getMessage()) + .build()); + } + } + + @Operation(summary = "执行已解析的命令") + @PostMapping("/execute") + public Result executeCommand( + @RequestBody AiExecuteRequestDto request, + HttpServletRequest httpRequest + ) { + log.info("收到 AI 命令执行请求: {}", request.getFunctionCall().getName()); + try { + Object result = aiAssistantRecordService.executeCommand(request, httpRequest); + return Result.success(result); + } catch (Exception e) { + log.error("命令执行失败", e); + return Result.failed(e.getMessage()); + } + } + + @Operation(summary = "获取 AI 命令记录分页列表") + @GetMapping("/records") + public PageResult getRecordPage(AiAssistantPageQuery queryParams) { + IPage page = aiAssistantRecordService.getRecordPage(queryParams); + return PageResult.success(page); + } + + @Operation(summary = "删除 AI 命令记录") + @DeleteMapping("/records/{ids}") + public Result deleteRecords( + @Parameter(description = "记录ID,多个以英文逗号(,)分割") + @PathVariable String ids + ) { + List idList = Arrays.stream(ids.split(",")) + .filter(s -> s != null && !s.isBlank()) + .map(String::trim) + .map(Long::valueOf) + .collect(Collectors.toList()); + + boolean removed = aiAssistantRecordService.deleteRecords(idList); + return Result.judge(removed); + } + + @Operation(summary = "撤销命令执行") + @PostMapping("/records/{recordId}/rollback") + public Result rollbackCommand( + @Parameter(description = "记录ID") + @PathVariable String recordId + ) { + aiAssistantRecordService.rollbackCommand(recordId); + return Result.success(); + } +} diff --git a/src/main/java/com/youlai/boot/platform/ai/controller/AiCommandController.java b/src/main/java/com/youlai/boot/platform/ai/controller/AiCommandController.java deleted file mode 100644 index 464dfc19..00000000 --- a/src/main/java/com/youlai/boot/platform/ai/controller/AiCommandController.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.youlai.boot.platform.ai.controller; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.youlai.boot.core.web.PageResult; -import com.youlai.boot.core.web.Result; -import com.youlai.boot.platform.ai.model.dto.AiExecuteRequestDTO; -import com.youlai.boot.platform.ai.model.dto.AiParseRequestDTO; -import com.youlai.boot.platform.ai.model.dto.AiParseResponseDTO; -import com.youlai.boot.platform.ai.model.query.AiCommandPageQuery; -import com.youlai.boot.platform.ai.model.vo.AiCommandRecordVO; -import com.youlai.boot.platform.ai.service.AiCommandRecordService; -import com.youlai.boot.platform.ai.service.AiCommandService; -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 lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.*; - -/** - * AI 命令控制器(基于 Spring AI) - * - * @author Ray.Hao - * @since 3.0.0 - */ -@Tag(name = "AI命令接口") -@RestController -@RequestMapping("/api/v1/ai/command") -@RequiredArgsConstructor -@Slf4j -public class AiCommandController { - - private final AiCommandService aiCommandService; - private final AiCommandRecordService recordService; - - @Operation(summary = "解析自然语言命令") - @PostMapping("/parse") - public Result parseCommand( - @RequestBody AiParseRequestDTO request, - HttpServletRequest httpRequest - ) { - log.info("收到AI命令解析请求: {}", request.getCommand()); - - try { - AiParseResponseDTO response = aiCommandService.parseCommand(request, httpRequest); - return Result.success(response); - } catch (Exception e) { - log.error("命令解析失败", e); - return Result.success(AiParseResponseDTO.builder() - .success(false) - .error(e.getMessage()) - .build()); - } - } - - @Operation(summary = "执行已解析的命令") - @PostMapping("/execute") - public Result executeCommand( - @RequestBody AiExecuteRequestDTO request, - HttpServletRequest httpRequest - ) { - log.info("收到AI命令执行请求: {}", request.getFunctionCall().getName()); - try { - Object result = aiCommandService.executeCommand(request, httpRequest); - return Result.success(result); - } catch (Exception e) { - log.error("命令执行失败", e); - return Result.failed(e.getMessage()); - } - } - - @Operation(summary = "获取AI命令记录分页列表") - @GetMapping("/records") - public PageResult getRecordPage(AiCommandPageQuery queryParams) { - IPage page = recordService.getRecordPage(queryParams); - return PageResult.success(page); - } - - @Operation(summary = "撤销命令执行") - @PostMapping("/rollback/{recordId}") - public Result rollbackCommand( - @Parameter(description = "记录ID") @PathVariable String recordId - ) { - recordService.rollbackCommand(recordId); - return Result.success("撤销成功"); - } - -} - - - - diff --git a/src/main/java/com/youlai/boot/platform/ai/mapper/AiAssistantRecordMapper.java b/src/main/java/com/youlai/boot/platform/ai/mapper/AiAssistantRecordMapper.java new file mode 100644 index 00000000..b5131587 --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/ai/mapper/AiAssistantRecordMapper.java @@ -0,0 +1,22 @@ +package com.youlai.boot.platform.ai.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.youlai.boot.platform.ai.model.entity.AiAssistantRecord; +import com.youlai.boot.platform.ai.model.query.AiAssistantPageQuery; +import com.youlai.boot.platform.ai.model.vo.AiAssistantRecordVo; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface AiAssistantRecordMapper extends BaseMapper { + + /** + * AI 助手行为记录分页列表 + * + * @param page 分页参数 + * @param queryParams 查询参数 + * @return 分页结果 + */ + IPage getRecordPage(Page page, AiAssistantPageQuery queryParams); +} diff --git a/src/main/java/com/youlai/boot/platform/ai/mapper/AiCommandRecordMapper.java b/src/main/java/com/youlai/boot/platform/ai/mapper/AiCommandRecordMapper.java deleted file mode 100644 index e26bb6c6..00000000 --- a/src/main/java/com/youlai/boot/platform/ai/mapper/AiCommandRecordMapper.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.youlai.boot.platform.ai.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.youlai.boot.platform.ai.model.entity.AiCommandRecord; -import com.youlai.boot.platform.ai.model.query.AiCommandPageQuery; -import com.youlai.boot.platform.ai.model.vo.AiCommandRecordVO; -import org.apache.ibatis.annotations.Mapper; - -/** - * AI 命令记录 Mapper - * - * @author Ray.Hao - * @since 3.0.0 - */ -@Mapper -public interface AiCommandRecordMapper extends BaseMapper { - - /** - * 获取 AI 命令记录分页列表 - */ - IPage getRecordPage(Page page, AiCommandPageQuery queryParams); -} - - diff --git a/src/main/java/com/youlai/boot/platform/ai/model/dto/AiExecuteRequestDTO.java b/src/main/java/com/youlai/boot/platform/ai/model/dto/AiExecuteRequestDTO.java index 0dc54317..80a3058e 100644 --- a/src/main/java/com/youlai/boot/platform/ai/model/dto/AiExecuteRequestDTO.java +++ b/src/main/java/com/youlai/boot/platform/ai/model/dto/AiExecuteRequestDTO.java @@ -3,13 +3,13 @@ package com.youlai.boot.platform.ai.model.dto; import lombok.Data; /** - * AI 命令执行请求 DTO + * AI 命令执行请求 Dto * * @author Ray.Hao * @since 3.0.0 */ @Data -public class AiExecuteRequestDTO { +public class AiExecuteRequestDto { /** * 关联的解析日志ID @@ -24,7 +24,7 @@ public class AiExecuteRequestDTO { /** * 要执行的函数调用 */ - private AiFunctionCallDTO functionCall; + private AiFunctionCallDto functionCall; /** * 确认模式:auto=自动执行, manual=需要用户确认 @@ -46,6 +46,3 @@ public class AiExecuteRequestDTO { */ private String currentRoute; } - - - diff --git a/src/main/java/com/youlai/boot/platform/ai/model/dto/AiExecuteResponseDTO.java b/src/main/java/com/youlai/boot/platform/ai/model/dto/AiExecuteResponseDTO.java index 8796e58e..aa2c0371 100644 --- a/src/main/java/com/youlai/boot/platform/ai/model/dto/AiExecuteResponseDTO.java +++ b/src/main/java/com/youlai/boot/platform/ai/model/dto/AiExecuteResponseDTO.java @@ -6,7 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; /** - * AI 命令执行响应 DTO + * AI 命令执行响应 Dto * * @author Ray.Hao * @since 3.0.0 @@ -15,7 +15,7 @@ import lombok.NoArgsConstructor; @Builder @NoArgsConstructor @AllArgsConstructor -public class AiExecuteResponseDTO { +public class AiExecuteResponseDto { /** * 是否执行成功 @@ -57,6 +57,3 @@ public class AiExecuteResponseDTO { */ private String confirmationPrompt; } - - - diff --git a/src/main/java/com/youlai/boot/platform/ai/model/dto/AiFunctionCallDTO.java b/src/main/java/com/youlai/boot/platform/ai/model/dto/AiFunctionCallDTO.java index 2b2368b1..c5aab5b1 100644 --- a/src/main/java/com/youlai/boot/platform/ai/model/dto/AiFunctionCallDTO.java +++ b/src/main/java/com/youlai/boot/platform/ai/model/dto/AiFunctionCallDTO.java @@ -7,7 +7,7 @@ import lombok.NoArgsConstructor; import java.util.Map; /** - * AI 函数调用 DTO + * AI 函数调用 Dto * * @author Ray.Hao * @since 3.0.0 @@ -16,7 +16,7 @@ import java.util.Map; @Builder @NoArgsConstructor @AllArgsConstructor -public class AiFunctionCallDTO { +public class AiFunctionCallDto { /** * 函数名称 diff --git a/src/main/java/com/youlai/boot/platform/ai/model/dto/AiParseRequestDTO.java b/src/main/java/com/youlai/boot/platform/ai/model/dto/AiParseRequestDTO.java index 4578a28a..35d7038a 100644 --- a/src/main/java/com/youlai/boot/platform/ai/model/dto/AiParseRequestDTO.java +++ b/src/main/java/com/youlai/boot/platform/ai/model/dto/AiParseRequestDTO.java @@ -4,13 +4,13 @@ import lombok.Data; import java.util.Map; /** - * AI 解析请求 DTO + * AI 解析请求 Dto * * @author Ray.Hao * @since 3.0.0 */ @Data -public class AiParseRequestDTO { +public class AiParseRequestDto { /** * 用户输入的自然语言命令 @@ -32,4 +32,3 @@ public class AiParseRequestDTO { */ private Map context; } - diff --git a/src/main/java/com/youlai/boot/platform/ai/model/dto/AiParseResponseDTO.java b/src/main/java/com/youlai/boot/platform/ai/model/dto/AiParseResponseDTO.java index 239dacc5..e8c9c372 100644 --- a/src/main/java/com/youlai/boot/platform/ai/model/dto/AiParseResponseDTO.java +++ b/src/main/java/com/youlai/boot/platform/ai/model/dto/AiParseResponseDTO.java @@ -7,7 +7,7 @@ import lombok.NoArgsConstructor; import java.util.List; /** - * AI 解析响应 DTO + * AI 解析响应 Dto * * @author Ray.Hao * @since 3.0.0 @@ -16,7 +16,7 @@ import java.util.List; @Builder @NoArgsConstructor @AllArgsConstructor -public class AiParseResponseDTO { +public class AiParseResponseDto { /** * 解析日志ID(用于关联执行记录) @@ -31,7 +31,7 @@ public class AiParseResponseDTO { /** * 解析后的函数调用列表 */ - private List functionCalls; + private List functionCalls; /** * AI 的理解和说明 @@ -53,4 +53,3 @@ public class AiParseResponseDTO { */ private String rawResponse; } - diff --git a/src/main/java/com/youlai/boot/platform/ai/model/entity/AiAssistantRecord.java b/src/main/java/com/youlai/boot/platform/ai/model/entity/AiAssistantRecord.java new file mode 100644 index 00000000..6fa37b12 --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/ai/model/entity/AiAssistantRecord.java @@ -0,0 +1,80 @@ +package com.youlai.boot.platform.ai.model.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.youlai.boot.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * AI 助手行为记录实体 + * + * @author Ray.Hao + * @since 3.0.0 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("ai_assistant_record") +public class AiAssistantRecord extends BaseEntity { + + /** 用户ID */ + private Long userId; + + /** 用户名 */ + private String username; + + /** 原始命令 */ + private String originalCommand; + + // ==================== 解析相关字段 ==================== + + /** AI 供应商(qwen/openai/deepseek等) */ + private String aiProvider; + + /** AI 模型(qwen-plus/qwen-max/gpt-4-turbo等) */ + private String aiModel; + + /** 解析状态(0-失败, 1-成功) */ + private Integer parseStatus; + + /** 解析出的函数调用列表(JSON) */ + private String functionCalls; + + /** AI 的理解说明 */ + private String explanation; + + /** 置信度(0.00-1.00) */ + private BigDecimal confidence; + + /** 解析错误信息 */ + private String parseErrorMessage; + + /** 输入 Token 数量 */ + private Integer inputTokens; + + /** 输出 Token 数量 */ + private Integer outputTokens; + + /** 解析耗时(毫秒) */ + private Integer parseDurationMs; + + // ==================== 执行相关字段 ==================== + + /** 执行的函数名称 */ + private String functionName; + + /** 函数参数(JSON) */ + private String functionArguments; + + /** 执行状态(0-待执行, 1-成功, -1-失败) */ + private Integer executeStatus; + + /** 执行错误信息 */ + private String executeErrorMessage; + + // ==================== 通用字段 ==================== + + /** IP 地址 */ + private String ipAddress; +} diff --git a/src/main/java/com/youlai/boot/platform/ai/model/entity/AiCommandRecord.java b/src/main/java/com/youlai/boot/platform/ai/model/entity/AiCommandRecord.java deleted file mode 100644 index 1750970b..00000000 --- a/src/main/java/com/youlai/boot/platform/ai/model/entity/AiCommandRecord.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.youlai.boot.platform.ai.model.entity; - -import com.baomidou.mybatisplus.annotation.TableName; -import com.youlai.boot.common.base.BaseEntity; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.math.BigDecimal; - -/** - * AI 命令记录实体 - * - * @author Ray.Hao - * @since 3.0.0 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@TableName("ai_command_record") -public class AiCommandRecord extends BaseEntity { - - /** 用户ID */ - private Long userId; - - /** 用户名 */ - private String username; - - /** 原始命令 */ - private String originalCommand; - - // ==================== 解析相关字段 ==================== - - /** AI 供应商(qwen/openai/deepseek等) */ - private String aiProvider; - - /** AI 模型(qwen-plus/qwen-max/gpt-4-turbo等) */ - private String aiModel; - - /** 解析状态(0-失败, 1-成功) */ - private Integer parseStatus; - - /** 解析出的函数调用列表(JSON) */ - private String functionCalls; - - /** AI 的理解说明 */ - private String explanation; - - /** 置信度(0.00-1.00) */ - private BigDecimal confidence; - - /** 解析错误信息 */ - private String parseErrorMessage; - - /** 输入 Token 数量 */ - private Integer inputTokens; - - /** 输出 Token 数量 */ - private Integer outputTokens; - - /** 解析耗时(毫秒) */ - private Integer parseDurationMs; - - // ==================== 执行相关字段 ==================== - - /** 执行的函数名称 */ - private String functionName; - - /** 函数参数(JSON) */ - private String functionArguments; - - /** 执行状态(0-待执行, 1-成功, -1-失败) */ - private Integer executeStatus; - - /** 执行错误信息 */ - private String executeErrorMessage; - - // ==================== 通用字段 ==================== - - /** IP 地址 */ - private String ipAddress; -} - - diff --git a/src/main/java/com/youlai/boot/platform/ai/model/query/AiAssistantPageQuery.java b/src/main/java/com/youlai/boot/platform/ai/model/query/AiAssistantPageQuery.java new file mode 100644 index 00000000..4d5cc552 --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/ai/model/query/AiAssistantPageQuery.java @@ -0,0 +1,44 @@ +package com.youlai.boot.platform.ai.model.query; + +import com.youlai.boot.common.base.BasePageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * AI 助手行为记录分页查询对象 + * + * @author Ray.Hao + * @since 3.0.0 + */ +@Schema(description = "AI 助手行为记录分页查询对象") +@Getter +@Setter +public class AiAssistantPageQuery extends BasePageQuery { + + @Schema(description = "关键字(原始命令/函数名称/用户名)") + private String keywords; + + @Schema(description = "执行状态(0-待执行, 1-成功, -1-失败)") + private Integer executeStatus; + + @Schema(description = "用户ID") + private Long userId; + + @Schema(description = "解析状态(0-失败, 1-成功)") + private Integer parseStatus; + + @Schema(description = "创建时间范围") + private List createTime; + + @Schema(description = "函数名称") + private String functionName; + + @Schema(description = "AI供应商") + private String aiProvider; + + @Schema(description = "AI模型") + private String aiModel; +} diff --git a/src/main/java/com/youlai/boot/platform/ai/model/query/AiCommandPageQuery.java b/src/main/java/com/youlai/boot/platform/ai/model/query/AiCommandPageQuery.java deleted file mode 100644 index 0322b09e..00000000 --- a/src/main/java/com/youlai/boot/platform/ai/model/query/AiCommandPageQuery.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.youlai.boot.platform.ai.model.query; - -import com.youlai.boot.common.base.BasePageQuery; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; -import lombok.Setter; - -import java.util.List; - -/** - * AI命令记录分页查询对象 - * - * @author Ray.Hao - * @since 3.0.0 - */ -@Schema(description = "AI命令记录分页查询对象") -@Getter -@Setter -public class AiCommandPageQuery extends BasePageQuery { - - @Schema(description = "关键字(原始命令/函数名称/用户名)") - private String keywords; - - @Schema(description = "执行状态(0-待执行, 1-成功, -1-失败)") - private Integer executeStatus; - - @Schema(description = "用户ID") - private Long userId; - - @Schema(description = "解析状态(0-失败, 1-成功)") - private Integer parseStatus; - - @Schema(description = "创建时间范围") - private List createTime; - - @Schema(description = "函数名称") - private String functionName; - - @Schema(description = "AI供应商") - private String aiProvider; - - @Schema(description = "AI模型") - private String aiModel; -} - diff --git a/src/main/java/com/youlai/boot/platform/ai/model/vo/AiAssistantRecordVo.java b/src/main/java/com/youlai/boot/platform/ai/model/vo/AiAssistantRecordVo.java new file mode 100644 index 00000000..e72f4129 --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/ai/model/vo/AiAssistantRecordVo.java @@ -0,0 +1,91 @@ +package com.youlai.boot.platform.ai.model.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * AI 助手行为记录Vo + * + * @author Ray.Hao + * @since 3.0.0 + */ +@Data +@Schema(description = "AI 助手行为记录Vo") +public class AiAssistantRecordVo implements Serializable { + + @Schema(description = "主键ID") + private String id; + + @Schema(description = "用户ID") + private Long userId; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "原始命令") + private String originalCommand; + + // ==================== 解析相关字段 ==================== + + @Schema(description = "AI供应商") + private String aiProvider; + + @Schema(description = "AI模型") + private String aiModel; + + @Schema(description = "解析状态(0-失败, 1-成功)") + private Integer parseStatus; + + @Schema(description = "解析出的函数调用列表(JSON)") + private String functionCalls; + + @Schema(description = "AI的理解说明") + private String explanation; + + @Schema(description = "置信度") + private BigDecimal confidence; + + @Schema(description = "解析错误信息") + private String parseErrorMessage; + + @Schema(description = "输入Token数量") + private Integer inputTokens; + + @Schema(description = "输出Token数量") + private Integer outputTokens; + + @Schema(description = "解析耗时(毫秒)") + private Integer parseDurationMs; + + // ==================== 执行相关字段 ==================== + + @Schema(description = "执行的函数名称") + private String functionName; + + @Schema(description = "函数参数(JSON)") + private String functionArguments; + + @Schema(description = "执行状态(0-待执行, 1-成功, -1-失败)") + private Integer executeStatus; + + @Schema(description = "执行错误信息") + private String executeErrorMessage; + + // ==================== 通用字段 ==================== + + @Schema(description = "IP地址") + private String ipAddress; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/src/main/java/com/youlai/boot/platform/ai/model/vo/AiCommandRecordVO.java b/src/main/java/com/youlai/boot/platform/ai/model/vo/AiCommandRecordVO.java deleted file mode 100644 index 088c5f9c..00000000 --- a/src/main/java/com/youlai/boot/platform/ai/model/vo/AiCommandRecordVO.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.youlai.boot.platform.ai.model.vo; - -import com.fasterxml.jackson.annotation.JsonFormat; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.io.Serializable; -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * AI命令记录VO - * - * @author Ray.Hao - * @since 3.0.0 - */ -@Data -@Schema(description = "AI命令记录VO") -public class AiCommandRecordVO implements Serializable { - - @Schema(description = "主键ID") - private String id; - - @Schema(description = "用户ID") - private Long userId; - - @Schema(description = "用户名") - private String username; - - @Schema(description = "原始命令") - private String originalCommand; - - // ==================== 解析相关字段 ==================== - - @Schema(description = "AI供应商") - private String aiProvider; - - @Schema(description = "AI模型") - private String aiModel; - - @Schema(description = "解析状态(0-失败, 1-成功)") - private Integer parseStatus; - - @Schema(description = "解析出的函数调用列表(JSON)") - private String functionCalls; - - @Schema(description = "AI的理解说明") - private String explanation; - - @Schema(description = "置信度") - private BigDecimal confidence; - - @Schema(description = "解析错误信息") - private String parseErrorMessage; - - @Schema(description = "输入Token数量") - private Integer inputTokens; - - @Schema(description = "输出Token数量") - private Integer outputTokens; - - @Schema(description = "解析耗时(毫秒)") - private Integer parseDurationMs; - - // ==================== 执行相关字段 ==================== - - @Schema(description = "执行的函数名称") - private String functionName; - - @Schema(description = "函数参数(JSON)") - private String functionArguments; - - @Schema(description = "执行状态(0-待执行, 1-成功, -1-失败)") - private Integer executeStatus; - - @Schema(description = "执行错误信息") - private String executeErrorMessage; - - // ==================== 通用字段 ==================== - - @Schema(description = "IP地址") - private String ipAddress; - - @Schema(description = "创建时间") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime createTime; - - @Schema(description = "更新时间") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime updateTime; -} - diff --git a/src/main/java/com/youlai/boot/platform/ai/service/AiAssistantRecordService.java b/src/main/java/com/youlai/boot/platform/ai/service/AiAssistantRecordService.java new file mode 100644 index 00000000..2e47a84a --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/ai/service/AiAssistantRecordService.java @@ -0,0 +1,66 @@ +package com.youlai.boot.platform.ai.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.youlai.boot.platform.ai.model.dto.AiExecuteRequestDto; +import com.youlai.boot.platform.ai.model.dto.AiParseRequestDto; +import com.youlai.boot.platform.ai.model.dto.AiParseResponseDto; +import com.youlai.boot.platform.ai.model.entity.AiAssistantRecord; +import com.youlai.boot.platform.ai.model.query.AiAssistantPageQuery; +import com.youlai.boot.platform.ai.model.vo.AiAssistantRecordVo; +import jakarta.servlet.http.HttpServletRequest; + +import java.util.List; + +/** + * AI 助手行为记录服务接口 + * + * 负责 AI 助手指令的解析/执行审计记录的分页查询、删除与回滚。 + * + * @author Ray.Hao + * @since 3.0.0 + */ +public interface AiAssistantRecordService extends IService { + + /** + * 解析自然语言命令。 + * + * @param request 解析请求参数 + * @param httpRequest HTTP 请求(用于获取 IP 等上下文) + * @return 解析结果(包含 functionCalls 等信息) + */ + AiParseResponseDto parseCommand(AiParseRequestDto request, HttpServletRequest httpRequest); + + /** + * 执行已解析的命令。 + * + * @param request 执行请求参数 + * @param httpRequest HTTP 请求(用于获取 IP 等上下文) + * @return 执行结果 + * @throws Exception 执行异常 + */ + Object executeCommand(AiExecuteRequestDto request, HttpServletRequest httpRequest) throws Exception; + + /** + * 获取 AI 助手行为记录分页列表 + * + * @param queryParams 查询参数 + * @return 分页列表 + */ + IPage getRecordPage(AiAssistantPageQuery queryParams); + + /** + * 删除 AI 助手行为记录。 + * + * @param ids 记录ID列表 + * @return 是否删除成功 + */ + boolean deleteRecords(List ids); + + /** + * 撤销命令执行 + * + * @param logId 记录ID + */ + void rollbackCommand(String logId); +} diff --git a/src/main/java/com/youlai/boot/platform/ai/service/AiCommandRecordService.java b/src/main/java/com/youlai/boot/platform/ai/service/AiCommandRecordService.java deleted file mode 100644 index 5e94c87d..00000000 --- a/src/main/java/com/youlai/boot/platform/ai/service/AiCommandRecordService.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.youlai.boot.platform.ai.service; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.youlai.boot.platform.ai.model.entity.AiCommandRecord; -import com.youlai.boot.platform.ai.model.query.AiCommandPageQuery; -import com.youlai.boot.platform.ai.model.vo.AiCommandRecordVO; - -/** - * AI 命令记录服务接口 - * - * @author Ray.Hao - * @since 3.0.0 - */ -public interface AiCommandRecordService extends IService { - - /** - * 获取命令记录分页列表 - * - * @param queryParams 查询参数 - * @return 命令记录分页列表 - */ - IPage getRecordPage(AiCommandPageQuery queryParams); - - /** - * 撤销命令执行 - * - * @param logId 记录ID - */ - void rollbackCommand(String logId); -} - - diff --git a/src/main/java/com/youlai/boot/platform/ai/service/AiCommandService.java b/src/main/java/com/youlai/boot/platform/ai/service/AiCommandService.java deleted file mode 100644 index 1f5011bf..00000000 --- a/src/main/java/com/youlai/boot/platform/ai/service/AiCommandService.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.youlai.boot.platform.ai.service; - -import com.youlai.boot.platform.ai.model.dto.AiExecuteRequestDTO; -import com.youlai.boot.platform.ai.model.dto.AiParseRequestDTO; -import com.youlai.boot.platform.ai.model.dto.AiParseResponseDTO; -import jakarta.servlet.http.HttpServletRequest; - -/** - * AI 命令编排服务:负责对外的解析与执行编排 - */ -public interface AiCommandService { - - /** - * 解析自然语言命令 - */ - AiParseResponseDTO parseCommand(AiParseRequestDTO request, HttpServletRequest httpRequest); - - /** - * 执行已解析的命令 - * - * @param request 执行请求 - * @param httpRequest HTTP 请求 - * @return 执行结果数据(成功时返回) - * @throws Exception 执行失败时抛出异常 - */ - Object executeCommand(AiExecuteRequestDTO request, HttpServletRequest httpRequest) throws Exception; -} - - - - - diff --git a/src/main/java/com/youlai/boot/platform/ai/service/impl/AiAssistantRecordServiceImpl.java b/src/main/java/com/youlai/boot/platform/ai/service/impl/AiAssistantRecordServiceImpl.java new file mode 100644 index 00000000..a56b9709 --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/ai/service/impl/AiAssistantRecordServiceImpl.java @@ -0,0 +1,321 @@ +package com.youlai.boot.platform.ai.service.impl; + +import cn.hutool.core.lang.TypeReference; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.JakartaServletUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.youlai.boot.platform.ai.mapper.AiAssistantRecordMapper; +import com.youlai.boot.platform.ai.model.dto.AiExecuteRequestDto; +import com.youlai.boot.platform.ai.model.dto.AiFunctionCallDto; +import com.youlai.boot.platform.ai.model.dto.AiParseRequestDto; +import com.youlai.boot.platform.ai.model.dto.AiParseResponseDto; +import com.youlai.boot.platform.ai.model.entity.AiAssistantRecord; +import com.youlai.boot.platform.ai.model.query.AiAssistantPageQuery; +import com.youlai.boot.platform.ai.model.vo.AiAssistantRecordVo; +import com.youlai.boot.platform.ai.service.AiAssistantRecordService; +import com.youlai.boot.platform.ai.tools.UserTools; +import com.youlai.boot.security.util.SecurityUtils; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * AI 助手行为记录服务实现类 + * + * @author Ray.Hao + * @since 3.0.0 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class AiAssistantRecordServiceImpl + extends ServiceImpl + implements AiAssistantRecordService { + + private static final String SYSTEM_PROMPT = """ + 你是一个智能的企业操作助手,需要将用户的自然语言命令解析成标准的函数调用。 + 请返回严格的 JSON 格式,包含字段: + - success: boolean + - explanation: string + - confidence: number (0-1) + - error: string + - provider: string + - model: string + - functionCalls: 数组,每个元素包含 name、description、arguments(对象) + 当无法识别命令时,success=false,并给出 error。 + """; + + private final UserTools userTools; + private final ChatClient chatClient; + + @Override + public AiParseResponseDto parseCommand(AiParseRequestDto request, HttpServletRequest httpRequest) { + long startTime = System.currentTimeMillis(); + String command = Optional.ofNullable(request.getCommand()).orElse("").trim(); + + if (StrUtil.isBlank(command)) { + return AiParseResponseDto.builder() + .success(false) + .error("命令不能为空") + .functionCalls(Collections.emptyList()) + .build(); + } + + Long userId = SecurityUtils.getUserId(); + String username = SecurityUtils.getUsername(); + String ipAddress = JakartaServletUtil.getClientIP(httpRequest); + + AiAssistantRecord commandRecord = new AiAssistantRecord(); + commandRecord.setUserId(userId); + commandRecord.setUsername(username); + commandRecord.setOriginalCommand(command); + commandRecord.setIpAddress(ipAddress); + commandRecord.setAiProvider("spring-ai"); + commandRecord.setAiModel("auto"); + + String systemPrompt = buildSystemPrompt(); + String userPrompt = buildUserPrompt(request); + + try { + log.info("📤 发送命令至 AI 模型: {}", command); + ChatResponse chatResponse = chatClient.prompt() + .system(systemPrompt) + .user(userPrompt) + .call().chatResponse(); + + String rawContent = Optional.ofNullable(chatResponse.getResult()) + .map(result -> result.getOutput().getText()) + .orElse(""); + + ParseResult parseResult = parseAiResponse(rawContent); + + commandRecord.setAiProvider(StrUtil.emptyToDefault(parseResult.provider(), "spring-ai")); + commandRecord.setAiModel(StrUtil.emptyToDefault(parseResult.model(), "auto")); + commandRecord.setParseStatus(parseResult.success() ? 1 : 0); + commandRecord.setExplanation(parseResult.explanation()); + commandRecord.setFunctionCalls(JSONUtil.toJsonStr(parseResult.functionCalls())); + commandRecord.setConfidence(parseResult.confidence() != null ? BigDecimal.valueOf(parseResult.confidence()) : null); + commandRecord.setParseErrorMessage(parseResult.success() ? null : StrUtil.emptyToDefault(parseResult.error(), "解析失败")); + long duration = System.currentTimeMillis() - startTime; + commandRecord.setParseDurationMs((int) duration); + + this.save(commandRecord); + + return AiParseResponseDto.builder() + .parseLogId(commandRecord.getId()) + .success(parseResult.success()) + .functionCalls(parseResult.functionCalls()) + .explanation(parseResult.explanation()) + .confidence(parseResult.confidence()) + .error(parseResult.error()) + .rawResponse(rawContent) + .build(); + } catch (Exception e) { + long duration = System.currentTimeMillis() - startTime; + commandRecord.setParseStatus(0); + commandRecord.setFunctionCalls(JSONUtil.toJsonStr(Collections.emptyList())); + commandRecord.setParseErrorMessage(e.getMessage()); + commandRecord.setParseDurationMs((int) duration); + this.save(commandRecord); + + log.error("❌ 解析命令失败: {}", e.getMessage(), e); + throw new RuntimeException("解析命令失败: " + e.getMessage(), e); + } + } + + private String buildSystemPrompt() { + return SYSTEM_PROMPT; + } + + private String buildUserPrompt(AiParseRequestDto request) { + JSONObject payload = JSONUtil.createObj() + .set("command", request.getCommand()) + .set("currentRoute", request.getCurrentRoute()) + .set("currentComponent", request.getCurrentComponent()) + .set("context", Optional.ofNullable(request.getContext()).orElse(Collections.emptyMap())) + .set("availableFunctions", availableFunctions()); + + return StrUtil.format(""" + 请根据以下上下文识别用户意图,并输出符合系统提示要求的 JSON: + {} + """, JSONUtil.toJsonPrettyStr(payload)); + } + + private List> availableFunctions() { + return List.of( + Map.of( + "name", "updateUserNickname", + "description", "根据用户名更新用户昵称", + "requiredParameters", List.of("username", "nickname") + ) + ); + } + + private ParseResult parseAiResponse(String rawContent) { + if (StrUtil.isBlank(rawContent)) { + throw new IllegalStateException("AI 返回内容为空"); + } + + try { + JSONObject jsonObject = JSONUtil.parseObj(rawContent); + boolean success = jsonObject.getBool("success", false); + String explanation = jsonObject.getStr("explanation"); + Double confidence = jsonObject.containsKey("confidence") ? jsonObject.getDouble("confidence") : null; + String error = jsonObject.getStr("error"); + String provider = jsonObject.getStr("provider"); + String model = jsonObject.getStr("model"); + + List functionCalls = toFunctionCallList(jsonObject.getJSONArray("functionCalls")); + + return new ParseResult(success, explanation, confidence, error, provider, model, functionCalls); + } catch (Exception ex) { + throw new IllegalStateException("无法解析 AI 响应: " + ex.getMessage(), ex); + } + } + + private List toFunctionCallList(JSONArray array) { + if (array == null || array.isEmpty()) { + return Collections.emptyList(); + } + + List result = new ArrayList<>(); + for (Object element : array) { + JSONObject functionJson = JSONUtil.parseObj(element); + Map arguments = Optional.ofNullable(functionJson.getJSONObject("arguments")) + .map(obj -> obj.toBean(new TypeReference>() { + })) + .orElse(Collections.emptyMap()); + + result.add(AiFunctionCallDto.builder() + .name(functionJson.getStr("name")) + .description(functionJson.getStr("description")) + .arguments(arguments) + .build()); + } + return result; + } + + private record ParseResult( + boolean success, + String explanation, + Double confidence, + String error, + String provider, + String model, + List functionCalls + ) { + } + + @Override + public Object executeCommand(AiExecuteRequestDto request, HttpServletRequest httpRequest) throws Exception { + Long userId = SecurityUtils.getUserId(); + String username = SecurityUtils.getUsername(); + String ipAddress = JakartaServletUtil.getClientIP(httpRequest); + + AiFunctionCallDto functionCall = request.getFunctionCall(); + + AiAssistantRecord commandRecord; + if (StrUtil.isNotBlank(request.getParseLogId())) { + commandRecord = this.getById(request.getParseLogId()); + if (commandRecord == null) { + throw new IllegalStateException("未找到对应的解析记录,ID: " + request.getParseLogId()); + } + } else { + commandRecord = new AiAssistantRecord(); + commandRecord.setUserId(userId); + commandRecord.setUsername(username); + commandRecord.setOriginalCommand(request.getOriginalCommand()); + commandRecord.setIpAddress(ipAddress); + this.save(commandRecord); + } + + commandRecord.setFunctionName(functionCall.getName()); + commandRecord.setFunctionArguments(JSONUtil.toJsonStr(functionCall.getArguments())); + commandRecord.setExecuteStatus(0); + + try { + Object result = executeFunctionCall(functionCall); + commandRecord.setExecuteStatus(1); + commandRecord.setExecuteErrorMessage(null); + this.updateById(commandRecord); + log.info("✅ 命令执行成功,审计记录ID: {}", commandRecord.getId()); + return result; + } catch (Exception e) { + commandRecord.setExecuteStatus(-1); + commandRecord.setExecuteErrorMessage(e.getMessage()); + this.updateById(commandRecord); + log.error("❌ 命令执行失败,审计记录ID: {}", commandRecord.getId(), e); + throw e; + } + } + + private Object executeFunctionCall(AiFunctionCallDto functionCall) { + String functionName = functionCall.getName(); + Map arguments = functionCall.getArguments(); + + log.info("🎯 执行函数: {}, 参数: {}", functionName, arguments); + + switch (functionName) { + case "updateUserNickname": + return executeUpdateUserNickname(arguments); + default: + throw new UnsupportedOperationException("不支持的函数: " + functionName); + } + } + + private Object executeUpdateUserNickname(Map arguments) { + String username = (String) arguments.get("username"); + String nickname = (String) arguments.get("nickname"); + + log.info("🔧 [Tool] 更新用户昵称: username={}, nickname={}", username, nickname); + String resultMsg = userTools.updateUserNickname(username, nickname); + + boolean success = resultMsg != null && resultMsg.contains("成功"); + if (!success) { + throw new RuntimeException(resultMsg != null ? resultMsg : "更新用户昵称失败"); + } + + return Map.of("username", username, "nickname", nickname, "message", resultMsg); + } + + @Override + public IPage getRecordPage(AiAssistantPageQuery queryParams) { + Page page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize()); + return this.baseMapper.getRecordPage(page, queryParams); + } + + @Override + public boolean deleteRecords(List ids) { + return this.removeByIds(ids); + } + + @Override + public void rollbackCommand(String logId) { + AiAssistantRecord commandRecord = this.getById(logId); + if (commandRecord == null) { + throw new RuntimeException("命令记录不存在"); + } + + if (commandRecord.getExecuteStatus() == null || commandRecord.getExecuteStatus() != 1) { + throw new RuntimeException("只能撤销成功执行的命令"); + } + + log.info("撤销命令执行: logId={}, function={}", logId, commandRecord.getFunctionName()); + throw new UnsupportedOperationException("回滚功能尚未实现"); + } +} diff --git a/src/main/java/com/youlai/boot/platform/ai/service/impl/AiCommandRecordServiceImpl.java b/src/main/java/com/youlai/boot/platform/ai/service/impl/AiCommandRecordServiceImpl.java deleted file mode 100644 index 33df604c..00000000 --- a/src/main/java/com/youlai/boot/platform/ai/service/impl/AiCommandRecordServiceImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.youlai.boot.platform.ai.service.impl; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.youlai.boot.platform.ai.mapper.AiCommandRecordMapper; -import com.youlai.boot.platform.ai.model.entity.AiCommandRecord; -import com.youlai.boot.platform.ai.model.query.AiCommandPageQuery; -import com.youlai.boot.platform.ai.model.vo.AiCommandRecordVO; -import com.youlai.boot.platform.ai.service.AiCommandRecordService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -/** - * AI 命令记录服务实现类 - * - * @author Ray.Hao - * @since 3.0.0 - */ -@Service -@Slf4j -@RequiredArgsConstructor -public class AiCommandRecordServiceImpl extends ServiceImpl - implements AiCommandRecordService { - - @Override - public IPage getRecordPage(AiCommandPageQuery queryParams) { - Page page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize()); - return this.baseMapper.getRecordPage(page, queryParams); - } - - @Override - public void rollbackCommand(String logId) { - AiCommandRecord commandRecord = this.getById(logId); - if (commandRecord == null) { - throw new RuntimeException("命令记录不存在"); - } - - if (commandRecord.getExecuteStatus() == null || commandRecord.getExecuteStatus() != 1) { - throw new RuntimeException("只能撤销成功执行的命令"); - } - - // TODO: 实现具体的回滚逻辑 - log.info("撤销命令执行: logId={}, function={}", logId, commandRecord.getFunctionName()); - throw new UnsupportedOperationException("回滚功能尚未实现"); - } -} - - diff --git a/src/main/java/com/youlai/boot/platform/ai/service/impl/AiCommandServiceImpl.java b/src/main/java/com/youlai/boot/platform/ai/service/impl/AiCommandServiceImpl.java deleted file mode 100644 index c4b76980..00000000 --- a/src/main/java/com/youlai/boot/platform/ai/service/impl/AiCommandServiceImpl.java +++ /dev/null @@ -1,324 +0,0 @@ -package com.youlai.boot.platform.ai.service.impl; - -import cn.hutool.core.lang.TypeReference; -import cn.hutool.core.util.StrUtil; -import cn.hutool.extra.servlet.JakartaServletUtil; -import cn.hutool.json.JSONUtil; -import cn.hutool.json.JSONArray; -import cn.hutool.json.JSONObject; -import com.youlai.boot.platform.ai.model.dto.AiExecuteRequestDTO; -import com.youlai.boot.platform.ai.model.dto.AiFunctionCallDTO; -import com.youlai.boot.platform.ai.model.dto.AiParseRequestDTO; -import com.youlai.boot.platform.ai.model.dto.AiParseResponseDTO; -import com.youlai.boot.platform.ai.model.entity.AiCommandRecord; -import com.youlai.boot.platform.ai.service.AiCommandRecordService; -import com.youlai.boot.platform.ai.service.AiCommandService; -import com.youlai.boot.platform.ai.tools.UserTools; -import com.youlai.boot.security.util.SecurityUtils; -import jakarta.servlet.http.HttpServletRequest; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.ai.chat.client.ChatClient; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** - * AI 命令编排服务实现 - */ -@Service -@Slf4j -@RequiredArgsConstructor -public class AiCommandServiceImpl implements AiCommandService { - - private static final String SYSTEM_PROMPT = """ - 你是一个智能的企业操作助手,需要将用户的自然语言命令解析成标准的函数调用。 - 请返回严格的 JSON 格式,包含字段: - - success: boolean - - explanation: string - - confidence: number (0-1) - - error: string - - provider: string - - model: string - - functionCalls: 数组,每个元素包含 name、description、arguments(对象) - 当无法识别命令时,success=false,并给出 error。 - """; - - private final AiCommandRecordService recordService; - private final UserTools userTools; - private final ChatClient chatClient; - - @Override - public AiParseResponseDTO parseCommand(AiParseRequestDTO request, HttpServletRequest httpRequest) { - long startTime = System.currentTimeMillis(); - String command = Optional.ofNullable(request.getCommand()).orElse("").trim(); - - if (StrUtil.isBlank(command)) { - return AiParseResponseDTO.builder() - .success(false) - .error("命令不能为空") - .functionCalls(Collections.emptyList()) - .build(); - } - - Long userId = SecurityUtils.getUserId(); - String username = SecurityUtils.getUsername(); - String ipAddress = JakartaServletUtil.getClientIP(httpRequest); - - AiCommandRecord commandRecord = new AiCommandRecord(); - commandRecord.setUserId(userId); - commandRecord.setUsername(username); - commandRecord.setOriginalCommand(command); - commandRecord.setIpAddress(ipAddress); - commandRecord.setAiProvider("spring-ai"); - commandRecord.setAiModel("auto"); - - String systemPrompt = buildSystemPrompt(); - String userPrompt = buildUserPrompt(request); - - try { - log.info("📤 发送命令至 AI 模型: {}", command); - ChatResponse chatResponse = chatClient.prompt() - .system(systemPrompt) - .user(userPrompt) - .call().chatResponse(); - - String rawContent = Optional.ofNullable(chatResponse.getResult()) - .map(result -> result.getOutput().getText()) - .orElse(""); - - ParseResult parseResult = parseAiResponse(rawContent); - - commandRecord.setAiProvider(StrUtil.emptyToDefault(parseResult.provider(), "spring-ai")); - commandRecord.setAiModel(StrUtil.emptyToDefault(parseResult.model(), "auto")); - commandRecord.setParseStatus(parseResult.success() ? 1 : 0); - commandRecord.setExplanation(parseResult.explanation()); - commandRecord.setFunctionCalls(JSONUtil.toJsonStr(parseResult.functionCalls())); - commandRecord.setConfidence(parseResult.confidence() != null ? BigDecimal.valueOf(parseResult.confidence()) : null); - commandRecord.setParseErrorMessage(parseResult.success() ? null : StrUtil.emptyToDefault(parseResult.error(), "解析失败")); - long duration = System.currentTimeMillis() - startTime; - commandRecord.setParseDurationMs((int) duration); - - recordService.save(commandRecord); - - AiParseResponseDTO response = AiParseResponseDTO.builder() - .parseLogId(commandRecord.getId()) - .success(parseResult.success()) - .functionCalls(parseResult.functionCalls()) - .explanation(parseResult.explanation()) - .confidence(parseResult.confidence()) - .error(parseResult.error()) - .rawResponse(rawContent) - .build(); - - if (!parseResult.success()) { - log.warn("❗️ AI 未能解析命令: {}", parseResult.error()); - } else { - log.info("✅ 解析成功,审计记录ID: {}", commandRecord.getId()); - } - - return response; - } catch (Exception e) { - long duration = System.currentTimeMillis() - startTime; - commandRecord.setParseStatus(0); - commandRecord.setFunctionCalls(JSONUtil.toJsonStr(Collections.emptyList())); - commandRecord.setParseErrorMessage(e.getMessage()); - commandRecord.setParseDurationMs((int) duration); - recordService.save(commandRecord); - - log.error("❌ 解析命令失败: {}", e.getMessage(), e); - throw new RuntimeException("解析命令失败: " + e.getMessage(), e); - } - } - - private String buildSystemPrompt() { - return SYSTEM_PROMPT; - } - - private String buildUserPrompt(AiParseRequestDTO request) { - JSONObject payload = JSONUtil.createObj() - .set("command", request.getCommand()) - .set("currentRoute", request.getCurrentRoute()) - .set("currentComponent", request.getCurrentComponent()) - .set("context", Optional.ofNullable(request.getContext()).orElse(Collections.emptyMap())) - .set("availableFunctions", availableFunctions()); - - return StrUtil.format(""" - 请根据以下上下文识别用户意图,并输出符合系统提示要求的 JSON: - {} - """, JSONUtil.toJsonPrettyStr(payload)); - } - - private List> availableFunctions() { - return List.of( - Map.of( - "name", "updateUserNickname", - "description", "根据用户名更新用户昵称", - "requiredParameters", List.of("username", "nickname") - ) - ); - } - - private ParseResult parseAiResponse(String rawContent) { - if (StrUtil.isBlank(rawContent)) { - throw new IllegalStateException("AI 返回内容为空"); - } - - try { - JSONObject jsonObject = JSONUtil.parseObj(rawContent); - boolean success = jsonObject.getBool("success", false); - String explanation = jsonObject.getStr("explanation"); - Double confidence = jsonObject.containsKey("confidence") ? jsonObject.getDouble("confidence") : null; - String error = jsonObject.getStr("error"); - String provider = jsonObject.getStr("provider"); - String model = jsonObject.getStr("model"); - - List functionCalls = toFunctionCallList(jsonObject.getJSONArray("functionCalls")); - - return new ParseResult(success, explanation, confidence, error, provider, model, functionCalls); - } catch (Exception ex) { - throw new IllegalStateException("无法解析 AI 响应: " + ex.getMessage(), ex); - } - } - - private List toFunctionCallList(JSONArray array) { - if (array == null || array.isEmpty()) { - return Collections.emptyList(); - } - - List result = new ArrayList<>(); - for (Object element : array) { - JSONObject functionJson = JSONUtil.parseObj(element); - Map arguments = Optional.ofNullable(functionJson.getJSONObject("arguments")) - .map(obj -> obj.toBean(new TypeReference>() { - })) - .orElse(Collections.emptyMap()); - - result.add(AiFunctionCallDTO.builder() - .name(functionJson.getStr("name")) - .description(functionJson.getStr("description")) - .arguments(arguments) - .build()); - } - return result; - } - - private record ParseResult( - boolean success, - String explanation, - Double confidence, - String error, - String provider, - String model, - List functionCalls - ) { - } - - @Override - public Object executeCommand(AiExecuteRequestDTO request, HttpServletRequest httpRequest) throws Exception { - long startTime = System.currentTimeMillis(); - - // 获取用户信息 - Long userId = SecurityUtils.getUserId(); - String username = SecurityUtils.getUsername(); - String ipAddress = JakartaServletUtil.getClientIP(httpRequest); - - AiFunctionCallDTO functionCall = request.getFunctionCall(); - - // 根据解析日志ID获取审计记录,如果不存在则创建新记录 - AiCommandRecord commandRecord ; - if (StrUtil.isNotBlank(request.getParseLogId())) { - // 更新已存在的审计记录(解析阶段已创建) - commandRecord = recordService.getById(request.getParseLogId()); - if (commandRecord == null) { - throw new IllegalStateException("未找到对应的解析记录,ID: " + request.getParseLogId()); - } - } else { - // 如果没有解析日志ID,创建新记录(兼容直接执行的情况) - commandRecord = new AiCommandRecord(); - commandRecord.setUserId(userId); - commandRecord.setUsername(username); - commandRecord.setOriginalCommand(request.getOriginalCommand()); - commandRecord.setIpAddress(ipAddress); - recordService.save(commandRecord); - } - - // 更新执行相关字段 - commandRecord.setFunctionName(functionCall.getName()); - commandRecord.setFunctionArguments(JSONUtil.toJsonStr(functionCall.getArguments())); - commandRecord.setExecuteStatus(0); // 0-待执行 - - try { - // 🎯 执行具体的函数调用 - Object result = executeFunctionCall(functionCall); - - // 更新执行成功 - commandRecord.setExecuteStatus(1); // 1-成功 - commandRecord.setExecuteErrorMessage(null); - - // 更新审计记录 - recordService.updateById(commandRecord); - - log.info("✅ 命令执行成功,审计记录ID: {}", commandRecord.getId()); - - return result; - - } catch (Exception e) { - // 更新执行失败 - commandRecord.setExecuteStatus(-1); // -1-失败 - commandRecord.setExecuteErrorMessage(e.getMessage()); - - // 更新审计记录 - recordService.updateById(commandRecord); - - log.error("❌ 命令执行失败,审计记录ID: {}", commandRecord.getId(), e); - - // 抛出异常,由 Controller 统一处理 - throw e; - } - } - - /** - * 执行具体的函数调用 - */ - private Object executeFunctionCall(AiFunctionCallDTO functionCall) { - String functionName = functionCall.getName(); - Map arguments = functionCall.getArguments(); - - log.info("🎯 执行函数: {}, 参数: {}", functionName, arguments); - - // 根据函数名称路由到不同的处理器 - switch (functionName) { - case "updateUserNickname": - return executeUpdateUserNickname(arguments); - default: - throw new UnsupportedOperationException("不支持的函数: " + functionName); - } - } - - /** - * 使用 Tool: 根据用户名更新用户昵称 - */ - private Object executeUpdateUserNickname(Map arguments) { - String username = (String) arguments.get("username"); - String nickname = (String) arguments.get("nickname"); - - log.info("🔧 [Tool] 更新用户昵称: username={}, nickname={}", username, nickname); - String resultMsg = userTools.updateUserNickname(username, nickname); - - boolean success = resultMsg != null && resultMsg.contains("成功"); - if (!success) { - throw new RuntimeException(resultMsg != null ? resultMsg : "更新用户昵称失败"); - } - - return Map.of("username", username, "nickname", nickname, "message", resultMsg); - } -} - - diff --git a/src/main/java/com/youlai/boot/platform/codegen/controller/CodegenController.java b/src/main/java/com/youlai/boot/platform/codegen/controller/CodegenController.java index 5485dced..05abcfd8 100644 --- a/src/main/java/com/youlai/boot/platform/codegen/controller/CodegenController.java +++ b/src/main/java/com/youlai/boot/platform/codegen/controller/CodegenController.java @@ -8,8 +8,8 @@ import com.youlai.boot.common.enums.LogModuleEnum; import com.youlai.boot.platform.codegen.service.CodegenService; import com.youlai.boot.platform.codegen.model.form.GenConfigForm; import com.youlai.boot.platform.codegen.model.query.TablePageQuery; -import com.youlai.boot.platform.codegen.model.vo.CodegenPreviewVO; -import com.youlai.boot.platform.codegen.model.vo.TablePageVO; +import com.youlai.boot.platform.codegen.model.vo.CodegenPreviewVo; +import com.youlai.boot.platform.codegen.model.vo.TablePageVo; import com.youlai.boot.common.annotation.Log; import com.youlai.boot.platform.codegen.service.GenTableService; import io.swagger.v3.oas.annotations.Operation; @@ -46,10 +46,10 @@ public class CodegenController { @Operation(summary = "获取数据表分页列表") @GetMapping("/table/page") @Log(value = "代码生成分页列表", module = LogModuleEnum.OTHER) - public PageResult getTablePage( + public PageResult getTablePage( TablePageQuery queryParams ) { - Page result = codegenService.getTablePage(queryParams); + Page result = codegenService.getTablePage(queryParams); return PageResult.success(result); } @@ -82,9 +82,9 @@ public class CodegenController { @Operation(summary = "获取预览生成代码") @GetMapping("/{tableName}/preview") @Log(value = "预览生成代码", module = LogModuleEnum.OTHER) - public Result> getTablePreviewData(@PathVariable String tableName, + public Result> getTablePreviewData(@PathVariable String tableName, @RequestParam(value = "pageType", required = false, defaultValue = "classic") String pageType) { - List list = codegenService.getCodegenPreviewData(tableName, pageType); + List list = codegenService.getCodegenPreviewData(tableName, pageType); return Result.success(list); } diff --git a/src/main/java/com/youlai/boot/platform/codegen/enums/JavaTypeEnum.java b/src/main/java/com/youlai/boot/platform/codegen/enums/JavaTypeEnum.java index 44ea85c6..7474abb8 100644 --- a/src/main/java/com/youlai/boot/platform/codegen/enums/JavaTypeEnum.java +++ b/src/main/java/com/youlai/boot/platform/codegen/enums/JavaTypeEnum.java @@ -27,9 +27,11 @@ public enum JavaTypeEnum { FLOAT("float", "Float", "number"), DOUBLE("double", "Double", "number"), DECIMAL("decimal", "BigDecimal", "number"), - DATE("date", "LocalDate", "Date"), - DATETIME("datetime", "LocalDateTime", "Date"), - TIMESTAMP("timestamp", "LocalDateTime", "Date"); + DATE("date", "LocalDate", "string"), + DATETIME("datetime", "LocalDateTime", "string"), + TIMESTAMP("timestamp", "LocalDateTime", "string"), + BOOLEAN("boolean", "Boolean", "boolean"), + BIT("bit", "Boolean", "boolean"); // 数据库类型 private final String dbType; @@ -61,11 +63,12 @@ public enum JavaTypeEnum { * @return 对应的Java类型 */ public static String getJavaTypeByColumnType(String columnType) { - JavaTypeEnum javaTypeEnum = typeMap.get(columnType); + String normalized = normalizeColumnType(columnType); + JavaTypeEnum javaTypeEnum = typeMap.get(normalized); if (javaTypeEnum != null) { return javaTypeEnum.getJavaType(); } - return null; + return "String"; } /** @@ -75,11 +78,31 @@ public enum JavaTypeEnum { * @return 对应的TypeScript类型 */ public static String getTsTypeByJavaType(String javaType) { + if (javaType == null) { + return "any"; + } for (JavaTypeEnum javaTypeEnum : JavaTypeEnum.values()) { if (javaTypeEnum.getJavaType().equals(javaType)) { return javaTypeEnum.getTsType(); } } - return null; + return "any"; + } + + private static String normalizeColumnType(String columnType) { + if (columnType == null) { + return ""; + } + // Handle values like: varchar(255), bigint unsigned, INT + String normalized = columnType.trim().toLowerCase(); + int parenIndex = normalized.indexOf('('); + if (parenIndex > -1) { + normalized = normalized.substring(0, parenIndex); + } + // Remove modifiers + normalized = normalized.replace("unsigned", "").replace("zerofill", "").trim(); + // Collapse repeated spaces + normalized = normalized.replaceAll("\\s+", " "); + return normalized; } } diff --git a/src/main/java/com/youlai/boot/platform/codegen/mapper/DatabaseMapper.java b/src/main/java/com/youlai/boot/platform/codegen/mapper/DatabaseMapper.java index 3d742c63..5737b495 100644 --- a/src/main/java/com/youlai/boot/platform/codegen/mapper/DatabaseMapper.java +++ b/src/main/java/com/youlai/boot/platform/codegen/mapper/DatabaseMapper.java @@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.platform.codegen.model.bo.ColumnMetaData; import com.youlai.boot.platform.codegen.model.bo.TableMetaData; import com.youlai.boot.platform.codegen.model.query.TablePageQuery; -import com.youlai.boot.platform.codegen.model.vo.TablePageVO; +import com.youlai.boot.platform.codegen.model.vo.TablePageVo; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -27,7 +27,7 @@ public interface DatabaseMapper extends BaseMapper { * @param queryParams * @return */ - Page getTablePage(Page page, TablePageQuery queryParams); + Page getTablePage(Page page, TablePageQuery queryParams); /** * 获取表字段列表 diff --git a/src/main/java/com/youlai/boot/platform/codegen/model/bo/ColumnMetaData.java b/src/main/java/com/youlai/boot/platform/codegen/model/bo/ColumnMetaData.java index 154947bc..835ab048 100644 --- a/src/main/java/com/youlai/boot/platform/codegen/model/bo/ColumnMetaData.java +++ b/src/main/java/com/youlai/boot/platform/codegen/model/bo/ColumnMetaData.java @@ -3,7 +3,7 @@ package com.youlai.boot.platform.codegen.model.bo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -@Schema(description = "数据表字段VO") +@Schema(description = "数据表字段Vo") @Data public class ColumnMetaData { diff --git a/src/main/java/com/youlai/boot/platform/codegen/model/vo/CodegenPreviewVO.java b/src/main/java/com/youlai/boot/platform/codegen/model/vo/CodegenPreviewVO.java index 749d21bf..deeb7289 100644 --- a/src/main/java/com/youlai/boot/platform/codegen/model/vo/CodegenPreviewVO.java +++ b/src/main/java/com/youlai/boot/platform/codegen/model/vo/CodegenPreviewVO.java @@ -3,9 +3,9 @@ package com.youlai.boot.platform.codegen.model.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -@Schema(description = "代码生成代码预览VO") +@Schema(description = "代码生成代码预览Vo") @Data -public class CodegenPreviewVO { +public class CodegenPreviewVo { @Schema(description = "生成文件路径") private String path; diff --git a/src/main/java/com/youlai/boot/platform/codegen/model/vo/TablePageVO.java b/src/main/java/com/youlai/boot/platform/codegen/model/vo/TablePageVO.java index 0b011181..2ac5184d 100644 --- a/src/main/java/com/youlai/boot/platform/codegen/model/vo/TablePageVO.java +++ b/src/main/java/com/youlai/boot/platform/codegen/model/vo/TablePageVO.java @@ -6,7 +6,7 @@ import lombok.Data; @Schema(description = "表视图对象") @Data -public class TablePageVO { +public class TablePageVo { @Schema(description = "表名称", example = "sys_user") private String tableName; diff --git a/src/main/java/com/youlai/boot/platform/codegen/service/CodegenService.java b/src/main/java/com/youlai/boot/platform/codegen/service/CodegenService.java index 32c020d1..7fcd0e29 100644 --- a/src/main/java/com/youlai/boot/platform/codegen/service/CodegenService.java +++ b/src/main/java/com/youlai/boot/platform/codegen/service/CodegenService.java @@ -2,8 +2,8 @@ package com.youlai.boot.platform.codegen.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.platform.codegen.model.query.TablePageQuery; -import com.youlai.boot.platform.codegen.model.vo.CodegenPreviewVO; -import com.youlai.boot.platform.codegen.model.vo.TablePageVO; +import com.youlai.boot.platform.codegen.model.vo.CodegenPreviewVo; +import com.youlai.boot.platform.codegen.model.vo.TablePageVo; import java.util.List; @@ -21,7 +21,7 @@ public interface CodegenService { * @param queryParams 查询参数 * @return */ - Page getTablePage(TablePageQuery queryParams); + Page getTablePage(TablePageQuery queryParams); /** * 获取预览生成代码 @@ -29,7 +29,7 @@ public interface CodegenService { * @param tableName 表名 * @return */ - List getCodegenPreviewData(String tableName, String pageType); + List getCodegenPreviewData(String tableName, String pageType); /** * 下载代码 diff --git a/src/main/java/com/youlai/boot/platform/codegen/service/impl/CodegenServiceImpl.java b/src/main/java/com/youlai/boot/platform/codegen/service/impl/CodegenServiceImpl.java index 8e33a2df..24bc902d 100644 --- a/src/main/java/com/youlai/boot/platform/codegen/service/impl/CodegenServiceImpl.java +++ b/src/main/java/com/youlai/boot/platform/codegen/service/impl/CodegenServiceImpl.java @@ -21,8 +21,8 @@ import com.youlai.boot.platform.codegen.mapper.DatabaseMapper; import com.youlai.boot.platform.codegen.model.entity.GenTable; import com.youlai.boot.platform.codegen.model.entity.GenTableColumn; import com.youlai.boot.platform.codegen.model.query.TablePageQuery; -import com.youlai.boot.platform.codegen.model.vo.CodegenPreviewVO; -import com.youlai.boot.platform.codegen.model.vo.TablePageVO; +import com.youlai.boot.platform.codegen.model.vo.CodegenPreviewVo; +import com.youlai.boot.platform.codegen.model.vo.TablePageVo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -36,7 +36,11 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** - * 数据库服务实现类 + * 代码生成服务实现类。 + * + *

+ * 根据代码生成配置({@link CodegenProperties})与表/字段元数据,渲染模板并提供预览与下载能力。 + *

* * @author Ray * @since 2.10.0 @@ -57,8 +61,8 @@ public class CodegenServiceImpl implements CodegenService { * @param queryParams 查询参数 * @return 分页结果 */ - public Page getTablePage(TablePageQuery queryParams) { - Page page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize()); + public Page getTablePage(TablePageQuery queryParams) { + Page page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize()); // 设置排除的表 List excludeTables = codegenProperties.getExcludeTables(); queryParams.setExcludeTables(excludeTables); @@ -73,9 +77,9 @@ public class CodegenServiceImpl implements CodegenService { * @return 预览数据 */ @Override - public List getCodegenPreviewData(String tableName, String pageType) { + public List getCodegenPreviewData(String tableName, String pageType) { - List list = new ArrayList<>(); + List list = new ArrayList<>(); GenTable genTable = genTableService.getOne(new LambdaQueryWrapper() .eq(GenTable::getTableName, tableName) @@ -96,7 +100,7 @@ public class CodegenServiceImpl implements CodegenService { // 遍历模板配置 Map templateConfigs = codegenProperties.getTemplateConfigs(); for (Map.Entry templateConfigEntry : templateConfigs.entrySet()) { - CodegenPreviewVO previewVO = new CodegenPreviewVO(); + CodegenPreviewVo previewVo = new CodegenPreviewVo(); CodegenProperties.TemplateConfig templateConfig = templateConfigEntry.getValue(); @@ -110,7 +114,7 @@ public class CodegenServiceImpl implements CodegenService { // 文件名 UserController.java String fileName = getFileName(entityName, templateName, extension); - previewVO.setFileName(fileName); + previewVo.setFileName(fileName); /* 2. 生成文件路径 */ // 包名:com.youlai.boot @@ -121,26 +125,28 @@ public class CodegenServiceImpl implements CodegenService { String subpackageName = templateConfig.getSubpackageName(); // 组合成文件路径:src/main/java/com/youlai/boot/system/controller String filePath = getFilePath(templateName, moduleName, packageName, subpackageName, entityName); - previewVO.setPath(filePath); + previewVo.setPath(filePath); /* 3. 生成文件内容 */ // 将模板文件中的变量替换为具体的值 生成代码内容 // 优先使用保存的 ui,没有则使用请求参数 String finalType = StrUtil.blankToDefault(genTable.getPageType(), pageType); String content = getCodeContent(templateConfig, genTable, fieldConfigs, finalType); - previewVO.setContent(content); + previewVo.setContent(content); - list.add(previewVO); + list.add(previewVo); } return list; } /** - * 生成文件名 + * 生成文件名。 * - * @param entityName 实体类名 UserController - * @param templateName 模板名 Entity - * @param extension 文件后缀 .java + *

部分模板需要使用约定的命名规则(例如前端 API 文件)。

+ * + * @param entityName 实体名(例如 User) + * @param templateName 模板名(例如 Entity、Controller、API) + * @param extension 文件后缀(例如 .java、.ts) * @return 文件名 */ private String getFileName(String entityName, String templateName, String extension) { @@ -149,8 +155,11 @@ public class CodegenServiceImpl implements CodegenService { } else if ("MapperXml".equals(templateName)) { return entityName + "Mapper" + extension; } else if ("API".equals(templateName)) { - // 生成 user-api.ts 命名 - return StrUtil.toSymbolCase(entityName, '-') + "-api" + extension; + // 生成 user.ts 命名 + return StrUtil.toSymbolCase(entityName, '-') + extension; + } else if ("API_TYPES".equals(templateName)) { + // 生成 types/api/user.ts + return StrUtil.toSymbolCase(entityName, '-') + extension; } else if ("VIEW".equals(templateName)) { return "index.vue"; } @@ -158,14 +167,14 @@ public class CodegenServiceImpl implements CodegenService { } /** - * 生成文件路径 + * 生成文件路径。 * - * @param templateName 模板名 Entity - * @param moduleName 模块名 system - * @param packageName 包名 com.youlai - * @param subPackageName 子包名 controller - * @param entityName 实体类名 UserController - * @return 文件路径 src/main/java/com/youlai/system/controller + * @param templateName 模板名 + * @param moduleName 模块名(例如 system) + * @param packageName 包名(例如 com.youlai.boot) + * @param subPackageName 子包名(例如 controller、service.impl、api、views) + * @param entityName 实体名(例如 User) + * @return 生成文件路径 */ private String getFilePath(String templateName, String moduleName, String packageName, String subPackageName, String entityName) { String path; @@ -183,6 +192,13 @@ public class CodegenServiceImpl implements CodegenService { + File.separator + subPackageName + File.separator + moduleName ); + } else if ("API_TYPES".equals(templateName)) { + // path = "src/types/api"; + path = (codegenProperties.getFrontendAppName() + + File.separator + "src" + + File.separator + "types" + + File.separator + "api" + ); } else if ("VIEW".equals(templateName)) { // path = "src/views/system/user"; path = (codegenProperties.getFrontendAppName() @@ -208,12 +224,13 @@ public class CodegenServiceImpl implements CodegenService { } /** - * 生成代码内容 + * 渲染模板,生成代码内容。 * * @param templateConfig 模板配置 - * @param genConfig 生成配置 + * @param genTable 表生成配置 * @param fieldConfigs 字段配置 - * @return 代码内容 + * @param pageType 前端页面类型 + * @return 渲染后的代码内容 */ private String getCodeContent(CodegenProperties.TemplateConfig templateConfig, GenTable genTable, List fieldConfigs, String pageType) { @@ -228,8 +245,12 @@ public class CodegenServiceImpl implements CodegenService { bindMap.put("entityName", entityName); bindMap.put("tableName", genTable.getTableName()); bindMap.put("author", genTable.getAuthor()); - bindMap.put("lowerFirstEntityName", StrUtil.lowerFirst(entityName)); // UserTest → userTest - bindMap.put("kebabCaseEntityName", StrUtil.toSymbolCase(entityName, '-')); // UserTest → user-test + String entityLowerCamel = StrUtil.lowerFirst(entityName); + String entityKebab = StrUtil.toSymbolCase(entityName, '-'); + String entityUpperSnake = StrUtil.toSymbolCase(entityName, '_').toUpperCase(); + bindMap.put("entityLowerCamel", entityLowerCamel); + bindMap.put("entityKebab", entityKebab); + bindMap.put("entityUpperSnake", entityUpperSnake); bindMap.put("businessName", genTable.getBusinessName()); bindMap.put("fieldConfigs", fieldConfigs); @@ -239,7 +260,11 @@ public class CodegenServiceImpl implements CodegenService { for (GenTableColumn fieldConfig : fieldConfigs) { - if ("LocalDateTime".equals(fieldConfig.getFieldType())) { + if (StrUtil.isBlank(fieldConfig.getFieldType())) { + fieldConfig.setFieldType(JavaTypeEnum.getJavaTypeByColumnType(fieldConfig.getColumnType())); + } + + if ("LocalDateTime".equals(fieldConfig.getFieldType()) || "LocalDate".equals(fieldConfig.getFieldType())) { hasLocalDateTime = true; } if ("BigDecimal".equals(fieldConfig.getFieldType())) { @@ -267,10 +292,11 @@ public class CodegenServiceImpl implements CodegenService { } /** - * 下载代码 + * 下载代码。 * - * @param tableNames 表名数组,支持多张表。 - * @return 压缩文件字节数组 + * @param tableNames 表名数组,支持多张表 + * @param ui 页面类型 + * @return zip 压缩文件字节数组 */ @Override public byte[] downloadCode(String[] tableNames, String ui) { @@ -292,15 +318,16 @@ public class CodegenServiceImpl implements CodegenService { } /** - * 根据表名生成代码并压缩到zip文件中 + * 根据表名生成代码并压缩到 zip 文件中。 * * @param tableName 表名 * @param zip 压缩文件输出流 + * @param ui 页面类型 */ private void generateAndZipCode(String tableName, ZipOutputStream zip, String ui) { - List codePreviewList = getCodegenPreviewData(tableName, ui); + List codePreviewList = getCodegenPreviewData(tableName, ui); - for (CodegenPreviewVO codePreview : codePreviewList) { + for (CodegenPreviewVo codePreview : codePreviewList) { String fileName = codePreview.getFileName(); String content = codePreview.getContent(); String path = codePreview.getPath(); diff --git a/src/main/java/com/youlai/boot/platform/codegen/service/impl/GenTableServiceImpl.java b/src/main/java/com/youlai/boot/platform/codegen/service/impl/GenTableServiceImpl.java index b483652f..c0bd7ebb 100644 --- a/src/main/java/com/youlai/boot/platform/codegen/service/impl/GenTableServiceImpl.java +++ b/src/main/java/com/youlai/boot/platform/codegen/service/impl/GenTableServiceImpl.java @@ -161,9 +161,10 @@ public class GenTableServiceImpl extends ServiceImpl i fieldConfig.setFieldName(StrUtil.toCamelCase(columnMetaData.getColumnName())); fieldConfig.setIsRequired("YES".equals(columnMetaData.getIsNullable()) ? 0 : 1); - if (fieldConfig.getColumnType().equals("date")) { + String columnType = StrUtil.blankToDefault(fieldConfig.getColumnType(), "").toLowerCase(); + if ("date".equals(columnType)) { fieldConfig.setFormType(FormTypeEnum.DATE); - } else if (fieldConfig.getColumnType().equals("datetime")) { + } else if ("datetime".equals(columnType) || "timestamp".equals(columnType)) { fieldConfig.setFormType(FormTypeEnum.DATE_TIME); } else { fieldConfig.setFormType(FormTypeEnum.INPUT); diff --git a/src/main/java/com/youlai/boot/platform/websocket/controller/WebsocketController.java b/src/main/java/com/youlai/boot/platform/websocket/controller/WebsocketController.java index 0a9f8966..01bb5187 100644 --- a/src/main/java/com/youlai/boot/platform/websocket/controller/WebsocketController.java +++ b/src/main/java/com/youlai/boot/platform/websocket/controller/WebsocketController.java @@ -1,12 +1,13 @@ package com.youlai.boot.platform.websocket.controller; -import com.youlai.boot.platform.websocket.model.ChatMessage; +import com.youlai.boot.platform.websocket.dto.TextMessage; +import com.youlai.boot.platform.websocket.publisher.WebSocketPublisher; +import com.youlai.boot.platform.websocket.topic.WebSocketTopics; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.messaging.handler.annotation.DestinationVariable; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; -import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -26,7 +27,7 @@ import java.security.Principal; @Slf4j public class WebsocketController { - private final SimpMessagingTemplate messagingTemplate; + private final WebSocketPublisher webSocketPublisher; /** @@ -58,7 +59,7 @@ public class WebsocketController { log.info("发送人:{}; 接收人:{}", sender, receiver); // 发送消息给指定用户,拼接后路径 /user/{receiver}/queue/greeting - messagingTemplate.convertAndSendToUser(receiver, "/queue/greeting", new ChatMessage(sender, message)); + webSocketPublisher.publishToUser(receiver, WebSocketTopics.USER_QUEUE_GREETING, new TextMessage(sender, message, System.currentTimeMillis())); } } diff --git a/src/main/java/com/youlai/boot/platform/websocket/dto/DictChangeEvent.java b/src/main/java/com/youlai/boot/platform/websocket/dto/DictChangeEvent.java new file mode 100644 index 00000000..4df538de --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/websocket/dto/DictChangeEvent.java @@ -0,0 +1,15 @@ +package com.youlai.boot.platform.websocket.dto; + +import lombok.Data; + +@Data +public class DictChangeEvent { + + private String dictCode; + private long timestamp; + + public DictChangeEvent(String dictCode) { + this.dictCode = dictCode; + this.timestamp = System.currentTimeMillis(); + } +} diff --git a/src/main/java/com/youlai/boot/platform/websocket/model/ChatMessage.java b/src/main/java/com/youlai/boot/platform/websocket/dto/TextMessage.java similarity index 52% rename from src/main/java/com/youlai/boot/platform/websocket/model/ChatMessage.java rename to src/main/java/com/youlai/boot/platform/websocket/dto/TextMessage.java index a94b0b11..53929687 100644 --- a/src/main/java/com/youlai/boot/platform/websocket/model/ChatMessage.java +++ b/src/main/java/com/youlai/boot/platform/websocket/dto/TextMessage.java @@ -1,25 +1,15 @@ -package com.youlai.boot.platform.websocket.model; +package com.youlai.boot.platform.websocket.dto; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -/** - * 系统消息体 - */ @Data @AllArgsConstructor @NoArgsConstructor -public class ChatMessage { +public class TextMessage { - /** - * 发送者 - */ private String sender; - - /** - * 消息内容 - */ private String content; - + private Long timestamp; } diff --git a/src/main/java/com/youlai/boot/platform/websocket/publisher/WebSocketPublisher.java b/src/main/java/com/youlai/boot/platform/websocket/publisher/WebSocketPublisher.java new file mode 100644 index 00000000..d6d04b7d --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/websocket/publisher/WebSocketPublisher.java @@ -0,0 +1,61 @@ +package com.youlai.boot.platform.websocket.publisher; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +@Slf4j +public class WebSocketPublisher { + + private SimpMessagingTemplate messagingTemplate; + private final ObjectMapper objectMapper; + + @Autowired(required = false) + public void setMessagingTemplate(SimpMessagingTemplate messagingTemplate) { + this.messagingTemplate = messagingTemplate; + } + + public void publish(String destination, Object payload) { + if (messagingTemplate == null) { + log.warn("消息模板尚未初始化,无法发送消息: destination={}", destination); + return; + } + + try { + Object body = serializeIfNeeded(payload); + messagingTemplate.convertAndSend(destination, body); + } catch (Exception e) { + log.error("发送消息失败: destination={}", destination, e); + } + } + + public void publishToUser(String username, String destination, Object payload) { + if (messagingTemplate == null) { + log.warn("消息模板尚未初始化,无法发送用户消息: username={}, destination={}", username, destination); + return; + } + + try { + Object body = serializeIfNeeded(payload); + messagingTemplate.convertAndSendToUser(username, destination, body); + } catch (Exception e) { + log.error("发送用户消息失败: username={}, destination={}", username, destination, e); + } + } + + private Object serializeIfNeeded(Object payload) throws JsonProcessingException { + if (payload == null) { + return null; + } + if (payload instanceof String || payload instanceof Number || payload instanceof Boolean) { + return payload; + } + return objectMapper.writeValueAsString(payload); + } +} diff --git a/src/main/java/com/youlai/boot/platform/websocket/service/impl/WebSocketServiceImpl.java b/src/main/java/com/youlai/boot/platform/websocket/service/impl/WebSocketServiceImpl.java index 982f34ae..595b78a2 100644 --- a/src/main/java/com/youlai/boot/platform/websocket/service/impl/WebSocketServiceImpl.java +++ b/src/main/java/com/youlai/boot/platform/websocket/service/impl/WebSocketServiceImpl.java @@ -1,22 +1,15 @@ package com.youlai.boot.platform.websocket.service.impl; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.youlai.boot.system.model.dto.DictEventDTO; +import com.youlai.boot.platform.websocket.dto.DictChangeEvent; +import com.youlai.boot.platform.websocket.dto.TextMessage; +import com.youlai.boot.platform.websocket.publisher.WebSocketPublisher; +import com.youlai.boot.platform.websocket.session.UserSessionRegistry; import com.youlai.boot.platform.websocket.service.WebSocketService; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import com.youlai.boot.platform.websocket.topic.WebSocketTopics; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; /** * WebSocket 服务实现类 @@ -33,39 +26,12 @@ import java.util.stream.Collectors; @Slf4j public class WebSocketServiceImpl implements WebSocketService { - // ==================== 在线用户管理 ==================== - - /** - * 用户在线会话映射表 - * Key: 用户名 - * Value: 该用户的所有会话 ID 集合(支持多设备登录) - */ - private final Map> userSessionsMap = new ConcurrentHashMap<>(); + private final UserSessionRegistry userSessionRegistry; + private final WebSocketPublisher webSocketPublisher; - /** - * 会话详情映射表 - * Key: 会话 ID - * Value: 会话详细信息 - */ - private final Map sessionDetailsMap = new ConcurrentHashMap<>(); - - // ==================== 依赖注入 ==================== - - private SimpMessagingTemplate messagingTemplate; - private final ObjectMapper objectMapper; - - @Autowired - public WebSocketServiceImpl(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - } - - /** - * 延迟注入 SimpMessagingTemplate,避免循环依赖 - */ - @Autowired(required = false) - public void setMessagingTemplate(SimpMessagingTemplate messagingTemplate) { - this.messagingTemplate = messagingTemplate; - log.info("✓ WebSocket 消息模板已初始化"); + public WebSocketServiceImpl(UserSessionRegistry userSessionRegistry, WebSocketPublisher webSocketPublisher) { + this.userSessionRegistry = userSessionRegistry; + this.webSocketPublisher = webSocketPublisher; } // ==================== 用户在线状态管理 ==================== @@ -88,16 +54,10 @@ public class WebSocketServiceImpl implements WebSocketService { return; } - // 添加会话到用户的会话集合中(支持多设备登录) - userSessionsMap.computeIfAbsent(username, k -> ConcurrentHashMap.newKeySet()) - .add(sessionId); + userSessionRegistry.userConnected(username, sessionId); - // 保存会话详情 - SessionInfo sessionInfo = new SessionInfo(username, sessionId, System.currentTimeMillis()); - sessionDetailsMap.put(sessionId, sessionInfo); - - int sessionCount = userSessionsMap.get(username).size(); - int totalOnlineUsers = userSessionsMap.size(); + int sessionCount = userSessionRegistry.getUserSessionCount(username); + int totalOnlineUsers = userSessionRegistry.getOnlineUserCount(); log.info("✓ 用户[{}]会话[{}]上线(该用户共 {} 个会话,系统总在线用户数:{})", username, sessionId, sessionCount, totalOnlineUsers); @@ -117,20 +77,9 @@ public class WebSocketServiceImpl implements WebSocketService { return; } - // 获取该用户的所有会话 - Set sessions = userSessionsMap.get(username); - if (sessions == null || sessions.isEmpty()) { - log.warn("用户[{}]下线:未找到会话记录", username); - return; - } + userSessionRegistry.userDisconnected(username); - // 移除所有会话详情(通常一次只断开一个会话,但这里做全量清理) - sessions.forEach(sessionDetailsMap::remove); - - // 移除用户的会话记录 - userSessionsMap.remove(username); - - int totalOnlineUsers = userSessionsMap.size(); + int totalOnlineUsers = userSessionRegistry.getOnlineUserCount(); log.info("✓ 用户[{}]下线(系统总在线用户数:{})", username, totalOnlineUsers); // 广播在线用户数变更 @@ -143,29 +92,8 @@ public class WebSocketServiceImpl implements WebSocketService { * @param sessionId 会话 ID */ public void removeSession(String sessionId) { - SessionInfo sessionInfo = sessionDetailsMap.remove(sessionId); - if (sessionInfo == null) { - return; - } - - String username = sessionInfo.getUsername(); - Set sessions = userSessionsMap.get(username); - - if (sessions != null) { - sessions.remove(sessionId); - - // 如果该用户没有其他会话了,移除用户记录 - if (sessions.isEmpty()) { - userSessionsMap.remove(username); - log.info("✓ 用户[{}]最后一个会话[{}]下线", username, sessionId); - } else { - log.info("✓ 用户[{}]会话[{}]下线(还剩 {} 个会话)", - username, sessionId, sessions.size()); - } - - // 广播在线用户数变更 - broadcastOnlineUserCount(); - } + userSessionRegistry.removeSession(sessionId); + broadcastOnlineUserCount(); } /** @@ -173,23 +101,8 @@ public class WebSocketServiceImpl implements WebSocketService { * * @return 在线用户信息列表 */ - public List getOnlineUsers() { - return userSessionsMap.entrySet().stream() - .map(entry -> { - String username = entry.getKey(); - Set sessions = entry.getValue(); - - // 获取该用户最早的登录时间 - long earliestLoginTime = sessions.stream() - .map(sessionDetailsMap::get) - .filter(info -> info != null) - .mapToLong(SessionInfo::getConnectTime) - .min() - .orElse(System.currentTimeMillis()); - - return new OnlineUserDTO(username, sessions.size(), earliestLoginTime); - }) - .collect(Collectors.toList()); + public List getOnlineUsers() { + return userSessionRegistry.getOnlineUsers(); } /** @@ -198,7 +111,7 @@ public class WebSocketServiceImpl implements WebSocketService { * @return 在线用户数(不是会话数) */ public int getOnlineUserCount() { - return userSessionsMap.size(); + return userSessionRegistry.getOnlineUserCount(); } /** @@ -207,7 +120,7 @@ public class WebSocketServiceImpl implements WebSocketService { * @return 所有在线会话的总数 */ public int getTotalSessionCount() { - return sessionDetailsMap.size(); + return userSessionRegistry.getTotalSessionCount(); } /** @@ -217,8 +130,7 @@ public class WebSocketServiceImpl implements WebSocketService { * @return 是否在线 */ public boolean isUserOnline(String username) { - Set sessions = userSessionsMap.get(username); - return sessions != null && !sessions.isEmpty(); + return userSessionRegistry.isUserOnline(username); } /** @@ -228,8 +140,7 @@ public class WebSocketServiceImpl implements WebSocketService { * @return 会话数量 */ public int getUserSessionCount(String username) { - Set sessions = userSessionsMap.get(username); - return sessions != null ? sessions.size() : 0; + return userSessionRegistry.getUserSessionCount(username); } /** @@ -246,18 +157,9 @@ public class WebSocketServiceImpl implements WebSocketService { * 广播在线用户数量变更(内部方法) */ private void broadcastOnlineUserCount() { - if (messagingTemplate == null) { - log.warn("消息模板尚未初始化,无法发送在线用户数量"); - return; - } - - try { - int count = getOnlineUserCount(); - messagingTemplate.convertAndSend("/topic/online-count", count); - log.debug("✓ 已广播在线用户数量: {}", count); - } catch (Exception e) { - log.error("广播在线用户数量失败", e); - } + int count = getOnlineUserCount(); + webSocketPublisher.publish(WebSocketTopics.TOPIC_ONLINE_COUNT, count); + log.debug("✓ 已广播在线用户数量: {}", count); } // ==================== 消息推送功能 ==================== @@ -274,30 +176,9 @@ public class WebSocketServiceImpl implements WebSocketService { return; } - DictEventDTO event = new DictEventDTO(dictCode); - sendDictChangeEvent(event); - } - - /** - * 发送字典变更事件 - * - * @param event 字典事件 - */ - private void sendDictChangeEvent(DictEventDTO event) { - if (messagingTemplate == null) { - log.warn("消息模板尚未初始化,无法发送字典更新通知"); - return; - } - - try { - String message = objectMapper.writeValueAsString(event); - messagingTemplate.convertAndSend("/topic/dict", message); - log.info("✓ 已广播字典变更通知: dictCode={}", event.getDictCode()); - } catch (JsonProcessingException e) { - log.error("字典事件序列化失败: dictCode={}", event.getDictCode(), e); - } catch (Exception e) { - log.error("发送字典变更通知失败: dictCode={}", event.getDictCode(), e); - } + DictChangeEvent event = new DictChangeEvent(dictCode); + webSocketPublisher.publish(WebSocketTopics.TOPIC_DICT, event); + log.info("✓ 已广播字典变更通知: dictCode={}", dictCode); } /** @@ -318,20 +199,8 @@ public class WebSocketServiceImpl implements WebSocketService { return; } - if (messagingTemplate == null) { - log.warn("消息模板尚未初始化,无法发送用户消息"); - return; - } - - try { - String messageJson = objectMapper.writeValueAsString(message); - messagingTemplate.convertAndSendToUser(username, "/queue/messages", messageJson); - log.info("✓ 已向用户[{}]发送通知", username); - } catch (JsonProcessingException e) { - log.error("消息序列化失败: username={}", username, e); - } catch (Exception e) { - log.error("向用户[{}]发送通知失败", username, e); - } + webSocketPublisher.publishToUser(username, WebSocketTopics.USER_QUEUE_MESSAGES, message); + log.info("✓ 已向用户[{}]发送通知", username); } /** @@ -345,71 +214,8 @@ public class WebSocketServiceImpl implements WebSocketService { return; } - if (messagingTemplate == null) { - log.warn("消息模板尚未初始化,无法发送广播消息"); - return; - } - - try { - SystemMessage systemMessage = new SystemMessage( - "系统通知", - message, - System.currentTimeMillis() - ); - String messageJson = objectMapper.writeValueAsString(systemMessage); - messagingTemplate.convertAndSend("/topic/public", messageJson); - log.info("✓ 已广播系统消息: {}", message); - } catch (JsonProcessingException e) { - log.error("系统消息序列化失败", e); - } catch (Exception e) { - log.error("广播系统消息失败", e); - } - } - - // ==================== 内部数据类 ==================== - - /** - * 会话信息 - */ - @Data - @AllArgsConstructor - @NoArgsConstructor - private static class SessionInfo { - /** 用户名 */ - private String username; - /** 会话 ID */ - private String sessionId; - /** 连接时间戳 */ - private long connectTime; - } - - /** - * 在线用户 DTO - */ - @Data - @AllArgsConstructor - @NoArgsConstructor - public static class OnlineUserDTO { - /** 用户名 */ - private String username; - /** 会话数量 */ - private int sessionCount; - /** 首次登录时间 */ - private long loginTime; - } - - /** - * 系统消息 - */ - @Data - @AllArgsConstructor - @NoArgsConstructor - public static class SystemMessage { - /** 发送者 */ - private String sender; - /** 消息内容 */ - private String content; - /** 时间戳 */ - private long timestamp; + TextMessage systemMessage = new TextMessage("系统通知", message, System.currentTimeMillis()); + webSocketPublisher.publish(WebSocketTopics.TOPIC_PUBLIC, systemMessage); + log.info("✓ 已广播系统消息: {}", message); } } diff --git a/src/main/java/com/youlai/boot/platform/websocket/session/UserSessionRegistry.java b/src/main/java/com/youlai/boot/platform/websocket/session/UserSessionRegistry.java new file mode 100644 index 00000000..34ee41da --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/websocket/session/UserSessionRegistry.java @@ -0,0 +1,103 @@ +package com.youlai.boot.platform.websocket.session; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Component +public class UserSessionRegistry { + + private final Map> userSessionsMap = new ConcurrentHashMap<>(); + private final Map sessionDetailsMap = new ConcurrentHashMap<>(); + + public void userConnected(String username, String sessionId) { + userSessionsMap.computeIfAbsent(username, k -> ConcurrentHashMap.newKeySet()).add(sessionId); + sessionDetailsMap.put(sessionId, new SessionInfo(username, sessionId, System.currentTimeMillis())); + } + + public void userDisconnected(String username) { + Set sessions = userSessionsMap.remove(username); + if (sessions == null) { + return; + } + sessions.forEach(sessionDetailsMap::remove); + } + + public void removeSession(String sessionId) { + SessionInfo sessionInfo = sessionDetailsMap.remove(sessionId); + if (sessionInfo == null) { + return; + } + + String username = sessionInfo.getUsername(); + Set sessions = userSessionsMap.get(username); + if (sessions == null) { + return; + } + + sessions.remove(sessionId); + if (sessions.isEmpty()) { + userSessionsMap.remove(username); + } + } + + public int getOnlineUserCount() { + return userSessionsMap.size(); + } + + public int getUserSessionCount(String username) { + Set sessions = userSessionsMap.get(username); + return sessions != null ? sessions.size() : 0; + } + + public int getTotalSessionCount() { + return sessionDetailsMap.size(); + } + + public boolean isUserOnline(String username) { + Set sessions = userSessionsMap.get(username); + return sessions != null && !sessions.isEmpty(); + } + + public List getOnlineUsers() { + return userSessionsMap.entrySet().stream() + .map(entry -> { + String username = entry.getKey(); + Set sessions = entry.getValue(); + long earliestLoginTime = sessions.stream() + .map(sessionDetailsMap::get) + .filter(info -> info != null) + .mapToLong(SessionInfo::getConnectTime) + .min() + .orElse(System.currentTimeMillis()); + + return new OnlineUserDto(username, sessions.size(), earliestLoginTime); + }) + .collect(Collectors.toList()); + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + private static class SessionInfo { + private String username; + private String sessionId; + private long connectTime; + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class OnlineUserDto { + private String username; + private int sessionCount; + private long loginTime; + } +} diff --git a/src/main/java/com/youlai/boot/platform/websocket/topic/WebSocketTopics.java b/src/main/java/com/youlai/boot/platform/websocket/topic/WebSocketTopics.java new file mode 100644 index 00000000..ca250f2f --- /dev/null +++ b/src/main/java/com/youlai/boot/platform/websocket/topic/WebSocketTopics.java @@ -0,0 +1,15 @@ +package com.youlai.boot.platform.websocket.topic; + +public final class WebSocketTopics { + + private WebSocketTopics() { + } + + public static final String TOPIC_DICT = "/topic/dict"; + public static final String TOPIC_ONLINE_COUNT = "/topic/online-count"; + public static final String TOPIC_PUBLIC = "/topic/public"; + + public static final String USER_QUEUE_MESSAGES = "/queue/messages"; + public static final String USER_QUEUE_MESSAGE = "/queue/message"; + public static final String USER_QUEUE_GREETING = "/queue/greeting"; +} diff --git a/src/main/java/com/youlai/boot/security/model/SysUserDetails.java b/src/main/java/com/youlai/boot/security/model/SysUserDetails.java index 8a79831c..ba59ea8c 100644 --- a/src/main/java/com/youlai/boot/security/model/SysUserDetails.java +++ b/src/main/java/com/youlai/boot/security/model/SysUserDetails.java @@ -3,6 +3,7 @@ package com.youlai.boot.security.model; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import com.youlai.boot.common.constant.SecurityConstants; +import com.youlai.boot.security.model.UserAuthInfo; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.security.core.GrantedAuthority; @@ -64,9 +65,9 @@ public class SysUserDetails implements UserDetails { /** * 构造函数:根据用户认证信息初始化用户详情对象 * - * @param user 用户认证信息对象 {@link UserAuthCredentials} + * @param user 用户认证信息对象 {@link UserAuthInfo} */ - public SysUserDetails(UserAuthCredentials user) { + public SysUserDetails(UserAuthInfo user) { this.userId = user.getUserId(); this.username = user.getUsername(); this.password = user.getPassword(); diff --git a/src/main/java/com/youlai/boot/security/model/UserAuthCredentials.java b/src/main/java/com/youlai/boot/security/model/UserAuthCredentials.java index e68d119d..2f6f7a7a 100644 --- a/src/main/java/com/youlai/boot/security/model/UserAuthCredentials.java +++ b/src/main/java/com/youlai/boot/security/model/UserAuthCredentials.java @@ -1,7 +1,6 @@ package com.youlai.boot.security.model; import lombok.Data; -import java.util.Set; /** * 用户认证凭证信息 @@ -10,48 +9,6 @@ import java.util.Set; * @since 2022/10/22 */ @Data -public class UserAuthCredentials { - - /** - * 用户ID - */ - private Long userId; - - /** - * 用户名 - */ - private String username; - - /** - * 昵称 - */ - private String nickname; - - /** - * 部门ID - */ - private Long deptId; - - /** - * 用户密码 - */ - private String password; - - /** - * 状态(1:启用;0:禁用) - */ - private Integer status; - - /** - * 用户所属的角色集合 - */ - private Set roles; - - /** - * 数据权限范围,用于控制用户可以访问的数据级别 - * - * @see com.youlai.boot.common.enums.DataScopeEnum - */ - private Integer dataScope; +public class UserAuthCredentials extends UserAuthInfo { } diff --git a/src/main/java/com/youlai/boot/security/model/UserAuthInfo.java b/src/main/java/com/youlai/boot/security/model/UserAuthInfo.java new file mode 100644 index 00000000..02cc7002 --- /dev/null +++ b/src/main/java/com/youlai/boot/security/model/UserAuthInfo.java @@ -0,0 +1,58 @@ +package com.youlai.boot.security.model; + +import lombok.Data; + +import java.util.Set; + +/** + * 用户认证信息 + *

+ * 用于登录认证过程中的用户信息承载,包含用户名、密码、状态、角色等与认证/授权相关的数据。 + *

+ * + * @author Ray.Hao + * @since 2025/12/16 + */ +@Data +public class UserAuthInfo { + + /** + * 用户ID + */ + private Long userId; + + /** + * 用户名 + */ + private String username; + + /** + * 昵称 + */ + private String nickname; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 密码(加密后) + */ + private String password; + + /** + * 状态(1:启用 其它:禁用) + */ + private Integer status; + + /** + * 角色集合 + */ + private Set roles; + + /** + * 数据权限范围 + */ + private Integer dataScope; +} diff --git a/src/main/java/com/youlai/boot/security/provider/SmsAuthenticationProvider.java b/src/main/java/com/youlai/boot/security/provider/SmsAuthenticationProvider.java index 681f31e8..57b5f79b 100644 --- a/src/main/java/com/youlai/boot/security/provider/SmsAuthenticationProvider.java +++ b/src/main/java/com/youlai/boot/security/provider/SmsAuthenticationProvider.java @@ -6,7 +6,7 @@ import com.youlai.boot.common.constant.RedisConstants; import com.youlai.boot.security.exception.CaptchaValidationException; import com.youlai.boot.security.model.SmsAuthenticationToken; import com.youlai.boot.security.model.SysUserDetails; -import com.youlai.boot.security.model.UserAuthCredentials; +import com.youlai.boot.security.model.UserAuthInfo; import com.youlai.boot.system.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; @@ -16,7 +16,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UsernameNotFoundException; - /** * 短信验证码认证 Provider * @@ -50,14 +49,14 @@ public class SmsAuthenticationProvider implements AuthenticationProvider { String inputVerifyCode = (String) authentication.getCredentials(); // 根据手机号获取用户信息 - UserAuthCredentials userAuthCredentials = userService.getAuthCredentialsByMobile(mobile); + UserAuthInfo userAuthInfo = userService.getAuthInfoByMobile(mobile); - if (userAuthCredentials == null) { + if (userAuthInfo == null) { throw new UsernameNotFoundException("用户不存在"); } // 检查用户状态是否有效 - if (ObjectUtil.notEqual(userAuthCredentials.getStatus(), 1)) { + if (ObjectUtil.notEqual(userAuthInfo.getStatus(), 1)) { throw new DisabledException("用户已被禁用"); } @@ -73,7 +72,7 @@ public class SmsAuthenticationProvider implements AuthenticationProvider { } // 构建认证后的用户详情信息 - SysUserDetails userDetails = new SysUserDetails(userAuthCredentials); + SysUserDetails userDetails = new SysUserDetails(userAuthInfo); // 创建已认证的 SmsAuthenticationToken return SmsAuthenticationToken.authenticated( diff --git a/src/main/java/com/youlai/boot/security/provider/WxMiniAppCodeAuthenticationProvider.java b/src/main/java/com/youlai/boot/security/provider/WxMiniAppCodeAuthenticationProvider.java index 3214df81..46fc17cf 100644 --- a/src/main/java/com/youlai/boot/security/provider/WxMiniAppCodeAuthenticationProvider.java +++ b/src/main/java/com/youlai/boot/security/provider/WxMiniAppCodeAuthenticationProvider.java @@ -5,7 +5,7 @@ import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.youlai.boot.security.model.SysUserDetails; -import com.youlai.boot.security.model.UserAuthCredentials; +import com.youlai.boot.security.model.UserAuthInfo; import com.youlai.boot.security.model.WxMiniAppCodeAuthenticationToken; import com.youlai.boot.system.service.UserService; import lombok.extern.slf4j.Slf4j; @@ -17,7 +17,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UsernameNotFoundException; - /** * 微信小程序Code认证Provider * @@ -30,13 +29,11 @@ public class WxMiniAppCodeAuthenticationProvider implements AuthenticationProvid private final UserService userService; private final WxMaService wxMaService; - public WxMiniAppCodeAuthenticationProvider(UserService userService, WxMaService wxMaService) { this.userService = userService; this.wxMaService = wxMaService; } - /** * 微信认证逻辑,参考 Spring Security 认证密码校验流程 * @@ -63,26 +60,26 @@ public class WxMiniAppCodeAuthenticationProvider implements AuthenticationProvid } // 根据微信 OpenID 查询用户信息 - UserAuthCredentials userAuthCredentials = userService.getAuthCredentialsByOpenId(openId); + UserAuthInfo userAuthInfo = userService.getAuthInfoByOpenId(openId); - if (userAuthCredentials == null) { + if (userAuthInfo == null) { // 用户不存在则注册 userService.registerOrBindWechatUser(openId); // 再次查询用户信息,确保用户注册成功 - userAuthCredentials = userService.getAuthCredentialsByOpenId(openId); - if (userAuthCredentials == null) { + userAuthInfo = userService.getAuthInfoByOpenId(openId); + if (userAuthInfo == null) { throw new UsernameNotFoundException("用户注册失败,请稍后重试"); } } // 检查用户状态是否有效 - if (ObjectUtil.notEqual(userAuthCredentials.getStatus(), 1)) { + if (ObjectUtil.notEqual(userAuthInfo.getStatus(), 1)) { throw new DisabledException("用户已被禁用"); } // 构建认证后的用户详情信息 - SysUserDetails userDetails = new SysUserDetails(userAuthCredentials); + SysUserDetails userDetails = new SysUserDetails(userAuthInfo); // 创建已认证的Token return WxMiniAppCodeAuthenticationToken.authenticated( diff --git a/src/main/java/com/youlai/boot/security/provider/WxMiniAppPhoneAuthenticationProvider.java b/src/main/java/com/youlai/boot/security/provider/WxMiniAppPhoneAuthenticationProvider.java index 2bcc933a..f7077764 100644 --- a/src/main/java/com/youlai/boot/security/provider/WxMiniAppPhoneAuthenticationProvider.java +++ b/src/main/java/com/youlai/boot/security/provider/WxMiniAppPhoneAuthenticationProvider.java @@ -6,7 +6,7 @@ import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.youlai.boot.security.model.SysUserDetails; -import com.youlai.boot.security.model.UserAuthCredentials; +import com.youlai.boot.security.model.UserAuthInfo; import com.youlai.boot.security.model.WxMiniAppPhoneAuthenticationToken; import com.youlai.boot.system.service.UserService; import lombok.extern.slf4j.Slf4j; @@ -78,28 +78,28 @@ public class WxMiniAppPhoneAuthenticationProvider implements AuthenticationProvi String phoneNumber = phoneNumberInfo.getPhoneNumber(); // 3. 根据手机号查询用户,不存在则创建新用户 - UserAuthCredentials userAuthCredentials = userService.getAuthCredentialsByMobile(phoneNumber); + UserAuthInfo userAuthInfo = userService.getAuthInfoByMobile(phoneNumber); - if (userAuthCredentials == null) { + if (userAuthInfo == null) { // 用户不存在,注册新用户 boolean registered = userService.registerUserByMobileAndOpenId(phoneNumber, openId); if (!registered) { throw new UsernameNotFoundException("用户注册失败"); } // 重新获取用户信息 - userAuthCredentials = userService.getAuthCredentialsByMobile(phoneNumber); + userAuthInfo = userService.getAuthInfoByMobile(phoneNumber); } else { // 用户存在,绑定openId(如果未绑定) - userService.bindUserOpenId(userAuthCredentials.getUserId(), openId); + userService.bindUserOpenId(userAuthInfo.getUserId(), openId); } // 4. 检查用户状态 - if (ObjectUtil.notEqual(userAuthCredentials.getStatus(), 1)) { + if (ObjectUtil.notEqual(userAuthInfo.getStatus(), 1)) { throw new DisabledException("用户已被禁用"); } // 5. 构建认证后的用户详情 - SysUserDetails userDetails = new SysUserDetails(userAuthCredentials); + SysUserDetails userDetails = new SysUserDetails(userAuthInfo); // 6. 创建已认证的Token return WxMiniAppPhoneAuthenticationToken.authenticated( diff --git a/src/main/java/com/youlai/boot/security/service/SysUserDetailsService.java b/src/main/java/com/youlai/boot/security/service/SysUserDetailsService.java index 213b698f..7b66208d 100644 --- a/src/main/java/com/youlai/boot/security/service/SysUserDetailsService.java +++ b/src/main/java/com/youlai/boot/security/service/SysUserDetailsService.java @@ -1,7 +1,7 @@ package com.youlai.boot.security.service; import com.youlai.boot.security.model.SysUserDetails; -import com.youlai.boot.security.model.UserAuthCredentials; +import com.youlai.boot.security.model.UserAuthInfo; import com.youlai.boot.system.service.UserService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -33,11 +33,11 @@ public class SysUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { try { - UserAuthCredentials userAuthCredentials = userService.getAuthCredentialsByUsername(username); - if (userAuthCredentials == null) { + UserAuthInfo userAuthInfo = userService.getAuthInfoByUsername(username); + if (userAuthInfo == null) { throw new UsernameNotFoundException(username); } - return new SysUserDetails(userAuthCredentials); + return new SysUserDetails(userAuthInfo); } catch (Exception e) { // 记录异常日志 log.error("认证异常:{}", e.getMessage()); diff --git a/src/main/java/com/youlai/boot/system/controller/ConfigController.java b/src/main/java/com/youlai/boot/system/controller/ConfigController.java index a7df99ed..f21bcb0d 100644 --- a/src/main/java/com/youlai/boot/system/controller/ConfigController.java +++ b/src/main/java/com/youlai/boot/system/controller/ConfigController.java @@ -7,7 +7,7 @@ import com.youlai.boot.core.web.Result; import com.youlai.boot.common.annotation.Log; import com.youlai.boot.system.model.form.ConfigForm; import com.youlai.boot.system.model.query.ConfigPageQuery; -import com.youlai.boot.system.model.vo.ConfigVO; +import com.youlai.boot.system.model.vo.ConfigVo; import com.youlai.boot.system.service.ConfigService; import io.swagger.v3.oas.annotations.Parameter; import jakarta.validation.Valid; @@ -38,8 +38,8 @@ public class ConfigController { @GetMapping("/page") @PreAuthorize("@ss.hasPerm('sys:config:list')") @Log( value = "系统配置分页列表",module = LogModuleEnum.SETTING) - public PageResult page(@ParameterObject ConfigPageQuery configPageQuery) { - IPage result = configService.page(configPageQuery); + public PageResult page(@ParameterObject ConfigPageQuery configPageQuery) { + IPage result = configService.page(configPageQuery); return PageResult.success(result); } diff --git a/src/main/java/com/youlai/boot/system/controller/DeptController.java b/src/main/java/com/youlai/boot/system/controller/DeptController.java index bb7fae27..ed5e6964 100644 --- a/src/main/java/com/youlai/boot/system/controller/DeptController.java +++ b/src/main/java/com/youlai/boot/system/controller/DeptController.java @@ -6,7 +6,7 @@ import com.youlai.boot.common.model.Option; import com.youlai.boot.core.web.Result; import com.youlai.boot.system.model.form.DeptForm; import com.youlai.boot.system.model.query.DeptQuery; -import com.youlai.boot.system.model.vo.DeptVO; +import com.youlai.boot.system.model.vo.DeptVo; import com.youlai.boot.common.annotation.Log; import com.youlai.boot.system.service.DeptService; import io.swagger.v3.oas.annotations.Parameter; @@ -36,10 +36,10 @@ public class DeptController { @Operation(summary = "部门列表") @GetMapping @Log( value = "部门列表",module = LogModuleEnum.DEPT) - public Result> getDeptList( + public Result> getDeptList( DeptQuery queryParams ) { - List list = deptService.getDeptList(queryParams); + List list = deptService.getDeptList(queryParams); return Result.success(list); } diff --git a/src/main/java/com/youlai/boot/system/controller/DictController.java b/src/main/java/com/youlai/boot/system/controller/DictController.java index f2fb1d10..67736fc9 100644 --- a/src/main/java/com/youlai/boot/system/controller/DictController.java +++ b/src/main/java/com/youlai/boot/system/controller/DictController.java @@ -8,9 +8,9 @@ import com.youlai.boot.common.enums.LogModuleEnum; import com.youlai.boot.system.model.form.DictItemForm; import com.youlai.boot.system.model.query.DictItemPageQuery; import com.youlai.boot.system.model.query.DictPageQuery; -import com.youlai.boot.system.model.vo.DictItemOptionVO; -import com.youlai.boot.system.model.vo.DictItemPageVO; -import com.youlai.boot.system.model.vo.DictPageVO; +import com.youlai.boot.system.model.vo.DictItemOptionVo; +import com.youlai.boot.system.model.vo.DictItemPageVo; +import com.youlai.boot.system.model.vo.DictPageVo; import com.youlai.boot.common.annotation.RepeatSubmit; import com.youlai.boot.system.model.form.DictForm; import com.youlai.boot.common.annotation.Log; @@ -51,10 +51,10 @@ public class DictController { @Operation(summary = "字典分页列表") @GetMapping("/page") @Log( value = "字典分页列表",module = LogModuleEnum.DICT) - public PageResult getDictPage( + public PageResult getDictPage( DictPageQuery queryParams ) { - Page result = dictService.getDictPage(queryParams); + Page result = dictService.getDictPage(queryParams); return PageResult.success(result); } @@ -128,21 +128,21 @@ public class DictController { //--------------------------------------------------- @Operation(summary = "字典项分页列表") @GetMapping("/{dictCode}/items/page") - public PageResult getDictItemPage( + public PageResult getDictItemPage( @PathVariable String dictCode, DictItemPageQuery queryParams ) { queryParams.setDictCode(dictCode); - Page result = dictItemService.getDictItemPage(queryParams); + Page result = dictItemService.getDictItemPage(queryParams); return PageResult.success(result); } @Operation(summary = "字典项列表") @GetMapping("/{dictCode}/items") - public Result> getDictItems( + public Result> getDictItems( @Parameter(description = "字典编码") @PathVariable String dictCode ) { - List list = dictItemService.getDictItems(dictCode); + List list = dictItemService.getDictItems(dictCode); return Result.success(list); } diff --git a/src/main/java/com/youlai/boot/system/controller/LogController.java b/src/main/java/com/youlai/boot/system/controller/LogController.java index 46e312c1..d494f005 100644 --- a/src/main/java/com/youlai/boot/system/controller/LogController.java +++ b/src/main/java/com/youlai/boot/system/controller/LogController.java @@ -2,20 +2,14 @@ package com.youlai.boot.system.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.core.web.PageResult; -import com.youlai.boot.core.web.Result; import com.youlai.boot.system.model.query.LogPageQuery; -import com.youlai.boot.system.model.vo.LogPageVO; -import com.youlai.boot.system.model.vo.VisitStatsVO; -import com.youlai.boot.system.model.vo.VisitTrendVO; +import com.youlai.boot.system.model.vo.LogPageVo; import com.youlai.boot.system.service.LogService; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import java.time.LocalDate; - /** * 日志控制层 * @@ -32,30 +26,11 @@ public class LogController { @Operation(summary = "日志分页列表") @GetMapping("/page") - public PageResult getLogPage( + public PageResult getLogPage( LogPageQuery queryParams ) { - Page result = logService.getLogPage(queryParams); + Page result = logService.getLogPage(queryParams); return PageResult.success(result); } - @Operation(summary = "获取访问趋势") - @GetMapping("/visit-trend") - public Result getVisitTrend( - @Parameter(description = "开始时间", example = "yyyy-MM-dd") @RequestParam String startDate, - @Parameter(description = "结束时间", example = "yyyy-MM-dd") @RequestParam String endDate - ) { - LocalDate start = LocalDate.parse(startDate); - LocalDate end = LocalDate.parse(endDate); - VisitTrendVO data = logService.getVisitTrend(start, end); - return Result.success(data); - } - - @Operation(summary = "获取访问统计") - @GetMapping("/visit-stats") - public Result getVisitStats() { - VisitStatsVO result = logService.getVisitStats(); - return Result.success(result); - } - } diff --git a/src/main/java/com/youlai/boot/system/controller/MenuController.java b/src/main/java/com/youlai/boot/system/controller/MenuController.java index e7e014a6..7fe0ffc6 100644 --- a/src/main/java/com/youlai/boot/system/controller/MenuController.java +++ b/src/main/java/com/youlai/boot/system/controller/MenuController.java @@ -7,8 +7,8 @@ import com.youlai.boot.common.model.Option; import com.youlai.boot.core.web.Result; import com.youlai.boot.system.model.form.MenuForm; import com.youlai.boot.system.model.query.MenuQuery; -import com.youlai.boot.system.model.vo.MenuVO; -import com.youlai.boot.system.model.vo.RouteVO; +import com.youlai.boot.system.model.vo.MenuVo; +import com.youlai.boot.system.model.vo.RouteVo; import com.youlai.boot.system.service.MenuService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -38,8 +38,8 @@ public class MenuController { @Operation(summary = "菜单列表") @GetMapping @Log(value = "菜单列表", module = LogModuleEnum.MENU) - public Result> getMenus(MenuQuery queryParams) { - List menuList = menuService.listMenus(queryParams); + public Result> getMenus(MenuQuery queryParams) { + List menuList = menuService.listMenus(queryParams); return Result.success(menuList); } @@ -55,8 +55,8 @@ public class MenuController { @Operation(summary = "当前用户菜单路由列表") @GetMapping("/routes") - public Result> getCurrentUserRoutes() { - List routeList = menuService.listCurrentUserRoutes(); + public Result> getCurrentUserRoutes() { + List routeList = menuService.listCurrentUserRoutes(); return Result.success(routeList); } diff --git a/src/main/java/com/youlai/boot/system/controller/NoticeController.java b/src/main/java/com/youlai/boot/system/controller/NoticeController.java index 1382aa5b..af153f36 100644 --- a/src/main/java/com/youlai/boot/system/controller/NoticeController.java +++ b/src/main/java/com/youlai/boot/system/controller/NoticeController.java @@ -5,9 +5,9 @@ import com.youlai.boot.core.web.PageResult; import com.youlai.boot.core.web.Result; import com.youlai.boot.system.model.form.NoticeForm; import com.youlai.boot.system.model.query.NoticePageQuery; -import com.youlai.boot.system.model.vo.NoticeDetailVO; -import com.youlai.boot.system.model.vo.NoticePageVO; -import com.youlai.boot.system.model.vo.UserNoticePageVO; +import com.youlai.boot.system.model.vo.NoticeDetailVo; +import com.youlai.boot.system.model.vo.NoticePageVo; +import com.youlai.boot.system.model.vo.UserNoticePageVo; import com.youlai.boot.system.service.NoticeService; import com.youlai.boot.system.service.UserNoticeService; import io.swagger.v3.oas.annotations.Operation; @@ -38,8 +38,8 @@ public class NoticeController { @Operation(summary = "通知公告分页列表") @GetMapping("/page") @PreAuthorize("@ss.hasPerm('sys:notice:list')") - public PageResult getNoticePage(NoticePageQuery queryParams) { - IPage result = noticeService.getNoticePage(queryParams); + public PageResult getNoticePage(NoticePageQuery queryParams) { + IPage result = noticeService.getNoticePage(queryParams); return PageResult.success(result); } @@ -63,11 +63,11 @@ public class NoticeController { @Operation(summary = "阅读获取通知公告详情") @GetMapping("/{id}/detail") - public Result getNoticeDetail( + public Result getNoticeDetail( @Parameter(description = "通知公告ID") @PathVariable Long id ) { - NoticeDetailVO detailVO = noticeService.getNoticeDetail(id); - return Result.success(detailVO); + NoticeDetailVo detailVo = noticeService.getNoticeDetail(id); + return Result.success(detailVo); } @Operation(summary = "修改通知公告") @@ -120,10 +120,10 @@ public class NoticeController { @Operation(summary = "获取我的通知公告分页列表") @GetMapping("/my") - public PageResult getMyNoticePage( + public PageResult getMyNoticePage( NoticePageQuery queryParams ) { - IPage result = noticeService.getMyNoticePage(queryParams); + IPage result = noticeService.getMyNoticePage(queryParams); return PageResult.success(result); } } diff --git a/src/main/java/com/youlai/boot/system/controller/RoleController.java b/src/main/java/com/youlai/boot/system/controller/RoleController.java index e178518d..4546fe66 100644 --- a/src/main/java/com/youlai/boot/system/controller/RoleController.java +++ b/src/main/java/com/youlai/boot/system/controller/RoleController.java @@ -8,7 +8,7 @@ import com.youlai.boot.core.web.PageResult; import com.youlai.boot.core.web.Result; import com.youlai.boot.system.model.form.RoleForm; import com.youlai.boot.system.model.query.RolePageQuery; -import com.youlai.boot.system.model.vo.RolePageVO; +import com.youlai.boot.system.model.vo.RolePageVo; import com.youlai.boot.common.annotation.Log; import com.youlai.boot.system.service.RoleService; import io.swagger.v3.oas.annotations.Parameter; @@ -39,10 +39,10 @@ public class RoleController { @Operation(summary = "角色分页列表") @GetMapping("/page") @Log(value = "角色分页列表", module = LogModuleEnum.ROLE) - public PageResult getRolePage( + public PageResult getRolePage( RolePageQuery queryParams ) { - Page result = roleService.getRolePage(queryParams); + Page result = roleService.getRolePage(queryParams); return PageResult.success(result); } diff --git a/src/main/java/com/youlai/boot/system/controller/StatisticsController.java b/src/main/java/com/youlai/boot/system/controller/StatisticsController.java new file mode 100644 index 00000000..66091c1f --- /dev/null +++ b/src/main/java/com/youlai/boot/system/controller/StatisticsController.java @@ -0,0 +1,47 @@ +package com.youlai.boot.system.controller; + +import com.youlai.boot.core.web.Result; +import com.youlai.boot.system.model.vo.VisitStatsVo; +import com.youlai.boot.system.model.vo.VisitTrendVo; +import com.youlai.boot.system.service.LogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; + +/** + * 统计分析控制层 + * + * @author haoxr + * @since 2024-12-15 + */ +@Tag(name = "11.统计分析") +@RestController +@RequestMapping("/api/v1/statistics") +@RequiredArgsConstructor +public class StatisticsController { + + private final LogService logService; + + @Operation(summary = "访问趋势统计") + @GetMapping("/visits/trend") + public Result getVisitTrend( + @Parameter(description = "开始时间", example = "2024-01-01") @RequestParam String startDate, + @Parameter(description = "结束时间", example = "2024-12-31") @RequestParam String endDate + ) { + LocalDate start = LocalDate.parse(startDate); + LocalDate end = LocalDate.parse(endDate); + VisitTrendVo data = logService.getVisitTrend(start, end); + return Result.success(data); + } + + @Operation(summary = "访问概览统计") + @GetMapping("/visits/overview") + public Result getVisitOverview() { + VisitStatsVo result = logService.getVisitStats(); + return Result.success(result); + } +} diff --git a/src/main/java/com/youlai/boot/system/controller/UserController.java b/src/main/java/com/youlai/boot/system/controller/UserController.java index db96814b..b2b436e2 100644 --- a/src/main/java/com/youlai/boot/system/controller/UserController.java +++ b/src/main/java/com/youlai/boot/system/controller/UserController.java @@ -14,14 +14,14 @@ import com.youlai.boot.core.web.Result; import com.youlai.boot.common.util.ExcelUtils; import com.youlai.boot.security.util.SecurityUtils; import com.youlai.boot.system.listener.UserImportListener; -import com.youlai.boot.system.model.dto.UserExportDTO; -import com.youlai.boot.system.model.dto.UserImportDTO; +import com.youlai.boot.system.model.dto.UserExportDto; +import com.youlai.boot.system.model.dto.UserImportDto; import com.youlai.boot.system.model.entity.User; import com.youlai.boot.system.model.form.*; import com.youlai.boot.system.model.query.UserPageQuery; -import com.youlai.boot.system.model.dto.CurrentUserDTO; -import com.youlai.boot.system.model.vo.UserPageVO; -import com.youlai.boot.system.model.vo.UserProfileVO; +import com.youlai.boot.system.model.dto.CurrentUserDto; +import com.youlai.boot.system.model.vo.UserPageVo; +import com.youlai.boot.system.model.vo.UserProfileVo; import com.youlai.boot.system.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -59,10 +59,10 @@ public class UserController { @Operation(summary = "用户分页列表") @GetMapping("/page") @Log(value = "用户分页列表", module = LogModuleEnum.USER) - public PageResult getUserPage( + public PageResult getUserPage( @Valid UserPageQuery queryParams ) { - IPage result = userService.getUserPage(queryParams); + IPage result = userService.getUserPage(queryParams); return PageResult.success(result); } @@ -130,9 +130,9 @@ public class UserController { @Operation(summary = "获取当前登录用户信息") @GetMapping("/me") @Log(value = "获取当前登录用户信息", module = LogModuleEnum.USER) - public Result getCurrentUser() { - CurrentUserDTO currentUserDTO = userService.getCurrentUserInfo(); - return Result.success(currentUserDTO); + public Result getCurrentUser() { + CurrentUserDto currentUserDto = userService.getCurrentUserInfo(); + return Result.success(currentUserDto); } @Operation(summary = "用户导入模板下载") @@ -160,7 +160,7 @@ public class UserController { @Log(value = "导入用户", module = LogModuleEnum.USER) public Result importUsers(MultipartFile file) throws IOException { UserImportListener listener = new UserImportListener(); - ExcelUtils.importExcel(file.getInputStream(), UserImportDTO.class, listener); + ExcelUtils.importExcel(file.getInputStream(), UserImportDto.class, listener); return Result.success(listener.getExcelResult()); } @@ -173,17 +173,17 @@ public class UserController { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8)); - List exportUserList = userService.listExportUsers(queryParams); - EasyExcel.write(response.getOutputStream(), UserExportDTO.class).sheet("用户列表") + List exportUserList = userService.listExportUsers(queryParams); + EasyExcel.write(response.getOutputStream(), UserExportDto.class).sheet("用户列表") .doWrite(exportUserList); } @Operation(summary = "获取个人中心用户信息") @GetMapping("/profile") @Log(value = "获取个人中心用户信息", module = LogModuleEnum.USER) - public Result getUserProfile() { + public Result getUserProfile() { Long userId = SecurityUtils.getUserId(); - UserProfileVO userProfile = userService.getUserProfile(userId); + UserProfileVo userProfile = userService.getUserProfile(userId); return Result.success(userProfile); } diff --git a/src/main/java/com/youlai/boot/system/converter/ConfigConverter.java b/src/main/java/com/youlai/boot/system/converter/ConfigConverter.java index dc448ecd..03e01c5d 100644 --- a/src/main/java/com/youlai/boot/system/converter/ConfigConverter.java +++ b/src/main/java/com/youlai/boot/system/converter/ConfigConverter.java @@ -2,7 +2,7 @@ package com.youlai.boot.system.converter; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.system.model.entity.Config; -import com.youlai.boot.system.model.vo.ConfigVO; +import com.youlai.boot.system.model.vo.ConfigVo; import com.youlai.boot.system.model.form.ConfigForm; import org.mapstruct.Mapper; @@ -15,7 +15,7 @@ import org.mapstruct.Mapper; @Mapper(componentModel = "spring") public interface ConfigConverter { - Page toPageVo(Page page); + Page toPageVo(Page page); Config toEntity(ConfigForm configForm); diff --git a/src/main/java/com/youlai/boot/system/converter/DeptConverter.java b/src/main/java/com/youlai/boot/system/converter/DeptConverter.java index 1ca1510e..9952f3f6 100644 --- a/src/main/java/com/youlai/boot/system/converter/DeptConverter.java +++ b/src/main/java/com/youlai/boot/system/converter/DeptConverter.java @@ -1,7 +1,7 @@ package com.youlai.boot.system.converter; import com.youlai.boot.system.model.entity.Dept; -import com.youlai.boot.system.model.vo.DeptVO; +import com.youlai.boot.system.model.vo.DeptVo; import com.youlai.boot.system.model.form.DeptForm; import org.mapstruct.Mapper; @@ -16,7 +16,7 @@ public interface DeptConverter { DeptForm toForm(Dept entity); - DeptVO toVo(Dept entity); + DeptVo toVo(Dept entity); Dept toEntity(DeptForm deptForm); diff --git a/src/main/java/com/youlai/boot/system/converter/DictConverter.java b/src/main/java/com/youlai/boot/system/converter/DictConverter.java index b15d23fc..9a844adb 100644 --- a/src/main/java/com/youlai/boot/system/converter/DictConverter.java +++ b/src/main/java/com/youlai/boot/system/converter/DictConverter.java @@ -2,7 +2,7 @@ package com.youlai.boot.system.converter; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.system.model.entity.Dict; -import com.youlai.boot.system.model.vo.DictPageVO; +import com.youlai.boot.system.model.vo.DictPageVo; import com.youlai.boot.system.model.form.DictForm; import org.mapstruct.Mapper; @@ -15,7 +15,7 @@ import org.mapstruct.Mapper; @Mapper(componentModel = "spring") public interface DictConverter { - Page toPageVo(Page page); + Page toPageVo(Page page); DictForm toForm(Dict entity); diff --git a/src/main/java/com/youlai/boot/system/converter/DictItemConverter.java b/src/main/java/com/youlai/boot/system/converter/DictItemConverter.java index 99a354b0..ed0477e2 100644 --- a/src/main/java/com/youlai/boot/system/converter/DictItemConverter.java +++ b/src/main/java/com/youlai/boot/system/converter/DictItemConverter.java @@ -3,7 +3,7 @@ package com.youlai.boot.system.converter; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.system.model.entity.DictItem; import com.youlai.boot.system.model.form.DictItemForm; -import com.youlai.boot.system.model.vo.DictPageVO; +import com.youlai.boot.system.model.vo.DictPageVo; import com.youlai.boot.common.model.Option; import org.mapstruct.Mapper; @@ -18,7 +18,7 @@ import java.util.List; @Mapper(componentModel = "spring") public interface DictItemConverter { - Page toPageVo(Page page); + Page toPageVo(Page page); DictItemForm toForm(DictItem entity); diff --git a/src/main/java/com/youlai/boot/system/converter/MenuConverter.java b/src/main/java/com/youlai/boot/system/converter/MenuConverter.java index a360ed4e..1dd49843 100644 --- a/src/main/java/com/youlai/boot/system/converter/MenuConverter.java +++ b/src/main/java/com/youlai/boot/system/converter/MenuConverter.java @@ -1,7 +1,7 @@ package com.youlai.boot.system.converter; import com.youlai.boot.system.model.entity.Menu; -import com.youlai.boot.system.model.vo.MenuVO; +import com.youlai.boot.system.model.vo.MenuVo; import com.youlai.boot.system.model.form.MenuForm; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -15,7 +15,7 @@ import org.mapstruct.Mapping; @Mapper(componentModel = "spring") public interface MenuConverter { - MenuVO toVo(Menu entity); + MenuVo toVo(Menu entity); @Mapping(target = "params", ignore = true) MenuForm toForm(Menu entity); diff --git a/src/main/java/com/youlai/boot/system/converter/NoticeConverter.java b/src/main/java/com/youlai/boot/system/converter/NoticeConverter.java index 5f3950cb..994868e0 100644 --- a/src/main/java/com/youlai/boot/system/converter/NoticeConverter.java +++ b/src/main/java/com/youlai/boot/system/converter/NoticeConverter.java @@ -1,11 +1,11 @@ package com.youlai.boot.system.converter; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.youlai.boot.system.model.bo.NoticeBO; +import com.youlai.boot.system.model.bo.NoticeBo; import com.youlai.boot.system.model.entity.Notice; import com.youlai.boot.system.model.form.NoticeForm; -import com.youlai.boot.system.model.vo.NoticeDetailVO; -import com.youlai.boot.system.model.vo.NoticePageVO; +import com.youlai.boot.system.model.vo.NoticeDetailVo; +import com.youlai.boot.system.model.vo.NoticePageVo; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; @@ -30,9 +30,9 @@ public interface NoticeConverter{ }) Notice toEntity(NoticeForm formData); - NoticePageVO toPageVo(NoticeBO bo); + NoticePageVo toPageVo(NoticeBo bo); - Page toPageVo(Page noticePage); + Page toPageVo(Page noticePage); - NoticeDetailVO toDetailVO(NoticeBO noticeBO); + NoticeDetailVo toDetailVo(NoticeBo noticeBo); } diff --git a/src/main/java/com/youlai/boot/system/converter/RoleConverter.java b/src/main/java/com/youlai/boot/system/converter/RoleConverter.java index ddcfc930..bba6dbaf 100644 --- a/src/main/java/com/youlai/boot/system/converter/RoleConverter.java +++ b/src/main/java/com/youlai/boot/system/converter/RoleConverter.java @@ -2,7 +2,7 @@ package com.youlai.boot.system.converter; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.system.model.entity.Role; -import com.youlai.boot.system.model.vo.RolePageVO; +import com.youlai.boot.system.model.vo.RolePageVo; import com.youlai.boot.common.model.Option; import com.youlai.boot.system.model.form.RoleForm; import org.mapstruct.Mapper; @@ -20,7 +20,7 @@ import java.util.List; @Mapper(componentModel = "spring") public interface RoleConverter { - Page toPageVo(Page page); + Page toPageVo(Page page); @Mappings({ @Mapping(target = "value", source = "id"), diff --git a/src/main/java/com/youlai/boot/system/converter/UserConverter.java b/src/main/java/com/youlai/boot/system/converter/UserConverter.java index 128d4773..ee9b2247 100644 --- a/src/main/java/com/youlai/boot/system/converter/UserConverter.java +++ b/src/main/java/com/youlai/boot/system/converter/UserConverter.java @@ -3,12 +3,12 @@ package com.youlai.boot.system.converter; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.common.model.Option; import com.youlai.boot.system.model.entity.User; -import com.youlai.boot.system.model.dto.CurrentUserDTO; -import com.youlai.boot.system.model.vo.UserPageVO; -import com.youlai.boot.system.model.vo.UserProfileVO; -import com.youlai.boot.system.model.bo.UserBO; +import com.youlai.boot.system.model.dto.CurrentUserDto; +import com.youlai.boot.system.model.vo.UserPageVo; +import com.youlai.boot.system.model.vo.UserProfileVo; +import com.youlai.boot.system.model.bo.UserBo; import com.youlai.boot.system.model.form.UserForm; -import com.youlai.boot.system.model.dto.UserImportDTO; +import com.youlai.boot.system.model.dto.UserImportDto; import com.youlai.boot.system.model.form.UserProfileForm; import org.mapstruct.InheritInverseConfiguration; import org.mapstruct.Mapper; @@ -26,9 +26,9 @@ import java.util.List; @Mapper(componentModel = "spring") public interface UserConverter { - UserPageVO toPageVo(UserBO bo); + UserPageVo toPageVo(UserBo bo); - Page toPageVo(Page bo); + Page toPageVo(Page bo); UserForm toForm(User entity); @@ -38,12 +38,12 @@ public interface UserConverter { @Mappings({ @Mapping(target = "userId", source = "id") }) - CurrentUserDTO toCurrentUserDto(User entity); + CurrentUserDto toCurrentUserDto(User entity); - User toEntity(UserImportDTO vo); + User toEntity(UserImportDto vo); - UserProfileVO toProfileVo(UserBO bo); + UserProfileVo toProfileVo(UserBo bo); User toEntity(UserProfileForm formData); diff --git a/src/main/java/com/youlai/boot/system/enums/NoticePublishStatusEnum.java b/src/main/java/com/youlai/boot/system/enums/NoticePublishStatusEnum.java index bedd5e53..ecda82d1 100644 --- a/src/main/java/com/youlai/boot/system/enums/NoticePublishStatusEnum.java +++ b/src/main/java/com/youlai/boot/system/enums/NoticePublishStatusEnum.java @@ -16,7 +16,7 @@ public enum NoticePublishStatusEnum implements IBaseEnum { UNPUBLISHED(0, "未发布"), PUBLISHED(1, "已发布"), - REVOKED(-1, "已撤回"); + REVoKED(-1, "已撤回"); private final Integer value; diff --git a/src/main/java/com/youlai/boot/system/handler/OnlineUserJobHandler.java b/src/main/java/com/youlai/boot/system/handler/OnlineUserJobHandler.java index 39d1b00f..3fcb7a80 100644 --- a/src/main/java/com/youlai/boot/system/handler/OnlineUserJobHandler.java +++ b/src/main/java/com/youlai/boot/system/handler/OnlineUserJobHandler.java @@ -2,9 +2,10 @@ package com.youlai.boot.system.handler; import com.youlai.boot.system.service.UserOnlineService; +import com.youlai.boot.platform.websocket.publisher.WebSocketPublisher; +import com.youlai.boot.platform.websocket.topic.WebSocketTopics; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -20,7 +21,7 @@ import org.springframework.stereotype.Component; public class OnlineUserJobHandler { private final UserOnlineService userOnlineService; - private final SimpMessagingTemplate messagingTemplate; + private final WebSocketPublisher webSocketPublisher; // 每3分钟统计一次在线用户数,减少服务器压力 @Scheduled(cron = "0 */3 * * * ?") @@ -28,7 +29,7 @@ public class OnlineUserJobHandler { log.info("定时任务:统计在线用户数"); // 推送在线用户数量到新主题 int count = userOnlineService.getOnlineUserCount(); - messagingTemplate.convertAndSend("/topic/online-count", count); + webSocketPublisher.publish(WebSocketTopics.TOPIC_ONLINE_COUNT, count); } } diff --git a/src/main/java/com/youlai/boot/system/listener/UserImportListener.java b/src/main/java/com/youlai/boot/system/listener/UserImportListener.java index a699fb54..66a23f29 100644 --- a/src/main/java/com/youlai/boot/system/listener/UserImportListener.java +++ b/src/main/java/com/youlai/boot/system/listener/UserImportListener.java @@ -14,7 +14,7 @@ import com.youlai.boot.common.enums.StatusEnum; import com.youlai.boot.core.web.ExcelResult; import com.youlai.boot.system.converter.UserConverter; import com.youlai.boot.system.enums.DictCodeEnum; -import com.youlai.boot.system.model.dto.UserImportDTO; +import com.youlai.boot.system.model.dto.UserImportDto; import com.youlai.boot.system.model.entity.*; import com.youlai.boot.system.service.*; import lombok.Getter; @@ -35,7 +35,7 @@ import java.util.stream.Collectors; * @since 2022/4/10 */ @Slf4j -public class UserImportListener extends AnalysisEventListener { +public class UserImportListener extends AnalysisEventListener { /** * Excel 导入结果 @@ -82,15 +82,15 @@ public class UserImportListener extends AnalysisEventListener { * 1. 数据校验;全字段校验 * 2. 数据持久化; * - * @param userImportDTO 一行数据,类似于 {@link AnalysisContext#readRowHolder()} + * @param userImportDto 一行数据,类似于 {@link AnalysisContext#readRowHolder()} */ @Override - public void invoke(UserImportDTO userImportDTO, AnalysisContext analysisContext) { - log.info("解析到一条用户数据:{}", JSONUtil.toJsonStr(userImportDTO)); + public void invoke(UserImportDto userImportDto, AnalysisContext analysisContext) { + log.info("解析到一条用户数据:{}", JSONUtil.toJsonStr(userImportDto)); boolean validation = true; String errorMsg = "第" + currentRow + "行数据校验失败:"; - String username = userImportDTO.getUsername(); + String username = userImportDto.getUsername(); if (StrUtil.isBlank(username)) { errorMsg += "用户名为空;"; validation = false; @@ -102,13 +102,13 @@ public class UserImportListener extends AnalysisEventListener { } } - String nickname = userImportDTO.getNickname(); + String nickname = userImportDto.getNickname(); if (StrUtil.isBlank(nickname)) { errorMsg += "用户昵称为空;"; validation = false; } - String mobile = userImportDTO.getMobile(); + String mobile = userImportDto.getMobile(); if (StrUtil.isBlank(mobile)) { errorMsg += "手机号码为空;"; validation = false; @@ -121,16 +121,16 @@ public class UserImportListener extends AnalysisEventListener { if (validation) { // 校验通过,持久化至数据库 - User entity = userConverter.toEntity(userImportDTO); + User entity = userConverter.toEntity(userImportDto); entity.setPassword(passwordEncoder.encode(SystemConstants.DEFAULT_PASSWORD)); // 默认密码 // 性别逆向翻译 根据字典标签得到字典值 - String genderLabel = userImportDTO.getGenderLabel(); + String genderLabel = userImportDto.getGenderLabel(); entity.setGender(getGenderValue(genderLabel)); // 角色解析 - String roleCodes = userImportDTO.getRoleCodes(); + String roleCodes = userImportDto.getRoleCodes(); List roleIds = getRoleIds(roleCodes); // 部门解析 - String deptCode = userImportDTO.getDeptCode(); + String deptCode = userImportDto.getDeptCode(); entity.setDeptId(getDeptId(deptCode)); boolean saveResult = userService.save(entity); diff --git a/src/main/java/com/youlai/boot/system/mapper/DictItemMapper.java b/src/main/java/com/youlai/boot/system/mapper/DictItemMapper.java index 1a0e1426..be5901cf 100644 --- a/src/main/java/com/youlai/boot/system/mapper/DictItemMapper.java +++ b/src/main/java/com/youlai/boot/system/mapper/DictItemMapper.java @@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.system.model.entity.DictItem; import com.youlai.boot.system.model.query.DictItemPageQuery; -import com.youlai.boot.system.model.vo.DictItemPageVO; +import com.youlai.boot.system.model.vo.DictItemPageVo; import org.apache.ibatis.annotations.Mapper; /** @@ -19,7 +19,7 @@ public interface DictItemMapper extends BaseMapper { /** * 字典项分页列表 */ - Page getDictItemPage(Page page, DictItemPageQuery queryParams); + Page getDictItemPage(Page page, DictItemPageQuery queryParams); } diff --git a/src/main/java/com/youlai/boot/system/mapper/DictMapper.java b/src/main/java/com/youlai/boot/system/mapper/DictMapper.java index a40fbb29..d2c76fb8 100644 --- a/src/main/java/com/youlai/boot/system/mapper/DictMapper.java +++ b/src/main/java/com/youlai/boot/system/mapper/DictMapper.java @@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.system.model.entity.Dict; import com.youlai.boot.system.model.query.DictPageQuery; -import com.youlai.boot.system.model.vo.DictPageVO; +import com.youlai.boot.system.model.vo.DictPageVo; import org.apache.ibatis.annotations.Mapper; /** @@ -23,7 +23,7 @@ public interface DictMapper extends BaseMapper { * @param queryParams 查询参数 * @return 字典分页列表 */ - Page getDictPage(Page page, DictPageQuery queryParams); + Page getDictPage(Page page, DictPageQuery queryParams); } diff --git a/src/main/java/com/youlai/boot/system/mapper/LogMapper.java b/src/main/java/com/youlai/boot/system/mapper/LogMapper.java index a52ae257..21fa6017 100644 --- a/src/main/java/com/youlai/boot/system/mapper/LogMapper.java +++ b/src/main/java/com/youlai/boot/system/mapper/LogMapper.java @@ -2,11 +2,11 @@ package com.youlai.boot.system.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.youlai.boot.system.model.bo.VisitCount; -import com.youlai.boot.system.model.bo.VisitStatsBO; +import com.youlai.boot.system.model.bo.VisitCountBo; +import com.youlai.boot.system.model.bo.VisitStatsBo; import com.youlai.boot.system.model.entity.Log; import com.youlai.boot.system.model.query.LogPageQuery; -import com.youlai.boot.system.model.vo.LogPageVO; +import com.youlai.boot.system.model.vo.LogPageVo; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -24,7 +24,7 @@ public interface LogMapper extends BaseMapper { /** * 获取日志分页列表 */ - Page getLogPage(Page page, LogPageQuery queryParams); + Page getLogPage(Page page, LogPageQuery queryParams); /** * 统计浏览数(PV) @@ -32,7 +32,7 @@ public interface LogMapper extends BaseMapper { * @param startDate 开始日期 yyyy-MM-dd * @param endDate 结束日期 yyyy-MM-dd */ - List getPvCounts(String startDate, String endDate); + List getPvCounts(String startDate, String endDate); /** * 统计IP数 @@ -40,17 +40,17 @@ public interface LogMapper extends BaseMapper { * @param startDate 开始日期 yyyy-MM-dd * @param endDate 结束日期 yyyy-MM-dd */ - List getIpCounts(String startDate, String endDate); + List getIpCounts(String startDate, String endDate); /** * 获取浏览量(PV)统计 */ - VisitStatsBO getPvStats(); + VisitStatsBo getPvStats(); /** * 获取访问IP统计 */ - VisitStatsBO getUvStats(); + VisitStatsBo getUvStats(); } diff --git a/src/main/java/com/youlai/boot/system/mapper/NoticeMapper.java b/src/main/java/com/youlai/boot/system/mapper/NoticeMapper.java index 74ad716d..f46c270d 100644 --- a/src/main/java/com/youlai/boot/system/mapper/NoticeMapper.java +++ b/src/main/java/com/youlai/boot/system/mapper/NoticeMapper.java @@ -2,10 +2,10 @@ package com.youlai.boot.system.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.youlai.boot.system.model.bo.NoticeBO; +import com.youlai.boot.system.model.bo.NoticeBo; import com.youlai.boot.system.model.entity.Notice; import com.youlai.boot.system.model.query.NoticePageQuery; -import com.youlai.boot.system.model.vo.NoticePageVO; +import com.youlai.boot.system.model.vo.NoticePageVo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -25,7 +25,7 @@ public interface NoticeMapper extends BaseMapper { * @param queryParams 查询参数 * @return 通知公告分页数据 */ - Page getNoticePage(Page page, NoticePageQuery queryParams); + Page getNoticePage(Page page, NoticePageQuery queryParams); /** * 获取阅读时通知公告详情 @@ -33,5 +33,5 @@ public interface NoticeMapper extends BaseMapper { * @param id 通知公告ID * @return 通知公告详情 */ - NoticeBO getNoticeDetail(@Param("id") Long id); + NoticeBo getNoticeDetail(@Param("id") Long id); } diff --git a/src/main/java/com/youlai/boot/system/mapper/RoleMenuMapper.java b/src/main/java/com/youlai/boot/system/mapper/RoleMenuMapper.java index 5f68f18e..111d4e53 100644 --- a/src/main/java/com/youlai/boot/system/mapper/RoleMenuMapper.java +++ b/src/main/java/com/youlai/boot/system/mapper/RoleMenuMapper.java @@ -1,7 +1,7 @@ package com.youlai.boot.system.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.youlai.boot.system.model.bo.RolePermsBO; +import com.youlai.boot.system.model.bo.RolePermsBo; import com.youlai.boot.system.model.entity.RoleMenu; import org.apache.ibatis.annotations.Mapper; @@ -28,7 +28,7 @@ public interface RoleMenuMapper extends BaseMapper { /** * 获取权限和拥有权限的角色列表 */ - List getRolePermsList(String roleCode); + List getRolePermsList(String roleCode); /** diff --git a/src/main/java/com/youlai/boot/system/mapper/UserMapper.java b/src/main/java/com/youlai/boot/system/mapper/UserMapper.java index 74af1bd5..db110363 100644 --- a/src/main/java/com/youlai/boot/system/mapper/UserMapper.java +++ b/src/main/java/com/youlai/boot/system/mapper/UserMapper.java @@ -2,13 +2,13 @@ package com.youlai.boot.system.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.youlai.boot.system.model.bo.UserBO; +import com.youlai.boot.system.model.bo.UserBo; import com.youlai.boot.system.model.entity.User; import com.youlai.boot.system.model.query.UserPageQuery; import com.youlai.boot.system.model.form.UserForm; import com.youlai.boot.common.annotation.DataPermission; -import com.youlai.boot.security.model.UserAuthCredentials; -import com.youlai.boot.system.model.dto.UserExportDTO; +import com.youlai.boot.security.model.UserAuthInfo; +import com.youlai.boot.system.model.dto.UserExportDto; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -30,7 +30,7 @@ public interface UserMapper extends BaseMapper { * @return 用户分页列表 */ @DataPermission(deptAlias = "u", userAlias = "u") - Page getUserPage(Page page, UserPageQuery queryParams); + Page getUserPage(Page page, UserPageQuery queryParams); /** * 获取用户表单详情 @@ -46,7 +46,11 @@ public interface UserMapper extends BaseMapper { * @param username 用户名 * @return 认证信息 */ - UserAuthCredentials getAuthCredentialsByUsername(String username); + UserAuthInfo getAuthInfoByUsername(String username); + + default UserAuthInfo getAuthCredentialsByUsername(String username) { + return getAuthInfoByUsername(username); + } /** * 根据微信openid获取用户认证信息 @@ -54,7 +58,11 @@ public interface UserMapper extends BaseMapper { * @param openid 微信openid * @return 认证信息 */ - UserAuthCredentials getAuthCredentialsByOpenId(String openid); + UserAuthInfo getAuthInfoByOpenId(String openid); + + default UserAuthInfo getAuthCredentialsByOpenId(String openid) { + return getAuthInfoByOpenId(openid); + } /** * 根据手机号获取用户认证信息 @@ -62,7 +70,11 @@ public interface UserMapper extends BaseMapper { * @param mobile 手机号 * @return 认证信息 */ - UserAuthCredentials getAuthCredentialsByMobile(String mobile); + UserAuthInfo getAuthInfoByMobile(String mobile); + + default UserAuthInfo getAuthCredentialsByMobile(String mobile) { + return getAuthInfoByMobile(mobile); + } /** * 获取导出用户列表 @@ -71,7 +83,7 @@ public interface UserMapper extends BaseMapper { * @return 导出用户列表 */ @DataPermission(deptAlias = "u", userAlias = "u") - List listExportUsers(UserPageQuery queryParams); + List listExportUsers(UserPageQuery queryParams); /** * 获取用户个人中心信息 @@ -79,6 +91,6 @@ public interface UserMapper extends BaseMapper { * @param userId 用户ID * @return 用户个人中心信息 */ - UserBO getUserProfile(Long userId); + UserBo getUserProfile(Long userId); } diff --git a/src/main/java/com/youlai/boot/system/mapper/UserNoticeMapper.java b/src/main/java/com/youlai/boot/system/mapper/UserNoticeMapper.java index e874cd3e..412ef549 100644 --- a/src/main/java/com/youlai/boot/system/mapper/UserNoticeMapper.java +++ b/src/main/java/com/youlai/boot/system/mapper/UserNoticeMapper.java @@ -5,8 +5,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.system.model.entity.UserNotice; import com.youlai.boot.system.model.query.NoticePageQuery; -import com.youlai.boot.system.model.vo.NoticePageVO; -import com.youlai.boot.system.model.vo.UserNoticePageVO; +import com.youlai.boot.system.model.vo.NoticePageVo; +import com.youlai.boot.system.model.vo.UserNoticePageVo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -26,5 +26,5 @@ public interface UserNoticeMapper extends BaseMapper { * @param queryParams 查询参数 * @return 通知公告分页列表 */ - IPage getMyNoticePage(Page page, @Param("queryParams") NoticePageQuery queryParams); + IPage getMyNoticePage(Page page, @Param("queryParams") NoticePageQuery queryParams); } diff --git a/src/main/java/com/youlai/boot/system/mapper/UserRoleMapper.java b/src/main/java/com/youlai/boot/system/mapper/UserRoleMapper.java index 196c2a52..38b24507 100644 --- a/src/main/java/com/youlai/boot/system/mapper/UserRoleMapper.java +++ b/src/main/java/com/youlai/boot/system/mapper/UserRoleMapper.java @@ -18,5 +18,5 @@ public interface UserRoleMapper extends BaseMapper { * * @param roleId 角色ID */ - int countUsersForRole(Long roleId); + int countUsersByRoleId(Long roleId); } diff --git a/src/main/java/com/youlai/boot/system/model/bo/NoticeBO.java b/src/main/java/com/youlai/boot/system/model/bo/NoticeBO.java index 72175c47..23b85991 100644 --- a/src/main/java/com/youlai/boot/system/model/bo/NoticeBO.java +++ b/src/main/java/com/youlai/boot/system/model/bo/NoticeBO.java @@ -11,7 +11,7 @@ import java.time.LocalDateTime; * @since 2024-09-01 10:31 */ @Data -public class NoticeBO { +public class NoticeBo { /** * 通知ID diff --git a/src/main/java/com/youlai/boot/system/model/bo/RolePermsBO.java b/src/main/java/com/youlai/boot/system/model/bo/RolePermsBO.java index 198e8180..ff3484c8 100644 --- a/src/main/java/com/youlai/boot/system/model/bo/RolePermsBO.java +++ b/src/main/java/com/youlai/boot/system/model/bo/RolePermsBO.java @@ -11,7 +11,7 @@ import java.util.Set; * @since 2023/11/29 */ @Data -public class RolePermsBO { +public class RolePermsBo { /** * 角色编码 diff --git a/src/main/java/com/youlai/boot/system/model/bo/UserBO.java b/src/main/java/com/youlai/boot/system/model/bo/UserBO.java index 7fbc61ae..b6d901df 100644 --- a/src/main/java/com/youlai/boot/system/model/bo/UserBO.java +++ b/src/main/java/com/youlai/boot/system/model/bo/UserBO.java @@ -7,11 +7,11 @@ import java.time.LocalDateTime; /** * 用户持久化对象 * - * @author haoxr + * @author Ray.Hao * @since 2022/6/10 */ @Data -public class UserBO { +public class UserBo { /** * 用户ID diff --git a/src/main/java/com/youlai/boot/system/model/bo/VisitCount.java b/src/main/java/com/youlai/boot/system/model/bo/VisitCountBo.java similarity index 90% rename from src/main/java/com/youlai/boot/system/model/bo/VisitCount.java rename to src/main/java/com/youlai/boot/system/model/bo/VisitCountBo.java index a5e1b81c..ce6e7c34 100644 --- a/src/main/java/com/youlai/boot/system/model/bo/VisitCount.java +++ b/src/main/java/com/youlai/boot/system/model/bo/VisitCountBo.java @@ -9,7 +9,7 @@ import lombok.Data; * @since 2.10.0 */ @Data -public class VisitCount { +public class VisitCountBo { /** * 日期 yyyy-MM-dd diff --git a/src/main/java/com/youlai/boot/system/model/bo/VisitStatsBO.java b/src/main/java/com/youlai/boot/system/model/bo/VisitStatsBO.java index 2fba9179..5417f14e 100644 --- a/src/main/java/com/youlai/boot/system/model/bo/VisitStatsBO.java +++ b/src/main/java/com/youlai/boot/system/model/bo/VisitStatsBO.java @@ -14,7 +14,7 @@ import java.math.BigDecimal; */ @Getter @Setter -public class VisitStatsBO { +public class VisitStatsBo { @Schema(description = "今日访问量 (PV)") private Integer todayCount; diff --git a/src/main/java/com/youlai/boot/system/model/dto/CurrentUserDTO.java b/src/main/java/com/youlai/boot/system/model/dto/CurrentUserDTO.java index e29bd22b..e0044d25 100644 --- a/src/main/java/com/youlai/boot/system/model/dto/CurrentUserDTO.java +++ b/src/main/java/com/youlai/boot/system/model/dto/CurrentUserDTO.java @@ -13,7 +13,7 @@ import java.util.Set; */ @Schema(description ="当前登录用户对象") @Data -public class CurrentUserDTO { +public class CurrentUserDto { @Schema(description="用户ID") private Long userId; diff --git a/src/main/java/com/youlai/boot/system/model/dto/DictEventDTO.java b/src/main/java/com/youlai/boot/system/model/dto/DictEventDTO.java deleted file mode 100644 index b3cae343..00000000 --- a/src/main/java/com/youlai/boot/system/model/dto/DictEventDTO.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.youlai.boot.system.model.dto; - -import lombok.Data; - -/** - * 字典更新事件消息 - * - * @author Ray.Hao - * @since 3.0.0 - */ -@Data -public class DictEventDTO { - /** - * 字典编码 - */ - private String dictCode; - - /** - * 时间戳 - */ - private long timestamp; - - public DictEventDTO(String dictCode) { - this.dictCode = dictCode; - this.timestamp = System.currentTimeMillis(); - } -} - diff --git a/src/main/java/com/youlai/boot/system/model/dto/NoticeDTO.java b/src/main/java/com/youlai/boot/system/model/dto/NoticeDTO.java index fd9ac242..8c6fbe18 100644 --- a/src/main/java/com/youlai/boot/system/model/dto/NoticeDTO.java +++ b/src/main/java/com/youlai/boot/system/model/dto/NoticeDTO.java @@ -13,7 +13,7 @@ import java.time.LocalDateTime; * @since 2024-9-2 14:32:58 */ @Data -public class NoticeDTO { +public class NoticeDto { @Schema(description = "通知ID") private Long id; @@ -28,5 +28,4 @@ public class NoticeDTO { @JsonFormat(pattern = "yyyy-MM-dd HH:mm") private LocalDateTime publishTime; - } diff --git a/src/main/java/com/youlai/boot/system/model/dto/UserExportDTO.java b/src/main/java/com/youlai/boot/system/model/dto/UserExportDTO.java index 7c472c61..975ace9b 100644 --- a/src/main/java/com/youlai/boot/system/model/dto/UserExportDTO.java +++ b/src/main/java/com/youlai/boot/system/model/dto/UserExportDTO.java @@ -16,7 +16,7 @@ import java.time.LocalDateTime; @Data @ColumnWidth(20) -public class UserExportDTO { +public class UserExportDto { @ExcelProperty(value = "用户名") private String username; diff --git a/src/main/java/com/youlai/boot/system/model/dto/UserImportDTO.java b/src/main/java/com/youlai/boot/system/model/dto/UserImportDTO.java index 01357c7a..876b5798 100644 --- a/src/main/java/com/youlai/boot/system/model/dto/UserImportDTO.java +++ b/src/main/java/com/youlai/boot/system/model/dto/UserImportDTO.java @@ -10,7 +10,7 @@ import lombok.Data; * @since 2022/4/10 */ @Data -public class UserImportDTO { +public class UserImportDto { @ExcelProperty(value = "用户名") private String username; diff --git a/src/main/java/com/youlai/boot/system/model/dto/UserSessionDTO.java b/src/main/java/com/youlai/boot/system/model/dto/UserSessionDTO.java index 80cb44c1..f1903acb 100644 --- a/src/main/java/com/youlai/boot/system/model/dto/UserSessionDTO.java +++ b/src/main/java/com/youlai/boot/system/model/dto/UserSessionDTO.java @@ -6,13 +6,13 @@ import java.util.HashSet; import java.util.Set; /** - * 用户会话DTO + * 用户会话Dto * * @author Ray.Hao * @since 3.0.0 */ @Data -public class UserSessionDTO { +public class UserSessionDto { /** * 用户名 @@ -29,7 +29,7 @@ public class UserSessionDTO { */ private long lastActiveTime; - public UserSessionDTO(String username) { + public UserSessionDto(String username) { this.username = username; this.sessionIds = new HashSet<>(); this.lastActiveTime = System.currentTimeMillis(); diff --git a/src/main/java/com/youlai/boot/system/model/vo/ConfigVO.java b/src/main/java/com/youlai/boot/system/model/vo/ConfigVO.java index 12bf2f47..2343d745 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/ConfigVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/ConfigVO.java @@ -18,8 +18,8 @@ import java.io.Serializable; @Data @Builder @EqualsAndHashCode(callSuper = false) -@Schema(description = "系统配置VO") -public class ConfigVO { +@Schema(description = "系统配置Vo") +public class ConfigVo { @Schema(description = "主键") private Long id; diff --git a/src/main/java/com/youlai/boot/system/model/vo/DeptVO.java b/src/main/java/com/youlai/boot/system/model/vo/DeptVO.java index d2249f4d..9b3d88c9 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/DeptVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/DeptVO.java @@ -9,7 +9,7 @@ import java.util.List; @Schema(description = "部门视图对象") @Data -public class DeptVO { +public class DeptVo { @Schema(description = "部门ID") private Long id; @@ -30,7 +30,7 @@ public class DeptVO { private Integer status; @Schema(description = "子部门") - private List children; + private List children; @Schema(description = "创建时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm") diff --git a/src/main/java/com/youlai/boot/system/model/vo/DictItemOptionVO.java b/src/main/java/com/youlai/boot/system/model/vo/DictItemOptionVO.java index 8470f1b7..dc69f029 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/DictItemOptionVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/DictItemOptionVO.java @@ -13,7 +13,7 @@ import lombok.Setter; @Schema(description = "字典项键值对象") @Getter @Setter -public class DictItemOptionVO { +public class DictItemOptionVo { @Schema(description = "字典项值") private String value; diff --git a/src/main/java/com/youlai/boot/system/model/vo/DictItemPageVO.java b/src/main/java/com/youlai/boot/system/model/vo/DictItemPageVO.java index 019da827..01529d44 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/DictItemPageVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/DictItemPageVO.java @@ -14,7 +14,7 @@ import lombok.Setter; @Schema(description = "字典项分页对象") @Getter @Setter -public class DictItemPageVO { +public class DictItemPageVo { @Schema(description = "字典项ID") private Long id; diff --git a/src/main/java/com/youlai/boot/system/model/vo/DictPageVO.java b/src/main/java/com/youlai/boot/system/model/vo/DictPageVO.java index 6df5d53c..a4ecb826 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/DictPageVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/DictPageVO.java @@ -9,7 +9,7 @@ import java.util.List; /** - * 字典分页VO + * 字典分页Vo * * @author Ray * @since 0.0.1 @@ -17,7 +17,7 @@ import java.util.List; @Schema(description = "字典分页对象") @Getter @Setter -public class DictPageVO { +public class DictPageVo { @Schema(description = "字典ID") private Long id; diff --git a/src/main/java/com/youlai/boot/system/model/vo/LogPageVO.java b/src/main/java/com/youlai/boot/system/model/vo/LogPageVO.java index 253c34c0..95944e89 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/LogPageVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/LogPageVO.java @@ -9,14 +9,14 @@ import java.io.Serializable; import java.time.LocalDateTime; /** - * 系统日志分页VO + * 系统日志分页Vo * * @author Ray * @since 2.10.0 */ @Data -@Schema(description = "系统日志分页VO") -public class LogPageVO implements Serializable { +@Schema(description = "系统日志分页Vo") +public class LogPageVo implements Serializable { @Schema(description = "主键") private Long id; diff --git a/src/main/java/com/youlai/boot/system/model/vo/MenuVO.java b/src/main/java/com/youlai/boot/system/model/vo/MenuVO.java index 18a3ca52..ee9cddfe 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/MenuVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/MenuVO.java @@ -8,7 +8,7 @@ import java.util.List; @Schema(description ="菜单视图对象") @Data -public class MenuVO { +public class MenuVo { @Schema(description = "菜单ID") private Long id; @@ -48,6 +48,6 @@ public class MenuVO { @Schema(description = "子菜单") @JsonInclude(value = JsonInclude.Include.NON_NULL) - private List children; + private List children; } diff --git a/src/main/java/com/youlai/boot/system/model/vo/NoticeDetailVO.java b/src/main/java/com/youlai/boot/system/model/vo/NoticeDetailVO.java index c8a7a22b..30d2f852 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/NoticeDetailVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/NoticeDetailVO.java @@ -7,13 +7,13 @@ import lombok.Data; import java.time.LocalDateTime; /** - * 阅读通知公告VO + * 阅读通知公告Vo * * @author Theo * @since 2024-9-8 01:25:06 */ @Data -public class NoticeDetailVO { +public class NoticeDetailVo { @Schema(description = "通知ID") private Long id; diff --git a/src/main/java/com/youlai/boot/system/model/vo/NoticePageVO.java b/src/main/java/com/youlai/boot/system/model/vo/NoticePageVO.java index 25de2efe..08224a46 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/NoticePageVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/NoticePageVO.java @@ -18,7 +18,7 @@ import java.time.LocalDateTime; @Getter @Setter @Schema(description = "通知公告视图对象") -public class NoticePageVO implements Serializable { +public class NoticePageVo implements Serializable { @Serial private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/youlai/boot/system/model/vo/RolePageVO.java b/src/main/java/com/youlai/boot/system/model/vo/RolePageVO.java index 86a1ce21..6c5e547a 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/RolePageVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/RolePageVO.java @@ -8,7 +8,7 @@ import java.time.LocalDateTime; @Schema(description ="角色分页对象") @Data -public class RolePageVO { +public class RolePageVo { @Schema(description="角色ID") private Long id; diff --git a/src/main/java/com/youlai/boot/system/model/vo/RouteVO.java b/src/main/java/com/youlai/boot/system/model/vo/RouteVO.java index 8c786f02..88c73fcc 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/RouteVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/RouteVO.java @@ -16,7 +16,7 @@ import java.util.Map; @Schema(description = "路由对象") @Data @JsonInclude(JsonInclude.Include.NON_EMPTY) -public class RouteVO { +public class RouteVo { @Schema(description = "路由路径", example = "user") private String path; @@ -59,5 +59,5 @@ public class RouteVO { } @Schema(description = "子路由列表") - private List children; + private List children; } diff --git a/src/main/java/com/youlai/boot/system/model/vo/UserNoticePageVO.java b/src/main/java/com/youlai/boot/system/model/vo/UserNoticePageVO.java index a21643fb..bb17ba2b 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/UserNoticePageVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/UserNoticePageVO.java @@ -7,14 +7,14 @@ import lombok.Data; import java.time.LocalDateTime; /** - * 用户公告VO + * 用户公告Vo * * @author Theo * @since 2024-08-28 16:56 */ @Data -@Schema(description = "用户公告VO") -public class UserNoticePageVO { +@Schema(description = "用户公告Vo") +public class UserNoticePageVo { @Schema(description = "通知ID") private Long id; diff --git a/src/main/java/com/youlai/boot/system/model/vo/UserPageVO.java b/src/main/java/com/youlai/boot/system/model/vo/UserPageVO.java index 0baa4c5b..e45c11f2 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/UserPageVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/UserPageVO.java @@ -14,7 +14,7 @@ import java.time.LocalDateTime; */ @Schema(description ="用户分页对象") @Data -public class UserPageVO { +public class UserPageVo { @Schema(description="用户ID") private Long id; diff --git a/src/main/java/com/youlai/boot/system/model/vo/UserProfileVO.java b/src/main/java/com/youlai/boot/system/model/vo/UserProfileVO.java index 614f917b..5bbcfa15 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/UserProfileVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/UserProfileVO.java @@ -14,7 +14,7 @@ import java.util.Date; */ @Schema(description = "个人中心用户信息") @Data -public class UserProfileVO { +public class UserProfileVo { @Schema(description = "用户ID") private Long id; diff --git a/src/main/java/com/youlai/boot/system/model/vo/VisitStatsVO.java b/src/main/java/com/youlai/boot/system/model/vo/VisitStatsVO.java index 3ffd5dab..7c71a40b 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/VisitStatsVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/VisitStatsVO.java @@ -15,7 +15,7 @@ import java.math.BigDecimal; @Schema(description = "访问量统计视图对象") @Getter @Setter -public class VisitStatsVO { +public class VisitStatsVo { @Schema(description = "今日独立访客数 (UV)") private Integer todayUvCount; diff --git a/src/main/java/com/youlai/boot/system/model/vo/VisitTrendVO.java b/src/main/java/com/youlai/boot/system/model/vo/VisitTrendVO.java index 42e8a2cb..25e5b784 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/VisitTrendVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/VisitTrendVO.java @@ -8,15 +8,15 @@ import lombok.Setter; import java.util.List; /** - * 访问趋势VO + * 访问趋势Vo * * @author Ray.Hao * @since 2.3.0 */ -@Schema(description = "访问趋势VO") +@Schema(description = "访问趋势Vo") @Getter @Setter -public class VisitTrendVO { +public class VisitTrendVo { @Schema(description = "日期列表") private List dates; diff --git a/src/main/java/com/youlai/boot/system/service/ConfigService.java b/src/main/java/com/youlai/boot/system/service/ConfigService.java index 988db94d..68d24eb5 100644 --- a/src/main/java/com/youlai/boot/system/service/ConfigService.java +++ b/src/main/java/com/youlai/boot/system/service/ConfigService.java @@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.youlai.boot.system.model.entity.Config; import com.youlai.boot.system.model.form.ConfigForm; import com.youlai.boot.system.model.query.ConfigPageQuery; -import com.youlai.boot.system.model.vo.ConfigVO; +import com.youlai.boot.system.model.vo.ConfigVo; /** * 系统配置Service接口 @@ -20,7 +20,7 @@ public interface ConfigService extends IService { * @param sysConfigPageQuery 查询参数 * @return 系统配置分页列表 */ - IPage page(ConfigPageQuery sysConfigPageQuery); + IPage page(ConfigPageQuery sysConfigPageQuery); /** * 保存系统配置 diff --git a/src/main/java/com/youlai/boot/system/service/DeptService.java b/src/main/java/com/youlai/boot/system/service/DeptService.java index 850a948e..f724fb77 100644 --- a/src/main/java/com/youlai/boot/system/service/DeptService.java +++ b/src/main/java/com/youlai/boot/system/service/DeptService.java @@ -5,7 +5,7 @@ import com.youlai.boot.system.model.entity.Dept; import com.youlai.boot.common.model.Option; import com.youlai.boot.system.model.form.DeptForm; import com.youlai.boot.system.model.query.DeptQuery; -import com.youlai.boot.system.model.vo.DeptVO; +import com.youlai.boot.system.model.vo.DeptVo; import java.util.List; @@ -21,7 +21,7 @@ public interface DeptService extends IService { * * @return 部门列表 */ - List getDeptList(DeptQuery queryParams); + List getDeptList(DeptQuery queryParams); /** * 部门树形下拉选项 diff --git a/src/main/java/com/youlai/boot/system/service/DictItemService.java b/src/main/java/com/youlai/boot/system/service/DictItemService.java index 54d4d197..7439b980 100644 --- a/src/main/java/com/youlai/boot/system/service/DictItemService.java +++ b/src/main/java/com/youlai/boot/system/service/DictItemService.java @@ -5,8 +5,8 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.youlai.boot.system.model.entity.DictItem; import com.youlai.boot.system.model.form.DictItemForm; import com.youlai.boot.system.model.query.DictItemPageQuery; -import com.youlai.boot.system.model.vo.DictItemOptionVO; -import com.youlai.boot.system.model.vo.DictItemPageVO; +import com.youlai.boot.system.model.vo.DictItemOptionVo; +import com.youlai.boot.system.model.vo.DictItemPageVo; import java.util.List; @@ -24,7 +24,7 @@ public interface DictItemService extends IService { * @param queryParams 查询参数 * @return 字典项分页列表 */ - Page getDictItemPage(DictItemPageQuery queryParams); + Page getDictItemPage(DictItemPageQuery queryParams); /** * 获取字典项列表 @@ -32,7 +32,7 @@ public interface DictItemService extends IService { * @param dictCode 字典编码 * @return 字典项列表 */ - List getDictItems(String dictCode); + List getDictItems(String dictCode); /** * 获取字典项表单 diff --git a/src/main/java/com/youlai/boot/system/service/DictService.java b/src/main/java/com/youlai/boot/system/service/DictService.java index 5ab06ab7..a22c7f91 100644 --- a/src/main/java/com/youlai/boot/system/service/DictService.java +++ b/src/main/java/com/youlai/boot/system/service/DictService.java @@ -6,8 +6,8 @@ import com.youlai.boot.common.model.Option; import com.youlai.boot.system.model.entity.Dict; import com.youlai.boot.system.model.form.DictForm; import com.youlai.boot.system.model.query.DictPageQuery; -import com.youlai.boot.system.model.vo.DictItemOptionVO; -import com.youlai.boot.system.model.vo.DictPageVO; +import com.youlai.boot.system.model.vo.DictItemOptionVo; +import com.youlai.boot.system.model.vo.DictPageVo; import java.util.List; @@ -25,7 +25,7 @@ public interface DictService extends IService { * @param queryParams 分页查询对象 * @return 字典分页列表 */ - Page getDictPage(DictPageQuery queryParams); + Page getDictPage(DictPageQuery queryParams); /** * 获取字典列表 diff --git a/src/main/java/com/youlai/boot/system/service/LogService.java b/src/main/java/com/youlai/boot/system/service/LogService.java index 8a621e66..58e13718 100644 --- a/src/main/java/com/youlai/boot/system/service/LogService.java +++ b/src/main/java/com/youlai/boot/system/service/LogService.java @@ -4,9 +4,9 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.boot.system.model.entity.Log; import com.baomidou.mybatisplus.extension.service.IService; import com.youlai.boot.system.model.query.LogPageQuery; -import com.youlai.boot.system.model.vo.LogPageVO; -import com.youlai.boot.system.model.vo.VisitStatsVO; -import com.youlai.boot.system.model.vo.VisitTrendVO; +import com.youlai.boot.system.model.vo.LogPageVo; +import com.youlai.boot.system.model.vo.VisitStatsVo; +import com.youlai.boot.system.model.vo.VisitTrendVo; import java.time.LocalDate; import java.util.List; @@ -22,7 +22,7 @@ public interface LogService extends IService { /** * 获取日志分页列表 */ - Page getLogPage(LogPageQuery queryParams); + Page getLogPage(LogPageQuery queryParams); /** @@ -31,11 +31,11 @@ public interface LogService extends IService { * @param startDate 开始时间 * @param endDate 结束时间 */ - VisitTrendVO getVisitTrend(LocalDate startDate, LocalDate endDate); + VisitTrendVo getVisitTrend(LocalDate startDate, LocalDate endDate); /** * 获取访问统计 */ - VisitStatsVO getVisitStats(); + VisitStatsVo getVisitStats(); } diff --git a/src/main/java/com/youlai/boot/system/service/MenuService.java b/src/main/java/com/youlai/boot/system/service/MenuService.java index 389ec2bb..09457d22 100644 --- a/src/main/java/com/youlai/boot/system/service/MenuService.java +++ b/src/main/java/com/youlai/boot/system/service/MenuService.java @@ -6,8 +6,8 @@ import com.youlai.boot.system.model.form.MenuForm; import com.youlai.boot.common.model.Option; import com.youlai.boot.system.model.entity.Menu; import com.youlai.boot.system.model.query.MenuQuery; -import com.youlai.boot.system.model.vo.MenuVO; -import com.youlai.boot.system.model.vo.RouteVO; +import com.youlai.boot.system.model.vo.MenuVo; +import com.youlai.boot.system.model.vo.RouteVo; import java.util.List; import java.util.Set; @@ -23,7 +23,7 @@ public interface MenuService extends IService { /** * 获取菜单表格列表 */ - List listMenus(MenuQuery queryParams); + List listMenus(MenuQuery queryParams); /** * 获取菜单下拉列表 @@ -42,14 +42,14 @@ public interface MenuService extends IService { /** * 获取当前用户的菜单路由列表 */ - List listCurrentUserRoutes(); + List listCurrentUserRoutes(); /** * 获取当前用户的菜单路由列表(指定数据源) * * @param datasource 数据源名称,如:master(主库)、naiveui(NaiveUI数据库)、template(模板数据库) */ - List listCurrentUserRoutes(String datasource); + List listCurrentUserRoutes(String datasource); /** * 修改菜单显示状态 diff --git a/src/main/java/com/youlai/boot/system/service/NoticeService.java b/src/main/java/com/youlai/boot/system/service/NoticeService.java index 870a3825..96461527 100644 --- a/src/main/java/com/youlai/boot/system/service/NoticeService.java +++ b/src/main/java/com/youlai/boot/system/service/NoticeService.java @@ -5,9 +5,9 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.youlai.boot.system.model.entity.Notice; import com.youlai.boot.system.model.form.NoticeForm; import com.youlai.boot.system.model.query.NoticePageQuery; -import com.youlai.boot.system.model.vo.NoticePageVO; -import com.youlai.boot.system.model.vo.UserNoticePageVO; -import com.youlai.boot.system.model.vo.NoticeDetailVO; +import com.youlai.boot.system.model.vo.NoticePageVo; +import com.youlai.boot.system.model.vo.UserNoticePageVo; +import com.youlai.boot.system.model.vo.NoticeDetailVo; /** * 通知公告服务类 @@ -22,7 +22,7 @@ public interface NoticeService extends IService { * * @return 通知公告分页列表 */ - IPage getNoticePage(NoticePageQuery queryParams); + IPage getNoticePage(NoticePageQuery queryParams); /** * 获取通知公告表单数据 @@ -79,7 +79,7 @@ public interface NoticeService extends IService { * @param id 通知公告ID * @return 通知公告详情 */ - NoticeDetailVO getNoticeDetail(Long id); + NoticeDetailVo getNoticeDetail(Long id); /** * 获取我的通知公告分页列表 @@ -87,5 +87,5 @@ public interface NoticeService extends IService { * @param queryParams 查询参数 * @return 通知公告分页列表 */ - IPage getMyNoticePage(NoticePageQuery queryParams); + IPage getMyNoticePage(NoticePageQuery queryParams); } diff --git a/src/main/java/com/youlai/boot/system/service/RoleService.java b/src/main/java/com/youlai/boot/system/service/RoleService.java index 43761877..030ed781 100644 --- a/src/main/java/com/youlai/boot/system/service/RoleService.java +++ b/src/main/java/com/youlai/boot/system/service/RoleService.java @@ -7,7 +7,7 @@ import com.youlai.boot.system.model.entity.Role; import com.youlai.boot.common.model.Option; import com.youlai.boot.system.model.form.RoleForm; import com.youlai.boot.system.model.query.RolePageQuery; -import com.youlai.boot.system.model.vo.RolePageVO; +import com.youlai.boot.system.model.vo.RolePageVo; import java.util.List; import java.util.Set; @@ -26,7 +26,7 @@ public interface RoleService extends IService { * @param queryParams * @return */ - Page getRolePage(RolePageQuery queryParams); + Page getRolePage(RolePageQuery queryParams); /** diff --git a/src/main/java/com/youlai/boot/system/service/UserNoticeService.java b/src/main/java/com/youlai/boot/system/service/UserNoticeService.java index ddf31c11..24326905 100644 --- a/src/main/java/com/youlai/boot/system/service/UserNoticeService.java +++ b/src/main/java/com/youlai/boot/system/service/UserNoticeService.java @@ -5,8 +5,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.youlai.boot.system.model.entity.UserNotice; import com.youlai.boot.system.model.query.NoticePageQuery; -import com.youlai.boot.system.model.vo.UserNoticePageVO; -import com.youlai.boot.system.model.vo.NoticePageVO; +import com.youlai.boot.system.model.vo.UserNoticePageVo; +import com.youlai.boot.system.model.vo.NoticePageVo; import java.util.List; @@ -31,5 +31,5 @@ public interface UserNoticeService extends IService { * @param queryParams 查询参数 * @return 我的通知公告分页列表 */ - IPage getMyNoticePage(Page page, NoticePageQuery queryParams); + IPage getMyNoticePage(Page page, NoticePageQuery queryParams); } diff --git a/src/main/java/com/youlai/boot/system/service/UserOnlineService.java b/src/main/java/com/youlai/boot/system/service/UserOnlineService.java index c0e2a67f..6ec80555 100644 --- a/src/main/java/com/youlai/boot/system/service/UserOnlineService.java +++ b/src/main/java/com/youlai/boot/system/service/UserOnlineService.java @@ -1,10 +1,9 @@ package com.youlai.boot.system.service; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.youlai.boot.platform.websocket.publisher.WebSocketPublisher; +import com.youlai.boot.platform.websocket.topic.WebSocketTopics; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import java.util.List; @@ -26,11 +25,10 @@ public class UserOnlineService { // 在线用户映射表,key为用户名,value为用户在线信息 private final Map onlineUsers = new ConcurrentHashMap<>(); - private SimpMessagingTemplate messagingTemplate; + private final WebSocketPublisher webSocketPublisher; - @Autowired(required = false) - public void setMessagingTemplate(SimpMessagingTemplate messagingTemplate) { - this.messagingTemplate = messagingTemplate; + public UserOnlineService(WebSocketPublisher webSocketPublisher) { + this.webSocketPublisher = webSocketPublisher; } /** @@ -68,9 +66,9 @@ public class UserOnlineService { * * @return 在线用户名列表 */ - public List getOnlineUsers() { + public List getOnlineUsers() { return onlineUsers.values().stream() - .map(info -> new UserOnlineDTO(info.getUsername(), info.getLoginTime())) + .map(info -> new UserOnlineDto(info.getUsername(), info.getLoginTime())) .collect(Collectors.toList()); } @@ -97,11 +95,6 @@ public class UserOnlineService { * 通知所有客户端在线用户变更 */ private void notifyOnlineUsersChange() { - if (messagingTemplate == null) { - log.warn("消息模板尚未初始化,无法发送在线用户数量"); - return; - } - // 发送简化版数据(仅数量) sendOnlineUserCount(); } @@ -110,15 +103,10 @@ public class UserOnlineService { * 发送在线用户数量(简化版,不包含用户详情) */ private void sendOnlineUserCount() { - if (messagingTemplate == null) { - log.warn("消息模板尚未初始化,无法发送在线用户数量"); - return; - } - try { // 直接发送数量,更轻量 int count = onlineUsers.size(); - messagingTemplate.convertAndSend("/topic/online-count", count); + webSocketPublisher.publish(WebSocketTopics.TOPIC_ONLINE_COUNT, count); log.debug("已发送在线用户数量: {}", count); } catch (Exception e) { log.error("发送在线用户数量失败", e); @@ -136,10 +124,10 @@ public class UserOnlineService { } /** - * 用户在线DTO(用于返回给前端) + * 用户在线Dto(用于返回给前端) */ @Data - public static class UserOnlineDTO { + public static class UserOnlineDto { private final String username; private final long loginTime; } @@ -151,7 +139,7 @@ public class UserOnlineService { private static class OnlineUsersChangeEvent { private String type; private int count; - private List users; + private List users; private long timestamp; } } diff --git a/src/main/java/com/youlai/boot/system/service/UserService.java b/src/main/java/com/youlai/boot/system/service/UserService.java index e625db5f..a3a57c60 100644 --- a/src/main/java/com/youlai/boot/system/service/UserService.java +++ b/src/main/java/com/youlai/boot/system/service/UserService.java @@ -3,13 +3,13 @@ package com.youlai.boot.system.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; import com.youlai.boot.common.model.Option; -import com.youlai.boot.security.model.UserAuthCredentials; -import com.youlai.boot.system.model.dto.CurrentUserDTO; -import com.youlai.boot.system.model.dto.UserExportDTO; +import com.youlai.boot.security.model.UserAuthInfo; +import com.youlai.boot.system.model.dto.CurrentUserDto; +import com.youlai.boot.system.model.dto.UserExportDto; import com.youlai.boot.system.model.entity.User; import com.youlai.boot.system.model.query.UserPageQuery; -import com.youlai.boot.system.model.vo.UserPageVO; -import com.youlai.boot.system.model.vo.UserProfileVO; +import com.youlai.boot.system.model.vo.UserPageVo; +import com.youlai.boot.system.model.vo.UserProfileVo; import com.youlai.boot.system.model.form.*; import java.util.List; @@ -25,9 +25,9 @@ public interface UserService extends IService { /** * 用户分页列表 * - * @return {@link IPage} 用户分页列表 + * @return {@link IPage} 用户分页列表 */ - IPage getUserPage(UserPageQuery queryParams); + IPage getUserPage(UserPageQuery queryParams); /** * 获取用户表单数据 @@ -69,33 +69,37 @@ public interface UserService extends IService { * 根据用户名获取认证信息 * * @param username 用户名 - * @return {@link UserAuthCredentials} + * @return {@link UserAuthInfo} */ - UserAuthCredentials getAuthCredentialsByUsername(String username); + UserAuthInfo getAuthInfoByUsername(String username); + + default UserAuthInfo getAuthCredentialsByUsername(String username) { + return getAuthInfoByUsername(username); + } /** * 获取导出用户列表 * * @param queryParams 查询参数 - * @return {@link List} 导出用户列表 + * @return {@link List} 导出用户列表 */ - List listExportUsers(UserPageQuery queryParams); + List listExportUsers(UserPageQuery queryParams); /** * 获取登录用户信息 * - * @return {@link CurrentUserDTO} 登录用户信息 + * @return {@link CurrentUserDto} 登录用户信息 */ - CurrentUserDTO getCurrentUserInfo(); + CurrentUserDto getCurrentUserInfo(); /** * 获取个人中心用户信息 * - * @return {@link UserProfileVO} 个人中心用户信息 + * @return {@link UserProfileVo} 个人中心用户信息 */ - UserProfileVO getUserProfile(Long userId); + UserProfileVo getUserProfile(Long userId); /** * 修改个人中心用户信息 @@ -165,10 +169,14 @@ public interface UserService extends IService { * 根据 openid 获取用户认证信息 * * @param openId 用户名 - * @return {@link UserAuthCredentials} + * @return {@link UserAuthInfo} */ - UserAuthCredentials getAuthCredentialsByOpenId(String openId); + UserAuthInfo getAuthInfoByOpenId(String openId); + + default UserAuthInfo getAuthCredentialsByOpenId(String openId) { + return getAuthInfoByOpenId(openId); + } /** * 根据微信 OpenID 注册或绑定用户 @@ -181,9 +189,13 @@ public interface UserService extends IService { * 根据手机号获取用户认证信息 * * @param mobile 手机号 - * @return {@link UserAuthCredentials} + * @return {@link UserAuthInfo} */ - UserAuthCredentials getAuthCredentialsByMobile(String mobile); + UserAuthInfo getAuthInfoByMobile(String mobile); + + default UserAuthInfo getAuthCredentialsByMobile(String mobile) { + return getAuthInfoByMobile(mobile); + } /** * 根据手机号和OpenID注册用户 diff --git a/src/main/java/com/youlai/boot/system/service/WebSocketMessageService.java b/src/main/java/com/youlai/boot/system/service/WebSocketMessageService.java deleted file mode 100644 index e183d7af..00000000 --- a/src/main/java/com/youlai/boot/system/service/WebSocketMessageService.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.youlai.boot.system.service; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.messaging.simp.SimpMessagingTemplate; -import org.springframework.stereotype.Service; - -/** - * WebSocket消息服务 - * - * @author Ray - * @since 3.0.0 - */ -@Service -@RequiredArgsConstructor -@Slf4j -public class WebSocketMessageService { - - private final SimpMessagingTemplate messagingTemplate; - private final ObjectMapper objectMapper; - - /** - * 字典事件类型 - */ - public enum DictEventType { - /** - * 字典更新 - */ - DICT_UPDATED, - - /** - * 字典删除 - */ - DICT_DELETED - } - - /** - * 字典事件消息 - */ - public static class DictEvent { - /** - * 事件类型 - */ - private String type; - - /** - * 字典编码 - */ - private String dictCode; - - /** - * 时间戳 - */ - private long timestamp; - - public DictEvent(DictEventType type, String dictCode) { - this.type = type.name(); - this.dictCode = dictCode; - this.timestamp = System.currentTimeMillis(); - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getDictCode() { - return dictCode; - } - - public void setDictCode(String dictCode) { - this.dictCode = dictCode; - } - - public long getTimestamp() { - return timestamp; - } - - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - } - - /** - * 向所有客户端发送字典更新事件 - * - * @param dictCode 字典编码 - */ - public void sendDictUpdatedEvent(String dictCode) { - DictEvent event = new DictEvent(DictEventType.DICT_UPDATED, dictCode); - sendDictEvent(event); - } - - /** - * 向所有客户端发送字典删除事件 - * - * @param dictCode 字典编码 - */ - public void sendDictDeletedEvent(String dictCode) { - DictEvent event = new DictEvent(DictEventType.DICT_DELETED, dictCode); - sendDictEvent(event); - } - - /** - * 发送字典事件消息 - * - * @param event 字典事件 - */ - private void sendDictEvent(DictEvent event) { - try { - String message = objectMapper.writeValueAsString(event); - messagingTemplate.convertAndSend("/topic/dict", message); - log.info("Sent dict event to clients: {}", message); - } catch (JsonProcessingException e) { - log.error("Failed to send dict event", e); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/youlai/boot/system/service/impl/ConfigServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/ConfigServiceImpl.java index e4e12c26..d0de5653 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/ConfigServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/ConfigServiceImpl.java @@ -11,7 +11,7 @@ import com.youlai.boot.system.mapper.ConfigMapper; import com.youlai.boot.system.model.entity.Config; import com.youlai.boot.system.model.form.ConfigForm; import com.youlai.boot.system.model.query.ConfigPageQuery; -import com.youlai.boot.system.model.vo.ConfigVO; +import com.youlai.boot.system.model.vo.ConfigVo; import com.youlai.boot.system.service.ConfigService; import com.youlai.boot.security.util.SecurityUtils; import jakarta.annotation.PostConstruct; @@ -54,7 +54,7 @@ public class ConfigServiceImpl extends ServiceImpl impleme * @return 系统配置分页列表 */ @Override - public IPage page(ConfigPageQuery configPageQuery) { + public IPage page(ConfigPageQuery configPageQuery) { Page page = new Page<>(configPageQuery.getPageNum(), configPageQuery.getPageSize()); String keywords = configPageQuery.getKeywords(); LambdaQueryWrapper query = new LambdaQueryWrapper() diff --git a/src/main/java/com/youlai/boot/system/service/impl/DeptServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/DeptServiceImpl.java index db0ec596..784b9024 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/DeptServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/DeptServiceImpl.java @@ -12,7 +12,7 @@ import com.youlai.boot.system.mapper.DeptMapper; import com.youlai.boot.system.model.entity.Dept; import com.youlai.boot.system.model.form.DeptForm; import com.youlai.boot.system.model.query.DeptQuery; -import com.youlai.boot.system.model.vo.DeptVO; +import com.youlai.boot.system.model.vo.DeptVo; import com.youlai.boot.common.constant.SystemConstants; import com.youlai.boot.common.enums.StatusEnum; import com.youlai.boot.common.model.Option; @@ -42,7 +42,7 @@ public class DeptServiceImpl extends ServiceImpl implements De * 获取部门列表 */ @Override - public List getDeptList(DeptQuery queryParams) { + public List getDeptList(DeptQuery queryParams) { // 查询参数 String keywords = queryParams.getKeywords(); Integer status = queryParams.getStatus(); @@ -83,14 +83,14 @@ public class DeptServiceImpl extends ServiceImpl implements De * @param deptList 部门列表 * @return 部门树形列表 */ - public List recurDeptList(Long parentId, List deptList) { + public List recurDeptList(Long parentId, List deptList) { return deptList.stream() .filter(dept -> dept.getParentId().equals(parentId)) .map(dept -> { - DeptVO deptVO = deptConverter.toVo(dept); - List children = recurDeptList(dept.getId(), deptList); - deptVO.setChildren(children); - return deptVO; + DeptVo deptVo = deptConverter.toVo(dept); + List children = recurDeptList(dept.getId(), deptList); + deptVo.setChildren(children); + return deptVo; }).toList(); } diff --git a/src/main/java/com/youlai/boot/system/service/impl/DictItemServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/DictItemServiceImpl.java index 7c1d8058..9cb89ff9 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/DictItemServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/DictItemServiceImpl.java @@ -8,8 +8,8 @@ import com.youlai.boot.system.mapper.DictItemMapper; import com.youlai.boot.system.model.entity.DictItem; import com.youlai.boot.system.model.form.DictItemForm; import com.youlai.boot.system.model.query.DictItemPageQuery; -import com.youlai.boot.system.model.vo.DictItemOptionVO; -import com.youlai.boot.system.model.vo.DictItemPageVO; +import com.youlai.boot.system.model.vo.DictItemOptionVo; +import com.youlai.boot.system.model.vo.DictItemPageVo; import com.youlai.boot.system.service.DictItemService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -36,10 +36,10 @@ public class DictItemServiceImpl extends ServiceImpl i * @return 字典项分页列表 */ @Override - public Page getDictItemPage(DictItemPageQuery queryParams) { + public Page getDictItemPage(DictItemPageQuery queryParams) { int pageNum = queryParams.getPageNum(); int pageSize = queryParams.getPageSize(); - Page page = new Page<>(pageNum, pageSize); + Page page = new Page<>(pageNum, pageSize); return this.baseMapper.getDictItemPage(page, queryParams); } @@ -51,7 +51,7 @@ public class DictItemServiceImpl extends ServiceImpl i * @param dictCode 字典编码 */ @Override - public List getDictItems(String dictCode) { + public List getDictItems(String dictCode) { return this.list( new LambdaQueryWrapper() .eq(DictItem::getDictCode, dictCode) @@ -59,11 +59,11 @@ public class DictItemServiceImpl extends ServiceImpl i .orderByAsc(DictItem::getSort) ).stream() .map(item -> { - DictItemOptionVO dictItemOptionVO = new DictItemOptionVO(); - dictItemOptionVO.setLabel(item.getLabel()); - dictItemOptionVO.setValue(item.getValue()); - dictItemOptionVO.setTagType(item.getTagType()); - return dictItemOptionVO; + DictItemOptionVo dictItemOptionVo = new DictItemOptionVo(); + dictItemOptionVo.setLabel(item.getLabel()); + dictItemOptionVo.setValue(item.getValue()); + dictItemOptionVo.setTagType(item.getTagType()); + return dictItemOptionVo; }).toList(); } diff --git a/src/main/java/com/youlai/boot/system/service/impl/DictServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/DictServiceImpl.java index 2573b4d3..e8fc8c5b 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/DictServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/DictServiceImpl.java @@ -12,7 +12,7 @@ import com.youlai.boot.system.model.entity.Dict; import com.youlai.boot.system.model.entity.DictItem; import com.youlai.boot.system.model.form.DictForm; import com.youlai.boot.system.model.query.DictPageQuery; -import com.youlai.boot.system.model.vo.DictPageVO; +import com.youlai.boot.system.model.vo.DictPageVo; import com.youlai.boot.system.service.DictItemService; import com.youlai.boot.system.service.DictService; import lombok.RequiredArgsConstructor; @@ -40,7 +40,7 @@ public class DictServiceImpl extends ServiceImpl implements Di * @param queryParams 分页查询对象 */ @Override - public Page getDictPage(DictPageQuery queryParams) { + public Page getDictPage(DictPageQuery queryParams) { // 查询参数 int pageNum = queryParams.getPageNum(); int pageSize = queryParams.getPageSize(); diff --git a/src/main/java/com/youlai/boot/system/service/impl/LogServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/LogServiceImpl.java index 035f91ca..224976cc 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/LogServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/LogServiceImpl.java @@ -3,17 +3,16 @@ package com.youlai.boot.system.service.impl; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.youlai.boot.system.mapper.LogMapper; -import com.youlai.boot.system.model.bo.VisitCount; -import com.youlai.boot.system.model.bo.VisitStatsBO; +import com.youlai.boot.system.model.bo.VisitCountBo; +import com.youlai.boot.system.model.bo.VisitStatsBo; import com.youlai.boot.system.model.entity.Log; import com.youlai.boot.system.model.query.LogPageQuery; -import com.youlai.boot.system.model.vo.LogPageVO; -import com.youlai.boot.system.model.vo.VisitStatsVO; -import com.youlai.boot.system.model.vo.VisitTrendVO; +import com.youlai.boot.system.model.vo.LogPageVo; +import com.youlai.boot.system.model.vo.VisitStatsVo; +import com.youlai.boot.system.model.vo.VisitTrendVo; import com.youlai.boot.system.service.LogService; import org.springframework.stereotype.Service; -import java.math.BigDecimal; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; @@ -37,7 +36,7 @@ public class LogServiceImpl extends ServiceImpl * @return 日志分页列表 */ @Override - public Page getLogPage(LogPageQuery queryParams) { + public Page getLogPage(LogPageQuery queryParams) { return this.baseMapper.getLogPage(new Page<>(queryParams.getPageNum(), queryParams.getPageSize()), queryParams); } @@ -50,8 +49,8 @@ public class LogServiceImpl extends ServiceImpl * @return */ @Override - public VisitTrendVO getVisitTrend(LocalDate startDate, LocalDate endDate) { - VisitTrendVO visitTrend = new VisitTrendVO(); + public VisitTrendVo getVisitTrend(LocalDate startDate, LocalDate endDate) { + VisitTrendVo visitTrend = new VisitTrendVo(); List dates = new ArrayList<>(); // 获取日期范围内的日期 @@ -62,12 +61,12 @@ public class LogServiceImpl extends ServiceImpl visitTrend.setDates(dates); // 获取访问量和访问 IP 数的统计数据 - List pvCounts = this.baseMapper.getPvCounts(dates.get(0) + " 00:00:00", dates.get(dates.size() - 1) + " 23:59:59"); - List ipCounts = this.baseMapper.getIpCounts(dates.get(0) + " 00:00:00", dates.get(dates.size() - 1) + " 23:59:59"); + List pvCounts = this.baseMapper.getPvCounts(dates.get(0) + " 00:00:00", dates.get(dates.size() - 1) + " 23:59:59"); + List ipCounts = this.baseMapper.getIpCounts(dates.get(0) + " 00:00:00", dates.get(dates.size() - 1) + " 23:59:59"); // 将统计数据转换为 Map - Map pvMap = pvCounts.stream().collect(Collectors.toMap(VisitCount::getDate, VisitCount::getCount)); - Map ipMap = ipCounts.stream().collect(Collectors.toMap(VisitCount::getDate, VisitCount::getCount)); + Map pvMap = pvCounts.stream().collect(Collectors.toMap(VisitCountBo::getDate, VisitCountBo::getCount)); + Map ipMap = ipCounts.stream().collect(Collectors.toMap(VisitCountBo::getDate, VisitCountBo::getCount)); // 匹配日期和访问量/访问 IP 数 List pvList = new ArrayList<>(); @@ -88,11 +87,11 @@ public class LogServiceImpl extends ServiceImpl * 访问量统计 */ @Override - public VisitStatsVO getVisitStats() { - VisitStatsVO result = new VisitStatsVO(); + public VisitStatsVo getVisitStats() { + VisitStatsVo result = new VisitStatsVo(); // 访客数统计(UV) - VisitStatsBO uvStats = this.baseMapper.getUvStats(); + VisitStatsBo uvStats = this.baseMapper.getUvStats(); if(uvStats!=null){ result.setTodayUvCount(uvStats.getTodayCount()); result.setTotalUvCount(uvStats.getTotalCount()); @@ -100,7 +99,7 @@ public class LogServiceImpl extends ServiceImpl } // 浏览量统计(PV) - VisitStatsBO pvStats = this.baseMapper.getPvStats(); + VisitStatsBo pvStats = this.baseMapper.getPvStats(); if(pvStats!=null){ result.setTodayPvCount(pvStats.getTodayCount()); result.setTotalPvCount(pvStats.getTotalCount()); diff --git a/src/main/java/com/youlai/boot/system/service/impl/MenuServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/MenuServiceImpl.java index 7a0d678d..fc77c1fa 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/MenuServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/MenuServiceImpl.java @@ -17,8 +17,8 @@ import com.youlai.boot.system.mapper.MenuMapper; import com.youlai.boot.system.model.entity.Menu; import com.youlai.boot.system.model.form.MenuForm; import com.youlai.boot.system.model.query.MenuQuery; -import com.youlai.boot.system.model.vo.MenuVO; -import com.youlai.boot.system.model.vo.RouteVO; +import com.youlai.boot.system.model.vo.MenuVo; +import com.youlai.boot.system.model.vo.RouteVo; import com.youlai.boot.common.constant.SystemConstants; import com.youlai.boot.system.enums.MenuTypeEnum; import com.youlai.boot.common.enums.StatusEnum; @@ -55,7 +55,7 @@ public class MenuServiceImpl extends ServiceImpl implements Me * @param queryParams {@link MenuQuery} */ @Override - public List listMenus(MenuQuery queryParams) { + public List listMenus(MenuQuery queryParams) { List menus = this.list(new LambdaQueryWrapper() .like(StrUtil.isNotBlank(queryParams.getKeywords()), Menu::getName, queryParams.getKeywords()) .orderByAsc(Menu::getSort) @@ -88,15 +88,15 @@ public class MenuServiceImpl extends ServiceImpl implements Me * @param menuList 菜单列表 * @return 菜单列表 */ - private List buildMenuTree(Long parentId, List menuList) { + private List buildMenuTree(Long parentId, List menuList) { return CollectionUtil.emptyIfNull(menuList) .stream() .filter(menu -> menu.getParentId().equals(parentId)) .map(entity -> { - MenuVO menuVO = menuConverter.toVo(entity); - List children = buildMenuTree(entity.getId(), menuList); - menuVO.setChildren(children); - return menuVO; + MenuVo menuVo = menuConverter.toVo(entity); + List children = buildMenuTree(entity.getId(), menuList); + menuVo.setChildren(children); + return menuVo; }).toList(); } @@ -142,7 +142,7 @@ public class MenuServiceImpl extends ServiceImpl implements Me * 获取当前用户的菜单路由列表 */ @Override - public List listCurrentUserRoutes() { + public List listCurrentUserRoutes() { Set roleCodes = SecurityUtils.getRoles(); if (CollectionUtil.isEmpty(roleCodes)) { @@ -195,7 +195,7 @@ public class MenuServiceImpl extends ServiceImpl implements Me * - template: 模板项目菜单数据 */ @Override - public List listCurrentUserRoutes(String datasource) { + public List listCurrentUserRoutes(String datasource) { return listCurrentUserRoutes(); } @@ -207,17 +207,17 @@ public class MenuServiceImpl extends ServiceImpl implements Me * @param menuList 菜单列表 * @return 路由层级列表 */ - private List buildRoutes(Long parentId, List menuList) { - List routeList = new ArrayList<>(); + private List buildRoutes(Long parentId, List menuList) { + List routeList = new ArrayList<>(); for (Menu menu : menuList) { if (menu.getParentId().equals(parentId)) { - RouteVO routeVO = toRouteVo(menu); - List children = buildRoutes(menu.getId(), menuList); + RouteVo routeVo = toRouteVo(menu); + List children = buildRoutes(menu.getId(), menuList); if (!children.isEmpty()) { - routeVO.setChildren(children); + routeVo.setChildren(children); } - routeList.add(routeVO); + routeList.add(routeVo); } } @@ -225,10 +225,10 @@ public class MenuServiceImpl extends ServiceImpl implements Me } /** - * 根据RouteBO创建RouteVO + * 根据RouteBO创建RouteVo */ - private RouteVO toRouteVo(Menu menu) { - RouteVO routeVO = new RouteVO(); + private RouteVo toRouteVo(Menu menu) { + RouteVo routeVo = new RouteVo(); String routePath = menu.getRoutePath(); boolean externalLink = StrUtil.startWithAny(routePath, "http://", "https://"); @@ -241,15 +241,15 @@ public class MenuServiceImpl extends ServiceImpl implements Me : StringUtils.capitalize(StrUtil.toCamelCase(routePath, '-')); } // 根据name路由跳转 this.$router.push({name:xxx}) - routeVO.setName(routeName); + routeVo.setName(routeName); // 根据path路由跳转 this.$router.push({path:xxx}) - routeVO.setPath(routePath); - routeVO.setRedirect(menu.getRedirect()); + routeVo.setPath(routePath); + routeVo.setRedirect(menu.getRedirect()); // 外链无组件 - routeVO.setComponent(externalLink ? null : menu.getComponent()); + routeVo.setComponent(externalLink ? null : menu.getComponent()); - RouteVO.Meta meta = new RouteVO.Meta(); + RouteVo.Meta meta = new RouteVo.Meta(); meta.setTitle(menu.getName()); meta.setIcon(menu.getIcon()); meta.setHidden(StatusEnum.DISABLE.getValue().equals(menu.getVisible())); @@ -272,8 +272,8 @@ public class MenuServiceImpl extends ServiceImpl implements Me throw new RuntimeException("解析参数失败", e); } } - routeVO.setMeta(meta); - return routeVO; + routeVo.setMeta(meta); + return routeVo; } /** diff --git a/src/main/java/com/youlai/boot/system/service/impl/NoticeServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/NoticeServiceImpl.java index b4d70ea5..5efb5a70 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/NoticeServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/NoticeServiceImpl.java @@ -13,22 +13,23 @@ import com.youlai.boot.system.converter.NoticeConverter; import com.youlai.boot.system.enums.NoticePublishStatusEnum; import com.youlai.boot.system.enums.NoticeTargetEnum; import com.youlai.boot.system.mapper.NoticeMapper; -import com.youlai.boot.system.model.bo.NoticeBO; -import com.youlai.boot.system.model.dto.NoticeDTO; +import com.youlai.boot.system.model.bo.NoticeBo; +import com.youlai.boot.system.model.dto.NoticeDto; import com.youlai.boot.system.model.entity.Notice; import com.youlai.boot.system.model.entity.UserNotice; import com.youlai.boot.system.model.entity.User; import com.youlai.boot.system.model.form.NoticeForm; import com.youlai.boot.system.model.query.NoticePageQuery; -import com.youlai.boot.system.model.vo.NoticePageVO; -import com.youlai.boot.system.model.vo.UserNoticePageVO; -import com.youlai.boot.system.model.vo.NoticeDetailVO; +import com.youlai.boot.system.model.vo.NoticePageVo; +import com.youlai.boot.system.model.vo.UserNoticePageVo; +import com.youlai.boot.system.model.vo.NoticeDetailVo; import com.youlai.boot.system.service.NoticeService; import com.youlai.boot.system.service.UserNoticeService; import com.youlai.boot.system.service.UserOnlineService; import com.youlai.boot.system.service.UserService; +import com.youlai.boot.platform.websocket.publisher.WebSocketPublisher; +import com.youlai.boot.platform.websocket.topic.WebSocketTopics; import lombok.RequiredArgsConstructor; -import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -52,18 +53,18 @@ public class NoticeServiceImpl extends ServiceImpl impleme private final NoticeConverter noticeConverter; private final UserNoticeService userNoticeService; private final UserService userService; - private final SimpMessagingTemplate messagingTemplate; + private final WebSocketPublisher webSocketPublisher; private final UserOnlineService userOnlineService; /** * 获取通知公告分页列表 * * @param queryParams 查询参数 - * @return {@link IPage< NoticePageVO >} 通知公告分页列表 + * @return {@link IPage< NoticePageVo >} 通知公告分页列表 */ @Override - public IPage getNoticePage(NoticePageQuery queryParams) { - Page noticePage = this.baseMapper.getNoticePage( + public IPage getNoticePage(NoticePageQuery queryParams) { + Page noticePage = this.baseMapper.getNoticePage( new Page<>(queryParams.getPageNum(), queryParams.getPageSize()), queryParams ); @@ -214,19 +215,19 @@ public class NoticeServiceImpl extends ServiceImpl impleme Set receivers = targetUserList.stream().map(User::getUsername).collect(Collectors.toSet()); Set allOnlineUsers = userOnlineService.getOnlineUsers().stream() - .map(UserOnlineService.UserOnlineDTO::getUsername) + .map(UserOnlineService.UserOnlineDto::getUsername) .collect(Collectors.toSet()); // 找出在线用户的通知接收者 Set onlineReceivers = new HashSet<>(CollectionUtil.intersection(receivers, allOnlineUsers)); - NoticeDTO noticeDTO = new NoticeDTO(); - noticeDTO.setId(id); - noticeDTO.setTitle(notice.getTitle()); - noticeDTO.setType(notice.getType()); - noticeDTO.setPublishTime(notice.getPublishTime()); + NoticeDto noticeDto = new NoticeDto(); + noticeDto.setId(id); + noticeDto.setTitle(notice.getTitle()); + noticeDto.setType(notice.getType()); + noticeDto.setPublishTime(notice.getPublishTime()); - onlineReceivers.forEach(receiver -> messagingTemplate.convertAndSendToUser(receiver, "/queue/message", noticeDTO)); + onlineReceivers.forEach(receiver -> webSocketPublisher.publishToUser(receiver, WebSocketTopics.USER_QUEUE_MESSAGE, noticeDto)); } return publishResult; } @@ -249,7 +250,7 @@ public class NoticeServiceImpl extends ServiceImpl impleme throw new BusinessException("通知公告未发布或已撤回"); } - notice.setPublishStatus(NoticePublishStatusEnum.REVOKED.getValue()); + notice.setPublishStatus(NoticePublishStatusEnum.REVoKED.getValue()); notice.setRevokeTime(LocalDateTime.now()); notice.setUpdateBy(SecurityUtils.getUserId()); @@ -267,11 +268,11 @@ public class NoticeServiceImpl extends ServiceImpl impleme /** * * @param id 通知公告ID - * @return NoticeDetailVO 通知公告详情 + * @return NoticeDetailVo 通知公告详情 */ @Override - public NoticeDetailVO getNoticeDetail(Long id) { - NoticeBO noticeBO = this.baseMapper.getNoticeDetail(id); + public NoticeDetailVo getNoticeDetail(Long id) { + NoticeBo noticeBo = this.baseMapper.getNoticeDetail(id); // 更新用户通知公告的阅读状态 Long userId = SecurityUtils.getUserId(); userNoticeService.update(new LambdaUpdateWrapper() @@ -280,7 +281,7 @@ public class NoticeServiceImpl extends ServiceImpl impleme .eq(UserNotice::getIsRead, 0) .set(UserNotice::getIsRead, 1) ); - return noticeConverter.toDetailVO(noticeBO); + return noticeConverter.toDetailVo(noticeBo); } /** @@ -290,7 +291,7 @@ public class NoticeServiceImpl extends ServiceImpl impleme * @return 通知公告分页列表 */ @Override - public IPage getMyNoticePage(NoticePageQuery queryParams) { + public IPage getMyNoticePage(NoticePageQuery queryParams) { queryParams.setUserId(SecurityUtils.getUserId()); return userNoticeService.getMyNoticePage( new Page<>(queryParams.getPageNum(), queryParams.getPageSize()), diff --git a/src/main/java/com/youlai/boot/system/service/impl/RoleMenuServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/RoleMenuServiceImpl.java index 9304ce68..c9acaf8d 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/RoleMenuServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/RoleMenuServiceImpl.java @@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.youlai.boot.common.constant.RedisConstants; import com.youlai.boot.system.mapper.RoleMenuMapper; -import com.youlai.boot.system.model.bo.RolePermsBO; +import com.youlai.boot.system.model.bo.RolePermsBo; import com.youlai.boot.system.model.entity.RoleMenu; import com.youlai.boot.system.service.RoleMenuService; import jakarta.annotation.PostConstruct; @@ -36,7 +36,7 @@ public class RoleMenuServiceImpl extends ServiceImpl i public void initRolePermsCache() { log.info("开始初始化权限缓存..."); - List allRolePermsList = this.baseMapper.getRolePermsList(null); + List allRolePermsList = this.baseMapper.getRolePermsList(null); if (CollectionUtil.isEmpty(allRolePermsList)) { log.warn("权限数据为空,跳过缓存初始化"); @@ -67,7 +67,7 @@ public class RoleMenuServiceImpl extends ServiceImpl i redisTemplate.delete(cacheKey); // 重新加载权限 - List list = this.baseMapper.getRolePermsList(null); + List list = this.baseMapper.getRolePermsList(null); if (CollectionUtil.isNotEmpty(list)) { list.forEach(item -> { String roleCode = item.getRoleCode(); @@ -92,9 +92,9 @@ public class RoleMenuServiceImpl extends ServiceImpl i redisTemplate.opsForHash().delete(cacheKey, roleCode); // 重新加载指定角色权限 - List list = this.baseMapper.getRolePermsList(roleCode); + List list = this.baseMapper.getRolePermsList(roleCode); if (CollectionUtil.isNotEmpty(list)) { - RolePermsBO rolePerms = list.get(0); + RolePermsBo rolePerms = list.get(0); if (rolePerms != null) { Set perms = rolePerms.getPerms(); if (CollectionUtil.isNotEmpty(perms)) { @@ -117,9 +117,9 @@ public class RoleMenuServiceImpl extends ServiceImpl i redisTemplate.opsForHash().delete(cacheKey, oldRoleCode); // 添加新角色权限缓存 - List list = this.baseMapper.getRolePermsList(newRoleCode); + List list = this.baseMapper.getRolePermsList(newRoleCode); if (CollectionUtil.isNotEmpty(list)) { - RolePermsBO rolePerms = list.get(0); + RolePermsBo rolePerms = list.get(0); if (rolePerms != null) { Set perms = rolePerms.getPerms(); if (CollectionUtil.isNotEmpty(perms)) { diff --git a/src/main/java/com/youlai/boot/system/service/impl/RoleServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/RoleServiceImpl.java index 0efab740..b7654c75 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/RoleServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/RoleServiceImpl.java @@ -14,7 +14,7 @@ import com.youlai.boot.system.model.entity.Role; import com.youlai.boot.system.model.entity.RoleMenu; import com.youlai.boot.system.model.form.RoleForm; import com.youlai.boot.system.model.query.RolePageQuery; -import com.youlai.boot.system.model.vo.RolePageVO; +import com.youlai.boot.system.model.vo.RolePageVo; import com.youlai.boot.common.constant.SystemConstants; import com.youlai.boot.common.model.Option; import com.youlai.boot.security.util.SecurityUtils; @@ -48,10 +48,10 @@ public class RoleServiceImpl extends ServiceImpl implements Ro * 角色分页列表 * * @param queryParams 角色查询参数 - * @return {@link Page< RolePageVO >} – 角色分页列表 + * @return {@link Page< RolePageVo >} – 角色分页列表 */ @Override - public Page getRolePage(RolePageQuery queryParams) { + public Page getRolePage(RolePageQuery queryParams) { // 查询参数 int pageNum = queryParams.getPageNum(); int pageSize = queryParams.getPageSize(); diff --git a/src/main/java/com/youlai/boot/system/service/impl/UserNoticeServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/UserNoticeServiceImpl.java index aa82529c..b93d7211 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/UserNoticeServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/UserNoticeServiceImpl.java @@ -8,8 +8,8 @@ import com.youlai.boot.security.util.SecurityUtils; import com.youlai.boot.system.mapper.UserNoticeMapper; import com.youlai.boot.system.model.entity.UserNotice; import com.youlai.boot.system.model.query.NoticePageQuery; -import com.youlai.boot.system.model.vo.NoticePageVO; -import com.youlai.boot.system.model.vo.UserNoticePageVO; +import com.youlai.boot.system.model.vo.NoticePageVo; +import com.youlai.boot.system.model.vo.UserNoticePageVo; import com.youlai.boot.system.service.UserNoticeService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -51,7 +51,7 @@ public class UserNoticeServiceImpl extends ServiceImpl getMyNoticePage(Page page, NoticePageQuery queryParams) { + public IPage getMyNoticePage(Page page, NoticePageQuery queryParams) { return this.getBaseMapper().getMyNoticePage( new Page<>(queryParams.getPageNum(), queryParams.getPageSize()), queryParams diff --git a/src/main/java/com/youlai/boot/system/service/impl/UserRoleServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/UserRoleServiceImpl.java index 60a4fc2b..b3457551 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/UserRoleServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/UserRoleServiceImpl.java @@ -17,11 +17,16 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; +/** + * 用户角色业务实现类 + * + * @author Ray.Hao + * @since 0.0.1 + */ @Service @RequiredArgsConstructor public class UserRoleServiceImpl extends ServiceImpl implements UserRoleService { - private final TokenManager tokenManager; /** @@ -86,7 +91,7 @@ public class UserRoleServiceImpl extends ServiceImpl i */ @Override public boolean hasAssignedUsers(Long roleId) { - int count = this.baseMapper.countUsersForRole(roleId); + int count = this.baseMapper.countUsersByRoleId(roleId); return count > 0; } } diff --git a/src/main/java/com/youlai/boot/system/service/impl/UserServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/UserServiceImpl.java index abcc4c9a..70dbe215 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/UserServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/UserServiceImpl.java @@ -14,7 +14,7 @@ import com.youlai.boot.core.exception.BusinessException; import com.youlai.boot.common.model.Option; import com.youlai.boot.platform.sms.enums.SmsTypeEnum; import com.youlai.boot.platform.sms.service.SmsService; -import com.youlai.boot.security.model.UserAuthCredentials; +import com.youlai.boot.security.model.UserAuthInfo; import com.youlai.boot.security.service.PermissionService; import com.youlai.boot.security.token.TokenManager; import com.youlai.boot.security.util.SecurityUtils; @@ -22,16 +22,16 @@ import com.youlai.boot.platform.mail.service.MailService; import com.youlai.boot.system.converter.UserConverter; import com.youlai.boot.system.enums.DictCodeEnum; import com.youlai.boot.system.mapper.UserMapper; -import com.youlai.boot.system.model.bo.UserBO; -import com.youlai.boot.system.model.dto.CurrentUserDTO; -import com.youlai.boot.system.model.dto.UserExportDTO; +import com.youlai.boot.system.model.bo.UserBo; +import com.youlai.boot.system.model.dto.CurrentUserDto; +import com.youlai.boot.system.model.dto.UserExportDto; import com.youlai.boot.system.model.entity.DictItem; import com.youlai.boot.system.model.entity.User; import com.youlai.boot.system.model.entity.UserRole; import com.youlai.boot.system.model.form.*; import com.youlai.boot.system.model.query.UserPageQuery; -import com.youlai.boot.system.model.vo.UserPageVO; -import com.youlai.boot.system.model.vo.UserProfileVO; +import com.youlai.boot.system.model.vo.UserPageVo; +import com.youlai.boot.system.model.vo.UserProfileVo; import com.youlai.boot.system.service.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -81,21 +81,21 @@ public class UserServiceImpl extends ServiceImpl implements Us * 获取用户分页列表 * * @param queryParams 查询参数 - * @return {@link IPage} 用户分页列表 + * @return {@link IPage} 用户分页列表 */ @Override - public IPage getUserPage(UserPageQuery queryParams) { + public IPage getUserPage(UserPageQuery queryParams) { // 参数构建 int pageNum = queryParams.getPageNum(); int pageSize = queryParams.getPageSize(); - Page page = new Page<>(pageNum, pageSize); + Page page = new Page<>(pageNum, pageSize); boolean isRoot = SecurityUtils.isRoot(); queryParams.setIsRoot(isRoot); // 查询数据 - Page userPage = this.baseMapper.getUserPage(page, queryParams); + Page userPage = this.baseMapper.getUserPage(page, queryParams); // 实体转换 return userConverter.toPageVo(userPage); @@ -208,18 +208,18 @@ public class UserServiceImpl extends ServiceImpl implements Us * 根据用户名获取认证凭证信息 * * @param username 用户名 - * @return 用户认证凭证信息 {@link UserAuthCredentials} + * @return 用户认证凭证信息 {@link UserAuthInfo} */ @Override - public UserAuthCredentials getAuthCredentialsByUsername(String username) { - UserAuthCredentials userAuthCredentials = this.baseMapper.getAuthCredentialsByUsername(username); - if (userAuthCredentials != null) { - Set roles = userAuthCredentials.getRoles(); + public UserAuthInfo getAuthInfoByUsername(String username) { + UserAuthInfo userAuthInfo = this.baseMapper.getAuthInfoByUsername(username); + if (userAuthInfo != null) { + Set roles = userAuthInfo.getRoles(); // 获取最大范围的数据权限 Integer dataScope = roleService.getMaximumDataScope(roles); - userAuthCredentials.setDataScope(dataScope); + userAuthInfo.setDataScope(dataScope); } - return userAuthCredentials; + return userAuthInfo; } @@ -230,18 +230,18 @@ public class UserServiceImpl extends ServiceImpl implements Us * @return 用户认证信息 */ @Override - public UserAuthCredentials getAuthCredentialsByOpenId(String openId) { + public UserAuthInfo getAuthInfoByOpenId(String openId) { if (StrUtil.isBlank(openId)) { return null; } - UserAuthCredentials userAuthCredentials = this.baseMapper.getAuthCredentialsByOpenId(openId); - if (userAuthCredentials != null) { - Set roles = userAuthCredentials.getRoles(); + UserAuthInfo userAuthInfo = this.baseMapper.getAuthInfoByOpenId(openId); + if (userAuthInfo != null) { + Set roles = userAuthInfo.getRoles(); // 获取最大范围的数据权限 Integer dataScope = roleService.getMaximumDataScope(roles); - userAuthCredentials.setDataScope(dataScope); + userAuthInfo.setDataScope(dataScope); } - return userAuthCredentials; + return userAuthInfo; } /** @@ -251,18 +251,18 @@ public class UserServiceImpl extends ServiceImpl implements Us * @return 用户认证信息 */ @Override - public UserAuthCredentials getAuthCredentialsByMobile(String mobile) { + public UserAuthInfo getAuthInfoByMobile(String mobile) { if (StrUtil.isBlank(mobile)) { return null; } - UserAuthCredentials userAuthCredentials = this.baseMapper.getAuthCredentialsByMobile(mobile); - if (userAuthCredentials != null) { - Set roles = userAuthCredentials.getRoles(); + UserAuthInfo userAuthInfo = this.baseMapper.getAuthInfoByMobile(mobile); + if (userAuthInfo != null) { + Set roles = userAuthInfo.getRoles(); // 获取最大范围的数据权限 Integer dataScope = roleService.getMaximumDataScope(roles); - userAuthCredentials.setDataScope(dataScope); + userAuthInfo.setDataScope(dataScope); } - return userAuthCredentials; + return userAuthInfo; } /** @@ -400,15 +400,15 @@ public class UserServiceImpl extends ServiceImpl implements Us * 获取导出用户列表 * * @param queryParams 查询参数 - * @return {@link List} 导出用户列表 + * @return {@link List} 导出用户列表 */ @Override - public List listExportUsers(UserPageQuery queryParams) { + public List listExportUsers(UserPageQuery queryParams) { boolean isRoot = SecurityUtils.isRoot(); queryParams.setIsRoot(isRoot); - List exportUsers = this.baseMapper.listExportUsers(queryParams); + List exportUsers = this.baseMapper.listExportUsers(queryParams); if (CollectionUtil.isNotEmpty(exportUsers)) { //获取性别的字典项 Map genderMap = dictItemService.list( @@ -438,10 +438,10 @@ public class UserServiceImpl extends ServiceImpl implements Us /** * 获取登录用户信息 * - * @return {@link CurrentUserDTO} 用户信息 + * @return {@link CurrentUserDto} 用户信息 */ @Override - public CurrentUserDTO getCurrentUserInfo() { + public CurrentUserDto getCurrentUserInfo() { String username = SecurityUtils.getUsername(); @@ -455,30 +455,30 @@ public class UserServiceImpl extends ServiceImpl implements Us User::getAvatar ) ); - // entity->VO - CurrentUserDTO userInfoVO = userConverter.toCurrentUserDto(user); + // entity->Vo + CurrentUserDto userInfoVo = userConverter.toCurrentUserDto(user); // 用户角色集合 Set roles = SecurityUtils.getRoles(); - userInfoVO.setRoles(roles); + userInfoVo.setRoles(roles); // 用户权限集合 if (CollectionUtil.isNotEmpty(roles)) { Set perms = permissionService.getRolePermsFormCache(roles); - userInfoVO.setPerms(perms); + userInfoVo.setPerms(perms); } - return userInfoVO; + return userInfoVo; } /** * 获取个人中心用户信息 * * @param userId 用户ID - * @return {@link UserProfileVO} 个人中心用户信息 + * @return {@link UserProfileVo} 个人中心用户信息 */ @Override - public UserProfileVO getUserProfile(Long userId) { - UserBO entity = this.baseMapper.getUserProfile(userId); + public UserProfileVo getUserProfile(Long userId) { + UserBo entity = this.baseMapper.getUserProfile(userId); return userConverter.toProfileVo(entity); } diff --git a/src/main/resources/codegen.yml b/src/main/resources/codegen.yml index ceaf271a..f8cf8111 100644 --- a/src/main/resources/codegen.yml +++ b/src/main/resources/codegen.yml @@ -1,4 +1,3 @@ - # 代码生成器配置 codegen: # 下载代码文件名称 @@ -21,6 +20,10 @@ codegen: templatePath: codegen/api.ts.vm subpackageName: api extension: .ts + API_TYPES: + templatePath: codegen/api-types.ts.vm + subpackageName: types + extension: .ts VIEW: templatePath: codegen/index.vue.vm subpackageName: views @@ -50,7 +53,7 @@ codegen: Form: templatePath: codegen/form.java.vm subpackageName: model.form - VO: + Vo: templatePath: codegen/vo.java.vm subpackageName: model.vo Entity: diff --git a/src/main/resources/mapper/ai/AiCommandRecordMapper.xml b/src/main/resources/mapper/ai/AiAssistantRecordMapper.xml similarity index 62% rename from src/main/resources/mapper/ai/AiCommandRecordMapper.xml rename to src/main/resources/mapper/ai/AiAssistantRecordMapper.xml index 1755acdc..eae36156 100644 --- a/src/main/resources/mapper/ai/AiCommandRecordMapper.xml +++ b/src/main/resources/mapper/ai/AiAssistantRecordMapper.xml @@ -2,9 +2,9 @@ - + - + @@ -28,55 +28,55 @@ - SELECT - acr.id, - acr.user_id, - acr.username, - acr.original_command, - acr.ai_provider, - acr.ai_model, - acr.parse_status, - acr.function_calls, - acr.explanation, - acr.confidence, - acr.parse_error_message, - acr.input_tokens, - acr.output_tokens, - acr.parse_duration_ms, - acr.function_name, - acr.function_arguments, - acr.execute_status, - acr.execute_error_message, - acr.ip_address, - acr.create_time, - acr.update_time - FROM ai_command_record acr + aar.id, + aar.user_id, + aar.username, + aar.original_command, + aar.ai_provider, + aar.ai_model, + aar.parse_status, + aar.function_calls, + aar.explanation, + aar.confidence, + aar.parse_error_message, + aar.input_tokens, + aar.output_tokens, + aar.parse_duration_ms, + aar.function_name, + aar.function_arguments, + aar.execute_status, + aar.execute_error_message, + aar.ip_address, + aar.create_time, + aar.update_time + FROM ai_assistant_record aar ( - acr.original_command LIKE CONCAT('%', #{queryParams.keywords}, '%') - OR acr.function_name LIKE CONCAT('%', #{queryParams.keywords}, '%') - OR acr.username LIKE CONCAT('%', #{queryParams.keywords}, '%') + aar.original_command LIKE CONCAT('%', #{queryParams.keywords}, '%') + OR aar.function_name LIKE CONCAT('%', #{queryParams.keywords}, '%') + OR aar.username LIKE CONCAT('%', #{queryParams.keywords}, '%') ) - AND acr.execute_status = #{queryParams.executeStatus} + AND aar.execute_status = #{queryParams.executeStatus} - AND acr.user_id = #{queryParams.userId} + AND aar.user_id = #{queryParams.userId} - AND acr.parse_status = #{queryParams.parseStatus} + AND aar.parse_status = #{queryParams.parseStatus} - AND acr.function_name = #{queryParams.functionName} + AND aar.function_name = #{queryParams.functionName} - AND acr.ai_provider = #{queryParams.aiProvider} + AND aar.ai_provider = #{queryParams.aiProvider} - AND acr.ai_model = #{queryParams.aiModel} + AND aar.ai_model = #{queryParams.aiModel} - AND acr.create_time BETWEEN #{queryParams.createTime[0]} AND #{queryParams.createTime[1]} + AND aar.create_time BETWEEN #{queryParams.createTime[0]} AND #{queryParams.createTime[1]} - ORDER BY acr.create_time DESC + ORDER BY aar.create_time DESC - - diff --git a/src/main/resources/mapper/codegen/DatabaseMapper.xml b/src/main/resources/mapper/codegen/DatabaseMapper.xml index 0e402a8d..7771dfd2 100644 --- a/src/main/resources/mapper/codegen/DatabaseMapper.xml +++ b/src/main/resources/mapper/codegen/DatabaseMapper.xml @@ -6,7 +6,7 @@ - SELECT t1.TABLE_NAME , t1.TABLE_COMMENT , @@ -34,7 +34,7 @@ CREATE_TIME DESC - SELECT t1.TABLE_NAME , c.COMMENTS AS TABLE_COMMENT , diff --git a/src/main/resources/mapper/system/DictItemMapper.xml b/src/main/resources/mapper/system/DictItemMapper.xml index ab6cfec2..7c76c7ce 100644 --- a/src/main/resources/mapper/system/DictItemMapper.xml +++ b/src/main/resources/mapper/system/DictItemMapper.xml @@ -5,7 +5,7 @@ - SELECT id, dict_code, diff --git a/src/main/resources/mapper/system/DictMapper.xml b/src/main/resources/mapper/system/DictMapper.xml index 670694b4..1624b764 100644 --- a/src/main/resources/mapper/system/DictMapper.xml +++ b/src/main/resources/mapper/system/DictMapper.xml @@ -4,7 +4,7 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - SELECT t1.id, t1.name, diff --git a/src/main/resources/mapper/system/LogMapper.xml b/src/main/resources/mapper/system/LogMapper.xml index ad3a205b..e542abaa 100644 --- a/src/main/resources/mapper/system/LogMapper.xml +++ b/src/main/resources/mapper/system/LogMapper.xml @@ -6,7 +6,7 @@ - SELECT t1.id, t1.module, @@ -48,7 +48,7 @@ t1.create_time DESC - SELECT t1.id, t1.module, @@ -91,7 +91,7 @@ - SELECT COUNT(1) AS count, DATE_FORMAT(create_time,'%Y-%m-%d') AS date @@ -105,7 +105,7 @@ - SELECT COUNT(DISTINCT ip) AS count, DATE_FORMAT(create_time, '%Y-%m-%d') AS date @@ -119,7 +119,7 @@ - SELECT COUNT(CASE WHEN DATE(create_time) = CURDATE() THEN 1 END) AS todayCount, COUNT(*) AS totalCount, @@ -138,7 +138,7 @@ is_deleted = 0 - SELECT COUNT(CASE WHEN TRUNC(create_time) = TRUNC(SYSDATE) THEN 1 END) AS todayCount, COUNT(*) AS totalCount, @@ -161,7 +161,7 @@ - SELECT COUNT(DISTINCT CASE WHEN DATE(create_time) = CURDATE() THEN ip END) AS todayCount, COUNT(DISTINCT ip) AS totalCount, @@ -180,7 +180,7 @@ is_deleted = 0 - SELECT COUNT(DISTINCT CASE WHEN TRUNC(create_time) = TRUNC(SYSDATE) THEN ip END) AS todayCount, COUNT(DISTINCT ip) AS totalCount, ROUND( diff --git a/src/main/resources/mapper/system/NoticeMapper.xml b/src/main/resources/mapper/system/NoticeMapper.xml index 3e25389f..1dcc97ec 100644 --- a/src/main/resources/mapper/system/NoticeMapper.xml +++ b/src/main/resources/mapper/system/NoticeMapper.xml @@ -3,7 +3,7 @@ - SELECT t1.id, t1.title, @@ -42,7 +42,7 @@ - SELECT t1.id, t1.title, diff --git a/src/main/resources/mapper/system/RoleMenuMapper.xml b/src/main/resources/mapper/system/RoleMenuMapper.xml index 75403b12..31b59157 100644 --- a/src/main/resources/mapper/system/RoleMenuMapper.xml +++ b/src/main/resources/mapper/system/RoleMenuMapper.xml @@ -16,7 +16,7 @@ - + diff --git a/src/main/resources/mapper/system/UserMapper.xml b/src/main/resources/mapper/system/UserMapper.xml index 7ea2f9f7..49efb882 100644 --- a/src/main/resources/mapper/system/UserMapper.xml +++ b/src/main/resources/mapper/system/UserMapper.xml @@ -6,7 +6,7 @@ - SELECT u.id, u.username, @@ -82,7 +82,7 @@ - SELECT u.id, u.username, @@ -196,7 +196,7 @@ - + @@ -208,7 +208,7 @@ - SELECT t1.id userId, t1.username, @@ -226,7 +226,7 @@ - SELECT t1.id userId, t1.username, @@ -244,7 +244,7 @@ - SELECT t1.id userId, t1.username, @@ -261,7 +261,7 @@ - SELECT u.username, u.nickname, @@ -302,7 +302,7 @@ - SELECT u.id, u.username, @@ -324,7 +324,7 @@ u.id = #{userId} AND u.is_deleted = 0 - SELECT u.id, u.username, diff --git a/src/main/resources/mapper/system/UserNoticeMapper.xml b/src/main/resources/mapper/system/UserNoticeMapper.xml index c3364cb0..5153ac49 100644 --- a/src/main/resources/mapper/system/UserNoticeMapper.xml +++ b/src/main/resources/mapper/system/UserNoticeMapper.xml @@ -3,7 +3,7 @@ - SELECT t2.id, t2.title, diff --git a/src/main/resources/mapper/system/UserRoleMapper.xml b/src/main/resources/mapper/system/UserRoleMapper.xml index 87c7ddb2..d99bce0f 100644 --- a/src/main/resources/mapper/system/UserRoleMapper.xml +++ b/src/main/resources/mapper/system/UserRoleMapper.xml @@ -15,7 +15,7 @@ - SELECT count(*) FROM diff --git a/src/main/resources/templates/codegen/api-types.ts.vm b/src/main/resources/templates/codegen/api-types.ts.vm new file mode 100644 index 00000000..611fd522 --- /dev/null +++ b/src/main/resources/templates/codegen/api-types.ts.vm @@ -0,0 +1,47 @@ +/** + * ${entityName} $!{businessName}类型定义 + */ + +/** $!{businessName}分页查询参数 */ +export interface ${entityName}PageQuery extends PageQuery { +#foreach($fieldConfig in $fieldConfigs) + #if($fieldConfig.isShowInQuery) + #if("$!fieldConfig.fieldComment" != "") + /** ${fieldConfig.fieldComment} */ + #end + #if($fieldConfig.formType == "DATE" || $fieldConfig.formType == "DATE_TIME") + #if($fieldConfig.queryType == "BETWEEN") + ${fieldConfig.fieldName}?: [string, string]; + #else + ${fieldConfig.fieldName}?: ${fieldConfig.tsType}; + #end + #else + ${fieldConfig.fieldName}?: ${fieldConfig.tsType}; + #end + #end +#end +} + +/** $!{businessName}表单对象 */ +export interface ${entityName}Form { +#foreach($fieldConfig in $fieldConfigs) + #if($fieldConfig.isShowInForm) + #if("$!fieldConfig.fieldComment" != "") + /** ${fieldConfig.fieldComment} */ + #end + ${fieldConfig.fieldName}?: ${fieldConfig.tsType}; + #end +#end +} + +/** $!{businessName}分页对象 */ +export interface ${entityName}PageVo { +#foreach($fieldConfig in $fieldConfigs) + #if($fieldConfig.isShowInList) + #if("$!fieldConfig.fieldComment" != "") + /** ${fieldConfig.fieldComment} */ + #end + ${fieldConfig.fieldName}?: ${fieldConfig.tsType}; + #end +#end +} diff --git a/src/main/resources/templates/codegen/api.ts.vm b/src/main/resources/templates/codegen/api.ts.vm index a80445e8..944f9535 100644 --- a/src/main/resources/templates/codegen/api.ts.vm +++ b/src/main/resources/templates/codegen/api.ts.vm @@ -1,12 +1,13 @@ import request from "@/utils/request"; +import type { ${entityName}Form, ${entityName}PageQuery, ${entityName}PageVo } from "@/api/types"; -const ${entityName.toUpperCase()}_BASE_URL = "/api/v1/${kebabCaseEntityName}"; +const ${entityUpperSnake}_BASE_URL = "/api/v1/${entityKebab}"; const ${entityName}API = { /** 获取${businessName}分页数据 */ getPage(queryParams?: ${entityName}PageQuery) { - return request>({ - url: `${${entityName.toUpperCase()}_BASE_URL}/page`, + return request>({ + url: `${${entityUpperSnake}_BASE_URL}/page`, method: "get", params: queryParams, }); @@ -19,7 +20,7 @@ const ${entityName}API = { */ getFormData(id: number) { return request({ - url: `${${entityName.toUpperCase()}_BASE_URL}/${id}/form`, + url: `${${entityUpperSnake}_BASE_URL}/${id}/form`, method: "get", }); }, @@ -31,7 +32,7 @@ const ${entityName}API = { */ create(data: ${entityName}Form) { return request({ - url: `${${entityName.toUpperCase()}_BASE_URL}`, + url: `${${entityUpperSnake}_BASE_URL}`, method: "post", data, }); @@ -45,7 +46,7 @@ const ${entityName}API = { */ update(id: string, data: ${entityName}Form) { return request({ - url: `${${entityName.toUpperCase()}_BASE_URL}/${id}`, + url: `${${entityUpperSnake}_BASE_URL}/${id}`, method: "put", data, }); @@ -58,54 +59,10 @@ const ${entityName}API = { */ deleteByIds(ids: string) { return request({ - url: `${${entityName.toUpperCase()}_BASE_URL}/${ids}`, + url: `${${entityUpperSnake}_BASE_URL}/${ids}`, method: "delete", }); } } export default ${entityName}API; - -/** ${businessName}分页查询参数 */ -export interface ${entityName}PageQuery extends PageQuery { - #foreach($fieldConfig in $fieldConfigs) - #if($fieldConfig.isShowInQuery) - #if("$!fieldConfig.fieldComment" != "") - /** ${fieldConfig.fieldComment} */ - #end - #if($fieldConfig.formType == "DATE" || $fieldConfig.formType == "DATE_TIME") - #if($fieldConfig.queryType == "BETWEEN") - ${fieldConfig.fieldName}?: [string, string]; - #else - ${fieldConfig.fieldName}?: ${fieldConfig.tsType}; - #end - #else - ${fieldConfig.fieldName}?: ${fieldConfig.tsType}; - #end - #end - #end -} - -/** ${businessName}表单对象 */ -export interface ${entityName}Form { - #foreach($fieldConfig in $fieldConfigs) - #if($fieldConfig.isShowInForm) - #if("$!fieldConfig.fieldComment" != "") - /** ${fieldConfig.fieldComment} */ - #end - ${fieldConfig.fieldName}?: ${fieldConfig.tsType}; - #end - #end -} - -/** ${businessName}分页对象 */ -export interface ${entityName}PageVO { - #foreach($fieldConfig in $fieldConfigs) - #if($fieldConfig.isShowInList) - #if("$!fieldConfig.fieldComment" != "") - /** ${fieldConfig.fieldComment} */ - #end - ${fieldConfig.fieldName}?: ${fieldConfig.tsType}; - #end - #end -} diff --git a/src/main/resources/templates/codegen/controller.java.vm b/src/main/resources/templates/codegen/controller.java.vm index bdadcc47..768a0de8 100644 --- a/src/main/resources/templates/codegen/controller.java.vm +++ b/src/main/resources/templates/codegen/controller.java.vm @@ -6,7 +6,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import ${packageName}.${moduleName}.model.form.${entityName}Form; import ${packageName}.${moduleName}.model.query.${entityName}Query; -import ${packageName}.${moduleName}.model.vo.${entityName}VO; +import ${packageName}.${moduleName}.model.vo.${entityName}Vo; import com.baomidou.mybatisplus.core.metadata.IPage; import com.youlai.boot.core.web.PageResult; import com.youlai.boot.core.web.Result; @@ -26,56 +26,56 @@ import jakarta.validation.Valid; */ @Tag(name = "${businessName}接口") @RestController -@RequestMapping("/api/v1/${kebabCaseEntityName}") +@RequestMapping("/api/v1/${entityKebab}") @RequiredArgsConstructor public class ${entityName}Controller { - private final ${entityName}Service ${lowerFirstEntityName}Service; + private final ${entityName}Service ${entityLowerCamel}Service; @Operation(summary = "$!{businessName}分页列表") @GetMapping("/page") - @PreAuthorize("@ss.hasPerm('${moduleName}:${kebabCaseEntityName}:query')") - public PageResult<${entityName}VO> get${entityName}Page(${entityName}Query queryParams ) { - IPage<${entityName}VO> result = ${lowerFirstEntityName}Service.get${entityName}Page(queryParams); + @PreAuthorize("@ss.hasPerm('${moduleName}:${entityKebab}:query')") + public PageResult<${entityName}Vo> get${entityName}Page(${entityName}Query queryParams ) { + IPage<${entityName}Vo> result = ${entityLowerCamel}Service.get${entityName}Page(queryParams); return PageResult.success(result); } @Operation(summary = "新增${businessName}") @PostMapping - @PreAuthorize("@ss.hasPerm('${moduleName}:${kebabCaseEntityName}:add')") + @PreAuthorize("@ss.hasPerm('${moduleName}:${entityKebab}:add')") public Result save${entityName}(@RequestBody @Valid ${entityName}Form formData ) { - boolean result = ${lowerFirstEntityName}Service.save${entityName}(formData); + boolean result = ${entityLowerCamel}Service.save${entityName}(formData); return Result.judge(result); } @Operation(summary = "获取${businessName}表单数据") @GetMapping("/{id}/form") - @PreAuthorize("@ss.hasPerm('${moduleName}:${kebabCaseEntityName}:edit')") + @PreAuthorize("@ss.hasPerm('${moduleName}:${entityKebab}:edit')") public Result<${entityName}Form> get${entityName}Form( @Parameter(description = "$!{businessName}ID") @PathVariable Long id ) { - ${entityName}Form formData = ${lowerFirstEntityName}Service.get${entityName}FormData(id); + ${entityName}Form formData = ${entityLowerCamel}Service.get${entityName}FormData(id); return Result.success(formData); } @Operation(summary = "修改${businessName}") @PutMapping(value = "/{id}") - @PreAuthorize("@ss.hasPerm('${moduleName}:${kebabCaseEntityName}:edit')") + @PreAuthorize("@ss.hasPerm('${moduleName}:${entityKebab}:edit')") public Result update${entityName}( @Parameter(description = "$!{businessName}ID") @PathVariable Long id, @RequestBody @Validated ${entityName}Form formData ) { - boolean result = ${lowerFirstEntityName}Service.update${entityName}(id, formData); + boolean result = ${entityLowerCamel}Service.update${entityName}(id, formData); return Result.judge(result); } @Operation(summary = "删除${businessName}") @DeleteMapping("/{ids}") - @PreAuthorize("@ss.hasPerm('${moduleName}:${kebabCaseEntityName}:delete')") + @PreAuthorize("@ss.hasPerm('${moduleName}:${entityKebab}:delete')") public Result delete${entityName}s( @Parameter(description = "$!{businessName}ID,多个以英文逗号(,)分割") @PathVariable String ids ) { - boolean result = ${lowerFirstEntityName}Service.delete${entityName}s(ids); + boolean result = ${entityLowerCamel}Service.delete${entityName}s(ids); return Result.judge(result); } } diff --git a/src/main/resources/templates/codegen/index.curd.vue.vm b/src/main/resources/templates/codegen/index.curd.vue.vm index 193d106d..2d89bece 100644 --- a/src/main/resources/templates/codegen/index.curd.vue.vm +++ b/src/main/resources/templates/codegen/index.curd.vue.vm @@ -63,7 +63,8 @@