add online monitor and fix admin scopes
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package com.xspaceagi.sandbox.application.dto;
|
||||
|
||||
import com.xspaceagi.system.infra.dao.entity.User;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "在线监控聚合信息")
|
||||
@Data
|
||||
public class OnlineMonitorDto {
|
||||
|
||||
@Schema(description = "客户端总数")
|
||||
private long totalClientCount;
|
||||
|
||||
@Schema(description = "在线客户端数")
|
||||
private long onlineClientCount;
|
||||
|
||||
@Schema(description = "离线客户端数")
|
||||
private long offlineClientCount;
|
||||
|
||||
@Schema(description = "已停用客户端数")
|
||||
private long inactiveClientCount;
|
||||
|
||||
@Schema(description = "用户总数")
|
||||
private long totalUserCount;
|
||||
|
||||
@Schema(description = "启用用户数")
|
||||
private long enabledUserCount;
|
||||
|
||||
@Schema(description = "禁用用户数")
|
||||
private long disabledUserCount;
|
||||
|
||||
@Schema(description = "用户组监控信息")
|
||||
private List<GroupMonitorDto> groups;
|
||||
|
||||
@Schema(description = "用户监控信息")
|
||||
private List<UserMonitorDto> users;
|
||||
|
||||
@Schema(description = "客户端监控信息")
|
||||
private List<ClientMonitorDto> clients;
|
||||
|
||||
@Schema(description = "用户组监控信息")
|
||||
@Data
|
||||
public static class GroupMonitorDto {
|
||||
private Long groupId;
|
||||
private String groupName;
|
||||
private Integer authEnabled;
|
||||
private Integer status;
|
||||
private Date expireTime;
|
||||
private Integer maxUserCount;
|
||||
private long currentUserCount;
|
||||
private Integer maxClientCount;
|
||||
private long currentClientCount;
|
||||
private long onlineClientCount;
|
||||
private long offlineClientCount;
|
||||
private long inactiveClientCount;
|
||||
}
|
||||
|
||||
@Schema(description = "用户监控信息")
|
||||
@Data
|
||||
public static class UserMonitorDto {
|
||||
private Long userId;
|
||||
private String userName;
|
||||
private String nickName;
|
||||
private User.Role role;
|
||||
private User.Status status;
|
||||
private List<String> groupNames;
|
||||
private long clientCount;
|
||||
private long onlineClientCount;
|
||||
private long inactiveClientCount;
|
||||
private Date lastLoginTime;
|
||||
}
|
||||
|
||||
@Schema(description = "客户端监控信息")
|
||||
@Data
|
||||
public static class ClientMonitorDto {
|
||||
private Long id;
|
||||
private String name;
|
||||
private Long userId;
|
||||
private String userName;
|
||||
private String nickName;
|
||||
private Long groupId;
|
||||
private String groupName;
|
||||
private Boolean isActive;
|
||||
private boolean online;
|
||||
private Integer maxAgentCount;
|
||||
private Date created;
|
||||
private Date modified;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,23 @@
|
||||
package com.xspaceagi.sandbox.ui.web.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.xspaceagi.sandbox.application.dto.OnlineMonitorDto;
|
||||
import com.xspaceagi.sandbox.application.dto.SandboxConfigDto;
|
||||
import com.xspaceagi.sandbox.application.dto.SandboxConfigQueryDto;
|
||||
import com.xspaceagi.sandbox.application.dto.SandboxGlobalConfigDto;
|
||||
import com.xspaceagi.sandbox.application.service.SandboxConfigApplicationService;
|
||||
import com.xspaceagi.system.application.dto.UserDto;
|
||||
import com.xspaceagi.system.application.service.SysGroupApplicationService;
|
||||
import com.xspaceagi.system.application.service.SysRoleApplicationService;
|
||||
import com.xspaceagi.system.infra.dao.entity.SysGroup;
|
||||
import com.xspaceagi.system.infra.dao.entity.User;
|
||||
import com.xspaceagi.system.infra.dao.service.UserService;
|
||||
import com.xspaceagi.system.spec.annotation.RequireResource;
|
||||
import com.xspaceagi.system.spec.common.RequestContext;
|
||||
import com.xspaceagi.system.spec.dto.ReqResult;
|
||||
import com.xspaceagi.system.spec.enums.ErrorCodeEnum;
|
||||
import com.xspaceagi.system.spec.enums.GroupEnum;
|
||||
import com.xspaceagi.system.spec.enums.RoleEnum;
|
||||
import com.xspaceagi.system.spec.exception.BizException;
|
||||
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -21,7 +26,12 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -41,6 +51,12 @@ public class SandboxConfigManageController {
|
||||
@Resource
|
||||
private SysGroupApplicationService sysGroupApplicationService;
|
||||
|
||||
@Resource
|
||||
private SysRoleApplicationService sysRoleApplicationService;
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
@RequireResource(SANDBOX_CONFIG_QUERY)
|
||||
@Operation(summary = "分页查询配置列表")
|
||||
@PostMapping("/page")
|
||||
@@ -148,6 +164,154 @@ public class SandboxConfigManageController {
|
||||
return ReqResult.success(globalConfig);
|
||||
}
|
||||
|
||||
@RequireResource(ONLINE_MONITOR_QUERY)
|
||||
@Operation(summary = "查询在线监控信息")
|
||||
@GetMapping("/online-monitor")
|
||||
public ReqResult<OnlineMonitorDto> onlineMonitor() {
|
||||
boolean platformAdmin = isPlatformAdmin();
|
||||
List<SysGroup> groups = visibleGroups();
|
||||
Set<Long> groupIds = groups.stream().map(SysGroup::getId).collect(Collectors.toSet());
|
||||
|
||||
List<User> users = visibleUsers(platformAdmin, groupIds);
|
||||
Set<Long> userIds = users.stream().map(User::getId).collect(Collectors.toSet());
|
||||
|
||||
SandboxConfigQueryDto queryDto = new SandboxConfigQueryDto();
|
||||
queryDto.setPageNum(1);
|
||||
queryDto.setPageSize(100000);
|
||||
if (!platformAdmin && !groupIds.isEmpty()) {
|
||||
queryDto.setGroupIds(new ArrayList<>(groupIds));
|
||||
} else if (!platformAdmin) {
|
||||
queryDto.setGroupIds(List.of(-1L));
|
||||
}
|
||||
List<SandboxConfigDto> configs = sandboxConfigApplicationService.pageQuery(queryDto).getRecords().stream()
|
||||
.filter(config -> config.getUserId() != null)
|
||||
.filter(config -> platformAdmin || userIds.contains(config.getUserId()))
|
||||
.toList();
|
||||
|
||||
return ReqResult.success(buildOnlineMonitor(groups, users, configs));
|
||||
}
|
||||
|
||||
private OnlineMonitorDto buildOnlineMonitor(List<SysGroup> groups, List<User> users, List<SandboxConfigDto> configs) {
|
||||
Map<Long, SysGroup> groupMap = groups.stream()
|
||||
.filter(group -> group.getId() != null)
|
||||
.collect(Collectors.toMap(SysGroup::getId, group -> group, (a, b) -> a));
|
||||
Map<Long, User> userMap = users.stream()
|
||||
.filter(user -> user.getId() != null)
|
||||
.collect(Collectors.toMap(User::getId, user -> user, (a, b) -> a));
|
||||
Map<Long, List<SysGroup>> userGroupMap = new HashMap<>();
|
||||
groups.forEach(group -> sysGroupApplicationService.getUserListByGroupId(group.getId())
|
||||
.forEach(user -> userGroupMap.computeIfAbsent(user.getId(), key -> new ArrayList<>()).add(group)));
|
||||
|
||||
OnlineMonitorDto dto = new OnlineMonitorDto();
|
||||
dto.setTotalClientCount(configs.size());
|
||||
dto.setOnlineClientCount(configs.stream().filter(config -> Boolean.TRUE.equals(config.getIsActive()) && config.isOnline()).count());
|
||||
dto.setInactiveClientCount(configs.stream().filter(config -> !Boolean.TRUE.equals(config.getIsActive())).count());
|
||||
dto.setOfflineClientCount(configs.stream().filter(config -> Boolean.TRUE.equals(config.getIsActive()) && !config.isOnline()).count());
|
||||
dto.setTotalUserCount(users.size());
|
||||
dto.setEnabledUserCount(users.stream().filter(user -> user.getStatus() == User.Status.Enabled).count());
|
||||
dto.setDisabledUserCount(users.stream().filter(user -> user.getStatus() == User.Status.Disabled).count());
|
||||
|
||||
dto.setGroups(groups.stream()
|
||||
.map(group -> buildGroupMonitor(group, users, configs))
|
||||
.sorted(Comparator.comparing(OnlineMonitorDto.GroupMonitorDto::getGroupId, Comparator.nullsLast(Long::compareTo)))
|
||||
.toList());
|
||||
dto.setUsers(users.stream()
|
||||
.map(user -> buildUserMonitor(user, userGroupMap, configs))
|
||||
.sorted(Comparator.comparing(OnlineMonitorDto.UserMonitorDto::getUserId, Comparator.nullsLast(Long::compareTo)))
|
||||
.toList());
|
||||
dto.setClients(configs.stream()
|
||||
.map(config -> buildClientMonitor(config, userMap, groupMap))
|
||||
.sorted(Comparator.comparing(OnlineMonitorDto.ClientMonitorDto::getId, Comparator.nullsLast(Long::compareTo)))
|
||||
.toList());
|
||||
return dto;
|
||||
}
|
||||
|
||||
private OnlineMonitorDto.GroupMonitorDto buildGroupMonitor(SysGroup group, List<User> users, List<SandboxConfigDto> configs) {
|
||||
Set<Long> groupUserIds = sysGroupApplicationService.getUserListByGroupId(group.getId()).stream()
|
||||
.map(User::getId)
|
||||
.collect(Collectors.toSet());
|
||||
List<SandboxConfigDto> groupConfigs = configs.stream()
|
||||
.filter(config -> Objects.equals(config.getGroupId(), group.getId()))
|
||||
.toList();
|
||||
OnlineMonitorDto.GroupMonitorDto dto = new OnlineMonitorDto.GroupMonitorDto();
|
||||
dto.setGroupId(group.getId());
|
||||
dto.setGroupName(group.getName());
|
||||
dto.setAuthEnabled(group.getAuthEnabled());
|
||||
dto.setStatus(group.getStatus());
|
||||
dto.setExpireTime(group.getExpireTime());
|
||||
dto.setMaxUserCount(group.getMaxUserCount());
|
||||
dto.setCurrentUserCount(users.stream().filter(user -> groupUserIds.contains(user.getId())).count());
|
||||
dto.setMaxClientCount(group.getMaxClientCount());
|
||||
dto.setCurrentClientCount(groupConfigs.size());
|
||||
dto.setOnlineClientCount(groupConfigs.stream().filter(config -> Boolean.TRUE.equals(config.getIsActive()) && config.isOnline()).count());
|
||||
dto.setInactiveClientCount(groupConfigs.stream().filter(config -> !Boolean.TRUE.equals(config.getIsActive())).count());
|
||||
dto.setOfflineClientCount(groupConfigs.stream().filter(config -> Boolean.TRUE.equals(config.getIsActive()) && !config.isOnline()).count());
|
||||
return dto;
|
||||
}
|
||||
|
||||
private OnlineMonitorDto.UserMonitorDto buildUserMonitor(User user, Map<Long, List<SysGroup>> userGroupMap, List<SandboxConfigDto> configs) {
|
||||
List<SandboxConfigDto> userConfigs = configs.stream()
|
||||
.filter(config -> Objects.equals(config.getUserId(), user.getId()))
|
||||
.toList();
|
||||
OnlineMonitorDto.UserMonitorDto dto = new OnlineMonitorDto.UserMonitorDto();
|
||||
dto.setUserId(user.getId());
|
||||
dto.setUserName(user.getUserName());
|
||||
dto.setNickName(user.getNickName());
|
||||
dto.setRole(user.getRole());
|
||||
dto.setStatus(user.getStatus());
|
||||
dto.setGroupNames(userGroupMap.getOrDefault(user.getId(), List.of()).stream().map(SysGroup::getName).toList());
|
||||
dto.setClientCount(userConfigs.size());
|
||||
dto.setOnlineClientCount(userConfigs.stream().filter(config -> Boolean.TRUE.equals(config.getIsActive()) && config.isOnline()).count());
|
||||
dto.setInactiveClientCount(userConfigs.stream().filter(config -> !Boolean.TRUE.equals(config.getIsActive())).count());
|
||||
dto.setLastLoginTime(user.getLastLoginTime());
|
||||
return dto;
|
||||
}
|
||||
|
||||
private OnlineMonitorDto.ClientMonitorDto buildClientMonitor(SandboxConfigDto config, Map<Long, User> userMap, Map<Long, SysGroup> groupMap) {
|
||||
User user = userMap.get(config.getUserId());
|
||||
SysGroup group = groupMap.get(config.getGroupId());
|
||||
OnlineMonitorDto.ClientMonitorDto dto = new OnlineMonitorDto.ClientMonitorDto();
|
||||
dto.setId(config.getId());
|
||||
dto.setName(config.getName());
|
||||
dto.setUserId(config.getUserId());
|
||||
dto.setUserName(user == null ? null : user.getUserName());
|
||||
dto.setNickName(user == null ? null : user.getNickName());
|
||||
dto.setGroupId(config.getGroupId());
|
||||
dto.setGroupName(group == null ? null : group.getName());
|
||||
dto.setIsActive(config.getIsActive());
|
||||
dto.setOnline(config.isOnline());
|
||||
dto.setMaxAgentCount(config.getMaxAgentCount());
|
||||
dto.setCreated(config.getCreated());
|
||||
dto.setModified(config.getModified());
|
||||
return dto;
|
||||
}
|
||||
|
||||
private List<SysGroup> visibleGroups() {
|
||||
if (isPlatformAdmin()) {
|
||||
return sysGroupApplicationService.getGroupList(new SysGroup()).stream()
|
||||
.filter(group -> !GroupEnum.DEFAULT_GROUP.getCode().equals(group.getCode()))
|
||||
.toList();
|
||||
}
|
||||
Set<Long> groupIds = currentUserGroupIds();
|
||||
if (groupIds.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
return sysGroupApplicationService.listGroupsByIds(new ArrayList<>(groupIds));
|
||||
}
|
||||
|
||||
private List<User> visibleUsers(boolean platformAdmin, Set<Long> groupIds) {
|
||||
if (platformAdmin) {
|
||||
return userService.list().stream()
|
||||
.filter(user -> user.getStatus() != User.Status.Deleted)
|
||||
.toList();
|
||||
}
|
||||
return groupIds.stream()
|
||||
.flatMap(groupId -> sysGroupApplicationService.getUserListByGroupId(groupId).stream())
|
||||
.filter(user -> user.getStatus() != User.Status.Deleted)
|
||||
.collect(Collectors.toMap(User::getId, user -> user, (a, b) -> a))
|
||||
.values().stream().toList();
|
||||
}
|
||||
|
||||
private void applySandboxConfigManageScope(SandboxConfigQueryDto queryDto) {
|
||||
if (queryDto == null || isPlatformAdmin()) {
|
||||
return;
|
||||
@@ -172,13 +336,18 @@ public class SandboxConfigManageController {
|
||||
}
|
||||
|
||||
private Set<Long> currentUserGroupIds() {
|
||||
return sysGroupApplicationService.getEffectiveGroupListByUserId(getCurrentUserDto().getId()).stream()
|
||||
return sysGroupApplicationService.getGroupListByUserId(getCurrentUserDto().getId()).stream()
|
||||
.filter(group -> !GroupEnum.DEFAULT_GROUP.getCode().equals(group.getCode()))
|
||||
.map(SysGroup::getId)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private boolean isPlatformAdmin() {
|
||||
return getCurrentUserDto().getRole() == User.Role.Admin;
|
||||
UserDto currentUser = getCurrentUserDto();
|
||||
return currentUser.getRole() == User.Role.Admin
|
||||
&& (currentUserGroupIds().isEmpty()
|
||||
|| sysRoleApplicationService.getRoleListByUserId(currentUser.getId()).stream()
|
||||
.anyMatch(role -> RoleEnum.SUPER_ADMIN.getCode().equals(role.getCode())));
|
||||
}
|
||||
|
||||
private UserDto getCurrentUserDto() {
|
||||
|
||||
@@ -145,13 +145,22 @@
|
||||
"sortIndex": 16,
|
||||
"status": 1
|
||||
},
|
||||
{
|
||||
"code": "online_monitor",
|
||||
"name": "在线监控模块",
|
||||
"description": "在线监控模块",
|
||||
"source": 1,
|
||||
"type": 1,
|
||||
"sortIndex": 17,
|
||||
"status": 1
|
||||
},
|
||||
{
|
||||
"code": "category_config",
|
||||
"name": "分类管理模块",
|
||||
"description": "分类管理模块",
|
||||
"source": 1,
|
||||
"type": 1,
|
||||
"sortIndex": 17,
|
||||
"sortIndex": 18,
|
||||
"status": 1
|
||||
},
|
||||
{
|
||||
@@ -924,6 +933,16 @@
|
||||
"sortIndex": 1,
|
||||
"status": 1
|
||||
},
|
||||
{
|
||||
"code": "online_monitor_query",
|
||||
"name": "查询",
|
||||
"description": "查询在线监控",
|
||||
"source": 1,
|
||||
"type": 2,
|
||||
"parentCode": "online_monitor",
|
||||
"sortIndex": 1,
|
||||
"status": 1
|
||||
},
|
||||
{
|
||||
"code": "subscription_points_query",
|
||||
"name": "查询",
|
||||
@@ -2645,6 +2664,18 @@
|
||||
"sortIndex": 10,
|
||||
"status": 1
|
||||
},
|
||||
{
|
||||
"parentCode": "system_manage",
|
||||
"code": "online_monitor",
|
||||
"name": "在线监控",
|
||||
"description": "在线监控",
|
||||
"source": 1,
|
||||
"path": "/system/online-monitor",
|
||||
"openType": 1,
|
||||
"icon": "",
|
||||
"sortIndex": 11,
|
||||
"status": 1
|
||||
},
|
||||
{
|
||||
"parentCode": "workspace",
|
||||
"code": "member_setting",
|
||||
@@ -2664,7 +2695,7 @@
|
||||
"source": 1,
|
||||
"openType": 1,
|
||||
"icon": "",
|
||||
"sortIndex": 11,
|
||||
"sortIndex": 12,
|
||||
"status": 1
|
||||
},
|
||||
{
|
||||
@@ -2675,7 +2706,7 @@
|
||||
"source": 1,
|
||||
"openType": 1,
|
||||
"icon": "",
|
||||
"sortIndex": 12,
|
||||
"sortIndex": 13,
|
||||
"status": 1
|
||||
},
|
||||
{
|
||||
@@ -3203,6 +3234,11 @@
|
||||
"resourceCode": "sandbox_config",
|
||||
"resourceBindType": 1
|
||||
},
|
||||
{
|
||||
"menuCode": "online_monitor",
|
||||
"resourceCode": "online_monitor",
|
||||
"resourceBindType": 1
|
||||
},
|
||||
{
|
||||
"menuCode": "category_config",
|
||||
"resourceCode": "category_config",
|
||||
@@ -4016,6 +4052,17 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"roleCode": "super_admin",
|
||||
"menuCode": "online_monitor",
|
||||
"menuBindType": 1,
|
||||
"resourceTree": [
|
||||
{
|
||||
"code": "online_monitor",
|
||||
"resourceBindType": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"roleCode": "super_admin",
|
||||
"menuCode": "category_config",
|
||||
@@ -4354,4 +4401,4 @@
|
||||
"pageDailyPromptLimit": -1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,6 +267,11 @@ public enum ResourceEnum {
|
||||
SANDBOX_CONFIG_DELETE(ResourceTypeEnum.OPERATION, "sandbox_config_delete", "删除", "sandbox_config"),
|
||||
// SANDBOX_CONFIG_ENABLE(ResourceTypeEnum.OPERATION, "sandbox_config_enable", "启用/禁用", "sandbox_config"),
|
||||
|
||||
// ================== 在线监控模块 ==================
|
||||
ONLINE_MONITOR(ResourceTypeEnum.MODULE, "online_monitor", "在线监控模块", "root"),
|
||||
|
||||
ONLINE_MONITOR_QUERY(ResourceTypeEnum.OPERATION, "online_monitor_query", "查询", "online_monitor"),
|
||||
|
||||
// ================== 分类管理模块 ==================
|
||||
CATEGORY_CONFIG(ResourceTypeEnum.MODULE, "category_config", "分类管理模块", "root"),
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.xspaceagi.system.application.dto.UserDto;
|
||||
import com.xspaceagi.system.application.dto.UserQueryDto;
|
||||
import com.xspaceagi.system.application.service.NotifyMessageApplicationService;
|
||||
import com.xspaceagi.system.application.service.SysGroupApplicationService;
|
||||
import com.xspaceagi.system.application.service.SysRoleApplicationService;
|
||||
import com.xspaceagi.system.application.service.UserApplicationService;
|
||||
import com.xspaceagi.system.infra.dao.entity.SysGroup;
|
||||
import com.xspaceagi.system.infra.dao.entity.NotifyMessage;
|
||||
@@ -19,6 +20,7 @@ import com.xspaceagi.system.spec.dto.PageQueryVo;
|
||||
import com.xspaceagi.system.spec.dto.ReqResult;
|
||||
import com.xspaceagi.system.spec.enums.ErrorCodeEnum;
|
||||
import com.xspaceagi.system.spec.enums.GroupEnum;
|
||||
import com.xspaceagi.system.spec.enums.RoleEnum;
|
||||
import com.xspaceagi.system.spec.exception.BizException;
|
||||
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
|
||||
import com.xspaceagi.system.web.dto.UserAddDto;
|
||||
@@ -49,6 +51,9 @@ public class UserManageController {
|
||||
@Resource
|
||||
private SysGroupApplicationService sysGroupApplicationService;
|
||||
|
||||
@Resource
|
||||
private SysRoleApplicationService sysRoleApplicationService;
|
||||
|
||||
@Resource
|
||||
private NotifyMessageApplicationService notifyMessageApplicationService;
|
||||
|
||||
@@ -189,12 +194,16 @@ public class UserManageController {
|
||||
}
|
||||
|
||||
private void checkCurrentTenantUser(Long userId) {
|
||||
if (userId == null || userService.getById(userId) == null || !visibleUserIds().contains(userId)) {
|
||||
User user = userId == null ? null : userService.getById(userId);
|
||||
if (user == null || !isCurrentTenantUser(user) || (!isPlatformAdmin() && !visibleUserIds().contains(userId))) {
|
||||
throw BizException.of(ErrorCodeEnum.PERMISSION_DENIED, BizExceptionCodeEnum.permissionDenied);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyUserManageScope(PageQueryVo<UserQueryDto> pageQueryVo) {
|
||||
if (isPlatformAdmin()) {
|
||||
return;
|
||||
}
|
||||
if (pageQueryVo.getQueryFilter() == null) {
|
||||
pageQueryVo.setQueryFilter(new UserQueryDto());
|
||||
}
|
||||
@@ -215,6 +224,18 @@ public class UserManageController {
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private boolean isPlatformAdmin() {
|
||||
UserDto currentUser = getCurrentUserDto();
|
||||
return currentUser.getRole() == User.Role.Admin
|
||||
&& (currentUserGroupIds().isEmpty()
|
||||
|| sysRoleApplicationService.getRoleListByUserId(currentUser.getId()).stream()
|
||||
.anyMatch(role -> RoleEnum.SUPER_ADMIN.getCode().equals(role.getCode())));
|
||||
}
|
||||
|
||||
private boolean isCurrentTenantUser(User user) {
|
||||
return user != null && (getCurrentUserDto().getTenantId() == null || getCurrentUserDto().getTenantId().equals(user.getTenantId()));
|
||||
}
|
||||
|
||||
private UserDto getCurrentUserDto() {
|
||||
UserDto userDto = (UserDto) RequestContext.get().getUser();
|
||||
if (userDto == null) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.xspaceagi.system.application.converter.SysDataPermissionConverter;
|
||||
import com.xspaceagi.system.application.dto.permission.*;
|
||||
import com.xspaceagi.system.application.service.SysDataPermissionApplicationService;
|
||||
import com.xspaceagi.system.application.service.SysGroupApplicationService;
|
||||
import com.xspaceagi.system.application.service.SysRoleApplicationService;
|
||||
import com.xspaceagi.system.application.service.SysSubjectPermissionApplicationService;
|
||||
import com.xspaceagi.system.application.dto.UserDto;
|
||||
import com.xspaceagi.system.domain.model.GroupBindMenuModel;
|
||||
@@ -52,6 +53,8 @@ public class SysGroupController extends BaseController {
|
||||
@Resource
|
||||
private SysGroupApplicationService sysGroupApplicationService;
|
||||
@Resource
|
||||
private SysRoleApplicationService sysRoleApplicationService;
|
||||
@Resource
|
||||
private SysDataPermissionApplicationService sysDataPermissionApplicationService;
|
||||
@Resource
|
||||
private SysSubjectPermissionApplicationService sysSubjectPermissionApplicationService;
|
||||
@@ -397,6 +400,9 @@ public class SysGroupController extends BaseController {
|
||||
if (CollectionUtils.isEmpty(groupList)) {
|
||||
return groupList;
|
||||
}
|
||||
if (isPlatformAdmin()) {
|
||||
return groupList;
|
||||
}
|
||||
Set<Long> allowedGroupIds = currentUserGroupIds();
|
||||
return groupList.stream()
|
||||
.filter(group -> group.getId() != null && allowedGroupIds.contains(group.getId()))
|
||||
@@ -404,6 +410,9 @@ public class SysGroupController extends BaseController {
|
||||
}
|
||||
|
||||
private void checkGroupManageScope(Long groupId) {
|
||||
if (isPlatformAdmin()) {
|
||||
return;
|
||||
}
|
||||
if (groupId == null || !currentUserGroupIds().contains(groupId)) {
|
||||
throw BizException.of(ErrorCodeEnum.PERMISSION_DENIED, BizExceptionCodeEnum.permissionDenied);
|
||||
}
|
||||
@@ -416,6 +425,14 @@ public class SysGroupController extends BaseController {
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private boolean isPlatformAdmin() {
|
||||
UserDto currentUser = getCurrentUserDto();
|
||||
return currentUser.getRole() == User.Role.Admin
|
||||
&& (currentUserGroupIds().isEmpty()
|
||||
|| sysRoleApplicationService.getRoleListByUserId(currentUser.getId()).stream()
|
||||
.anyMatch(role -> RoleEnum.SUPER_ADMIN.getCode().equals(role.getCode())));
|
||||
}
|
||||
|
||||
private UserDto getCurrentUserDto() {
|
||||
UserDto userDto = (UserDto) RequestContext.get().getUser();
|
||||
if (userDto == null) {
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.xspaceagi.system.spec.common.RequestContext;
|
||||
import com.xspaceagi.system.spec.dto.ReqResult;
|
||||
import com.xspaceagi.system.spec.enums.ErrorCodeEnum;
|
||||
import com.xspaceagi.system.spec.enums.GroupEnum;
|
||||
import com.xspaceagi.system.spec.enums.RoleEnum;
|
||||
import com.xspaceagi.system.spec.exception.BizException;
|
||||
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
|
||||
import com.xspaceagi.system.spec.utils.I18nUtil;
|
||||
@@ -157,6 +158,9 @@ public class SysUserController extends BaseController {
|
||||
if (targetUser == null || !Objects.equals(targetUser.getTenantId(), RequestContext.get().getTenantId())) {
|
||||
throw BizException.of(ErrorCodeEnum.PERMISSION_DENIED, BizExceptionCodeEnum.permissionDenied);
|
||||
}
|
||||
if (isPlatformAdmin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<Long> allowedGroupIds = currentUserGroupIds();
|
||||
boolean inScope = sysGroupApplicationService.getGroupListByUserId(userId).stream()
|
||||
@@ -171,6 +175,9 @@ public class SysUserController extends BaseController {
|
||||
if (CollectionUtils.isEmpty(groupIds)) {
|
||||
return;
|
||||
}
|
||||
if (isPlatformAdmin()) {
|
||||
return;
|
||||
}
|
||||
Set<Long> allowedGroupIds = currentUserGroupIds();
|
||||
boolean allInScope = groupIds.stream().allMatch(allowedGroupIds::contains);
|
||||
if (!allInScope) {
|
||||
@@ -182,6 +189,9 @@ public class SysUserController extends BaseController {
|
||||
if (CollectionUtils.isEmpty(roleIds)) {
|
||||
return;
|
||||
}
|
||||
if (isPlatformAdmin()) {
|
||||
return;
|
||||
}
|
||||
Set<Long> allowedRoleIds = sysRoleApplicationService.getRoleListByUserId(getCurrentUserDto().getId()).stream()
|
||||
.map(SysRole::getId)
|
||||
.collect(Collectors.toSet());
|
||||
@@ -205,6 +215,14 @@ public class SysUserController extends BaseController {
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private boolean isPlatformAdmin() {
|
||||
UserDto currentUser = getCurrentUserDto();
|
||||
return currentUser.getRole() == User.Role.Admin
|
||||
&& (currentUserGroupIds().isEmpty()
|
||||
|| sysRoleApplicationService.getRoleListByUserId(currentUser.getId()).stream()
|
||||
.anyMatch(role -> RoleEnum.SUPER_ADMIN.getCode().equals(role.getCode())));
|
||||
}
|
||||
|
||||
private UserDto getCurrentUserDto() {
|
||||
UserDto userDto = (UserDto) RequestContext.get().getUser();
|
||||
if (userDto == null) {
|
||||
|
||||
74
qiming-backend/sql/update-20260602.sql
Normal file
74
qiming-backend/sql/update-20260602.sql
Normal file
@@ -0,0 +1,74 @@
|
||||
-- Add system online monitor menu and resource.
|
||||
-- Idempotent for existing tenants: creates menu/resource rows, binds menu to resource,
|
||||
-- and grants super_admin default access. User-group admins can be granted this menu
|
||||
-- from the database menu permission management UI.
|
||||
|
||||
INSERT INTO sys_resource (`parent_id`, `code`, `name`, `description`, `source`, `type`, `sort_index`, `status`, `_tenant_id`, `creator_id`, `creator`, `yn`)
|
||||
SELECT 0, 'online_monitor', '在线监控模块', '在线监控模块', 1, 1, 17, 1, t._tenant_id, 0, 'system', 1
|
||||
FROM (SELECT DISTINCT `_tenant_id` FROM sys_resource) t
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM sys_resource r
|
||||
WHERE r.`_tenant_id` = t.`_tenant_id` AND r.`code` = 'online_monitor' AND r.`yn` = 1
|
||||
);
|
||||
|
||||
INSERT INTO sys_resource (`parent_id`, `code`, `name`, `description`, `source`, `type`, `sort_index`, `status`, `_tenant_id`, `creator_id`, `creator`, `yn`)
|
||||
SELECT parent.id, 'online_monitor_query', '查询', '查询在线监控', 1, 2, 1, 1, parent.`_tenant_id`, 0, 'system', 1
|
||||
FROM sys_resource parent
|
||||
WHERE parent.`code` = 'online_monitor' AND parent.`yn` = 1
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM sys_resource r
|
||||
WHERE r.`_tenant_id` = parent.`_tenant_id` AND r.`code` = 'online_monitor_query' AND r.`yn` = 1
|
||||
);
|
||||
|
||||
INSERT INTO sys_menu (`parent_id`, `code`, `name`, `description`, `source`, `path`, `open_type`, `icon`, `sort_index`, `status`, `_tenant_id`, `creator_id`, `creator`, `yn`)
|
||||
SELECT parent.id, 'online_monitor', '在线监控', '在线监控', 1, '/system/online-monitor', 1, '', 11, 1, parent.`_tenant_id`, 0, 'system', 1
|
||||
FROM sys_menu parent
|
||||
WHERE parent.`code` = 'system_manage' AND parent.`yn` = 1
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM sys_menu m
|
||||
WHERE m.`_tenant_id` = parent.`_tenant_id` AND m.`code` = 'online_monitor' AND m.`yn` = 1
|
||||
);
|
||||
|
||||
INSERT INTO sys_menu_resource (`menu_id`, `resource_id`, `resource_bind_type`, `_tenant_id`, `creator_id`, `creator`, `yn`)
|
||||
SELECT m.id, r.id, 1, m.`_tenant_id`, 0, 'system', 1
|
||||
FROM sys_menu m
|
||||
JOIN sys_resource r ON r.`_tenant_id` = m.`_tenant_id` AND r.`code` = 'online_monitor' AND r.`yn` = 1
|
||||
WHERE m.`code` = 'online_monitor' AND m.`yn` = 1
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM sys_menu_resource mr
|
||||
WHERE mr.`_tenant_id` = m.`_tenant_id` AND mr.`menu_id` = m.id AND mr.`resource_id` = r.id AND mr.`yn` = 1
|
||||
);
|
||||
|
||||
UPDATE sys_menu_resource mr
|
||||
JOIN sys_menu m ON m.id = mr.menu_id AND m.`_tenant_id` = mr.`_tenant_id` AND m.`code` = 'online_monitor' AND m.`yn` = 1
|
||||
JOIN sys_resource r ON r.id = mr.resource_id AND r.`_tenant_id` = mr.`_tenant_id` AND r.`code` = 'online_monitor' AND r.`yn` = 1
|
||||
SET mr.`resource_bind_type` = 1,
|
||||
mr.`modified` = CURRENT_TIMESTAMP
|
||||
WHERE mr.`yn` = 1;
|
||||
|
||||
INSERT INTO sys_role_menu (`role_id`, `menu_id`, `menu_bind_type`, `resource_tree_json`, `_tenant_id`, `creator_id`, `creator`, `yn`)
|
||||
SELECT role.id,
|
||||
menu.id,
|
||||
1,
|
||||
JSON_ARRAY(JSON_OBJECT('id', resource.id, 'code', resource.`code`, 'resourceBindType', 1)),
|
||||
menu.`_tenant_id`,
|
||||
0,
|
||||
'system',
|
||||
1
|
||||
FROM sys_role role
|
||||
JOIN sys_menu menu ON menu.`_tenant_id` = role.`_tenant_id` AND menu.`code` = 'online_monitor' AND menu.`yn` = 1
|
||||
JOIN sys_resource resource ON resource.`_tenant_id` = role.`_tenant_id` AND resource.`code` = 'online_monitor' AND resource.`yn` = 1
|
||||
WHERE role.`code` = 'super_admin' AND role.`yn` = 1
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM sys_role_menu rm
|
||||
WHERE rm.`_tenant_id` = role.`_tenant_id` AND rm.`role_id` = role.id AND rm.`menu_id` = menu.id AND rm.`yn` = 1
|
||||
);
|
||||
|
||||
UPDATE sys_role_menu rm
|
||||
JOIN sys_role role ON role.id = rm.role_id AND role.`_tenant_id` = rm.`_tenant_id` AND role.`code` = 'super_admin' AND role.`yn` = 1
|
||||
JOIN sys_menu menu ON menu.id = rm.menu_id AND menu.`_tenant_id` = rm.`_tenant_id` AND menu.`code` = 'online_monitor' AND menu.`yn` = 1
|
||||
JOIN sys_resource resource ON resource.`_tenant_id` = rm.`_tenant_id` AND resource.`code` = 'online_monitor' AND resource.`yn` = 1
|
||||
SET rm.`menu_bind_type` = 1,
|
||||
rm.`resource_tree_json` = JSON_ARRAY(JSON_OBJECT('id', resource.id, 'code', resource.`code`, 'resourceBindType', 1)),
|
||||
rm.`modified` = CURRENT_TIMESTAMP
|
||||
WHERE rm.`yn` = 1;
|
||||
@@ -4815,6 +4815,7 @@ export const EN_US: SystemLangMap = {
|
||||
"PC.Routes.permissionResources": "Permission Resources",
|
||||
"PC.Routes.publicModelManagement": "Public Model Mgmt",
|
||||
"PC.Routes.modelMonitor": "Model Monitor",
|
||||
"PC.Routes.onlineMonitor": "Online Monitor",
|
||||
"PC.Routes.publishAudit": "Publish Audit",
|
||||
"PC.Routes.publishedManagement": "Published Mgmt",
|
||||
"PC.Routes.roleManage": "Role Mgmt",
|
||||
@@ -4828,6 +4829,39 @@ export const EN_US: SystemLangMap = {
|
||||
"PC.Routes.themeConfig": "Theme Config",
|
||||
"PC.Routes.userGroupManage": "User Group Mgmt",
|
||||
"PC.Routes.userManagement": "User Mgmt",
|
||||
"PC.Pages.OnlineMonitor.authorization": "Authorization",
|
||||
"PC.Pages.OnlineMonitor.clientCapacity": "Client Capacity",
|
||||
"PC.Pages.OnlineMonitor.clientCount": "Clients",
|
||||
"PC.Pages.OnlineMonitor.clientName": "Client Name",
|
||||
"PC.Pages.OnlineMonitor.clientTab": "Client Status",
|
||||
"PC.Pages.OnlineMonitor.created": "Created",
|
||||
"PC.Pages.OnlineMonitor.disabled": "Disabled",
|
||||
"PC.Pages.OnlineMonitor.disabledUsers": "Disabled Users",
|
||||
"PC.Pages.OnlineMonitor.enabled": "Enabled",
|
||||
"PC.Pages.OnlineMonitor.enabledUsers": "Enabled Users",
|
||||
"PC.Pages.OnlineMonitor.expireTime": "Expires At",
|
||||
"PC.Pages.OnlineMonitor.fetchFailed": "Failed to load online monitor data",
|
||||
"PC.Pages.OnlineMonitor.groupName": "User Group",
|
||||
"PC.Pages.OnlineMonitor.groups": "Groups",
|
||||
"PC.Pages.OnlineMonitor.groupTab": "Group Capacity",
|
||||
"PC.Pages.OnlineMonitor.inactive": "Inactive",
|
||||
"PC.Pages.OnlineMonitor.inactiveClients": "Inactive Clients",
|
||||
"PC.Pages.OnlineMonitor.lastLoginTime": "Last Login",
|
||||
"PC.Pages.OnlineMonitor.maxAgentCount": "Max Sessions",
|
||||
"PC.Pages.OnlineMonitor.modified": "Updated",
|
||||
"PC.Pages.OnlineMonitor.nickName": "Nickname",
|
||||
"PC.Pages.OnlineMonitor.offline": "Offline",
|
||||
"PC.Pages.OnlineMonitor.offlineClients": "Offline Clients",
|
||||
"PC.Pages.OnlineMonitor.online": "Online",
|
||||
"PC.Pages.OnlineMonitor.onlineClients": "Online Clients",
|
||||
"PC.Pages.OnlineMonitor.pageTitle": "Online Monitor",
|
||||
"PC.Pages.OnlineMonitor.status": "Status",
|
||||
"PC.Pages.OnlineMonitor.totalClients": "Total Clients",
|
||||
"PC.Pages.OnlineMonitor.totalUsers": "Total Users",
|
||||
"PC.Pages.OnlineMonitor.unlimited": "Unlimited",
|
||||
"PC.Pages.OnlineMonitor.userCapacity": "User Capacity",
|
||||
"PC.Pages.OnlineMonitor.userName": "Username",
|
||||
"PC.Pages.OnlineMonitor.userTab": "User Status",
|
||||
"PC.Routes.devPaymentEarnings": "Payment & Earnings (Dev)",
|
||||
"PC.Routes.adminSubscriptionCredits": "Subscriptions & Credits (Admin)",
|
||||
"PC.Routes.paymentConfig": "Payment Config",
|
||||
|
||||
@@ -4834,6 +4834,7 @@ export const ZH_CN: SystemLangMap = {
|
||||
"PC.Routes.permissionResources": "权限资源",
|
||||
"PC.Routes.publicModelManagement": "公共模型管理",
|
||||
"PC.Routes.modelMonitor": "模型监控",
|
||||
"PC.Routes.onlineMonitor": "在线监控",
|
||||
"PC.Routes.publishAudit": "发布审核",
|
||||
"PC.Routes.publishedManagement": "已发布管理",
|
||||
"PC.Routes.roleManage": "角色管理",
|
||||
@@ -4847,6 +4848,39 @@ export const ZH_CN: SystemLangMap = {
|
||||
"PC.Routes.themeConfig": "主题配置",
|
||||
"PC.Routes.userGroupManage": "单位(部门)管理",
|
||||
"PC.Routes.userManagement": "用户管理",
|
||||
"PC.Pages.OnlineMonitor.authorization": "授权状态",
|
||||
"PC.Pages.OnlineMonitor.clientCapacity": "客户端容量",
|
||||
"PC.Pages.OnlineMonitor.clientCount": "客户端数",
|
||||
"PC.Pages.OnlineMonitor.clientName": "客户端名称",
|
||||
"PC.Pages.OnlineMonitor.clientTab": "客户端状态",
|
||||
"PC.Pages.OnlineMonitor.created": "创建时间",
|
||||
"PC.Pages.OnlineMonitor.disabled": "已禁用",
|
||||
"PC.Pages.OnlineMonitor.disabledUsers": "禁用用户",
|
||||
"PC.Pages.OnlineMonitor.enabled": "已启用",
|
||||
"PC.Pages.OnlineMonitor.enabledUsers": "启用用户",
|
||||
"PC.Pages.OnlineMonitor.expireTime": "到期时间",
|
||||
"PC.Pages.OnlineMonitor.fetchFailed": "获取在线监控信息失败",
|
||||
"PC.Pages.OnlineMonitor.groupName": "用户组",
|
||||
"PC.Pages.OnlineMonitor.groups": "所属用户组",
|
||||
"PC.Pages.OnlineMonitor.groupTab": "用户组容量",
|
||||
"PC.Pages.OnlineMonitor.inactive": "已停用",
|
||||
"PC.Pages.OnlineMonitor.inactiveClients": "停用客户端",
|
||||
"PC.Pages.OnlineMonitor.lastLoginTime": "最后登录时间",
|
||||
"PC.Pages.OnlineMonitor.maxAgentCount": "最大会话数",
|
||||
"PC.Pages.OnlineMonitor.modified": "更新时间",
|
||||
"PC.Pages.OnlineMonitor.nickName": "昵称",
|
||||
"PC.Pages.OnlineMonitor.offline": "离线",
|
||||
"PC.Pages.OnlineMonitor.offlineClients": "离线客户端",
|
||||
"PC.Pages.OnlineMonitor.online": "在线",
|
||||
"PC.Pages.OnlineMonitor.onlineClients": "在线客户端",
|
||||
"PC.Pages.OnlineMonitor.pageTitle": "在线监控",
|
||||
"PC.Pages.OnlineMonitor.status": "状态",
|
||||
"PC.Pages.OnlineMonitor.totalClients": "客户端总数",
|
||||
"PC.Pages.OnlineMonitor.totalUsers": "用户总数",
|
||||
"PC.Pages.OnlineMonitor.unlimited": "不限",
|
||||
"PC.Pages.OnlineMonitor.userCapacity": "用户容量",
|
||||
"PC.Pages.OnlineMonitor.userName": "用户名",
|
||||
"PC.Pages.OnlineMonitor.userTab": "用户状态",
|
||||
"PC.Routes.devPaymentEarnings": "支付与收益(开发者)",
|
||||
"PC.Routes.adminSubscriptionCredits": "订阅与积分(管理员)",
|
||||
"PC.Routes.paymentConfig": "支付配置",
|
||||
|
||||
@@ -4628,6 +4628,7 @@ export const ZH_TW: SystemLangMap = {
|
||||
"PC.Routes.permissionResources": "許可權資源",
|
||||
"PC.Routes.publicModelManagement": "公共模型管理",
|
||||
"PC.Routes.modelMonitor": "模型監控",
|
||||
"PC.Routes.onlineMonitor": "線上監控",
|
||||
"PC.Routes.publishAudit": "釋出稽核",
|
||||
"PC.Routes.publishedManagement": "已釋出管理",
|
||||
"PC.Routes.roleManage": "角色管理",
|
||||
@@ -4641,6 +4642,39 @@ export const ZH_TW: SystemLangMap = {
|
||||
"PC.Routes.themeConfig": "主題設定",
|
||||
"PC.Routes.userGroupManage": "使用者組管理",
|
||||
"PC.Routes.userManagement": "使用者管理",
|
||||
"PC.Pages.OnlineMonitor.authorization": "授權狀態",
|
||||
"PC.Pages.OnlineMonitor.clientCapacity": "客戶端容量",
|
||||
"PC.Pages.OnlineMonitor.clientCount": "客戶端數",
|
||||
"PC.Pages.OnlineMonitor.clientName": "客戶端名稱",
|
||||
"PC.Pages.OnlineMonitor.clientTab": "客戶端狀態",
|
||||
"PC.Pages.OnlineMonitor.created": "建立時間",
|
||||
"PC.Pages.OnlineMonitor.disabled": "已停用",
|
||||
"PC.Pages.OnlineMonitor.disabledUsers": "停用使用者",
|
||||
"PC.Pages.OnlineMonitor.enabled": "已啟用",
|
||||
"PC.Pages.OnlineMonitor.enabledUsers": "啟用使用者",
|
||||
"PC.Pages.OnlineMonitor.expireTime": "到期時間",
|
||||
"PC.Pages.OnlineMonitor.fetchFailed": "獲取線上監控資訊失敗",
|
||||
"PC.Pages.OnlineMonitor.groupName": "使用者組",
|
||||
"PC.Pages.OnlineMonitor.groups": "所屬使用者組",
|
||||
"PC.Pages.OnlineMonitor.groupTab": "使用者組容量",
|
||||
"PC.Pages.OnlineMonitor.inactive": "已停用",
|
||||
"PC.Pages.OnlineMonitor.inactiveClients": "停用客戶端",
|
||||
"PC.Pages.OnlineMonitor.lastLoginTime": "最後登入時間",
|
||||
"PC.Pages.OnlineMonitor.maxAgentCount": "最大會話數",
|
||||
"PC.Pages.OnlineMonitor.modified": "更新時間",
|
||||
"PC.Pages.OnlineMonitor.nickName": "暱稱",
|
||||
"PC.Pages.OnlineMonitor.offline": "離線",
|
||||
"PC.Pages.OnlineMonitor.offlineClients": "離線客戶端",
|
||||
"PC.Pages.OnlineMonitor.online": "線上",
|
||||
"PC.Pages.OnlineMonitor.onlineClients": "線上客戶端",
|
||||
"PC.Pages.OnlineMonitor.pageTitle": "線上監控",
|
||||
"PC.Pages.OnlineMonitor.status": "狀態",
|
||||
"PC.Pages.OnlineMonitor.totalClients": "客戶端總數",
|
||||
"PC.Pages.OnlineMonitor.totalUsers": "使用者總數",
|
||||
"PC.Pages.OnlineMonitor.unlimited": "不限",
|
||||
"PC.Pages.OnlineMonitor.userCapacity": "使用者容量",
|
||||
"PC.Pages.OnlineMonitor.userName": "使用者名稱",
|
||||
"PC.Pages.OnlineMonitor.userTab": "使用者狀態",
|
||||
"PC.Routes.devPaymentEarnings": "支付與收益(開發者)",
|
||||
"PC.Routes.adminSubscriptionCredits": "訂閱與積分(管理員)",
|
||||
"PC.Routes.paymentConfig": "支付設定",
|
||||
|
||||
16
qiming/src/pages/SystemManagement/OnlineMonitor/index.less
Normal file
16
qiming/src/pages/SystemManagement/OnlineMonitor/index.less
Normal file
@@ -0,0 +1,16 @@
|
||||
.summaryRow {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.summaryCard {
|
||||
height: 100%;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
:global {
|
||||
.ant-tabs-nav {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
351
qiming/src/pages/SystemManagement/OnlineMonitor/index.tsx
Normal file
351
qiming/src/pages/SystemManagement/OnlineMonitor/index.tsx
Normal file
@@ -0,0 +1,351 @@
|
||||
import WorkspaceLayout from '@/components/WorkspaceLayout';
|
||||
import { SUCCESS_CODE } from '@/constants/codes.constants';
|
||||
import { dict } from '@/services/i18nRuntime';
|
||||
import { apiGetOnlineMonitor } from '@/services/systemManage';
|
||||
import type {
|
||||
OnlineMonitorClient,
|
||||
OnlineMonitorGroup,
|
||||
OnlineMonitorInfo,
|
||||
OnlineMonitorUser,
|
||||
} from '@/types/interfaces/systemManage';
|
||||
import { ReloadOutlined } from '@ant-design/icons';
|
||||
import type { ProColumns } from '@ant-design/pro-components';
|
||||
import { ProTable } from '@ant-design/pro-components';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Row,
|
||||
Space,
|
||||
Statistic,
|
||||
Tabs,
|
||||
Tag,
|
||||
message,
|
||||
} from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import styles from './index.less';
|
||||
|
||||
const unlimitedText = (value?: number) =>
|
||||
value === undefined || value === null || value < 0
|
||||
? dict('PC.Pages.OnlineMonitor.unlimited')
|
||||
: value;
|
||||
|
||||
const formatTime = (value?: string) =>
|
||||
value ? dayjs(value).format('YYYY-MM-DD HH:mm') : '-';
|
||||
|
||||
const OnlineMonitor: React.FC = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [data, setData] = useState<OnlineMonitorInfo>();
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await apiGetOnlineMonitor();
|
||||
if (res.code === SUCCESS_CODE) {
|
||||
setData(res.data);
|
||||
} else {
|
||||
message.error(
|
||||
res.message || dict('PC.Pages.OnlineMonitor.fetchFailed'),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
const summaryItems = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.totalClients'),
|
||||
value: data?.totalClientCount || 0,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.onlineClients'),
|
||||
value: data?.onlineClientCount || 0,
|
||||
valueStyle: { color: '#16a34a' },
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.offlineClients'),
|
||||
value: data?.offlineClientCount || 0,
|
||||
valueStyle: { color: '#ea580c' },
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.inactiveClients'),
|
||||
value: data?.inactiveClientCount || 0,
|
||||
valueStyle: { color: '#64748b' },
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.totalUsers'),
|
||||
value: data?.totalUserCount || 0,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.enabledUsers'),
|
||||
value: data?.enabledUserCount || 0,
|
||||
valueStyle: { color: '#2563eb' },
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.disabledUsers'),
|
||||
value: data?.disabledUserCount || 0,
|
||||
valueStyle: { color: '#dc2626' },
|
||||
},
|
||||
],
|
||||
[data],
|
||||
);
|
||||
|
||||
const groupColumns: ProColumns<OnlineMonitorGroup>[] = [
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.groupName'),
|
||||
dataIndex: 'groupName',
|
||||
width: 160,
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.authorization'),
|
||||
dataIndex: 'authEnabled',
|
||||
width: 100,
|
||||
render: (_, record) => (
|
||||
<Tag color={record.authEnabled === 1 ? 'green' : 'default'}>
|
||||
{record.authEnabled === 1
|
||||
? dict('PC.Pages.OnlineMonitor.enabled')
|
||||
: dict('PC.Pages.OnlineMonitor.disabled')}
|
||||
</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.expireTime'),
|
||||
dataIndex: 'expireTime',
|
||||
width: 160,
|
||||
render: (_, record) => formatTime(record.expireTime),
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.userCapacity'),
|
||||
width: 120,
|
||||
render: (_, record) =>
|
||||
`${record.currentUserCount}/${unlimitedText(record.maxUserCount)}`,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.clientCapacity'),
|
||||
width: 120,
|
||||
render: (_, record) =>
|
||||
`${record.currentClientCount}/${unlimitedText(record.maxClientCount)}`,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.onlineClients'),
|
||||
dataIndex: 'onlineClientCount',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.offlineClients'),
|
||||
dataIndex: 'offlineClientCount',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.inactiveClients'),
|
||||
dataIndex: 'inactiveClientCount',
|
||||
width: 110,
|
||||
},
|
||||
];
|
||||
|
||||
const clientColumns: ProColumns<OnlineMonitorClient>[] = [
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.clientName'),
|
||||
dataIndex: 'name',
|
||||
width: 180,
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.status'),
|
||||
width: 100,
|
||||
render: (_, record) => (
|
||||
<Tag
|
||||
color={
|
||||
!record.isActive ? 'default' : record.online ? 'green' : 'orange'
|
||||
}
|
||||
>
|
||||
{!record.isActive
|
||||
? dict('PC.Pages.OnlineMonitor.inactive')
|
||||
: record.online
|
||||
? dict('PC.Pages.OnlineMonitor.online')
|
||||
: dict('PC.Pages.OnlineMonitor.offline')}
|
||||
</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.userName'),
|
||||
dataIndex: 'userName',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.nickName'),
|
||||
dataIndex: 'nickName',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.groupName'),
|
||||
dataIndex: 'groupName',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.maxAgentCount'),
|
||||
dataIndex: 'maxAgentCount',
|
||||
width: 140,
|
||||
render: (_, record) => unlimitedText(record.maxAgentCount),
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.created'),
|
||||
dataIndex: 'created',
|
||||
width: 160,
|
||||
render: (_, record) => formatTime(record.created),
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.modified'),
|
||||
dataIndex: 'modified',
|
||||
width: 160,
|
||||
render: (_, record) => formatTime(record.modified),
|
||||
},
|
||||
];
|
||||
|
||||
const userColumns: ProColumns<OnlineMonitorUser>[] = [
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.userName'),
|
||||
dataIndex: 'userName',
|
||||
width: 150,
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.nickName'),
|
||||
dataIndex: 'nickName',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.status'),
|
||||
width: 100,
|
||||
render: (_, record) => (
|
||||
<Tag color={record.status === 'Enabled' ? 'green' : 'red'}>
|
||||
{record.status === 'Enabled'
|
||||
? dict('PC.Pages.OnlineMonitor.enabled')
|
||||
: dict('PC.Pages.OnlineMonitor.disabled')}
|
||||
</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.groups'),
|
||||
width: 220,
|
||||
render: (_, record) => (
|
||||
<Space wrap>
|
||||
{(record.groupNames || []).map((name) => (
|
||||
<Tag key={name}>{name}</Tag>
|
||||
))}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.clientCount'),
|
||||
dataIndex: 'clientCount',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.onlineClients'),
|
||||
dataIndex: 'onlineClientCount',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.inactiveClients'),
|
||||
dataIndex: 'inactiveClientCount',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
title: dict('PC.Pages.OnlineMonitor.lastLoginTime'),
|
||||
dataIndex: 'lastLoginTime',
|
||||
width: 160,
|
||||
render: (_, record) => formatTime(record.lastLoginTime),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<WorkspaceLayout
|
||||
title={dict('PC.Pages.OnlineMonitor.pageTitle')}
|
||||
rightSlot={
|
||||
<Button icon={<ReloadOutlined />} loading={loading} onClick={fetchData}>
|
||||
{dict('PC.Common.Global.refresh')}
|
||||
</Button>
|
||||
}
|
||||
contentPadding="16px 24px"
|
||||
>
|
||||
<Row gutter={[16, 16]} className={styles.summaryRow}>
|
||||
{summaryItems.map((item) => (
|
||||
<Col xs={12} sm={8} md={6} xl={3} key={item.title}>
|
||||
<Card size="small" className={styles.summaryCard}>
|
||||
<Statistic
|
||||
title={item.title}
|
||||
value={item.value}
|
||||
valueStyle={item.valueStyle}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
|
||||
<Tabs
|
||||
className={styles.tabs}
|
||||
items={[
|
||||
{
|
||||
key: 'groups',
|
||||
label: dict('PC.Pages.OnlineMonitor.groupTab'),
|
||||
children: (
|
||||
<ProTable
|
||||
rowKey="groupId"
|
||||
search={false}
|
||||
options={false}
|
||||
loading={loading}
|
||||
columns={groupColumns}
|
||||
dataSource={data?.groups || []}
|
||||
pagination={{ pageSize: 10 }}
|
||||
scroll={{ x: 980 }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'clients',
|
||||
label: dict('PC.Pages.OnlineMonitor.clientTab'),
|
||||
children: (
|
||||
<ProTable
|
||||
rowKey="id"
|
||||
search={false}
|
||||
options={false}
|
||||
loading={loading}
|
||||
columns={clientColumns}
|
||||
dataSource={data?.clients || []}
|
||||
pagination={{ pageSize: 10 }}
|
||||
scroll={{ x: 1180 }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'users',
|
||||
label: dict('PC.Pages.OnlineMonitor.userTab'),
|
||||
children: (
|
||||
<ProTable
|
||||
rowKey="userId"
|
||||
search={false}
|
||||
options={false}
|
||||
loading={loading}
|
||||
columns={userColumns}
|
||||
dataSource={data?.users || []}
|
||||
pagination={{ pageSize: 10 }}
|
||||
scroll={{ x: 1100 }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</WorkspaceLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnlineMonitor;
|
||||
@@ -259,6 +259,11 @@ const routes = [
|
||||
name: getRouteLabel('PC.Routes.modelMonitor'),
|
||||
component: '@/pages/SystemManagement/ModelMonitor',
|
||||
},
|
||||
{
|
||||
path: 'online-monitor',
|
||||
name: getRouteLabel('PC.Routes.onlineMonitor'),
|
||||
component: '@/pages/SystemManagement/OnlineMonitor',
|
||||
},
|
||||
{
|
||||
path: 'config',
|
||||
name: getRouteLabel('PC.Routes.systemConfig'),
|
||||
|
||||
@@ -59,6 +59,8 @@ const MENU_ICON_MAP: Record<string, string> = {
|
||||
admin_subscription_credits: 'icons-nav-subscription',
|
||||
// 模型监控
|
||||
model_monitor: 'icons-common-console',
|
||||
// 在线监控
|
||||
online_monitor: 'icons-nav-computer',
|
||||
|
||||
// 二级菜单 - 工作空间
|
||||
// 智能体开发
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
ConversationStatsResult,
|
||||
ModelConfigDto,
|
||||
NotifyMessageSendParams,
|
||||
OnlineMonitorInfo,
|
||||
PayConfigResult,
|
||||
PayConnectivityResult,
|
||||
PublishedDto,
|
||||
@@ -567,6 +568,17 @@ export async function apiGetSandboxConfigList(): Promise<
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询在线监控信息
|
||||
*/
|
||||
export async function apiGetOnlineMonitor(): Promise<
|
||||
RequestResponse<OnlineMonitorInfo>
|
||||
> {
|
||||
return request('/api/system/sandbox/config/online-monitor', {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建沙盒配置
|
||||
*/
|
||||
|
||||
@@ -837,6 +837,66 @@ export interface SandboxGlobalConfig {
|
||||
perUserCpuCores: number | string;
|
||||
}
|
||||
|
||||
/** 在线监控聚合信息 */
|
||||
export interface OnlineMonitorInfo {
|
||||
totalClientCount: number;
|
||||
onlineClientCount: number;
|
||||
offlineClientCount: number;
|
||||
inactiveClientCount: number;
|
||||
totalUserCount: number;
|
||||
enabledUserCount: number;
|
||||
disabledUserCount: number;
|
||||
groups: OnlineMonitorGroup[];
|
||||
users: OnlineMonitorUser[];
|
||||
clients: OnlineMonitorClient[];
|
||||
}
|
||||
|
||||
/** 在线监控-用户组 */
|
||||
export interface OnlineMonitorGroup {
|
||||
groupId: number;
|
||||
groupName: string;
|
||||
authEnabled?: number;
|
||||
status?: number;
|
||||
expireTime?: string;
|
||||
maxUserCount?: number;
|
||||
currentUserCount: number;
|
||||
maxClientCount?: number;
|
||||
currentClientCount: number;
|
||||
onlineClientCount: number;
|
||||
offlineClientCount: number;
|
||||
inactiveClientCount: number;
|
||||
}
|
||||
|
||||
/** 在线监控-用户 */
|
||||
export interface OnlineMonitorUser {
|
||||
userId: number;
|
||||
userName: string;
|
||||
nickName?: string;
|
||||
role?: string;
|
||||
status?: string;
|
||||
groupNames?: string[];
|
||||
clientCount: number;
|
||||
onlineClientCount: number;
|
||||
inactiveClientCount: number;
|
||||
lastLoginTime?: string;
|
||||
}
|
||||
|
||||
/** 在线监控-客户端 */
|
||||
export interface OnlineMonitorClient {
|
||||
id: number;
|
||||
name: string;
|
||||
userId?: number;
|
||||
userName?: string;
|
||||
nickName?: string;
|
||||
groupId?: number;
|
||||
groupName?: string;
|
||||
isActive?: boolean;
|
||||
online: boolean;
|
||||
maxAgentCount?: number;
|
||||
created?: string;
|
||||
modified?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 沙盒选择项(用于电脑选择器下拉)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user