package com.sinata.appointment.service;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.sinata.appointment.constants.BizErrorCode;
|
import com.sinata.appointment.dto.MenuTreeNodeVo;
|
import com.sinata.appointment.dto.RoleManageCreateRequest;
|
import com.sinata.appointment.dto.RoleManageDetailVo;
|
import com.sinata.appointment.dto.RoleManageListVo;
|
import com.sinata.appointment.dto.RoleManageUpdateRequest;
|
import com.sinata.appointment.dto.RoleUserCountRow;
|
import com.sinata.appointment.entity.SysMenu;
|
import com.sinata.appointment.entity.SysRole;
|
import com.sinata.appointment.entity.SysRoleMenu;
|
import com.sinata.appointment.entity.SysUserRole;
|
import com.sinata.appointment.exception.BizException;
|
import com.sinata.appointment.mapper.SysMenuMapper;
|
import com.sinata.appointment.mapper.SysRoleMapper;
|
import com.sinata.appointment.mapper.SysRoleMenuMapper;
|
import com.sinata.appointment.mapper.SysUserRoleMapper;
|
import com.sinata.appointment.util.UuidAssert;
|
import java.util.ArrayList;
|
import java.util.HashMap;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.UUID;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.StringUtils;
|
|
@Service
|
@RequiredArgsConstructor
|
public class SysRoleManageApplicationService {
|
|
private final SysRoleMapper sysRoleMapper;
|
private final SysMenuMapper sysMenuMapper;
|
private final SysRoleMenuMapper sysRoleMenuMapper;
|
private final SysUserRoleMapper sysUserRoleMapper;
|
|
public List<MenuTreeNodeVo> menuTree() {
|
List<SysMenu> all =
|
sysMenuMapper.selectList(
|
new LambdaQueryWrapper<SysMenu>()
|
.eq(SysMenu::getDelFlag, 0)
|
.orderByAsc(SysMenu::getSortOrder)
|
.orderByAsc(SysMenu::getId));
|
Map<Long, MenuTreeNodeVo> nodes = new LinkedHashMap<>();
|
for (SysMenu m : all) {
|
MenuTreeNodeVo n = new MenuTreeNodeVo();
|
n.setId(m.getId());
|
n.setLabel(m.getMenuName());
|
n.setMenuType(m.getMenuType());
|
n.setPermCode(m.getPermCode());
|
n.setRoutePath(m.getRoutePath());
|
nodes.put(m.getId(), n);
|
}
|
List<MenuTreeNodeVo> roots = new ArrayList<>();
|
for (SysMenu m : all) {
|
MenuTreeNodeVo n = nodes.get(m.getId());
|
long pid = m.getPid() == null ? 0L : m.getPid();
|
if (pid == 0L) {
|
roots.add(n);
|
} else {
|
MenuTreeNodeVo p = nodes.get(pid);
|
if (p != null) {
|
p.getChildren().add(n);
|
} else {
|
roots.add(n);
|
}
|
}
|
}
|
return roots;
|
}
|
|
public IPage<RoleManageListVo> pageRoles(long page, long size, String roleName) {
|
LambdaQueryWrapper<SysRole> q = new LambdaQueryWrapper<>();
|
q.eq(SysRole::getDelFlag, 0);
|
if (StringUtils.hasText(roleName)) {
|
q.like(SysRole::getRoleName, roleName.trim());
|
}
|
q.orderByDesc(SysRole::getId);
|
Page<SysRole> p = sysRoleMapper.selectPage(new Page<>(page, size), q);
|
List<Long> ids = p.getRecords().stream().map(SysRole::getId).toList();
|
Map<Long, Long> countMap = new HashMap<>();
|
if (!ids.isEmpty()) {
|
for (RoleUserCountRow row : sysUserRoleMapper.countUsersGroupedByRoleId(ids)) {
|
long c = row.getUserCount() == null ? 0L : row.getUserCount();
|
countMap.put(row.getRoleId(), c);
|
}
|
}
|
return p.convert(
|
r -> {
|
RoleManageListVo vo = new RoleManageListVo();
|
vo.setId(r.getId());
|
vo.setUuid(r.getUuid());
|
vo.setRoleName(r.getRoleName());
|
vo.setRemark(r.getRemark());
|
vo.setCreateTime(r.getCreateTime());
|
vo.setUserCount(countMap.getOrDefault(r.getId(), 0L));
|
return vo;
|
});
|
}
|
|
public RoleManageDetailVo getDetail(Long id, String uuid) {
|
SysRole r = loadActiveWithUuid(id, uuid);
|
RoleManageDetailVo vo = new RoleManageDetailVo();
|
vo.setId(r.getId());
|
vo.setUuid(r.getUuid());
|
vo.setRoleName(r.getRoleName());
|
vo.setRemark(r.getRemark());
|
vo.setCreateTime(r.getCreateTime());
|
vo.setMenuIds(listMenuIdsForRole(id));
|
return vo;
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public Map<String, Object> create(RoleManageCreateRequest req) {
|
String roleName = req.getRoleName().trim();
|
validateRoleNameUnique(roleName, null);
|
String code = generateUniqueRoleCode();
|
SysRole r = new SysRole();
|
r.setRoleCode(code);
|
r.setRoleName(roleName);
|
r.setRemark(trimToEmpty(req.getRemark()));
|
sysRoleMapper.insert(r);
|
SysRole fresh = sysRoleMapper.selectById(r.getId());
|
if (fresh == null || !StringUtils.hasText(fresh.getUuid())) {
|
throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "创建后读取角色失败");
|
}
|
replaceRoleMenus(fresh.getId(), req.getMenuIds());
|
Map<String, Object> m = new HashMap<>();
|
m.put("id", fresh.getId());
|
m.put("uuid", fresh.getUuid());
|
return m;
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void update(Long id, RoleManageUpdateRequest req) {
|
SysRole r = loadActiveWithUuid(id, req.getUuid());
|
String roleName = req.getRoleName().trim();
|
validateRoleNameUnique(roleName, id);
|
r.setRoleName(roleName);
|
r.setRemark(trimToEmpty(req.getRemark()));
|
sysRoleMapper.updateById(r);
|
replaceRoleMenus(id, req.getMenuIds());
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void delete(Long id, String uuid) {
|
SysRole r = loadActiveWithUuid(id, uuid);
|
long n =
|
sysUserRoleMapper.selectCount(
|
new LambdaQueryWrapper<SysUserRole>()
|
.eq(SysUserRole::getRoleId, id)
|
.eq(SysUserRole::getDelFlag, 0));
|
if (n > 0) {
|
throw new BizException(BizErrorCode.ROLE_HAS_BOUND_USERS, "该角色下仍有关联账号,无法删除");
|
}
|
sysRoleMenuMapper.delete(
|
new LambdaQueryWrapper<SysRoleMenu>()
|
.eq(SysRoleMenu::getRoleId, id)
|
.eq(SysRoleMenu::getDelFlag, 0));
|
int affected = sysRoleMapper.deleteById(r.getId());
|
if (affected <= 0) {
|
throw new BizException(BizErrorCode.RESOURCE_VERIFY_FAILED, "删除失败,请刷新后重试");
|
}
|
}
|
|
private List<Long> listMenuIdsForRole(Long roleId) {
|
return sysRoleMenuMapper
|
.selectList(
|
new LambdaQueryWrapper<SysRoleMenu>()
|
.eq(SysRoleMenu::getRoleId, roleId)
|
.eq(SysRoleMenu::getDelFlag, 0))
|
.stream()
|
.map(SysRoleMenu::getMenuId)
|
.toList();
|
}
|
|
private void replaceRoleMenus(Long roleId, List<Long> menuIds) {
|
validateMenuIds(menuIds);
|
sysRoleMenuMapper.delete(
|
new LambdaQueryWrapper<SysRoleMenu>()
|
.eq(SysRoleMenu::getRoleId, roleId)
|
.eq(SysRoleMenu::getDelFlag, 0));
|
if (menuIds == null || menuIds.isEmpty()) {
|
return;
|
}
|
for (Long mid : menuIds.stream().distinct().toList()) {
|
SysRoleMenu rm = new SysRoleMenu();
|
rm.setRoleId(roleId);
|
rm.setMenuId(mid);
|
sysRoleMenuMapper.insert(rm);
|
}
|
}
|
|
private void validateMenuIds(List<Long> menuIds) {
|
if (menuIds == null || menuIds.isEmpty()) {
|
return;
|
}
|
List<Long> distinct = menuIds.stream().distinct().toList();
|
Long cnt =
|
sysMenuMapper.selectCount(
|
new LambdaQueryWrapper<SysMenu>()
|
.in(SysMenu::getId, distinct)
|
.eq(SysMenu::getDelFlag, 0));
|
if (!Objects.equals(cnt, (long) distinct.size())) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "存在无效的菜单 id");
|
}
|
}
|
|
private SysRole loadActiveWithUuid(Long id, String uuid) {
|
SysRole r = sysRoleMapper.selectById(id);
|
if (r == null || r.getDelFlag() != null && r.getDelFlag() == 1) {
|
throw new BizException(BizErrorCode.RESOURCE_VERIFY_FAILED, "资源不存在或无权访问");
|
}
|
UuidAssert.match(r, uuid);
|
return r;
|
}
|
|
private String generateUniqueRoleCode() {
|
for (int i = 0; i < 20; i++) {
|
String code =
|
"C"
|
+ UUID.randomUUID()
|
.toString()
|
.replace("-", "")
|
.substring(0, 12)
|
.toUpperCase();
|
long exists =
|
sysRoleMapper.selectCount(
|
new LambdaQueryWrapper<SysRole>()
|
.eq(SysRole::getRoleCode, code)
|
.eq(SysRole::getDelFlag, 0));
|
if (exists == 0) {
|
return code;
|
}
|
}
|
throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "无法生成唯一角色编码");
|
}
|
|
private void validateRoleNameUnique(String roleName, Long excludeRoleId) {
|
LambdaQueryWrapper<SysRole> query =
|
new LambdaQueryWrapper<SysRole>()
|
.eq(SysRole::getDelFlag, 0)
|
.eq(SysRole::getRoleName, roleName);
|
if (excludeRoleId != null) {
|
query.ne(SysRole::getId, excludeRoleId);
|
}
|
long exists = sysRoleMapper.selectCount(query);
|
if (exists > 0) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "角色名称已存在");
|
}
|
}
|
|
private static String trimToNull(String s) {
|
if (!StringUtils.hasText(s)) {
|
return null;
|
}
|
String t = s.trim();
|
return t.isEmpty() ? null : t;
|
}
|
|
private static String trimToEmpty(String s) {
|
return s == null ? "" : s.trim();
|
}
|
}
|