diff --git a/src/main/java/com/campus/water/controller/web/AdminController.java b/src/main/java/com/campus/water/controller/web/AdminController.java index dcf3dc0..3cf6275 100644 --- a/src/main/java/com/campus/water/controller/web/AdminController.java +++ b/src/main/java/com/campus/water/controller/web/AdminController.java @@ -40,6 +40,22 @@ public class AdminController { } } + + /** + * 新增:查询可分配校区的区域管理员(未负责任何片区) + */ + @GetMapping("/available-area-admins") + @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") + @Operation(summary = "获取可分配校区的区域管理员", description = "返回未负责任何片区的区域管理员,用于片区绑定负责人") + public ResponseEntity>> getAvailableAreaAdmins() { + try { + List availableAdmins = adminService.getAvailableAreaAdmins(); + return ResponseEntity.ok(ResultVO.success(availableAdmins)); + } catch (Exception e) { + return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage())); + } + } + /** * 新增:获取指定区域的管理员列表 */ diff --git a/src/main/java/com/campus/water/controller/web/AreaController.java b/src/main/java/com/campus/water/controller/web/AreaController.java index 3ad45e5..62c2622 100644 --- a/src/main/java/com/campus/water/controller/web/AreaController.java +++ b/src/main/java/com/campus/water/controller/web/AreaController.java @@ -193,7 +193,7 @@ public class AreaController { * 响应:返回该市区下每个校区的设备统计,不进行汇总 */ @GetMapping("/device-stats/city/{cityId}/campuses") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") + @PreAuthorize("hasAnyRole('SUPER_ADMIN')") public ResponseEntity> getCampusDeviceStatsUnderCity(@PathVariable String cityId) { try { List statsVOList = areaService.getCampusDeviceStatsUnderCity(cityId); diff --git a/src/main/java/com/campus/water/mapper/AdminRepository.java b/src/main/java/com/campus/water/mapper/AdminRepository.java index bc3efbd..b7b7458 100644 --- a/src/main/java/com/campus/water/mapper/AdminRepository.java +++ b/src/main/java/com/campus/water/mapper/AdminRepository.java @@ -2,6 +2,7 @@ package com.campus.water.mapper; import com.campus.water.entity.Admin; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; @@ -24,8 +25,6 @@ public interface AdminRepository extends JpaRepository { // 新增:按区域ID查询管理员 List findByAreaId(String areaId); - // 新增:按角色和区域ID查询(用于区域管理员的权限控制) - List findByRoleAndAreaId(Admin.AdminRole role, String areaId); // 按角色查询管理员(核心:恢复角色筛选) List findByRole(Admin.AdminRole role); @@ -33,6 +32,18 @@ public interface AdminRepository extends JpaRepository { // 按姓名+角色组合查询(可选,增强筛选) List findByAdminNameContainingAndRole(String name, Admin.AdminRole role); + // 新增:查询未负责任何片区的区域管理员(role=ROLE_AREA_ADMIN 且 areaId=null) + List findByRoleAndAreaIdIsNull(Admin.AdminRole role); + + // 新增1:查询指定校区的区域管理员(精准查询,用于单个校区权限校验) + List findByRoleAndAreaId(Admin.AdminRole role, String areaId); + + // 新增2:查询所有校区关联的区域管理员(排除市区,用于管理员列表筛选) + // 备注:此处使用@Query注解,关联Area表过滤区域类型为campus的管理员 + @Query("SELECT a FROM Admin a WHERE a.role = ?1 AND a.areaId IN " + + "(SELECT ar.areaId FROM Area ar WHERE ar.areaType = com.campus.water.entity.Area.AreaType.campus)") + List findAllAreaAdminsForCampus(Admin.AdminRole role); + // 检查唯一约束 boolean existsByAdminId(String adminId); boolean existsByPhone(String phone); diff --git a/src/main/java/com/campus/water/mapper/AreaRepository.java b/src/main/java/com/campus/water/mapper/AreaRepository.java index da36134..e40eb6f 100644 --- a/src/main/java/com/campus/water/mapper/AreaRepository.java +++ b/src/main/java/com/campus/water/mapper/AreaRepository.java @@ -54,7 +54,6 @@ public interface AreaRepository extends JpaRepository { * 查询没有负责人的片区(manager为null或空字符串) * 覆盖未设置负责人的所有场景 */ - @Query("SELECT a FROM Area a WHERE a.manager IS NULL OR a.manager = ''") - List findAreasWithoutManager(); + List findByAreaTypeAndManagerIsNullOrManagerEquals(Area.AreaType areaType, String emptyStr); } \ No newline at end of file diff --git a/src/main/java/com/campus/water/service/AdminService.java b/src/main/java/com/campus/water/service/AdminService.java index 39946f3..e21d723 100644 --- a/src/main/java/com/campus/water/service/AdminService.java +++ b/src/main/java/com/campus/water/service/AdminService.java @@ -1,6 +1,7 @@ package com.campus.water.service; import com.campus.water.entity.Admin; +import com.campus.water.entity.Area; import com.campus.water.mapper.AdminRepository; import com.campus.water.mapper.AreaRepository; import lombok.RequiredArgsConstructor; @@ -41,6 +42,14 @@ public class AdminService { } } + /** + * 新增:查询可分配校区的区域管理员(未负责任何片区的区域管理员) + * 用于前端片区选择负责人时的下拉框数据源 + */ + public List getAvailableAreaAdmins() { + return adminRepository.findByRoleAndAreaIdIsNull(Admin.AdminRole.ROLE_AREA_ADMIN); + } + /** * 新增:获取指定区域的管理员列表 */ @@ -69,16 +78,27 @@ public class AdminService { admin.setCreatedTime(LocalDateTime.now()); } - // 区域管理员必须关联区域 + // 区域管理员(ROLE_AREA_ADMIN)的专属校验逻辑 if (admin.getRole() == Admin.AdminRole.ROLE_AREA_ADMIN) { + // 1. 若未填写区域ID(null/空字符串),直接放行(支持先创建管理员,后续补填) if (admin.getAreaId() == null || admin.getAreaId().trim().isEmpty()) { - if (!areaRepository.existsById(admin.getAreaId().trim())) { - throw new RuntimeException("关联的区域不存在:" + admin.getAreaId().trim()); + admin.setAreaId(null); // 统一置为null,避免空字符串冗余数据 + // 无需校验,直接允许保存 + } else { + // 2. 若填写了区域ID,进行严格校验:区域存在 + 类型为校区(禁止市区) + String areaId = admin.getAreaId().trim(); + // 校验区域是否存在 + Area targetArea = areaRepository.findById(areaId) + .orElseThrow(() -> new RuntimeException("关联的区域不存在:" + areaId)); + // 核心校验:仅允许关联校区,禁止关联市区 + if (Area.AreaType.zone.equals(targetArea.getAreaType())) { + throw new RuntimeException("区域管理员仅允许关联校区,不能关联市区,请重新选择"); } + // 校验通过,保留填写的合法校区ID + admin.setAreaId(areaId); } - } else { - // 非区域管理员清空区域ID + // 非区域管理员,清空区域ID,避免冗余数据 admin.setAreaId(null); } diff --git a/src/main/java/com/campus/water/service/AreaService.java b/src/main/java/com/campus/water/service/AreaService.java index d2f7aff..6b14f81 100644 --- a/src/main/java/com/campus/water/service/AreaService.java +++ b/src/main/java/com/campus/water/service/AreaService.java @@ -141,12 +141,14 @@ public class AreaService { } /** - * 获取所有未设置负责人的片区(manager为空或null) - * @return 无负责人片区列表 + * 修改:仅查询无负责人的校区,排除市区 */ - @Transactional(readOnly = true) // 只读事务,提升查询性能 public List getAreasWithoutManager() { - return areaRepository.findAreasWithoutManager(); + // 调用仓库新增方法,限定:区域类型=campus,负责人=null 或 空字符串 + return areaRepository.findByAreaTypeAndManagerIsNullOrManagerEquals( + Area.AreaType.campus, // 仅筛选校区 + "" // 匹配空字符串的负责人 + ); } /** @@ -234,6 +236,10 @@ public class AreaService { private void bindAdminToArea(String adminId, String areaId) { if (adminId != null && !adminId.trim().isEmpty() && areaId != null) { Admin admin = adminRepository.findById(adminId).get(); // 已在前序校验,无需再次处理空值 + // 新增:校验该管理员是否已绑定其他校区 + if (admin.getAreaId() != null) { + throw new RuntimeException("该区域管理员已绑定校区【" + admin.getAreaId() + "】,无法重复绑定"); + } admin.setAreaId(areaId); // 给管理员设置关联的区域ID(Admin实体需有areaId字段) adminRepository.save(admin); }