Merge branch 'hhk' into main

plp
HuangHuiKang 3 weeks ago
commit e31bf6543c

@ -230,8 +230,11 @@ public class DeviceController {
return success(deviceService.getDeviceAttribute(id));
}
@GetMapping("/devicePointList")
@PreAuthorize("@ss.hasPermission('iot:device:query')")
public CommonResult<List<DevicePointRespVO>> devicePointList() {
return success( deviceService.devicePointList());
}
}

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
import cn.iocoder.yudao.module.iot.dal.devicecontactmodel.DeviceContactModelDO;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.List;
@Schema(description = "管理后台 - 设备参数集合列表 Resp VO")
@Data
@ToString(callSuper = true)
public class DevicePointRespVO {
@Schema(description = "设备Id")
private Long deviceId;
@Schema(description = "设备名称")
private String deviceName;
@Schema(description = "子集参数列表")
private List<DeviceContactModelDO> contactModelDOList;
}

@ -125,4 +125,5 @@ public interface DeviceService {
Map<Long, Map<String, Object>> createDeviceDataMap(Long deviceId);
List<DevicePointRespVO> devicePointList();
}

@ -27,10 +27,12 @@ import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceAttributeMapper;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
@ -55,6 +57,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
*/
@Service
@Validated
@Slf4j
public class DeviceServiceImpl implements DeviceService {
@Resource
@ -307,19 +310,45 @@ public class DeviceServiceImpl implements DeviceService {
resultMap.put(recordId, recordInfoMap);
} else {
// 如果记录没有ID可以记录日志或使用其他策略如生成临时ID这里简单跳过
System.err.println("警告发现一条数据记录缺少ID已跳过。");
log.error("发现一条数据记录缺少ID已跳过");
}
}
}
} catch (Exception e) {
// 异常处理
System.err.println("处理设备" + deviceId + "的数据时发生异常: " + e.getMessage());
// 可以选择在异常时返回空Map或包含错误信息的特殊Map根据业务需求决定
log.error("处理设备" + deviceId + "的数据时发生异常: ", e.getMessage());
return new HashMap<>();
}
return resultMap;
}
@Override
public List<DevicePointRespVO> devicePointList() {
List<DevicePointRespVO> devicePointRespVOList = new ArrayList<>();
List<DeviceDO> deviceDOS = deviceMapper.selectList(Wrappers.<DeviceDO>lambdaQuery().orderByDesc(DeviceDO::getCreateTime));
if (deviceDOS.isEmpty()){
return devicePointRespVOList;
}
for (DeviceDO deviceDO : deviceDOS) {
DevicePointRespVO devicePointRespVO = new DevicePointRespVO();
devicePointRespVO.setDeviceId(deviceDO.getId());
devicePointRespVO.setDeviceName(deviceDO.getDeviceName());
List<DeviceContactModelDO> deviceContactModelDOS = deviceContactModelMapper.selectList(
Wrappers.<DeviceContactModelDO>lambdaQuery()
.eq(DeviceContactModelDO::getDeviceId, deviceDO.getId()));
if (!deviceContactModelDOS.isEmpty()){
devicePointRespVO.setContactModelDOList(deviceContactModelDOS);
}
devicePointRespVOList.add(devicePointRespVO);
}
return devicePointRespVOList;
}
@Override
public Long createDeviceAttribute(DeviceAttributeDO deviceAttribute) {

@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.taosdata.jdbc.utils.BlobUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.springframework.dao.EmptyResultDataAccessException;
@ -22,6 +23,7 @@ import java.text.SimpleDateFormat;
import java.util.*;
@Service
@Slf4j
public class TDengineService {
@Resource
private JdbcTemplate jdbcTemplate;
@ -374,11 +376,9 @@ public class TDengineService {
return result;
}
});
} catch (EmptyResultDataAccessException e) {
return Collections.singletonList(createEmptyResult(id));
} catch (Exception e) {
System.err.println("查询设备" + id + "的最新数据时发生异常: " + e.getMessage());
e.printStackTrace();
log.error("查询设备" + id + "的最新数据时发生异常", e);
// e.printStackTrace();
return Collections.singletonList(createEmptyResult(id));
}
}

@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.dal.mysql.deviceattributetype.DeviceAttribute
import cn.iocoder.yudao.module.iot.service.device.TDengineService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@ -36,6 +37,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
*/
@Service
@Validated
@Slf4j
public class DeviceModelAttributeServiceImpl implements DeviceModelAttributeService {
@Resource
@ -170,7 +172,10 @@ public class DeviceModelAttributeServiceImpl implements DeviceModelAttributeServ
}
} catch (Exception e) {
throw new RuntimeException("处理设备数据时发生异常", e);
log.error(e.getMessage());
// e.printStackTrace();
// throw new RuntimeException("处理设备数据时发生异常", e);
return new ArrayList<>();
}

@ -18,6 +18,7 @@ public interface ErrorCodeConstants {
ErrorCode BOM_NOT_EXISTS = new ErrorCode(5_001, "产品BOM不存在");
ErrorCode BOM_EXISTS = new ErrorCode(5_002, "产品BOM已存在");
ErrorCode ORGANIZATION_NOT_EXISTS = new ErrorCode(5_0011, "产线工位不存在");
ErrorCode ORGANIZATION_ID_NOT_EXISTS = new ErrorCode(5_0011, "产线工位不存在");
ErrorCode ORGANIZATION_EXITS_CHILDREN = new ErrorCode(5_0012, "存在存在子产线工位,无法删除");
ErrorCode ORGANIZATION_PARENT_NOT_EXITS = new ErrorCode(5_0013,"父级产线工位不存在");
ErrorCode ORGANIZATION_PARENT_ERROR = new ErrorCode(5_0014, "不能设置自己为父产线工位");

@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDeviceConsumptionReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDevicePageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDeviceRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDeviceSaveReqVO;
@ -24,6 +25,7 @@ import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -97,12 +99,11 @@ public class EnergyDeviceController {
BeanUtils.toBean(list, EnergyDeviceRespVO.class));
}
@PostMapping("/queryDataRecords")
@GetMapping("/queryDataRecords")
@Operation(summary = "查询数据记录")
@PreAuthorize("@ss.hasPermission('mes:energy-device:create')")
public CommonResult<List<EnergyDeviceRespVO>> queryDataRecords(@RequestParam(name = "startTime", required = false ) String startTime,
@RequestParam(name = "endTime", required = false ) String endTime) {
return success(energyDeviceService.queryDataRecords(startTime,endTime));
public CommonResult<List<EnergyDeviceRespVO>> queryDataRecords(@Valid EnergyDeviceConsumptionReqVO deviceConsumptionReqVO) {
return success(energyDeviceService.queryDataRecords(deviceConsumptionReqVO));
}

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 能耗管理/能耗报表 Request VO")
@Data
public class EnergyDeviceConsumptionReqVO {
@Schema(description = "表名称")
private String name;
@Schema(description = "所属区域")
private Long orgId;
@Schema(description = "开始时间")
private String startTime;
@Schema(description = "结束时间")
private String endTime;
}

@ -100,7 +100,7 @@ public class EnergyDeviceRespVO {
@ExcelProperty("子列表点位参数值")
private Map<String,String> sublistPointList;
@Schema(description = "列表")
Map<Long,List<OperationRulesVO>> operationRulesVOMap;
@Schema(description = "点位差值列表")
private Map<String, String> operationRulesVOMap;
}

@ -4,10 +4,7 @@ import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.LineAnalysisTreeDTO;
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.OrganizationListReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.OrganizationRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.OrganizationSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.organization.OrganizationDO;
import cn.iocoder.yudao.module.mes.service.organization.OrganizationService;
import io.swagger.v3.oas.annotations.Operation;
@ -98,10 +95,22 @@ public class OrganizationController {
@GetMapping("/deviceParameterAnalysis")
@Operation(summary = "设备运行参数分析")
@PreAuthorize("@ss.hasPermission('iot:device:query')")
public CommonResult<List<LineAnalysisTreeDTO.LineNode>> deviceParameterAnalysis(@RequestParam(value = "keyword", required = false) String keyword) {
List<LineAnalysisTreeDTO.LineNode> list = organizationService.deviceParameterAnalysis(keyword);
public CommonResult<List<LineAnalysisTreeDTO.LineNode>> deviceParameterAnalysis(@RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "showDevices") Integer showDevices
) {
List<LineAnalysisTreeDTO.LineNode> list = organizationService.deviceParameterAnalysis(keyword,showDevices);
return success(list);
}
//
// @GetMapping("/getParametersById")
// @Operation(summary = "根据产线Id获取点位参数")
// @Parameter(name = "id", description = "编号", required = true, example = "1024")
// //@PreAuthorize("@ss.hasPermission('mes:organization:query')")
// public CommonResult<List<DeviceParametersDTO>> getParametersById(@RequestParam("id") Long id) {
// List<DeviceParametersDTO> organization = organizationService.getDeviceParametersByOrganizationId(id);
// return success(organization);
// }
}

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.mes.controller.admin.organization.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeviceParametersDTO {
/**
* ID
*/
private Long deviceId;
/**
*
*/
private String deviceName;
/**
*
*/
private String deviceCode;
/**
*
*/
private String deviceType;
/**
*
*/
private String deviceStatus;
/**
*
*/
private List<ParameterInfoDTO> parameters;
}

@ -27,8 +27,12 @@ public class LineAnalysisTreeDTO {
public static class LineNode {
private Long id; // 产线ID
private String name; // 产线名称
private String orgClass; // 组织等级
private Long parentId;
private List<EquipmentNode> equipments = new ArrayList<>();
// private List<EquipmentNode> equipments = new ArrayList<>();
private List<EquipmentNode> equipments;
private List<LineNode> children;
}
// 设备节点
@ -39,7 +43,7 @@ public class LineAnalysisTreeDTO {
public static class EquipmentNode {
private Long id; // 设备ID
private String name; // 设备名称
private List<ParameterNode> parameters = new ArrayList<>();
private List<ParameterNode> parameters;
}
// 参数节点

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.mes.controller.admin.organization.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ParameterInfoDTO {
/**
* ID
*/
private Long parameterId;
/**
*
*/
private String parameterName;
/**
*
*/
private String parameterCode;
/**
*
*/
private String parameterType;
/**
*
*/
private String dataType;
/**
*
*/
private String unit;
/**
*
*/
private Double ratio;
}

@ -27,9 +27,11 @@ public class TaskManagementSaveReqVO {
private Integer taskType;
@Schema(description = "设备列表")
@NotEmpty(message = "名称不能为空")
private String deviceList;
@Schema(description = "项目表单")
@NotNull
private Long projectForm;
@Schema(description = "起止开始日期")

@ -16,5 +16,5 @@ public class TicketManagementBatchUpdateReqVO {
@Schema(description = "作业状态", example = "2")
@NotNull(message = "作业状态不能为空")
private Integer jobStatus ; // 默认值为2
private Integer jobStatus ;
}

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mes.service.energydevice;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDeviceConsumptionReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDevicePageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDeviceRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDeviceSaveReqVO;
@ -109,7 +110,7 @@ public interface EnergyDeviceService {
return convertMap(getList(ids), EnergyDeviceDO::getId);
}
List<EnergyDeviceRespVO> queryDataRecords(String startTime,String endTime);
List<EnergyDeviceRespVO> queryDataRecords(EnergyDeviceConsumptionReqVO deviceConsumptionReqVO);
}

@ -4,19 +4,21 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.iot.dal.devicecontactmodel.DeviceContactModelDO;
import cn.iocoder.yudao.module.iot.dal.mysql.devicecontactmodel.DeviceContactModelMapper;
import cn.iocoder.yudao.module.iot.service.device.TDengineService;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDevicePageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDeviceRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.EnergyDeviceSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.OperationRulesVO;
import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.energydevice.EnergyDeviceCheckRecordDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.energydevice.EnergyDeviceDO;
import cn.iocoder.yudao.module.mes.dal.mysql.energydevice.EnergyDeviceCheckRecordMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.energydevice.EnergyDeviceMapper;
import cn.iocoder.yudao.module.mes.dal.redis.no.MesNoRedisDAO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -24,6 +26,8 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.*;
@ -39,6 +43,7 @@ import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
*/
@Service
@Validated
@Slf4j
public class EnergyDeviceServiceImpl implements EnergyDeviceService {
@Resource
@ -49,6 +54,8 @@ public class EnergyDeviceServiceImpl implements EnergyDeviceService {
private MesNoRedisDAO noRedisDAO;
@Resource
private TDengineService tDengineService;
@Resource
private DeviceContactModelMapper deviceContactModelMapper;
@Override
public Long createEnergyDevice(EnergyDeviceSaveReqVO createReqVO) {
@ -242,50 +249,647 @@ public class EnergyDeviceServiceImpl implements EnergyDeviceService {
}
@Override
public List<EnergyDeviceRespVO> queryDataRecords(String startTime,String endTime) {
List<EnergyDeviceRespVO> energyDeviceRespVOArrayList = new ArrayList<>();
List<EnergyDeviceDO> energyDeviceDO = energyDeviceMapper.selectList();
if (energyDeviceDO.isEmpty()){
public List<EnergyDeviceRespVO> queryDataRecords(EnergyDeviceConsumptionReqVO deviceConsumptionReqVO) {
List<EnergyDeviceRespVO> result = new ArrayList<>();
List<EnergyDeviceDO> energyDeviceDO = energyDeviceMapper.selectList(
Wrappers.<EnergyDeviceDO>lambdaQuery()
.like(StringUtils.isNotBlank(deviceConsumptionReqVO.getName()), EnergyDeviceDO::getName, deviceConsumptionReqVO.getName())
.eq(deviceConsumptionReqVO.getOrgId() != null, EnergyDeviceDO::getOrgId, deviceConsumptionReqVO.getOrgId()));
if (energyDeviceDO == null || energyDeviceDO.isEmpty()) {
throw exception(ENERGY_LIST_NOT_EXISTS);
}
for (EnergyDeviceDO deviceDO : energyDeviceDO) {
EnergyDeviceRespVO energyDeviceRespVO = new EnergyDeviceRespVO();
if (StringUtils.isBlank(deviceDO.getRules())){
if (StringUtils.isBlank(deviceDO.getRules())) {
continue;
}
//查询每个点位的Id
// 解析规则
List<OperationRulesVO> operationRulesVOList = JSON.parseArray(deviceDO.getRules(), OperationRulesVO.class);
Map<Long,List<OperationRulesVO>> operationRulesVOMap =new HashMap<>();
for (OperationRulesVO operationRulesVO : operationRulesVOList) {
List<OperationRulesVO> operationRulesVOS = new ArrayList<>();
//获取Td列表
List<Map<String, Object>> maps = tDengineService.getstDeviceDataOrderByTimeDesc(operationRulesVO.getDeviceId(), startTime, endTime);
for (Map<String, Object> map : maps) {
String queryData = map.get("queryData").toString();
//获取json数据列表
List<DeviceContactModelDO> deviceContactModelDOS = JSON.parseArray(queryData, DeviceContactModelDO.class);
for (DeviceContactModelDO deviceContactModelDO : deviceContactModelDOS) {
if (operationRulesVO.equals(deviceContactModelDO.getId())){
OperationRulesVO operationRulesVO1 = new OperationRulesVO();
operationRulesVO1.setPointId(deviceContactModelDO.getId());
operationRulesVO1.setPointValue((String) deviceContactModelDO.getAddressValue());
operationRulesVOS.add(operationRulesVO1);
if (operationRulesVOList == null || operationRulesVOList.isEmpty()) {
continue;
}
try {
// 计算设备结果
EnergyDeviceRespVO deviceRespVO = buildEnergyDeviceRespVO(deviceDO, operationRulesVOList, deviceConsumptionReqVO.getStartTime(), deviceConsumptionReqVO.getEndTime());
if (deviceRespVO != null) {
result.add(deviceRespVO);
}
} catch (Exception e) {
log.error("计算设备结果失败, deviceId: {}", deviceDO.getId(), e);
}
}
return result;
}
/**
* EnergyDeviceRespVO
*/
private EnergyDeviceRespVO buildEnergyDeviceRespVO(EnergyDeviceDO deviceDO,
List<OperationRulesVO> rules,
String startTime, String endTime) {
if (deviceDO == null || rules == null || rules.isEmpty()) {
return null;
}
EnergyDeviceRespVO respVO = new EnergyDeviceRespVO();
// 设置设备基本信息
respVO.setId(deviceDO.getId());
respVO.setName(deviceDO.getName());
respVO.setCode(deviceDO.getCode());
respVO.setInfo(deviceDO.getInfo());
respVO.setCheckCron(deviceDO.getCheckCron());
respVO.setLastCheckTime(deviceDO.getLastCheckTime());
respVO.setLastCheckValue(deviceDO.getLastCheckValue());
respVO.setUnitName(deviceDO.getUnitName());
respVO.setIsEnable(deviceDO.getIsEnable());
respVO.setCreateTime(deviceDO.getCreateTime());
respVO.setUpdateTime(deviceDO.getUpdateTime());
respVO.setDeviceTypeId(deviceDO.getDeviceTypeId());
respVO.setDeviceTypeName(deviceDO.getDeviceTypeName());
respVO.setOrgId(deviceDO.getOrgId());
respVO.setOrgName(deviceDO.getOrgName());
respVO.setRules(deviceDO.getRules());
respVO.setOperationRulesVOList(rules);
// 计算数据结果
Map<String, Object> calculationResult = calculateDeviceData(deviceDO, rules, startTime, endTime);
if (calculationResult == null) {
return respVO;
}
// 设置能耗总用量差值
Double totalDifference = (Double) calculationResult.get("totalDifference");
if (totalDifference != null) {
respVO.setEnergyConsumption(formatDouble(totalDifference));
} else {
respVO.setEnergyConsumption("0.0");
}
// 设置每个点位参数的差值key为点位参数名称
Map<String, String> operationRulesVOMap = buildPointDifferenceMap(calculationResult, deviceDO, rules);
respVO.setOperationRulesVOMap(operationRulesVOMap);
return respVO;
}
/**
*
*/
private Map<String, Object> getPointData(Map<String, Object> dataMap, Long pointId) {
if (dataMap == null || pointId == null) {
return null;
}
try {
Object queryDataObj = dataMap.get("queryData");
if (queryDataObj == null) {
return null;
}
String queryData = queryDataObj.toString();
if (StringUtils.isBlank(queryData)) {
return null;
}
// 处理编码问题
queryData = fixEncoding(queryData);
// 解析JSON数组
JSONArray jsonArray = JSON.parseArray(queryData);
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject jsonObj = jsonArray.getJSONObject(i);
// 安全获取id
Long dataPointId = null;
try {
dataPointId = jsonObj.getLong("id");
} catch (Exception e) {
continue;
}
if (dataPointId == null) {
continue;
}
// 匹配点位ID
if (pointId.equals(dataPointId)) {
Map<String, Object> pointData = new HashMap<>();
// 提取所有需要的字段
pointData.put("id", dataPointId);
// 安全获取字段
pointData.put("address", getJsonString(jsonObj, "address"));
// 处理值
Object value = jsonObj.get("addressValue");
Double doubleValue = null;
if (value != null) {
try {
if (value instanceof Number) {
doubleValue = ((Number) value).doubleValue();
} else {
doubleValue = Double.parseDouble(value.toString());
}
} catch (NumberFormatException e) {
log.warn("点位值无法转换为数字: pointId={}, value={}", pointId, value);
doubleValue = null;
}
}
pointData.put("value", doubleValue);
pointData.put("addressValue", value);
pointData.put("attributeCode", getJsonString(jsonObj, "attributeCode"));
pointData.put("attributeName", getJsonString(jsonObj, "attributeName"));
pointData.put("attributeType", getJsonString(jsonObj, "attributeType"));
pointData.put("dataType", getJsonString(jsonObj, "dataType"));
pointData.put("dataUnit", getJsonString(jsonObj, "dataUnit"));
// 安全获取ratio
try {
Float ratio = jsonObj.getFloat("ratio");
pointData.put("ratio", ratio);
} catch (Exception e) {
pointData.put("ratio", null);
}
return pointData;
}
}
} catch (Exception e) {
log.error("解析点位数据失败, pointId: {}", pointId, e);
}
return null;
}
/**
* JSON
*/
private String getJsonString(JSONObject jsonObj, String key) {
try {
return jsonObj.getString(key);
} catch (Exception e) {
return "";
}
}
/**
* double
*/
private String formatDouble(Double value) {
if (value == null) {
return "0.0";
}
DecimalFormat df = new DecimalFormat("#.##");
return df.format(value);
}
/**
*
*/
private Map<String, Object> calculateDeviceData(EnergyDeviceDO deviceDO,
List<OperationRulesVO> rules,
String startTime, String endTime) {
if (deviceDO == null || rules == null || rules.isEmpty()) {
return null;
}
Map<String, Object> result = new HashMap<>();
try {
// 分别计算最新和最晚时间的数据
Map<String, Object> latestData = getTimePointData(rules, startTime, endTime, true);
Map<String, Object> earliestData = getTimePointData(rules, startTime, endTime, false);
if (latestData == null || earliestData == null) {
return result;
}
// 使用相同的规则计算两个时间点的总值
Double latestTotal = calculateTotalByRules(latestData, rules);
Double earliestTotal = calculateTotalByRules(earliestData, rules);
// 计算每个点位的差值
List<Map<String, Object>> pointDifferences = calculatePointDifferences(latestData, earliestData, rules);
result.put("latestData", latestData);
result.put("earliestData", earliestData);
result.put("latestTotal", latestTotal != null ? latestTotal : 0.0);
result.put("earliestTotal", earliestTotal != null ? earliestTotal : 0.0);
result.put("totalDifference", (latestTotal != null && earliestTotal != null) ?
latestTotal - earliestTotal : 0.0);
result.put("pointDifferences", pointDifferences != null ? pointDifferences : Collections.emptyList());
} catch (Exception e) {
log.error("计算设备数据失败, deviceId: {}", deviceDO.getId(), e);
}
return result;
}
/**
*
*/
private Double getPointValueFromDataByDevice(Map<String, Object> timePointData, Long deviceId, Long pointId) {
if (timePointData == null || deviceId == null || pointId == null) {
return null;
}
String deviceKey = "device_" + deviceId;
Map<String, Object> deviceData = (Map<String, Object>) timePointData.get(deviceKey);
if (deviceData == null) {
return null;
}
return getPointValueFromData(deviceData, pointId);
}
/**
*
*/
private Double getPointValueFromData(Map<String, Object> dataMap, Long pointId) {
if (dataMap == null || pointId == null) {
return null;
}
Map<String, Object> pointData = getPointData(dataMap, pointId);
if (pointData != null) {
Object value = pointData.get("value");
if (value instanceof Double) {
return (Double) value;
} else if (value instanceof Number) {
return ((Number) value).doubleValue();
}
}
return null;
}
/**
*
*/
private Map<String, Object> getTimePointData(List<OperationRulesVO> rules,
String startTime, String endTime,
boolean isLatest) {
if (rules == null || rules.isEmpty()) {
return null;
}
Map<String, Object> timePointData = new HashMap<>();
String timestamp = null;
for (OperationRulesVO rule : rules) {
if (rule == null || rule.getDeviceId() == null) {
continue;
}
List<Map<String, Object>> maps = null;
try {
maps = tDengineService.getstDeviceDataOrderByTimeDesc(
rule.getDeviceId(), startTime, endTime);
} catch (Exception e) {
log.error("查询设备数据失败, deviceId: {}", rule.getDeviceId(), e);
continue;
}
if (maps == null || maps.isEmpty()) {
continue;
}
Map<String, Object> dataMap = null;
try {
if (isLatest) {
dataMap = maps.get(0);
} else {
dataMap = maps.get(maps.size() - 1);
}
} catch (Exception e) {
log.error("获取时间点数据失败, deviceId: {}, isLatest: {}", rule.getDeviceId(), isLatest, e);
continue;
}
if (dataMap == null) {
continue;
}
if (timestamp == null && dataMap.containsKey("timestamp")) {
Object tsObj = dataMap.get("timestamp");
if (tsObj != null) {
timestamp = tsObj.toString();
}
operationRulesVOMap.put(operationRulesVO.getPointId(),operationRulesVOS);
}
String deviceKey = "device_" + rule.getDeviceId();
if (!timePointData.containsKey(deviceKey)) {
timePointData.put(deviceKey, dataMap);
}
energyDeviceRespVO.setOperationRulesVOMap(operationRulesVOMap);
energyDeviceRespVOArrayList.add(energyDeviceRespVO);
}
if (timestamp != null) {
timePointData.put("timestamp", timestamp);
} else {
timePointData.put("timestamp", "");
}
return timePointData.isEmpty() ? null : timePointData;
}
/**
*
*/
private Double calculateTotalByRules(Map<String, Object> timePointData, List<OperationRulesVO> rules) {
if (timePointData == null || timePointData.isEmpty() || rules == null || rules.isEmpty()) {
return 0.0;
}
Double total = null;
String lastOperator = null;
for (int i = 0; i < rules.size(); i++) {
OperationRulesVO rule = rules.get(i);
if (rule == null || rule.getDeviceId() == null || rule.getPointId() == null) {
continue;
}
String deviceKey = "device_" + rule.getDeviceId();
Map<String, Object> deviceData = (Map<String, Object>) timePointData.get(deviceKey);
if (deviceData == null) {
continue;
}
Double pointValue = getPointValueFromData(deviceData, rule.getPointId());
if (pointValue == null) {
continue;
}
if (total == null) {
total = pointValue;
} else {
String operator = null;
if (rule.getOperator() != null) {
operator = rule.getOperator().trim();
}
if (StringUtils.isEmpty(operator)) {
operator = lastOperator;
}
if (StringUtils.isNotEmpty(operator)) {
try {
total = applyOperator(total, pointValue, operator);
} catch (Exception e) {
log.error("应用运算符失败: current={}, value={}, operator={}", total, pointValue, operator, e);
total += pointValue;
}
} else {
total += pointValue;
}
}
lastOperator = rule.getOperator();
}
return total != null ? total : 0.0;
}
/**
*
*/
private List<Map<String, Object>> calculatePointDifferences(Map<String, Object> latestData,
Map<String, Object> earliestData,
List<OperationRulesVO> rules) {
List<Map<String, Object>> differences = new ArrayList<>();
if (rules == null || rules.isEmpty()) {
return differences;
}
for (OperationRulesVO rule : rules) {
if (rule == null || rule.getDeviceId() == null || rule.getPointId() == null) {
continue;
}
Map<String, Object> pointDiff = new HashMap<>();
pointDiff.put("pointId", rule.getPointId());
pointDiff.put("operator", rule.getOperator() != null ? rule.getOperator() : "");
pointDiff.put("deviceId", rule.getDeviceId());
Double latestValue = getPointValueFromDataByDevice(latestData, rule.getDeviceId(), rule.getPointId());
Double earliestValue = getPointValueFromDataByDevice(earliestData, rule.getDeviceId(), rule.getPointId());
pointDiff.put("latestValue", latestValue != null ? latestValue : 0.0);
pointDiff.put("earliestValue", earliestValue != null ? earliestValue : 0.0);
if (latestValue != null && earliestValue != null) {
Double difference = latestValue - earliestValue;
pointDiff.put("difference", difference);
} else if (latestValue != null) {
pointDiff.put("difference", latestValue);
} else if (earliestValue != null) {
pointDiff.put("difference", -earliestValue);
} else {
pointDiff.put("difference", 0.0);
}
differences.add(pointDiff);
}
return differences;
}
/**
*
*/
private Double applyOperator(Double current, Double value, String operator) {
if (current == null || value == null || operator == null) {
return current;
}
String op = operator.trim();
switch (op) {
case "+":
return current + value;
case "-":
return current - value;
case "*":
return current * value;
case "/":
if (Math.abs(value) > 0.000001) { // 避免除零
return current / value;
} else {
log.warn("除数不能为0: current={}, value={}", current, value);
return current;
}
default:
log.warn("不支持的操作符: {}, 使用加法", operator);
return current + value;
}
}
/**
*
*/
private String fixEncoding(String str) {
if (StringUtils.isBlank(str)) {
return str;
}
try {
// 尝试UTF-8解码
byte[] bytes = str.getBytes(StandardCharsets.ISO_8859_1);
return new String(bytes, StandardCharsets.UTF_8);
} catch (Exception e) {
return str;
}
}
/**
* Map
*/
private Map<String, String> buildPointDifferenceMap(Map<String, Object> calculationResult,
EnergyDeviceDO deviceDO,
List<OperationRulesVO> originalRules) {
Map<String, String> result = new HashMap<>();
if (calculationResult == null || originalRules == null || originalRules.isEmpty()) {
return result;
}
List<Map<String, Object>> pointDifferences = (List<Map<String, Object>>) calculationResult.get("pointDifferences");
if (pointDifferences == null || pointDifferences.isEmpty()) {
return result;
}
// 获取最新数据用于获取点位名称
Map<String, Object> latestData = (Map<String, Object>) calculationResult.get("latestData");
// 收集所有点位ID
List<Long> allPointIds = new ArrayList<>();
for (Map<String, Object> pointDiff : pointDifferences) {
Long pointId = (Long) pointDiff.get("pointId");
if (pointId != null) {
allPointIds.add(pointId);
}
}
// 批量从本地数据库获取点位名称
Map<Long, String> pointNameMap = batchGetPointNamesFromLocalDB(allPointIds);
for (Map<String, Object> pointDiff : pointDifferences) {
Long pointId = (Long) pointDiff.get("pointId");
if (pointId == null) {
continue;
}
// 获取点位名称
String pointName = null;
// 1. 尝试从TD数据库获取
pointName = getPointNameFromTDData(latestData, pointId, pointDiff);
// 2. 如果TD数据库没有从本地数据库获取
if (StringUtils.isBlank(pointName)) {
pointName = pointNameMap.get(pointId);
}
// 获取差值
Double difference = (Double) pointDiff.get("difference");
String differenceStr = formatDouble(difference != null ? difference : 0.0);
// 以点位名称为key差值为value
if (StringUtils.isNotBlank(pointName)) {
result.put(pointName, differenceStr);
} else {
// 如果还没有点位名称使用点位ID作为key
result.put("点位" + pointId, differenceStr);
}
}
return result;
}
/**
* TD
*/
private String getPointNameFromTDData(Map<String, Object> timePointData, Long pointId, Map<String, Object> pointDiff) {
if (timePointData == null || pointId == null || pointDiff == null) {
return null;
}
Long deviceId = (Long) pointDiff.get("deviceId");
if (deviceId == null) {
return null;
}
String deviceKey = "device_" + deviceId;
Map<String, Object> deviceData = (Map<String, Object>) timePointData.get(deviceKey);
if (deviceData == null) {
return null;
}
Map<String, Object> pointData = getPointData(deviceData, pointId);
if (pointData == null) {
return null;
}
String attributeName = (String) pointData.get("attributeName");
if (StringUtils.isNotBlank(attributeName)) {
return attributeName;
}
String attributeCode = (String) pointData.get("attributeCode");
if (StringUtils.isNotBlank(attributeCode)) {
return attributeCode;
}
return null;
}
/**
*
*/
private Map<Long, String> batchGetPointNamesFromLocalDB(List<Long> pointIds) {
Map<Long, String> result = new HashMap<>();
if (pointIds == null || pointIds.isEmpty()) {
return result;
}
try {
// 批量查询点位信息
List<DeviceContactModelDO> deviceContacts = deviceContactModelMapper.selectBatchIds(pointIds);
if (deviceContacts != null && !deviceContacts.isEmpty()) {
for (DeviceContactModelDO deviceContact : deviceContacts) {
if (deviceContact == null || deviceContact.getId() == null) {
continue;
}
String pointName = null;
if (StringUtils.isNotBlank(deviceContact.getAttributeName())) {
pointName = deviceContact.getAttributeName();
} else if (StringUtils.isNotBlank(deviceContact.getAttributeCode())) {
pointName = deviceContact.getAttributeCode();
}
if (StringUtils.isNotBlank(pointName)) {
result.put(deviceContact.getId(), pointName);
}
}
}
} catch (Exception e) {
log.error("批量查询点位信息失败, pointIds: {}", pointIds, e);
}
return energyDeviceRespVOArrayList;
return result;
}
}

@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.mes.service.organization;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.LineAnalysisTreeDTO;
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.OrganizationListReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.OrganizationRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.OrganizationSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.organization.OrganizationDO;
import javax.validation.Valid;
@ -80,5 +77,7 @@ public interface OrganizationService {
return convertMap(getOrganizationVOList(ids), OrganizationDO::getId);
}
List<LineAnalysisTreeDTO.LineNode> deviceParameterAnalysis(String keyword);
List<LineAnalysisTreeDTO.LineNode> deviceParameterAnalysis(String keyword,Integer showDevices);
// List<DeviceParametersDTO> getDeviceParametersByOrganizationId(Long id);
}

@ -257,374 +257,405 @@ public class OrganizationServiceImpl implements OrganizationService {
}
@Override
public List<LineAnalysisTreeDTO.LineNode> deviceParameterAnalysis(String keyword) {
public List<LineAnalysisTreeDTO.LineNode> deviceParameterAnalysis(String keyword, Integer showDevices) {
// 参数验证
if (showDevices == null || (showDevices != 1 && showDevices != 2)) {
showDevices = 1; // 默认展示设备和参数
}
boolean needShowDevices = showDevices == 1; // 1-展示2-不展示
//1. 获取产线集合
// 1. 获取产线集合
OrganizationListReqVO organizationListReqVO = new OrganizationListReqVO();
List<OrganizationDO> organizationDOS = getOrganizationList(organizationListReqVO);
List<OrganizationRespVO> organizationRespVOS = buildVOList(organizationDOS);
if (organizationRespVOS.isEmpty()) {
return Collections.emptyList();
return Collections.emptyList();
}
// 2. 获取所有有machineId的产线
List<Long> machineIds = organizationRespVOS.stream()
// 2. 获取所有有machineId的组织
List<Long> deviceIds = organizationRespVOS.stream()
.map(OrganizationRespVO::getMachineId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
// 3. 根据machineId查询设备
List<DeviceDO> allDevices = Collections.emptyList();
if (!machineIds.isEmpty()) {
// 3. 查询设备信息
Map<Long, DeviceDO> deviceMap;
if (!deviceIds.isEmpty()) {
LambdaQueryWrapper<DeviceDO> deviceWrapper = new LambdaQueryWrapper<>();
deviceWrapper.in(DeviceDO::getId, machineIds)
deviceWrapper.in(DeviceDO::getId, deviceIds)
.eq(DeviceDO::getIsEnable, true);
allDevices = deviceMapper.selectList(deviceWrapper);
List<DeviceDO> devices = deviceMapper.selectList(deviceWrapper);
deviceMap = devices.stream()
.collect(Collectors.toMap(DeviceDO::getId, Function.identity()));
} else {
deviceMap = new HashMap<>();
}
// 4. 获取所有参数
List<DeviceContactModelDO> allParameters = getAllParameters(allDevices);
// 5. 构建映射关系
Map<Long, DeviceDO> deviceById = allDevices.stream()
.collect(Collectors.toMap(DeviceDO::getId, Function.identity()));
// 4. 查询设备参数
Map<Long, List<DeviceContactModelDO>> paramsByDeviceId;
if (!deviceIds.isEmpty()) {
LambdaQueryWrapper<DeviceContactModelDO> paramWrapper = new LambdaQueryWrapper<>();
paramWrapper.in(DeviceContactModelDO::getDeviceId, deviceIds)
.orderByAsc(DeviceContactModelDO::getSort);
List<DeviceContactModelDO> allParameters = deviceContactModelMapper.selectList(paramWrapper);
paramsByDeviceId = allParameters.stream()
.filter(param -> param.getDeviceId() != null)
.collect(Collectors.groupingBy(DeviceContactModelDO::getDeviceId));
} else {
paramsByDeviceId = new HashMap<>();
}
// 6. 构建设备按产线分组的映射
Map<Long, List<DeviceDO>> devicesByLineId = new HashMap<>();
for (OrganizationRespVO line : organizationRespVOS) {
if (line.getMachineId() != null) {
DeviceDO device = deviceById.get(line.getMachineId());
if (device != null) {
devicesByLineId.computeIfAbsent(line.getId(), k -> new ArrayList<>())
.add(device);
}
// 5. 构建产线ID到orgClass的映射
Map<Long, String> lineOrgClassMap = new HashMap<>();
for (int i = 0; i < organizationDOS.size(); i++) {
OrganizationDO orgDO = organizationDOS.get(i);
OrganizationRespVO orgVO = organizationRespVOS.get(i);
if (orgDO.getOrgClass() != null && orgVO != null) {
lineOrgClassMap.put(orgVO.getId(), orgDO.getOrgClass());
}
}
Map<Long, List<DeviceContactModelDO>> paramsByDeviceId = allParameters.stream()
.filter(param -> param.getDeviceId() != null)
.collect(Collectors.groupingBy(DeviceContactModelDO::getDeviceId));
// 获取产线与父节点的映射关系
Map<Long, Long> lineParentIdMap = organizationRespVOS.stream()
.collect(Collectors.toMap(
OrganizationRespVO::getId,
line -> line.getParentId() != null ? line.getParentId() : 0L, // 如果父节点为空使用默认值0
(existing, replacement) -> existing
));
// 构建产线ID到产线对象的映射
Map<Long, OrganizationRespVO> lineMap = organizationRespVOS.stream()
.collect(Collectors.toMap(OrganizationRespVO::getId, Function.identity()));
// 获取所有匹配的产线(包括下级匹配的)
List<OrganizationRespVO> matchedLines = getMatchedLinesWithAncestors(
organizationRespVOS, keyword, allDevices, paramsByDeviceId, lineParentIdMap, lineMap
);
// 7. 构建树结构
return buildTreeStructureWithKeyword(matchedLines, devicesByLineId, paramsByDeviceId,keyword,lineParentIdMap);
}
private List<OrganizationRespVO> getMatchedLinesWithAncestors(
List<OrganizationRespVO> allLines,
String keyword,
List<DeviceDO> allDevices,
Map<Long, List<DeviceContactModelDO>> paramsByDeviceId,
Map<Long, Long> lineParentIdMap,
Map<Long, OrganizationRespVO> lineMap) {
// 6. 构建组织ID到子节点的映射
Map<Long, List<OrganizationRespVO>> childrenByParentId = organizationRespVOS.stream()
.filter(org -> org.getParentId() != null && org.getParentId() != 0L)
.collect(Collectors.groupingBy(OrganizationRespVO::getParentId));
// 7. 如果有搜索关键词,筛选匹配的节点
Set<Long> matchedNodeIds = new HashSet<>();
boolean hasKeyword = StringUtils.isNotBlank(keyword);
String lowerKeyword = hasKeyword ? keyword.toLowerCase() : "";
// 存储最终要包含的产线ID
Set<Long> lineIdsToInclude = new HashSet<>();
if (hasKeyword) {
String lowerKeyword = keyword.toLowerCase();
// 1. 首先找出直接匹配的产线
for (OrganizationRespVO line : allLines) {
boolean lineMatch = !hasKeyword ||
(line.getName() != null && line.getName().toLowerCase().contains(lowerKeyword));
// 查找组织名称匹配的节点
for (OrganizationRespVO node : organizationRespVOS) {
boolean nodeMatched = false;
if (lineMatch) {
// 添加到结果集
lineIdsToInclude.add(line.getId());
// 向上查找所有父级节点
addAllAncestors(line.getId(), lineParentIdMap, lineMap, lineIdsToInclude);
}
}
// 1. 检查组织名称是否匹配
if (node.getName() != null && node.getName().toLowerCase().contains(lowerKeyword)) {
nodeMatched = true;
}
// 2. 查找设备匹配的产线
if (hasKeyword) {
for (DeviceDO device : allDevices) {
boolean deviceMatch = device.getDeviceName() != null &&
device.getDeviceName().toLowerCase().contains(lowerKeyword);
if (deviceMatch) {
// 找到这个设备所属的产线
for (OrganizationRespVO line : allLines) {
if (line.getMachineId() != null && line.getMachineId().equals(device.getId())) {
lineIdsToInclude.add(line.getId());
addAllAncestors(line.getId(), lineParentIdMap, lineMap, lineIdsToInclude);
// 2. 如果没有组织名称匹配,检查该节点是否有设备匹配
if (!nodeMatched && needShowDevices && node.getMachineId() != null) {
DeviceDO device = deviceMap.get(node.getMachineId());
if (device != null) {
// 检查设备名称是否匹配
if (device.getDeviceName() != null &&
device.getDeviceName().toLowerCase().contains(lowerKeyword)) {
nodeMatched = true;
}
}
}
}
}
// 3. 查找参数匹配的产线
if (hasKeyword) {
for (Map.Entry<Long, List<DeviceContactModelDO>> entry : paramsByDeviceId.entrySet()) {
Long deviceId = entry.getKey();
List<DeviceContactModelDO> params = entry.getValue();
boolean hasMatchingParam = params.stream()
.anyMatch(param -> param.getAttributeName() != null &&
param.getAttributeName().toLowerCase().contains(lowerKeyword));
if (hasMatchingParam) {
// 找到这个设备所属的产线
for (OrganizationRespVO line : allLines) {
if (line.getMachineId() != null && line.getMachineId().equals(deviceId)) {
lineIdsToInclude.add(line.getId());
addAllAncestors(line.getId(), lineParentIdMap, lineMap, lineIdsToInclude);
// 检查设备参数是否匹配
if (!nodeMatched) {
List<DeviceContactModelDO> deviceParams = paramsByDeviceId.getOrDefault(device.getId(), new ArrayList<>());
boolean hasMatchingParam = deviceParams.stream()
.anyMatch(param -> param.getAttributeName() != null &&
param.getAttributeName().toLowerCase().contains(lowerKeyword));
if (hasMatchingParam) {
nodeMatched = true;
}
}
}
}
if (nodeMatched) {
// 将当前节点加入匹配列表
matchedNodeIds.add(node.getId());
// 迭代添加所有子节点
addAllDescendants(node.getId(), childrenByParentId, matchedNodeIds);
}
}
}
// 如果没有关键词,返回所有产线
if (!hasKeyword) {
return allLines;
// 如果没有匹配任何节点,返回空列表
if (matchedNodeIds.isEmpty()) {
return Collections.emptyList();
}
} else {
// 无关键词时,包含所有节点
matchedNodeIds.addAll(organizationRespVOS.stream()
.map(OrganizationRespVO::getId)
.collect(Collectors.toSet()));
}
// 只返回需要包含的产线
return allLines.stream()
.filter(line -> lineIdsToInclude.contains(line.getId()))
.collect(Collectors.toList());
}
private void addAllAncestors(Long lineId,
Map<Long, Long> lineParentIdMap,
Map<Long, OrganizationRespVO> lineMap,
Set<Long> lineIdsToInclude) {
Long currentParentId = lineParentIdMap.get(lineId);
// 递归向上查找所有父级节点
while (currentParentId != null && currentParentId != 0L) {
lineIdsToInclude.add(currentParentId);
// 8. 找到最顶层的匹配节点(没有匹配的父节点)
Set<Long> topLevelNodeIds = new HashSet<>(matchedNodeIds);
// 继续向上查找
currentParentId = lineParentIdMap.get(currentParentId);
// 从匹配节点中移除那些父节点也在匹配列表中的节点
for (OrganizationRespVO node : organizationRespVOS) {
if (matchedNodeIds.contains(node.getId()) && node.getParentId() != null &&
node.getParentId() != 0L && matchedNodeIds.contains(node.getParentId())) {
topLevelNodeIds.remove(node.getId());
}
}
}
private List<LineAnalysisTreeDTO.LineNode> buildTreeStructureWithKeyword(List<OrganizationRespVO> lines,
Map<Long, List<DeviceDO>> devicesByLineId,
Map<Long, List<DeviceContactModelDO>> paramsByDeviceId,
String keyword,
Map<Long, Long> lineParentIdMap) {
// 9. 获取顶层节点
Map<Long, OrganizationRespVO> nodeMap = organizationRespVOS.stream()
.collect(Collectors.toMap(OrganizationRespVO::getId, Function.identity()));
// 统一处理关键词
boolean hasKeyword = StringUtils.isNotBlank(keyword);
String lowerKeyword = hasKeyword ? keyword.toLowerCase() : "";
List<OrganizationRespVO> topLevelNodes = topLevelNodeIds.stream()
.map(nodeMap::get)
.filter(Objects::nonNull)
.collect(Collectors.toList());
// 如果lines已经过滤过这里不再需要复杂的匹配判断
if (!hasKeyword) {
// 没有关键词时,返回完整的树结构
return lines.stream().map(line -> {
Long parentId = lineParentIdMap.getOrDefault(line.getId(), 0L);
// 10. 构建树结构
return buildOrganizationTreeWithChildren(topLevelNodes, matchedNodeIds, childrenByParentId,
deviceMap, paramsByDeviceId, lineOrgClassMap, keyword, organizationRespVOS, needShowDevices, hasKeyword);
}
// 获取该产线的设备
List<DeviceDO> lineDevices = devicesByLineId.getOrDefault(line.getId(), new ArrayList<>());
/**
*
*/
private void addAllDescendants(Long nodeId,
Map<Long, List<OrganizationRespVO>> childrenByParentId,
Set<Long> matchedNodeIds) {
if (childrenByParentId == null || childrenByParentId.isEmpty()) {
return;
}
// 构建设备节点(显示所有设备和参数)
List<LineAnalysisTreeDTO.EquipmentNode> equipmentNodes = lineDevices.stream()
.map(device -> {
List<DeviceContactModelDO> deviceParams = paramsByDeviceId.getOrDefault(device.getId(), new ArrayList<>());
// 使用队列进行广度优先遍历
Queue<Long> queue = new LinkedList<>();
queue.offer(nodeId);
List<LineAnalysisTreeDTO.ParameterNode> parameterNodes = deviceParams.stream()
.map(this::buildParameterNode)
.collect(Collectors.toList());
while (!queue.isEmpty()) {
Long currentId = queue.poll();
return LineAnalysisTreeDTO.EquipmentNode.builder()
.id(device.getId())
.name(device.getDeviceName())
.parameters(parameterNodes)
.build();
})
.collect(Collectors.toList());
return LineAnalysisTreeDTO.LineNode.builder()
.id(line.getId())
.name(line.getName())
.parentId(parentId)
.equipments(equipmentNodes)
.build();
}).collect(Collectors.toList());
}
// 有关键词时lines已经包含了匹配的产线及其父级产线
// 但我们仍然需要根据关键词过滤设备和参数
// 记录匹配情况
Map<Long, Boolean> lineMatchedMap = new HashMap<>();
Map<Long, Boolean> deviceMatchedMap = new HashMap<>();
// 第一遍:分析匹配情况
for (OrganizationRespVO line : lines) {
// 产线是否匹配
boolean lineMatch = line.getName() != null &&
line.getName().toLowerCase().contains(lowerKeyword);
lineMatchedMap.put(line.getId(), lineMatch);
// 检查该产线的设备
List<DeviceDO> lineDevices = devicesByLineId.getOrDefault(line.getId(), new ArrayList<>());
for (DeviceDO device : lineDevices) {
// 设备是否匹配
boolean deviceMatch = device.getDeviceName() != null &&
device.getDeviceName().toLowerCase().contains(lowerKeyword);
deviceMatchedMap.put(device.getId(), deviceMatch);
List<OrganizationRespVO> children = childrenByParentId.get(currentId);
if (children != null && !children.isEmpty()) {
for (OrganizationRespVO child : children) {
matchedNodeIds.add(child.getId());
queue.offer(child.getId());
}
}
}
}
// 第二遍:构建树结构
return lines.stream().map(line -> {
boolean lineMatch = lineMatchedMap.getOrDefault(line.getId(), false);
Long parentId = lineParentIdMap.getOrDefault(line.getId(), 0L);
/**
*
*/
private List<LineAnalysisTreeDTO.LineNode> buildOrganizationTreeWithChildren(
List<OrganizationRespVO> topLevelNodes,
Set<Long> matchedNodeIds,
Map<Long, List<OrganizationRespVO>> childrenByParentId,
Map<Long, DeviceDO> deviceMap,
Map<Long, List<DeviceContactModelDO>> paramsByDeviceId,
Map<Long, String> lineOrgClassMap,
String keyword,
List<OrganizationRespVO> allOrganizationRespVOS,
boolean needShowDevices,
boolean hasKeyword) {
// 获取该产线的设备
List<DeviceDO> lineDevices = devicesByLineId.getOrDefault(line.getId(), new ArrayList<>());
// 创建节点映射
Map<Long, LineAnalysisTreeDTO.LineNode> nodeMap = new HashMap<>();
// 构建设备节点
List<LineAnalysisTreeDTO.EquipmentNode> equipmentNodes = lineDevices.stream()
.map(device -> {
boolean deviceMatch = deviceMatchedMap.getOrDefault(device.getId(), false);
List<DeviceContactModelDO> deviceParams = paramsByDeviceId.getOrDefault(device.getId(), new ArrayList<>());
// 创建所有组织节点的映射
Map<Long, OrganizationRespVO> allNodesMap = allOrganizationRespVOS.stream()
.collect(Collectors.toMap(OrganizationRespVO::getId, Function.identity()));
// 如果产线匹配,显示该产线下的所有设备
if (lineMatch) {
List<LineAnalysisTreeDTO.ParameterNode> parameterNodes = deviceParams.stream()
.map(this::buildParameterNode)
.collect(Collectors.toList());
// 获取所有匹配节点的完整列表(包括所有子孙节点)
Set<Long> allMatchedAndDescendantIds = new HashSet<>();
for (Long matchedId : matchedNodeIds) {
allMatchedAndDescendantIds.add(matchedId);
addAllDescendants(matchedId, childrenByParentId, allMatchedAndDescendantIds);
}
return LineAnalysisTreeDTO.EquipmentNode.builder()
.id(device.getId())
.name(device.getDeviceName())
.parameters(parameterNodes)
.build();
}
// 构建所有匹配节点的树节点
for (OrganizationRespVO node : allOrganizationRespVOS) {
if (!allMatchedAndDescendantIds.contains(node.getId())) {
continue;
}
// 如果设备匹配,显示该设备的所有参数
if (deviceMatch) {
List<LineAnalysisTreeDTO.ParameterNode> parameterNodes = deviceParams.stream()
.map(this::buildParameterNode)
.collect(Collectors.toList());
return LineAnalysisTreeDTO.EquipmentNode.builder()
.id(device.getId())
.name(device.getDeviceName())
.parameters(parameterNodes)
.build();
}
// 构建设备节点
List<LineAnalysisTreeDTO.EquipmentNode> equipmentNodes = new ArrayList<>();
if (needShowDevices) {
// 有搜索关键词时获取所有设备,无关键词时只获取当前节点的设备
List<Long> deviceIds = hasKeyword ?
getAllDeviceIdsForNode(node.getId(), childrenByParentId, allNodesMap, allMatchedAndDescendantIds) :
getCurrentDeviceId(node, allNodesMap);
for (Long deviceId : deviceIds) {
DeviceDO device = deviceMap.get(deviceId);
if (device != null) {
// 获取设备参数
List<DeviceContactModelDO> deviceParams = paramsByDeviceId.getOrDefault(device.getId(), new ArrayList<>());
// 检查设备和参数是否匹配关键词
boolean shouldIncludeDevice = false;
List<DeviceContactModelDO> filteredParams = new ArrayList<>();
if (hasKeyword) {
String lowerKeyword = keyword.toLowerCase();
// 检查当前节点是否匹配关键词(组织名称匹配)
boolean isNodeNameMatched = node.getName() != null &&
node.getName().toLowerCase().contains(lowerKeyword);
if (!isNodeNameMatched) {
// 有关键词但不是组织名称匹配的情况
boolean deviceNameMatches = device.getDeviceName() != null &&
device.getDeviceName().toLowerCase().contains(lowerKeyword);
// 检查参数是否匹配
filteredParams = deviceParams.stream()
.filter(param -> param.getAttributeName() != null &&
param.getAttributeName().toLowerCase().contains(lowerKeyword))
.collect(Collectors.toList());
// 检查是否有匹配的参数
boolean hasMatchingParam = deviceParams.stream()
.anyMatch(param -> isParameterMatch(param, lowerKeyword));
boolean hasMatchingParam = !filteredParams.isEmpty();
if (!hasMatchingParam) {
return null;
// 如果设备名称或参数匹配,则包含设备
if (deviceNameMatches || hasMatchingParam) {
shouldIncludeDevice = true;
// 如果设备名称匹配但参数不匹配,包含所有参数
if (deviceNameMatches && filteredParams.isEmpty()) {
filteredParams = new ArrayList<>(deviceParams);
}
}
} else {
// 是组织名称匹配的情况:包含所有设备和参数
shouldIncludeDevice = true;
filteredParams = new ArrayList<>(deviceParams);
}
} else {
// 无关键词的情况:包含所有设备和参数
shouldIncludeDevice = true;
filteredParams = new ArrayList<>(deviceParams);
}
// 只显示匹配的参数
List<LineAnalysisTreeDTO.ParameterNode> parameterNodes = deviceParams.stream()
.filter(param -> isParameterMatch(param, lowerKeyword))
.map(this::buildParameterNode)
.collect(Collectors.toList());
if (shouldIncludeDevice) {
List<LineAnalysisTreeDTO.ParameterNode> paramInfos = filteredParams.stream()
.map(this::convertToSimpleInfo)
.collect(Collectors.toList());
return LineAnalysisTreeDTO.EquipmentNode.builder()
// 检查设备是否已添加(避免重复)
boolean alreadyAdded = equipmentNodes.stream()
.anyMatch(e -> e.getId().equals(device.getId()));
if (!alreadyAdded) {
equipmentNodes.add(LineAnalysisTreeDTO.EquipmentNode.builder()
.id(device.getId())
.name(device.getDeviceName())
.parameters(parameterNodes)
.build();
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
return LineAnalysisTreeDTO.LineNode.builder()
.id(line.getId())
.name(line.getName())
.parentId(parentId)
.equipments(equipmentNodes)
.build();
})
.collect(Collectors.toList());
}
.parameters(paramInfos)
.build());
}
}
}
}
}
// /**
// * 检查产线下是否有匹配的设备或参数
// */
// private boolean checkIfLineHasMatchingDeviceOrParam(OrganizationRespVO line,
// Map<Long, List<DeviceDO>> devicesByLineId,
// Map<Long, List<DeviceContactModelDO>> paramsByDeviceId,
// String lowerKeyword,
// Map<Long, Boolean> deviceMatchedMap) {
//
// List<DeviceDO> lineDevices = devicesByLineId.getOrDefault(line.getId(), new ArrayList<>());
//
// for (DeviceDO device : lineDevices) {
// // 检查设备是否匹配
// boolean deviceMatch = deviceMatchedMap.getOrDefault(device.getId(), false);
// if (deviceMatch) {
// return true;
// }
//
// // 检查设备下的参数是否匹配
// List<DeviceContactModelDO> deviceParams = paramsByDeviceId.getOrDefault(device.getId(), new ArrayList<>());
// boolean hasMatchingParam = deviceParams.stream()
// .anyMatch(param -> isParameterMatch(param, lowerKeyword));
// if (hasMatchingParam) {
// return true;
// }
// }
//
// return false;
// }
//
// /**
// * 检查设备下是否有匹配的参数
// */
// private boolean checkIfDeviceHasMatchingParam(DeviceDO device,
// Map<Long, List<DeviceContactModelDO>> paramsByDeviceId,
// String lowerKeyword) {
//
// List<DeviceContactModelDO> deviceParams = paramsByDeviceId.getOrDefault(device.getId(), new ArrayList<>());
// return deviceParams.stream()
// .anyMatch(param -> isParameterMatch(param, lowerKeyword));
// }
LineAnalysisTreeDTO.LineNode lineNode = LineAnalysisTreeDTO.LineNode.builder()
.id(node.getId())
.name(node.getName())
.orgClass(lineOrgClassMap.getOrDefault(node.getId(), null))
.parentId(node.getParentId())
.equipments(equipmentNodes)
.children(new ArrayList<>())
.build();
nodeMap.put(node.getId(), lineNode);
}
// 构建父子关系
List<LineAnalysisTreeDTO.LineNode> result = new ArrayList<>();
for (LineAnalysisTreeDTO.LineNode lineNode : nodeMap.values()) {
if (lineNode.getParentId() == null || lineNode.getParentId() == 0L) {
// 根节点
result.add(lineNode);
} else {
// 查找父节点
LineAnalysisTreeDTO.LineNode parentNode = nodeMap.get(lineNode.getParentId());
if (parentNode != null) {
parentNode.getChildren().add(lineNode);
} else {
// 父节点不在当前构建的节点中,但当前节点是匹配的
// 这种情况下,当前节点应该作为根节点展示
result.add(lineNode);
}
}
}
// 过滤:只保留顶层节点
List<LineAnalysisTreeDTO.LineNode> filteredResult = new ArrayList<>();
Set<Long> topLevelNodeIds = topLevelNodes.stream()
.map(OrganizationRespVO::getId)
.collect(Collectors.toSet());
for (LineAnalysisTreeDTO.LineNode node : result) {
if (topLevelNodeIds.contains(node.getId())) {
filteredResult.add(node);
} else if (node.getParentId() == null || node.getParentId() == 0L) {
// 或者是没有父节点的根节点
filteredResult.add(node);
}
}
return filteredResult;
}
/**
*
* ID
*/
private boolean isParameterMatch(DeviceContactModelDO param, String lowerKeyword) {
if (StringUtils.isBlank(lowerKeyword)) {
return true;
private List<Long> getCurrentDeviceId(OrganizationRespVO node, Map<Long, OrganizationRespVO> allNodesMap) {
List<Long> deviceIds = new ArrayList<>();
// 获取当前节点
OrganizationRespVO currentNode = allNodesMap.get(node.getId());
if (currentNode != null && currentNode.getMachineId() != null) {
deviceIds.add(currentNode.getMachineId());
}
return (param.getAttributeName() != null && param.getAttributeName().toLowerCase().contains(lowerKeyword));
return deviceIds;
}
/**
* ID
*/
private List<Long> getAllDeviceIdsForNode(Long nodeId,
Map<Long, List<OrganizationRespVO>> childrenByParentId,
Map<Long, OrganizationRespVO> allNodesMap,
Set<Long> matchedNodeIds) {
Set<Long> deviceIds = new HashSet<>();
// 先检查当前节点是否有设备
OrganizationRespVO currentNode = allNodesMap.get(nodeId);
if (currentNode != null && currentNode.getMachineId() != null) {
deviceIds.add(currentNode.getMachineId());
}
// 使用队列迭代获取所有子孙节点
Queue<Long> queue = new LinkedList<>();
queue.offer(nodeId);
while (!queue.isEmpty()) {
Long currentId = queue.poll();
// 获取当前节点的子节点
List<OrganizationRespVO> children = childrenByParentId.get(currentId);
if (children != null) {
for (OrganizationRespVO child : children) {
if (matchedNodeIds.contains(child.getId())) {
// 如果子节点有设备,添加到设备列表
if (child.getMachineId() != null) {
deviceIds.add(child.getMachineId());
}
// 继续处理子节点的子节点
queue.offer(child.getId());
}
}
}
}
return new ArrayList<>(deviceIds);
}
/**
*
*
*/
private LineAnalysisTreeDTO.ParameterNode buildParameterNode(DeviceContactModelDO param) {
private LineAnalysisTreeDTO.ParameterNode convertToSimpleInfo(DeviceContactModelDO param) {
return LineAnalysisTreeDTO.ParameterNode.builder()
.id(param.getId())
.name(param.getAttributeName())
@ -636,29 +667,4 @@ public class OrganizationServiceImpl implements OrganizationService {
.build();
}
private List<DeviceContactModelDO> getAllParameters(List<DeviceDO> devices) {
if (devices.isEmpty()) {
return Collections.emptyList();
}
List<Long> deviceIds = devices.stream()
.map(DeviceDO::getId)
.collect(Collectors.toList());
LambdaQueryWrapper<DeviceContactModelDO> wrapper = new LambdaQueryWrapper<>();
wrapper.in(DeviceContactModelDO::getDeviceId, deviceIds)
.orderByAsc(DeviceContactModelDO::getSort); // 按排序字段排序
List<DeviceContactModelDO> result = deviceContactModelMapper.selectList(wrapper);
// 调试日志
System.out.println("查询条件: 设备IDs=" + deviceIds);
System.out.println("查询结果数量: " + result.size());
return result;
}
}

@ -109,7 +109,9 @@ public class TaskManagementServiceImpl implements TaskManagementService {
PageResult<TaskManagementDO> taskManagementDOPageResult = taskManagementMapper.selectPage(pageReqVO);
for (TaskManagementDO taskManagementDO : taskManagementDOPageResult.getList()) {
PlanMaintenanceDO planMaintenanceDO = planMaintenanceMapper.selectById(taskManagementDO.getProjectForm());
taskManagementDO.setProjectFormName(planMaintenanceDO.getPlanName());
if (planMaintenanceDO !=null) {
taskManagementDO.setProjectFormName(planMaintenanceDO.getPlanName());
}
}

Loading…
Cancel
Save