|
|
|
|
@ -5,7 +5,12 @@ import cn.iocoder.yudao.module.common.enums.CodeTypeEnum;
|
|
|
|
|
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
|
|
|
|
|
import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.devicecontactmodel.DeviceContactModelDO;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.dal.mysql.devicecontactmodel.DeviceContactModelMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.mes.dal.dataobject.deviceledger.DeviceLedgerDO;
|
|
|
|
|
import cn.iocoder.yudao.module.mes.dal.mysql.deviceledger.DeviceLedgerMapper;
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
|
|
@ -18,6 +23,7 @@ import java.io.UnsupportedEncodingException;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
import cn.iocoder.yudao.module.mes.controller.admin.deviceline.vo.*;
|
|
|
|
|
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.LineAnalysisTreeDTO;
|
|
|
|
|
import cn.iocoder.yudao.module.mes.dal.dataobject.deviceline.DeviceLineDO;
|
|
|
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
|
|
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
|
|
|
@ -25,6 +31,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
|
|
|
import cn.iocoder.yudao.module.mes.dal.mysql.deviceline.DeviceLineMapper;
|
|
|
|
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
|
|
import java.util.function.Function;
|
|
|
|
|
|
|
|
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
|
|
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
|
|
|
|
|
@ -48,6 +55,15 @@ public class DeviceLineServiceImpl implements DeviceLineService {
|
|
|
|
|
@Resource
|
|
|
|
|
private QrcodeRecordService qrcodeService;
|
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
|
private DeviceLedgerMapper deviceLedgerMapper;
|
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
|
private DeviceMapper deviceMapper;
|
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
|
private DeviceContactModelMapper deviceContactModelMapper;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Long createDeviceLine(DeviceLineSaveReqVO createReqVO) throws UnsupportedEncodingException {
|
|
|
|
|
validateParentDeviceLine(createReqVO.getParentId());
|
|
|
|
|
@ -212,6 +228,245 @@ public class DeviceLineServiceImpl implements DeviceLineService {
|
|
|
|
|
return ancestors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List<LineAnalysisTreeDTO.LineNode> deviceParameterAnalysis(String keyword, Integer showDevices) {
|
|
|
|
|
if (showDevices == null || (showDevices != 1 && showDevices != 2)) {
|
|
|
|
|
showDevices = 1;
|
|
|
|
|
}
|
|
|
|
|
boolean needShowDevices = showDevices == 1;
|
|
|
|
|
boolean hasKeyword = StringUtils.isNotBlank(keyword);
|
|
|
|
|
String lowerKeyword = hasKeyword ? keyword.toLowerCase() : null;
|
|
|
|
|
|
|
|
|
|
List<DeviceLineDO> deviceLines = deviceLineMapper.selectList();
|
|
|
|
|
if (deviceLines == null || deviceLines.isEmpty()) {
|
|
|
|
|
return Collections.emptyList();
|
|
|
|
|
}
|
|
|
|
|
deviceLines.sort(Comparator.comparing(DeviceLineDO::getSort,
|
|
|
|
|
Comparator.nullsLast(Integer::compareTo)).thenComparing(DeviceLineDO::getId));
|
|
|
|
|
|
|
|
|
|
List<DeviceLedgerDO> ledgers = deviceLedgerMapper.selectList(new LambdaQueryWrapper<DeviceLedgerDO>()
|
|
|
|
|
.isNotNull(DeviceLedgerDO::getDeviceLine)
|
|
|
|
|
.isNotNull(DeviceLedgerDO::getDvId)
|
|
|
|
|
.ne(DeviceLedgerDO::getDvId, 0));
|
|
|
|
|
|
|
|
|
|
List<Long> deviceIds = ledgers.stream()
|
|
|
|
|
.map(DeviceLedgerDO::getDvId)
|
|
|
|
|
.filter(Objects::nonNull)
|
|
|
|
|
.distinct()
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
|
|
|
Map<Long, DeviceDO> deviceMap = new HashMap<>();
|
|
|
|
|
Map<Long, List<DeviceContactModelDO>> paramsByDeviceId = new HashMap<>();
|
|
|
|
|
if (!deviceIds.isEmpty()) {
|
|
|
|
|
deviceMap = deviceMapper.selectBatchIds(deviceIds).stream()
|
|
|
|
|
.collect(Collectors.toMap(DeviceDO::getId, Function.identity(), (a, b) -> a));
|
|
|
|
|
|
|
|
|
|
List<DeviceContactModelDO> parameters = deviceContactModelMapper.selectList(
|
|
|
|
|
new LambdaQueryWrapper<DeviceContactModelDO>()
|
|
|
|
|
.in(DeviceContactModelDO::getDeviceId, deviceIds)
|
|
|
|
|
.orderByAsc(DeviceContactModelDO::getSort));
|
|
|
|
|
paramsByDeviceId = parameters.stream()
|
|
|
|
|
.filter(item -> item.getDeviceId() != null)
|
|
|
|
|
.collect(Collectors.groupingBy(DeviceContactModelDO::getDeviceId));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Map<Long, List<DeviceLedgerDO>> ledgersByLineId = ledgers.stream()
|
|
|
|
|
.filter(item -> item.getDeviceLine() != null)
|
|
|
|
|
.collect(Collectors.groupingBy(item -> item.getDeviceLine().longValue()));
|
|
|
|
|
|
|
|
|
|
Map<Long, List<DeviceLineDO>> childrenByParentId = deviceLines.stream()
|
|
|
|
|
.filter(item -> item.getParentId() != null && item.getParentId() != 0L)
|
|
|
|
|
.collect(Collectors.groupingBy(DeviceLineDO::getParentId));
|
|
|
|
|
|
|
|
|
|
Set<Long> matchedNodeIds = new HashSet<>();
|
|
|
|
|
if (hasKeyword) {
|
|
|
|
|
for (DeviceLineDO line : deviceLines) {
|
|
|
|
|
if (isDeviceLineAnalysisMatched(line, ledgersByLineId, deviceMap, paramsByDeviceId, lowerKeyword, needShowDevices)) {
|
|
|
|
|
matchedNodeIds.add(line.getId());
|
|
|
|
|
addAllDeviceLineDescendants(line.getId(), childrenByParentId, matchedNodeIds);
|
|
|
|
|
addDeviceLineAncestors(line, matchedNodeIds);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (matchedNodeIds.isEmpty()) {
|
|
|
|
|
return Collections.emptyList();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
matchedNodeIds.addAll(deviceLines.stream().map(DeviceLineDO::getId).collect(Collectors.toSet()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buildDeviceLineAnalysisTree(deviceLines, matchedNodeIds, ledgersByLineId, deviceMap,
|
|
|
|
|
paramsByDeviceId, needShowDevices, hasKeyword, lowerKeyword);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isDeviceLineAnalysisMatched(DeviceLineDO line,
|
|
|
|
|
Map<Long, List<DeviceLedgerDO>> ledgersByLineId,
|
|
|
|
|
Map<Long, DeviceDO> deviceMap,
|
|
|
|
|
Map<Long, List<DeviceContactModelDO>> paramsByDeviceId,
|
|
|
|
|
String lowerKeyword,
|
|
|
|
|
boolean needShowDevices) {
|
|
|
|
|
if (line.getName() != null && line.getName().toLowerCase().contains(lowerKeyword)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (line.getCode() != null && line.getCode().toLowerCase().contains(lowerKeyword)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (!needShowDevices) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for (DeviceLedgerDO ledger : ledgersByLineId.getOrDefault(line.getId(), Collections.emptyList())) {
|
|
|
|
|
DeviceDO device = deviceMap.get(ledger.getDvId());
|
|
|
|
|
if (device == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (device.getDeviceName() != null && device.getDeviceName().toLowerCase().contains(lowerKeyword)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (device.getDeviceCode() != null && device.getDeviceCode().toLowerCase().contains(lowerKeyword)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
boolean matchedParam = paramsByDeviceId.getOrDefault(device.getId(), Collections.emptyList()).stream()
|
|
|
|
|
.anyMatch(param -> param.getAttributeName() != null
|
|
|
|
|
&& param.getAttributeName().toLowerCase().contains(lowerKeyword));
|
|
|
|
|
if (matchedParam) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void addAllDeviceLineDescendants(Long nodeId,
|
|
|
|
|
Map<Long, List<DeviceLineDO>> childrenByParentId,
|
|
|
|
|
Set<Long> matchedNodeIds) {
|
|
|
|
|
Queue<Long> queue = new LinkedList<>();
|
|
|
|
|
queue.offer(nodeId);
|
|
|
|
|
while (!queue.isEmpty()) {
|
|
|
|
|
Long currentId = queue.poll();
|
|
|
|
|
for (DeviceLineDO child : childrenByParentId.getOrDefault(currentId, Collections.emptyList())) {
|
|
|
|
|
matchedNodeIds.add(child.getId());
|
|
|
|
|
queue.offer(child.getId());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void addDeviceLineAncestors(DeviceLineDO line, Set<Long> matchedNodeIds) {
|
|
|
|
|
if (StringUtils.isBlank(line.getParentChain())) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Arrays.stream(line.getParentChain().split(","))
|
|
|
|
|
.filter(StringUtils::isNotBlank)
|
|
|
|
|
.forEach(id -> {
|
|
|
|
|
try {
|
|
|
|
|
matchedNodeIds.add(Long.valueOf(id.trim()));
|
|
|
|
|
} catch (NumberFormatException ignored) {
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<LineAnalysisTreeDTO.LineNode> buildDeviceLineAnalysisTree(
|
|
|
|
|
List<DeviceLineDO> deviceLines,
|
|
|
|
|
Set<Long> matchedNodeIds,
|
|
|
|
|
Map<Long, List<DeviceLedgerDO>> ledgersByLineId,
|
|
|
|
|
Map<Long, DeviceDO> deviceMap,
|
|
|
|
|
Map<Long, List<DeviceContactModelDO>> paramsByDeviceId,
|
|
|
|
|
boolean needShowDevices,
|
|
|
|
|
boolean hasKeyword,
|
|
|
|
|
String lowerKeyword) {
|
|
|
|
|
|
|
|
|
|
Map<Long, LineAnalysisTreeDTO.LineNode> nodeMap = new LinkedHashMap<>();
|
|
|
|
|
for (DeviceLineDO line : deviceLines) {
|
|
|
|
|
if (!matchedNodeIds.contains(line.getId())) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
nodeMap.put(line.getId(), LineAnalysisTreeDTO.LineNode.builder()
|
|
|
|
|
.id(line.getId())
|
|
|
|
|
.name(line.getName())
|
|
|
|
|
.parentId(line.getParentId())
|
|
|
|
|
.equipments(needShowDevices ? buildEquipmentNodes(line, ledgersByLineId, deviceMap,
|
|
|
|
|
paramsByDeviceId, hasKeyword, lowerKeyword) : new ArrayList<>())
|
|
|
|
|
.children(new ArrayList<>())
|
|
|
|
|
.build());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<LineAnalysisTreeDTO.LineNode> result = new ArrayList<>();
|
|
|
|
|
for (LineAnalysisTreeDTO.LineNode node : nodeMap.values()) {
|
|
|
|
|
if (node.getParentId() == null || node.getParentId() == 0L) {
|
|
|
|
|
result.add(node);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
LineAnalysisTreeDTO.LineNode parent = nodeMap.get(node.getParentId());
|
|
|
|
|
if (parent != null) {
|
|
|
|
|
parent.getChildren().add(node);
|
|
|
|
|
} else {
|
|
|
|
|
result.add(node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<LineAnalysisTreeDTO.EquipmentNode> buildEquipmentNodes(
|
|
|
|
|
DeviceLineDO line,
|
|
|
|
|
Map<Long, List<DeviceLedgerDO>> ledgersByLineId,
|
|
|
|
|
Map<Long, DeviceDO> deviceMap,
|
|
|
|
|
Map<Long, List<DeviceContactModelDO>> paramsByDeviceId,
|
|
|
|
|
boolean hasKeyword,
|
|
|
|
|
String lowerKeyword) {
|
|
|
|
|
|
|
|
|
|
List<LineAnalysisTreeDTO.EquipmentNode> equipmentNodes = new ArrayList<>();
|
|
|
|
|
for (DeviceLedgerDO ledger : ledgersByLineId.getOrDefault(line.getId(), Collections.emptyList())) {
|
|
|
|
|
DeviceDO device = deviceMap.get(ledger.getDvId());
|
|
|
|
|
if (device == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
List<DeviceContactModelDO> deviceParams = paramsByDeviceId.getOrDefault(device.getId(), Collections.emptyList());
|
|
|
|
|
List<DeviceContactModelDO> filteredParams = filterDeviceLineParams(line, device, deviceParams, hasKeyword, lowerKeyword);
|
|
|
|
|
if (hasKeyword && filteredParams.isEmpty()
|
|
|
|
|
&& !isDeviceLineNameMatched(line, lowerKeyword)
|
|
|
|
|
&& !isDeviceMatched(device, lowerKeyword)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
equipmentNodes.add(LineAnalysisTreeDTO.EquipmentNode.builder()
|
|
|
|
|
.id(device.getId())
|
|
|
|
|
.name(device.getDeviceName())
|
|
|
|
|
.parameters(filteredParams.stream().map(this::convertToSimpleInfo).collect(Collectors.toList()))
|
|
|
|
|
.build());
|
|
|
|
|
}
|
|
|
|
|
return equipmentNodes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<DeviceContactModelDO> filterDeviceLineParams(DeviceLineDO line, DeviceDO device,
|
|
|
|
|
List<DeviceContactModelDO> deviceParams,
|
|
|
|
|
boolean hasKeyword, String lowerKeyword) {
|
|
|
|
|
if (!hasKeyword || isDeviceLineNameMatched(line, lowerKeyword) || isDeviceMatched(device, lowerKeyword)) {
|
|
|
|
|
return new ArrayList<>(deviceParams);
|
|
|
|
|
}
|
|
|
|
|
return deviceParams.stream()
|
|
|
|
|
.filter(param -> param.getAttributeName() != null
|
|
|
|
|
&& param.getAttributeName().toLowerCase().contains(lowerKeyword))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isDeviceLineNameMatched(DeviceLineDO line, String lowerKeyword) {
|
|
|
|
|
return (line.getName() != null && line.getName().toLowerCase().contains(lowerKeyword))
|
|
|
|
|
|| (line.getCode() != null && line.getCode().toLowerCase().contains(lowerKeyword));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isDeviceMatched(DeviceDO device, String lowerKeyword) {
|
|
|
|
|
return (device.getDeviceName() != null && device.getDeviceName().toLowerCase().contains(lowerKeyword))
|
|
|
|
|
|| (device.getDeviceCode() != null && device.getDeviceCode().toLowerCase().contains(lowerKeyword));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private LineAnalysisTreeDTO.ParameterNode convertToSimpleInfo(DeviceContactModelDO param) {
|
|
|
|
|
return LineAnalysisTreeDTO.ParameterNode.builder()
|
|
|
|
|
.id(param.getId())
|
|
|
|
|
.name(param.getAttributeName())
|
|
|
|
|
.code(param.getAttributeCode())
|
|
|
|
|
.type(param.getAttributeType())
|
|
|
|
|
.dataType(param.getDataType())
|
|
|
|
|
.unit(param.getDataUnit())
|
|
|
|
|
.ratio(param.getRatio())
|
|
|
|
|
.build();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<DeviceLineTreeRespVO> buildDeviceLineTree(List<DeviceLineDO> allDeviceLines) {
|
|
|
|
|
Map<Long, List<DeviceLineDO>> childrenMap = CollectionUtils.convertMultiMap(
|
|
|
|
|
allDeviceLines, DeviceLineDO::getParentId);
|
|
|
|
|
|