增加管理员管理地区代码 #99

Merged
hnu202326010106 merged 1 commits from wanglei_branch into develop 3 weeks ago

@ -39,6 +39,23 @@ public class AdminController {
}
}
/**
*
*/
@GetMapping("/by-area/{areaId}")
@PreAuthorize("hasRole('SUPER_ADMIN')") // 只有超级管理员可以查看
@Operation(summary = "按区域查询管理员", description = "查询指定区域下的所有管理员")
public ResponseEntity<ResultVO<List<Admin>>> getAdminsByArea(
@PathVariable String areaId
) {
try {
List<Admin> admins = adminService.getAdminsByAreaId(areaId);
return ResponseEntity.ok(ResultVO.success(admins));
} catch (Exception e) {
return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage()));
}
}
/**
*
*/
@ -56,11 +73,13 @@ public class AdminController {
/**
* /
*
*/
@PostMapping("/save")
@PreAuthorize("hasRole('SUPER_ADMIN')") // 仅超级管理员可新增/编辑
@Operation(summary = "保存管理员", description = "新增/编辑管理员,支持指定角色")
@PreAuthorize("hasRole('SUPER_ADMIN')")
@Operation(summary = "保存管理员", description = "新增/编辑管理员,区域管理员必须指定areaId")
public ResponseEntity<ResultVO<Admin>> saveAdmin(@RequestBody Admin admin) {
// 实现保持不变
try {
Admin savedAdmin = adminService.saveAdmin(admin);
return ResponseEntity.ok(ResultVO.success(savedAdmin));

@ -0,0 +1,174 @@
package com.campus.water.controller.web;
import com.campus.water.entity.Area;
import com.campus.water.service.AreaService;
import com.campus.water.util.ResultVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
*
* //
*/
@RestController
@RequestMapping("/api/web/area")
@RequiredArgsConstructor
@Tag(name = "区域管理接口", description = "校园、楼宇、区域的层级管理(增删改查)")
public class AreaController {
private final AreaService areaService;
/**
* //
*
*/
@PostMapping("/add")
@PreAuthorize("hasRole('SUPER_ADMIN')")
@Operation(summary = "新增区域", description = "创建校园/楼宇/区域,严格校验层级关联规则")
public ResponseEntity<ResultVO<Area>> addArea(
@RequestBody @Parameter(description = "区域信息(名称/类型为必填)") Area area
) {
try {
Area newArea = areaService.addArea(area);
return ResponseEntity.ok(ResultVO.success(newArea, "新增区域成功"));
} catch (RuntimeException e) {
return ResponseEntity.ok(ResultVO.error(500, "新增失败:" + e.getMessage()));
}
}
/**
*
*
*/
@DeleteMapping("/delete/{areaId}")
@PreAuthorize("hasRole('SUPER_ADMIN')")
@Operation(summary = "删除区域", description = "删除指定区域,需确保无关联管理员和子区域")
public ResponseEntity<ResultVO<Void>> deleteArea(
@PathVariable @Parameter(description = "区域ID") String areaId
) {
try {
areaService.deleteArea(areaId);
return ResponseEntity.ok(ResultVO.success(null, "删除区域成功"));
} catch (RuntimeException e) {
return ResponseEntity.ok(ResultVO.error(500, "删除失败:" + e.getMessage()));
}
}
/**
*
*
*/
@PutMapping("/update")
@PreAuthorize("hasRole('SUPER_ADMIN')")
@Operation(summary = "修改区域", description = "更新区域名称/父级/地址/负责人等信息,不允许修改区域类型")
public ResponseEntity<ResultVO<Area>> updateArea(
@RequestBody @Parameter(description = "区域信息areaId为必填") Area area
) {
try {
if (area.getAreaId() == null || area.getAreaId().trim().isEmpty()) {
return ResponseEntity.ok(ResultVO.error(400, "区域ID不能为空"));
}
Area updatedArea = areaService.updateArea(area);
return ResponseEntity.ok(ResultVO.success(updatedArea, "修改区域成功"));
} catch (RuntimeException e) {
return ResponseEntity.ok(ResultVO.error(500, "修改失败:" + e.getMessage()));
}
}
/**
* ID
* /
*/
@GetMapping("/detail/{areaId}")
@PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')")
@Operation(summary = "查询区域详情", description = "按ID查询单个区域的完整信息")
public ResponseEntity<ResultVO<Area>> getAreaDetail(
@PathVariable @Parameter(description = "区域ID") String areaId
) {
try {
Area area = areaService.getAreaById(areaId);
return ResponseEntity.ok(ResultVO.success(area));
} catch (RuntimeException e) {
return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage()));
}
}
/**
*
* /
*/
@GetMapping("/list")
@PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')")
@Operation(summary = "查询区域列表", description = "支持按父级ID/区域类型/名称关键词筛选区域")
public ResponseEntity<ResultVO<List<Area>>> listAreas(
@RequestParam(required = false) @Parameter(description = "父级区域ID") String parentAreaId,
@RequestParam(required = false) @Parameter(description = "区域类型campus/building/zone") Area.AreaType areaType,
@RequestParam(required = false) @Parameter(description = "名称关键词(模糊匹配)") String keyword
) {
try {
List<Area> areas = areaService.listAreas(parentAreaId, areaType, keyword);
return ResponseEntity.ok(ResultVO.success(areas));
} catch (RuntimeException e) {
return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage()));
}
}
/**
*
* /
*/
@GetMapping("/list-campus")
@PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')")
@Operation(summary = "查询所有校园", description = "快速获取所有校园级别的顶级区域")
public ResponseEntity<ResultVO<List<Area>>> listCampus() {
try {
List<Area> campusList = areaService.listAreas(null, Area.AreaType.campus, null);
return ResponseEntity.ok(ResultVO.success(campusList));
} catch (RuntimeException e) {
return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage()));
}
}
/**
*
* /
*/
@GetMapping("/list-building/{campusId}")
@PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')")
@Operation(summary = "查询校园下的楼宇", description = "按校园ID查询该校园下的所有楼宇")
public ResponseEntity<ResultVO<List<Area>>> listBuildingByCampus(
@PathVariable @Parameter(description = "校园ID") String campusId
) {
try {
List<Area> buildingList = areaService.listAreas(campusId, Area.AreaType.building, null);
return ResponseEntity.ok(ResultVO.success(buildingList));
} catch (RuntimeException e) {
return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage()));
}
}
/**
*
* /
*/
@GetMapping("/list-zone/{buildingId}")
@PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')")
@Operation(summary = "查询楼宇下的区域", description = "按楼宇ID查询该楼宇下的所有子区域")
public ResponseEntity<ResultVO<List<Area>>> listZoneByBuilding(
@PathVariable @Parameter(description = "楼宇ID") String buildingId
) {
try {
List<Area> zoneList = areaService.listAreas(buildingId, Area.AreaType.zone, null);
return ResponseEntity.ok(ResultVO.success(zoneList));
} catch (RuntimeException e) {
return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage()));
}
}
}

@ -25,6 +25,10 @@ public class Admin {
@Column(name = "phone", length = 20)
private String phone;
// 新增管理员负责的区域ID区域管理员专用
@Column(name = "area_id", length = 20)
private String areaId;
// 恢复三个角色枚举
@Enumerated(EnumType.STRING)
@Column(name = "role", length = 50, nullable = false)

@ -8,12 +8,15 @@ package com.campus.water.entity;
import lombok.Data;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import org.hibernate.annotations.GenericGenerator;
@Data
@Entity
@Table(name = "area")
public class Area {
@Id
@GeneratedValue(generator = "uuid") // 新增自动生成UUID
@GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
@Column(name = "area_id", length = 20)
private String areaId;
@ -43,6 +46,18 @@ public class Area {
private LocalDateTime updatedTime = LocalDateTime.now();
public enum AreaType {
campus, building, zone
campus("校园"),
building("楼宇"),
zone("区域");
private final String desc;
AreaType(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}
}

@ -21,6 +21,12 @@ public interface AdminRepository extends JpaRepository<Admin, String> {
// 按手机号查询
Optional<Admin> findByPhone(String phone);
// 新增按区域ID查询管理员
List<Admin> findByAreaId(String areaId);
// 新增按角色和区域ID查询用于区域管理员的权限控制
List<Admin> findByRoleAndAreaId(Admin.AdminRole role, String areaId);
// 按角色查询管理员(核心:恢复角色筛选)
List<Admin> findByRole(Admin.AdminRole role);

@ -14,6 +14,20 @@ public interface AreaRepository extends JpaRepository<Area, String> {
// 根据父区域ID查询子区域
List<Area> findByParentAreaId(String parentAreaId);
// 新增按区域类型查询
List<Area> findByAreaTypeOrderByCreatedTimeDesc(Area.AreaType areaType);
// 按父级ID+类型查询(如查询某校园下的所有楼宇)
List<Area> findByParentAreaIdAndAreaType(String parentAreaId, Area.AreaType areaType);
// 按名称模糊查询
List<Area> findByAreaNameContaining(String keyword);
// 查询所有(按创建时间倒序)
List<Area> findAllByOrderByCreatedTimeDesc();
// 根据管理员姓名查询区域
List<Area> findByManager(String manager);

@ -2,6 +2,7 @@ package com.campus.water.service;
import com.campus.water.entity.Admin;
import com.campus.water.mapper.AdminRepository;
import com.campus.water.mapper.AreaRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
@ -16,6 +17,8 @@ import java.util.Optional;
public class AdminService {
private final AdminRepository adminRepository;
private final AreaRepository areaRepository; // 新增注入
@Autowired
private PasswordEncoder passwordEncoder;
@ -38,6 +41,17 @@ public class AdminService {
}
}
/**
*
*/
public List<Admin> getAdminsByAreaId(String areaId) {
// 校验区域是否存在
if (!areaRepository.existsById(areaId)) {
throw new RuntimeException("区域不存在:" + areaId);
}
return adminRepository.findByAreaId(areaId);
}
/**
* ID
*/
@ -47,12 +61,28 @@ public class AdminService {
/**
* /
*
*/
public Admin saveAdmin(Admin admin) {
admin.setUpdatedTime(LocalDateTime.now());
if (admin.getCreatedTime() == null) {
admin.setCreatedTime(LocalDateTime.now());
}
// 区域管理员必须关联区域
if (admin.getRole() == Admin.AdminRole.ROLE_AREA_ADMIN) {
if (admin.getAreaId() == null || admin.getAreaId().trim().isEmpty()) {
throw new RuntimeException("区域管理员必须关联具体区域");
}
// 校验关联的区域是否存在
if (!areaRepository.existsById(admin.getAreaId())) {
throw new RuntimeException("关联的区域不存在:" + admin.getAreaId());
}
} else {
// 非区域管理员清空区域ID
admin.setAreaId(null);
}
return adminRepository.save(admin);
}
@ -77,4 +107,12 @@ public class AdminService {
public Admin.AdminRole[] getAllRoles() {
return Admin.AdminRole.values();
}
public AreaRepository getAreaRepository() {
return areaRepository;
}
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
}

@ -0,0 +1,187 @@
package com.campus.water.service;
import com.campus.water.entity.Area;
import com.campus.water.mapper.AreaRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
*
* //
*/
@Service
@RequiredArgsConstructor
public class AreaService {
private final AreaRepository areaRepository;
private final AdminService adminService; // 用于删除时校验管理员关联
/**
* //
*
* 1.
* 2.
* 3.
* 4.
*/
public Area addArea(Area area) {
// 基础字段校验
if (area.getAreaName() == null || area.getAreaName().trim().isEmpty()) {
throw new RuntimeException("区域名称不能为空");
}
if (area.getAreaType() == null) {
throw new RuntimeException("区域类型不能为空(校园/楼宇/区域)");
}
// 层级关联校验
handleAreaLevelCheck(area);
// 初始化时间字段(兜底,防止手动修改)
area.setCreatedTime(LocalDateTime.now());
area.setUpdatedTime(LocalDateTime.now());
return areaRepository.save(area);
}
/**
*
*
* 1.
* 2.
* 3.
*/
public void deleteArea(String areaId) {
// 1. 校验区域是否存在
Area existArea = areaRepository.findById(areaId)
.orElseThrow(() -> new RuntimeException("区域不存在:" + areaId));
// 2. 校验是否有管理员关联该区域
List<com.campus.water.entity.Admin> relatedAdmins = adminService.getAdminsByAreaId(areaId);
if (!relatedAdmins.isEmpty()) {
throw new RuntimeException("该区域关联了" + relatedAdmins.size() + "个管理员,无法删除");
}
// 3. 校验是否有下级子区域
List<Area> childAreas = areaRepository.findByParentAreaId(areaId);
if (!childAreas.isEmpty()) {
throw new RuntimeException("该区域包含" + childAreas.size() + "个子区域,无法删除(请先删除子区域)");
}
// 执行删除
areaRepository.delete(existArea);
}
/**
*
*
*
*/
public Area updateArea(Area area) {
// 1. 校验区域是否存在
Area existArea = areaRepository.findById(area.getAreaId())
.orElseThrow(() -> new RuntimeException("区域不存在:" + area.getAreaId()));
// 2. 基础字段校验
if (area.getAreaName() == null || area.getAreaName().trim().isEmpty()) {
throw new RuntimeException("区域名称不能为空");
}
// 3. 层级关联校验如果修改了父级ID
if (!equalsWithNull(existArea.getParentAreaId(), area.getParentAreaId())) {
handleAreaLevelCheck(area);
}
// 4. 赋值(仅更新允许修改的字段)
existArea.setAreaName(area.getAreaName());
existArea.setParentAreaId(area.getParentAreaId());
existArea.setAddress(area.getAddress());
existArea.setManager(area.getManager());
existArea.setManagerPhone(area.getManagerPhone());
existArea.setUpdatedTime(LocalDateTime.now());
// 5. 保存修改
return areaRepository.save(existArea);
}
/**
* ID
*/
public Area getAreaById(String areaId) {
return areaRepository.findById(areaId)
.orElseThrow(() -> new RuntimeException("区域不存在:" + areaId));
}
/**
*
* ID
*/
public List<Area> listAreas(String parentAreaId, Area.AreaType areaType, String keyword) {
if (parentAreaId != null && !parentAreaId.trim().isEmpty()) {
// 按父级ID查询
if (areaType != null) {
// 父级ID + 类型
return areaRepository.findByParentAreaIdAndAreaType(parentAreaId, areaType);
} else {
// 仅父级ID
return areaRepository.findByParentAreaId(parentAreaId);
}
} else if (areaType != null) {
// 按类型查询
return areaRepository.findByAreaTypeOrderByCreatedTimeDesc(areaType);
} else if (keyword != null && !keyword.trim().isEmpty()) {
// 按名称模糊查询
return areaRepository.findByAreaNameContaining(keyword);
} else {
// 查询所有(按创建时间倒序)
return areaRepository.findAllByOrderByCreatedTimeDesc();
}
}
/**
*
*/
private void handleAreaLevelCheck(Area area) {
Area.AreaType type = area.getAreaType();
String parentId = area.getParentAreaId();
// 1. 校园(顶级节点):不允许设置父级
if (type == Area.AreaType.campus) {
if (parentId != null && !parentId.trim().isEmpty()) {
throw new RuntimeException("校园作为顶级节点,不允许关联父级区域");
}
return;
}
// 2. 楼宇/区域:必须设置父级
if (parentId == null || parentId.trim().isEmpty()) {
throw new RuntimeException(type.getDesc() + "必须关联父级区域");
}
// 3. 校验父级区域是否存在且类型匹配
Area parentArea = areaRepository.findById(parentId)
.orElseThrow(() -> new RuntimeException("父级区域不存在:" + parentId));
if (type == Area.AreaType.building && parentArea.getAreaType() != Area.AreaType.campus) {
throw new RuntimeException("楼宇的父级必须是校园");
}
if (type == Area.AreaType.zone && parentArea.getAreaType() != Area.AreaType.building) {
throw new RuntimeException("区域的父级必须是楼宇");
}
}
/**
* null
*/
private boolean equalsWithNull(Object a, Object b) {
if (a == null && b == null) {
return true;
}
if (a == null || b == null) {
return false;
}
return a.equals(b);
}
}
Loading…
Cancel
Save