diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-api.ts.vm b/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-api.ts.vm index 0647d0cb..e3b199a4 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-api.ts.vm +++ b/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-api.ts.vm @@ -53,13 +53,13 @@ export interface ${vue.featureEntity}QueryRequest extends Pagination { export interface ${vue.featureEntity}QueryResponse extends TableData { #foreach($field in ${table.fields}) #if("$field.propertyType" == "String") - ${field.propertyName}?: string; + ${field.propertyName}: string; #elseif("$field.propertyType" == "Integer" || "$field.propertyType" == "Long" || "$field.propertyType" == "Date") - ${field.propertyName}?: number; + ${field.propertyName}: number; #elseif("$field.propertyType" == "Boolean") - ${field.propertyName}?: boolean; + ${field.propertyName}: boolean; #else - ${field.propertyName}?: any; + ${field.propertyName}: any; #end #end createTime: number; diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-redis/src/main/java/com/orion/ops/framework/redis/core/utils/RedisUtils.java b/orion-ops-framework/orion-ops-spring-boot-starter-redis/src/main/java/com/orion/ops/framework/redis/core/utils/RedisUtils.java index 0235329e..96d4466a 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-redis/src/main/java/com/orion/ops/framework/redis/core/utils/RedisUtils.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-redis/src/main/java/com/orion/ops/framework/redis/core/utils/RedisUtils.java @@ -9,8 +9,8 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ScanOptions; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; /** @@ -92,7 +92,7 @@ public class RedisUtils { * * @param keys keys */ - public static void delete(List keys) { + public static void delete(Collection keys) { redisTemplate.delete(keys); } diff --git a/orion-ops-launch/src/main/resources/application.yaml b/orion-ops-launch/src/main/resources/application.yaml index 8bab7805..fc088a57 100644 --- a/orion-ops-launch/src/main/resources/application.yaml +++ b/orion-ops-launch/src/main/resources/application.yaml @@ -161,7 +161,7 @@ orion: # 下面引用了 需要注意 field: ignore: - - password,beforePassword,newPassword,useNewPassword,publicKey,privateKey + - password,beforePassword,newPassword,useNewPassword,publicKey,privateKey,token - metrics desensitize: storage: diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/MineController.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/MineController.java index 3691735a..86367f5a 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/MineController.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/MineController.java @@ -6,7 +6,7 @@ import com.orion.ops.framework.log.core.annotation.IgnoreLog; import com.orion.ops.framework.log.core.enums.IgnoreLogMode; import com.orion.ops.framework.web.core.annotation.RestWrapper; import com.orion.ops.module.infra.define.operator.AuthenticationOperatorType; -import com.orion.ops.module.infra.entity.request.user.OfflineUserSessionRequest; +import com.orion.ops.module.infra.entity.request.user.UserSessionOfflineRequest; import com.orion.ops.module.infra.entity.request.user.SystemUserUpdateRequest; import com.orion.ops.module.infra.entity.request.user.UserUpdatePasswordRequest; import com.orion.ops.module.infra.entity.vo.LoginHistoryVO; @@ -79,12 +79,11 @@ public class MineController { @IgnoreLog(IgnoreLogMode.RET) @PutMapping("/offline-session") @Operation(summary = "下线当前用户会话") - public HttpWrapper offlineCurrentUserSession(@Validated @RequestBody OfflineUserSessionRequest request) { + public HttpWrapper offlineCurrentUserSession(@Validated @RequestBody UserSessionOfflineRequest request) { mineService.offlineCurrentUserSession(request); return HttpWrapper.ok(); } - // fixme 全部用户接口进行 设置缓存 // fixme 操作日志 } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemRoleController.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemRoleController.java index 27c01397..99e2d8a5 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemRoleController.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemRoleController.java @@ -99,6 +99,7 @@ public class SystemRoleController { @GetMapping("/get-menu-id") @Operation(summary = "获取角色菜单id") + @Parameter(name = "roleId", description = "roleId", required = true) @PreAuthorize("@ss.hasPermission('infra:system-role:query')") public List getRoleMenuIdList(@RequestParam("roleId") Long roleId) { return systemRoleMenuService.getRoleMenuIdList(roleId); diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemUserController.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemUserController.java index e3c6ce67..ae3841b1 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemUserController.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemUserController.java @@ -110,7 +110,7 @@ public class SystemUserController { @Operation(summary = "查询所有用户") @PreAuthorize("@ss.hasPermission('infra:system-user:query')") public List getSystemUserList() { - return systemUserService.getSystemUserByIdList(); + return systemUserService.getSystemUserList(); } @IgnoreLog(IgnoreLogMode.RET) @@ -150,7 +150,7 @@ public class SystemUserController { @IgnoreLog(IgnoreLogMode.RET) @PutMapping("/offline-session") @Operation(summary = "下线用户会话") - public HttpWrapper offlineUserSession(@Validated @RequestBody OfflineUserSessionRequest request) { + public HttpWrapper offlineUserSession(@Validated @RequestBody UserSessionOfflineRequest request) { systemUserService.offlineUserSession(request); return HttpWrapper.ok(); } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/convert/SystemUserConvert.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/convert/SystemUserConvert.java index 12ae921a..24aa9047 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/convert/SystemUserConvert.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/convert/SystemUserConvert.java @@ -2,6 +2,7 @@ package com.orion.ops.module.infra.convert; import com.orion.ops.framework.common.security.LoginUser; import com.orion.ops.module.infra.entity.domain.SystemUserDO; +import com.orion.ops.module.infra.entity.dto.UserInfoDTO; import com.orion.ops.module.infra.entity.request.user.SystemUserCreateRequest; import com.orion.ops.module.infra.entity.request.user.SystemUserQueryRequest; import com.orion.ops.module.infra.entity.request.user.SystemUserUpdateRequest; @@ -35,10 +36,14 @@ public interface SystemUserConvert { SystemUserVO to(SystemUserDO domain); + SystemUserVO to(UserInfoDTO user); + List to(List list); LoginUser toLoginUser(SystemUserDO domain); + UserInfoDTO toUserInfo(SystemUserDO domain); + UserCollectInfoVO toCollectInfo(LoginUser user); } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/cache/UserCacheKeyDefine.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/cache/UserCacheKeyDefine.java index 322af55d..be220b9a 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/cache/UserCacheKeyDefine.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/cache/UserCacheKeyDefine.java @@ -4,6 +4,7 @@ import com.orion.lang.define.cache.CacheKeyBuilder; import com.orion.lang.define.cache.CacheKeyDefine; import com.orion.ops.framework.common.security.LoginUser; import com.orion.ops.module.infra.entity.dto.LoginTokenDTO; +import com.orion.ops.module.infra.entity.dto.UserInfoDTO; import java.util.concurrent.TimeUnit; @@ -22,9 +23,17 @@ public interface UserCacheKeyDefine { .type(LoginUser.class) .build(); + CacheKeyDefine USER_LIST = new CacheKeyBuilder() + .key("user:list:{}") + .desc("用户列表") + .type(UserInfoDTO.class) + .timeout(1, TimeUnit.DAYS) + .build(); + CacheKeyDefine LOGIN_FAILED_COUNT = new CacheKeyBuilder() .key("user:failed:{}") .desc("用户登录失败次数 ${username}") + .type(Integer.class) .timeout(3, TimeUnit.DAYS) .build(); diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/dto/UserInfoDTO.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/dto/UserInfoDTO.java new file mode 100644 index 00000000..6f1aee9d --- /dev/null +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/dto/UserInfoDTO.java @@ -0,0 +1,48 @@ +package com.orion.ops.module.infra.entity.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 用户信息 缓存对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023-7-13 18:42 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "UserInfoDTO", description = "用户信息 缓存对象") +public class UserInfoDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "花名") + private String nickname; + + @Schema(description = "头像地址") + private String avatar; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "用户状态 0停用 1启用 2锁定") + private Integer status; + +} diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/user/OfflineUserSessionRequest.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/user/UserSessionOfflineRequest.java similarity index 72% rename from orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/user/OfflineUserSessionRequest.java rename to orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/user/UserSessionOfflineRequest.java index c276777b..d84d2264 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/user/OfflineUserSessionRequest.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/user/UserSessionOfflineRequest.java @@ -6,15 +6,15 @@ import lombok.Data; import javax.validation.constraints.NotNull; /** - * 用户下线请求 + * 用户会话下线请求 * * @author Jiahang Li * @version 1.0.0 * @since 2023/7/17 12:19 */ @Data -@Schema(name = "OfflineUserSessionRequest", description = "用户下线请求") -public class OfflineUserSessionRequest { +@Schema(name = "UserSessionOfflineRequest", description = "用户会话下线请求") +public class UserSessionOfflineRequest { @Schema(description = "userId") private Long userId; diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/MineService.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/MineService.java index 449a31d1..d77a7a46 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/MineService.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/MineService.java @@ -1,6 +1,6 @@ package com.orion.ops.module.infra.service; -import com.orion.ops.module.infra.entity.request.user.OfflineUserSessionRequest; +import com.orion.ops.module.infra.entity.request.user.UserSessionOfflineRequest; import com.orion.ops.module.infra.entity.request.user.SystemUserUpdateRequest; import com.orion.ops.module.infra.entity.request.user.UserUpdatePasswordRequest; import com.orion.ops.module.infra.entity.vo.LoginHistoryVO; @@ -59,6 +59,6 @@ public interface MineService { * * @param request request */ - void offlineCurrentUserSession(OfflineUserSessionRequest request); + void offlineCurrentUserSession(UserSessionOfflineRequest request); } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/SystemUserService.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/SystemUserService.java index 8c8b6649..6a8c9948 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/SystemUserService.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/SystemUserService.java @@ -53,7 +53,7 @@ public interface SystemUserService { * * @return rows */ - List getSystemUserByIdList(); + List getSystemUserList(); /** * 分页查询用户 @@ -74,9 +74,10 @@ public interface SystemUserService { /** * 删除 id 删除用户拓展信息 * - * @param id id + * @param id id + * @param username username */ - void deleteSystemUserRel(Long id); + void deleteSystemUserRel(Long id, String username); /** * 重置密码 @@ -98,6 +99,6 @@ public interface SystemUserService { * * @param request request */ - void offlineUserSession(OfflineUserSessionRequest request); + void offlineUserSession(UserSessionOfflineRequest request); } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/MineServiceImpl.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/MineServiceImpl.java index 73e84e60..bb956b6b 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/MineServiceImpl.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/MineServiceImpl.java @@ -6,7 +6,7 @@ import com.orion.ops.framework.common.utils.Valid; import com.orion.ops.framework.security.core.utils.SecurityUtils; import com.orion.ops.module.infra.dao.SystemUserDAO; import com.orion.ops.module.infra.entity.domain.SystemUserDO; -import com.orion.ops.module.infra.entity.request.user.OfflineUserSessionRequest; +import com.orion.ops.module.infra.entity.request.user.UserSessionOfflineRequest; import com.orion.ops.module.infra.entity.request.user.SystemUserUpdateRequest; import com.orion.ops.module.infra.entity.request.user.UserResetPasswordRequest; import com.orion.ops.module.infra.entity.request.user.UserUpdatePasswordRequest; @@ -81,7 +81,7 @@ public class MineServiceImpl implements MineService { } @Override - public void offlineCurrentUserSession(OfflineUserSessionRequest request) { + public void offlineCurrentUserSession(UserSessionOfflineRequest request) { request.setUserId(SecurityUtils.getLoginUserId()); systemUserService.offlineUserSession(request); } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/SystemUserServiceImpl.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/SystemUserServiceImpl.java index 4973cc36..2661c420 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/SystemUserServiceImpl.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/SystemUserServiceImpl.java @@ -6,10 +6,12 @@ import com.orion.lang.define.wrapper.DataGrid; import com.orion.lang.utils.collect.Lists; import com.orion.lang.utils.crypto.Signatures; import com.orion.ops.framework.biz.operator.log.core.uitls.OperatorLogs; +import com.orion.ops.framework.common.constant.Const; import com.orion.ops.framework.common.constant.ErrorCode; import com.orion.ops.framework.common.constant.ErrorMessage; import com.orion.ops.framework.common.security.LoginUser; import com.orion.ops.framework.common.utils.Valid; +import com.orion.ops.framework.redis.core.utils.RedisMaps; import com.orion.ops.framework.redis.core.utils.RedisStrings; import com.orion.ops.framework.redis.core.utils.RedisUtils; import com.orion.ops.framework.security.core.utils.SecurityUtils; @@ -21,9 +23,11 @@ import com.orion.ops.module.infra.define.cache.TipsCacheKeyDefine; import com.orion.ops.module.infra.define.cache.UserCacheKeyDefine; import com.orion.ops.module.infra.entity.domain.SystemUserDO; import com.orion.ops.module.infra.entity.dto.LoginTokenDTO; +import com.orion.ops.module.infra.entity.dto.UserInfoDTO; import com.orion.ops.module.infra.entity.request.user.*; import com.orion.ops.module.infra.entity.vo.SystemUserVO; import com.orion.ops.module.infra.entity.vo.UserSessionVO; +import com.orion.ops.module.infra.enums.LoginTokenStatusEnum; import com.orion.ops.module.infra.enums.UserStatusEnum; import com.orion.ops.module.infra.service.AuthenticationService; import com.orion.ops.module.infra.service.FavoriteService; @@ -31,7 +35,6 @@ import com.orion.ops.module.infra.service.PreferenceService; import com.orion.ops.module.infra.service.SystemUserService; import com.orion.spring.SpringHolder; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @@ -68,9 +71,6 @@ public class SystemUserServiceImpl implements SystemUserService { @Resource private PreferenceService preferenceService; - @Resource - private RedisTemplate redisTemplate; - @Override public Long createSystemUser(SystemUserCreateRequest request) { // 转换 @@ -82,6 +82,8 @@ public class SystemUserServiceImpl implements SystemUserService { // 插入 int effect = systemUserDAO.insert(record); log.info("SystemUserService-createSystemUser effect: {}, record: {}", effect, JSON.toJSONString(record)); + // 删除用户列表缓存 + RedisUtils.delete(UserCacheKeyDefine.USER_LIST); return record.getId(); } @@ -104,6 +106,8 @@ public class SystemUserServiceImpl implements SystemUserService { RedisStrings.processSetJson(UserCacheKeyDefine.USER_INFO, s -> { s.setNickname(request.getNickname()); }, id); + // 删除用户列表缓存 + RedisUtils.delete(UserCacheKeyDefine.USER_LIST); return effect; } @@ -131,12 +135,14 @@ public class SystemUserServiceImpl implements SystemUserService { log.info("SystemUserService-updateUserStatus effect: {}, updateRecord: {}", effect, JSON.toJSONString(updateRecord)); // 如果之前是锁定则删除登录失败次数缓存 if (UserStatusEnum.LOCKED.getStatus().equals(record.getStatus())) { - redisTemplate.delete(UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(record.getUsername())); + RedisUtils.delete(UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(record.getUsername())); } - // 更新缓存中的status + // 更新用户缓存中的 status RedisStrings.processSetJson(UserCacheKeyDefine.USER_INFO, s -> { s.setStatus(request.getStatus()); }, id); + // 删除用户列表缓存 + RedisUtils.delete(UserCacheKeyDefine.USER_LIST); return effect; } @@ -150,14 +156,28 @@ public class SystemUserServiceImpl implements SystemUserService { } @Override - public List getSystemUserByIdList() { - // 查询 - List records = systemUserDAO.selectList(null); - if (records.isEmpty()) { - return Lists.empty(); + public List getSystemUserList() { + // fixme test + // 查询用户列表 + List list = RedisMaps.valuesJson(UserCacheKeyDefine.USER_LIST); + if (list.isEmpty()) { + // 查询数据库 + list = systemUserDAO.of().list(SystemUserConvert.MAPPER::toUserInfo); + // 添加默认值 防止穿透 + if (list.isEmpty()) { + list.add(UserInfoDTO.builder() + .id(Const.NONE_ID) + .build()); + } + // 设置缓存 + RedisMaps.putAllJson(UserCacheKeyDefine.USER_LIST.getKey(), s -> s.getId().toString(), list); + RedisMaps.setExpire(UserCacheKeyDefine.USER_LIST); } - // 转换 - return SystemUserConvert.MAPPER.to(records); + // 删除默认值 + return list.stream() + .filter(s -> !s.getId().equals(Const.NONE_ID)) + .map(SystemUserConvert.MAPPER::to) + .collect(Collectors.toList()); } @Override @@ -190,21 +210,26 @@ public class SystemUserServiceImpl implements SystemUserService { int effect = systemUserDAO.deleteById(id); log.info("SystemUserService-deleteSystemUserById id: {}, effect: {}", id, effect); // 异步删除额外信息 - SpringHolder.getBean(SystemUserService.class).deleteSystemUserRel(id); + SpringHolder.getBean(SystemUserService.class).deleteSystemUserRel(id, record.getUsername()); return effect; } @Override @Async("asyncExecutor") - public void deleteSystemUserRel(Long id) { + public void deleteSystemUserRel(Long id, String username) { log.info("SystemUserService-deleteSystemUserRel id: {}", id); + // 删除用户列表缓存 + // FIXME test + RedisMaps.delete(UserCacheKeyDefine.USER_LIST, id); // 删除用户缓存 需要扫描的 key 让其自动过期 - redisTemplate.delete(Lists.of( + RedisUtils.delete( // 用户缓存 UserCacheKeyDefine.USER_INFO.format(id), + // 登录失败次数 + UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(username), // 用户提示 TipsCacheKeyDefine.TIPS.format(id) - )); + ); // 删除角色关联 systemUserRoleDAO.deleteByUserId(id); // 删除操作日志 @@ -230,19 +255,19 @@ public class SystemUserServiceImpl implements SystemUserService { int effect = systemUserDAO.updateById(update); log.info("SystemUserService-resetPassword record: {}, effect: {}", JSON.toJSONString(update), effect); // 删除登录失败次数缓存 - redisTemplate.delete(UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(record.getUsername())); + RedisUtils.delete(UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(record.getUsername())); // 删除登录缓存 String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, "*"); Set loginKeyList = RedisUtils.scanKeys(loginKey); if (!loginKeyList.isEmpty()) { - redisTemplate.delete(loginKeyList); + RedisUtils.delete(loginKeyList); } // 删除续签信息 if (AuthenticationService.allowRefresh) { String refreshKey = UserCacheKeyDefine.LOGIN_REFRESH.format(id, "*"); Set refreshKeyList = RedisUtils.scanKeys(refreshKey); if (!refreshKeyList.isEmpty()) { - redisTemplate.delete(refreshKeyList); + RedisUtils.delete(refreshKeyList); } } } @@ -259,22 +284,25 @@ public class SystemUserServiceImpl implements SystemUserService { if (Lists.isEmpty(tokens)) { return Lists.empty(); } + final boolean isCurrentUser = userId.equals(SecurityUtils.getLoginUserId()); // 返回 return tokens.stream() + .filter(s -> LoginTokenStatusEnum.OK.getStatus().equals(s.getStatus())) .map(LoginTokenDTO::getOrigin) .map(s -> UserSessionVO.builder() - .current(s.getLoginTime().equals(SecurityUtils.getLoginTimestamp())) + .current(isCurrentUser && s.getLoginTime().equals(SecurityUtils.getLoginTimestamp())) .address(s.getAddress()) .location(s.getLocation()) .userAgent(s.getUserAgent()) .loginTime(new Date(s.getLoginTime())) .build()) - .sorted(Comparator.comparing(UserSessionVO::getLoginTime).reversed()) + .sorted(Comparator.comparing(UserSessionVO::getCurrent).reversed() + .thenComparing(Comparator.comparing(UserSessionVO::getLoginTime).reversed())) .collect(Collectors.toList()); } @Override - public void offlineUserSession(OfflineUserSessionRequest request) { + public void offlineUserSession(UserSessionOfflineRequest request) { Long userId = Valid.notNull(request.getUserId()); Long timestamp = request.getTimestamp(); RedisStrings.delete( diff --git a/orion-ops-ui/src/api/asset/host-identity.ts b/orion-ops-ui/src/api/asset/host-identity.ts index a0536a40..3e0fb2a3 100644 --- a/orion-ops-ui/src/api/asset/host-identity.ts +++ b/orion-ops-ui/src/api/asset/host-identity.ts @@ -35,11 +35,11 @@ export interface HostIdentityQueryRequest extends Pagination { * 主机身份查询响应 */ export interface HostIdentityQueryResponse extends TableData { - id?: number; - name?: string; - username?: string; - password?: string; - keyId?: number; + id: number; + name: string; + username: string; + password: string; + keyId: number; createTime: number; updateTime: number; creator: string; diff --git a/orion-ops-ui/src/api/asset/host-key.ts b/orion-ops-ui/src/api/asset/host-key.ts index 3bdf3f8d..73db51d4 100644 --- a/orion-ops-ui/src/api/asset/host-key.ts +++ b/orion-ops-ui/src/api/asset/host-key.ts @@ -35,11 +35,11 @@ export interface HostKeyQueryRequest extends Pagination { * 主机秘钥查询响应 */ export interface HostKeyQueryResponse extends TableData { - id?: number; - name?: string; - publicKey?: string; - privateKey?: string; - password?: string; + id: number; + name: string; + publicKey: string; + privateKey: string; + password: string; createTime: number; updateTime: number; } diff --git a/orion-ops-ui/src/api/asset/host.ts b/orion-ops-ui/src/api/asset/host.ts index a80e07c7..297ce528 100644 --- a/orion-ops-ui/src/api/asset/host.ts +++ b/orion-ops-ui/src/api/asset/host.ts @@ -38,10 +38,10 @@ export interface HostQueryRequest extends Pagination { * 主机查询响应 */ export interface HostQueryResponse extends TableData { - id?: number; - name?: string; - code?: string; - address?: string; + id: number; + name: string; + code: string; + address: string; createTime: number; updateTime: number; creator: string; diff --git a/orion-ops-ui/src/api/meta/history-value.ts b/orion-ops-ui/src/api/meta/history-value.ts index 9867b141..8bcb0247 100644 --- a/orion-ops-ui/src/api/meta/history-value.ts +++ b/orion-ops-ui/src/api/meta/history-value.ts @@ -15,9 +15,9 @@ export interface HistoryValueQueryRequest extends Pagination { * 历史归档查询响应 */ export interface HistoryValueQueryResponse extends TableData { - id?: number; - beforeValue?: string; - afterValue?: string; + id: number; + beforeValue: string; + afterValue: string; createTime: number; creator: string; } diff --git a/orion-ops-ui/src/api/system/dict-key.ts b/orion-ops-ui/src/api/system/dict-key.ts index 0301e82d..0595f98b 100644 --- a/orion-ops-ui/src/api/system/dict-key.ts +++ b/orion-ops-ui/src/api/system/dict-key.ts @@ -34,11 +34,11 @@ export interface DictKeyQueryRequest extends Pagination { * 字典配置项查询响应 */ export interface DictKeyQueryResponse extends TableData { - id?: number; - keyName?: string; - valueType?: string; - extraSchema?: string; - description?: string; + id: number; + keyName: string; + valueType: string; + extraSchema: string; + description: string; } /** diff --git a/orion-ops-ui/src/api/system/dict-value.ts b/orion-ops-ui/src/api/system/dict-value.ts index 3ec62e77..2de4f3cc 100644 --- a/orion-ops-ui/src/api/system/dict-value.ts +++ b/orion-ops-ui/src/api/system/dict-value.ts @@ -48,14 +48,14 @@ export interface DictValueQueryRequest extends Pagination { * 字典配置值查询响应 */ export interface DictValueQueryResponse extends TableData { - id?: number; - keyId?: number; - keyName?: string; - keyDescription?: string; - value?: string; - label?: string; - extra?: string; - sort?: number; + id: number; + keyId: number; + keyName: string; + keyDescription: string; + value: string; + label: string; + extra: string; + sort: number; createTime: number; updateTime: number; creator: string; diff --git a/orion-ops-ui/src/api/system/menu.ts b/orion-ops-ui/src/api/system/menu.ts index 99de3abd..65527fca 100644 --- a/orion-ops-ui/src/api/system/menu.ts +++ b/orion-ops-ui/src/api/system/menu.ts @@ -37,25 +37,25 @@ export interface MenuQueryRequest { * 菜单查询响应 */ export interface MenuQueryResponse extends TableData { - id?: number; - parentId?: number; - name?: string; - permission?: string; - type?: number; - sort?: number; - visible?: number; - status?: number; - cache?: number; - icon?: string; - path?: string; - component?: string; - children?: Array; + id: number; + parentId: number; + name: string; + permission: string; + type: number; + sort: number; + visible: number; + status: number; + cache: number; + icon: string; + path: string; + component: string; + children: Array; } /** * 查询菜单列表 */ -export function getMenuList(request?: MenuQueryRequest) { +export function getMenuList(request: MenuQueryRequest) { return axios.post('/infra/system-menu/list', request); } diff --git a/orion-ops-ui/src/api/user/mine.ts b/orion-ops-ui/src/api/user/mine.ts index 9fe489bf..c232c056 100644 --- a/orion-ops-ui/src/api/user/mine.ts +++ b/orion-ops-ui/src/api/user/mine.ts @@ -1,5 +1,5 @@ import type { LoginHistoryQueryResponse } from './operator-log'; -import type { UserQueryResponse, UserUpdateRequest } from './user'; +import type { UserQueryResponse, UserSessionQueryResponse, UserSessionOfflineRequest, UserUpdateRequest } from './user'; import axios from 'axios'; /** @@ -38,3 +38,16 @@ export function getCurrentLoginHistory() { return axios.get('/infra/mine/login-history'); } +/** + * 获取当前用户会话列表 + */ +export function getCurrentUserSessionList() { + return axios.get('/infra/mine/user-session'); +} + +/** + * 下线当前用户会话 + */ +export function offlineCurrentUserSession(request: UserSessionOfflineRequest) { + return axios.put('/infra/mine/offline-session', request); +} diff --git a/orion-ops-ui/src/api/user/operator-log.ts b/orion-ops-ui/src/api/user/operator-log.ts index fd82bf78..ca5094c0 100644 --- a/orion-ops-ui/src/api/user/operator-log.ts +++ b/orion-ops-ui/src/api/user/operator-log.ts @@ -30,6 +30,7 @@ export interface OperatorLogQueryResponse { module: string; type: string; logInfo: string; + originLogInfo: string; extra: string; result: number; errorMessage: string; diff --git a/orion-ops-ui/src/api/user/role.ts b/orion-ops-ui/src/api/user/role.ts index 9d352133..772475fa 100644 --- a/orion-ops-ui/src/api/user/role.ts +++ b/orion-ops-ui/src/api/user/role.ts @@ -40,10 +40,10 @@ export interface RoleQueryRequest extends Pagination { * 角色查询响应 */ export interface RoleQueryResponse extends TableData { - id?: number; - name?: string; - code?: string; - status?: number; + id: number; + name: string; + code: string; + status: number; createTime: number; updateTime: number; creator: string; diff --git a/orion-ops-ui/src/api/user/user.ts b/orion-ops-ui/src/api/user/user.ts index 366adf9d..a1bfc611 100644 --- a/orion-ops-ui/src/api/user/user.ts +++ b/orion-ops-ui/src/api/user/user.ts @@ -42,13 +42,13 @@ export interface UserQueryRequest extends Pagination { * 用户查询响应 */ export interface UserQueryResponse extends TableData { - id?: number; - username?: string; - nickname?: string; - avatar?: string; - mobile?: string; - email?: string; - status?: number; + id: number; + username: string; + nickname: string; + avatar: string; + mobile: string; + email: string; + status: number; lastLoginTime?: number; createTime: number; updateTime: number; @@ -56,6 +56,26 @@ export interface UserQueryResponse extends TableData { updater: string; } +/** + * 用户会话查询响应 + */ +export interface UserSessionQueryResponse { + visible: boolean; + current: boolean; + address: string; + location: string; + userAgent: string; + loginTime: number; +} + +/** + * 用户会话下线请求 + */ +export interface UserSessionOfflineRequest { + userId?: number; + timestamp: number; +} + /** * 创建用户 */ diff --git a/orion-ops-ui/src/assets/style/layout.less b/orion-ops-ui/src/assets/style/layout.less index d050ba2b..d0628e77 100644 --- a/orion-ops-ui/src/assets/style/layout.less +++ b/orion-ops-ui/src/assets/style/layout.less @@ -122,6 +122,18 @@ cursor: pointer; } +.mx0 { + margin: 0 0; +} + +.mx2 { + margin: 0 2px; +} + +.mx4 { + margin: 0 4px; +} + .ml4 { margin-left: 4px; } diff --git a/orion-ops-ui/src/components/user/role/user-selector.vue b/orion-ops-ui/src/components/user/role/user-selector.vue new file mode 100644 index 00000000..13f47191 --- /dev/null +++ b/orion-ops-ui/src/components/user/role/user-selector.vue @@ -0,0 +1,61 @@ + + + + + + + diff --git a/orion-ops-ui/src/views/system/dict-key/components/dict-key-view-modal.vue b/orion-ops-ui/src/components/view/json/json-view-modal.vue similarity index 53% rename from orion-ops-ui/src/views/system/dict-key/components/dict-key-view-modal.vue rename to orion-ops-ui/src/components/view/json/json-view-modal.vue index 57a99700..98e8c061 100644 --- a/orion-ops-ui/src/views/system/dict-key/components/dict-key-view-modal.vue +++ b/orion-ops-ui/src/components/view/json/json-view-modal.vue @@ -1,7 +1,7 @@ diff --git a/orion-ops-ui/src/views/user/info/components/user-session.vue b/orion-ops-ui/src/views/user/info/components/user-session.vue new file mode 100644 index 00000000..fdddc68c --- /dev/null +++ b/orion-ops-ui/src/views/user/info/components/user-session.vue @@ -0,0 +1,150 @@ + + + + + + + diff --git a/orion-ops-ui/src/views/user/info/index.vue b/orion-ops-ui/src/views/user/info/index.vue index 3f0ee171..0766e868 100644 --- a/orion-ops-ui/src/views/user/info/index.vue +++ b/orion-ops-ui/src/views/user/info/index.vue @@ -15,10 +15,11 @@ - + + @@ -33,6 +34,8 @@ diff --git a/orion-ops-ui/src/views/user/operator-log/components/operator-log-table.vue b/orion-ops-ui/src/views/user/operator-log/components/operator-log-table.vue new file mode 100644 index 00000000..fe18d778 --- /dev/null +++ b/orion-ops-ui/src/views/user/operator-log/components/operator-log-table.vue @@ -0,0 +1,139 @@ + + + + + + + diff --git a/orion-ops-ui/src/views/user/operator-log/index.vue b/orion-ops-ui/src/views/user/operator-log/index.vue new file mode 100644 index 00000000..dddfbdc3 --- /dev/null +++ b/orion-ops-ui/src/views/user/operator-log/index.vue @@ -0,0 +1,71 @@ + + + + + + + diff --git a/orion-ops-ui/src/views/user/operator-log/types/const.ts b/orion-ops-ui/src/views/user/operator-log/types/const.ts new file mode 100644 index 00000000..ef0d1bd2 --- /dev/null +++ b/orion-ops-ui/src/views/user/operator-log/types/const.ts @@ -0,0 +1,24 @@ +// 结果状态 +export const ResultStatus = { + // 失败 + FAILED: 0, + // 成功 + SUCCESS: 1, +}; + +// 操作日志模块 字典项 +export const operatorLogModuleKey = 'operatorLogModule'; + +// 操作日志类型 字典项 +export const operatorLogTypeKey = 'operatorLogType'; + +// 操作风险等级 字典项 +export const operatorRiskLevelKey = 'operatorRiskLevel'; + +// 操作日志结果 字典项 +export const operatorLogResultKey = 'operatorLogResult'; + +// 加载的字典值 +export const dictKeys = [operatorLogModuleKey, operatorLogTypeKey, operatorRiskLevelKey, operatorLogResultKey]; + + diff --git a/orion-ops-ui/src/views/user/operator-log/types/table.columns.ts b/orion-ops-ui/src/views/user/operator-log/types/table.columns.ts new file mode 100644 index 00000000..4711e5c5 --- /dev/null +++ b/orion-ops-ui/src/views/user/operator-log/types/table.columns.ts @@ -0,0 +1,69 @@ +import type { TableColumnData } from '@arco-design/web-vue/es/table/interface'; +import { dateFormat } from '@/utils'; + +const columns = [ + { + title: 'id', + dataIndex: 'id', + slotName: 'id', + width: 70, + align: 'left', + fixed: 'left', + }, { + title: '操作用户', + dataIndex: 'username', + slotName: 'username', + width: 120, + ellipsis: true, + tooltip: true, + }, { + title: '操作模块', + dataIndex: 'module', + slotName: 'module', + width: 120, + ellipsis: true, + tooltip: true, + }, { + title: '操作类型', + dataIndex: 'type', + slotName: 'type', + width: 150, + ellipsis: true, + tooltip: true, + }, { + title: '风险等级', + dataIndex: 'riskLevel', + slotName: 'riskLevel', + width: 90, + align: 'center', + }, { + title: '执行结果', + dataIndex: 'result', + slotName: 'result', + width: 90, + align: 'center', + }, { + title: '操作日志', + dataIndex: 'originLogInfo', + slotName: 'originLogInfo', + ellipsis: true, + tooltip: true, + }, { + title: '创建时间', + dataIndex: 'createTime', + slotName: 'createTime', + align: 'center', + width: 180, + render: ({ record }) => { + return dateFormat(new Date(record.createTime)); + }, + }, { + title: '操作', + slotName: 'handle', + width: 90, + align: 'center', + fixed: 'right', + }, +] as TableColumnData[]; + +export default columns; diff --git a/orion-ops-ui/tsconfig.json b/orion-ops-ui/tsconfig.json index c025998c..c7b9679d 100644 --- a/orion-ops-ui/tsconfig.json +++ b/orion-ops-ui/tsconfig.json @@ -12,7 +12,7 @@ "paths": { "@/*": ["src/*"] }, - "lib": ["es2020", "dom"], + "lib": ["es2021", "dom"], "skipLibCheck": true }, "include": ["src/**/*", "src/**/*.vue"],