diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 50e22fd63b..b549cd6d70 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -56,7 +56,7 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_POINT_RULES_NOT_EXISTS = new ErrorCode(1_004_000_001, "点位规则不存在"); ErrorCode DEVICE_MODEL_RULES_NOT_EXISTS = new ErrorCode(1_004_000_002, "点位规则关联模型不存在"); ErrorCode DEVICE_OPERATION_RECORD_NOT_EXISTS = new ErrorCode(1_004_000_003, "运行记录不存在"); - + ErrorCode DEVICE_WARINNING_RECORD_NOT_EXISTS = new ErrorCode(1_004_000_004, "告警记录不存在"); // ======================================= 配方 ============================================ ErrorCode RECIPE_NOT_EXISTS = new ErrorCode(1_003_000_000, "配方主不存在"); ErrorCode RECIPE_TYPE_NOT_EXISTS = new ErrorCode(1_003_000_000, "配方类型表(基础字典)不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java index dca260bc7f..d88ec95fa1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java @@ -201,7 +201,6 @@ public class DeviceController { } - // ==================== 子表(设备属性) ==================== @GetMapping("/device-attribute/page") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/scheduled/coretask/DeviceTask.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/scheduled/coretask/DeviceTask.java index 9caa15cab1..91f6ada6cb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/scheduled/coretask/DeviceTask.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/scheduled/coretask/DeviceTask.java @@ -11,10 +11,12 @@ 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.dataobject.devicewarinningrecord.DeviceWarinningRecordDO; 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.deviceoperationrecord.DeviceOperationRecordMapper; import cn.iocoder.yudao.module.iot.dal.mysql.devicepointrules.DevicePointRulesMapper; +import cn.iocoder.yudao.module.iot.dal.mysql.devicewarinningrecord.DeviceWarinningRecordMapper; import cn.iocoder.yudao.module.iot.service.device.TDengineService; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -52,6 +54,9 @@ public class DeviceTask implements Task { @Resource private DeviceOperationRecordMapper deviceOperationRecordMapper; + @Resource + private DeviceWarinningRecordMapper deviceWarinningRecordMapper; + @Override public String getTaskType() { return TaskTypeEnum.DEVICE.getCode(); @@ -387,23 +392,46 @@ public class DeviceTask implements Task { DeviceDO device, String attributeCode, Long modelId) { + DeviceContactModelDO deviceContactModelDO = deviceContactModelMapper.selectById(modelId); + if (deviceContactModelDO == null){ + return; + } - DeviceOperationRecordDO record = new DeviceOperationRecordDO(); - record.setDeviceId(device.getId()); - record.setModelId(modelId); - record.setRule(pointRulesRespVO.getRule()); - record.setAddressValue(processedValue); - record.setRecordType(getRecordType(devicePointRulesDO)); - record.setRuleId(devicePointRulesDO.getId()); - //TODO 创建人和更新人为内置默认管理员 - record.setCreator("1"); - record.setUpdater("1"); - - - // 处理累计时间 - calculateAndSetTotalTime(record, pointRulesRespVO.getRule(), device.getSampleCycle()); - deviceOperationRecordMapper.insert(record); + //分别处理运行记录和告警记录 + if (StringUtils.isBlank(devicePointRulesDO.getAlarmLevel())){ + DeviceOperationRecordDO record = new DeviceOperationRecordDO(); + record.setDeviceId(device.getId()); + record.setModelId(modelId); + record.setRule(pointRulesRespVO.getRule()); + record.setAddressValue(processedValue); + record.setRecordType(getRecordType(devicePointRulesDO)); + record.setRuleId(devicePointRulesDO.getId()); + //TODO 创建人和更新人为内置默认管理员 + record.setCreator("1"); + record.setUpdater("1"); + + // 处理累计时间 + calculateAndSetTotalTime(record, pointRulesRespVO.getRule(), device.getSampleCycle()); + + deviceOperationRecordMapper.insert(record); + }else { + + DeviceWarinningRecordDO deviceWarinningRecordDO = new DeviceWarinningRecordDO(); + deviceWarinningRecordDO.setDeviceId(device.getId()); + deviceWarinningRecordDO.setModelId(modelId); + deviceWarinningRecordDO.setRule(pointRulesRespVO.getRule()); + deviceWarinningRecordDO.setAlarmLevel(devicePointRulesDO.getAlarmLevel()); + deviceWarinningRecordDO.setAddressValue(processedValue); + deviceWarinningRecordDO.setRuleId(devicePointRulesDO.getId()); + deviceWarinningRecordDO.setDeviceName(device.getDeviceName()); + deviceWarinningRecordDO.setModelName(deviceContactModelDO.getAttributeName()); + deviceWarinningRecordDO.setRuleName(devicePointRulesDO.getFieldName()); + //TODO 创建人和更新人为内置默认管理员 + deviceWarinningRecordDO.setCreator("1"); + deviceWarinningRecordDO.setUpdater("1"); + deviceWarinningRecordMapper.insert(deviceWarinningRecordDO); + } } private void calculateAndSetTotalTime(DeviceOperationRecordDO record, String ruleCode, Double sampleCycle) { @@ -612,68 +640,6 @@ public class DeviceTask implements Task { } } - /** - * 使用连接池执行任务 - */ -// private void executeWithConnectionPool(Long deviceId, DeviceDO device) { -// SessionInfo sessionInfo = connectionPool.get(deviceId); -// -// // 检查是否可复用现有连接 -// if (sessionInfo != null && !sessionInfo.isExpired() && OpcUtils.isConnected()) { -// log.debug("复用现有连接,设备ID: {}", deviceId); -// sessionInfo.updateLastUsed(); -// } else { -// // 需要创建新连接 -// if (sessionInfo != null) { -// // 清理过期连接 -// connectionPool.remove(deviceId); -// OpcUtils.disconnect(); -// } -// -// log.info("创建新OPC连接,设备ID: {}", deviceId); -// if (!OpcUtils.connect(device.getUrl(), device.getUsername(), device.getPassword(), 10)) { -// throw new RuntimeException("OPC连接失败: " + device.getUrl()); -// } -// -// // 记录新会话 -// sessionInfo = new SessionInfo(device.getUrl(), device.getUsername()); -// connectionPool.put(deviceId, sessionInfo); -// } -// -// try { -// // 执行数据采集 -// processDeviceData(deviceId, device); -// } catch (Exception e) { -// // 发生异常时清理连接 -// connectionPool.remove(deviceId); -// OpcUtils.disconnect(); -// throw e; -// } -// } -// -// /** -// * 清理过期连接 -// */ -// private static void cleanupExpiredConnections() { -// int initialSize = connectionPool.size(); -// if (initialSize == 0) return; -// -// connectionPool.entrySet().removeIf(entry -> { -// SessionInfo session = entry.getValue(); -// if (session != null && session.isExpired()) { -// log.debug("清理过期连接,设备ID: {}", entry.getKey()); -// OpcUtils.disconnect(); -// return true; -// } -// return false; -// }); -// -// int finalSize = connectionPool.size(); -// if (initialSize != finalSize) { -// log.info("连接池清理完成: {} -> {}", initialSize, finalSize); -// } -// } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceSaveReqVO.java index 7fee1d1d71..c05d0c38dc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceSaveReqVO.java @@ -7,7 +7,6 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.time.LocalDateTime; -@Schema(description = "管理后台 - 物联设备新增/修改 Request VO") @Data public class DeviceSaveReqVO { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicecontactmodel/vo/DeviceContactModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicecontactmodel/vo/DeviceContactModelRespVO.java index 8e484ff4b4..1773d41e29 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicecontactmodel/vo/DeviceContactModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicecontactmodel/vo/DeviceContactModelRespVO.java @@ -59,4 +59,8 @@ public class DeviceContactModelRespVO { @ExcelProperty("排序") private int sort; + @Schema(description = "采集点类型名称", example = "1") + private String typeName; + + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicecontactmodel/vo/DeviceContactModelSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicecontactmodel/vo/DeviceContactModelSaveReqVO.java index d1c4dfe218..728358558a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicecontactmodel/vo/DeviceContactModelSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicecontactmodel/vo/DeviceContactModelSaveReqVO.java @@ -44,4 +44,7 @@ public class DeviceContactModelSaveReqVO { @Schema(description = "排序", example = "2") private int sort; + + @Schema(description = "采集点类型名称", example = "2") + private String typeName; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeRespVO.java index 67b0126945..4d02dabfee 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeRespVO.java @@ -62,4 +62,6 @@ public class DeviceModelAttributeRespVO { @ColumnWidth(20) // 设置此列的宽度为 20 个字符的宽度 private LocalDateTime createTime; + + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeSaveReqVO.java index fa78fd506e..1a6e6d8c43 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeSaveReqVO.java @@ -42,4 +42,6 @@ public class DeviceModelAttributeSaveReqVO { @NotNull(message = "采集设备模型id不能为空") private Long deviceModelId; + @Schema(description = "采集点类型名称") + private String typeName; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/DeviceModelRulesRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/DeviceModelRulesRespVO.java index 61204d148b..50552a2866 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/DeviceModelRulesRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/DeviceModelRulesRespVO.java @@ -43,4 +43,7 @@ public class DeviceModelRulesRespVO { @Schema(description = "点位规则") private List pointRulesVOList; + @Schema(description = "告警等级") + private String alarmLevel; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/DeviceModelRulesSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/DeviceModelRulesSaveReqVO.java index 632db3bbae..52b77d32fc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/DeviceModelRulesSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/DeviceModelRulesSaveReqVO.java @@ -28,6 +28,9 @@ public class DeviceModelRulesSaveReqVO { @Schema(description = "关联设备模型Id", example = "13397") private Long modelId; + @Schema(description = "告警等级") + private String alarmLevel; + @Schema(description = "点位规则列表", implementation = PointRulesRespVO.class) private List pointRulesVOList; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/PointRulesRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/PointRulesRespVO.java index a62575a28f..c42cbe34e2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/PointRulesRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelrules/vo/PointRulesRespVO.java @@ -10,6 +10,8 @@ public class PointRulesRespVO { @Schema(description = "点位规则") private String rule; + + @Schema(description = "点位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "10916") private String code; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicepointrules/vo/DevicePointRulesRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicepointrules/vo/DevicePointRulesRespVO.java index 54c4ffde50..6b747f441c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicepointrules/vo/DevicePointRulesRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicepointrules/vo/DevicePointRulesRespVO.java @@ -44,4 +44,7 @@ public class DevicePointRulesRespVO { @Schema(description = "点位规则") private List pointRulesVOList; + @Schema(description = "告警等级", example = "19582") + private String alarmLevel; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicepointrules/vo/DevicePointRulesSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicepointrules/vo/DevicePointRulesSaveReqVO.java index af3a4771ce..4bb55c6079 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicepointrules/vo/DevicePointRulesSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicepointrules/vo/DevicePointRulesSaveReqVO.java @@ -32,4 +32,6 @@ public class DevicePointRulesSaveReqVO { @Schema(description = "点位规则列表", implementation = PointRulesRespVO.class) private List pointRulesVOList; + @Schema(description = "告警等级", example = "19582") + private String alarmLevel; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/DeviceWarinningRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/DeviceWarinningRecordController.java new file mode 100644 index 0000000000..bc1315afea --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/DeviceWarinningRecordController.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.iot.controller.admin.devicewarinningrecord; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.iot.controller.admin.devicewarinningrecord.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.devicewarinningrecord.DeviceWarinningRecordDO; +import cn.iocoder.yudao.module.iot.service.devicewarinningrecord.DeviceWarinningRecordService; + +@Tag(name = "管理后台 - 告警记录") +@RestController +@RequestMapping("/iot/device-warinning-record") +@Validated +public class DeviceWarinningRecordController { + + @Resource + private DeviceWarinningRecordService deviceWarinningRecordService; + + @PostMapping("/create") + @Operation(summary = "创建告警记录") + @PreAuthorize("@ss.hasPermission('iot:device-warinning-record:create')") + public CommonResult createDeviceWarinningRecord(@Valid @RequestBody DeviceWarinningRecordSaveReqVO createReqVO) { + return success(deviceWarinningRecordService.createDeviceWarinningRecord(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新告警记录") + @PreAuthorize("@ss.hasPermission('iot:device-warinning-record:update')") + public CommonResult updateDeviceWarinningRecord(@Valid @RequestBody DeviceWarinningRecordSaveReqVO updateReqVO) { + deviceWarinningRecordService.updateDeviceWarinningRecord(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除告警记录") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:device-warinning-record:delete')") + public CommonResult deleteDeviceWarinningRecord(@RequestParam("id") Long id) { + deviceWarinningRecordService.deleteDeviceWarinningRecord(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得告警记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:device-warinning-record:query')") + public CommonResult getDeviceWarinningRecord(@RequestParam("id") Long id) { + DeviceWarinningRecordDO deviceWarinningRecord = deviceWarinningRecordService.getDeviceWarinningRecord(id); + return success(BeanUtils.toBean(deviceWarinningRecord, DeviceWarinningRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得告警记录分页") + @PreAuthorize("@ss.hasPermission('iot:device-warinning-record:query')") + public CommonResult> getDeviceWarinningRecordPage(@Valid DeviceWarinningRecordPageReqVO pageReqVO) { + PageResult pageResult = deviceWarinningRecordService.getDeviceWarinningRecordPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, DeviceWarinningRecordRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出告警记录 Excel") + @PreAuthorize("@ss.hasPermission('iot:device-warinning-record:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDeviceWarinningRecordExcel(@Valid DeviceWarinningRecordPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = deviceWarinningRecordService.getDeviceWarinningRecordPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "告警记录.xls", "数据", DeviceWarinningRecordRespVO.class, + BeanUtils.toBean(list, DeviceWarinningRecordRespVO.class)); + } + + + @GetMapping("/getList") + @Operation(summary = "获得告警记录列表") + @Parameter(name = "deviceId", description = "设备Id", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:device-warinning-record:query')") + public CommonResult> getList(@RequestParam(name = "deviceId" ,required = false) Long id) { + List deviceWarinningRecord = deviceWarinningRecordService.getList(id); + return success(deviceWarinningRecord); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/vo/DeviceWarinningRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/vo/DeviceWarinningRecordPageReqVO.java new file mode 100644 index 0000000000..1b5b1f98e7 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/vo/DeviceWarinningRecordPageReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.iot.controller.admin.devicewarinningrecord.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 告警记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeviceWarinningRecordPageReqVO extends PageParam { + + @Schema(description = "设备ID", example = "27939") + private Long deviceId; + + @Schema(description = "模型ID", example = "18634") + private Long modelId; + + @Schema(description = "规则值") + private String rule; + + @Schema(description = "告警等级") + private String alarmLevel; + + @Schema(description = "地址值") + private String addressValue; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "点位规则Id", example = "25946") + private Long ruleId; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/vo/DeviceWarinningRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/vo/DeviceWarinningRecordRespVO.java new file mode 100644 index 0000000000..2e7d6f1c10 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/vo/DeviceWarinningRecordRespVO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.iot.controller.admin.devicewarinningrecord.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 告警记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class DeviceWarinningRecordRespVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "22919") + @ExcelProperty("ID") + private Long id; + + @Schema(description = "设备ID", example = "27939") + @ExcelProperty("设备ID") + private Long deviceId; + + @Schema(description = "设备名称") + private String deviceName; + + @Schema(description = "点位模型ID", example = "18634") + @ExcelProperty("点位模型ID") + private Long modelId; + + @Schema(description = "点位模型名称") + private String modelName; + + @Schema(description = "规则值") + @ExcelProperty("规则值") + private String rule; + + @Schema(description = "告警等级") + @ExcelProperty("告警等级") + private String alarmLevel; + + @Schema(description = "地址值") + @ExcelProperty("地址值") + private String addressValue; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "点位规则Id", example = "25946") + @ExcelProperty("点位规则Id") + private Long ruleId; + + @Schema(description = "点位规则名称", example = "25946") + private String ruleName; + + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/vo/DeviceWarinningRecordSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/vo/DeviceWarinningRecordSaveReqVO.java new file mode 100644 index 0000000000..33a48a8daf --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicewarinningrecord/vo/DeviceWarinningRecordSaveReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.iot.controller.admin.devicewarinningrecord.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 告警记录新增/修改 Request VO") +@Data +public class DeviceWarinningRecordSaveReqVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "22919") + private Long id; + + @Schema(description = "设备ID", example = "27939") + private Long deviceId; + + @Schema(description = "模型ID", example = "18634") + private Long modelId; + + @Schema(description = "规则值") + private String rule; + + @Schema(description = "告警等级") + private String alarmLevel; + + @Schema(description = "地址值") + private String addressValue; + + @Schema(description = "点位规则Id", example = "25946") + private Long ruleId; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicecontactmodel/DeviceContactModelDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicecontactmodel/DeviceContactModelDO.java index 458f0fefc1..584580345f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicecontactmodel/DeviceContactModelDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicecontactmodel/DeviceContactModelDO.java @@ -99,4 +99,9 @@ public class DeviceContactModelDO extends BaseDO { private LocalDateTime updateTime; + /** + * 采集点类型名称 + */ + private String typeName; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicemodelattribute/DeviceModelAttributeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicemodelattribute/DeviceModelAttributeDO.java index 887f78eea3..e69613db79 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicemodelattribute/DeviceModelAttributeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicemodelattribute/DeviceModelAttributeDO.java @@ -74,4 +74,9 @@ public class DeviceModelAttributeDO extends BaseDO { @Schema(description = "采集设备模型id") private Long deviceModelId; + /** + * 采集点类型名称 + */ + private String typeName; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicemodelrules/DeviceModelRulesDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicemodelrules/DeviceModelRulesDO.java index 08339791c6..3f808bbf23 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicemodelrules/DeviceModelRulesDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicemodelrules/DeviceModelRulesDO.java @@ -48,4 +48,9 @@ public class DeviceModelRulesDO extends BaseDO { */ private Long modelId; + /** + * 告警等级 + */ + private String alarmLevel; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicepointrules/DevicePointRulesDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicepointrules/DevicePointRulesDO.java index a621cc44ea..87dd1d2bce 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicepointrules/DevicePointRulesDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicepointrules/DevicePointRulesDO.java @@ -48,4 +48,9 @@ public class DevicePointRulesDO extends BaseDO { */ private Long deviceId; + /** + * 告警等级 + */ + private String alarmLevel; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicewarinningrecord/DeviceWarinningRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicewarinningrecord/DeviceWarinningRecordDO.java new file mode 100644 index 0000000000..a7a0f0e540 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/devicewarinningrecord/DeviceWarinningRecordDO.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.devicewarinningrecord; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 告警记录 DO + * + * @author 必硕科技 + */ +@TableName("iot_device_warinning_record") +@KeySequence("iot_device_warinning_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DeviceWarinningRecordDO extends BaseDO { + + /** + * ID + */ + @TableId + private Long id; + /** + * 设备ID + */ + private Long deviceId; + /** + * 模型ID + */ + private Long modelId; + /** + * 规则值 + */ + private String rule; + /** + * 告警等级 + */ + private String alarmLevel; + /** + * 地址值 + */ + private String addressValue; + /** + * 点位规则Id + */ + private Long ruleId; + + /** + * 设备名称 + */ + private String deviceName; + /** + * 点位名称 + */ + private String modelName; + /** + * 点位规则名称 + */ + private String ruleName; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/devicewarinningrecord/DeviceWarinningRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/devicewarinningrecord/DeviceWarinningRecordMapper.java new file mode 100644 index 0000000000..c56b95fb0a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/devicewarinningrecord/DeviceWarinningRecordMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.devicewarinningrecord; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.iot.dal.dataobject.devicewarinningrecord.DeviceWarinningRecordDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.iot.controller.admin.devicewarinningrecord.vo.*; + +/** + * 告警记录 Mapper + * + * @author 必硕科技 + */ +@Mapper +public interface DeviceWarinningRecordMapper extends BaseMapperX { + + default PageResult selectPage(DeviceWarinningRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(DeviceWarinningRecordDO::getDeviceId, reqVO.getDeviceId()) + .eqIfPresent(DeviceWarinningRecordDO::getModelId, reqVO.getModelId()) + .eqIfPresent(DeviceWarinningRecordDO::getRule, reqVO.getRule()) + .eqIfPresent(DeviceWarinningRecordDO::getAlarmLevel, reqVO.getAlarmLevel()) + .eqIfPresent(DeviceWarinningRecordDO::getAddressValue, reqVO.getAddressValue()) + .betweenIfPresent(DeviceWarinningRecordDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(DeviceWarinningRecordDO::getRuleId, reqVO.getRuleId()) + .orderByDesc(DeviceWarinningRecordDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceService.java index ecac3189df..1322f9f7a0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceService.java @@ -134,4 +134,5 @@ public interface DeviceService { Boolean scheduledStop(Long id); DeviceOperationStatusRespVO getDeviceOperationalStatus(); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java index c9cba6ae73..3b8b3b9fcf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java @@ -109,6 +109,7 @@ public class DeviceServiceImpl implements DeviceService { private DeviceOperationRecordMapper deviceOperationRecordMapper; + @Override @Transactional(rollbackFor = Exception.class) public DeviceDO createDevice(DeviceSaveReqVO createReqVO) { @@ -820,6 +821,8 @@ public class DeviceServiceImpl implements DeviceService { return deviceOperationalStatus; } + + /** * 计算利用率 * 利用率 = 运行数量 / 设备总数 * 100% diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/TDengineService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/TDengineService.java index d1316e36b3..1680546d55 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/TDengineService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/TDengineService.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang3.StringUtils; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; @@ -20,6 +21,7 @@ import java.sql.SQLException; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; @Service @@ -497,11 +499,11 @@ public class TDengineService { for (Long deviceId : deviceIds) { try { // 查询首条数据 - List> firstList = getstDeviceDataOrderByTimeDesc(deviceId, startTime, endTime, 1); + List> firstList = getDeviceFirstData(deviceId, startTime, endTime, 1); Map firstData = firstList.isEmpty() ? null : firstList.get(0); // 查询末条数据 - List> lastList = getstDeviceDataOrderByTimeDesc(deviceId, startTime, endTime, 1); + List> lastList = getDeviceLastData(deviceId, startTime, endTime, 1); Map lastData = lastList.isEmpty() ? null : lastList.get(0); DeviceEdgeData edgeData = new DeviceEdgeData(); @@ -528,4 +530,161 @@ public class TDengineService { + @DS("tdengine") + public List> getDeviceFirstData( + Long deviceId, + String startTime, + String endTime, + Integer limit) { + + String tableName = "d_" + deviceId; + StringBuilder sql = new StringBuilder(); + + sql.append("SELECT ts, query_data ") + .append("FROM besure.").append(tableName) + .append(" WHERE ts >= '").append(startTime).append("'") + .append(" AND ts <= '").append(endTime).append("'") + .append(" ORDER BY ts ASC "); + + if (limit != null && limit > 0) { + sql.append(" LIMIT ").append(limit); + } + + return jdbcTemplate.query(sql.toString(), (rs, rowNum) -> { + Map map = new HashMap<>(); + map.put("timestamp", rs.getTimestamp("ts")); + map.put("deviceId", deviceId); + + // 读取 query_data(二进制字段) + byte[] blob = rs.getBytes("query_data"); + if (blob != null) { + // 转为字符串 + String json = new String(blob, StandardCharsets.UTF_8).trim(); + + // 去除 TDengine 中可能存在的外层双引号 + if (json.startsWith("\"") && json.endsWith("\"")) { + json = json.substring(1, json.length() - 1); + } + + // 如果是十六进制字符串,先解码 + if (isHexString(json)) { + json = hexToString(json); + } + + // 统一约定:queryData 始终返回 String,由上层决定是否解析 JSON + map.put("queryData", json); + } else { + // 没有数据时返回空数组字符串 + map.put("queryData", "[]"); + } + + return map; + }); + } + + @DS("tdengine") + public List> getDeviceLastData( + Long deviceId, + String startTime, + String endTime, + Integer limit) { + + String tableName = "d_" + deviceId; + StringBuilder sql = new StringBuilder(); + + sql.append("SELECT ts, query_data ") + .append("FROM besure.").append(tableName) + .append(" WHERE ts >= '").append(startTime).append("'") + .append(" AND ts <= '").append(endTime).append("'") + .append(" ORDER BY ts DESC "); + + if (limit != null && limit > 0) { + sql.append(" LIMIT ").append(limit); + } + + return jdbcTemplate.query(sql.toString(), (rs, rowNum) -> { + Map map = new HashMap<>(); + map.put("timestamp", rs.getTimestamp("ts")); + map.put("deviceId", deviceId); + + + // 读取 query_data(二进制字段) + byte[] blob = rs.getBytes("query_data"); + if (blob != null) { + // 转为字符串 + String json = new String(blob, StandardCharsets.UTF_8).trim(); + + // 去除 TDengine 中可能存在的外层双引号 + if (json.startsWith("\"") && json.endsWith("\"")) { + json = json.substring(1, json.length() - 1); + } + + // 如果是十六进制字符串,先解码 + if (isHexString(json)) { + json = hexToString(json); + } + + // 统一约定:queryData 始终返回 String,由上层决定是否解析 JSON + map.put("queryData", json); + } else { + // 没有数据时返回空数组字符串 + map.put("queryData", "[]"); + } + + return map; + }); + } + + + + @DS("tdengine") + public List> queryLastDataByHour(Long deviceId, LocalDateTime startTime, LocalDateTime endTime) { + if (deviceId == null) { + return Collections.emptyList(); + } + + String tableName = "d_" + deviceId; + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ts, query_data FROM besure.").append(tableName) + .append(" WHERE ts >= '").append(startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("'") + .append(" AND ts <= '").append(endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("'") + .append(" ORDER BY ts ASC"); // 升序,方便取每小时最后一条 + + return jdbcTemplate.query(sql.toString(), (rs, rowNum) -> { + Map map = new HashMap<>(); + map.put("deviceId", deviceId); + + Timestamp ts = rs.getTimestamp("ts"); + map.put("timestamp", ts != null ? ts.toLocalDateTime() : null); + + // 读取 query_data(二进制字段) + byte[] blob = rs.getBytes("query_data"); + if (blob != null) { + // 转为字符串 + String json = new String(blob, StandardCharsets.UTF_8).trim(); + + // 去除 TDengine 中可能存在的外层双引号 + if (json.startsWith("\"") && json.endsWith("\"")) { + json = json.substring(1, json.length() - 1); + } + + // 如果是十六进制字符串,先解码 + if (isHexString(json)) { + json = hexToString(json); + } + + // 统一约定:queryData 始终返回 String,由上层决定是否解析 JSON + map.put("queryData", json); + } else { + // 没有数据时返回空数组字符串 + map.put("queryData", "[]"); + } + + return map; + }); + } + + + + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicecontactmodel/DeviceContactModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicecontactmodel/DeviceContactModelServiceImpl.java index 7621f5f281..bc624c87a6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicecontactmodel/DeviceContactModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicecontactmodel/DeviceContactModelServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.service.devicecontactmodel; import cn.iocoder.yudao.module.iot.dal.dataobject.devicecontactmodel.DeviceContactModelDO; +import cn.iocoder.yudao.module.iot.dal.mysql.deviceattributetype.DeviceAttributeTypeMapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -28,11 +29,14 @@ public class DeviceContactModelServiceImpl implements DeviceContactModelService @Resource private DeviceContactModelMapper deviceContactModelMapper; + @Resource + private DeviceAttributeTypeMapper deviceAttributeTypeMapper; @Override public Long createDeviceContactModel(DeviceContactModelSaveReqVO createReqVO) { // 插入 DeviceContactModelDO deviceContactModel = BeanUtils.toBean(createReqVO, DeviceContactModelDO.class); +// deviceContactModel.setTypeName(deviceAttributeTypeMapper.selectById(createReqVO.getAttributeCode()).getName()); deviceContactModelMapper.insert(deviceContactModel); // 返回 return deviceContactModel.getId(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicemodelattribute/DeviceModelAttributeServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicemodelattribute/DeviceModelAttributeServiceImpl.java index ec751d1b4c..4c672d7485 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicemodelattribute/DeviceModelAttributeServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicemodelattribute/DeviceModelAttributeServiceImpl.java @@ -52,6 +52,7 @@ public class DeviceModelAttributeServiceImpl implements DeviceModelAttributeServ public Long createDeviceModelAttribute(DeviceModelAttributeSaveReqVO createReqVO) { // 插入 DeviceModelAttributeDO deviceModelAttribute = BeanUtils.toBean(createReqVO, DeviceModelAttributeDO.class); +// deviceModelAttribute.setTypeName(deviceAttributeTypeMapper.selectById(createReqVO.getAttributeCode()).getName()); deviceModelAttributeMapper.insert(deviceModelAttribute); // 返回 return deviceModelAttribute.getId(); @@ -90,23 +91,23 @@ public class DeviceModelAttributeServiceImpl implements DeviceModelAttributeServ @Override public PageResult getDeviceModelAttributePage(DeviceModelAttributePageReqVO pageReqVO) { - // 1. 获取设备模型属性分页数据 + // 获取设备模型属性分页数据 PageResult pageResult = deviceModelAttributeMapper.selectPage(pageReqVO); - // 2. 获取所有属性类型并构建映射 - List attributeTypes = deviceAttributeTypeMapper.selectList(); - Map typeNameMap = attributeTypes.stream() - .collect(Collectors.toMap(DeviceAttributeTypeDO::getId, DeviceAttributeTypeDO::getName)); +// // 获取所有属性类型并构建映射 +// List attributeTypes = deviceAttributeTypeMapper.selectList(); +// Map typeNameMap = attributeTypes.stream() +// .collect(Collectors.toMap(DeviceAttributeTypeDO::getId, DeviceAttributeTypeDO::getName)); - // 3. 转换并设置类型名称 + // 转换并设置类型名称 PageResult respPageResult = BeanUtils.toBean(pageResult, DeviceModelAttributeRespVO.class); - respPageResult.getList().forEach(item -> { - String typeName = typeNameMap.get(item.getAttributeType()); - if (typeName != null) { - item.setTypeName(typeName); - } - }); +// respPageResult.getList().forEach(item -> { +// String typeName = typeNameMap.get(item.getAttributeType()); +// if (typeName != null) { +// item.setTypeName(typeName); +// } +// }); return respPageResult; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicewarinningrecord/DeviceWarinningRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicewarinningrecord/DeviceWarinningRecordService.java new file mode 100644 index 0000000000..c5f8a8d0aa --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicewarinningrecord/DeviceWarinningRecordService.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.iot.service.devicewarinningrecord; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.iot.controller.admin.devicewarinningrecord.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.devicewarinningrecord.DeviceWarinningRecordDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 告警记录 Service 接口 + * + * @author 必硕科技 + */ +public interface DeviceWarinningRecordService { + + /** + * 创建告警记录 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDeviceWarinningRecord(@Valid DeviceWarinningRecordSaveReqVO createReqVO); + + /** + * 更新告警记录 + * + * @param updateReqVO 更新信息 + */ + void updateDeviceWarinningRecord(@Valid DeviceWarinningRecordSaveReqVO updateReqVO); + + /** + * 删除告警记录 + * + * @param id 编号 + */ + void deleteDeviceWarinningRecord(Long id); + + /** + * 获得告警记录 + * + * @param id 编号 + * @return 告警记录 + */ + DeviceWarinningRecordDO getDeviceWarinningRecord(Long id); + + /** + * 获得告警记录分页 + * + * @param pageReqVO 分页查询 + * @return 告警记录分页 + */ + PageResult getDeviceWarinningRecordPage(DeviceWarinningRecordPageReqVO pageReqVO); + + List getList(Long id); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicewarinningrecord/DeviceWarinningRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicewarinningrecord/DeviceWarinningRecordServiceImpl.java new file mode 100644 index 0000000000..2957a94081 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicewarinningrecord/DeviceWarinningRecordServiceImpl.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.iot.service.devicewarinningrecord; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.iot.controller.admin.devicewarinningrecord.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.devicewarinningrecord.DeviceWarinningRecordDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.iot.dal.mysql.devicewarinningrecord.DeviceWarinningRecordMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; + +/** + * 告警记录 Service 实现类 + * + * @author 必硕科技 + */ +@Service +@Validated +public class DeviceWarinningRecordServiceImpl implements DeviceWarinningRecordService { + + @Resource + private DeviceWarinningRecordMapper deviceWarinningRecordMapper; + + @Override + public Long createDeviceWarinningRecord(DeviceWarinningRecordSaveReqVO createReqVO) { + // 插入 + DeviceWarinningRecordDO deviceWarinningRecord = BeanUtils.toBean(createReqVO, DeviceWarinningRecordDO.class); + deviceWarinningRecordMapper.insert(deviceWarinningRecord); + // 返回 + return deviceWarinningRecord.getId(); + } + + @Override + public void updateDeviceWarinningRecord(DeviceWarinningRecordSaveReqVO updateReqVO) { + // 校验存在 + validateDeviceWarinningRecordExists(updateReqVO.getId()); + // 更新 + DeviceWarinningRecordDO updateObj = BeanUtils.toBean(updateReqVO, DeviceWarinningRecordDO.class); + deviceWarinningRecordMapper.updateById(updateObj); + } + + @Override + public void deleteDeviceWarinningRecord(Long id) { + // 校验存在 + validateDeviceWarinningRecordExists(id); + // 删除 + deviceWarinningRecordMapper.deleteById(id); + } + + private void validateDeviceWarinningRecordExists(Long id) { + if (deviceWarinningRecordMapper.selectById(id) == null) { + throw exception(DEVICE_WARINNING_RECORD_NOT_EXISTS); + } + } + + @Override + public DeviceWarinningRecordDO getDeviceWarinningRecord(Long id) { + return deviceWarinningRecordMapper.selectById(id); + } + + @Override + public PageResult getDeviceWarinningRecordPage(DeviceWarinningRecordPageReqVO pageReqVO) { + return deviceWarinningRecordMapper.selectPage(pageReqVO); + } + + @Override + public List getList(Long id) { + return deviceWarinningRecordMapper.selectList(Wrappers.lambdaQuery() + .eq(id != null, DeviceWarinningRecordDO::getDeviceId, id)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/DeviceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/DeviceMapper.xml index 56cfd180f5..3804d3e6db 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/DeviceMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/DeviceMapper.xml @@ -19,7 +19,7 @@ mo.code as lineNode, mo.name as lineName, iod.device_code as deviceCode, - iod.device_name as deviceName, + IFNULL(mo.device_name, iod.device_name) as deviceName, iod.status, CASE iod.status WHEN '1' THEN '在线' diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/devicewarinningrecord/DeviceWarinningRecordMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/devicewarinningrecord/DeviceWarinningRecordMapper.xml new file mode 100644 index 0000000000..f96d5e94d8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/devicewarinningrecord/DeviceWarinningRecordMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dashboard/DashboardController.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dashboard/DashboardController.java index d25977123a..989e5011f4 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dashboard/DashboardController.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dashboard/DashboardController.java @@ -11,6 +11,8 @@ import cn.iocoder.yudao.module.erp.service.mold.MoldBrandService; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceMapper; import cn.iocoder.yudao.module.mes.controller.admin.dashboard.vo.*; +import cn.iocoder.yudao.module.mes.controller.admin.dashboard.vo.dashboard.EventStatisticsVO; +import cn.iocoder.yudao.module.mes.controller.admin.dashboard.vo.dashboard.TaskVO; import cn.iocoder.yudao.module.mes.controller.admin.plan.vo.PlanRespVO; import cn.iocoder.yudao.module.mes.dal.dataobject.deviceledger.DeviceLedgerDO; import cn.iocoder.yudao.module.mes.dal.dataobject.dvrepair.DvRepairDO; @@ -485,4 +487,133 @@ public class DashboardController { deviceRepairLineOptionsVO.setSeries(series); return success(deviceRepairLineOptionsVO); } + + + + @GetMapping("/getTaskStatistics") + @Operation(summary = "获得各设备统计个数") + @PreAuthorize("@ss.hasPermission('mes:device-ledger:query')") + public CommonResult getTaskStatistics() { + + EventStatisticsVO vo = new EventStatisticsVO(); + //设备点检 + ticketManagementService.selectCountDeviceInspection(vo ); + //设备保养 + ticketManagementService.selectCountDeviceMaintenance(vo ); + //设备维修 + dvRepairService.selectCountDeviceRepair(vo ); + //模具点检 + moldTicketManagementService.selectCountMoldInspection(vo ); + //模具保养 + moldTicketManagementService.selectCountMoldMaintenance(vo ); + //模具维修 + moldRepairService.selectCountMoldRepair(vo ); + + // 计算占比 + int total = vo.getDeviceInspection() + + vo.getDeviceMaintenance() + + vo.getDeviceRepair() + + vo.getMoldInspection() + + vo.getMoldMaintenance() + + vo.getMoldRepair(); + + if (total > 0) { + vo.setDeviceInspectionProportion(calcPercent(vo.getDeviceInspection(), total)); + vo.setDeviceMaintenanceProportion(calcPercent(vo.getDeviceMaintenance(), total)); + vo.setDeviceRepairProportion(calcPercent(vo.getDeviceRepair(), total)); + + vo.setMoldInspectionProportion(calcPercent(vo.getMoldInspection(), total)); + vo.setMoldMaintenanceProportion(calcPercent(vo.getMoldMaintenance(), total)); + vo.setMoldRepairProportion(calcPercent(vo.getMoldRepair(), total)); + } else { + // 防止除 0 + vo.setDeviceInspectionProportion("0%"); + vo.setDeviceMaintenanceProportion("0%"); + vo.setDeviceRepairProportion("0%"); + vo.setMoldInspectionProportion("0%"); + vo.setMoldMaintenanceProportion("0%"); + vo.setMoldRepairProportion("0%"); + } + + return success(vo); + } + + /** + * 计算百分比,保留整数 + */ + private String calcPercent(int value, int total) { + if (total <= 0) { + return "0%"; + } + int percent = (int) Math.round(value * 100.0 / total); + return percent + "%"; + } + + + + @GetMapping("/getAllTaskList") + @Operation(summary = "获得所有任务") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:bom:query')") + public CommonResult> getAllTaskList() { + List taskVOList = new ArrayList<>(); + + // 设备保养 点检 + List ticketManagementDOList = ticketManagementService.getList(); + for (TicketManagementDO ticketManagementDO : ticketManagementDOList) { + TaskVO taskVO = new TaskVO(); + taskVO.setCode(ticketManagementDO.getPlanNo()); + taskVO.setName(ticketManagementDO.getConfigName()); + if (ticketManagementDO.getPlanType() == 2) { + taskVO.setType("设备保养"); + } else { + taskVO.setType("设备点检"); + } + taskVO.setFinishStatus(ticketManagementDO.getJobStatus()); + taskVO.setResultStatus(ticketManagementDO.getJobResult()); + taskVOList.add(taskVO); + } + + // 设备维修 + List dvRepairDOList = dvRepairService.getList(); + for (DvRepairDO dvRepairDO : dvRepairDOList) { + TaskVO taskVO = new TaskVO(); + taskVO.setCode(dvRepairDO.getRepairCode()); + taskVO.setName(dvRepairDO.getRepairName()); + taskVO.setType("设备维修"); + taskVO.setFinishStatus(String.valueOf(dvRepairDO.getStatus())); + taskVO.setResultStatus(dvRepairDO.getRepairStatus()); + taskVOList.add(taskVO); + } + + // 模具保养 点检 + List moldTicketManagementDOList = moldTicketManagementService.getList(); + for (MoldTicketManagementDO moldTicketManagementDO : moldTicketManagementDOList) { + TaskVO taskVO = new TaskVO(); + taskVO.setCode(moldTicketManagementDO.getPlanNo()); + taskVO.setName(moldTicketManagementDO.getConfigName()); + if (moldTicketManagementDO.getPlanType() == 2) { + taskVO.setType("模具保养"); + } else { + taskVO.setType("模具点检"); + } + taskVO.setFinishStatus(String.valueOf(moldTicketManagementDO.getJobStatus())); + taskVO.setResultStatus(moldTicketManagementDO.getJobResult()); + taskVOList.add(taskVO); + } + + // 模具维修 + List moldRepairDOList = moldRepairService.getList(); + for (MoldRepairDO moldRepairDO : moldRepairDOList) { + TaskVO taskVO = new TaskVO(); + taskVO.setCode(moldRepairDO.getRepairCode()); + taskVO.setName(moldRepairDO.getRepairName()); + taskVO.setType("模具维修"); + taskVO.setFinishStatus(String.valueOf(moldRepairDO.getStatus())); + taskVO.setResultStatus(moldRepairDO.getRepairStatus()); + taskVOList.add(taskVO); + } + + return success(taskVOList); + } } diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/energydevice/EnergyDeviceController.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/energydevice/EnergyDeviceController.java index cd83e1257d..1ef1e1c9eb 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/energydevice/EnergyDeviceController.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/energydevice/EnergyDeviceController.java @@ -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.HourEnergyValueVO; 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; @@ -21,12 +22,8 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; 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; @@ -167,4 +164,14 @@ public class EnergyDeviceController { return success(energyDeviceService.getEnergyDeviceCheckRecord(id)); } + + @GetMapping("/lastEnergyStatistics") + public CommonResult> lastEnergyStatistics(@RequestParam("deviceTypeId") Long deviceTypeId, + @RequestParam("orgId") Long orgId) { + + List hourEnergyValueVOS = energyDeviceService.lastEnergyStatistics(deviceTypeId, orgId); + + return success(hourEnergyValueVOS); + } + } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/energydevice/vo/HourEnergyValueVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/energydevice/vo/HourEnergyValueVO.java new file mode 100644 index 0000000000..c7c0ae429a --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/energydevice/vo/HourEnergyValueVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 能耗管理统计 VO") +@Data +public class HourEnergyValueVO { + + /** 小时(yyyy-MM-dd HH) */ + private String hour; + + /** 按规则计算后的值 */ + private String value; +} diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/energydevice/vo/HourPointData.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/energydevice/vo/HourPointData.java new file mode 100644 index 0000000000..5650d30ae1 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/energydevice/vo/HourPointData.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo; + +import lombok.Data; + +import java.time.LocalDateTime; + + +@Data +public class HourPointData { + private LocalDateTime timestamp; + private String queryData; +} diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/vo/OrganizationRespVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/vo/OrganizationRespVO.java index 6d62fecdff..a5d415d691 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/vo/OrganizationRespVO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/vo/OrganizationRespVO.java @@ -76,4 +76,7 @@ import java.time.LocalDateTime; @ExcelProperty("创建时间") private LocalDateTime createTime; + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String deviceName; + } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/energydevice/EnergyDeviceDO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/energydevice/EnergyDeviceDO.java index eeebe2745e..81950d9ea1 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/energydevice/EnergyDeviceDO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/energydevice/EnergyDeviceDO.java @@ -81,4 +81,6 @@ public class EnergyDeviceDO extends BaseDO { * 计算规则 */ private String rules; + + } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/organization/OrganizationDO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/organization/OrganizationDO.java index a0527490d9..87219f0059 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/organization/OrganizationDO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/organization/OrganizationDO.java @@ -83,4 +83,9 @@ public class OrganizationDO extends BaseDO { */ private String orgType; + /** + * 设备名称 + */ + private String deviceName; + } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/energydevice/EnergyDeviceService.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/energydevice/EnergyDeviceService.java index e916916b56..2bfd3951a3 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/energydevice/EnergyDeviceService.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/energydevice/EnergyDeviceService.java @@ -2,13 +2,13 @@ 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.HourEnergyValueVO; 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; import cn.iocoder.yudao.module.mes.dal.dataobject.energydevice.EnergyDeviceCheckRecordDO; import cn.iocoder.yudao.module.mes.dal.dataobject.energydevice.EnergyDeviceDO; -import org.springframework.web.bind.annotation.RequestParam; import javax.validation.Valid; import java.util.Collection; @@ -113,4 +113,5 @@ public interface EnergyDeviceService { List queryDataRecords(EnergyDeviceConsumptionReqVO deviceConsumptionReqVO); + List lastEnergyStatistics(Long deviceTypeId,Long orgId); } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/energydevice/EnergyDeviceServiceImpl.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/energydevice/EnergyDeviceServiceImpl.java index ecc92e70dd..63d8bb2061 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/energydevice/EnergyDeviceServiceImpl.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/energydevice/EnergyDeviceServiceImpl.java @@ -3,7 +3,9 @@ package cn.iocoder.yudao.module.mes.service.energydevice; import cn.iocoder.yudao.framework.common.pojo.DeviceEdgeData; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.energydevice.vo.HourEnergyValueVO; import cn.iocoder.yudao.module.iot.dal.dataobject.devicecontactmodel.DeviceContactModelDO; import cn.iocoder.yudao.module.iot.dal.mysql.devicecontactmodel.DeviceContactModelMapper; import cn.iocoder.yudao.module.iot.service.device.TDengineService; @@ -28,7 +30,9 @@ import javax.annotation.Resource; import java.math.BigDecimal; import java.text.DecimalFormat; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_ID_DOES_NOT_EXIST; @@ -295,6 +299,81 @@ public class EnergyDeviceServiceImpl implements EnergyDeviceService { return result; } + @Override + public List lastEnergyStatistics(Long deviceTypeId, Long orgId) { + + // 1. 找最新的能耗设备 + EnergyDeviceDO energyDevice = energyDeviceMapper.selectOne( + Wrappers.lambdaQuery() + .eq(EnergyDeviceDO::getDeviceTypeId, deviceTypeId) + .eq(EnergyDeviceDO::getOrgId, orgId) + .orderByDesc(EnergyDeviceDO::getCreateTime) + .last("LIMIT 1") + ); + + if (energyDevice == null || StringUtils.isBlank(energyDevice.getRules())) { + return Collections.emptyList(); + } + + // 2. 解析规则 + List rules = JsonUtils.parseArray(energyDevice.getRules(), OperationRulesVO.class); + if (rules.isEmpty()) return Collections.emptyList(); + + // 3. 收集设备列表 + Set deviceIds = rules.stream() + .map(OperationRulesVO::getDeviceId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (deviceIds.isEmpty()) return Collections.emptyList(); + + // 4. 时间范围:最近 7 小时 + LocalDateTime end = LocalDateTime.now(); + LocalDateTime start = end.minusHours(7); + + DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH"); + + // hour -> deviceId -> 数据缓存 + Map> hourCacheMap = new LinkedHashMap<>(); + + // 5. 查询每个设备的原始数据 + for (Long deviceId : deviceIds) { + List> rawData = tDengineService.queryLastDataByHour(deviceId, start, end); + + for (Map row : rawData) { + LocalDateTime ts = (LocalDateTime) row.get("timestamp"); + String hourKey = ts.format(hourFormatter); + + TimePointCache cache = new TimePointCache(); + cache.setTimestamp(ts); + cache.setQueryData((String) row.get("queryData")); + + // 每小时最新覆盖之前的 + hourCacheMap.computeIfAbsent(hourKey, k -> new HashMap<>()) + .put(deviceId, cache); + } + } + + // 6. 生成每小时结果,补齐缺失小时 + List result = new ArrayList<>(); + for (int i = 0; i < 7; i++) { + LocalDateTime hourTime = start.plusHours(i); + String hourKey = hourTime.format(hourFormatter); + + Map deviceCache = hourCacheMap.getOrDefault(hourKey, new HashMap<>()); + Double value = calculateByRules(rules, deviceCache); + + HourEnergyValueVO vo = new HourEnergyValueVO(); + vo.setHour(hourKey); + vo.setValue(formatDouble(value)); + + result.add(vo); + } + + return result; + } + + + // =================== 核心方法 =================== /** 查询设备列表 */ @@ -355,7 +434,7 @@ public class EnergyDeviceServiceImpl implements EnergyDeviceService { vo.setCreateTime(device.getCreateTime()); vo.setUpdateTime(device.getUpdateTime()); vo.setRules(device.getRules()); - + vo.setDeviceTypeName(device.getDeviceTypeName()); vo.setEnergyConsumption(formatDouble(lastTotal - firstTotal)); vo.setEarliestDataTime(req.getStartTime()); vo.setLatestDataTime(req.getEndTime()); @@ -459,11 +538,25 @@ public class EnergyDeviceServiceImpl implements EnergyDeviceService { p.setPointId(r.getPointId()); p.setOperator(r.getOperator()); - Double firstVal = getPointValue(firstCache.get(r.getDeviceId()), r.getPointId()); - Double lastVal = getPointValue(lastCache.get(r.getDeviceId()), r.getPointId()); + // ====== 这里是改动点 ====== + TimePointCache first = firstCache.get(r.getDeviceId()); + TimePointCache last = lastCache.get(r.getDeviceId()); + + Double firstVal = getPointValue(first, r.getPointId()); + Double lastVal = getPointValue(last, r.getPointId()); + p.setEarliestValue(formatDouble(firstVal)); p.setLatestValue(formatDouble(lastVal)); - p.setDifference(formatDouble((lastVal != null ? lastVal : 0.0) - (firstVal != null ? firstVal : 0.0))); + p.setDifference(formatDouble( + (lastVal != null ? lastVal : 0.0) - (firstVal != null ? firstVal : 0.0) + )); + + if (first != null) { + p.setEarliestTime(formatToSecond(first.getTimestamp())); + } + if (last != null) { + p.setLatestTime(formatToSecond(last.getTimestamp())); + } // 从本地数据库获取点位名称和单位 DeviceContactModelDO pointInfo = pointInfoMap.get(r.getPointId()); @@ -479,6 +572,30 @@ public class EnergyDeviceServiceImpl implements EnergyDeviceService { return result; } + private String formatToSecond(Object timestamp) { + if (timestamp == null) { + return ""; + } + try { + String ts = timestamp.toString(); + + // ISO: 2026-01-22T17:18:50.092 + if (ts.contains("T")) { + ts = ts.replace("T", " "); + } + + // 去掉毫秒 + int dotIndex = ts.indexOf("."); + if (dotIndex > 0) { + ts = ts.substring(0, dotIndex); + } + + return ts; + } catch (Exception e) { + return timestamp.toString(); + } + } + /** 格式化 double */ private String formatDouble(Double value) { if (value == null) return "0.0";