diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceAccessRecordController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceAccessRecordController.java index 5c646628..26d7e647 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceAccessRecordController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceAccessRecordController.java @@ -6,6 +6,8 @@ import lombok.RequiredArgsConstructor; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusProjectService; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; import org.dromara.common.idempotent.annotation.RepeatSubmit; @@ -36,17 +38,17 @@ public class DeviceAccessRecordController extends BaseController { private final IDeviceAccessRecordService deviceAccessRecordService; + private final IBusProjectService projectService; + /** * 查询设备进出场记录列表 */ - @SaCheckPermission("device:accessRecord:list") +// @SaCheckPermission("device:accessRecord:list") @GetMapping("/list") public TableDataInfo list(DeviceAccessRecordBo bo, PageQuery pageQuery) { return deviceAccessRecordService.queryPageList(bo, pageQuery); } - - /** * 导出设备进出场记录列表 */ @@ -63,17 +65,29 @@ public class DeviceAccessRecordController extends BaseController { * * @param id 主键 */ - @SaCheckPermission("device:accessRecord:query") +// @SaCheckPermission("device:accessRecord:query") @GetMapping("/{id}") public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { return R.ok(deviceAccessRecordService.queryById(id)); } + /** + * 子项目列表 + */ + @GetMapping("/childProjectList/{projectId}") + public R> childProjectId(@PathVariable Long projectId) { + List list = projectService.lambdaQuery() + .select(BusProject::getId, BusProject::getProjectName) + .eq(BusProject::getPId, projectId).list(); + return R.ok(list); + } + + /** * 新增设备进出场记录 */ - @SaCheckPermission("device:accessRecord:add") +// @SaCheckPermission("device:accessRecord:add") @Log(title = "设备进出场记录", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping() @@ -81,10 +95,12 @@ public class DeviceAccessRecordController extends BaseController { return toAjax(deviceAccessRecordService.insertByBo(bo)); } + + /** * 修改设备进出场记录 */ - @SaCheckPermission("device:accessRecord:edit") +// @SaCheckPermission("device:accessRecord:edit") @Log(title = "设备进出场记录", businessType = BusinessType.UPDATE) @RepeatSubmit() @PutMapping() diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceInfoController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceInfoController.java index ad34b887..e108eb1e 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceInfoController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceInfoController.java @@ -85,12 +85,18 @@ public class DeviceInfoController extends BaseController { } + /** + * 设备信息统计 + */ @SaCheckPermission("device:info:list") @GetMapping("/count/{projectId}") - public R count(@PathVariable Long projectId) { + public R> count(@PathVariable Long projectId) { return R.ok(deviceInfoService.count(projectId)); } + /** + * 设备类型统计 + */ @SaCheckPermission("device:info:list") @GetMapping("/typeCount/{projectId}") public R> typeCount(@PathVariable Long projectId) { diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceTypeController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceTypeController.java index 7cd8e4f3..881ce274 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceTypeController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceTypeController.java @@ -3,6 +3,7 @@ package org.dromara.device.controller; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; @@ -56,47 +57,72 @@ public class DeviceTypeController extends BaseController { @GetMapping("/treeList") public R> treeList(DeviceTypeBo bo) { List list = deviceTypeService.queryList(bo); - buildTreeWithAutoRoot(list); - return R.ok(list); + List deviceTypeVos = buildTreeWithAutoRoot(list); + return R.ok(deviceTypeVos); } public static List buildTreeWithAutoRoot(List list) { // 1. 用 Map 缓存所有节点(key=节点ID,value=节点对象) + // 防御性判断:空列表直接返回,避免空指针 + if (list == null || list.isEmpty()) { + return new ArrayList<>(); + } + + // 1. 提取所有有效节点ID(用于判断父ID是否存在) + Set validNodeIds = list.stream() + .map(DeviceTypeVo::getId) + .collect(Collectors.toSet()); + + // 2. 用Map缓存所有节点(key=节点ID,value=节点对象),O(1)查找 Map nodeMap = list.stream() .collect(Collectors.toMap(DeviceTypeVo::getId, node -> node)); - List rootNodes = new ArrayList<>(); // 存储自动识别的顶级节点 - List orphanNodes = new ArrayList<>(); // 存储孤儿节点(可选:单独处理) + List rootNodes = new ArrayList<>(); + List orphanNodes = new ArrayList<>(); for (DeviceTypeVo node : list) { Long parentId = node.getParentId(); - // 情况1:parent_id 为0或NULL → 直接视为顶级节点 + boolean isRoot = false; + + // 判定是否为顶级节点(满足以下任一条件) if (parentId == null || parentId == 0) { + // 条件1:parentId为0或NULL(设计约定的顶级节点) + isRoot = true; + } else if (!validNodeIds.contains(parentId)) { + // 条件2:parentId不在有效节点ID中(孤儿节点,视为顶级) + isRoot = true; + orphanNodes.add(node); + } + + if (isRoot) { + // 顶级节点直接加入根列表,无需挂载 rootNodes.add(node); } else { - // 情况2:查找父节点 + // 非顶级节点:挂载到父节点的children中 DeviceTypeVo parentNode = nodeMap.get(parentId); if (parentNode != null) { - // 父节点存在 → 挂载到子节点列表 if (parentNode.getChildren() == null) { parentNode.setChildren(new ArrayList<>()); } - parentNode.getChildren().add(node); - } else { - // 父节点不存在 → 视为顶级节点(或加入孤儿节点列表) - rootNodes.add(node); - // 可选:记录孤儿节点,用于后续告警或修复 - orphanNodes.add(node); + // 关键:避免重复挂载(判断子节点中是否已存在当前节点) + boolean isAlreadyMounted = parentNode.getChildren().stream() + .anyMatch(child -> child.getId().equals(node.getId())); + if (!isAlreadyMounted) { + parentNode.getChildren().add(node); + } } } } - // 可选:打印孤儿节点日志(便于排查数据问题) -// if (!orphanNodes.isEmpty()) { -// System.out.println("警告:存在孤儿节点(父节点不存在),节点ID:" + -// orphanNodes.stream().map(DeviceType::getId).collect(Collectors.toList())); -// } + // 打印孤儿节点日志(便于排查数据问题) + if (!orphanNodes.isEmpty()) { + String orphanIds = orphanNodes.stream() + .map(DeviceTypeVo::getId) + .map(String::valueOf) + .collect(Collectors.joining(",")); + System.out.println("警告:存在孤儿节点(父节点不存在),节点ID:" + orphanIds); + } return rootNodes; } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/bo/DeviceAccessRecordBo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/bo/DeviceAccessRecordBo.java index c9369261..472e47f0 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/bo/DeviceAccessRecordBo.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/bo/DeviceAccessRecordBo.java @@ -78,5 +78,9 @@ public class DeviceAccessRecordBo extends BaseEntity { */ private String details; + /** + * 子项目ID + */ + private Long childProjectId; } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/vo/DeviceInfoCountVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/vo/DeviceInfoCountVo.java index 44a2840e..a47e7d92 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/vo/DeviceInfoCountVo.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/vo/DeviceInfoCountVo.java @@ -20,4 +20,8 @@ public class DeviceInfoCountVo { * 闲置 */ private Integer idle; + /** + * 报废 + */ + private Integer broken; } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/vo/DeviceInfoVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/vo/DeviceInfoVo.java index 6c4d9f08..3a5ed8ed 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/vo/DeviceInfoVo.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/domain/vo/DeviceInfoVo.java @@ -65,7 +65,6 @@ public class DeviceInfoVo implements Serializable { * 设备类型ID(关联设备类型表device_type的id) */ @ExcelProperty(value = "设备类型ID", converter = ExcelDictConvert.class) - @ExcelDictFormat(readConverterExp = "关=联设备类型表device_type的id") private Long typeId; private String typeName; diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/IDeviceInfoService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/IDeviceInfoService.java index 4b694d23..85c2e7a9 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/IDeviceInfoService.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/IDeviceInfoService.java @@ -1,6 +1,5 @@ package org.dromara.device.service; -import org.dromara.device.domain.vo.DeviceInfoCountVo; import org.dromara.device.domain.vo.DeviceInfoVo; import org.dromara.device.domain.bo.DeviceInfoBo; import org.dromara.device.domain.DeviceInfo; @@ -8,7 +7,6 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; import com.baomidou.mybatisplus.extension.service.IService; -import org.springframework.web.bind.annotation.PathVariable; import java.util.Collection; import java.util.List; @@ -75,7 +73,7 @@ public interface IDeviceInfoService extends IService{ /** * 设备数量统计 */ - DeviceInfoCountVo count(Long projectId); + Map count(Long projectId); /** * 设备类型统计 diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/impl/DeviceInfoServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/impl/DeviceInfoServiceImpl.java index f95725bd..63f3793f 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/impl/DeviceInfoServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/impl/DeviceInfoServiceImpl.java @@ -2,6 +2,7 @@ package org.dromara.device.service.impl; import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.TableDataInfo; @@ -10,9 +11,14 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; +import org.dromara.device.domain.DeviceAccessRecord; import org.dromara.device.domain.DeviceType; import org.dromara.device.domain.vo.DeviceInfoCountVo; +import org.dromara.device.service.IDeviceAccessRecordService; import org.dromara.device.service.IDeviceTypeService; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.service.ISysDictDataService; +import org.dromara.system.service.ISysDictTypeService; import org.springframework.stereotype.Service; import org.dromara.device.domain.bo.DeviceInfoBo; import org.dromara.device.domain.vo.DeviceInfoVo; @@ -37,6 +43,10 @@ public class DeviceInfoServiceImpl extends ServiceImpl ids, Boolean isValid) { if(isValid){ - //TODO 做一些业务上的校验,判断是否需要校验 + List list = deviceAccessRecordService.lambdaQuery().in(DeviceAccessRecord::getDeviceId, ids).list(); + if(CollectionUtil.isNotEmpty(list)){ + throw new ServiceException("设备存在进出场记录,不能删除"); + } } + return baseMapper.deleteByIds(ids) > 0; } @Override - public DeviceInfoCountVo count(Long projectId) { - List list = this.lambdaQuery().eq(DeviceInfo::getProjectId, projectId).list(); - DeviceInfoCountVo countVo = new DeviceInfoCountVo(); - countVo.setTotal(list.size()); - countVo.setUse((int)list.stream().filter(deviceInfo -> "1".equals(deviceInfo.getStatus())).count()); - countVo.setMaintain((int)list.stream().filter(deviceInfo -> "2".equals(deviceInfo.getStatus())).count()); - countVo.setIdle((int)list.stream().filter(deviceInfo -> "0".equals(deviceInfo.getStatus())).count()); + public Map count(Long projectId) { - return countVo; + Map map = new LinkedHashMap<>(); + List deviceStatus = dictTypeService.selectDictDataByType("device_status"); + + List list = this.lambdaQuery().eq(DeviceInfo::getProjectId, projectId).list(); + for (SysDictDataVo status : deviceStatus) { + map.put(status.getDictLabel(), (int)list.stream().filter(deviceInfo -> status.getDictValue().equals(deviceInfo.getStatus())).count()); + } + return map; } @Override diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/impl/DeviceTypeServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/impl/DeviceTypeServiceImpl.java index c30856a8..6f6392fa 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/impl/DeviceTypeServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/service/impl/DeviceTypeServiceImpl.java @@ -22,6 +22,7 @@ import org.dromara.device.domain.DeviceType; import org.dromara.device.mapper.DeviceTypeMapper; import org.dromara.device.service.IDeviceTypeService; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Collection; @@ -83,6 +84,7 @@ public class DeviceTypeServiceImpl extends ServiceImpl params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.orderByDesc(DeviceType::getId); + lqw.like(StringUtils.isNotBlank(bo.getTypeCode()), DeviceType::getTypeCode, bo.getTypeCode()); lqw.like(StringUtils.isNotBlank(bo.getTypeName()), DeviceType::getTypeName, bo.getTypeName()); lqw.eq(bo.getParentId() != null, DeviceType::getParentId, bo.getParentId()); lqw.eq(bo.getLevel() != null, DeviceType::getLevel, bo.getLevel()); @@ -149,13 +151,25 @@ public class DeviceTypeServiceImpl extends ServiceImpl ids, Boolean isValid) { + List checkIds = new ArrayList<>(); if(isValid){ - //TODO 做一些业务上的校验,判断是否需要校验 + for (Long id : ids) { + DeviceType deviceType = baseMapper.selectById(id); + if(deviceType == null){ + continue; + } + String prefix = deviceType.getAncestors() + "," + deviceType.getId(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .like(DeviceType::getAncestors, prefix) + .orderByAsc(DeviceType::getLevel, DeviceType::getId); + List list = baseMapper.selectList(queryWrapper); + checkIds.addAll(list.stream().map(DeviceType::getId).toList()); + } + List list = deviceInfoService.lambdaQuery().in(DeviceInfo::getTypeId, checkIds).list(); + if(CollectionUtil.isNotEmpty(list)){ + throw new ServiceException("当前类型或子级类型存在设备"); + } } - List list = deviceInfoService.lambdaQuery().in(DeviceInfo::getTypeId, ids).list(); - if(CollectionUtil.isNotEmpty(list)){ - throw new ServiceException("请先删除该设备类型下的设备"); - } - return baseMapper.deleteByIds(ids) > 0; + return baseMapper.deleteByIds(checkIds) > 0; } }