package com.ruoyi.device.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.device.dto.DeviceAreaDto; import com.ruoyi.device.mapper.DeviceAreaMapper; import com.ruoyi.device.mapper.DeviceLedgerMapper; import com.ruoyi.device.pojo.DeviceArea; import com.ruoyi.device.pojo.DeviceLedger; import com.ruoyi.device.service.IDeviceAreaService; import com.ruoyi.device.vo.DeviceAreaTreeDto; import com.ruoyi.framework.web.domain.AjaxResult; 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.Map; import java.util.stream.Collectors; /** * 设备区域 Service 实现 */ @Service @RequiredArgsConstructor public class DeviceAreaServiceImpl extends ServiceImpl implements IDeviceAreaService { private final DeviceAreaMapper deviceAreaMapper; private final DeviceLedgerMapper deviceLedgerMapper; @Override public List selectAreaTree() { List all = this.list(new LambdaQueryWrapper().orderByAsc(DeviceArea::getSort)); if (all == null || all.isEmpty()) { return new ArrayList<>(); } // 统计每个区域直接挂载的设备数量 Map directCountMap = deviceLedgerMapper.selectList( new LambdaQueryWrapper() .select(DeviceLedger::getAreaId) .isNotNull(DeviceLedger::getAreaId)) .stream() .filter(d -> d.getAreaId() != null) .collect(Collectors.groupingBy(DeviceLedger::getAreaId, Collectors.counting())); Map areaMap = all.stream() .collect(Collectors.toMap(DeviceArea::getId, a -> a)); // 递归汇总每个节点的设备数量(含所有子级) Map countMap = directCountMap.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); for (DeviceArea area : all) { accumulate(area.getId(), directCountMap.getOrDefault(area.getId(), 0L), countMap, areaMap); } List rootIds = all.stream() .filter(a -> a.getParentId() == null || !areaMap.containsKey(a.getParentId())) .map(DeviceArea::getId) .collect(Collectors.toList()); List tree = new ArrayList<>(); for (Long rootId : rootIds) { DeviceArea root = areaMap.get(rootId); tree.add(buildNode(root, all, countMap)); } return tree; } // 将当前节点数量累加到所有祖级节点 private void accumulate(Long areaId, Long count, Map countMap, Map areaMap) { DeviceArea area = areaMap.get(areaId); if (area == null) { return; } countMap.merge(areaId, count, Long::sum); // 沿祖先链继续累加(避免祖先链循环依赖) if (area.getParentId() != null && areaMap.containsKey(area.getParentId())) { accumulate(area.getParentId(), count, countMap, areaMap); } } private DeviceAreaTreeDto buildNode(DeviceArea area, List all, Map countMap) { DeviceAreaTreeDto node = new DeviceAreaTreeDto(); node.setId(area.getId()); node.setParentId(area.getParentId()); node.setLabel(area.getName()); node.setDeviceCount(countMap.getOrDefault(area.getId(), 0L)); for (DeviceArea child : all) { if (area.getId().equals(child.getParentId())) { node.getChildren().add(buildNode(child, all, countMap)); } } return node; } @Override public AjaxResult addArea(DeviceAreaDto dto) { if (StringUtils.isEmpty(dto.getName())) { return AjaxResult.error("区域名称不能为空"); } DeviceArea area = new DeviceArea(); area.setName(dto.getName()); area.setParentId(dto.getParentId()); area.setSort(dto.getSort()); area.setDeptId(dto.getDeptId()); area.setTenantId(SecurityUtils.getLoginUser().getTenantId()); if (dto.getParentId() != null) { DeviceArea parent = this.getById(dto.getParentId()); if (parent == null) { return AjaxResult.error("父级区域不存在"); } area.setAncestors(StringUtils.isEmpty(parent.getAncestors()) ? String.valueOf(parent.getId()) : parent.getAncestors() + "," + parent.getId()); } this.save(area); return AjaxResult.success(); } @Override public AjaxResult updateArea(DeviceAreaDto dto) { if (dto.getId() == null) { return AjaxResult.error("区域ID不能为空"); } DeviceArea area = this.getById(dto.getId()); if (area == null) { return AjaxResult.error("区域不存在"); } // 不允许把区域挂到自己的子级下,避免循环 if (dto.getParentId() != null && dto.getParentId().equals(dto.getId())) { return AjaxResult.error("不能将区域挂载到自身"); } if (dto.getParentId() != null && isDescendant(dto.getId(), dto.getParentId())) { return AjaxResult.error("不能将区域挂载到自己的子级下"); } area.setName(dto.getName()); area.setSort(dto.getSort()); area.setDeptId(dto.getDeptId()); if (!java.util.Objects.equals(dto.getParentId(), area.getParentId())) { area.setParentId(dto.getParentId()); if (dto.getParentId() == null) { area.setAncestors(null); } else { DeviceArea parent = this.getById(dto.getParentId()); if (parent == null) { return AjaxResult.error("父级区域不存在"); } area.setAncestors(StringUtils.isEmpty(parent.getAncestors()) ? String.valueOf(parent.getId()) : parent.getAncestors() + "," + parent.getId()); } } this.updateById(area); return AjaxResult.success(); } private boolean isDescendant(Long targetId, Long candidateParentId) { DeviceArea cur = this.getById(candidateParentId); while (cur != null && cur.getParentId() != null) { if (cur.getParentId().equals(targetId)) { return true; } cur = this.getById(cur.getParentId()); } return false; } @Override @Transactional(rollbackFor = Exception.class) public AjaxResult deleteArea(List ids) { for (Long id : ids) { DeviceArea area = this.getById(id); if (area == null) { return AjaxResult.error("区域不存在"); } long childCount = this.count(new LambdaQueryWrapper().eq(DeviceArea::getParentId, id)); if (childCount > 0) { return AjaxResult.error("该区域存在子级区域,请先删除子级"); } long deviceCount = deviceLedgerMapper.selectCount( new LambdaQueryWrapper().eq(DeviceLedger::getAreaId, id)); if (deviceCount > 0) { return AjaxResult.error("该区域下存在设备,请先移除设备关联"); } } this.removeByIds(ids); return AjaxResult.success(); } }