设备
This commit is contained in:
@ -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<DeviceAccessRecordVo> 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<DeviceAccessRecordVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(deviceAccessRecordService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 子项目列表
|
||||
*/
|
||||
@GetMapping("/childProjectList/{projectId}")
|
||||
public R<List<BusProject>> childProjectId(@PathVariable Long projectId) {
|
||||
List<BusProject> 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()
|
||||
|
||||
@ -85,12 +85,18 @@ public class DeviceInfoController extends BaseController {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设备信息统计
|
||||
*/
|
||||
@SaCheckPermission("device:info:list")
|
||||
@GetMapping("/count/{projectId}")
|
||||
public R<DeviceInfoCountVo> count(@PathVariable Long projectId) {
|
||||
public R<Map<String, Integer>> count(@PathVariable Long projectId) {
|
||||
return R.ok(deviceInfoService.count(projectId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备类型统计
|
||||
*/
|
||||
@SaCheckPermission("device:info:list")
|
||||
@GetMapping("/typeCount/{projectId}")
|
||||
public R<Map<String, Integer>> typeCount(@PathVariable Long projectId) {
|
||||
|
||||
@ -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<List<DeviceTypeVo>> treeList(DeviceTypeBo bo) {
|
||||
List<DeviceTypeVo> list = deviceTypeService.queryList(bo);
|
||||
buildTreeWithAutoRoot(list);
|
||||
return R.ok(list);
|
||||
List<DeviceTypeVo> deviceTypeVos = buildTreeWithAutoRoot(list);
|
||||
return R.ok(deviceTypeVos);
|
||||
}
|
||||
|
||||
|
||||
public static List<DeviceTypeVo> buildTreeWithAutoRoot(List<DeviceTypeVo> list) {
|
||||
// 1. 用 Map 缓存所有节点(key=节点ID,value=节点对象)
|
||||
// 防御性判断:空列表直接返回,避免空指针
|
||||
if (list == null || list.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 1. 提取所有有效节点ID(用于判断父ID是否存在)
|
||||
Set<Long> validNodeIds = list.stream()
|
||||
.map(DeviceTypeVo::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 2. 用Map缓存所有节点(key=节点ID,value=节点对象),O(1)查找
|
||||
Map<Long, DeviceTypeVo> nodeMap = list.stream()
|
||||
.collect(Collectors.toMap(DeviceTypeVo::getId, node -> node));
|
||||
|
||||
List<DeviceTypeVo> rootNodes = new ArrayList<>(); // 存储自动识别的顶级节点
|
||||
List<DeviceTypeVo> orphanNodes = new ArrayList<>(); // 存储孤儿节点(可选:单独处理)
|
||||
List<DeviceTypeVo> rootNodes = new ArrayList<>();
|
||||
List<DeviceTypeVo> 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;
|
||||
}
|
||||
|
||||
@ -78,5 +78,9 @@ public class DeviceAccessRecordBo extends BaseEntity {
|
||||
*/
|
||||
private String details;
|
||||
|
||||
/**
|
||||
* 子项目ID
|
||||
*/
|
||||
private Long childProjectId;
|
||||
|
||||
}
|
||||
|
||||
@ -20,4 +20,8 @@ public class DeviceInfoCountVo {
|
||||
* 闲置
|
||||
*/
|
||||
private Integer idle;
|
||||
/**
|
||||
* 报废
|
||||
*/
|
||||
private Integer broken;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<DeviceInfo>{
|
||||
/**
|
||||
* 设备数量统计
|
||||
*/
|
||||
DeviceInfoCountVo count(Long projectId);
|
||||
Map<String, Integer> count(Long projectId);
|
||||
|
||||
/**
|
||||
* 设备类型统计
|
||||
|
||||
@ -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<DeviceInfoMapper, DeviceI
|
||||
|
||||
private final IDeviceTypeService deviceTypeService;
|
||||
|
||||
private final IDeviceAccessRecordService deviceAccessRecordService;
|
||||
|
||||
private final ISysDictTypeService dictTypeService;
|
||||
|
||||
/**
|
||||
* 查询设备信息
|
||||
*
|
||||
@ -139,7 +149,11 @@ public class DeviceInfoServiceImpl extends ServiceImpl<DeviceInfoMapper, DeviceI
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(DeviceInfo entity){
|
||||
//TODO 做一些数据校验,如唯一约束
|
||||
boolean exists = this.lambdaQuery().eq(DeviceInfo::getDeviceCode, entity.getDeviceCode())
|
||||
.ne(entity.getId() != null, DeviceInfo::getId, entity.getId()).exists();
|
||||
if (exists) {
|
||||
throw new ServiceException("设备编码已存在");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,22 +166,27 @@ public class DeviceInfoServiceImpl extends ServiceImpl<DeviceInfoMapper, DeviceI
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
List<DeviceAccessRecord> 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<DeviceInfo> 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<String, Integer> count(Long projectId) {
|
||||
|
||||
return countVo;
|
||||
Map<String, Integer> map = new LinkedHashMap<>();
|
||||
List<SysDictDataVo> deviceStatus = dictTypeService.selectDictDataByType("device_status");
|
||||
|
||||
List<DeviceInfo> 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
|
||||
|
||||
@ -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<DeviceTypeMapper, DeviceT
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<DeviceType> 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<DeviceTypeMapper, DeviceT
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
List<Long> 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<DeviceType> queryWrapper = new LambdaQueryWrapper<DeviceType>()
|
||||
.like(DeviceType::getAncestors, prefix)
|
||||
.orderByAsc(DeviceType::getLevel, DeviceType::getId);
|
||||
List<DeviceType> list = baseMapper.selectList(queryWrapper);
|
||||
checkIds.addAll(list.stream().map(DeviceType::getId).toList());
|
||||
}
|
||||
List<DeviceInfo> list = deviceInfoService.lambdaQuery().in(DeviceInfo::getTypeId, checkIds).list();
|
||||
if(CollectionUtil.isNotEmpty(list)){
|
||||
throw new ServiceException("当前类型或子级类型存在设备");
|
||||
}
|
||||
}
|
||||
List<DeviceInfo> 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user