From 6923984f8fca71140b8873a1376e3693fa03ae48 Mon Sep 17 00:00:00 2001 From: HuangHuiKang Date: Fri, 17 Apr 2026 14:02:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=AE=8C=E6=88=90app=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E6=8A=A5=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../admin/device/DeviceController.java | 6 + .../enums/DeviceRateTrendPeriodEnum.java | 71 ++++++++++ .../device/vo/DeviceRateTrendPointRespVO.java | 21 +++ .../admin/device/vo/DeviceRateTrendReqVO.java | 27 ++++ .../DeviceOperationRecordController.java | 18 ++- .../iot/dal/mysql/device/DeviceMapper.java | 5 + .../iot/service/device/DeviceService.java | 2 + .../iot/service/device/DeviceServiceImpl.java | 131 +++++++++++++++++- .../DeviceOperationRecordService.java | 6 +- .../DeviceOperationRecordServiceImpl.java | 107 ++++++++++++-- .../resources/mapper/device/DeviceMapper.xml | 26 ++++ 12 files changed, 404 insertions(+), 17 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/enums/DeviceRateTrendPeriodEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceRateTrendPointRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceRateTrendReqVO.java 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 bbc66ba99..81f57e0f2 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 @@ -52,6 +52,7 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_ATTRIBUTE_NOT_EXISTS = new ErrorCode(1_003_000_006, "设备属性不存在"); ErrorCode DEVICE_ATTRIBUTE_TYPE_NOT_EXISTS = new ErrorCode(1_003_000_007, "采集点分类不存在"); ErrorCode DEVICE_CODE_EXISTS = new ErrorCode(1_003_000_000, "采集点编码已存在"); + ErrorCode DEVICE_RATE_TREND_PERIOD_INVALID = new ErrorCode(1_003_000_100, "设备趋势查询时间区间参数不正确"); ErrorCode DEVICE_ATTRIBUTE_TYPE_REFERENCES_EXISTS = new ErrorCode(1_003_000_008, "存在采集点类型已被引用,请先删除对应引用"); ErrorCode ENDPOINT_DOES_NOT_EXIS = new ErrorCode(1_003_000_009, "暂未设置设备端点"); ErrorCode DEVICE_DOES_NOT_EXIST= new ErrorCode(1_003_000_010, "该采集设备不存在"); 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 a4a57f7fd..da69cda27 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 @@ -256,6 +256,12 @@ public class DeviceController { return success(deviceOperationalStatus); } + @GetMapping("/deviceRateTrend") + @Operation(summary = "按天查询设备整体开机率和稼动率趋势") + public CommonResult> getDeviceRateTrend(@Valid DeviceRateTrendReqVO reqVO) { + return success(deviceService.getDeviceRateTrend(reqVO)); + } + @GetMapping("/getDeviceOverview") @Operation(summary = "获取设备概况") public CommonResult getDeviceOverview() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/enums/DeviceRateTrendPeriodEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/enums/DeviceRateTrendPeriodEnum.java new file mode 100644 index 000000000..ece8cfba2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/enums/DeviceRateTrendPeriodEnum.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.time.LocalDate; +import java.time.temporal.TemporalAdjusters; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_RATE_TREND_PERIOD_INVALID; + +@Getter +@AllArgsConstructor +public enum DeviceRateTrendPeriodEnum { + + LAST_WEEK("LAST_WEEK", "上周") { + @Override + public DateRange resolve(LocalDate today) { + LocalDate start = today.minusWeeks(1).with(java.time.DayOfWeek.MONDAY); + return new DateRange(start, start.plusDays(6)); + } + }, + THIS_WEEK("THIS_WEEK", "本周") { + @Override + public DateRange resolve(LocalDate today) { + LocalDate start = today.with(java.time.DayOfWeek.MONDAY); + return new DateRange(start, today.minusDays(1)); + } + }, + LAST_7_DAYS("LAST_7_DAYS", "近7日") { + @Override + public DateRange resolve(LocalDate today) { + return new DateRange(today.minusDays(7), today.minusDays(1)); + } + }, + LAST_MONTH("LAST_MONTH", "上月") { + @Override + public DateRange resolve(LocalDate today) { + LocalDate start = today.minusMonths(1).withDayOfMonth(1); + return new DateRange(start, start.with(TemporalAdjusters.lastDayOfMonth())); + } + }, + THIS_MONTH("THIS_MONTH", "本月") { + @Override + public DateRange resolve(LocalDate today) { + LocalDate start = today.withDayOfMonth(1); + return new DateRange(start, today.minusDays(1)); + } + }; + + private final String code; + private final String name; + + public abstract DateRange resolve(LocalDate today); + + public static DeviceRateTrendPeriodEnum valueOfCode(String code) { + for (DeviceRateTrendPeriodEnum value : values()) { + if (value.code.equalsIgnoreCase(code)) { + return value; + } + } + throw exception(DEVICE_RATE_TREND_PERIOD_INVALID); + } + + @Getter + @AllArgsConstructor + public static class DateRange { + private final LocalDate start; + private final LocalDate end; + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceRateTrendPointRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceRateTrendPointRespVO.java new file mode 100644 index 000000000..d1cb962eb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceRateTrendPointRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "管理后台 - 设备开机率/稼动率趋势点 Response VO") +public class DeviceRateTrendPointRespVO { + + @Schema(description = "日期") + private String day; + + @Schema(description = "当天整体开机率") + private String powerOnRate; + + @Schema(description = "当天整体稼动率") + private String utilizationRate; + + @Schema(description = "当天参与统计设备数") + private Integer deviceCount; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceRateTrendReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceRateTrendReqVO.java new file mode 100644 index 000000000..e4f6bb0e4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceRateTrendReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "管理后台 - 设备开机率/稼动率趋势 Request VO") +public class DeviceRateTrendReqVO { + + @Schema(description = "设备编码") + private String deviceCode; + + @Schema(description = "设备名称") + private String deviceName; + + @Schema(description = "设备ID集合,逗号分隔") + private String ids; + + @Schema(description = "时间区间:LAST_WEEK/THIS_WEEK/LAST_7_DAYS/LAST_MONTH/THIS_MONTH") + private String period; + + @Schema(description = "是否只统计排产设备,默认 true") + private Boolean onlyScheduled; + + @Schema(description = "是否跳过节假日,默认 false") + private Boolean skipHoliday; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/deviceoperationrecord/DeviceOperationRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/deviceoperationrecord/DeviceOperationRecordController.java index 16b4178d5..cce051eee 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/deviceoperationrecord/DeviceOperationRecordController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/deviceoperationrecord/DeviceOperationRecordController.java @@ -103,10 +103,24 @@ public class DeviceOperationRecordController { return success(pageResult); } + @GetMapping("/deviceOperationPageList") + @Operation(summary = "设备运行报表列表") + @PreAuthorize("@ss.hasPermission('iot:device-operation-record:query')") + public CommonResult> deviceOperationPageList(@Valid DeviceTotalTimeRecordReqVO pageReqVO) { + return success(deviceOperationRecordService.deviceOperationPageList(pageReqVO)); + } + + @GetMapping("/deviceRateTrendByDeviceId") + @Operation(summary = "根据设备ID查询某个设备近7日开机率和稼动率") + @PreAuthorize("@ss.hasPermission('iot:device-operation-record:query')") + public CommonResult> getDeviceRateTrendByDeviceId(@RequestParam("deviceId") Long deviceId) { + return success(deviceOperationRecordService.getDeviceRateTrendByDeviceId(deviceId)); + } + @GetMapping("/deviceOperationList") @Operation(summary = "产线设备运行开机率/稼动率-大屏") - // @PreAuthorize("@ss.hasPermission('iot:device-operation-record:query')") + @PreAuthorize("@ss.hasPermission('iot:device-operation-record:query')") public CommonResult> deviceOperationList(@Valid DeviceTotalTimeRecordReqVO pageReqVO) { List deviceTotalTimeRecordRespVOList = deviceOperationRecordService.deviceOperationList(pageReqVO); return success(deviceTotalTimeRecordRespVOList); @@ -130,4 +144,4 @@ public class DeviceOperationRecordController { // 导出 Excel ExcelUtils.write(response, fileName, "数据", DeviceTotalTimeRecordRespVO.class,pageResult.getList()); } -} \ 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/device/DeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java index 08aa7b712..294e1334b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java @@ -15,6 +15,7 @@ import org.apache.ibatis.annotations.Select; import java.util.Arrays; import java.util.Collection; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -135,6 +136,10 @@ public interface DeviceMapper extends BaseMapperX { List selectListIncludeDeletedByIds(@Param("ids") Collection ids); + List selectScheduledDvIds(@Param("requestIds") Collection requestIds); + + List selectHolidayDays(@Param("startDay") Date startDay, @Param("endDay") Date endDay); + } 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 31e699222..a39b9abd5 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 @@ -138,6 +138,8 @@ public interface DeviceService { DeviceOverviewRespVO getDeviceOverview(); + List getDeviceRateTrend(DeviceRateTrendReqVO reqVO); + List> getMultiDeviceAttributes(Long goviewId); List getDeviceAttributeList(Long deviceId); 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 4e9402434..eefa31923 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 @@ -5,14 +5,18 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.DeviceConnectionStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.opc.OpcUtils; +import cn.iocoder.yudao.module.iot.controller.admin.device.enums.DeviceRateTrendPeriodEnum; import cn.iocoder.yudao.module.iot.controller.admin.device.enums.DeviceStatusEnum; import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.utils.CronExpressionUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.scheduler.TaskSchedulerManager; import cn.iocoder.yudao.module.iot.controller.admin.device.utils.DataTypeParseUtil; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*; import cn.iocoder.yudao.module.iot.controller.admin.devicecontactmodel.vo.DeviceContactModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.deviceoperationrecord.vo.DeviceTotalTimeRecordReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.deviceoperationrecord.vo.DeviceTotalTimeRecordRespVO; import cn.iocoder.yudao.module.iot.controller.admin.mqttdatarecord.vo.MqttDataRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.deviceattributetype.DeviceAttributeTypeDO; @@ -31,6 +35,8 @@ import cn.iocoder.yudao.module.iot.dal.mysql.devicemodel.DeviceModelMapper; import cn.iocoder.yudao.module.iot.dal.mysql.devicemodelattribute.DeviceModelAttributeMapper; import cn.iocoder.yudao.module.iot.dal.mysql.devicemodelrules.DeviceModelRulesMapper; import cn.iocoder.yudao.module.iot.dal.mysql.deviceoperationrecord.DeviceOperationRecordMapper; +import cn.iocoder.yudao.module.iot.service.deviceoperationrecord.DeviceOperationRecordService; + import cn.iocoder.yudao.module.iot.dal.mysql.devicepointrules.DevicePointRulesMapper; import cn.iocoder.yudao.module.iot.dal.mysql.gateway.GatewayMapper; import cn.iocoder.yudao.module.iot.dal.mysql.mqttdatarecord.MqttDataRecordMapper; @@ -57,7 +63,10 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.sql.Timestamp; import java.text.SimpleDateFormat; +import java.time.Duration; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.function.Function; @@ -114,6 +123,8 @@ public class DeviceServiceImpl implements DeviceService { @Resource private DeviceOperationRecordMapper deviceOperationRecordMapper; + @Resource + private DeviceOperationRecordService deviceOperationRecordService; @Resource private IMqttservice mqttService; @@ -1279,7 +1290,7 @@ public class DeviceServiceImpl implements DeviceService { standbyCount++; } else if ("3".equals(status)) { faultCount++; - } else if ("0".equals(status)){ + } else { offlineCount++; } } @@ -1725,6 +1736,124 @@ public class DeviceServiceImpl implements DeviceService { )); } + /** + * 按时间区间查询设备整体开机率、稼动率日趋势。 + * 按天复用 deviceOperationPage 统计单设备数据后求平均。 + */ + @Override + public List getDeviceRateTrend(DeviceRateTrendReqVO reqVO) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND); + // 根据 period 解析查询日期范围,不包含当天 + DeviceRateTrendPeriodEnum.DateRange dateRange = DeviceRateTrendPeriodEnum.valueOfCode(reqVO.getPeriod()).resolve(LocalDate.now()); + LocalDateTime startDateTime = dateRange.getStart().atStartOfDay(); + LocalDateTime endDateTime = dateRange.getEnd().atTime(LocalTime.MAX).withNano(0); + // 默认只统计排产设备,这里先得到最终参与统计的设备集合 + String filteredIds = buildFilteredDeviceIds(reqVO); + + List result = new ArrayList<>(); + for (LocalDate day = startDateTime.toLocalDate(); !day.isAfter(endDateTime.toLocalDate()); day = day.plusDays(1)) { + // 跳过节假日时,这一天不查询,也不返回 + if (Boolean.TRUE.equals(reqVO.getSkipHoliday()) && isHoliday(day)) { + continue; + } + LocalDateTime dayStart = day.atStartOfDay(); + LocalDateTime dayEnd = day.atTime(LocalTime.MAX).withNano(0); + // 复用现有 deviceOperationPage,查出当天每台设备的开机率、稼动率基础数据 + List deviceDayList = queryDeviceDayList(reqVO, filteredIds, dayStart.format(formatter), dayEnd.format(formatter)); + + double powerOnRateSum = 0D; + double utilizationRateSum = 0D; + int deviceCount = deviceDayList.size(); + + for (DeviceTotalTimeRecordRespVO record : deviceDayList) { + powerOnRateSum += parsePercentValue(record.getPowerOnRate()); + utilizationRateSum += parsePercentValue(record.getUtilizationRate()); + } + + + DeviceRateTrendPointRespVO point = new DeviceRateTrendPointRespVO(); + point.setDay(day.toString()); + point.setDeviceCount(deviceCount); + point.setPowerOnRate(formatPercentValue(deviceCount > 0 ? powerOnRateSum / deviceCount : 0D)); + point.setUtilizationRate(formatPercentValue(deviceCount > 0 ? utilizationRateSum / deviceCount : 0D)); + result.add(point); + + } + return result; + } + + private double parsePercentValue(String percent) { + if (StringUtils.isBlank(percent)) { + return 0D; + } + String value = percent.trim(); + if (value.endsWith("%")) { + value = value.substring(0, value.length() - 1); + } + if (StringUtils.isBlank(value)) { + return 0D; + } + return Double.parseDouble(value); + } + + private String formatPercentValue(double value) { + return String.format("%.2f%%", value); + } + + + + private List queryDeviceDayList(DeviceRateTrendReqVO reqVO, String ids, String startTime, String endTime) { + DeviceTotalTimeRecordReqVO pageReqVO = + new DeviceTotalTimeRecordReqVO(); + pageReqVO.setDeviceCode(reqVO.getDeviceCode()); + pageReqVO.setDeviceName(reqVO.getDeviceName()); + pageReqVO.setIds(ids); + pageReqVO.setStartTime(startTime); + pageReqVO.setEndTime(endTime); + return deviceOperationRecordService.deviceOperationPageList(pageReqVO); + } + + private String buildFilteredDeviceIds(DeviceRateTrendReqVO reqVO) { + boolean onlyScheduled = reqVO.getOnlyScheduled() == null || reqVO.getOnlyScheduled(); + if (!onlyScheduled) { + return reqVO.getIds(); + } + + Collection requestIds = parseIds(reqVO.getIds()); + List filteredDvIds = deviceMapper.selectScheduledDvIds(requestIds); + + if (StringUtils.isNotBlank(reqVO.getIds())) { + Set requestIdSet = new HashSet<>(requestIds); + filteredDvIds = filteredDvIds.stream().filter(requestIdSet::contains).collect(Collectors.toList()); + } + + if (filteredDvIds.isEmpty()) { + return "-1"; + } + return filteredDvIds.stream().map(String::valueOf).collect(Collectors.joining(",")); + } + + private boolean isHoliday(LocalDate day) { + List holidays = deviceMapper.selectHolidayDays(java.sql.Date.valueOf(day), java.sql.Date.valueOf(day.plusDays(1))); + return !CollectionUtils.isEmpty(holidays); + } + + private String toPercent(double value) { + return String.format("%.2f%%", value * 100); + } + + private Collection parseIds(String ids) { + if (StringUtils.isBlank(ids)) { + return Collections.emptyList(); + } + return Arrays.stream(ids.split(",")) + .map(String::trim) + .filter(StringUtils::isNotBlank) + .map(Long::valueOf) + .collect(Collectors.toList()); + } + + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/deviceoperationrecord/DeviceOperationRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/deviceoperationrecord/DeviceOperationRecordService.java index 37614e7af..92ed6f461 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/deviceoperationrecord/DeviceOperationRecordService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/deviceoperationrecord/DeviceOperationRecordService.java @@ -54,5 +54,9 @@ public interface DeviceOperationRecordService { PageResult deviceOperationPage(@Valid DeviceTotalTimeRecordReqVO pageReqVO); + List deviceOperationPageList(@Valid DeviceTotalTimeRecordReqVO pageReqVO); + + List getDeviceRateTrendByDeviceId(Long deviceId); + List deviceOperationList(@Valid DeviceTotalTimeRecordReqVO pageReqVO); -} \ 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/deviceoperationrecord/DeviceOperationRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/deviceoperationrecord/DeviceOperationRecordServiceImpl.java index c388d2c1a..cc6c475b9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/deviceoperationrecord/DeviceOperationRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/deviceoperationrecord/DeviceOperationRecordServiceImpl.java @@ -13,6 +13,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.transaction.annotation.Transactional; import java.time.Duration; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; @@ -144,6 +145,79 @@ public class DeviceOperationRecordServiceImpl implements DeviceOperationRecordSe } + @Override + public List deviceOperationPageList(DeviceTotalTimeRecordReqVO pageReqVO) { + + List deviceList = + deviceOperationRecordMapper.selectDeviceListFromMySQL(pageReqVO); + + if (CollectionUtils.isEmpty(deviceList)) { + return Collections.emptyList(); + } + + List deviceIds = deviceList.stream() + .map(DeviceTotalTimeRecordRespVO::getId) + .collect(Collectors.toList()); + + List> statsList = + deviceOperationRecordMapper.selectDeviceStatsFromTD( + deviceIds, + pageReqVO.getStartTime(), + pageReqVO.getEndTime() + ); + + Map tdStatsMap = convertStatsListToMap(statsList); + + List result = new ArrayList<>(); + for (DeviceTotalTimeRecordRespVO device : deviceList) { + DeviceTotalTimeRecordRespVO stats = tdStatsMap.get(device.getId()); + if (stats != null) { + device.setTotalOfflineTime(stats.getTotalOfflineTime()); + device.setTotalRunningTime(stats.getTotalRunningTime()); + device.setTotalStandbyTime(stats.getTotalStandbyTime()); + device.setTotalFaultTime(stats.getTotalFaultTime()); + } else { + device.setTotalOfflineTime(0); + device.setTotalRunningTime(0); + device.setTotalStandbyTime(0); + device.setTotalFaultTime(0); + } + result.add(device); + } + + calculateAndSetConvertedValues(result, pageReqVO); + result.sort(Comparator.comparingDouble(this::parsePercentValue).reversed()); + return result; + } + + @Override + public List getDeviceRateTrendByDeviceId(Long deviceId) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + List result = new ArrayList<>(); + + for (int offset = 6; offset >= 0; offset--) { + LocalDate day = LocalDate.now().minusDays(offset); + LocalDateTime dayStart = day.atStartOfDay(); + LocalDateTime dayEnd = day.atTime(LocalTime.MAX).withNano(0); + + DeviceTotalTimeRecordReqVO reqVO = new DeviceTotalTimeRecordReqVO(); + reqVO.setIds(String.valueOf(deviceId)); + reqVO.setStartTime(dayStart.format(formatter)); + reqVO.setEndTime(dayEnd.format(formatter)); + + List dayList = deviceOperationPageList(reqVO); + DeviceTotalTimeRecordRespVO record = CollectionUtils.isNotEmpty(dayList) ? dayList.get(0) : null; + + DeviceOperationRateTrendRespVO trend = new DeviceOperationRateTrendRespVO(); + trend.setDay(day.toString()); + trend.setPowerOnRate(record != null ? record.getPowerOnRate() : "0%"); + trend.setUtilizationRate(record != null ? record.getUtilizationRate() : "0%"); + result.add(trend); + } + + return result; + } + @Override public List deviceOperationList(DeviceTotalTimeRecordReqVO deviceTotalTimeRecordReqVO) { @@ -242,6 +316,13 @@ public class DeviceOperationRecordServiceImpl implements DeviceOperationRecordSe return lineList; } + private double parsePercentValue(DeviceTotalTimeRecordRespVO record) { + if (record == null || StringUtils.isBlank(record.getUtilizationRate())) { + return 0D; + } + return Double.parseDouble(record.getUtilizationRate().replace("%", "").trim()); + } + private void calculateAndSetConvertedValues( List records, DeviceTotalTimeRecordReqVO reqVO) { @@ -269,19 +350,19 @@ public class DeviceOperationRecordServiceImpl implements DeviceOperationRecordSe // 在线时间 = 运行 + 待机 + 故障 double onlineSec = runningSec + standbySec + faultSec; - + double totalSec = offlineSec + onlineSec; // 计算总时间(根据筛选时间) - double totalSec = 0; - if (StringUtils.isNotBlank(startTimeStr) && StringUtils.isNotBlank(endTimeStr)) { - - DateTimeFormatter formatter = - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - - LocalDateTime start = LocalDateTime.parse(startTimeStr, formatter); - LocalDateTime end = LocalDateTime.parse(endTimeStr, formatter); - - totalSec = Duration.between(start, end).getSeconds(); - } +// double totalSec = 0; +// if (StringUtils.isNotBlank(startTimeStr) && StringUtils.isNotBlank(endTimeStr)) { +// +// DateTimeFormatter formatter = +// DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); +// +// LocalDateTime start = LocalDateTime.parse(startTimeStr, formatter); +// LocalDateTime end = LocalDateTime.parse(endTimeStr, formatter); +// +// totalSec = Duration.between(start, end).getSeconds(); +// } // 防止负数或异常 if (totalSec < 0) { @@ -393,4 +474,4 @@ public class DeviceOperationRecordServiceImpl implements DeviceOperationRecordSe return 0; } -} \ 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 a73de9534..d7a95e1b6 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 @@ -246,5 +246,31 @@ + + + +