package com.tourguide.modules.system.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.tourguide.common.api.PageResponse; import com.tourguide.common.exception.BusinessException; import com.tourguide.modules.system.dto.PermissionActionResponse; import com.tourguide.modules.system.dto.PermissionModuleResponse; import com.tourguide.modules.system.dto.PermissionPageResponse; import com.tourguide.modules.system.dto.RoleDetailResponse; import com.tourguide.modules.system.dto.RoleResponse; import com.tourguide.modules.system.dto.RoleSaveRequest; import com.tourguide.modules.system.entity.SystemMenu; import com.tourguide.modules.system.entity.SystemRole; import com.tourguide.modules.system.entity.SystemRoleMenu; import com.tourguide.modules.system.mapper.SystemMenuMapper; import com.tourguide.modules.system.mapper.SystemRoleMapper; import com.tourguide.modules.system.mapper.SystemRoleMenuMapper; import com.tourguide.modules.user.entity.AdminUser; import com.tourguide.modules.user.mapper.AdminUserMapper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @Service public class SystemRoleService { private final SystemRoleMapper roleMapper; private final SystemMenuMapper menuMapper; private final SystemRoleMenuMapper roleMenuMapper; private final AdminUserMapper adminUserMapper; public SystemRoleService(SystemRoleMapper roleMapper, SystemMenuMapper menuMapper, SystemRoleMenuMapper roleMenuMapper, AdminUserMapper adminUserMapper) { this.roleMapper = roleMapper; this.menuMapper = menuMapper; this.roleMenuMapper = roleMenuMapper; this.adminUserMapper = adminUserMapper; } public PageResponse page(long page, long size, String keyword) { LambdaQueryWrapper query = new LambdaQueryWrapper() .like(StringUtils.hasText(keyword), SystemRole::getRoleName, StringUtils.hasText(keyword) ? keyword.trim() : null) .orderByAsc(SystemRole::getId); Page result = roleMapper.selectPage(new Page(page, size), query); List records = result.getRecords().stream() .map(role -> new RoleResponse(role, countAccounts(role.getRoleCode()))) .collect(Collectors.toList()); return new PageResponse(records, result.getTotal(), result.getCurrent(), result.getSize()); } public RoleDetailResponse detail(Long id) { SystemRole role = findRole(id); List relationMenuIds = roleMenuMapper.selectList(new LambdaQueryWrapper() .eq(SystemRoleMenu::getRoleId, id)) .stream().map(SystemRoleMenu::getMenuId).collect(Collectors.toList()); List menuIds = relationMenuIds.isEmpty() ? Collections.emptyList() : menuMapper.selectList(new LambdaQueryWrapper() .in(SystemMenu::getId, relationMenuIds).eq(SystemMenu::getStatus, 1)) .stream().map(SystemMenu::getId).collect(Collectors.toList()); return new RoleDetailResponse(role, menuIds); } public List permissions() { List menus = menuMapper.selectList(new LambdaQueryWrapper() .eq(SystemMenu::getStatus, 1).orderByAsc(SystemMenu::getSort, SystemMenu::getId)); Map> children = new HashMap>(); for (SystemMenu menu : menus) { children.computeIfAbsent(menu.getParentId(), key -> new ArrayList()).add(menu); } List modules = new ArrayList(); for (SystemMenu module : children.getOrDefault(0L, Collections.emptyList())) { if (!"DIRECTORY".equals(module.getMenuType())) continue; List pages = new ArrayList(); for (SystemMenu page : children.getOrDefault(module.getId(), Collections.emptyList())) { if (!"MENU".equals(page.getMenuType())) continue; List actions = children .getOrDefault(page.getId(), Collections.emptyList()).stream() .filter(menu -> "BUTTON".equals(menu.getMenuType())) .map(PermissionActionResponse::new).collect(Collectors.toList()); pages.add(new PermissionPageResponse(page, actions)); } if (!pages.isEmpty()) modules.add(new PermissionModuleResponse(module, pages)); } return modules; } @Transactional public RoleDetailResponse create(RoleSaveRequest request) { validateRoleName(request.getRoleName(), null); validateMenuIds(request.getMenuIds()); SystemRole role = new SystemRole(); role.setRoleCode("CUSTOM_" + UUID.randomUUID().toString().replace("-", "").substring(0, 12).toUpperCase()); role.setRoleName(request.getRoleName().trim()); role.setRemark(normalizeRemark(request.getRemark())); role.setStatus(1); roleMapper.insert(role); replaceRoleMenus(role.getId(), request.getMenuIds()); return detail(role.getId()); } @Transactional public RoleDetailResponse update(Long id, RoleSaveRequest request) { SystemRole role = findRole(id); validateRoleName(request.getRoleName(), id); validateMenuIds(request.getMenuIds()); role.setRoleName(request.getRoleName().trim()); role.setRemark(normalizeRemark(request.getRemark())); roleMapper.updateById(role); replaceRoleMenus(id, request.getMenuIds()); return detail(id); } @Transactional public void delete(Long id) { SystemRole role = findRole(id); if ("ADMIN".equals(role.getRoleCode())) { throw new BusinessException(409, "超级管理员角色不能删除"); } if (countAccounts(role.getRoleCode()) > 0) { throw new BusinessException(409, "该角色已关联后台账号,不能删除"); } roleMenuMapper.markDeletedByRoleId(id); roleMapper.deleteById(id); } private SystemRole findRole(Long id) { SystemRole role = roleMapper.selectById(id); if (role == null) throw new BusinessException(404, "角色不存在"); return role; } private long countAccounts(String roleCode) { return adminUserMapper.selectCount(new LambdaQueryWrapper().eq(AdminUser::getRoleCode, roleCode)); } private void validateRoleName(String roleName, Long excludedId) { LambdaQueryWrapper query = new LambdaQueryWrapper() .eq(SystemRole::getRoleName, roleName.trim()).ne(excludedId != null, SystemRole::getId, excludedId); if (roleMapper.selectCount(query) > 0) throw new BusinessException(409, "角色名称已存在"); } private void validateMenuIds(List menuIds) { Set uniqueIds = new HashSet(menuIds); if (uniqueIds.isEmpty()) return; long validCount = menuMapper.selectCount(new LambdaQueryWrapper() .in(SystemMenu::getId, uniqueIds).eq(SystemMenu::getStatus, 1)); if (validCount != uniqueIds.size()) throw new BusinessException(400, "包含无效权限"); } private void replaceRoleMenus(Long roleId, List menuIds) { roleMenuMapper.markDeletedByRoleId(roleId); for (Long menuId : new HashSet(menuIds)) { SystemRoleMenu relation = new SystemRoleMenu(); relation.setRoleId(roleId); relation.setMenuId(menuId); roleMenuMapper.upsert(relation); } } private String normalizeRemark(String remark) { return StringUtils.hasText(remark) ? remark.trim() : null; } }