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 6acf470..d303526 100644 --- a/src/main/java/com/campus/water/controller/web/AreaController.java +++ b/src/main/java/com/campus/water/controller/web/AreaController.java @@ -2,6 +2,7 @@ package com.campus.water.controller.web; import com.campus.water.entity.Area; import com.campus.water.service.AreaService; +import com.campus.water.entity.vo.AreaDeviceStatsVO; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; @@ -148,4 +149,47 @@ public class AreaController { .body(buildResponse(500, "查询区域详情失败:" + e.getMessage(), null)); } } + + /** + * 获取指定片区设备统计 + * 权限:超级管理员/区域管理员(与新增/修改区域权限一致) + * 响应:校区返回自身数据,市区返回下属校区汇总数据 + */ + @GetMapping("/device-stats/{areaId}") + @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") + public ResponseEntity> getAreaDeviceStats(@PathVariable String areaId) { + try { + AreaDeviceStatsVO statsVO = areaService.getAreaDeviceStats(areaId); + return ResponseEntity.ok(buildResponse(200, "统计成功", statsVO)); + } catch (RuntimeException e) { + // 业务异常(片区不存在、参数错误等)返回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)); + } + } + + /** + * 获取市区下所有校区单独统计 + * 权限:超级管理员/区域管理员(与新增/修改区域权限一致) + * 响应:返回该市区下每个校区的设备统计,不进行汇总 + */ + @GetMapping("/device-stats/city/{cityId}/campuses") + @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") + public ResponseEntity> getCampusDeviceStatsUnderCity(@PathVariable String cityId) { + try { + List statsVOList = areaService.getCampusDeviceStatsUnderCity(cityId); + return ResponseEntity.ok(buildResponse(200, "统计成功", statsVOList)); + } catch (RuntimeException e) { + // 业务异常(非市区、市区不存在等)返回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)); + } + } + } \ No newline at end of file diff --git a/src/main/java/com/campus/water/entity/vo/AreaDeviceStatsVO.java b/src/main/java/com/campus/water/entity/vo/AreaDeviceStatsVO.java new file mode 100644 index 0000000..5d332c2 --- /dev/null +++ b/src/main/java/com/campus/water/entity/vo/AreaDeviceStatsVO.java @@ -0,0 +1,16 @@ +package com.campus.water.entity.vo; + +import lombok.Data; + +/** + * 片区设备统计VO(适配现有实体,无新增依赖) + */ +@Data +public class AreaDeviceStatsVO { + private String areaId; // 对应Area.areaId + private String areaName; // 对应Area.areaName + private String areaTypeDesc; // 对应Area.AreaType.desc(市区/校园) + private int waterMakerCount; // 制水机数量 + private int waterSupplyCount; // 供水机数量 + private int terminalCount; // 终端数量(基于DeviceTerminalMapping) +} \ No newline at end of file diff --git a/src/main/java/com/campus/water/mapper/DeviceRepository.java b/src/main/java/com/campus/water/mapper/DeviceRepository.java index ab8db1d..82f5963 100644 --- a/src/main/java/com/campus/water/mapper/DeviceRepository.java +++ b/src/main/java/com/campus/water/mapper/DeviceRepository.java @@ -48,4 +48,6 @@ public interface DeviceRepository extends JpaRepository { // 按设备类型加载加载设备(支持区域筛选) List findByDeviceTypeAndAreaId(Device.DeviceType deviceType, String areaId); + + long countByAreaIdAndDeviceType(String areaId, Device.DeviceType deviceType); } \ No newline at end of file diff --git a/src/main/java/com/campus/water/mapper/DeviceTerminalMappingRepository.java b/src/main/java/com/campus/water/mapper/DeviceTerminalMappingRepository.java index 69e7a36..5a53e54 100644 --- a/src/main/java/com/campus/water/mapper/DeviceTerminalMappingRepository.java +++ b/src/main/java/com/campus/water/mapper/DeviceTerminalMappingRepository.java @@ -30,4 +30,6 @@ public interface DeviceTerminalMappingRepository extends JpaRepository campusList = getCampusesByCityId(cityId); + List campusIds = campusList.stream() + .map(Area::getAreaId) + .collect(Collectors.toList()); + + // 第二步:汇总下属所有校区的设备/终端数量(循环复用现有count方法,适配现有Mapper) + long campusWaterMaker = 0; + long campusWaterSupply = 0; + long campusTerminal = 0; + if (!campusIds.isEmpty()) { + for (String campusId : campusIds) { + campusWaterMaker += deviceRepository.countByAreaIdAndDeviceType(campusId, Device.DeviceType.water_maker); + campusWaterSupply += deviceRepository.countByAreaIdAndDeviceType(campusId, Device.DeviceType.water_supply); + campusTerminal += deviceTerminalMappingRepository.countByAreaId(campusId); + } + } + + // 第三步:直接赋值校区汇总数据(市区自身无数据) + statsVO.setWaterMakerCount((int) campusWaterMaker); + statsVO.setWaterSupplyCount((int) campusWaterSupply); + statsVO.setTerminalCount((int) campusTerminal); + } + + /** + * 获取指定市区下所有校区的单独设备统计(每个校区各自的统计结果,不汇总) + * @param cityId 市区ID + * @return 校区统计列表(复用现有方法,无新增依赖) + */ + @Transactional(readOnly = true) + public List getCampusDeviceStatsUnderCity(String cityId) { + // 1. 校验市区存在且类型正确 + Area cityArea = getAreaById(cityId); + if (!Area.AreaType.zone.equals(cityArea.getAreaType())) { + throw new RuntimeException("指定区域不是市区,无法查询下属校区统计"); + } + + // 2. 获取下属所有校区(复用现有方法) + List campusList = getCampusesByCityId(cityId); + + // 3. 逐个生成校区统计结果(复用getAreaDeviceStats方法) + return campusList.stream() + .map(campus -> getAreaDeviceStats(campus.getAreaId())) + .collect(Collectors.toList()); + } + } \ No newline at end of file