package com.ruoyi.device.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.device.dto.DeviceAreaTreeDto; 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.framework.web.domain.AjaxResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @Service public class DeviceAreaServiceImpl extends ServiceImpl implements IDeviceAreaService { @Autowired private DeviceAreaMapper deviceAreaMapper; @Autowired private DeviceLedgerMapper deviceLedgerMapper; @Override public IPage queryPage(Page page, DeviceArea deviceArea) { return deviceAreaMapper.queryPage(page, deviceArea); } @Override public List listTree() { return buildTree(Collections.emptyMap()); } @Override public List listTreeWithDevices() { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.isNotNull(DeviceLedger::getAreaId); queryWrapper.orderByAsc(DeviceLedger::getId); List deviceLedgers = deviceLedgerMapper.selectList(queryWrapper); Map> deviceMap = new HashMap<>(); for (DeviceLedger deviceLedger : deviceLedgers) { deviceMap.computeIfAbsent(deviceLedger.getAreaId(), key -> new ArrayList<>()).add(deviceLedger); } return buildTree(deviceMap); } @Override public AjaxResult saveDeviceArea(DeviceArea deviceArea) { if (deviceArea == null || !StringUtils.hasText(deviceArea.getAreaName())) { return AjaxResult.error("区域名称不能为空"); } normalizeDeviceArea(deviceArea); if (existsSameName(deviceArea.getParentId(), deviceArea.getAreaName(), null)) { return AjaxResult.error("同级区域名称已存在"); } if (deviceArea.getParentId() != null && deviceAreaMapper.selectById(deviceArea.getParentId()) == null) { return AjaxResult.error("父级区域不存在"); } return this.save(deviceArea) ? AjaxResult.success() : AjaxResult.error(); } @Override public AjaxResult updateDeviceArea(DeviceArea deviceArea) { if (deviceArea == null || deviceArea.getId() == null) { return AjaxResult.error("区域ID不能为空"); } if (!StringUtils.hasText(deviceArea.getAreaName())) { return AjaxResult.error("区域名称不能为空"); } normalizeDeviceArea(deviceArea); DeviceArea current = deviceAreaMapper.selectById(deviceArea.getId()); if (current == null) { return AjaxResult.error("区域不存在"); } if (deviceArea.getParentId() != null && deviceArea.getId().equals(deviceArea.getParentId())) { return AjaxResult.error("父级区域不能选择自身"); } if (isDescendant(deviceArea.getId(), deviceArea.getParentId())) { return AjaxResult.error("父级区域不能选择子节点"); } if (deviceArea.getParentId() != null && deviceAreaMapper.selectById(deviceArea.getParentId()) == null) { return AjaxResult.error("父级区域不存在"); } if (existsSameName(deviceArea.getParentId(), deviceArea.getAreaName(), deviceArea.getId())) { return AjaxResult.error("同级区域名称已存在"); } return this.updateById(deviceArea) ? AjaxResult.success() : AjaxResult.error(); } @Override public AjaxResult removeDeviceAreas(List ids) { if (CollectionUtils.isEmpty(ids)) { return AjaxResult.error("请选择要删除的区域"); } LambdaQueryWrapper childWrapper = new LambdaQueryWrapper<>(); childWrapper.in(DeviceArea::getParentId, ids); if (deviceAreaMapper.selectCount(childWrapper) > 0) { return AjaxResult.error("存在子区域,不能直接删除"); } return this.removeBatchByIds(ids) ? AjaxResult.success() : AjaxResult.error(); } private List buildTree(Map> deviceMap) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.and(wrapper -> wrapper.isNull(DeviceArea::getParentId).or().eq(DeviceArea::getParentId, 0L)); queryWrapper.orderByAsc(DeviceArea::getSort).orderByAsc(DeviceArea::getId); List rootList = deviceAreaMapper.selectList(queryWrapper); List tree = new ArrayList<>(); for (DeviceArea deviceArea : rootList) { DeviceAreaTreeDto node = toTreeDto(deviceArea, deviceMap); node.setChildren(buildChildren(deviceArea.getId(), deviceMap)); tree.add(node); } return tree; } private void normalizeDeviceArea(DeviceArea deviceArea) { if (deviceArea.getParentId() != null && deviceArea.getParentId() == 0L) { deviceArea.setParentId(null); } if (deviceArea.getSort() == null) { deviceArea.setSort(0L); } } private boolean existsSameName(Long parentId, String areaName, Long excludeId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(DeviceArea::getAreaName, areaName); if (parentId == null) { queryWrapper.and(wrapper -> wrapper.isNull(DeviceArea::getParentId).or().eq(DeviceArea::getParentId, 0L)); } else { queryWrapper.eq(DeviceArea::getParentId, parentId); } if (excludeId != null) { queryWrapper.ne(DeviceArea::getId, excludeId); } return deviceAreaMapper.selectCount(queryWrapper) > 0; } private boolean isDescendant(Long currentId, Long parentId) { if (currentId == null || parentId == null) { return false; } Long cursor = parentId; while (cursor != null && cursor != 0L) { if (currentId.equals(cursor)) { return true; } DeviceArea parent = deviceAreaMapper.selectById(cursor); if (parent == null) { return false; } cursor = parent.getParentId(); } return false; } private List buildChildren(Long parentId, Map> deviceMap) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(DeviceArea::getParentId, parentId); queryWrapper.orderByAsc(DeviceArea::getSort).orderByAsc(DeviceArea::getId); List children = deviceAreaMapper.selectList(queryWrapper); List result = new ArrayList<>(); for (DeviceArea child : children) { DeviceAreaTreeDto node = toTreeDto(child, deviceMap); node.setChildren(buildChildren(child.getId(), deviceMap)); result.add(node); } return result; } private DeviceAreaTreeDto toTreeDto(DeviceArea deviceArea, Map> deviceMap) { DeviceAreaTreeDto dto = new DeviceAreaTreeDto(); BeanUtils.copyProperties(deviceArea, dto); dto.setLabel(deviceArea.getAreaName()); dto.setDeviceList(new ArrayList<>(deviceMap.getOrDefault(deviceArea.getId(), Collections.emptyList()))); dto.setChildren(new ArrayList<>()); return dto; } }