SystemRoleServiceImpl.java 10.7 KB
package com.diligrp.rider.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.diligrp.rider.common.enums.AdminRoleScopeEnum;
import com.diligrp.rider.common.exception.BizException;
import com.diligrp.rider.dto.AdminRoleSaveDTO;
import com.diligrp.rider.entity.AdminUser;
import com.diligrp.rider.entity.Substation;
import com.diligrp.rider.entity.SysRole;
import com.diligrp.rider.entity.SysRoleMenu;
import com.diligrp.rider.mapper.AdminUserMapper;
import com.diligrp.rider.mapper.SubstationMapper;
import com.diligrp.rider.mapper.SysRoleMapper;
import com.diligrp.rider.mapper.SysRoleMenuMapper;
import com.diligrp.rider.service.SystemRoleService;
import com.diligrp.rider.vo.AdminRoleVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Service
@RequiredArgsConstructor
public class SystemRoleServiceImpl implements SystemRoleService {

    /** 内置角色编码(city_id=0 且 code 在此集合内,不允许编辑/删除) */
    private static final Set<String> BUILT_IN_CODES = Set.of("platform_admin", "substation_admin");

    private final SysRoleMapper sysRoleMapper;
    private final SysRoleMenuMapper sysRoleMenuMapper;
    private final AdminUserMapper adminUserMapper;
    private final SubstationMapper substationMapper;

    // ----------------------------------------------------------------
    // 平台侧:只看/操作 city_id=0 的全局角色
    // ----------------------------------------------------------------

    @Override
    public List<AdminRoleVO> list(boolean includeDisabled) {
        List<SysRole> roles = sysRoleMapper.selectList(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getCityId, 0L)
                .eq(!includeDisabled, SysRole::getStatus, 1)
                .orderByAsc(SysRole::getId));
        return toVOList(roles);
    }

    @Override
    public void add(AdminRoleSaveDTO dto) {
        validateScope(dto.getRoleScope());
        ensureUniqueCode(dto.getCode(), null, 0L);
        SysRole role = buildRole(dto, 0L);
        sysRoleMapper.insert(role);
    }

    @Override
    public void edit(AdminRoleSaveDTO dto) {
        SysRole role = requireRole(dto.getId());
        if (!role.getCityId().equals(0L)) {
            throw new BizException("平台侧不允许编辑分站专属角色");
        }
        if (isBuiltIn(role)) {
            throw new BizException("内置角色不允许编辑");
        }
        validateScope(dto.getRoleScope());
        if (!role.getRoleScope().equals(dto.getRoleScope())) {
            throw new BizException("角色范围不允许修改");
        }
        ensureUniqueCode(dto.getCode(), role.getId(), 0L);
        role.setCode(dto.getCode().trim());
        role.setName(dto.getName().trim());
        sysRoleMapper.updateById(role);
    }

    @Override
    public void ban(Long id) {
        SysRole role = requireRole(id);
        if (!role.getCityId().equals(0L)) {
            throw new BizException("平台侧不允许操作分站专属角色");
        }
        if (isBuiltIn(role)) {
            throw new BizException("内置角色不允许禁用");
        }
        ensureNotBound(role.getId(), "当前角色已绑定账号,不能禁用");
        sysRoleMapper.update(null, new LambdaUpdateWrapper<SysRole>()
                .eq(SysRole::getId, id).set(SysRole::getStatus, 0));
    }

    @Override
    public void cancelBan(Long id) {
        SysRole role = requireRole(id);
        if (!role.getCityId().equals(0L)) {
            throw new BizException("平台侧不允许操作分站专属角色");
        }
        sysRoleMapper.update(null, new LambdaUpdateWrapper<SysRole>()
                .eq(SysRole::getId, id).set(SysRole::getStatus, 1));
    }

    @Override
    @Transactional
    public void del(Long id) {
        SysRole role = requireRole(id);
        if (!role.getCityId().equals(0L)) {
            throw new BizException("平台侧不允许删除分站专属角色");
        }
        if (isBuiltIn(role)) {
            throw new BizException("内置角色不允许删除");
        }
        ensureNotBound(role.getId(), "当前角色已绑定账号,不能删除");
        sysRoleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>()
                .eq(SysRoleMenu::getRoleId, role.getId()));
        sysRoleMapper.deleteById(role.getId());
    }

    // ----------------------------------------------------------------
    // 分站侧:只看/操作本 cityId 的角色
    // ----------------------------------------------------------------

    @Override
    public List<AdminRoleVO> listByCityId(Long cityId) {
        List<SysRole> roles = sysRoleMapper.selectList(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getCityId, cityId)
                .eq(SysRole::getStatus, 1)
                .orderByAsc(SysRole::getId));
        return toVOList(roles);
    }

    @Override
    public void addForCity(AdminRoleSaveDTO dto, Long cityId) {
        // 分站角色只能是 SUBSTATION scope
        if (!AdminRoleScopeEnum.SUBSTATION.name().equals(dto.getRoleScope())) {
            throw new BizException("分站角色范围只能是 SUBSTATION");
        }
        ensureUniqueCode(dto.getCode(), null, cityId);
        SysRole role = buildRole(dto, cityId);
        sysRoleMapper.insert(role);
    }

    @Override
    public void editForCity(AdminRoleSaveDTO dto, Long cityId) {
        SysRole role = requireRole(dto.getId());
        requireOwnedByCity(role, cityId);
        ensureUniqueCode(dto.getCode(), role.getId(), cityId);
        role.setCode(dto.getCode().trim());
        role.setName(dto.getName().trim());
        sysRoleMapper.updateById(role);
    }

    @Override
    public void banForCity(Long id, Long cityId) {
        SysRole role = requireRole(id);
        requireOwnedByCity(role, cityId);
        ensureNotBoundForCity(role.getId(), cityId, "当前角色已绑定账号,不能禁用");
        sysRoleMapper.update(null, new LambdaUpdateWrapper<SysRole>()
                .eq(SysRole::getId, id).set(SysRole::getStatus, 0));
    }

    @Override
    public void cancelBanForCity(Long id, Long cityId) {
        SysRole role = requireRole(id);
        requireOwnedByCity(role, cityId);
        sysRoleMapper.update(null, new LambdaUpdateWrapper<SysRole>()
                .eq(SysRole::getId, id).set(SysRole::getStatus, 1));
    }

    @Override
    @Transactional
    public void delForCity(Long id, Long cityId) {
        SysRole role = requireRole(id);
        requireOwnedByCity(role, cityId);
        ensureNotBoundForCity(role.getId(), cityId, "当前角色已绑定账号,不能删除");
        sysRoleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>()
                .eq(SysRoleMenu::getRoleId, role.getId()));
        sysRoleMapper.deleteById(role.getId());
    }

    // ----------------------------------------------------------------
    // 私有工具方法
    // ----------------------------------------------------------------

    private SysRole requireRole(Long id) {
        if (id == null || id < 1) {
            throw new BizException("角色ID不能为空");
        }
        SysRole role = sysRoleMapper.selectById(id);
        if (role == null) {
            throw new BizException("角色不存在");
        }
        return role;
    }

    private void requireOwnedByCity(SysRole role, Long cityId) {
        if (!cityId.equals(role.getCityId())) {
            throw new BizException("无权操作其他租户的角色");
        }
    }

    private void validateScope(String scope) {
        for (AdminRoleScopeEnum value : AdminRoleScopeEnum.values()) {
            if (value.name().equals(scope)) {
                return;
            }
        }
        throw new BizException("角色范围不合法");
    }

    private void ensureUniqueCode(String code, Long excludeId, Long cityId) {
        SysRole duplicate = sysRoleMapper.selectOne(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getCode, code.trim())
                .eq(SysRole::getCityId, cityId)
                .ne(excludeId != null, SysRole::getId, excludeId)
                .last("LIMIT 1"));
        if (duplicate != null) {
            throw new BizException("角色编码已存在");
        }
    }

    private void ensureNotBound(Long roleId, String message) {
        if (countAdminUsers(roleId) > 0 || countSubstations(roleId) > 0) {
            throw new BizException(message);
        }
    }

    private void ensureNotBoundForCity(Long roleId, Long cityId, String message) {
        Long count = substationMapper.selectCount(new LambdaQueryWrapper<Substation>()
                .eq(Substation::getRoleId, roleId)
                .eq(Substation::getCityId, cityId));
        if (count != null && count > 0) {
            throw new BizException(message);
        }
    }

    private SysRole buildRole(AdminRoleSaveDTO dto, Long cityId) {
        SysRole role = new SysRole();
        role.setCode(dto.getCode().trim());
        role.setName(dto.getName().trim());
        role.setRoleScope(dto.getRoleScope());
        role.setCityId(cityId);
        role.setStatus(1);
        role.setCreateTime(System.currentTimeMillis() / 1000);
        return role;
    }

    private List<AdminRoleVO> toVOList(List<SysRole> roles) {
        List<AdminRoleVO> result = new ArrayList<>();
        for (SysRole role : roles) {
            result.add(toVO(role));
        }
        return result;
    }

    private AdminRoleVO toVO(SysRole role) {
        AdminRoleVO vo = new AdminRoleVO();
        vo.setId(role.getId());
        vo.setCode(role.getCode());
        vo.setName(role.getName());
        vo.setRoleScope(role.getRoleScope());
        vo.setStatus(role.getStatus());
        vo.setBuiltIn(isBuiltIn(role));
        vo.setAdminUserCount(countAdminUsers(role.getId()));
        vo.setSubstationCount(countSubstations(role.getId()));
        vo.setCreateTime(role.getCreateTime());
        return vo;
    }

    private boolean isBuiltIn(SysRole role) {
        // 只有全局角色(city_id=0)且编码匹配才是内置角色
        return role.getCityId() != null && role.getCityId() == 0L
                && BUILT_IN_CODES.contains(role.getCode());
    }

    private long countAdminUsers(Long roleId) {
        Long count = adminUserMapper.selectCount(new LambdaQueryWrapper<AdminUser>()
                .eq(AdminUser::getRoleId, roleId));
        return count == null ? 0L : count;
    }

    private long countSubstations(Long roleId) {
        Long count = substationMapper.selectCount(new LambdaQueryWrapper<Substation>()
                .eq(Substation::getRoleId, roleId));
        return count == null ? 0L : count;
    }
}