fix:修复已知问题

liutao_branch
HuangHuiKang 3 weeks ago
parent f301c25ab9
commit 5778e72827

@ -121,7 +121,7 @@ public class DeviceController {
ExcelUtils.write(response, "物联设备.xls", "数据", DeviceRespVO.class,list); ExcelUtils.write(response, "物联设备.xls", "数据", DeviceRespVO.class,list);
} }
@GetMapping("/deviceList") @GetMapping("/deviceList")
@PreAuthorize("@ss.hasPermission('iot:device:query')") // @PreAuthorize("@ss.hasPermission('iot:device:query')")
public CommonResult<List<DeviceRespVO>> deviceList(@Valid DevicePageReqVO pageReqVO) { public CommonResult<List<DeviceRespVO>> deviceList(@Valid DevicePageReqVO pageReqVO) {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<DeviceRespVO> list = deviceService.getDevicePage(pageReqVO).getList(); List<DeviceRespVO> list = deviceService.getDevicePage(pageReqVO).getList();
@ -199,17 +199,20 @@ public class DeviceController {
@ApiAccessLog(operateType = EXPORT) @ApiAccessLog(operateType = EXPORT)
public void exportLineDevice(@Valid LineDeviceRequestVO pageReqVO, public void exportLineDevice(@Valid LineDeviceRequestVO pageReqVO,
HttpServletResponse response) throws IOException { HttpServletResponse response) throws IOException {
List<LineDeviceRespVO> lineDeviceList = deviceService.lineDeviceList(pageReqVO); pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
PageResult<LineDeviceRespVO> lineDeviceRespVOPageResult = deviceService.lineDevicePage(pageReqVO);
// 设置响应头 // 设置响应头
response.setContentType("application/vnd.ms-excel;charset=UTF-8"); // response.setContentType("application/vnd.ms-excel;charset=UTF-8");
response.setHeader("Content-Disposition", // response.setHeader("Content-Disposition",
"attachment;filename=" + URLEncoder.encode("设备运行报表记录.xls", "UTF-8")); // "attachment;filename=" + URLEncoder.encode("设备运行报表记录.xls", "UTF-8"));
response.setHeader("Content-Encoding", "identity"); // response.setHeader("Content-Encoding", "identity");
// 导出Excel // 导出Excel
String fileName = String.format("数据实时监控_%s.xls", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); String fileName = String.format("数据实时监控_%s.xls", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
// 导出 Excel // 导出 Excel
ExcelUtils.write(response, fileName, "数据", LineDeviceRespVO.class,lineDeviceList); ExcelUtils.write(response, fileName, "数据", LineDeviceRespVO.class,lineDeviceRespVOPageResult.getList());
} }
@ -238,7 +241,7 @@ public class DeviceController {
@GetMapping("/getDeviceOperationalStatus") @GetMapping("/getDeviceOperationalStatus")
@Operation(summary = "获取首页设备运行状态") @Operation(summary = "获取首页设备运行状态")
@PreAuthorize("@ss.hasPermission('iot:device:query')") // @PreAuthorize("@ss.hasPermission('iot:device:query')")
@Parameter(name = "orgId", description = "产线组织Id") @Parameter(name = "orgId", description = "产线组织Id")
public CommonResult<DeviceOperationStatusRespVO> getDeviceOperationalStatus(@RequestParam(name = "orgId",required = false) Long orgId) throws JsonProcessingException { public CommonResult<DeviceOperationStatusRespVO> getDeviceOperationalStatus(@RequestParam(name = "orgId",required = false) Long orgId) throws JsonProcessingException {
DeviceOperationStatusRespVO deviceOperationalStatus=deviceService.getDeviceOperationalStatus(); DeviceOperationStatusRespVO deviceOperationalStatus=deviceService.getDeviceOperationalStatus();

@ -0,0 +1,13 @@
package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
import lombok.Data;
@Data
public class LineCodeAndNameRespVO {
private Long deviceId;
private String lineCode;
private String lineName;
}

@ -39,7 +39,7 @@ public class LineDeviceRespVO {
private String deviceName; private String deviceName;
@Schema(description = "状态 1-在线 2-离线") @Schema(description = "状态 1-在线 2-离线")
@ExcelProperty(value = "连接状态", converter = DictConvert.class) // @ExcelProperty(value = "连接状态", converter = DictConvert.class)
@DictFormat("iot_gateway_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 @DictFormat("iot_gateway_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
private String status; private String status;

@ -22,22 +22,30 @@ public class DeviceTotalTimeRecordRespVO {
@ExcelProperty("设备名称") @ExcelProperty("设备名称")
private String deviceName; private String deviceName;
@Schema(description = "运行时间(小时)") @Schema(description = "离线时间(小时)")
@ExcelProperty("运行时间(小时)") // @ExcelProperty("离线时间(s)")
private double totalOfflineTime;
@Schema(description = "运行时间(s)")
@ExcelProperty("运行时间(s)")
private double totalRunningTime; private double totalRunningTime;
@Schema(description = "待机时间(小时)") @Schema(description = "待机时间(s)")
@ExcelProperty("待机时间(小时)") @ExcelProperty("待机时间(s)")
private double totalStandbyTime; private double totalStandbyTime;
@Schema(description = "故障时间(小时)") @Schema(description = "故障时间(s)")
@ExcelProperty("故障时间(小时)") @ExcelProperty("故障时间(s)")
private double totalFaultTime; private double totalFaultTime;
@Schema(description = "警告时间(小时)") @Schema(description = "警告时间(s)")
@ExcelProperty("警告时间(小时)") // @ExcelProperty("警告时间(s)")
private double totalWarningTime; private double totalWarningTime;
@Schema(description = "开机率")
@ExcelProperty("开机率")
private String powerOnRate;
@Schema(description = "稼动率") @Schema(description = "稼动率")
@ExcelProperty("稼动率") @ExcelProperty("稼动率")
private String utilizationRate; private String utilizationRate;

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.device; package cn.iocoder.yudao.module.iot.dal.dataobject.device;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*; import lombok.*;
import java.util.*; import java.util.*;
import java.time.LocalDateTime; import java.time.LocalDateTime;

@ -4,15 +4,11 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.DeviceOperationStatusRespVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.DevicePageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.LineDeviceRequestVO;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.LineDeviceRespVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO;
import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
@ -47,7 +43,7 @@ public interface DeviceMapper extends BaseMapperX<DeviceDO> {
.eqIfPresent(DeviceDO::getRemark, reqVO.getRemark()) .eqIfPresent(DeviceDO::getRemark, reqVO.getRemark())
.eqIfPresent(DeviceDO::getIsEnable, reqVO.getIsEnable()) .eqIfPresent(DeviceDO::getIsEnable, reqVO.getIsEnable())
.betweenIfPresent(DeviceDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(DeviceDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(DeviceDO::getCreateTime); .orderByDesc(DeviceDO::getId);
// 单独处理 ids 条件 // 单独处理 ids 条件
if (StringUtils.isNotBlank(reqVO.getIds())) { if (StringUtils.isNotBlank(reqVO.getIds())) {
@ -122,4 +118,9 @@ public interface DeviceMapper extends BaseMapperX<DeviceDO> {
*/ */
@Select("SELECT device_ids FROM mes_goview WHERE id = #{goviewId}") @Select("SELECT device_ids FROM mes_goview WHERE id = #{goviewId}")
String selectDeviceIdsByGoviewId(@Param("goviewId") Long goviewId); String selectDeviceIdsByGoviewId(@Param("goviewId") Long goviewId);
List<LineCodeAndNameRespVO> selectLineBatch(@Param("deviceIds") List<Long> deviceIds);
List<Long> selectDeviceIdsByLine(@Param("lineNode") String lineNode, @Param("lineName") String lineName);
} }

@ -204,7 +204,6 @@ public class MqttDataHandler extends SuperConsumer<String> {
} }
} }
public void processDeviceDataFromMqtt(DeviceDO device, public void processDeviceDataFromMqtt(DeviceDO device,
Map<String, Object> varListMap) { Map<String, Object> varListMap) {
@ -217,15 +216,15 @@ public class MqttDataHandler extends SuperConsumer<String> {
log.warn("设备 {} 未配置点位", device.getId()); log.warn("设备 {} 未配置点位", device.getId());
DeviceOperationRecordDO record = new DeviceOperationRecordDO(); // DeviceOperationRecordDO record = new DeviceOperationRecordDO();
record.setDeviceId(deviceId); // record.setDeviceId(deviceId);
record.setRule(DeviceStatusEnum.STANDBY.getCode()); // record.setRule(DeviceStatusEnum.STANDBY.getCode());
//TODO 待优化 // //TODO 待优化
record.setTotalStandbyTime(device.getSampleCycle()); // record.setTotalStandbyTime(device.getSampleCycle());
record.setCreator("1"); // record.setCreator("1");
record.setUpdater("1"); // record.setUpdater("1");
//
deviceOperationRecordMapper.insert(record); // deviceOperationRecordMapper.insert(record);
return; return;
} }
@ -236,22 +235,22 @@ public class MqttDataHandler extends SuperConsumer<String> {
return; return;
} }
// 查询RUNNING点位规则 // TODO 迁移定时任务存储RUNNING点位规则
DevicePointRulesDO devicePoints = getDevicePointRules(deviceId); // DevicePointRulesDO devicePoints = getDevicePointRules(deviceId);
if (StringUtils.isBlank(devicePoints.getFieldRule())){ // if (StringUtils.isBlank(devicePoints.getFieldRule())){
log.warn("设备 {} 没有RUNNING点位规则", device.getId()); // log.warn("设备 {} 没有RUNNING点位规则", device.getId());
//
DeviceOperationRecordDO record = new DeviceOperationRecordDO(); // DeviceOperationRecordDO record = new DeviceOperationRecordDO();
record.setDeviceId(deviceId); // record.setDeviceId(deviceId);
record.setRule(DeviceStatusEnum.STANDBY.getCode()); // record.setRule(DeviceStatusEnum.STANDBY.getCode());
//TODO 待优化 // //TODO 待优化
record.setTotalStandbyTime(device.getSampleCycle()); // record.setTotalStandbyTime(device.getSampleCycle());
record.setCreator("1"); // record.setCreator("1");
record.setUpdater("1"); // record.setUpdater("1");
//
deviceOperationRecordMapper.insert(record); // deviceOperationRecordMapper.insert(record);
//
} // }
@ -484,21 +483,22 @@ public class MqttDataHandler extends SuperConsumer<String> {
//分别处理运行记录和告警记录 //分别处理运行记录和告警记录
if (StringUtils.isBlank(devicePointRulesDO.getAlarmLevel())) { if (StringUtils.isBlank(devicePointRulesDO.getAlarmLevel())) {
DeviceOperationRecordDO record = new DeviceOperationRecordDO(); //TODO 迁移运行记录到定时任务
record.setDeviceId(device.getId()); // DeviceOperationRecordDO record = new DeviceOperationRecordDO();
record.setModelId(modelId); // record.setDeviceId(device.getId());
record.setRule(pointRulesRespVO.getRule()); // record.setModelId(modelId);
record.setAddressValue(processedValue); // record.setRule(pointRulesRespVO.getRule());
record.setRecordType(getRecordType(devicePointRulesDO)); // record.setAddressValue(processedValue);
record.setRuleId(devicePointRulesDO.getId()); // record.setRecordType(getRecordType(devicePointRulesDO));
//TODO 创建人和更新人为内置默认管理员 // record.setRuleId(devicePointRulesDO.getId());
record.setCreator("1"); // //TODO 创建人和更新人为内置默认管理员
record.setUpdater("1"); // record.setCreator("1");
// record.setUpdater("1");
// 处理累计时间 //
calculateAndSetTotalTime(record, pointRulesRespVO.getRule(), device.getSampleCycle()); // // 处理累计时间
// calculateAndSetTotalTime(record, pointRulesRespVO.getRule(), device.getSampleCycle());
deviceOperationRecordMapper.insert(record); //
// deviceOperationRecordMapper.insert(record);
} else { } else {
DeviceWarinningRecordDO deviceWarinningRecordDO = new DeviceWarinningRecordDO(); DeviceWarinningRecordDO deviceWarinningRecordDO = new DeviceWarinningRecordDO();

@ -1,17 +1,35 @@
package cn.iocoder.yudao.module.iot.job; package cn.iocoder.yudao.module.iot.job;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.iot.controller.admin.device.enums.DeviceStatusEnum;
import cn.iocoder.yudao.module.iot.controller.admin.devicemodelrules.vo.PointRulesRespVO;
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.dataobject.deviceoperationrecord.DeviceOperationRecordDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicepointrules.DevicePointRulesDO;
import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceMapper; 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.iot.dal.mysql.devicecontactmodel.DeviceContactModelMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.deviceoperationrecord.DeviceOperationRecordMapper;
import cn.iocoder.yudao.module.iot.dal.mysql.devicepointrules.DevicePointRulesMapper;
import cn.iocoder.yudao.module.iot.service.device.TDengineService; import cn.iocoder.yudao.module.iot.service.device.TDengineService;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Date; import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -28,35 +46,354 @@ public class DeviceJob implements JobHandler {
@Resource @Resource
private DeviceContactModelMapper deviceContactModelMapper; private DeviceContactModelMapper deviceContactModelMapper;
@Resource
private DeviceOperationRecordMapper deviceOperationRecordMapper;
@Resource
private DevicePointRulesMapper devicePointRulesMapper;
@Override @Override
public String execute(String param) throws Exception { public String execute(String param) throws Exception {
// 设置租户上下文
TenantContextHolder.setTenantId(1L);
// 解析超时时间默认60秒
long timeoutSeconds = 60L;
if (StringUtils.isNotBlank(param)) {
try {
timeoutSeconds = Long.parseLong(param);
} catch (NumberFormatException e) {
log.warn("定时任务参数非法使用默认60秒 param={}", param);
}
}
log.info("定时任务开始, timeoutSeconds={} 时间={}", timeoutSeconds, new Date());
// 查询采集设备列表
List<DeviceDO> deviceDOS =
deviceMapper.selectList(Wrappers.<DeviceDO>lambdaQuery().in(DeviceDO::getId, Arrays.asList(142L, 140L) ).orderByDesc(DeviceDO::getId));
if (CollectionUtils.isEmpty(deviceDOS)) {
return param;
}
List<Long> deviceIds = deviceDOS.stream()
.map(DeviceDO::getId)
.collect(Collectors.toList());
// 获取设备的每条最新数据
Map<Long, Map<String, Object>> deviceRowMap =
tDengineService.queryDevicesLatestRow(deviceIds, null, null);
Instant now = Instant.now();
// 遍历设备
for (Long deviceId : deviceIds) {
Map<String, Object> row = deviceRowMap.get(deviceId);
boolean isTimeout = false;
if (row == null || row.get("ts") == null) {
isTimeout = true;
} else {
Instant ts = parseTs(row.get("ts"), deviceId);
if (ts == null || Duration.between(ts, now).getSeconds() > timeoutSeconds) {
isTimeout = true;
}
}
if (isTimeout) {
handleDeviceTimeout(deviceId);
} else {
handleDeviceOnline(deviceId, row);
}
}
return param;
}
// 解析JSON字符串获取deviceId /**
JSONObject jsonParam = JSON.parseObject(param); * ts Instant
System.out.println(jsonParam + new Date().toString()); */
// Long deviceId = jsonParam.getLong("deviceId"); private Instant parseTs(Object tsObj, Long deviceId) {
// log.info("定时任务执行,接收到的参数 param: {}", param); if (tsObj == null) return null;
// if (deviceId == null){
// throw exception(DEVICE_DOES_NOT_EXIST); log.debug("设备 {} tsObj 类型: {}, 值: {}", deviceId, tsObj.getClass().getName(), tsObj);
// }
if (tsObj instanceof Instant) {
// // 设置租户上下文 return (Instant) tsObj;
// TenantContextHolder.setTenantId(1L); } else if (tsObj instanceof Timestamp) {
// return ((Timestamp) tsObj).toInstant();
// LambdaQueryWrapper<DeviceContactModelDO> deviceModelAttributeLambdaQueryWrapper = new LambdaQueryWrapper<>(); } else if (tsObj instanceof Date) {
// deviceModelAttributeLambdaQueryWrapper.eq(DeviceContactModelDO::getDeviceId,deviceId); return ((Date) tsObj).toInstant();
// List<DeviceContactModelDO> deviceContactModelDOS = deviceContactModelMapper.selectList(deviceModelAttributeLambdaQueryWrapper); } else if (tsObj instanceof LocalDateTime) {
// return ((LocalDateTime) tsObj).atZone(ZoneId.systemDefault()).toInstant();
// if (deviceContactModelDOS != null && deviceContactModelDOS.size() > 0){ } else if (tsObj instanceof String) {
// for (DeviceContactModelDO deviceContactModelDO : deviceContactModelDOS) { String tsStr = (String) tsObj;
// Object addressValue = OpcUtils.readValue(deviceContactModelDO.getAddress() != null ? deviceContactModelDO.getAddress() : ""); try {
// deviceContactModelDO.setAddressValue(addressValue); return Instant.parse(tsStr); // ISO 8601
// } } catch (Exception e1) {
// try {
// } return Timestamp.valueOf(tsStr).toInstant(); // yyyy-MM-dd HH:mm:ss
// String json = JSON.toJSONString(deviceContactModelDOS); } catch (Exception e2) {
// tDengineService.insertDeviceData(deviceId,json); log.warn("设备 {} ts 字符串解析失败: {}", deviceId, tsStr);
}
return ""; }
} else {
log.warn("设备 {} ts 类型未知: {}", deviceId, tsObj);
}
return null;
}
/**
* 线
*/
private void handleDeviceOnline(Long deviceId, Map<String, Object> row) {
if (row == null) return;
// 1. 查询设备规则
DevicePointRulesDO pointRulesDO = devicePointRulesMapper.selectOne(
Wrappers.<DevicePointRulesDO>lambdaQuery()
.eq(DevicePointRulesDO::getDeviceId, deviceId)
.eq(DevicePointRulesDO::getIdentifier, "RUNNING")
.orderByDesc(DevicePointRulesDO::getId)
.last("LIMIT 1")
);
if (pointRulesDO == null || StringUtils.isBlank(pointRulesDO.getFieldRule())) return;
// 解析规则列表
List<PointRulesRespVO> pointRulesVOList = JSON.parseArray(
pointRulesDO.getFieldRule(), PointRulesRespVO.class
);
if (CollectionUtils.isEmpty(pointRulesVOList)) return;
// 2. 查询设备 contact model
List<DeviceContactModelDO> deviceContactModelDOS = deviceContactModelMapper.selectList(
Wrappers.<DeviceContactModelDO>lambdaQuery().eq(DeviceContactModelDO::getDeviceId, deviceId)
);
if (CollectionUtils.isEmpty(deviceContactModelDOS)) return;
// 3. 遍历规则,匹配成功则保存记录
for (PointRulesRespVO pointRule : pointRulesVOList) {
if (StringUtils.isBlank(pointRule.getCode())) continue;
String ruleCode = pointRule.getCode().toLowerCase();
String processedValue = row.get(ruleCode).toString();
boolean matched = matchRule(processedValue, pointRule);
if (!matched) {
log.debug("规则匹配失败: device={}, value={}, rule={}", deviceId, processedValue, JSON.toJSONString(pointRule));
continue;
}
log.info("规则匹配成功: device={}, value={}, rule={}", deviceId, processedValue, JSON.toJSONString(pointRule));
// 4. 遍历 contact model 查找对应 code
DeviceContactModelDO matchedContact = null;
for (DeviceContactModelDO contact : deviceContactModelDOS) {
if (ruleCode.equalsIgnoreCase(contact.getAttributeCode())) {
matchedContact = contact;
break;
}
}
if (matchedContact == null) {
log.warn("设备 {} 找不到 attributeCode={} 对应的 modelId跳过", deviceId, pointRule.getCode());
continue;
}
// 5. 保存运行记录
DeviceOperationRecordDO record = new DeviceOperationRecordDO();
record.setDeviceId(deviceId);
record.setModelId(matchedContact.getId());
record.setRule(pointRule.getRule());
record.setAddressValue(processedValue);
record.setRuleId(pointRulesDO.getId());
record.setCreator("1");
record.setUpdater("1");
deviceOperationRecordMapper.insert(record);
break;
}
}
private void handleDeviceTimeout(Long deviceId) {
DeviceOperationRecordDO record = new DeviceOperationRecordDO();
record.setDeviceId(deviceId);
record.setRule(DeviceStatusEnum.OFFLINE.getCode());
record.setCreator("1");
record.setUpdater("1");
deviceOperationRecordMapper.insert(record);
}
/**
*
* : EQ(), NE(), GT(), GE(),
* LT(), LE(), TRUE(), FALSE()
*/
private boolean matchRule(String value, PointRulesRespVO rule) {
if (StringUtils.isBlank(value) || rule == null ||
StringUtils.isBlank(rule.getOperator())) {
return false;
}
try {
String operator = rule.getOperator().toUpperCase();
String inputValue = value.trim().toLowerCase();
String ruleValue = StringUtils.trimToEmpty(rule.getOperatorRule());
// 1. 处理布尔值判断
if ("TRUE".equals(operator) || "FALSE".equals(operator)) {
return matchBooleanRule(inputValue, operator);
}
// 2. 如果operatorRule为空且不是布尔操作符则返回false
if (StringUtils.isBlank(ruleValue)) {
log.warn("规则比较值为空,但操作符不是布尔类型: operator={}", operator);
return false;
}
ruleValue = ruleValue.trim();
// 3. 尝试数值比较
if (isNumeric(inputValue) && isNumeric(ruleValue)) {
Double num1 = Double.parseDouble(inputValue);
Double num2 = Double.parseDouble(ruleValue);
return compareNumbers(num1, num2, operator);
}
// 4. 字符串比较
else {
return compareStrings(inputValue, ruleValue, operator);
}
} catch (Exception e) {
log.error("规则匹配异常: value={}, rule={}, error={}",
value, JSON.toJSONString(rule), e.getMessage());
return false;
}
}
/**
*
*/
private boolean compareStrings(String value, String ruleValue, String operator) {
switch (operator) {
case "EQ":
return value.equals(ruleValue);
case "NE":
return !value.equals(ruleValue);
case "GT":
return value.compareTo(ruleValue) > 0;
case "GE":
return value.compareTo(ruleValue) >= 0;
case "LT":
return value.compareTo(ruleValue) < 0;
case "LE":
return value.compareTo(ruleValue) <= 0;
default:
log.warn("不支持的操作符: {}", operator);
return false;
}
}
/**
*
*/
private boolean compareNumbers(Double value, Double ruleValue, String operator) {
switch (operator) {
case "EQ":
return Math.abs(value - ruleValue) < 0.000001; // 处理浮点数精度
case "NE":
return Math.abs(value - ruleValue) >= 0.000001;
case "GT":
return value > ruleValue;
case "GE":
return value >= ruleValue;
case "LT":
return value < ruleValue;
case "LE":
return value <= ruleValue;
default:
log.warn("不支持的操作符: {}", operator);
return false;
}
}
/**
*
*/
private boolean isNumeric(String str) {
if (StringUtils.isBlank(str)) {
return false;
}
try {
Double.parseDouble(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
/**
*
*/
private boolean matchBooleanRule(String value, String operator) {
// 常见布尔值表示
boolean booleanValue = parseBoolean(value);
if ("TRUE".equals(operator)) {
return booleanValue;
} else if ("FALSE".equals(operator)) {
return !booleanValue;
}
return false;
}
/**
*
* : true, false, 1, 0, yes, no, on, off
*/
private boolean parseBoolean(String value) {
if (StringUtils.isBlank(value)) {
return false;
}
String lowerValue = value.toLowerCase();
// 常见真值表示
if ("true".equals(lowerValue) ||
"1".equals(lowerValue) ||
"yes".equals(lowerValue) ||
"on".equals(lowerValue) ||
"是".equals(lowerValue) || // 中文支持
"成功".equals(lowerValue)) {
return true;
}
// 常见假值表示
if ("false".equals(lowerValue) ||
"0".equals(lowerValue) ||
"no".equals(lowerValue) ||
"off".equals(lowerValue) ||
"否".equals(lowerValue) || // 中文支持
"失败".equals(lowerValue)) {
return false;
}
// 尝试转换为布尔值
try {
return Boolean.parseBoolean(lowerValue);
} catch (Exception e) {
log.warn("无法解析为布尔值: {}", value);
return false;
}
} }
} }

@ -37,15 +37,11 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceAttributeDO;
import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceAttributeMapper; import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceAttributeMapper;
import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.IMqttservice; import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.IMqttservice;
import cn.iocoder.yudao.module.iot.service.gateway.GatewayService;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; 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.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -58,7 +54,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -728,6 +723,25 @@ public class DeviceServiceImpl implements DeviceService {
public PageResult<LineDeviceRespVO> lineDevicePage(LineDeviceRequestVO pageReqVO) { public PageResult<LineDeviceRespVO> lineDevicePage(LineDeviceRequestVO pageReqVO) {
// 1. 查询分页设备 // 1. 查询分页设备
// 如果有产线过滤条件
if (StringUtils.isNotBlank(pageReqVO.getLineNode())
|| StringUtils.isNotBlank(pageReqVO.getLineName())) {
List<Long> filteredDeviceIds =
deviceMapper.selectDeviceIdsByLine(
pageReqVO.getLineNode(),
pageReqVO.getLineName()
);
if (filteredDeviceIds.isEmpty()) {
return PageResult.empty();
}
// 把过滤后的 deviceIds 传给分页条件
pageReqVO.setIds( filteredDeviceIds.stream()
.map(String::valueOf)
.collect(Collectors.joining(",")));
}
PageResult<DeviceRespVO> pageResult = PageResult<DeviceRespVO> pageResult =
getDevicePage(BeanUtils.toBean(pageReqVO, DevicePageReqVO.class)); getDevicePage(BeanUtils.toBean(pageReqVO, DevicePageReqVO.class));
@ -748,6 +762,17 @@ public class DeviceServiceImpl implements DeviceService {
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(Collectors.toList()); .collect(Collectors.toList());
List<LineCodeAndNameRespVO> lineList =
deviceMapper.selectLineBatch(deviceIds);
Map<Long, LineCodeAndNameRespVO> lineMap =
lineList.stream()
.collect(Collectors.toMap(
LineCodeAndNameRespVO::getDeviceId,
Function.identity(),
(a, b) -> a
));
// // 批量查 workshop // // 批量查 workshop
// List<Map<String,Object>> mapList = deviceMapper.selectWorkshopBatch(deviceIds); // List<Map<String,Object>> mapList = deviceMapper.selectWorkshopBatch(deviceIds);
// //
@ -795,9 +820,12 @@ public class DeviceServiceImpl implements DeviceService {
} }
// 查询产线名称 // 查询产线名称
vo.setLineName( LineCodeAndNameRespVO line = lineMap.get(device.getId());
deviceMapper.lineDeviceLedgerPage(device.getId())
); if (line != null) {
vo.setLineName(line.getLineName());
vo.setLineNode(line.getLineCode());
}
// vo.setLineName(workshopMap.get(device.getId())); // vo.setLineName(workshopMap.get(device.getId()));
@ -1535,7 +1563,7 @@ public class DeviceServiceImpl implements DeviceService {
log.info("gateway订阅记录已禁用 topic={}", topic); log.info("gateway订阅记录已禁用 topic={}", topic);
//更新设备运行状态为离线 //更新设备运行状态为离线
updateOperationalStatus(deviceDO); // updateOperationalStatus(deviceDO);
log.info("更新设备运行状态为离线 deviceId={}", deviceDO.getId()); log.info("更新设备运行状态为离线 deviceId={}", deviceDO.getId());

@ -25,6 +25,7 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -1193,7 +1194,13 @@ public class TDengineService {
} }
/**
*
* @param deviceIds
* @param startTime
* @param endTime
* @return
*/
@DS("tdengine") @DS("tdengine")
public Map<Long, Map<String, Object>> queryDevicesLatestRow( public Map<Long, Map<String, Object>> queryDevicesLatestRow(
List<Long> deviceIds, List<Long> deviceIds,
@ -1251,6 +1258,49 @@ public class TDengineService {
return result; return result;
} }
/**
* ts
* @param deviceIds
* @return
*/
@DS("tdengine")
public Map<Long, Instant> queryDevicesLatestTs(List<Long> deviceIds) {
if (CollectionUtils.isEmpty(deviceIds)) {
return Collections.emptyMap();
}
Map<Long, Instant> result = new HashMap<>();
for (Long deviceId : deviceIds) {
String sql = "SELECT LAST(ts) AS ts FROM besure_server.d_" + deviceId;
try {
List<Map<String, Object>> list =
jdbcTemplate.queryForList(sql);
if (!list.isEmpty() && list.get(0).get("ts") != null) {
Timestamp ts = (Timestamp) list.get(0).get("ts");
result.put(deviceId, ts.toInstant());
}
} catch (Exception e) {
log.error("查询设备最新时间失败 deviceId={}", deviceId, e);
}
}
return result;
}
@DS("tdengine") @DS("tdengine")
public Map<Long, Map<String, Object>> queryDevicesEarliestRow( public Map<Long, Map<String, Object>> queryDevicesEarliestRow(
List<Long> deviceIds, List<Long> deviceIds,

@ -10,6 +10,9 @@ import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import cn.iocoder.yudao.module.iot.controller.admin.deviceoperationrecord.vo.*; import cn.iocoder.yudao.module.iot.controller.admin.deviceoperationrecord.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.deviceoperationrecord.DeviceOperationRecordDO; import cn.iocoder.yudao.module.iot.dal.dataobject.deviceoperationrecord.DeviceOperationRecordDO;
@ -92,49 +95,80 @@ public class DeviceOperationRecordServiceImpl implements DeviceOperationRecordSe
} }
private void calculateAndSetConvertedValues(List<DeviceTotalTimeRecordRespVO> records,DeviceTotalTimeRecordReqVO deviceTotalTimeRecordReqVO) { private void calculateAndSetConvertedValues(
List<DeviceTotalTimeRecordRespVO> records,
DeviceTotalTimeRecordReqVO reqVO) {
for (DeviceTotalTimeRecordRespVO record : records) { for (DeviceTotalTimeRecordRespVO record : records) {
try { try {
//添加时间字段
if (StringUtils.isNotBlank(deviceTotalTimeRecordReqVO.getStartTime())){ // 1设置查询时间
record.setStartTime(deviceTotalTimeRecordReqVO.getStartTime()); String startTimeStr = reqVO.getStartTime();
String endTimeStr = reqVO.getEndTime();
if (StringUtils.isNotBlank(startTimeStr)) {
record.setStartTime(startTimeStr);
} }
if (StringUtils.isNotBlank(deviceTotalTimeRecordReqVO.getEndTime())){ if (StringUtils.isNotBlank(endTimeStr)) {
record.setEndTime(deviceTotalTimeRecordReqVO.getEndTime()); record.setEndTime(endTimeStr);
} }
// 获取原始秒数 // 获取原始秒数
double runningTimeSec = record.getTotalRunningTime(); double offlineSec = record.getTotalOfflineTime();
double standbyTimeSec = record.getTotalStandbyTime(); double runningSec = record.getTotalRunningTime();
double faultTimeSec = record.getTotalFaultTime(); double standbySec = record.getTotalStandbyTime();
double warningTimeSec = record.getTotalWarningTime(); double faultSec = record.getTotalFaultTime();
// 1. 转换为小时 // 在线时间 = 运行 + 待机 + 故障
double runningHours = TimeConverterUtil.secondsToHours(runningTimeSec, 2); double onlineSec = runningSec + standbySec + faultSec;
double standbyHours = TimeConverterUtil.secondsToHours(standbyTimeSec, 2);
double faultHours = TimeConverterUtil.secondsToHours(faultTimeSec, 2); // 计算总时间(根据筛选时间)
double warningHours = TimeConverterUtil.secondsToHours(warningTimeSec, 2); double totalSec = 0;
if (StringUtils.isNotBlank(startTimeStr) && StringUtils.isNotBlank(endTimeStr)) {
// 2. 计算稼动率
double utilizationRate = TimeConverterUtil.calculateUtilizationRate( DateTimeFormatter formatter =
runningTimeSec, standbyTimeSec, faultTimeSec, warningTimeSec DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
);
LocalDateTime start = LocalDateTime.parse(startTimeStr, formatter);
// 3. 设置转换后的值(将原来的秒数值覆盖为小时值) LocalDateTime end = LocalDateTime.parse(endTimeStr, formatter);
record.setTotalRunningTime(runningHours);
record.setTotalStandbyTime(standbyHours); totalSec = Duration.between(start, end).getSeconds();
record.setTotalFaultTime(faultHours); }
record.setTotalWarningTime(warningHours);
// 防止负数或异常
if (totalSec < 0) {
totalSec = 0;
}
// 计算开机率
double powerOnRate = 0;
if (totalSec > 0) {
powerOnRate = onlineSec / totalSec;
}
// 计算稼动率
double utilizationRate = 0;
if (onlineSec > 0) {
utilizationRate = runningSec / onlineSec;
}
// 秒转小时保留2位
record.setTotalOfflineTime(TimeConverterUtil.secondsToHours(offlineSec, 2));
record.setTotalRunningTime(TimeConverterUtil.secondsToHours(runningSec, 2));
record.setTotalStandbyTime(TimeConverterUtil.secondsToHours(standbySec, 2));
record.setTotalFaultTime(TimeConverterUtil.secondsToHours(faultSec, 2));
// 百分比字符串
record.setPowerOnRate(TimeConverterUtil.getPercentString(powerOnRate));
record.setUtilizationRate(TimeConverterUtil.getPercentString(utilizationRate)); record.setUtilizationRate(TimeConverterUtil.getPercentString(utilizationRate));
} catch (Exception e) { } catch (Exception e) {
log.error("计算设备{}时间转换时出错: {}", record.getDeviceCode(), e.getMessage()); log.error("计算设备{}时间统计出错: {}", record.getDeviceCode(), e.getMessage());
// 设置默认值
setDefaultValues(record); setDefaultValues(record);
} }
} }
} }
private void setDefaultValues(DeviceTotalTimeRecordRespVO record) { private void setDefaultValues(DeviceTotalTimeRecordRespVO record) {
record.setTotalRunningTime(0.0); record.setTotalRunningTime(0.0);
record.setTotalStandbyTime(0.0); record.setTotalStandbyTime(0.0);

@ -163,4 +163,34 @@
WHERE rn = 1 WHERE rn = 1
</select> </select>
<select id="selectLineBatch"
resultType="cn.iocoder.yudao.module.iot.controller.admin.device.vo.LineCodeAndNameRespVO">
SELECT
iotd.id AS deviceId,
mo.code AS lineCode,
mo.name AS lineName
FROM mes_organization mo
LEFT JOIN iot_device iotd ON mo.dv_id = iotd.id
WHERE iotd.id IN
<foreach collection="deviceIds" item="id" open="(" separator="," close=")">
#{id}
</foreach>
AND mo.deleted = 0
</select>
<select id="selectDeviceIdsByLine" resultType="java.lang.Long">
SELECT iotd.id
FROM mes_organization mo
LEFT JOIN iot_device iotd ON mo.dv_id = iotd.id
WHERE mo.deleted = 0
and mo.dv_id is not null
<if test="lineNode != null and lineNode != ''">
AND mo.code LIKE CONCAT('%', #{lineNode}, '%')
</if>
<if test="lineName != null and lineName != ''">
AND mo.name LIKE CONCAT('%', #{lineName}, '%')
</if>
</select>
</mapper> </mapper>

@ -12,15 +12,21 @@
<select id="deviceOperationPage" <select id="deviceOperationPage"
resultType="cn.iocoder.yudao.module.iot.controller.admin.deviceoperationrecord.vo.DeviceTotalTimeRecordRespVO"> resultType="cn.iocoder.yudao.module.iot.controller.admin.deviceoperationrecord.vo.DeviceTotalTimeRecordRespVO">
SELECT SELECT
ide.device_code as deviceCode, ide.id,
ide.device_name as deviceName, ide.device_code AS deviceCode,
SUM(CASE WHEN idor.rule = '1' THEN idor.total_running_time ELSE 0 END) AS totalRunningTime, ide.device_name AS deviceName,
SUM(CASE WHEN idor.rule = '2' THEN idor.total_standby_time ELSE 0 END) AS totalStandbyTime, -- 每条 rule=0 的记录计数 * 60 秒
SUM(CASE WHEN idor.rule = '3' THEN idor.total_fault_time ELSE 0 END) AS totalFaultTime, SUM(CASE WHEN idor.rule = '0' THEN 1 ELSE 0 END) * 60 AS totalOfflineTime,
SUM(CASE WHEN idor.rule = '4' THEN idor.total_warning_time ELSE 0 END) AS totalWarningTime -- 每条 rule=1 的记录计数 * 60 秒
FROM besure.iot_device_operation_record idor SUM(CASE WHEN idor.rule = '1' THEN 1 ELSE 0 END) * 60 AS totalRunningTime,
LEFT JOIN besure.iot_device ide ON idor.device_id = ide.id -- 每条 rule=2 的记录计数 * 60 秒
WHERE idor.rule IN ('1', '2', '3', '4') SUM(CASE WHEN idor.rule = '2' THEN 1 ELSE 0 END) * 60 AS totalStandbyTime,
-- 每条 rule=3 的记录计数 * 60 秒
SUM(CASE WHEN idor.rule = '3' THEN 1 ELSE 0 END) * 60 AS totalFaultTime
FROM besure.iot_device ide
LEFT JOIN besure.iot_device_operation_record idor
ON idor.device_id = ide.id
AND idor.deleted = 0 AND idor.deleted = 0
<!-- 时间筛选条件 --> <!-- 时间筛选条件 -->
<if test="pageReqVO.startTime != null"> <if test="pageReqVO.startTime != null">
@ -29,6 +35,7 @@
<if test="pageReqVO.endTime != null"> <if test="pageReqVO.endTime != null">
AND idor.create_time &lt;= #{pageReqVO.endTime} AND idor.create_time &lt;= #{pageReqVO.endTime}
</if> </if>
WHERE ide.deleted = 0
<!-- 设备编码筛选条件 --> <!-- 设备编码筛选条件 -->
<if test="pageReqVO.deviceCode != null and pageReqVO.deviceCode != ''"> <if test="pageReqVO.deviceCode != null and pageReqVO.deviceCode != ''">
AND ide.device_code LIKE CONCAT('%', #{pageReqVO.deviceCode}, '%') AND ide.device_code LIKE CONCAT('%', #{pageReqVO.deviceCode}, '%')
@ -38,7 +45,8 @@
AND ide.device_name LIKE CONCAT('%', #{pageReqVO.deviceName}, '%') AND ide.device_name LIKE CONCAT('%', #{pageReqVO.deviceName}, '%')
</if> </if>
GROUP BY ide.id, ide.device_code, ide.device_name GROUP BY ide.id, ide.device_code, ide.device_name
ORDER BY ide.device_code ORDER BY ide.id desc
</select> </select>
<select id="selectLatestByDeviceAndRule" <select id="selectLatestByDeviceAndRule"
resultType="cn.iocoder.yudao.module.iot.dal.dataobject.deviceoperationrecord.DeviceOperationRecordDO"> resultType="cn.iocoder.yudao.module.iot.dal.dataobject.deviceoperationrecord.DeviceOperationRecordDO">

@ -121,7 +121,7 @@ public class DashboardController {
@GetMapping("/getProduction") @GetMapping("/getProduction")
@Operation(summary = "获得整体生产概况") @Operation(summary = "获得整体生产概况")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('mes:bom:query')") // @PreAuthorize("@ss.hasPermission('mes:bom:query')")
public CommonResult<TaskRespVO> getProduction(@Valid TaskReqVO taskReqVO) { public CommonResult<TaskRespVO> getProduction(@Valid TaskReqVO taskReqVO) {
TaskRespVO taskRespVO = new TaskRespVO(); TaskRespVO taskRespVO = new TaskRespVO();
List<TaskRespVO.Item> taskItems = new ArrayList<>(); List<TaskRespVO.Item> taskItems = new ArrayList<>();
@ -241,7 +241,7 @@ public class DashboardController {
@GetMapping("/getPlan") @GetMapping("/getPlan")
@Operation(summary = "获得实时生产进度") @Operation(summary = "获得实时生产进度")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('mes:bom:query')") // @PreAuthorize("@ss.hasPermission('mes:bom:query')")
public CommonResult<List<PlanRespVO>> getPlan() { public CommonResult<List<PlanRespVO>> getPlan() {
List<Integer> statusList = new ArrayList<>(); List<Integer> statusList = new ArrayList<>();
statusList.add(1); statusList.add(1);
@ -265,7 +265,7 @@ public class DashboardController {
@GetMapping("/getDevice") @GetMapping("/getDevice")
@Operation(summary = "获得设备任务") @Operation(summary = "获得设备任务")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('mes:bom:query')") // @PreAuthorize("@ss.hasPermission('mes:bom:query')")
public CommonResult<List<DeviceRespVO>> getDevice() { public CommonResult<List<DeviceRespVO>> getDevice() {
List<DeviceRespVO> deviceRespVOList = new ArrayList<>(); List<DeviceRespVO> deviceRespVOList = new ArrayList<>();
DeviceRespVO deviceRespVO = new DeviceRespVO(); DeviceRespVO deviceRespVO = new DeviceRespVO();
@ -295,7 +295,7 @@ public class DashboardController {
@GetMapping("/getMold") @GetMapping("/getMold")
@Operation(summary = "获得模具任务") @Operation(summary = "获得模具任务")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('mes:bom:query')") // @PreAuthorize("@ss.hasPermission('mes:bom:query')")
public CommonResult<List<MoldRespVO>> getMold() { public CommonResult<List<MoldRespVO>> getMold() {
List<MoldRespVO> moldRespVOList = new ArrayList<>(); List<MoldRespVO> moldRespVOList = new ArrayList<>();
MoldRespVO moldRespVO = new MoldRespVO(); MoldRespVO moldRespVO = new MoldRespVO();
@ -325,7 +325,7 @@ public class DashboardController {
@GetMapping("/getTodoList") @GetMapping("/getTodoList")
@Operation(summary = "获得待办任务") @Operation(summary = "获得待办任务")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('mes:bom:query')") // @PreAuthorize("@ss.hasPermission('mes:bom:query')")
public CommonResult<List<TodoRespVO>> getTodoList() { public CommonResult<List<TodoRespVO>> getTodoList() {
List<TodoRespVO> todoRespVOList = new ArrayList<>(); List<TodoRespVO> todoRespVOList = new ArrayList<>();
// 设备维修 // 设备维修
@ -390,7 +390,7 @@ public class DashboardController {
@GetMapping("/getDeviceRepairLineOptions") @GetMapping("/getDeviceRepairLineOptions")
@Operation(summary = "获得设备维修数量统计") @Operation(summary = "获得设备维修数量统计")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('mes:bom:query')") // @PreAuthorize("@ss.hasPermission('mes:bom:query')")
public CommonResult<DeviceRepairLineOptionsVO> getDeviceRepairLineOptions() { public CommonResult<DeviceRepairLineOptionsVO> getDeviceRepairLineOptions() {
DeviceRepairLineOptionsVO deviceRepairLineOptionsVO = new DeviceRepairLineOptionsVO(); DeviceRepairLineOptionsVO deviceRepairLineOptionsVO = new DeviceRepairLineOptionsVO();
// 计算6个月前的日期 // 计算6个月前的日期
@ -447,7 +447,7 @@ public class DashboardController {
@GetMapping("/getDeviceTypePieOptions") @GetMapping("/getDeviceTypePieOptions")
@Operation(summary = "获得设备分类统计") @Operation(summary = "获得设备分类统计")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('mes:bom:query')") // @PreAuthorize("@ss.hasPermission('mes:bom:query')")
public CommonResult<List<DeviceTypePieOptionsVO>> getDeviceTypePieOptions() { public CommonResult<List<DeviceTypePieOptionsVO>> getDeviceTypePieOptions() {
List<DeviceTypePieOptionsVO> deviceTypePieOptionsVOList = new ArrayList<>(); List<DeviceTypePieOptionsVO> deviceTypePieOptionsVOList = new ArrayList<>();
QueryWrapper<DeviceLedgerDO> queryWrapper = new QueryWrapper<>(); QueryWrapper<DeviceLedgerDO> queryWrapper = new QueryWrapper<>();
@ -470,7 +470,7 @@ public class DashboardController {
@GetMapping("/getMoldTypeBarOptions") @GetMapping("/getMoldTypeBarOptions")
@Operation(summary = "获得模具分类分布统计") @Operation(summary = "获得模具分类分布统计")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('mes:bom:query')") // @PreAuthorize("@ss.hasPermission('mes:bom:query')")
public CommonResult<DeviceRepairLineOptionsVO> getMoldTypeBarOptions() { public CommonResult<DeviceRepairLineOptionsVO> getMoldTypeBarOptions() {
DeviceRepairLineOptionsVO deviceRepairLineOptionsVO = new DeviceRepairLineOptionsVO(); DeviceRepairLineOptionsVO deviceRepairLineOptionsVO = new DeviceRepairLineOptionsVO();
QueryWrapper<MoldDO> queryWrapper = new QueryWrapper<>(); QueryWrapper<MoldDO> queryWrapper = new QueryWrapper<>();

@ -25,6 +25,7 @@ import cn.iocoder.yudao.module.mes.service.machine.MachineComponentService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -47,6 +48,7 @@ import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
*/ */
@Service @Service
@Validated @Validated
@Slf4j
public class OrganizationServiceImpl implements OrganizationService { public class OrganizationServiceImpl implements OrganizationService {
@Resource @Resource
@ -220,6 +222,7 @@ public class OrganizationServiceImpl implements OrganizationService {
if (CollUtil.isEmpty(list)) { if (CollUtil.isEmpty(list)) {
return Collections.emptyList(); return Collections.emptyList();
} }
//关联机台 //关联机台
// Map<Long, MachineComponentDO> map = machineComponentService.getMap( // Map<Long, MachineComponentDO> map = machineComponentService.getMap(
// convertSet(list, OrganizationDO::getMachineId)); // convertSet(list, OrganizationDO::getMachineId));
@ -230,21 +233,27 @@ public class OrganizationServiceImpl implements OrganizationService {
// //
// }); // });
//关联设备 //关联设备
// Map<Long, DeviceDO> map = deviceService.getMap( Map<Long, DeviceDO> map = deviceService.getMap(
// convertSet(list, OrganizationDO::getMachineId)); convertSet(list, OrganizationDO::getDvId));
// List<DeviceLedgerDO> deviceLedgerDOList = deviceLedgerService.getDeviceLedgerList();
// Map<Long, DeviceLedgerDO> resultMap = deviceLedgerDOList.stream()
// .filter(Objects::nonNull)
// .collect(Collectors.toMap(
// DeviceLedgerDO::getId,
// Function.identity(),
// (existing, replacement) -> existing // 处理重复key
// ));
List<DeviceLedgerDO> deviceLedgerDOList = deviceLedgerService.getDeviceLedgerList(); // return BeanUtils.toBean(list, OrganizationRespVO.class, item -> {
Map<Long, DeviceLedgerDO> resultMap = deviceLedgerDOList.stream() // MapUtils.findAndThen(resultMap, item.getDvId(),
.filter(Objects::nonNull) // device -> item.setMachineName(device.getDeviceName()));
.collect(Collectors.toMap( // });
DeviceLedgerDO::getId,
Function.identity(),
(existing, replacement) -> existing // 处理重复key
));
return BeanUtils.toBean(list, OrganizationRespVO.class, item -> { return BeanUtils.toBean(list, OrganizationRespVO.class, item -> {
MapUtils.findAndThen(resultMap, item.getMachineId(), MapUtils.findAndThen(map, item.getDvId(),
device -> item.setMachineName(device.getDeviceName())); device -> item.setMachineName(device.getDeviceName()));
}); });
} }
@Override @Override
@ -316,20 +325,27 @@ public class OrganizationServiceImpl implements OrganizationService {
return Collections.emptyList(); return Collections.emptyList();
} }
organizationRespVOS.forEach(vo ->
log.info("[Debug] OrgId={} dvId={} machineName={}", vo.getId(), vo.getDvId(), vo.getMachineName()));
// 2. 获取所有有machineId的组织 // 2. 获取所有有machineId的组织
List<Long> deviceIds = organizationRespVOS.stream() List<Long> deviceIds = organizationRespVOS.stream()
.map(OrganizationRespVO::getMachineId) .map(OrganizationRespVO::getDvId)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.distinct() .distinct()
.collect(Collectors.toList()); .collect(Collectors.toList());
// 添加日志:看看 deviceIds 是否为空
log.info("[Debug] deviceIds={}", deviceIds);
// 3. 查询设备信息 // 3. 查询设备信息
Map<Long, DeviceDO> deviceMap; Map<Long, DeviceDO> deviceMap;
if (!deviceIds.isEmpty()) { if (!deviceIds.isEmpty()) {
LambdaQueryWrapper<DeviceDO> deviceWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<DeviceDO> deviceWrapper = new LambdaQueryWrapper<>();
deviceWrapper.in(DeviceDO::getId, deviceIds) deviceWrapper.in(DeviceDO::getId, deviceIds);
.eq(DeviceDO::getIsEnable, true);
List<DeviceDO> devices = deviceMapper.selectList(deviceWrapper); List<DeviceDO> devices = deviceMapper.selectList(deviceWrapper);
log.info("[Debug] devices from DB: {}", devices.stream()
.map(DeviceDO::getDeviceName)
.collect(Collectors.toList()));
deviceMap = devices.stream() deviceMap = devices.stream()
.collect(Collectors.toMap(DeviceDO::getId, Function.identity())); .collect(Collectors.toMap(DeviceDO::getId, Function.identity()));
} else { } else {
@ -347,6 +363,11 @@ public class OrganizationServiceImpl implements OrganizationService {
paramsByDeviceId = allParameters.stream() paramsByDeviceId = allParameters.stream()
.filter(param -> param.getDeviceId() != null) .filter(param -> param.getDeviceId() != null)
.collect(Collectors.groupingBy(DeviceContactModelDO::getDeviceId)); .collect(Collectors.groupingBy(DeviceContactModelDO::getDeviceId));
paramsByDeviceId.forEach((deviceId, params) -> {
log.info("[Debug] deviceId={} parameters={}", deviceId,
params.stream().map(DeviceContactModelDO::getAttributeName).collect(Collectors.toList()));
});
} else { } else {
paramsByDeviceId = new HashMap<>(); paramsByDeviceId = new HashMap<>();
} }
@ -383,8 +404,8 @@ public class OrganizationServiceImpl implements OrganizationService {
} }
// 2. 如果没有组织名称匹配,检查该节点是否有设备匹配 // 2. 如果没有组织名称匹配,检查该节点是否有设备匹配
if (!nodeMatched && needShowDevices && node.getMachineId() != null) { if (!nodeMatched && needShowDevices && node.getDvId() != null) {
DeviceDO device = deviceMap.get(node.getMachineId()); DeviceDO device = deviceMap.get(node.getDvId());
if (device != null) { if (device != null) {
// 检查设备名称是否匹配 // 检查设备名称是否匹配
if (device.getDeviceName() != null && if (device.getDeviceName() != null &&
@ -647,8 +668,8 @@ public class OrganizationServiceImpl implements OrganizationService {
// 获取当前节点 // 获取当前节点
OrganizationRespVO currentNode = allNodesMap.get(node.getId()); OrganizationRespVO currentNode = allNodesMap.get(node.getId());
if (currentNode != null && currentNode.getMachineId() != null) { if (currentNode != null && currentNode.getDvId() != null) {
deviceIds.add(currentNode.getMachineId()); deviceIds.add(currentNode.getDvId());
} }
return deviceIds; return deviceIds;
@ -665,8 +686,8 @@ public class OrganizationServiceImpl implements OrganizationService {
// 先检查当前节点是否有设备 // 先检查当前节点是否有设备
OrganizationRespVO currentNode = allNodesMap.get(nodeId); OrganizationRespVO currentNode = allNodesMap.get(nodeId);
if (currentNode != null && currentNode.getMachineId() != null) { if (currentNode != null && currentNode.getDvId() != null) {
deviceIds.add(currentNode.getMachineId()); deviceIds.add(currentNode.getDvId());
} }
// 使用队列迭代获取所有子孙节点 // 使用队列迭代获取所有子孙节点
@ -682,8 +703,8 @@ public class OrganizationServiceImpl implements OrganizationService {
for (OrganizationRespVO child : children) { for (OrganizationRespVO child : children) {
if (matchedNodeIds.contains(child.getId())) { if (matchedNodeIds.contains(child.getId())) {
// 如果子节点有设备,添加到设备列表 // 如果子节点有设备,添加到设备列表
if (child.getMachineId() != null) { if (child.getDvId() != null) {
deviceIds.add(child.getMachineId()); deviceIds.add(child.getDvId());
} }
// 继续处理子节点的子节点 // 继续处理子节点的子节点
queue.offer(child.getId()); queue.offer(child.getId());

Loading…
Cancel
Save