From 9131203d1c524af5e057113a9a59d1eacc8d67a9 Mon Sep 17 00:00:00 2001 From: Peanut Date: Sat, 27 Jun 2026 10:25:17 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E6=96=B0=E5=A2=9E=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E9=85=8D=E7=BD=AE=E6=A8=A1=E5=9D=97=EF=BC=88Entity/Ma?= =?UTF-8?q?pper/DTO/Service/Controller=EF=BC=89+=20=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=85=AC=E5=BC=80=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend-single/sql/t_system_config.sql | 34 ++++++ .../java/com/emotion/config/WebMvcConfig.java | 1 + .../emotion/controller/AuthController.java | 15 +++ .../controller/SystemConfigController.java | 48 ++++++++ .../request/SystemConfigUpdateRequest.java | 27 +++++ .../dto/response/LoginConfigResponse.java | 24 ++++ .../dto/response/SystemConfigResponse.java | 48 ++++++++ .../java/com/emotion/entity/SystemConfig.java | 72 ++++++++++++ .../emotion/mapper/SystemConfigMapper.java | 15 +++ .../emotion/service/SystemConfigService.java | 41 +++++++ .../service/impl/SystemConfigServiceImpl.java | 108 ++++++++++++++++++ 11 files changed, 433 insertions(+) create mode 100644 backend-single/sql/t_system_config.sql create mode 100644 backend-single/src/main/java/com/emotion/controller/SystemConfigController.java create mode 100644 backend-single/src/main/java/com/emotion/dto/request/SystemConfigUpdateRequest.java create mode 100644 backend-single/src/main/java/com/emotion/dto/response/LoginConfigResponse.java create mode 100644 backend-single/src/main/java/com/emotion/dto/response/SystemConfigResponse.java create mode 100644 backend-single/src/main/java/com/emotion/entity/SystemConfig.java create mode 100644 backend-single/src/main/java/com/emotion/mapper/SystemConfigMapper.java create mode 100644 backend-single/src/main/java/com/emotion/service/SystemConfigService.java create mode 100644 backend-single/src/main/java/com/emotion/service/impl/SystemConfigServiceImpl.java diff --git a/backend-single/sql/t_system_config.sql b/backend-single/sql/t_system_config.sql new file mode 100644 index 0000000..04878d0 --- /dev/null +++ b/backend-single/sql/t_system_config.sql @@ -0,0 +1,34 @@ +-- 系统配置表 +CREATE TABLE t_system_config ( + id VARCHAR(64) PRIMARY KEY, + config_key VARCHAR(100) NOT NULL UNIQUE COMMENT '配置唯一标识', + config_value VARCHAR(500) NOT NULL DEFAULT '' COMMENT '配置值', + value_type VARCHAR(20) NOT NULL DEFAULT 'string' COMMENT '值类型: boolean/string/number/json', + config_group VARCHAR(50) NOT NULL DEFAULT 'system' COMMENT '配置分组: system/login/notification', + config_name VARCHAR(100) NOT NULL DEFAULT '' COMMENT '显示名称', + description VARCHAR(300) DEFAULT '' COMMENT '配置说明', + sort_order INT NOT NULL DEFAULT 0 COMMENT '排序号', + is_visible TINYINT NOT NULL DEFAULT 1 COMMENT '是否在管理后台可见: 0-隐藏, 1-显示', + create_by VARCHAR(64) DEFAULT NULL, + create_time DATETIME DEFAULT NULL, + update_by VARCHAR(64) DEFAULT NULL, + update_time DATETIME DEFAULT NULL, + is_deleted TINYINT NOT NULL DEFAULT 0 +) COMMENT = '系统配置表'; + +-- 初始数据:短信登录开关(默认关闭) +INSERT INTO t_system_config (id, config_key, config_value, value_type, config_group, config_name, description, sort_order, is_visible, create_time, update_time, is_deleted) +VALUES ( + REPLACE(UUID(), '-', ''), + 'sms_login_enabled', + 'false', + 'boolean', + 'login', + '短信登录', + '是否启用手机号+短信验证码登录方式', + 1, + 1, + NOW(), + NOW(), + 0 +); diff --git a/backend-single/src/main/java/com/emotion/config/WebMvcConfig.java b/backend-single/src/main/java/com/emotion/config/WebMvcConfig.java index 04a5b6b..7cfa530 100644 --- a/backend-single/src/main/java/com/emotion/config/WebMvcConfig.java +++ b/backend-single/src/main/java/com/emotion/config/WebMvcConfig.java @@ -60,6 +60,7 @@ public class WebMvcConfig implements WebMvcConfigurer { "/actuator/**", // Actuator endpoints "/admin/**", // 排除管理员路径,由管理员拦截器处理 "/auth/wechat/login", // WeChat mini program login endpoint + "/auth/loginConfig", // 登录方式配置接口(免登录) "/error" // Spring Boot error page ) .order(2); // 优先级2 diff --git a/backend-single/src/main/java/com/emotion/controller/AuthController.java b/backend-single/src/main/java/com/emotion/controller/AuthController.java index e59b8fa..61b61ac 100644 --- a/backend-single/src/main/java/com/emotion/controller/AuthController.java +++ b/backend-single/src/main/java/com/emotion/controller/AuthController.java @@ -10,9 +10,11 @@ import com.emotion.dto.response.ResetPasswordResponse; import com.emotion.dto.response.AuthResponse; import com.emotion.dto.response.CaptchaResponse; +import com.emotion.dto.response.LoginConfigResponse; import com.emotion.dto.response.SmsCodeResponse; import com.emotion.dto.response.UserInfoResponse; import com.emotion.service.AuthService; +import com.emotion.service.SystemConfigService; import com.emotion.service.TokenService; import com.emotion.util.UserContextUtils; import io.swagger.v3.oas.annotations.Operation; @@ -41,6 +43,9 @@ public class AuthController { @Autowired private TokenService tokenService; + @Autowired + private SystemConfigService systemConfigService; + /** * 用户登录(简化版:手机号+验证码,不存在则自动注册) */ @@ -61,6 +66,16 @@ public class AuthController { return Result.success("登录成功", response); } + /** + * 获取登录方式配置 + */ + @GetMapping("/loginConfig") + @Operation(summary = "获取登录方式配置", description = "返回当前启用的登录方式,供小程序登录页动态渲染") + public Result getLoginConfig() { + LoginConfigResponse response = systemConfigService.getLoginConfig(); + return Result.success(response); + } + @PostMapping(value = "/register") @Operation(summary = "用户注册", description = "使用手机号、密码和短信验证码进行注册") public Result register(@Valid @RequestBody RegisterRequest request) { diff --git a/backend-single/src/main/java/com/emotion/controller/SystemConfigController.java b/backend-single/src/main/java/com/emotion/controller/SystemConfigController.java new file mode 100644 index 0000000..53a87df --- /dev/null +++ b/backend-single/src/main/java/com/emotion/controller/SystemConfigController.java @@ -0,0 +1,48 @@ +package com.emotion.controller; + +import com.emotion.common.Result; +import com.emotion.dto.request.SystemConfigUpdateRequest; +import com.emotion.dto.response.SystemConfigResponse; +import com.emotion.service.SystemConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 系统配置管理控制器(管理端) + * + * @author system + * @date 2026-06-27 + */ +@RestController +@RequestMapping("/admin/systemConfig") +@Tag(name = "系统配置管理", description = "系统配置的查询和更新功能") +public class SystemConfigController { + + @Autowired + private SystemConfigService systemConfigService; + + /** + * 获取所有可见配置列表 + */ + @GetMapping("/list") + @Operation(summary = "获取配置列表", description = "获取所有可见的系统配置列表") + public Result> list() { + List configs = systemConfigService.getVisibleConfigList(); + return Result.success(configs); + } + + /** + * 批量更新配置 + */ + @PutMapping("/update") + @Operation(summary = "批量更新配置", description = "批量更新系统配置值") + public Result update(@RequestBody @Validated List requests) { + systemConfigService.batchUpdateConfigs(requests); + return Result.success("更新成功", null); + } +} diff --git a/backend-single/src/main/java/com/emotion/dto/request/SystemConfigUpdateRequest.java b/backend-single/src/main/java/com/emotion/dto/request/SystemConfigUpdateRequest.java new file mode 100644 index 0000000..32e8d75 --- /dev/null +++ b/backend-single/src/main/java/com/emotion/dto/request/SystemConfigUpdateRequest.java @@ -0,0 +1,27 @@ +package com.emotion.dto.request; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 系统配置更新请求 + * + * @author system + * @date 2026-06-27 + */ +@Data +public class SystemConfigUpdateRequest { + + /** + * 配置唯一标识 + */ + @NotBlank(message = "配置标识不能为空") + private String configKey; + + /** + * 配置值 + */ + @NotBlank(message = "配置值不能为空") + private String configValue; +} diff --git a/backend-single/src/main/java/com/emotion/dto/response/LoginConfigResponse.java b/backend-single/src/main/java/com/emotion/dto/response/LoginConfigResponse.java new file mode 100644 index 0000000..a6ca2ba --- /dev/null +++ b/backend-single/src/main/java/com/emotion/dto/response/LoginConfigResponse.java @@ -0,0 +1,24 @@ +package com.emotion.dto.response; + +import lombok.Data; + +/** + * 登录方式配置响应 + * 返回给小程序,告知当前启用的登录方式 + * + * @author system + * @date 2026-06-27 + */ +@Data +public class LoginConfigResponse { + + /** + * 是否启用微信登录 + */ + private Boolean wechatLoginEnabled; + + /** + * 是否启用短信登录 + */ + private Boolean smsLoginEnabled; +} diff --git a/backend-single/src/main/java/com/emotion/dto/response/SystemConfigResponse.java b/backend-single/src/main/java/com/emotion/dto/response/SystemConfigResponse.java new file mode 100644 index 0000000..cff8870 --- /dev/null +++ b/backend-single/src/main/java/com/emotion/dto/response/SystemConfigResponse.java @@ -0,0 +1,48 @@ +package com.emotion.dto.response; + +import lombok.Data; + +/** + * 系统配置响应 + * + * @author system + * @date 2026-06-27 + */ +@Data +public class SystemConfigResponse { + + /** + * 配置唯一标识 + */ + private String configKey; + + /** + * 配置值 + */ + private String configValue; + + /** + * 值类型: boolean/string/number/json + */ + private String valueType; + + /** + * 配置分组 + */ + private String configGroup; + + /** + * 显示名称 + */ + private String configName; + + /** + * 配置说明 + */ + private String description; + + /** + * 排序号 + */ + private Integer sortOrder; +} diff --git a/backend-single/src/main/java/com/emotion/entity/SystemConfig.java b/backend-single/src/main/java/com/emotion/entity/SystemConfig.java new file mode 100644 index 0000000..3d1b81d --- /dev/null +++ b/backend-single/src/main/java/com/emotion/entity/SystemConfig.java @@ -0,0 +1,72 @@ +package com.emotion.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.emotion.common.BaseEntity; +import lombok.experimental.SuperBuilder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 系统配置实体 + * + * @author system + * @date 2026-06-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@TableName("t_system_config") +public class SystemConfig extends BaseEntity { + + /** + * 配置唯一标识 + */ + @TableField("config_key") + private String configKey; + + /** + * 配置值 + */ + @TableField("config_value") + private String configValue; + + /** + * 值类型: boolean/string/number/json + */ + @TableField("value_type") + private String valueType; + + /** + * 配置分组: system/login/notification + */ + @TableField("config_group") + private String configGroup; + + /** + * 显示名称 + */ + @TableField("config_name") + private String configName; + + /** + * 配置说明 + */ + @TableField("description") + private String description; + + /** + * 排序号 + */ + @TableField("sort_order") + private Integer sortOrder; + + /** + * 是否在管理后台可见: 0-隐藏, 1-显示 + */ + @TableField("is_visible") + private Integer isVisible; +} diff --git a/backend-single/src/main/java/com/emotion/mapper/SystemConfigMapper.java b/backend-single/src/main/java/com/emotion/mapper/SystemConfigMapper.java new file mode 100644 index 0000000..40d5196 --- /dev/null +++ b/backend-single/src/main/java/com/emotion/mapper/SystemConfigMapper.java @@ -0,0 +1,15 @@ +package com.emotion.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.emotion.entity.SystemConfig; +import org.apache.ibatis.annotations.Mapper; + +/** + * 系统配置Mapper接口 + * + * @author system + * @date 2026-06-27 + */ +@Mapper +public interface SystemConfigMapper extends BaseMapper { +} diff --git a/backend-single/src/main/java/com/emotion/service/SystemConfigService.java b/backend-single/src/main/java/com/emotion/service/SystemConfigService.java new file mode 100644 index 0000000..308e222 --- /dev/null +++ b/backend-single/src/main/java/com/emotion/service/SystemConfigService.java @@ -0,0 +1,41 @@ +package com.emotion.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.emotion.dto.request.SystemConfigUpdateRequest; +import com.emotion.dto.response.LoginConfigResponse; +import com.emotion.dto.response.SystemConfigResponse; +import com.emotion.entity.SystemConfig; + +import java.util.List; + +/** + * 系统配置服务接口 + * + * @author system + * @date 2026-06-27 + */ +public interface SystemConfigService extends IService { + + /** + * 获取所有可见配置列表 + */ + List getVisibleConfigList(); + + /** + * 批量更新配置 + */ + void batchUpdateConfigs(List requests); + + /** + * 获取配置值(带 Redis 缓存) + * + * @param configKey 配置标识 + * @return 配置值字符串,不存在返回 null + */ + String getConfigValue(String configKey); + + /** + * 获取登录方式配置 + */ + LoginConfigResponse getLoginConfig(); +} diff --git a/backend-single/src/main/java/com/emotion/service/impl/SystemConfigServiceImpl.java b/backend-single/src/main/java/com/emotion/service/impl/SystemConfigServiceImpl.java new file mode 100644 index 0000000..f78115f --- /dev/null +++ b/backend-single/src/main/java/com/emotion/service/impl/SystemConfigServiceImpl.java @@ -0,0 +1,108 @@ +package com.emotion.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.emotion.dto.request.SystemConfigUpdateRequest; +import com.emotion.dto.response.LoginConfigResponse; +import com.emotion.dto.response.SystemConfigResponse; +import com.emotion.entity.SystemConfig; +import com.emotion.mapper.SystemConfigMapper; +import com.emotion.service.SystemConfigService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 系统配置服务实现类 + * + * @author system + * @date 2026-06-27 + */ +@Slf4j +@Service +public class SystemConfigServiceImpl extends ServiceImpl implements SystemConfigService { + + @Autowired + private RedisTemplate redisTemplate; + + private static final String CACHE_PREFIX = "system_config:"; + private static final long CACHE_EXPIRE_HOURS = 24; + private static final String SMS_LOGIN_ENABLED_KEY = "sms_login_enabled"; + + @Override + public List getVisibleConfigList() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SystemConfig::getIsVisible, 1) + .orderByAsc(SystemConfig::getSortOrder); + List configs = list(wrapper); + return configs.stream().map(this::convertToResponse).collect(Collectors.toList()); + } + + @Override + public void batchUpdateConfigs(List requests) { + for (SystemConfigUpdateRequest request : requests) { + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(SystemConfig::getConfigKey, request.getConfigKey()) + .set(SystemConfig::getConfigValue, request.getConfigValue()); + update(updateWrapper); + + // 清除缓存 + redisTemplate.delete(CACHE_PREFIX + request.getConfigKey()); + log.info("更新系统配置: key={}, value={}", request.getConfigKey(), request.getConfigValue()); + } + } + + @Override + public String getConfigValue(String configKey) { + // 先查 Redis 缓存 + String cacheKey = CACHE_PREFIX + configKey; + String cached = (String) redisTemplate.opsForValue().get(cacheKey); + if (cached != null) { + return cached; + } + + // 查数据库 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SystemConfig::getConfigKey, configKey); + SystemConfig config = getOne(wrapper); + if (config == null) { + return null; + } + + // 写入缓存 + redisTemplate.opsForValue().set(cacheKey, config.getConfigValue(), CACHE_EXPIRE_HOURS, TimeUnit.HOURS); + return config.getConfigValue(); + } + + @Override + public LoginConfigResponse getLoginConfig() { + LoginConfigResponse response = new LoginConfigResponse(); + response.setWechatLoginEnabled(true); + + String smsEnabled = getConfigValue(SMS_LOGIN_ENABLED_KEY); + response.setSmsLoginEnabled("true".equalsIgnoreCase(smsEnabled)); + + return response; + } + + /** + * 实体转响应对象 + */ + private SystemConfigResponse convertToResponse(SystemConfig config) { + SystemConfigResponse response = new SystemConfigResponse(); + response.setConfigKey(config.getConfigKey()); + response.setConfigValue(config.getConfigValue()); + response.setValueType(config.getValueType()); + response.setConfigGroup(config.getConfigGroup()); + response.setConfigName(config.getConfigName()); + response.setDescription(config.getDescription()); + response.setSortOrder(config.getSortOrder()); + return response; + } +}