From aa72787505fb7a621ee95bab9099bded18e652b5 Mon Sep 17 00:00:00 2001 From: wanglei <3085637232@qq.com> Date: Sat, 27 Dec 2025 12:05:00 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9C=B0=E5=8C=BA?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../water/controller/web/AreaController.java | 199 +++++++-------- .../java/com/campus/water/entity/Area.java | 13 +- .../campus/water/mapper/AreaRepository.java | 36 +-- .../com/campus/water/service/AreaService.java | 233 ++++++++---------- 4 files changed, 218 insertions(+), 263 deletions(-) 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 aebfddf..131c14b 100644 --- a/src/main/java/com/campus/water/controller/web/AreaController.java +++ b/src/main/java/com/campus/water/controller/web/AreaController.java @@ -2,173 +2,152 @@ 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.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 区域管理控制器 - * 处理校园/楼宇/区域的增删改查接口请求 + * 不使用 ResultVO,直接通过 ResponseEntity 返回响应 + * 适配 Area 实体(areaId 主键、市区-校园层级) */ @RestController -@RequestMapping("/api/web/area") -@RequiredArgsConstructor -@Tag(name = "区域管理接口", description = "校园、楼宇、区域的层级管理(增删改查)") +@RequestMapping("/api/area") +@CrossOrigin // 允许跨域(前端调用时需要) public class AreaController { private final AreaService areaService; - /** - * 新增区域(校园/楼宇/区域) - * 仅超级管理员可操作 - */ - @PostMapping("/add") - @PreAuthorize("hasRole('SUPER_ADMIN')") - @Operation(summary = "新增区域", description = "创建校园/楼宇/区域,严格校验层级关联规则") - public ResponseEntity> 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())); - } + // 构造器注入 + public AreaController(AreaService areaService) { + this.areaService = areaService; } /** - * 删除区域 - * 仅超级管理员可操作,需校验无关联管理员和子区域 + * 构建通用响应体 + * @param code 响应码(200成功,400参数/业务异常,500系统异常) + * @param msg 响应消息 + * @param data 响应数据 + * @return 封装后的Map响应体 */ - @DeleteMapping("/delete/{areaId}") - @PreAuthorize("hasRole('SUPER_ADMIN')") - @Operation(summary = "删除区域", description = "删除指定区域,需确保无关联管理员和子区域") - public ResponseEntity> 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())); - } + private Map buildResponse(int code, String msg, Object data) { + Map response = new HashMap<>(); + response.put("code", code); + response.put("msg", msg); + response.put("data", data); + return response; } /** - * 修改区域信息 - * 仅超级管理员可操作,不允许修改区域类型 + * 新增区域(市区/校园) + * @param area 区域信息(JSON格式) + * @return 新增后的区域对象 */ - @PutMapping("/update") - @PreAuthorize("hasRole('SUPER_ADMIN')") - @Operation(summary = "修改区域", description = "更新区域名称/父级/地址/负责人等信息,不允许修改区域类型") - public ResponseEntity> updateArea( - @RequestBody @Parameter(description = "区域信息(areaId为必填)") Area area - ) { + @PostMapping("/add") + public ResponseEntity> addArea(@RequestBody 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, "修改区域成功")); + Area savedArea = areaService.addArea(area); + return ResponseEntity.ok(buildResponse(200, "新增成功", savedArea)); } catch (RuntimeException e) { - return ResponseEntity.ok(ResultVO.error(500, "修改失败:" + e.getMessage())); + // 业务异常:400状态码 + 具体提示 + return ResponseEntity.badRequest().body(buildResponse(400, e.getMessage(), null)); + } catch (Exception e) { + // 系统异常:500状态码 + 通用提示 + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "新增区域失败:" + e.getMessage(), null)); } } /** - * 按ID查询区域详情 - * 超级管理员/区域管理员均可查询 + * 修改区域 + * @param areaId 区域ID + * @param area 待修改的区域信息 + * @return 修改后的区域对象 */ - @GetMapping("/detail/{areaId}") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") - @Operation(summary = "查询区域详情", description = "按ID查询单个区域的完整信息") - public ResponseEntity> getAreaDetail( - @PathVariable @Parameter(description = "区域ID") String areaId - ) { + @PutMapping("/update/{areaId}") + public ResponseEntity> updateArea(@PathVariable String areaId, @RequestBody Area area) { try { - Area area = areaService.getAreaById(areaId); - return ResponseEntity.ok(ResultVO.success(area)); + Area updatedArea = areaService.updateArea(areaId, area); + return ResponseEntity.ok(buildResponse(200, "修改成功", updatedArea)); } catch (RuntimeException e) { - return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage())); + return ResponseEntity.badRequest().body(buildResponse(400, e.getMessage(), null)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "修改区域失败:" + e.getMessage(), null)); } } /** - * 条件查询区域列表 - * 超级管理员/区域管理员均可查询,支持多条件筛选 + * 删除区域 + * @param areaId 区域ID + * @return 操作结果 */ - @GetMapping("/list") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") - @Operation(summary = "查询区域列表", description = "支持按父级ID/区域类型/名称关键词筛选区域") - public ResponseEntity>> 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 - ) { + @DeleteMapping("/delete/{areaId}") + public ResponseEntity> deleteArea(@PathVariable String areaId) { try { - List areas = areaService.listAreas(parentAreaId, areaType, keyword); - return ResponseEntity.ok(ResultVO.success(areas)); + areaService.deleteArea(areaId); + return ResponseEntity.ok(buildResponse(200, "删除成功", null)); } catch (RuntimeException e) { - return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage())); + return ResponseEntity.badRequest().body(buildResponse(400, e.getMessage(), null)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "删除区域失败:" + e.getMessage(), null)); } } /** - * 查询所有校园(顶级节点) - * 超级管理员/区域管理员均可查询 + * 查询所有市区(根节点) + * @return 市区列表 */ - @GetMapping("/list-campus") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") - @Operation(summary = "查询所有校园", description = "快速获取所有校园级别的顶级区域") - public ResponseEntity>> listCampus() { + @GetMapping("/cities") + public ResponseEntity> getAllCities() { try { - List 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())); + List cities = areaService.getAllCities(); + return ResponseEntity.ok(buildResponse(200, "查询成功", cities)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "查询市区列表失败:" + e.getMessage(), null)); } } /** - * 查询指定校园下的所有楼宇 - * 超级管理员/区域管理员均可查询 + * 根据市区ID查询下属校园 + * @param cityId 市区ID(areaId) + * @return 该市区下的校园列表 */ - @GetMapping("/list-building/{campusId}") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") - @Operation(summary = "查询校园下的楼宇", description = "按校园ID查询该校园下的所有楼宇") - public ResponseEntity>> listBuildingByCampus( - @PathVariable @Parameter(description = "校园ID") String campusId - ) { + @GetMapping("/campuses/{cityId}") + public ResponseEntity> getCampusesByCityId(@PathVariable String cityId) { try { - List buildingList = areaService.listAreas(campusId, Area.AreaType.building, null); - return ResponseEntity.ok(ResultVO.success(buildingList)); + List campuses = areaService.getCampusesByCityId(cityId); + return ResponseEntity.ok(buildResponse(200, "查询成功", campuses)); } catch (RuntimeException e) { - return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage())); + return ResponseEntity.badRequest().body(buildResponse(400, e.getMessage(), null)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "查询校园列表失败:" + e.getMessage(), null)); } } /** - * 查询指定楼宇下的所有区域 - * 超级管理员/区域管理员均可查询 + * 根据区域ID查询单个区域信息 + * (扩展接口:方便前端回显详情) + * @param areaId 区域ID + * @return 区域详情 */ - @GetMapping("/list-zone/{buildingId}") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") - @Operation(summary = "查询楼宇下的区域", description = "按楼宇ID查询该楼宇下的所有子区域") - public ResponseEntity>> listZoneByBuilding( - @PathVariable @Parameter(description = "楼宇ID") String buildingId - ) { + @GetMapping("/{areaId}") + public ResponseEntity> getAreaById(@PathVariable String areaId) { try { - List zoneList = areaService.listAreas(buildingId, Area.AreaType.zone, null); - return ResponseEntity.ok(ResultVO.success(zoneList)); + Area area = areaService.getAreaById(areaId); + return ResponseEntity.ok(buildResponse(200, "查询成功", area)); } catch (RuntimeException e) { - return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage())); + return ResponseEntity.badRequest().body(buildResponse(400, e.getMessage(), null)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "查询区域详情失败:" + e.getMessage(), null)); } } } \ No newline at end of file diff --git a/src/main/java/com/campus/water/entity/Area.java b/src/main/java/com/campus/water/entity/Area.java index 476a963..c2fd4e6 100644 --- a/src/main/java/com/campus/water/entity/Area.java +++ b/src/main/java/com/campus/water/entity/Area.java @@ -45,19 +45,22 @@ public class Area { @Column(name = "updated_time") private LocalDateTime updatedTime = LocalDateTime.now(); + + + // 枚举值与数据库完全匹配:zone=市区,campus=校园,building=楼栋(暂时保留) public enum AreaType { - campus("校园"), - building("楼宇"), - zone("区域"); + zone("市区"), // 对应数据库的zone,含义是市区 + campus("校园"); // 对应数据库的campus,含义是校园 - private final String desc; + private final String desc; AreaType(String desc) { this.desc = desc; } - public String getDesc() { return desc; } } + + } \ No newline at end of file diff --git a/src/main/java/com/campus/water/mapper/AreaRepository.java b/src/main/java/com/campus/water/mapper/AreaRepository.java index da22769..ee27455 100644 --- a/src/main/java/com/campus/water/mapper/AreaRepository.java +++ b/src/main/java/com/campus/water/mapper/AreaRepository.java @@ -2,39 +2,27 @@ package com.campus.water.mapper; import com.campus.water.entity.Area; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; + import java.util.List; +import java.util.Optional; @Repository public interface AreaRepository extends JpaRepository { - // 根据区域类型查询 - List findByAreaType(Area.AreaType areaType); - // 根据父区域ID查询子区域 - List findByParentAreaId(String parentAreaId); + // 修正:将findByIdAndIsDeletedFalse改为findByAreaIdAndIsDeletedFalse(如果有isDeleted字段) + // 注意:你的实体类目前没有isDeleted字段,先删除该方法,或补充字段后再用 + Optional findByAreaId(String areaId); - // 新增按区域类型查询 - List findByAreaTypeOrderByCreatedTimeDesc(Area.AreaType areaType); + // 查询所有市区(根节点:areaType=CITY 且 parentAreaId=null) + List findByAreaTypeAndParentAreaIdIsNull(Area.AreaType areaType); - // 按父级ID+类型查询(如查询某校园下的所有楼宇) + // 根据父级ID和区域类型查询(指定市区下的校园) List findByParentAreaIdAndAreaType(String parentAreaId, Area.AreaType areaType); + // 统计指定父级ID下的区域数量 + long countByParentAreaId(String parentAreaId); - - // 按名称模糊查询 - List findByAreaNameContaining(String keyword); - - // 查询所有(按创建时间倒序) - List findAllByOrderByCreatedTimeDesc(); - - // 根据管理员姓名查询区域 - List findByManager(String manager); - - // 根据管理员手机号查询区域 - List findByManagerPhone(String managerPhone); - - // 查询指定类型的根级区域 - @Query("SELECT a FROM Area a WHERE a.areaType = ?1 AND a.parentAreaId IS NULL") - List findRootAreasByType(Area.AreaType areaType); + // 校验区域ID是否存在 + boolean existsByAreaId(String areaId); } \ No newline at end of file diff --git a/src/main/java/com/campus/water/service/AreaService.java b/src/main/java/com/campus/water/service/AreaService.java index f59a170..c1edf8d 100644 --- a/src/main/java/com/campus/water/service/AreaService.java +++ b/src/main/java/com/campus/water/service/AreaService.java @@ -2,186 +2,171 @@ 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 org.springframework.transaction.annotation.Transactional; + import java.time.LocalDateTime; import java.util.List; import java.util.Optional; /** - * 区域管理服务层 - * 处理校园/楼宇/区域的增删改查业务逻辑 + * 区域管理服务类 + * 完全适配你的 Area 实体类(areaId 主键、新增 address/manager 等字段) + * 核心规则:市区为根节点(无父级),校园必须以市区为父节点 */ @Service -@RequiredArgsConstructor public class AreaService { private final AreaRepository areaRepository; - private final AdminService adminService; // 用于删除时校验管理员关联 + + // 构造器注入(推荐的注入方式) + public AreaService(AreaRepository areaRepository) { + this.areaRepository = areaRepository; + } /** - * 新增区域(校园/楼宇/区域) - * 校验规则: - * 1. 名称和类型不能为空 - * 2. 楼宇必须关联校园作为父级 - * 3. 区域必须关联楼宇作为父级 - * 4. 校园无需父级(顶级节点) + * 新增区域 + * @param area 区域对象(包含名称、类型、父级ID、地址、管理员等) + * @return 保存后的区域对象 */ + @Transactional(rollbackFor = Exception.class) public Area addArea(Area area) { - // 基础字段校验 - if (area.getAreaName() == null || area.getAreaName().trim().isEmpty()) { - throw new RuntimeException("区域名称不能为空"); - } - if (area.getAreaType() == null) { - throw new RuntimeException("区域类型不能为空(校园/楼宇/区域)"); - } + // 1. 基础参数校验 + validateBaseParams(area); - // 层级关联校验 - handleAreaLevelCheck(area); + // 2. 层级规则校验(核心) + validateAreaHierarchy(area); - // 初始化时间字段(兜底,防止手动修改) + // 3. 补充基础字段(createdTime/updatedTime 已默认赋值,可手动刷新) area.setCreatedTime(LocalDateTime.now()); area.setUpdatedTime(LocalDateTime.now()); + // 4. 保存数据 return areaRepository.save(area); } /** - * 删除区域 - * 校验规则: - * 1. 区域必须存在 - * 2. 无管理员关联该区域 - * 3. 无下级子区域 + * 修改区域 + * @param areaId 区域ID + * @param area 待修改的区域信息 + * @return 修改后的区域对象 */ - public void deleteArea(String areaId) { + @Transactional(rollbackFor = Exception.class) + public Area updateArea(String areaId, Area area) { // 1. 校验区域是否存在 - Area existArea = areaRepository.findById(areaId) - .orElseThrow(() -> new RuntimeException("区域不存在:" + areaId)); + Area existingArea = areaRepository.findByAreaId(areaId) + .orElseThrow(() -> new RuntimeException("区域不存在,ID:" + areaId)); - // 2. 校验是否有管理员关联该区域 - List relatedAdmins = adminService.getAdminsByAreaId(areaId); - if (!relatedAdmins.isEmpty()) { - throw new RuntimeException("该区域关联了" + relatedAdmins.size() + "个管理员,无法删除"); - } + // 2. 基础参数校验 + validateBaseParams(area); - // 3. 校验是否有下级子区域 - List childAreas = areaRepository.findByParentAreaId(areaId); - if (!childAreas.isEmpty()) { - throw new RuntimeException("该区域包含" + childAreas.size() + "个子区域,无法删除(请先删除子区域)"); + // 3. 层级规则校验(修改时需保持层级规则) + validateAreaHierarchy(area); + + // 4. 覆盖可修改字段(适配你的实体类所有字段) + existingArea.setAreaName(area.getAreaName()); + existingArea.setAreaType(area.getAreaType()); + // 父级ID:市区不允许修改,校园必须指向市区 + if (Area.AreaType.campus.equals(area.getAreaType())) { + existingArea.setParentAreaId(area.getParentAreaId()); } + // 新增字段赋值 + existingArea.setAddress(area.getAddress()); + existingArea.setManager(area.getManager()); + existingArea.setManagerPhone(area.getManagerPhone()); + // 更新时间 + existingArea.setUpdatedTime(LocalDateTime.now()); - // 执行删除 - areaRepository.delete(existArea); + // 5. 保存修改 + return areaRepository.save(existingArea); } /** - * 修改区域信息 - * 支持修改:名称、父级、地址、负责人、联系电话 - * 不允许修改:区域类型(避免层级混乱) + * 删除区域 + * @param areaId 区域ID */ - public Area updateArea(Area area) { + @Transactional(rollbackFor = Exception.class) + public void deleteArea(String areaId) { // 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); + Area existingArea = areaRepository.findByAreaId(areaId) + .orElseThrow(() -> new RuntimeException("区域不存在,ID:" + areaId)); + + // 2. 校验删除规则:若为市区,需先删除其下所有校园 + if (Area.AreaType.zone.equals(existingArea.getAreaType())) { + long campusCount = areaRepository.countByParentAreaId(areaId); + if (campusCount > 0) { + throw new RuntimeException("该市区下仍有 " + campusCount + " 个校园,无法删除,请先删除下属校园"); + } } - // 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); + // 3. 物理删除(若需逻辑删除,可参考后续说明添加 isDeleted 字段) + areaRepository.delete(existingArea); } /** - * 按ID查询区域详情 + * 查询所有市区(根节点) + * @return 市区列表 */ - public Area getAreaById(String areaId) { - return areaRepository.findById(areaId) - .orElseThrow(() -> new RuntimeException("区域不存在:" + areaId)); + public List getAllCities() { + return areaRepository.findByAreaTypeAndParentAreaIdIsNull(Area.AreaType.zone); } /** - * 条件查询区域列表 - * 支持筛选条件:父级ID、区域类型、名称关键词 + * 根据市区ID查询下属校园 + * @param cityId 市区ID(areaId) + * @return 该市区下的校园列表 */ - public List 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(); + public List getCampusesByCityId(String cityId) { + // 校验市区是否存在 + if (!areaRepository.existsByAreaId(cityId)) { + throw new RuntimeException("市区不存在,ID:" + cityId); } + return areaRepository.findByParentAreaIdAndAreaType(cityId, Area.AreaType.campus ); } /** - * 辅助方法:校验区域层级关联规则 + * 基础参数校验(名称、类型不能为空) + * @param area 区域对象 */ - 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("楼宇的父级必须是校园"); + private void validateBaseParams(Area area) { + if (area.getAreaName() == null || area.getAreaName().trim().isEmpty()) { + throw new RuntimeException("区域名称不能为空"); } - if (type == Area.AreaType.zone && parentArea.getAreaType() != Area.AreaType.building) { - throw new RuntimeException("区域的父级必须是楼宇"); + if (area.getAreaType() == null) { + throw new RuntimeException("区域类型不能为空(市区/校园)"); } } /** - * 辅助方法:判断两个值是否相等(兼容null) + * 区域层级规则校验(核心) + * 规则1:市区必须是根节点,无父级ID(parentAreaId=null) + * 规则2:校园必须有父级ID,且父级必须是市区 */ - private boolean equalsWithNull(Object a, Object b) { - if (a == null && b == null) { - return true; - } - if (a == null || b == null) { - return false; + private void validateAreaHierarchy(Area area) { + if (Area.AreaType.zone.equals(area.getAreaType())) { + // 市区不允许设置父级ID + if (area.getParentAreaId() != null && !area.getParentAreaId().trim().isEmpty()) { + throw new RuntimeException("市区为根节点,不允许设置父级区域"); + } + } else if (Area.AreaType.campus .equals(area.getAreaType())) { + // 校园必须设置父级ID + if (area.getParentAreaId() == null || area.getParentAreaId().trim().isEmpty()) { + throw new RuntimeException("校园必须关联市区作为父级区域"); + } + // 校验父级区域是否存在且类型为市区 + Optional parentAreaOpt = areaRepository.findByAreaId(area.getParentAreaId()); + if (parentAreaOpt.isEmpty()) { + throw new RuntimeException("父级市区不存在,ID:" + area.getParentAreaId()); + } + Area parentArea = parentAreaOpt.get(); + if (!Area.AreaType.zone.equals(parentArea.getAreaType())) { + throw new RuntimeException("校园的父级区域必须是市区,当前父级类型为:" + parentArea.getAreaType().getDesc()); + } } - return a.equals(b); + } + + public Area getAreaById(String areaId) { + return areaRepository.findByAreaId(areaId) + .orElseThrow(() -> new RuntimeException("区域不存在,ID:" + areaId)); } } \ No newline at end of file -- 2.34.1 From e4aded018eabb8816544038b5e73c4619b5644f4 Mon Sep 17 00:00:00 2001 From: wanglei <3085637232@qq.com> Date: Sat, 27 Dec 2025 12:10:22 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9C=B0=E5=8C=BA?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../water/controller/web/AreaController.java | 199 ++++++++---------- 1 file changed, 89 insertions(+), 110 deletions(-) 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 ab0326b..131c14b 100644 --- a/src/main/java/com/campus/water/controller/web/AreaController.java +++ b/src/main/java/com/campus/water/controller/web/AreaController.java @@ -2,173 +2,152 @@ 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.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 区域管理控制器 - * 处理校园/楼宇/区域的增删改查接口请求 + * 不使用 ResultVO,直接通过 ResponseEntity 返回响应 + * 适配 Area 实体(areaId 主键、市区-校园层级) */ @RestController -@RequestMapping("/api/web/area") -@RequiredArgsConstructor -@Tag(name = "区域管理接口", description = "校园、楼宇、区域的层级管理(增删改查)") +@RequestMapping("/api/area") +@CrossOrigin // 允许跨域(前端调用时需要) public class AreaController { private final AreaService areaService; - /** - * 新增区域(校园/楼宇/区域) - * 仅超级管理员可操作 - */ - @PostMapping("/add") - @PreAuthorize("hasRole('SUPER_ADMIN')") - @Operation(summary = "新增区域", description = "创建校园/楼宇/区域,严格校验层级关联规则") - public ResponseEntity> 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())); - } + // 构造器注入 + public AreaController(AreaService areaService) { + this.areaService = areaService; } /** - * 删除区域 - * 仅超级管理员可操作,需校验无关联管理员和子区域 + * 构建通用响应体 + * @param code 响应码(200成功,400参数/业务异常,500系统异常) + * @param msg 响应消息 + * @param data 响应数据 + * @return 封装后的Map响应体 */ - @DeleteMapping("/delete/{areaId}") - @PreAuthorize("hasRole('SUPER_ADMIN')") - @Operation(summary = "删除区域", description = "删除指定区域,需确保无关联管理员和子区域") - public ResponseEntity> 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())); - } + private Map buildResponse(int code, String msg, Object data) { + Map response = new HashMap<>(); + response.put("code", code); + response.put("msg", msg); + response.put("data", data); + return response; } /** - * 修改区域信息 - * 仅超级管理员可操作,不允许修改区域类型 + * 新增区域(市区/校园) + * @param area 区域信息(JSON格式) + * @return 新增后的区域对象 */ - @PutMapping("/update") - @PreAuthorize("hasRole('SUPER_ADMIN')") - @Operation(summary = "修改区域", description = "更新区域名称/父级/地址/负责人等信息,不允许修改区域类型") - public ResponseEntity> updateArea( - @RequestBody @Parameter(description = "区域信息(areaId为必填)") Area area - ) { + @PostMapping("/add") + public ResponseEntity> addArea(@RequestBody Area area) { try { - if (area.getAreaId() == null) { - return ResponseEntity.ok(ResultVO.error(400, "区域ID不能为空")); - } - Area updatedArea = areaService.updateArea(area); - return ResponseEntity.ok(ResultVO.success(updatedArea, "修改区域成功")); + Area savedArea = areaService.addArea(area); + return ResponseEntity.ok(buildResponse(200, "新增成功", savedArea)); } catch (RuntimeException e) { - return ResponseEntity.ok(ResultVO.error(500, "修改失败:" + e.getMessage())); + // 业务异常:400状态码 + 具体提示 + return ResponseEntity.badRequest().body(buildResponse(400, e.getMessage(), null)); + } catch (Exception e) { + // 系统异常:500状态码 + 通用提示 + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "新增区域失败:" + e.getMessage(), null)); } } /** - * 按ID查询区域详情 - * 超级管理员/区域管理员均可查询 + * 修改区域 + * @param areaId 区域ID + * @param area 待修改的区域信息 + * @return 修改后的区域对象 */ - @GetMapping("/detail/{areaId}") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") - @Operation(summary = "查询区域详情", description = "按ID查询单个区域的完整信息") - public ResponseEntity> getAreaDetail( - @PathVariable @Parameter(description = "区域ID") String areaId - ) { + @PutMapping("/update/{areaId}") + public ResponseEntity> updateArea(@PathVariable String areaId, @RequestBody Area area) { try { - Area area = areaService.getAreaById(areaId); - return ResponseEntity.ok(ResultVO.success(area)); + Area updatedArea = areaService.updateArea(areaId, area); + return ResponseEntity.ok(buildResponse(200, "修改成功", updatedArea)); } catch (RuntimeException e) { - return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage())); + return ResponseEntity.badRequest().body(buildResponse(400, e.getMessage(), null)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "修改区域失败:" + e.getMessage(), null)); } } /** - * 条件查询区域列表 - * 超级管理员/区域管理员均可查询,支持多条件筛选 + * 删除区域 + * @param areaId 区域ID + * @return 操作结果 */ - @GetMapping("/list") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") - @Operation(summary = "查询区域列表", description = "支持按父级ID/区域类型/名称关键词筛选区域") - public ResponseEntity>> 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 - ) { + @DeleteMapping("/delete/{areaId}") + public ResponseEntity> deleteArea(@PathVariable String areaId) { try { - List areas = areaService.listAreas(parentAreaId, areaType, keyword); - return ResponseEntity.ok(ResultVO.success(areas)); + areaService.deleteArea(areaId); + return ResponseEntity.ok(buildResponse(200, "删除成功", null)); } catch (RuntimeException e) { - return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage())); + return ResponseEntity.badRequest().body(buildResponse(400, e.getMessage(), null)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "删除区域失败:" + e.getMessage(), null)); } } /** - * 查询所有校园(顶级节点) - * 超级管理员/区域管理员均可查询 + * 查询所有市区(根节点) + * @return 市区列表 */ - @GetMapping("/list-campus") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") - @Operation(summary = "查询所有校园", description = "快速获取所有校园级别的顶级区域") - public ResponseEntity>> listCampus() { + @GetMapping("/cities") + public ResponseEntity> getAllCities() { try { - List 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())); + List cities = areaService.getAllCities(); + return ResponseEntity.ok(buildResponse(200, "查询成功", cities)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "查询市区列表失败:" + e.getMessage(), null)); } } /** - * 查询指定校园下的所有楼宇 - * 超级管理员/区域管理员均可查询 + * 根据市区ID查询下属校园 + * @param cityId 市区ID(areaId) + * @return 该市区下的校园列表 */ - @GetMapping("/list-building/{campusId}") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") - @Operation(summary = "查询校园下的楼宇", description = "按校园ID查询该校园下的所有楼宇") - public ResponseEntity>> listBuildingByCampus( - @PathVariable @Parameter(description = "校园ID") String campusId - ) { + @GetMapping("/campuses/{cityId}") + public ResponseEntity> getCampusesByCityId(@PathVariable String cityId) { try { - List buildingList = areaService.listAreas(campusId, Area.AreaType.building, null); - return ResponseEntity.ok(ResultVO.success(buildingList)); + List campuses = areaService.getCampusesByCityId(cityId); + return ResponseEntity.ok(buildResponse(200, "查询成功", campuses)); } catch (RuntimeException e) { - return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage())); + return ResponseEntity.badRequest().body(buildResponse(400, e.getMessage(), null)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "查询校园列表失败:" + e.getMessage(), null)); } } /** - * 查询指定楼宇下的所有区域 - * 超级管理员/区域管理员均可查询 + * 根据区域ID查询单个区域信息 + * (扩展接口:方便前端回显详情) + * @param areaId 区域ID + * @return 区域详情 */ - @GetMapping("/list-zone/{buildingId}") - @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") - @Operation(summary = "查询楼宇下的区域", description = "按楼宇ID查询该楼宇下的所有子区域") - public ResponseEntity>> listZoneByBuilding( - @PathVariable @Parameter(description = "楼宇ID") String buildingId - ) { + @GetMapping("/{areaId}") + public ResponseEntity> getAreaById(@PathVariable String areaId) { try { - List zoneList = areaService.listAreas(buildingId, Area.AreaType.zone, null); - return ResponseEntity.ok(ResultVO.success(zoneList)); + Area area = areaService.getAreaById(areaId); + return ResponseEntity.ok(buildResponse(200, "查询成功", area)); } catch (RuntimeException e) { - return ResponseEntity.ok(ResultVO.error(500, "查询失败:" + e.getMessage())); + return ResponseEntity.badRequest().body(buildResponse(400, e.getMessage(), null)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(buildResponse(500, "查询区域详情失败:" + e.getMessage(), null)); } } } \ No newline at end of file -- 2.34.1