Pārlūkot izejas kodu

多线程计算

wukai 1 gadu atpakaļ
vecāks
revīzija
7359101d39
42 mainītis faili ar 1536 papildinājumiem un 762 dzēšanām
  1. 4 0
      ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
  2. 35 3
      ruoyi-admin/src/main/java/com/ruoyi/biz/controller/ApiController.java
  3. 160 0
      ruoyi-admin/src/main/java/com/ruoyi/biz/controller/DemoController.java
  4. 18 20
      ruoyi-admin/src/main/java/com/ruoyi/biz/controller/TwinDeviceController.java
  5. 1 1
      ruoyi-admin/src/main/java/com/ruoyi/biz/controller/TwinRecordAlarmsController.java
  6. 1 1
      ruoyi-admin/src/main/java/com/ruoyi/biz/domain/TwinCalc2hr.java
  7. 85 54
      ruoyi-admin/src/main/java/com/ruoyi/biz/domain/TwinDevice.java
  8. 23 6
      ruoyi-admin/src/main/java/com/ruoyi/biz/domain/TwinRecordAlarms.java
  9. 22 15
      ruoyi-admin/src/main/java/com/ruoyi/biz/mapper/TwinDeviceMapper.java
  10. 1 1
      ruoyi-admin/src/main/java/com/ruoyi/biz/mapper/TwinRecordAlarmsMapper.java
  11. 1 8
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/IIotService.java
  12. 35 0
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITaskService.java
  13. 0 34
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITwinCalc2hrService.java
  14. 8 8
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITwinDataService.java
  15. 25 17
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITwinDeviceService.java
  16. 1 1
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITwinRecordAlarmsService.java
  17. 312 0
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/AsyncServiceImpl.java
  18. 14 47
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/IotServiceImpl.java
  19. 56 0
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/IotTokenServiceImpl.java
  20. 168 0
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/TaskServiceImpl.java
  21. 0 305
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/TwinCalc2hrServiceImpl.java
  22. 28 25
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/TwinDeviceServiceImpl.java
  23. 1 1
      ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/TwinRecordAlarmsServiceImpl.java
  24. 57 0
      ruoyi-admin/src/main/java/com/ruoyi/biz/tools/IotTools.java
  25. 16 9
      ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml
  26. 47 30
      ruoyi-admin/src/main/resources/mapper/biz/TwinDeviceMapper.xml
  27. 6 1
      ruoyi-admin/src/main/resources/mapper/biz/TwinRecordAlarmsMapper.xml
  28. 49 0
      ruoyi-admin/src/main/resources/templates/biz/biz/add.html
  29. 122 0
      ruoyi-admin/src/main/resources/templates/biz/biz/biz.html
  30. 50 0
      ruoyi-admin/src/main/resources/templates/biz/biz/edit.html
  31. 37 31
      ruoyi-admin/src/main/resources/templates/biz/device/add.html
  32. 35 27
      ruoyi-admin/src/main/resources/templates/biz/device/device.html
  33. 37 48
      ruoyi-admin/src/main/resources/templates/biz/device/edit.html
  34. 6 0
      ruoyi-admin/src/main/resources/templates/biz/record/add.html
  35. 6 0
      ruoyi-admin/src/main/resources/templates/biz/record/edit.html
  36. 8 0
      ruoyi-admin/src/main/resources/templates/biz/record/record.html
  37. 32 12
      ruoyi-admin/src/test/java/com/jjt/DataPF.java
  38. 0 2
      ruoyi-admin/src/test/java/com/jjt/DataProcess.java
  39. 1 14
      ruoyi-admin/src/test/java/com/jjt/DataProcess2hr.java
  40. 0 20
      ruoyi-admin/src/test/java/com/jjt/TwinApplicationTests.java
  41. 25 21
      ruoyi-common/src/main/java/com/ruoyi/common/config/thread/ThreadPoolConfig.java
  42. 3 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/Tools.java

+ 4 - 0
ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java

@@ -3,12 +3,16 @@ package com.ruoyi;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.scheduling.annotation.EnableAsync;
 
 /**
  * 启动程序
  *
  * @author ruoyi
  */
+@EnableAsync
+@EnableCaching
 @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
 public class RuoYiApplication {
     public static void main(String[] args) {

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 35 - 3
ruoyi-admin/src/main/java/com/ruoyi/biz/controller/ApiController.java


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 160 - 0
ruoyi-admin/src/main/java/com/ruoyi/biz/controller/DemoController.java


+ 18 - 20
ruoyi-admin/src/main/java/com/ruoyi/biz/controller/TwinDeviceController.java

@@ -19,34 +19,32 @@ import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.common.core.page.TableDataInfo;
 
-import javax.annotation.Resource;
-
 /**
  * 设备管理Controller
- *
+ * 
  * @author ruoyi
- * @date 2024-05-07
+ * @date 2024-05-19
  */
 @Controller
-@RequestMapping("/biz/device")
+@RequestMapping("/biz/biz")
 public class TwinDeviceController extends BaseController
 {
-    private String prefix = "biz/device";
+    private String prefix = "biz/biz";
 
-    @Resource
+    @Autowired
     private ITwinDeviceService twinDeviceService;
 
-    @RequiresPermissions("biz:device:view")
+    @RequiresPermissions("biz:biz:view")
     @GetMapping()
-    public String device()
+    public String biz()
     {
-        return prefix + "/device";
+        return prefix + "/biz";
     }
 
     /**
      * 查询设备管理列表
      */
-    @RequiresPermissions("biz:device:list")
+    @RequiresPermissions("biz:biz:list")
     @PostMapping("/list")
     @ResponseBody
     public TableDataInfo list(TwinDevice twinDevice)
@@ -59,7 +57,7 @@ public class TwinDeviceController extends BaseController
     /**
      * 导出设备管理列表
      */
-    @RequiresPermissions("biz:device:export")
+    @RequiresPermissions("biz:biz:export")
     @Log(title = "设备管理", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     @ResponseBody
@@ -82,7 +80,7 @@ public class TwinDeviceController extends BaseController
     /**
      * 新增保存设备管理
      */
-    @RequiresPermissions("biz:device:add")
+    @RequiresPermissions("biz:biz:add")
     @Log(title = "设备管理", businessType = BusinessType.INSERT)
     @PostMapping("/add")
     @ResponseBody
@@ -94,11 +92,11 @@ public class TwinDeviceController extends BaseController
     /**
      * 修改设备管理
      */
-    @RequiresPermissions("biz:device:edit")
-    @GetMapping("/edit/{ID}")
-    public String edit(@PathVariable("ID") Long ID, ModelMap mmap)
+    @RequiresPermissions("biz:biz:edit")
+    @GetMapping("/edit/{id}")
+    public String edit(@PathVariable("id") Long id, ModelMap mmap)
     {
-        TwinDevice twinDevice = twinDeviceService.selectTwinDeviceByID(ID);
+        TwinDevice twinDevice = twinDeviceService.selectTwinDeviceById(id);
         mmap.put("twinDevice", twinDevice);
         return prefix + "/edit";
     }
@@ -106,7 +104,7 @@ public class TwinDeviceController extends BaseController
     /**
      * 修改保存设备管理
      */
-    @RequiresPermissions("biz:device:edit")
+    @RequiresPermissions("biz:biz:edit")
     @Log(title = "设备管理", businessType = BusinessType.UPDATE)
     @PostMapping("/edit")
     @ResponseBody
@@ -118,12 +116,12 @@ public class TwinDeviceController extends BaseController
     /**
      * 删除设备管理
      */
-    @RequiresPermissions("biz:device:remove")
+    @RequiresPermissions("biz:biz:remove")
     @Log(title = "设备管理", businessType = BusinessType.DELETE)
     @PostMapping( "/remove")
     @ResponseBody
     public AjaxResult remove(String ids)
     {
-        return toAjax(twinDeviceService.deleteTwinDeviceByIDs(ids));
+        return toAjax(twinDeviceService.deleteTwinDeviceByIds(ids));
     }
 }

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/biz/controller/TwinRecordAlarmsController.java

@@ -23,7 +23,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
  * 告警数据记录Controller
  * 
  * @author ruoyi
- * @date 2024-05-15
+ * @date 2024-05-21
  */
 @Controller
 @RequestMapping("/biz/record")

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/biz/domain/TwinCalc2hr.java

@@ -383,7 +383,7 @@ public class TwinCalc2hr extends BaseEntity {
     }
 
     public Object[] toArray() {
-        Object[] objects = {this.dataDate, this.timePeriod, this.deviceId, this.lengthA, this.openTimeA, this.closeTimeA, this.lengthB, this.closeTimeB, this.openTimeB, this.weight, this.weightA, this.weightB, this.alarm, this.stop1A, this.stop2A, this.stop3A, this.stop1B, this.stop2B, this.stop3B};
+        Object[] objects = {this.dataDate, this.timePeriod, this.deviceId, this.lengthA, this.openTimeA, this.closeTimeA, this.lengthB, this.closeTimeB, this.openTimeB, this.weight, this.weightA, this.weightB, this.alarm, this.stop1A, this.stop2A, this.stop3A, this.stop1B, this.stop2B, this.stop3B, getRemark()};
         return objects;
     }
 

+ 85 - 54
ruoyi-admin/src/main/java/com/ruoyi/biz/domain/TwinDevice.java

@@ -1,126 +1,157 @@
 package com.ruoyi.biz.domain;
 
-import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.Date;
 
 /**
  * 设备管理对象 twin_device
  *
  * @author ruoyi
- * @date 2024-05-07
+ * @date 2024-05-19
  */
-public class TwinDevice extends BaseEntity
-{
+@ApiModel(value = "ITwinDevice", description = "设备管理")
+public class TwinDevice extends BaseEntity {
     private static final long serialVersionUID = 1L;
 
-    /** ID */
-    private Long ID;
+    /**
+     * ID
+     */
+    private Long id;
 
-    /** 设备名称 */
+    /**
+     * 设备名称
+     */
     @Excel(name = "设备名称")
+    @ApiModelProperty("设备名称")
     private String deviceName;
 
-    /** 设备路径 */
+    /**
+     * 设备编码
+     */
+    @Excel(name = "设备编码")
+    @ApiModelProperty("设备编码")
+    private String deviceCode;
+
+    /**
+     * 设备路径
+     */
     @Excel(name = "设备路径")
+    @ApiModelProperty("设备路径")
     private String devicePath;
 
-    /** 创建人 */
+    /**
+     * 创建人
+     */
     @Excel(name = "创建人")
+    @ApiModelProperty("创建人")
     private String createdBy;
 
-    /** 创建时间 */
+    /**
+     * 创建时间
+     */
     @JsonFormat(pattern = "yyyy-MM-dd")
     @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
+    @ApiModelProperty("创建时间")
     private Date createdTime;
 
-    /** 更新人 */
+    /**
+     * 更新人
+     */
     @Excel(name = "更新人")
+    @ApiModelProperty("更新人")
     private String updatedBy;
 
-    /** 更新时间 */
+    /**
+     * 更新时间
+     */
     @JsonFormat(pattern = "yyyy-MM-dd")
     @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
+    @ApiModelProperty("更新时间")
     private Date updatedTime;
 
-    public void setID(Long ID)
-    {
-        this.ID = ID;
+    public void setId(Long id) {
+        this.id = id;
     }
 
-    public Long getID()
-    {
-        return ID;
+    public Long getId() {
+        return id;
     }
-    public void setDeviceName(String deviceName)
-    {
+
+    public void setDeviceName(String deviceName) {
         this.deviceName = deviceName;
     }
 
-    public String getDeviceName()
-    {
+    public String getDeviceName() {
         return deviceName;
     }
-    public void setDevicePath(String devicePath)
-    {
+
+    public void setDeviceCode(String deviceCode) {
+        this.deviceCode = deviceCode;
+    }
+
+    public String getDeviceCode() {
+        return deviceCode;
+    }
+
+    public void setDevicePath(String devicePath) {
         this.devicePath = devicePath;
     }
 
-    public String getDevicePath()
-    {
+    public String getDevicePath() {
         return devicePath;
     }
-    public void setCreatedBy(String createdBy)
-    {
+
+    public void setCreatedBy(String createdBy) {
         this.createdBy = createdBy;
     }
 
-    public String getCreatedBy()
-    {
+    public String getCreatedBy() {
         return createdBy;
     }
-    public void setCreatedTime(Date createdTime)
-    {
+
+    public void setCreatedTime(Date createdTime) {
         this.createdTime = createdTime;
     }
 
-    public Date getCreatedTime()
-    {
+    public Date getCreatedTime() {
         return createdTime;
     }
-    public void setUpdatedBy(String updatedBy)
-    {
+
+    public void setUpdatedBy(String updatedBy) {
         this.updatedBy = updatedBy;
     }
 
-    public String getUpdatedBy()
-    {
+    public String getUpdatedBy() {
         return updatedBy;
     }
-    public void setUpdatedTime(Date updatedTime)
-    {
+
+    public void setUpdatedTime(Date updatedTime) {
         this.updatedTime = updatedTime;
     }
 
-    public Date getUpdatedTime()
-    {
+    public Date getUpdatedTime() {
         return updatedTime;
     }
 
     @Override
     public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("ID", getID())
-            .append("deviceName", getDeviceName())
-            .append("devicePath", getDevicePath())
-            .append("createdBy", getCreatedBy())
-            .append("createdTime", getCreatedTime())
-            .append("updatedBy", getUpdatedBy())
-            .append("updatedTime", getUpdatedTime())
-            .append("remark", getRemark())
-            .toString();
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("id", getId())
+                .append("deviceName", getDeviceName())
+                .append("deviceCode", getDeviceCode())
+                .append("devicePath", getDevicePath())
+                .append("createdBy", getCreatedBy())
+                .append("createdTime", getCreatedTime())
+                .append("updatedBy", getUpdatedBy())
+                .append("updatedTime", getUpdatedTime())
+                .append("remark", getRemark())
+                .toString();
     }
 }

+ 23 - 6
ruoyi-admin/src/main/java/com/ruoyi/biz/domain/TwinRecordAlarms.java

@@ -14,7 +14,7 @@ import java.util.Date;
  * 告警数据记录对象 twin_record_alarms
  *
  * @author ruoyi
- * @date 2024-05-15
+ * @date 2024-05-21
  */
 @ApiModel(value = "ITwinRecordAlarms", description = "告警数据记录")
 public class TwinRecordAlarms extends BaseEntity {
@@ -48,6 +48,13 @@ public class TwinRecordAlarms extends BaseEntity {
     private String alarmType;
 
     /**
+     * 告警编号;接口对应的编号
+     */
+    @Excel(name = "告警编号;接口对应的编号")
+    @ApiModelProperty("告警编号;接口对应的编号")
+    private Long alarmCode;
+
+    /**
      * 创建人
      */
     @Excel(name = "创建人")
@@ -77,6 +84,12 @@ public class TwinRecordAlarms extends BaseEntity {
     @ApiModelProperty("更新时间")
     private Date updatedTime;
 
+
+    public Object[] toArray() {
+        Object[] objects = {this.deviceId, this.alarmType, this.alarmCode, this.dataTime};
+        return objects;
+    }
+
     public void setId(Long id) {
         this.id = id;
     }
@@ -109,6 +122,14 @@ public class TwinRecordAlarms extends BaseEntity {
         return alarmType;
     }
 
+    public void setAlarmCode(Long alarmCode) {
+        this.alarmCode = alarmCode;
+    }
+
+    public Long getAlarmCode() {
+        return alarmCode;
+    }
+
     public void setCreatedBy(String createdBy) {
         this.createdBy = createdBy;
     }
@@ -141,11 +162,6 @@ public class TwinRecordAlarms extends BaseEntity {
         return updatedTime;
     }
 
-    public Object[] toArray() {
-        Object[] objects = {this.deviceId, this.alarmType, this.dataTime};
-        return objects;
-    }
-
     @Override
     public String toString() {
         return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
@@ -153,6 +169,7 @@ public class TwinRecordAlarms extends BaseEntity {
                 .append("deviceId", getDeviceId())
                 .append("dataTime", getDataTime())
                 .append("alarmType", getAlarmType())
+                .append("alarmCode", getAlarmCode())
                 .append("createdBy", getCreatedBy())
                 .append("createdTime", getCreatedTime())
                 .append("updatedBy", getUpdatedBy())

+ 22 - 15
ruoyi-admin/src/main/java/com/ruoyi/biz/mapper/TwinDeviceMapper.java

@@ -5,23 +5,23 @@ import com.ruoyi.biz.domain.TwinDevice;
 
 /**
  * 设备管理Mapper接口
- * 
+ *
  * @author ruoyi
- * @date 2024-05-07
+ * @date 2024-05-19
  */
-public interface TwinDeviceMapper 
+public interface TwinDeviceMapper
 {
     /**
      * 查询设备管理
-     * 
-     * @param ID 设备管理主键
+     *
+     * @param id 设备管理主键
      * @return 设备管理
      */
-    public TwinDevice selectTwinDeviceByID(Long ID);
+    public TwinDevice selectTwinDeviceById(Long id);
 
     /**
      * 查询设备管理列表
-     * 
+     *
      * @param twinDevice 设备管理
      * @return 设备管理集合
      */
@@ -29,7 +29,7 @@ public interface TwinDeviceMapper
 
     /**
      * 新增设备管理
-     * 
+     *
      * @param twinDevice 设备管理
      * @return 结果
      */
@@ -37,7 +37,7 @@ public interface TwinDeviceMapper
 
     /**
      * 修改设备管理
-     * 
+     *
      * @param twinDevice 设备管理
      * @return 结果
      */
@@ -45,17 +45,24 @@ public interface TwinDeviceMapper
 
     /**
      * 删除设备管理
-     * 
-     * @param ID 设备管理主键
+     *
+     * @param id 设备管理主键
      * @return 结果
      */
-    public int deleteTwinDeviceByID(Long ID);
+    public int deleteTwinDeviceById(Long id);
 
     /**
      * 批量删除设备管理
-     * 
-     * @param IDs 需要删除的数据主键集合
+     *
+     * @param ids 需要删除的数据主键集合
      * @return 结果
      */
-    public int deleteTwinDeviceByIDs(String[] IDs);
+    public int deleteTwinDeviceByIds(String[] ids);
+    /**
+     * 通过设备编号查询设备
+     *
+     * @param code 设备编号
+     * @return 设备信息
+     */
+    TwinDevice selectTwinDeviceByCode(String code);
 }

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/biz/mapper/TwinRecordAlarmsMapper.java

@@ -7,7 +7,7 @@ import com.ruoyi.biz.domain.TwinRecordAlarms;
  * 告警数据记录Mapper接口
  * 
  * @author ruoyi
- * @date 2024-05-15
+ * @date 2024-05-21
  */
 public interface TwinRecordAlarmsMapper 
 {

+ 1 - 8
ruoyi-admin/src/main/java/com/ruoyi/biz/service/IIotService.java

@@ -7,17 +7,10 @@ import cn.hutool.json.JSONObject;
  */
 public interface IIotService {
     /**
-     * 获取token
-     *
-     * @return token
-     */
-    String getToken();
-
-    /**
      * 查询数据
      *
      * @param sql sql语句
      * @return JSON数据
      */
-    public JSONObject query(String sql);
+    JSONObject query(String sql);
 }

+ 35 - 0
ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITaskService.java

@@ -0,0 +1,35 @@
+package com.ruoyi.biz.service;
+
+import java.time.LocalDate;
+import java.util.Map;
+
+/**
+ * 计算任务服务
+ *
+ * @author wukai
+ */
+public interface ITaskService {
+    /**
+     * 统计上一个偶数时间至当前的数据
+     */
+    void calcCurr();
+
+    /**
+     * 统计昨日数据
+     */
+    void calcYesterday();
+
+    /**
+     * 统计指定日期数据
+     *
+     * @param date 指定日期
+     */
+    void calc(LocalDate date);
+
+    /**
+     * 统计指定日期数据
+     *
+     * @param date 指定日期 yyyy-mm-dd
+     */
+    void calc(String date);
+}

+ 0 - 34
ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITwinCalc2hrService.java

@@ -14,40 +14,6 @@ import java.util.Map;
  */
 public interface ITwinCalc2hrService {
     /**
-     * 数据统计
-     */
-    void calc();
-
-    /**
-     * 统计昨日数据
-     */
-    void calcYesterday();
-
-    /**
-     * 统计指定日期数据
-     *
-     * @param date 指定日期
-     */
-    void calc(LocalDate date);
-
-    /**
-     * 统计指定日期数据
-     *
-     * @param date 指定日期 yyyy-mm-dd
-     */
-    void calc(String date);
-
-    /**
-     * 数据统计
-     *
-     * @param table     表名
-     * @param startTime 开始时间
-     * @param endTime   结束时间
-     * @return map{total/alarms}
-     */
-    Map<String, Object> calc(String table, long startTime, long endTime);
-
-    /**
      * 查询2小时统计数据
      *
      * @param id 2小时统计数据主键

+ 8 - 8
ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITwinDataService.java

@@ -5,15 +5,15 @@ import com.ruoyi.biz.domain.TwinData;
 
 /**
  * 时序数据Service接口
- * 
+ *
  * @author ruoyi
  * @date 2024-05-07
  */
-public interface ITwinDataService 
+public interface ITwinDataService
 {
     /**
      * 查询时序数据
-     * 
+     *
      * @param id 时序数据主键
      * @return 时序数据
      */
@@ -21,7 +21,7 @@ public interface ITwinDataService
 
     /**
      * 查询时序数据列表
-     * 
+     *
      * @param twinData 时序数据
      * @return 时序数据集合
      */
@@ -29,7 +29,7 @@ public interface ITwinDataService
 
     /**
      * 新增时序数据
-     * 
+     *
      * @param twinData 时序数据
      * @return 结果
      */
@@ -37,7 +37,7 @@ public interface ITwinDataService
 
     /**
      * 修改时序数据
-     * 
+     *
      * @param twinData 时序数据
      * @return 结果
      */
@@ -45,7 +45,7 @@ public interface ITwinDataService
 
     /**
      * 批量删除时序数据
-     * 
+     *
      * @param ids 需要删除的时序数据主键集合
      * @return 结果
      */
@@ -53,7 +53,7 @@ public interface ITwinDataService
 
     /**
      * 删除时序数据信息
-     * 
+     *
      * @param id 时序数据主键
      * @return 结果
      */

+ 25 - 17
ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITwinDeviceService.java

@@ -1,27 +1,27 @@
 package com.ruoyi.biz.service;
 
-import java.util.List;
 import com.ruoyi.biz.domain.TwinDevice;
 
+import java.util.List;
+
 /**
  * 设备管理Service接口
- * 
+ *
  * @author ruoyi
- * @date 2024-05-07
+ * @date 2024-05-19
  */
-public interface ITwinDeviceService 
-{
+public interface ITwinDeviceService {
     /**
      * 查询设备管理
-     * 
-     * @param ID 设备管理主键
+     *
+     * @param id 设备管理主键
      * @return 设备管理
      */
-    public TwinDevice selectTwinDeviceByID(Long ID);
+    public TwinDevice selectTwinDeviceById(Long id);
 
     /**
      * 查询设备管理列表
-     * 
+     *
      * @param twinDevice 设备管理
      * @return 设备管理集合
      */
@@ -29,7 +29,7 @@ public interface ITwinDeviceService
 
     /**
      * 新增设备管理
-     * 
+     *
      * @param twinDevice 设备管理
      * @return 结果
      */
@@ -37,7 +37,7 @@ public interface ITwinDeviceService
 
     /**
      * 修改设备管理
-     * 
+     *
      * @param twinDevice 设备管理
      * @return 结果
      */
@@ -45,17 +45,25 @@ public interface ITwinDeviceService
 
     /**
      * 批量删除设备管理
-     * 
-     * @param IDs 需要删除的设备管理主键集合
+     *
+     * @param ids 需要删除的设备管理主键集合
      * @return 结果
      */
-    public int deleteTwinDeviceByIDs(String IDs);
+    public int deleteTwinDeviceByIds(String ids);
 
     /**
      * 删除设备管理信息
-     * 
-     * @param ID 设备管理主键
+     *
+     * @param id 设备管理主键
      * @return 结果
      */
-    public int deleteTwinDeviceByID(Long ID);
+    public int deleteTwinDeviceById(Long id);
+
+    /**
+     * 通过设备编号查询设备
+     *
+     * @param code 设备编号
+     * @return 设备信息
+     */
+    TwinDevice selectTwinDeviceByCode(String code);
 }

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/biz/service/ITwinRecordAlarmsService.java

@@ -7,7 +7,7 @@ import com.ruoyi.biz.domain.TwinRecordAlarms;
  * 告警数据记录Service接口
  * 
  * @author ruoyi
- * @date 2024-05-15
+ * @date 2024-05-21
  */
 public interface ITwinRecordAlarmsService 
 {

+ 312 - 0
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/AsyncServiceImpl.java

@@ -0,0 +1,312 @@
+package com.ruoyi.biz.service.impl;
+
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import com.ruoyi.biz.domain.TwinCalc2hr;
+import com.ruoyi.biz.domain.TwinDevice;
+import com.ruoyi.biz.domain.TwinRecordAlarms;
+import com.ruoyi.biz.service.IIotService;
+import javafx.util.Pair;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.AsyncResult;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+import java.util.concurrent.Future;
+
+/**
+ * 多线程执行任务
+ *
+ * @author wukai
+ * @date 2024/5/4 20:35
+ */
+@Service
+@Slf4j
+public class AsyncServiceImpl {
+    @Resource
+    private IIotService iotService;
+    @Async("threadPoolTaskExecutor")
+    public Future<Map<String, List<Object[]>>> process(TwinDevice twinDevice, Date date, long startTime, long endTime, String period) {
+        Map<String, List<Object[]>> result = new HashMap<>();
+        List<Object[]> calc2hrList = new ArrayList<>();
+        List<Object[]> recordAlarmsList = new ArrayList<>();
+        String table = twinDevice.getDevicePath();
+        TwinCalc2hr calc2hr = new TwinCalc2hr();
+        calc2hr.setDeviceId(twinDevice.getId());
+        calc2hr.setDataDate(date);
+        calc2hr.setTimePeriod(period);
+        Map<String, Object> map = calc(table, startTime, endTime);
+        //0.已织造米数 1.A班组总开机时间 2.A班组总停机时间 3.A班总产量 4.B班组总开机时间 5.B班组总停机时间 6.B班总产量 7.A班总重量 8.B班总重量
+        float[] total = (float[]) map.get("total");
+        calc2hr.setLengthA(BigDecimal.valueOf(total[3]));
+        calc2hr.setLengthB(BigDecimal.valueOf(total[6]));
+        calc2hr.setWeightA(BigDecimal.valueOf(total[7]));
+        calc2hr.setWeightB(BigDecimal.valueOf(total[8]));
+        calc2hr.setOpenTimeA(BigDecimal.valueOf(total[1]));
+        calc2hr.setOpenTimeB(BigDecimal.valueOf(total[4]));
+        calc2hr.setCloseTimeA(BigDecimal.valueOf(total[2]));
+        calc2hr.setCloseTimeB(BigDecimal.valueOf(total[5]));
+
+        Map<String, Long> stop = (Map<String, Long>) map.get("stop");
+        calc2hr.setStop1A(stop.get("stop1_A"));
+        calc2hr.setStop1B(stop.get("stop1_B"));
+        calc2hr.setStop2A(stop.get("stop2_A"));
+        calc2hr.setStop2B(stop.get("stop2_B"));
+        calc2hr.setStop3A(stop.get("stop3_A"));
+        calc2hr.setStop3B(stop.get("stop3_B"));
+
+        int[] alarms = (int[]) map.get("alarms");
+        int alarmsTimes = 0;
+        for (int i = 0; i < alarms.length; i++) {
+            alarmsTimes += alarms[i];
+        }
+        calc2hr.setAlarm((long) alarmsTimes);
+        calc2hr.setRemark(Arrays.toString(alarms));
+
+        calc2hrList.add(calc2hr.toArray());
+        List<Pair<String, Long>> alarmRecord = (List<Pair<String, Long>>) map.get("alarmRecord");
+        String strStop = "stop";
+        String strAlarm = "alarm";
+        alarmRecord.forEach(pair -> {
+            TwinRecordAlarms recordAlarms = new TwinRecordAlarms();
+            recordAlarms.setDeviceId(twinDevice.getId());
+            String key = pair.getKey();
+            if (key.startsWith(strStop)) {
+                recordAlarms.setAlarmType(strStop);
+                recordAlarms.setAlarmCode(Long.parseLong(key.replace(strStop, "")));
+            } else {
+                recordAlarms.setAlarmType(strAlarm);
+                recordAlarms.setAlarmCode(Long.parseLong(key.replace(strAlarm, "")));
+            }
+            recordAlarms.setDataTime(new Date(pair.getValue()));
+            recordAlarmsList.add(recordAlarms.toArray());
+        });
+
+        result.put("calc", calc2hrList);
+        result.put("record", recordAlarmsList);
+        return new AsyncResult<>(result);
+    }
+
+
+    /**
+     * //    0        Capacity_data_2	已织造米数
+     * //    1        Capacity_data_37	A班组开机时间
+     * //    2        Capacity_data_38	A班组停机时间
+     * //    3        Capacity_data_39	A班当前产量
+     * //    4        Capacity_data_42	B班组开机时间
+     * //    5        Capacity_data_43	B班组停机时间
+     * //    6        Capacity_data_44	B班当前产量
+     * //    7        Capacity_data_48	停机状态
+     * //    8        Formula_data_3	米克重
+     * //    9        Formula_data_13	卷曲幅宽
+     */
+    public Map<String, Object> calc(String table, long startTime, long endTime) {
+        String sql = "select Capacity_data_2,Capacity_data_37,Capacity_data_38,Capacity_data_39,Capacity_data_42,Capacity_data_43,Capacity_data_44,Capacity_data_48,Formula_data_3,Formula_data_13,Capacity_data_36,Capacity_data_41," + "Alarm_unit_1,Alarm_unit_2,Alarm_unit_3,Alarm_unit_4,Alarm_unit_5,Alarm_unit_6,Alarm_unit_7,Alarm_unit_8,Alarm_unit_9,Alarm_unit_10,Alarm_unit_11,Alarm_unit_12,Alarm_unit_13,Alarm_unit_14,Alarm_unit_15,Alarm_unit_16,Alarm_unit_17,Alarm_unit_18,Alarm_unit_19,Alarm_unit_20,Alarm_unit_21,Alarm_unit_22,Alarm_unit_23,Alarm_unit_24,Alarm_unit_25,Alarm_unit_26,Alarm_unit_27" + " from %s where time>%s and time <=%s";
+        sql = String.format(sql, table, startTime, endTime);
+        JSONObject jsonObject = iotService.query(sql);
+
+        JSONObject data = jsonObject.getJSONObject("data");
+        JSONArray values = data.getJSONArray("values");
+        JSONArray timestamps = data.getJSONArray("timestamps");
+        //初始时间点数据
+        //0-data2,1-data37,2-data38,3-data39,4-data42,5-data-43,6data-44
+        float[] first = new float[7];
+        //上一个时间点数据
+        float[] last = new float[7];
+        //统计数据,后面2个分别代表A班重量,B班重量
+        float[] total = new float[9];
+        //告警数据统计
+        boolean[] lastAlarms = new boolean[26];
+        //最后一个值为int型,需要单独计算
+        int[] alarmsTimes = new int[27];
+        //米克重
+        int lastMkz = 0;
+        //卷曲幅宽
+        float lastFk = 0f;
+        int last48 = 0;
+        //状态计数
+        Map<String, Long> stopMap = new HashMap<>(16);
+        for (int i = 1; i <= 7; i++) {
+            stopMap.put("stop" + i + "_A", 0L);
+            stopMap.put("stop" + i + "_B", 0L);
+        }
+        //停机和告警时间记录
+        List<Pair<String, Long>> alarmRecord = new ArrayList<>();
+
+        for (int i = 0; i < timestamps.size(); i++) {
+            JSONArray da = values.getJSONArray(i);
+            //0-data2,1-data37,2-data38,3-data39,4-data42,5-data-43,6data-44
+            //当前时间数据
+            float[] curr = {da.getFloat(0), da.getFloat(1), da.getFloat(2), da.getFloat(3), da.getFloat(4), da.getFloat(5), da.getFloat(6)};
+            int curr48 = da.getInt(7);
+
+            if (i == 0) {
+                //第一次数据是上次最后一条,只做记录用,不做处理
+                first = curr.clone();
+                last = curr.clone();
+                lastMkz = da.getInt(8);
+                lastFk = da.getFloat(9);
+                last48 = curr48;
+                for (int j = 0; j < lastAlarms.length; j++) {
+                    lastAlarms[j] = da.getBool(12 + j);
+                }
+                continue;
+            }
+
+            for (int j = 0; j < first.length; j++) {
+                //如果当前值为小于上一个,且上一个值不为0,则计算
+                //因为会出现数据波动,停机再启动之后的第一个点不为0,为0.00几几几的
+                //计算累加类的数据
+                if (curr[j] < last[j] && last[j] != 0f) {
+                    calcTotal(j, last, first, total, lastMkz, lastFk);
+                    first[j] = curr[j];
+                }
+            }
+
+            calcAlarms(lastAlarms, da, timestamps, values, i, alarmsTimes, alarmRecord);
+
+            if (curr48 != 0 && curr48 != last48) {
+                //不等于0,并且超过连续10次或者时间超过10秒
+                //取出后面9次的数据,跟当前值是否一样,如果后面数据不足9次,则取至末尾
+                int endNum = timestamps.size();
+                if (i + 9 < timestamps.size()) {
+                    endNum = i + 9;
+                }
+                boolean numFlag = calcStops(i, endNum, values, curr48);
+                if (numFlag) {
+                    //记录停机时间
+                    //10 A班登入 11B班登入
+                    String key = "stop" + curr48;
+                    alarmRecord.add(new Pair<>(key, timestamps.getLong(i)));
+
+                    if (da.getBool(10)) {
+                        key += "_A";
+                    }
+                    if (da.getBool(11)) {
+                        key += "_B";
+                    }
+                    if (stopMap.get(key) != null) {
+                        Long times = stopMap.get(key) + 1;
+                        stopMap.put(key, times);
+                    }
+                }
+
+            }
+
+            //复制数组,设置last值为当前值
+            last = curr.clone();
+            lastMkz = da.getInt(8);
+            lastFk = da.getFloat(9);
+            for (int j = 0; j < lastAlarms.length; j++) {
+                lastAlarms[j] = da.getBool(12 + j);
+            }
+            last48 = curr48;
+        }
+        //最后再补一次计算
+        for (int j = 0; j < first.length; j++) {
+            calcTotal(j, last, first, total, lastMkz, lastFk);
+        }
+
+        Map<String, Object> result = new HashMap<>(16);
+        result.put("total", total);
+        result.put("stop", stopMap);
+        result.put("alarms", alarmsTimes);
+        result.put("alarmRecord", alarmRecord);
+        return result;
+    }
+
+    /**
+     * 停机次数计算
+     */
+    private boolean calcStops(int startNum, int endNum, JSONArray values, int curr) {
+        boolean numFlag = true;
+        for (int j = startNum + 1; j < endNum; j++) {
+            JSONArray nextData = values.getJSONArray(j);
+            int next48 = nextData.getInt(7);
+            if (curr != next48) {
+                numFlag = false;
+                break;
+            }
+        }
+
+        return numFlag;
+    }
+
+    /**
+     * 告警次数计算
+     */
+    private void calcAlarms(boolean[] lastAlarms, JSONArray da, JSONArray timestamps, JSONArray values, int i, int[] alarmsTimes, List<Pair<String, Long>> alarmRecord) {
+        int endNum = timestamps.size();
+        if (i + 9 < timestamps.size()) {
+            endNum = i + 9;
+        }
+        int j = 0;
+        for (; j < lastAlarms.length; j++) {
+            boolean currV = da.getBool(j + 12);
+            if (currV && !lastAlarms[j]) {
+                //如果当前值为true,上一条为false 则记录一次告警(并且后面连续多次为TRUE)
+                boolean numFlag = true;
+                for (int k = i + 1; k < endNum; k++) {
+                    JSONArray nextData = values.getJSONArray(k);
+                    boolean nextV = nextData.getBool(j + 12);
+                    if (!nextV) {
+                        numFlag = false;
+                        break;
+                    }
+                }
+                if (numFlag) {
+                    alarmRecord.add(new Pair<>("alarm" + (j + 1), timestamps.getLong(i)));
+                    alarmsTimes[j] += 1;
+                }
+            }
+        }
+        //需要单独计算alarm27
+        //数据位置
+        int pos = j + 12;
+        int alarm27 = da.getInt(pos);
+        //上面已经处理过i=0,所以这里i不可能等于0
+        JSONArray last = values.getJSONArray(i - 1);
+        int last27 = last.getInt(pos);
+        if (alarm27 != 0 && last27 == 0) {
+            //当前值不为0,上一条为0,则记录一次告警(并且后面连续多次为该值)
+            boolean numFlag = true;
+            for (int k = i + 1; k < endNum; k++) {
+                JSONArray nextData = values.getJSONArray(k);
+                int nextV = nextData.getInt(j + 12);
+                if (alarm27 != nextV) {
+                    numFlag = false;
+                    break;
+                }
+            }
+            if (numFlag) {
+                alarmRecord.add(new Pair<>("alarm" + (j + 1), timestamps.getLong(i)));
+                alarmsTimes[j] += 1;
+            }
+        }
+    }
+
+    /**
+     * 重量计算 提取公共方法
+     */
+    private void calcTotal(int j, float[] last, float[] first, float[] total, int lastMkz, float lastFk) {
+        float v = last[j] - first[j];
+        total[j] += v;
+        if (j == 3 || j == 6) {
+            float weight = BigDecimal.valueOf(v * lastMkz * lastFk / 1000 / 1000).setScale(2, RoundingMode.HALF_UP).floatValue();
+            if (j == 3) {
+                //如果是A班产量,则计算A班重量
+                total[7] = total[7] + weight;
+            }
+            if (j == 6) {
+                //如果是B班产量,则计算B班重量
+                total[8] = total[8] + weight;
+            }
+        }
+    }
+
+}

+ 14 - 47
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/IotServiceImpl.java

@@ -1,19 +1,17 @@
 package com.ruoyi.biz.service.impl;
 
-import cn.hutool.core.text.UnicodeUtil;
-import cn.hutool.crypto.digest.MD5;
 import cn.hutool.http.HttpRequest;
-import cn.hutool.http.HttpResponse;
 import cn.hutool.http.HttpUtil;
 import cn.hutool.http.Method;
 import cn.hutool.json.JSONObject;
-import cn.hutool.json.JSONUtil;
 import com.ruoyi.biz.service.IIotService;
+import com.ruoyi.biz.tools.IotTools;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
-import java.util.HashMap;
-import java.util.Map;
+import javax.annotation.Resource;
+import java.util.Date;
 
 /**
  * IotServiceImpl$
@@ -22,42 +20,12 @@ import java.util.Map;
  * @date 2024/5/4 20:35
  */
 @Service
+@Slf4j
 public class IotServiceImpl implements IIotService {
     @Value("${iot.uri}")
     private String uri;
-    @Value("${iot.tenantId}")
-    private String tenantId;
-    @Value("${iot.username}")
-    private String username;
-    @Value("${iot.password}")
-    private String password;
-    @Value("${iot.authorization}")
-    private String authorization;
-
-    /**
-     * 获取token
-     *
-     * @return token
-     */
-    @Override
-    public String getToken() {
-        String uri = this.uri + "/api/blade-auth/oauth/token";
-        Map<String, Object> map = new HashMap<>(16);
-        map.put("tenantId", tenantId);
-        map.put("username", username);
-        map.put("password", MD5.create().digestHex(password));
-        HttpRequest request = HttpUtil.createPost(uri);
-        request.setMethod(Method.POST);
-        request.header("Authorization", authorization);
-        request.form(map);
-        HttpResponse execute = request.execute();
-        if (!execute.isOk()) {
-            throw new RuntimeException(execute.body());
-        }
-        String res = UnicodeUtil.toString(execute.body());
-        JSONObject jsonObject = JSONUtil.parseObj(res, true);
-        return (String) jsonObject.get("access_token");
-    }
+    @Resource
+    private IotTokenServiceImpl tokenService;
 
     /**
      * 查询数据
@@ -67,20 +35,19 @@ public class IotServiceImpl implements IIotService {
      */
     @Override
     public JSONObject query(String sql) {
+        Date s = new Date();
         String uri = this.uri + "/api/cnv-device/data-point/timeseries/query";
         JSONObject object = new JSONObject();
         object.set("sql", sql);
         HttpRequest request = HttpUtil.createPost(uri);
         request.setMethod(Method.POST);
-        request.header("Blade-Auth", "bearer " + getToken());
+        request.header("Blade-Auth", "bearer " + tokenService.getToken());
         request.body(object.toString());
-        try (HttpResponse execute = request.execute()) {
-            if (!execute.isOk()) {
-                throw new RuntimeException(execute.body());
-            }
-            String res = UnicodeUtil.toString(execute.body());
-            return JSONUtil.parseObj(res, true);
-        }
+        JSONObject result = IotTools.getData(request);
+        Date e = new Date();
+        log.info("接口耗时:{}ms\t", (e.getTime() - s.getTime()));
+        return result;
     }
 
+
 }

+ 56 - 0
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/IotTokenServiceImpl.java

@@ -0,0 +1,56 @@
+package com.ruoyi.biz.service.impl;
+
+import cn.hutool.crypto.digest.MD5;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.http.Method;
+import cn.hutool.json.JSONObject;
+import com.ruoyi.biz.tools.IotTools;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * IotServiceImpl$
+ *
+ * @author wukai
+ * @date 2024/5/4 20:35
+ */
+@Service
+@Slf4j
+public class IotTokenServiceImpl {
+    @Value("${iot.uri}")
+    private String uri;
+    @Value("${iot.tenantId}")
+    private String tenantId;
+    @Value("${iot.username}")
+    private String username;
+    @Value("${iot.password}")
+    private String password;
+    @Value("${iot.authorization}")
+    private String authorization;
+
+    /**
+     * 获取token,项目启动时执行一次
+     *
+     * @return token
+     */
+    @Cacheable(value = "iotCache")
+    public String getToken() {
+        String uri = this.uri + "/api/blade-auth/oauth/token";
+        Map<String, Object> map = new HashMap<>(16);
+        map.put("tenantId", tenantId);
+        map.put("username", username);
+        map.put("password", MD5.create().digestHex(password));
+        HttpRequest request = HttpUtil.createPost(uri);
+        request.setMethod(Method.POST);
+        request.header("Authorization", authorization);
+        request.form(map);
+        JSONObject jsonObject = IotTools.getData(request);
+        return jsonObject.getStr("access_token");
+    }
+}

+ 168 - 0
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/TaskServiceImpl.java

@@ -0,0 +1,168 @@
+package com.ruoyi.biz.service.impl;
+
+import com.ruoyi.biz.domain.TwinCalc2hr;
+import com.ruoyi.biz.domain.TwinDevice;
+import com.ruoyi.biz.service.IIotService;
+import com.ruoyi.biz.service.ITaskService;
+import com.ruoyi.biz.service.ITwinDeviceService;
+import com.ruoyi.common.utils.Tools;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+/**
+ * 计算任务
+ *
+ * @author wukai
+ * @date 2024/5/4 20:35
+ */
+@Service
+@Slf4j
+public class TaskServiceImpl implements ITaskService {
+    @Resource
+    private ITwinDeviceService deviceService;
+    @Resource
+    private IIotService iotService;
+    @Resource
+    private IotTokenServiceImpl iotTokenService;
+    @Resource
+    private JdbcTemplate jdbcTemplate;
+    @Resource
+    private AsyncServiceImpl asyncService;
+
+    /**
+     * 统计上一个偶数时间至当前的数据
+     */
+    @Override
+    public void calcCurr() {
+        LocalDateTime ldt = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);
+        //当前时间之前的偶数时间段
+        ldt = ldt.minusHours(ldt.getHour() % 2);
+        //开始时间需要向前取一秒
+        LocalDateTime start = ldt.minusSeconds(1);
+        //获取时段范围 时间 1=0-2点 2=2-4
+        LocalDateTime end = LocalDateTime.now();
+        Long startTime = start.toInstant(ZoneOffset.of("+8")).toEpochMilli();
+        Long endTime = end.toInstant(ZoneOffset.of("+8")).toEpochMilli();
+        deviceService.selectTwinDeviceList(new TwinDevice()).forEach(twinDevice -> {
+            String table = twinDevice.getDevicePath();
+            TwinCalc2hr calc2hr = new TwinCalc2hr();
+            calc2hr.setDeviceId(twinDevice.getId());
+            Map<String, Object> map = asyncService.calc(table, startTime, endTime);
+            //0.已织造米数 1.A班组总开机时间 2.A班组总停机时间 3.A班总产量 4.B班组总开机时间 5.B班组总停机时间 6.B班总产量 7.A班总重量 8.B班总重量
+            float[] total = (float[]) map.get("total");
+            calc2hr.setLengthA(BigDecimal.valueOf(total[3]));
+            calc2hr.setLengthB(BigDecimal.valueOf(total[6]));
+            calc2hr.setWeightA(BigDecimal.valueOf(total[7]));
+            calc2hr.setWeightB(BigDecimal.valueOf(total[8]));
+            calc2hr.setOpenTimeA(BigDecimal.valueOf(total[1]));
+            calc2hr.setOpenTimeB(BigDecimal.valueOf(total[4]));
+            calc2hr.setCloseTimeA(BigDecimal.valueOf(total[2]));
+            calc2hr.setCloseTimeB(BigDecimal.valueOf(total[5]));
+
+            Map<String, Long> stop = (Map<String, Long>) map.get("stop");
+            calc2hr.setStop1A(stop.get("stop1_A"));
+            calc2hr.setStop1B(stop.get("stop1_B"));
+            calc2hr.setStop2A(stop.get("stop2_A"));
+            calc2hr.setStop2B(stop.get("stop2_B"));
+            calc2hr.setStop3A(stop.get("stop3_A"));
+            calc2hr.setStop3B(stop.get("stop3_B"));
+
+            int[] alarms = (int[]) map.get("alarms");
+            int alarmsTimes = 0;
+            for (int i = 0; i < alarms.length; i++) {
+                alarmsTimes += alarms[i];
+            }
+            calc2hr.setAlarm((long) alarmsTimes);
+            calc2hr.setRemark(Arrays.toString(alarms));
+        });
+    }
+
+    /**
+     * 统计昨日数据
+     */
+    @Override
+    public void calcYesterday() {
+        LocalDate localDate = LocalDate.now().minusDays(1);
+        calc(localDate);
+    }
+
+    /**
+     * 统计指定日期数据
+     *
+     * @param date 指定日期 yyyy-mm-dd
+     */
+    @Override
+    public void calc(String date) {
+        LocalDate localDate = LocalDate.parse(date);
+        calc(localDate);
+    }
+
+    /**
+     * 统计指定日期数据
+     *
+     * @param date 指定日期
+     */
+    @Override
+    public void calc(LocalDate date) {
+        Tools.timePeriod(date).forEach(map -> {
+            long start = (long) map.get("start");
+            long end = (long) map.get("end");
+            String period = (String) map.get("period");
+            Date d = Date.from(date.atStartOfDay(ZoneOffset.of("+8")).toInstant());
+            calc4device(d, start, end, period);
+        });
+    }
+
+    /**
+     * 按设备循环计算
+     *
+     * @param date      日期
+     * @param startTime 开始时间戳
+     * @param endTime   结束时间戳
+     * @param period    时段
+     */
+    private void calc4device(Date date, long startTime, long endTime, String period) {
+        List<Object[]> calc2hrList = new ArrayList<>();
+        List<Object[]> recordAlarmsList = new ArrayList<>();
+        Date s = new Date();
+        //为了避免多线程同时获取token导致重复执行,先执行一次获取token
+        iotTokenService.getToken();
+        List<TwinDevice> list = deviceService.selectTwinDeviceList(new TwinDevice());
+        List<Future<Map<String, List<Object[]>>>> futureList = new ArrayList<>();
+        for (int i = 0; i < list.size(); i++) {
+            TwinDevice twinDevice = list.get(i);
+            futureList.add(asyncService.process(twinDevice, date, startTime, endTime, period));
+        }
+        try {
+            for (Future<Map<String, List<Object[]>>> future : futureList) {
+                Map<String, List<Object[]>> map = future.get();
+                calc2hrList.addAll(map.get("calc"));
+                recordAlarmsList.addAll(map.get("record"));
+            }
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } catch (ExecutionException e) {
+            throw new RuntimeException(e);
+        }
+        Date d = new Date();
+        System.err.println("总共消耗:");
+        System.err.println(d.getTime() - s.getTime());
+        System.err.println("ms");
+        String sql = "INSERT INTO TWIN_CALC_2HR (DATA_DATE, TIME_PERIOD, DEVICE_ID, LENGTH_A, OPEN_TIME_A, CLOSE_TIME_A, LENGTH_B, CLOSE_TIME_B, OPEN_TIME_B, WEIGHT, WEIGHT_A, WEIGHT_B, ALARM, STOP1_A, STOP2_A, STOP3_A, STOP1_B, STOP2_B, STOP3_B,REMARK)" +
+                " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
+        jdbcTemplate.batchUpdate(sql, calc2hrList);
+
+        sql = "INSERT INTO TWIN_RECORD_ALARMS (DEVICE_ID, ALARM_TYPE,ALARM_CODE,DATA_TIME) VALUES (?,?,?,?)";
+        jdbcTemplate.batchUpdate(sql, recordAlarmsList);
+    }
+}

+ 0 - 305
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/TwinCalc2hrServiceImpl.java

@@ -4,7 +4,6 @@ import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import com.ruoyi.biz.domain.TwinCalc2hr;
 import com.ruoyi.biz.domain.TwinDevice;
-import com.ruoyi.biz.domain.TwinRecordAlarms;
 import com.ruoyi.biz.mapper.TwinCalc2hrMapper;
 import com.ruoyi.biz.service.IIotService;
 import com.ruoyi.biz.service.ITwinCalc2hrService;
@@ -41,310 +40,6 @@ public class TwinCalc2hrServiceImpl implements ITwinCalc2hrService {
     private JdbcTemplate jdbcTemplate;
 
     /**
-     * 数据统计
-     */
-    @Override
-    public void calc() {
-        LocalDateTime ldt = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);
-        //当前时间之前的偶数时间段
-        ldt = ldt.minusHours(2).minusHours(ldt.getHour() % 2);
-        //开始时间需要向前取一秒
-        LocalDateTime start = ldt.minusSeconds(1);
-        //获取时段范围 时间 1=0-2点 2=2-4
-        int period = ldt.getHour() / 2 + 1;
-        LocalDateTime end = ldt.plusHours(2);
-        Long startTime = start.toInstant(ZoneOffset.of("+8")).toEpochMilli();
-        Long endTime = end.toInstant(ZoneOffset.of("+8")).toEpochMilli();
-        Date date = Date.from(ldt.toLocalDate().atStartOfDay(ZoneOffset.of("+8")).toInstant());
-        calc4device(date, startTime, endTime, period + "");
-    }
-
-    /**
-     * 统计昨日数据
-     */
-    @Override
-    public void calcYesterday() {
-        LocalDate localDate = LocalDate.now().minusDays(1);
-        calc(localDate);
-    }
-
-    /**
-     * 统计指定日期数据
-     *
-     * @param date 指定日期 yyyy-mm-dd
-     */
-    @Override
-    public void calc(String date) {
-        LocalDate localDate = LocalDate.parse(date);
-        calc(localDate);
-    }
-
-    /**
-     * 统计指定日期数据
-     *
-     * @param date 指定日期
-     */
-    @Override
-    public void calc(LocalDate date) {
-        Tools.timePeriod(date).forEach(map -> {
-            long start = (long) map.get("start");
-            long end = (long) map.get("end");
-            String period = (String) map.get("period");
-            Date d = Date.from(date.atStartOfDay(ZoneOffset.of("+8")).toInstant());
-            calc4device(d, start, end, period);
-        });
-    }
-
-    /**
-     * 按设备循环计算
-     *
-     * @param date      日期
-     * @param startTime 开始时间戳
-     * @param endTime   结束时间戳
-     * @param period    时段
-     */
-    private void calc4device(Date date, long startTime, long endTime, String period) {
-        List<Object[]> calc2hrList = new ArrayList<>();
-        List<Object[]> recordAlarmsList = new ArrayList<>();
-        deviceService.selectTwinDeviceList(new TwinDevice()).forEach(twinDevice -> {
-            String table = twinDevice.getDevicePath();
-            TwinCalc2hr calc2hr = new TwinCalc2hr();
-            calc2hr.setDeviceId(twinDevice.getID());
-            calc2hr.setDataDate(date);
-            calc2hr.setTimePeriod(period);
-            Map<String, Object> map = calc(table, startTime, endTime);
-            //0.已织造米数 1.A班组总开机时间 2.A班组总停机时间 3.A班总产量 4.B班组总开机时间 5.B班组总停机时间 6.B班总产量 7.A班总重量 8.B班总重量
-            float[] total = (float[]) map.get("total");
-            calc2hr.setLengthA(BigDecimal.valueOf(total[3]));
-            calc2hr.setLengthB(BigDecimal.valueOf(total[6]));
-            calc2hr.setWeightA(BigDecimal.valueOf(total[7]));
-            calc2hr.setWeightB(BigDecimal.valueOf(total[8]));
-            calc2hr.setOpenTimeA(BigDecimal.valueOf(total[1]));
-            calc2hr.setOpenTimeB(BigDecimal.valueOf(total[4]));
-            calc2hr.setCloseTimeA(BigDecimal.valueOf(total[2]));
-            calc2hr.setCloseTimeB(BigDecimal.valueOf(total[5]));
-
-            Map<String, Long> stop = (Map<String, Long>) map.get("stop");
-            calc2hr.setStop1A(stop.get("stop1_A"));
-            calc2hr.setStop1B(stop.get("stop1_B"));
-            calc2hr.setStop2A(stop.get("stop2_A"));
-            calc2hr.setStop2B(stop.get("stop2_B"));
-            calc2hr.setStop3A(stop.get("stop3_A"));
-            calc2hr.setStop3B(stop.get("stop3_B"));
-
-            int[] alarms = (int[]) map.get("alarms");
-            int alarmsTimes = 0;
-            for (int i = 0; i < alarms.length; i++) {
-                alarmsTimes += alarms[i];
-            }
-            calc2hr.setAlarm((long) alarmsTimes);
-            calc2hr.setRemark(Arrays.toString(alarms));
-
-//            insertTwinCalc2hr(calc2hr);
-            calc2hrList.add(calc2hr.toArray());
-            List<Pair<Integer, Long>> stopRecord = (List<Pair<Integer, Long>>) map.get("stopRecord");
-            stopRecord.forEach(pair -> {
-                TwinRecordAlarms recordAlarms = new TwinRecordAlarms();
-                recordAlarms.setDeviceId(twinDevice.getID());
-                recordAlarms.setAlarmType(pair.getKey() + "");
-                recordAlarms.setDataTime(new Date(pair.getValue()));
-                recordAlarmsList.add(recordAlarms.toArray());
-//                recordAlarmsService.insertTwinRecordAlarms(recordAlarms);
-            });
-        });
-        String sql = "INSERT INTO TWIN_CALC_2HR (DATA_DATE, TIME_PERIOD, DEVICE_ID, LENGTH_A, OPEN_TIME_A, CLOSE_TIME_A, LENGTH_B, CLOSE_TIME_B, OPEN_TIME_B, WEIGHT, WEIGHT_A, WEIGHT_B, ALARM, STOP1_A, STOP2_A, STOP3_A, STOP1_B, STOP2_B, STOP3_B)" +
-                " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
-        jdbcTemplate.batchUpdate(sql, calc2hrList);
-
-        sql = "INSERT INTO TWIN_RECORD_ALARMS (DEVICE_ID, ALARM_TYPE,DATA_TIME) VALUES (?,?,?)";
-        jdbcTemplate.batchUpdate(sql, recordAlarmsList);
-
-    }
-
-
-    /**
-     * //    0        Capacity_data_2	已织造米数
-     * //    1        Capacity_data_37	A班组开机时间
-     * //    2        Capacity_data_38	A班组停机时间
-     * //    3        Capacity_data_39	A班当前产量
-     * //    4        Capacity_data_42	B班组开机时间
-     * //    5        Capacity_data_43	B班组停机时间
-     * //    6        Capacity_data_44	B班当前产量
-     * //    7        Capacity_data_48	停机状态
-     * //    8        Formula_data_3	米克重
-     * //    9        Formula_data_13	卷曲幅宽
-     */
-    @Override
-    public Map<String, Object> calc(String table, long startTime, long endTime) {
-        String sql = "select Capacity_data_2,Capacity_data_37,Capacity_data_38,Capacity_data_39,Capacity_data_42,Capacity_data_43,Capacity_data_44,Capacity_data_48,Formula_data_3,Formula_data_13,Capacity_data_36,Capacity_data_41," + "Alarm_unit_1,Alarm_unit_2,Alarm_unit_3,Alarm_unit_4,Alarm_unit_5,Alarm_unit_6,Alarm_unit_7,Alarm_unit_8,Alarm_unit_9,Alarm_unit_10,Alarm_unit_11,Alarm_unit_12,Alarm_unit_13,Alarm_unit_14,Alarm_unit_15,Alarm_unit_16,Alarm_unit_17,Alarm_unit_18,Alarm_unit_19,Alarm_unit_20,Alarm_unit_21,Alarm_unit_22,Alarm_unit_23,Alarm_unit_24,Alarm_unit_25,Alarm_unit_26,Alarm_unit_27" + " from %s where time>%s and time <=%s";
-        sql = String.format(sql, table, startTime, endTime);
-        JSONObject jsonObject = iotService.query(sql);
-
-        JSONObject data = jsonObject.getJSONObject("data");
-        JSONArray values = data.getJSONArray("values");
-        JSONArray timestamps = data.getJSONArray("timestamps");
-        //初始时间点数据
-        //0-data2,1-data37,2-data38,3-data39,4-data42,5-data-43,6data-44
-        float[] first = new float[7];
-        //上一个时间点数据
-        float[] last = new float[7];
-        //统计数据,后面2个分别代表A班重量,B班重量
-        float[] total = new float[9];
-        //告警数据统计
-        boolean[] lastAlarms = new boolean[26];
-        int[] alarmsTimes = new int[26];
-        //米克重
-        int lastMkz = 0;
-        //卷曲幅宽
-        float lastFk = 0f;
-        int last48 = 0;
-        //状态计数
-        Map<String, Long> stopMap = new HashMap<>(16);
-        for (int i = 1; i <= 7; i++) {
-            stopMap.put("stop" + i + "_A", 0L);
-            stopMap.put("stop" + i + "_B", 0L);
-        }
-        //停机时间记录
-        List<Pair<Integer, Long>> stopRecord = new ArrayList<>();
-
-        for (int i = 0; i < timestamps.size(); i++) {
-            JSONArray da = values.getJSONArray(i);
-            //0-data2,1-data37,2-data38,3-data39,4-data42,5-data-43,6data-44
-            //当前时间数据
-            float[] curr = {da.getFloat(0), da.getFloat(1), da.getFloat(2), da.getFloat(3), da.getFloat(4), da.getFloat(5), da.getFloat(6)};
-            int curr48 = da.getInt(7);
-
-            if (i == 0) {
-                //第一次数据是上次最后一条,只做记录用,不做处理
-                first = curr.clone();
-                last = curr.clone();
-                lastMkz = da.getInt(8);
-                lastFk = da.getFloat(9);
-                last48 = curr48;
-                for (int j = 0; j < lastAlarms.length; j++) {
-                    lastAlarms[j] = da.getBool(12 + j);
-                }
-                continue;
-            }
-
-            for (int j = 0; j < first.length; j++) {
-                //如果当前值为小于上一个,且上一个值不为0,则计算
-                //因为会出现数据波动,停机再启动之后的第一个点不为0,为0.00几几几的
-                if (curr[j] < last[j] && last[j] != 0f) {
-                    calcTotal(j, last, first, total, lastMkz, lastFk);
-                    first[j] = curr[j];
-                }
-            }
-
-            for (int j = 0; j < lastAlarms.length; j++) {
-                boolean currV = da.getBool(j + 12);
-                if (currV && !lastAlarms[j]) {
-                    //如果当前值为true,上一条为false 则记录一次告警
-                    int endNum = timestamps.size();
-                    if (i + 9 < timestamps.size()) {
-                        endNum = i + 9;
-                    }
-                    boolean numFlag = true;
-                    for (int k = i + 1; k < endNum; k++) {
-                        JSONArray nextData = values.getJSONArray(k);
-                        boolean nextV = nextData.getBool(j + 12);
-                        if (!nextV) {
-                            numFlag = false;
-                            break;
-                        }
-                    }
-                    if (numFlag) {
-                        alarmsTimes[j] += 1;
-                    }
-                }
-            }
-
-            if (curr48 != 0 && curr48 != last48) {
-                //不等于0,并且超过连续10次或者时间超过10秒
-                //取出后面9次的数据,跟当前值是否一样,如果后面数据不足9次,则取至末尾
-                int endNum = timestamps.size();
-                if (i + 9 < timestamps.size()) {
-                    endNum = i + 9;
-                }
-                boolean numFlag = calcAlarms(i, endNum, values, curr48);
-                if (numFlag) {
-                    //记录停机时间
-                    stopRecord.add(new Pair<>(curr48, timestamps.getLong(i)));
-                    //10 A班登入 11B班登入
-                    String key = "stop" + curr48;
-                    if (da.getBool(10)) {
-                        key += "_A";
-                    }
-                    if (da.getBool(11)) {
-                        key += "_B";
-                    }
-                    if (stopMap.get(key) != null) {
-                        Long times = stopMap.get(key) + 1;
-                        stopMap.put(key, times);
-                    }
-                }
-
-            }
-
-            //复制数组,设置last值为当前值
-            last = curr.clone();
-            lastMkz = da.getInt(8);
-            lastFk = da.getFloat(9);
-            for (int j = 0; j < lastAlarms.length; j++) {
-                lastAlarms[j] = da.getBool(12 + j);
-            }
-            last48 = curr48;
-        }
-        //最后再补一次计算
-        for (int j = 0; j < first.length; j++) {
-            calcTotal(j, last, first, total, lastMkz, lastFk);
-        }
-
-        Map<String, Object> result = new HashMap<>(16);
-        result.put("total", total);
-        result.put("stop", stopMap);
-        result.put("alarms", alarmsTimes);
-        result.put("stopRecord", stopRecord);
-        return result;
-    }
-
-    /**
-     * 告警次数计算
-     */
-    private boolean calcAlarms(int startNum, int endNum, JSONArray values, int curr) {
-        boolean numFlag = true;
-        for (int j = startNum + 1; j < endNum; j++) {
-            JSONArray nextData = values.getJSONArray(j);
-            int next48 = nextData.getInt(7);
-            if (curr != next48) {
-                numFlag = false;
-                break;
-            }
-        }
-
-        return numFlag;
-    }
-
-    /**
-     * 计算 提取公共方法
-     */
-    private void calcTotal(int j, float[] last, float[] first, float[] total, int lastMkz, float lastFk) {
-        float v = last[j] - first[j];
-        total[j] += v;
-        if (j == 3 || j == 6) {
-            float weight = BigDecimal.valueOf(v * lastMkz * lastFk / 1000 / 1000).setScale(2, RoundingMode.HALF_UP).floatValue();
-            if (j == 3) {
-                //如果是A班产量,则计算A班重量
-                total[7] = total[7] + weight;
-            }
-            if (j == 6) {
-                //如果是B班产量,则计算B班重量
-                total[8] = total[8] + weight;
-            }
-        }
-    }
-
-    /**
      * 查询2小时统计数据
      *
      * @param id 2小时统计数据主键

+ 28 - 25
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/TwinDeviceServiceImpl.java

@@ -1,37 +1,34 @@
 package com.ruoyi.biz.service.impl;
 
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.biz.mapper.TwinDeviceMapper;
 import com.ruoyi.biz.domain.TwinDevice;
+import com.ruoyi.biz.mapper.TwinDeviceMapper;
 import com.ruoyi.biz.service.ITwinDeviceService;
 import com.ruoyi.common.core.text.Convert;
+import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.List;
 
 /**
  * 设备管理Service业务层处理
  *
  * @author ruoyi
- * @date 2024-05-07
+ * @date 2024-05-19
  */
 @Service
-public class TwinDeviceServiceImpl implements ITwinDeviceService
-{
+public class TwinDeviceServiceImpl implements ITwinDeviceService {
     @Resource
     private TwinDeviceMapper twinDeviceMapper;
 
     /**
      * 查询设备管理
      *
-     * @param ID 设备管理主键
+     * @param id 设备管理主键
      * @return 设备管理
      */
     @Override
-    public TwinDevice selectTwinDeviceByID(Long ID)
-    {
-        return twinDeviceMapper.selectTwinDeviceByID(ID);
+    public TwinDevice selectTwinDeviceById(Long id) {
+        return twinDeviceMapper.selectTwinDeviceById(id);
     }
 
     /**
@@ -41,8 +38,7 @@ public class TwinDeviceServiceImpl implements ITwinDeviceService
      * @return 设备管理
      */
     @Override
-    public List<TwinDevice> selectTwinDeviceList(TwinDevice twinDevice)
-    {
+    public List<TwinDevice> selectTwinDeviceList(TwinDevice twinDevice) {
         return twinDeviceMapper.selectTwinDeviceList(twinDevice);
     }
 
@@ -53,8 +49,7 @@ public class TwinDeviceServiceImpl implements ITwinDeviceService
      * @return 结果
      */
     @Override
-    public int insertTwinDevice(TwinDevice twinDevice)
-    {
+    public int insertTwinDevice(TwinDevice twinDevice) {
         return twinDeviceMapper.insertTwinDevice(twinDevice);
     }
 
@@ -65,32 +60,40 @@ public class TwinDeviceServiceImpl implements ITwinDeviceService
      * @return 结果
      */
     @Override
-    public int updateTwinDevice(TwinDevice twinDevice)
-    {
+    public int updateTwinDevice(TwinDevice twinDevice) {
         return twinDeviceMapper.updateTwinDevice(twinDevice);
     }
 
     /**
      * 批量删除设备管理
      *
-     * @param IDs 需要删除的设备管理主键
+     * @param ids 需要删除的设备管理主键
      * @return 结果
      */
     @Override
-    public int deleteTwinDeviceByIDs(String IDs)
-    {
-        return twinDeviceMapper.deleteTwinDeviceByIDs(Convert.toStrArray(IDs));
+    public int deleteTwinDeviceByIds(String ids) {
+        return twinDeviceMapper.deleteTwinDeviceByIds(Convert.toStrArray(ids));
     }
 
     /**
      * 删除设备管理信息
      *
-     * @param ID 设备管理主键
+     * @param id 设备管理主键
      * @return 结果
      */
     @Override
-    public int deleteTwinDeviceByID(Long ID)
-    {
-        return twinDeviceMapper.deleteTwinDeviceByID(ID);
+    public int deleteTwinDeviceById(Long id) {
+        return twinDeviceMapper.deleteTwinDeviceById(id);
+    }
+
+    /**
+     * 通过设备编号查询设备
+     *
+     * @param code 设备编号
+     * @return 设备信息
+     */
+    @Override
+    public TwinDevice selectTwinDeviceByCode(String code) {
+        return twinDeviceMapper.selectTwinDeviceByCode(code);
     }
 }

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/biz/service/impl/TwinRecordAlarmsServiceImpl.java

@@ -12,7 +12,7 @@ import com.ruoyi.common.core.text.Convert;
  * 告警数据记录Service业务层处理
  * 
  * @author ruoyi
- * @date 2024-05-15
+ * @date 2024-05-21
  */
 @Service
 public class TwinRecordAlarmsServiceImpl implements ITwinRecordAlarmsService 

+ 57 - 0
ruoyi-admin/src/main/java/com/ruoyi/biz/tools/IotTools.java

@@ -0,0 +1,57 @@
+package com.ruoyi.biz.tools;
+
+import cn.hutool.core.text.UnicodeUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * IotTools$
+ *
+ * @author wukai
+ * @date 2024/5/20 17:37
+ */
+@Slf4j
+public class IotTools {
+    /**
+     * 获取接口返回值
+     * 如果报错,则一直重试
+     *
+     * @param request request
+     * @return json
+     */
+    public static JSONObject getData(HttpRequest request) {
+        //连接超时时间 5秒
+        request.setConnectionTimeout(50000);
+        HttpResponse execute;
+        int times = 1;
+        while (true) {
+            try {
+                // 尝试执行的操作
+                execute = response(request);
+                // 如果操作成功,则不会执行以下代码
+                break; // 退出循环
+            } catch (Exception e) {
+                log.error("接口返回数据失败,正在第{}次重新请求!!!", times++);
+                try {
+                    Thread.sleep(1000);
+                    //暂停1秒一直重试
+                } catch (InterruptedException ignored) {
+                }
+            }
+        }
+        String res = UnicodeUtil.toString(execute.body());
+        return JSONUtil.parseObj(res, true);
+    }
+
+    public static HttpResponse response(HttpRequest request) throws Exception {
+        try (HttpResponse res = request.execute()) {
+            if (!res.isOk()) {
+                throw new RuntimeException(res.body());
+            }
+            return res;
+        }
+    }
+}

+ 16 - 9
ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml

@@ -3,7 +3,7 @@
 
     <!-- 磁盘缓存位置 -->
     <diskStore path="java.io.tmpdir"/>
-    
+
     <!-- maxEntriesLocalHeap:堆内存中最大缓存对象数,0没有限制 -->
     <!-- maxElementsInMemory: 在内存中缓存的element的最大数目。-->
     <!-- eternal:elements是否永久有效,如果为true,timeouts将被忽略,element将永不过期 -->
@@ -11,7 +11,15 @@
     <!-- timeToLiveSeconds:失效前的存活秒数,创建时间到失效时间的间隔为存活时间,当eternal为false时,这个属性才有效,0为不限制 -->
     <!-- overflowToDisk: 如果内存中数据超过内存限制,是否要缓存到磁盘上 -->
     <!-- statistics:是否收集统计信息。如果需要监控缓存使用情况,应该打开这个选项。默认为关闭(统计会影响性能)。设置statistics="true"开启统计 -->
-    
+    <!-- iot缓存 1800秒 -->
+    <cache name="iotCache"
+           maxEntriesLocalHeap="100"
+           eternal="false"
+           timeToIdleSeconds="1800"
+           timeToLiveSeconds="1800"
+           overflowToDisk="false"
+           statistics="false">
+    </cache>
     <!-- 默认缓存 -->
     <defaultCache
             maxEntriesLocalHeap="1000"
@@ -41,7 +49,7 @@
            timeToIdleSeconds="0"
            statistics="false">
     </cache>
-    
+
     <!-- 系统用户授权缓存  没必要过期 -->
     <cache name="sys-authCache"
            maxEntriesLocalHeap="10000"
@@ -52,7 +60,7 @@
            timeToIdleSeconds="0"
            memoryStoreEvictionPolicy="LRU"
            statistics="false"/>
-    
+
     <!-- 系统缓存 -->
     <cache name="sys-cache"
            maxEntriesLocalHeap="1000"
@@ -60,7 +68,7 @@
            overflowToDisk="true"
            statistics="false">
     </cache>
-    
+
     <!-- 系统参数缓存 -->
     <cache name="sys-config"
            maxEntriesLocalHeap="1000"
@@ -68,7 +76,7 @@
            overflowToDisk="true"
            statistics="false">
     </cache>
-    
+
     <!-- 系统字典缓存 -->
     <cache name="sys-dict"
            maxEntriesLocalHeap="1000"
@@ -76,7 +84,7 @@
            overflowToDisk="true"
            statistics="false">
     </cache>
-    
+
     <!-- 系统会话缓存 -->
     <cache name="shiro-activeSessionCache"
            maxEntriesLocalHeap="10000"
@@ -86,6 +94,5 @@
            timeToLiveSeconds="0"
            timeToIdleSeconds="0"
            statistics="false"/>
-    
+
 </ehcache>
-	

+ 47 - 30
ruoyi-admin/src/main/resources/mapper/biz/TwinDeviceMapper.xml

@@ -1,68 +1,83 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ruoyi.biz.mapper.TwinDeviceMapper">
 
     <resultMap type="TwinDevice" id="TwinDeviceResult">
-        <result property="ID"    column="ID"    />
-        <result property="deviceName"    column="DEVICE_NAME"    />
-        <result property="devicePath"    column="DEVICE_PATH"    />
-        <result property="createdBy"    column="CREATED_BY"    />
-        <result property="createdTime"    column="CREATED_TIME"    />
-        <result property="updatedBy"    column="UPDATED_BY"    />
-        <result property="updatedTime"    column="UPDATED_TIME"    />
-        <result property="remark"    column="REMARK"    />
+        <result property="id" column="ID"/>
+        <result property="deviceName" column="DEVICE_NAME"/>
+        <result property="deviceCode" column="DEVICE_CODE"/>
+        <result property="devicePath" column="DEVICE_PATH"/>
+        <result property="createdBy" column="CREATED_BY"/>
+        <result property="createdTime" column="CREATED_TIME"/>
+        <result property="updatedBy" column="UPDATED_BY"/>
+        <result property="updatedTime" column="UPDATED_TIME"/>
+        <result property="remark" column="REMARK"/>
     </resultMap>
 
     <sql id="selectTwinDeviceVo">
-        select ID, DEVICE_NAME, DEVICE_PATH, CREATED_BY, CREATED_TIME, UPDATED_BY, UPDATED_TIME, REMARK from twin_device
+        select ID,
+               DEVICE_NAME,
+               DEVICE_CODE,
+               DEVICE_PATH,
+               CREATED_BY,
+               CREATED_TIME,
+               UPDATED_BY,
+               UPDATED_TIME,
+               REMARK
+        from twin_device
     </sql>
 
     <select id="selectTwinDeviceList" parameterType="TwinDevice" resultMap="TwinDeviceResult">
         <include refid="selectTwinDeviceVo"/>
         <where>
-            <if test="deviceName != null  and deviceName != ''"> and DEVICE_NAME like concat('%', #{deviceName}, '%')</if>
-            <if test="devicePath != null  and devicePath != ''"> and DEVICE_PATH like concat('%', #{devicePath}, '%')</if>
-            <if test="createdBy != null  and createdBy != ''"> and CREATED_BY like concat('%', #{createdBy}, '%')</if>
-            <if test="params.beginCreatedTime != null and params.beginCreatedTime != '' and params.endCreatedTime != null and params.endCreatedTime != ''"> and CREATED_TIME between #{params.beginCreatedTime} and #{params.endCreatedTime}</if>
-            <if test="updatedBy != null  and updatedBy != ''"> and UPDATED_BY = #{updatedBy}</if>
-            <if test="params.beginUpdatedTime != null and params.beginUpdatedTime != '' and params.endUpdatedTime != null and params.endUpdatedTime != ''"> and UPDATED_TIME between #{params.beginUpdatedTime} and #{params.endUpdatedTime}</if>
-            <if test="remark != null  and remark != ''"> and REMARK like concat('%', #{remark}, '%')</if>
+            <if test="deviceName != null  and deviceName != ''">and DEVICE_NAME like concat('%', #{deviceName}, '%')
+            </if>
+            <if test="deviceCode != null  and deviceCode != ''">and DEVICE_CODE = #{deviceCode}</if>
+            <if test="devicePath != null  and devicePath != ''">and DEVICE_PATH = #{devicePath}</if>
+            <if test="remark != null  and remark != ''">and REMARK = #{remark}</if>
         </where>
     </select>
 
-    <select id="selectTwinDeviceByID" parameterType="Long" resultMap="TwinDeviceResult">
+    <select id="selectTwinDeviceById" parameterType="Long" resultMap="TwinDeviceResult">
         <include refid="selectTwinDeviceVo"/>
-        where ID = #{ID}
+        where ID = #{id}
+    </select>
+    <select id="selectTwinDeviceByCode" resultMap="TwinDeviceResult">
+        <include refid="selectTwinDeviceVo"/>
+        where DEVICE_CODE = #{code}
     </select>
 
-    <insert id="insertTwinDevice" parameterType="TwinDevice" useGeneratedKeys="true" keyProperty="ID">
+    <insert id="insertTwinDevice" parameterType="TwinDevice" useGeneratedKeys="true" keyProperty="id">
         insert into twin_device
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="deviceName != null">DEVICE_NAME,</if>
+            <if test="deviceCode != null">DEVICE_CODE,</if>
             <if test="devicePath != null">DEVICE_PATH,</if>
             <if test="createdBy != null">CREATED_BY,</if>
             <if test="createdTime != null">CREATED_TIME,</if>
             <if test="updatedBy != null">UPDATED_BY,</if>
             <if test="updatedTime != null">UPDATED_TIME,</if>
             <if test="remark != null">REMARK,</if>
-         </trim>
+        </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="deviceName != null">#{deviceName},</if>
+            <if test="deviceCode != null">#{deviceCode},</if>
             <if test="devicePath != null">#{devicePath},</if>
             <if test="createdBy != null">#{createdBy},</if>
             <if test="createdTime != null">#{createdTime},</if>
             <if test="updatedBy != null">#{updatedBy},</if>
             <if test="updatedTime != null">#{updatedTime},</if>
-            <if test="remark != null">#{REMARK},</if>
-         </trim>
+            <if test="remark != null">#{remark},</if>
+        </trim>
     </insert>
 
     <update id="updateTwinDevice" parameterType="TwinDevice">
         update twin_device
         <trim prefix="SET" suffixOverrides=",">
             <if test="deviceName != null">DEVICE_NAME = #{deviceName},</if>
+            <if test="deviceCode != null">DEVICE_CODE = #{deviceCode},</if>
             <if test="devicePath != null">DEVICE_PATH = #{devicePath},</if>
             <if test="createdBy != null">CREATED_BY = #{createdBy},</if>
             <if test="createdTime != null">CREATED_TIME = #{createdTime},</if>
@@ -70,17 +85,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="updatedTime != null">UPDATED_TIME = #{updatedTime},</if>
             <if test="remark != null">REMARK = #{remark},</if>
         </trim>
-        where ID = #{ID}
+        where ID = #{id}
     </update>
 
-    <delete id="deleteTwinDeviceByID" parameterType="Long">
-        delete from twin_device where ID = #{ID}
+    <delete id="deleteTwinDeviceById" parameterType="Long">
+        delete
+        from twin_device
+        where ID = #{id}
     </delete>
 
-    <delete id="deleteTwinDeviceByIDs" parameterType="String">
+    <delete id="deleteTwinDeviceByIds" parameterType="String">
         delete from twin_device where ID in
-        <foreach item="ID" collection="array" open="(" separator="," close=")">
-            #{ID}
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
         </foreach>
     </delete>
 

+ 6 - 1
ruoyi-admin/src/main/resources/mapper/biz/TwinRecordAlarmsMapper.xml

@@ -9,6 +9,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="deviceId"    column="DEVICE_ID"    />
         <result property="dataTime"    column="DATA_TIME"    />
         <result property="alarmType"    column="ALARM_TYPE"    />
+        <result property="alarmCode"    column="ALARM_CODE"    />
         <result property="createdBy"    column="CREATED_BY"    />
         <result property="createdTime"    column="CREATED_TIME"    />
         <result property="updatedBy"    column="UPDATED_BY"    />
@@ -17,7 +18,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
 
     <sql id="selectTwinRecordAlarmsVo">
-        select ID, DEVICE_ID, DATA_TIME, ALARM_TYPE, CREATED_BY, CREATED_TIME, UPDATED_BY, UPDATED_TIME, REMARK from twin_record_alarms
+        select ID, DEVICE_ID, DATA_TIME, ALARM_TYPE, ALARM_CODE, CREATED_BY, CREATED_TIME, UPDATED_BY, UPDATED_TIME, REMARK from twin_record_alarms
     </sql>
 
     <select id="selectTwinRecordAlarmsList" parameterType="TwinRecordAlarms" resultMap="TwinRecordAlarmsResult">
@@ -26,6 +27,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="deviceId != null "> and DEVICE_ID = #{deviceId}</if>
             <if test="dataTime != null "> and DATA_TIME = #{dataTime}</if>
             <if test="alarmType != null  and alarmType != ''"> and ALARM_TYPE = #{alarmType}</if>
+            <if test="alarmCode != null "> and ALARM_CODE = #{alarmCode}</if>
             <if test="createdBy != null  and createdBy != ''"> and CREATED_BY = #{createdBy}</if>
             <if test="createdTime != null "> and CREATED_TIME = #{createdTime}</if>
             <if test="updatedBy != null  and updatedBy != ''"> and UPDATED_BY = #{updatedBy}</if>
@@ -45,6 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="deviceId != null">DEVICE_ID,</if>
             <if test="dataTime != null">DATA_TIME,</if>
             <if test="alarmType != null">ALARM_TYPE,</if>
+            <if test="alarmCode != null">ALARM_CODE,</if>
             <if test="createdBy != null">CREATED_BY,</if>
             <if test="createdTime != null">CREATED_TIME,</if>
             <if test="updatedBy != null">UPDATED_BY,</if>
@@ -55,6 +58,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="deviceId != null">#{deviceId},</if>
             <if test="dataTime != null">#{dataTime},</if>
             <if test="alarmType != null">#{alarmType},</if>
+            <if test="alarmCode != null">#{alarmCode},</if>
             <if test="createdBy != null">#{createdBy},</if>
             <if test="createdTime != null">#{createdTime},</if>
             <if test="updatedBy != null">#{updatedBy},</if>
@@ -69,6 +73,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="deviceId != null">DEVICE_ID = #{deviceId},</if>
             <if test="dataTime != null">DATA_TIME = #{dataTime},</if>
             <if test="alarmType != null">ALARM_TYPE = #{alarmType},</if>
+            <if test="alarmCode != null">ALARM_CODE = #{alarmCode},</if>
             <if test="createdBy != null">CREATED_BY = #{createdBy},</if>
             <if test="createdTime != null">CREATED_TIME = #{createdTime},</if>
             <if test="updatedBy != null">UPDATED_BY = #{updatedBy},</if>

+ 49 - 0
ruoyi-admin/src/main/resources/templates/biz/biz/add.html

@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('新增设备管理')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-biz-add">
+            <div class="form-group">    
+                <label class="col-sm-3 control-label">设备名称:</label>
+                <div class="col-sm-8">
+                    <input name="deviceName" class="form-control" type="text">
+                </div>
+            </div>
+            <div class="form-group">    
+                <label class="col-sm-3 control-label">设备编码:</label>
+                <div class="col-sm-8">
+                    <input name="deviceCode" class="form-control" type="text">
+                </div>
+            </div>
+            <div class="form-group">    
+                <label class="col-sm-3 control-label">设备路径:</label>
+                <div class="col-sm-8">
+                    <input name="devicePath" class="form-control" type="text">
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="col-sm-3 control-label">备注:</label>
+                <div class="col-sm-8">
+                    <textarea name="remark" class="form-control"></textarea>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "biz/biz"
+        $("#form-biz-add").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/add", $('#form-biz-add').serialize());
+            }
+        }
+    </script>
+</body>
+</html>

+ 122 - 0
ruoyi-admin/src/main/resources/templates/biz/biz/biz.html

@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
+<head>
+    <th:block th:include="include :: header('设备管理列表')" />
+</head>
+<body class="gray-bg">
+     <div class="container-div">
+        <div class="row">
+            <div class="col-sm-12 search-collapse">
+                <form id="formId">
+                    <div class="select-list">
+                        <ul>
+                            <li>
+                                <label>设备名称:</label>
+                                <input type="text" name="deviceName"/>
+                            </li>
+                            <li>
+                                <label>设备编码:</label>
+                                <input type="text" name="deviceCode"/>
+                            </li>
+                            <li>
+                                <label>设备路径:</label>
+                                <input type="text" name="devicePath"/>
+                            </li>
+                            <li>
+                                <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;搜索</a>
+                                <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;重置</a>
+                            </li>
+                        </ul>
+                    </div>
+                </form>
+            </div>
+
+            <div class="btn-group-sm" id="toolbar" role="group">
+                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="biz:biz:add">
+                    <i class="fa fa-plus"></i> 添加
+                </a>
+                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="biz:biz:edit">
+                    <i class="fa fa-edit"></i> 修改
+                </a>
+                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="biz:biz:remove">
+                    <i class="fa fa-remove"></i> 删除
+                </a>
+                <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="biz:biz:export">
+                    <i class="fa fa-download"></i> 导出
+                </a>
+            </div>
+            <div class="col-sm-12 select-table table-striped">
+                <table id="bootstrap-table"></table>
+            </div>
+        </div>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var editFlag = [[${@permission.hasPermi('biz:biz:edit')}]];
+        var removeFlag = [[${@permission.hasPermi('biz:biz:remove')}]];
+        var prefix = ctx + "biz/biz";
+
+        $(function() {
+            var options = {
+                url: prefix + "/list",
+                createUrl: prefix + "/add",
+                updateUrl: prefix + "/edit/{id}",
+                removeUrl: prefix + "/remove",
+                exportUrl: prefix + "/export",
+                modalName: "设备管理",
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'id',
+                    title: 'ID',
+                    visible: false
+                },
+                {
+                    field: 'deviceName',
+                    title: '设备名称'
+                },
+                {
+                    field: 'deviceCode',
+                    title: '设备编码'
+                },
+                {
+                    field: 'devicePath',
+                    title: '设备路径'
+                },
+                {
+                    field: 'createdBy',
+                    title: '创建人'
+                },
+                {
+                    field: 'createdTime',
+                    title: '创建时间'
+                },
+                {
+                    field: 'updatedBy',
+                    title: '更新人'
+                },
+                {
+                    field: 'updatedTime',
+                    title: '更新时间'
+                },
+                {
+                    field: 'remark',
+                    title: '备注'
+                },
+                {
+                    title: '操作',
+                    align: 'center',
+                    formatter: function(value, row, index) {
+                        var actions = [];
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.id + '\')"><i class="fa fa-edit"></i>编辑</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.id + '\')"><i class="fa fa-remove"></i>删除</a>');
+                        return actions.join('');
+                    }
+                }]
+            };
+            $.table.init(options);
+        });
+    </script>
+</body>
+</html>

+ 50 - 0
ruoyi-admin/src/main/resources/templates/biz/biz/edit.html

@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('修改设备管理')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-biz-edit" th:object="${twinDevice}">
+            <input name="id" th:field="*{id}" type="hidden">
+            <div class="form-group">    
+                <label class="col-sm-3 control-label">设备名称:</label>
+                <div class="col-sm-8">
+                    <input name="deviceName" th:field="*{deviceName}" class="form-control" type="text">
+                </div>
+            </div>
+            <div class="form-group">    
+                <label class="col-sm-3 control-label">设备编码:</label>
+                <div class="col-sm-8">
+                    <input name="deviceCode" th:field="*{deviceCode}" class="form-control" type="text">
+                </div>
+            </div>
+            <div class="form-group">    
+                <label class="col-sm-3 control-label">设备路径:</label>
+                <div class="col-sm-8">
+                    <input name="devicePath" th:field="*{devicePath}" class="form-control" type="text">
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="col-sm-3 control-label">备注:</label>
+                <div class="col-sm-8">
+                    <textarea name="remark" class="form-control">[[*{remark}]]</textarea>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "biz/biz";
+        $("#form-biz-edit").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/edit", $('#form-biz-edit').serialize());
+            }
+        }
+    </script>
+</body>
+</html>

+ 37 - 31
ruoyi-admin/src/main/resources/templates/biz/device/add.html

@@ -4,40 +4,46 @@
     <th:block th:include="include :: header('新增设备管理')" />
 </head>
 <body class="white-bg">
-    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
-        <form class="form-horizontal m" id="form-device-add">
-            <div class="form-group">    
-                <label class="col-sm-3 control-label">设备名称:</label>
-                <div class="col-sm-8">
-                    <input name="deviceName" class="form-control" type="text">
-                </div>
+<div class="wrapper wrapper-content animated fadeInRight ibox-content">
+    <form class="form-horizontal m" id="form-biz-add">
+        <div class="form-group">
+            <label class="col-sm-3 control-label">设备名称:</label>
+            <div class="col-sm-8">
+                <input name="deviceName" class="form-control" type="text">
             </div>
-            <div class="form-group">    
-                <label class="col-sm-3 control-label">设备路径:</label>
-                <div class="col-sm-8">
-                    <input name="devicePath" class="form-control" type="text">
-                </div>
+        </div>
+        <div class="form-group">
+            <label class="col-sm-3 control-label">设备编码:</label>
+            <div class="col-sm-8">
+                <input name="deviceCode" class="form-control" type="text">
             </div>
-            <div class="form-group">
-                <label class="col-sm-3 control-label">备注:</label>
-                <div class="col-sm-8">
-                    <textarea name="REMARK" class="form-control"></textarea>
-                </div>
+        </div>
+        <div class="form-group">
+            <label class="col-sm-3 control-label">设备路径:</label>
+            <div class="col-sm-8">
+                <input name="devicePath" class="form-control" type="text">
             </div>
-        </form>
-    </div>
-    <th:block th:include="include :: footer" />
-    <script th:inline="javascript">
-        var prefix = ctx + "biz/device"
-        $("#form-device-add").validate({
-            focusCleanup: true
-        });
+        </div>
+        <div class="form-group">
+            <label class="col-sm-3 control-label">备注:</label>
+            <div class="col-sm-8">
+                <textarea name="remark" class="form-control"></textarea>
+            </div>
+        </div>
+    </form>
+</div>
+<th:block th:include="include :: footer" />
+<script th:inline="javascript">
+    var prefix = ctx + "biz/biz"
+    $("#form-biz-add").validate({
+        focusCleanup: true
+    });
 
-        function submitHandler() {
-            if ($.validate.form()) {
-                $.operate.save(prefix + "/add", $('#form-device-add').serialize());
-            }
+    function submitHandler() {
+        if ($.validate.form()) {
+            $.operate.save(prefix + "/add", $('#form-biz-add').serialize());
         }
-    </script>
+    }
+</script>
 </body>
-</html>
+</html>

+ 35 - 27
ruoyi-admin/src/main/resources/templates/biz/device/device.html

@@ -15,6 +15,10 @@
                             <input type="text" name="deviceName"/>
                         </li>
                         <li>
+                            <label>设备编码:</label>
+                            <input type="text" name="deviceCode"/>
+                        </li>
+                        <li>
                             <label>设备路径:</label>
                             <input type="text" name="devicePath"/>
                         </li>
@@ -28,16 +32,16 @@
         </div>
 
         <div class="btn-group-sm" id="toolbar" role="group">
-            <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="biz:device:add">
+            <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="biz:biz:add">
                 <i class="fa fa-plus"></i> 添加
             </a>
-            <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="biz:device:edit">
+            <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="biz:biz:edit">
                 <i class="fa fa-edit"></i> 修改
             </a>
-            <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="biz:device:remove">
+            <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="biz:biz:remove">
                 <i class="fa fa-remove"></i> 删除
             </a>
-            <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="biz:device:export">
+            <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="biz:biz:export">
                 <i class="fa fa-download"></i> 导出
             </a>
         </div>
@@ -48,9 +52,9 @@
 </div>
 <th:block th:include="include :: footer" />
 <script th:inline="javascript">
-    var editFlag = [[${@permission.hasPermi('biz:device:edit')}]];
-    var removeFlag = [[${@permission.hasPermi('biz:device:remove')}]];
-    var prefix = ctx + "biz/device";
+    var editFlag = [[${@permission.hasPermi('biz:biz:edit')}]];
+    var removeFlag = [[${@permission.hasPermi('biz:biz:remove')}]];
+    var prefix = ctx + "biz/biz";
 
     $(function() {
         var options = {
@@ -64,7 +68,7 @@
                 checkbox: true
             },
                 {
-                    field: 'ID',
+                    field: 'id',
                     title: 'ID',
                     visible: false
                 },
@@ -73,27 +77,31 @@
                     title: '设备名称'
                 },
                 {
+                    field: 'deviceCode',
+                    title: '设备编码'
+                },
+                {
                     field: 'devicePath',
                     title: '设备路径'
                 },
-                // {
-                //     field: 'createdBy',
-                //     title: '创建人'
-                // },
-                // {
-                //     field: 'createdTime',
-                //     title: '创建时间'
-                // },
-                // {
-                //     field: 'updatedBy',
-                //     title: '更新人'
-                // },
-                // {
-                //     field: 'updatedTime',
-                //     title: '更新时间'
-                // },
                 {
-                    field: 'REMARK',
+                    field: 'createdBy',
+                    title: '创建人'
+                },
+                {
+                    field: 'createdTime',
+                    title: '创建时间'
+                },
+                {
+                    field: 'updatedBy',
+                    title: '更新人'
+                },
+                {
+                    field: 'updatedTime',
+                    title: '更新时间'
+                },
+                {
+                    field: 'remark',
                     title: '备注'
                 },
                 {
@@ -101,8 +109,8 @@
                     align: 'center',
                     formatter: function(value, row, index) {
                         var actions = [];
-                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.ID + '\')"><i class="fa fa-edit"></i>编辑</a> ');
-                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.ID + '\')"><i class="fa fa-remove"></i>删除</a>');
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.id + '\')"><i class="fa fa-edit"></i>编辑</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.id + '\')"><i class="fa fa-remove"></i>删除</a>');
                         return actions.join('');
                     }
                 }]

+ 37 - 48
ruoyi-admin/src/main/resources/templates/biz/device/edit.html

@@ -2,60 +2,49 @@
 <html lang="zh" xmlns:th="http://www.thymeleaf.org" >
 <head>
     <th:block th:include="include :: header('修改设备管理')" />
-    <th:block th:include="include :: datetimepicker-css" />
 </head>
 <body class="white-bg">
-    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
-        <form class="form-horizontal m" id="form-device-edit" th:object="${twinDevice}">
-            <input name="ID" th:field="*{ID}" type="hidden">
-            <div class="form-group">    
-                <label class="col-sm-3 control-label">设备名称:</label>
-                <div class="col-sm-8">
-                    <input name="deviceName" th:field="*{deviceName}" class="form-control" type="text">
-                </div>
+<div class="wrapper wrapper-content animated fadeInRight ibox-content">
+    <form class="form-horizontal m" id="form-biz-edit" th:object="${twinDevice}">
+        <input name="id" th:field="*{id}" type="hidden">
+        <div class="form-group">
+            <label class="col-sm-3 control-label">设备名称:</label>
+            <div class="col-sm-8">
+                <input name="deviceName" th:field="*{deviceName}" class="form-control" type="text">
             </div>
-            <div class="form-group">    
-                <label class="col-sm-3 control-label">设备路径:</label>
-                <div class="col-sm-8">
-                    <input name="devicePath" th:field="*{devicePath}" class="form-control" type="text">
-                </div>
+        </div>
+        <div class="form-group">
+            <label class="col-sm-3 control-label">设备编码:</label>
+            <div class="col-sm-8">
+                <input name="deviceCode" th:field="*{deviceCode}" class="form-control" type="text">
             </div>
-            <div class="form-group">    
-                <label class="col-sm-3 control-label">更新时间:</label>
-                <div class="col-sm-8">
-                    <div class="input-group date">
-                        <input name="updatedTime" th:value="${#dates.format(twinDevice.updatedTime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
-                        <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
-                    </div>
-                </div>
+        </div>
+        <div class="form-group">
+            <label class="col-sm-3 control-label">设备路径:</label>
+            <div class="col-sm-8">
+                <input name="devicePath" th:field="*{devicePath}" class="form-control" type="text">
             </div>
-            <div class="form-group">
-                <label class="col-sm-3 control-label">备注:</label>
-                <div class="col-sm-8">
-                    <textarea name="REMARK" class="form-control">[[*{REMARK}]]</textarea>
-                </div>
+        </div>
+        <div class="form-group">
+            <label class="col-sm-3 control-label">备注:</label>
+            <div class="col-sm-8">
+                <textarea name="remark" class="form-control">[[*{remark}]]</textarea>
             </div>
-        </form>
-    </div>
-    <th:block th:include="include :: footer" />
-    <th:block th:include="include :: datetimepicker-js" />
-    <script th:inline="javascript">
-        var prefix = ctx + "biz/device";
-        $("#form-device-edit").validate({
-            focusCleanup: true
-        });
+        </div>
+    </form>
+</div>
+<th:block th:include="include :: footer" />
+<script th:inline="javascript">
+    var prefix = ctx + "biz/biz";
+    $("#form-biz-edit").validate({
+        focusCleanup: true
+    });
 
-        function submitHandler() {
-            if ($.validate.form()) {
-                $.operate.save(prefix + "/edit", $('#form-device-edit').serialize());
-            }
+    function submitHandler() {
+        if ($.validate.form()) {
+            $.operate.save(prefix + "/edit", $('#form-biz-edit').serialize());
         }
-
-        $("input[name='updatedTime']").datetimepicker({
-            format: "yyyy-mm-dd",
-            minView: "month",
-            autoclose: true
-        });
-    </script>
+    }
+</script>
 </body>
-</html>
+</html>

+ 6 - 0
ruoyi-admin/src/main/resources/templates/biz/record/add.html

@@ -23,6 +23,12 @@
                 </div>
             </div>
             <div class="form-group">    
+                <label class="col-sm-3 control-label">告警编号;接口对应的编号:</label>
+                <div class="col-sm-8">
+                    <input name="alarmCode" class="form-control" type="text">
+                </div>
+            </div>
+            <div class="form-group">    
                 <label class="col-sm-3 control-label">创建人:</label>
                 <div class="col-sm-8">
                     <input name="createdBy" class="form-control" type="text">

+ 6 - 0
ruoyi-admin/src/main/resources/templates/biz/record/edit.html

@@ -24,6 +24,12 @@
                 </div>
             </div>
             <div class="form-group">    
+                <label class="col-sm-3 control-label">告警编号;接口对应的编号:</label>
+                <div class="col-sm-8">
+                    <input name="alarmCode" th:field="*{alarmCode}" class="form-control" type="text">
+                </div>
+            </div>
+            <div class="form-group">    
                 <label class="col-sm-3 control-label">创建人:</label>
                 <div class="col-sm-8">
                     <input name="createdBy" th:field="*{createdBy}" class="form-control" type="text">

+ 8 - 0
ruoyi-admin/src/main/resources/templates/biz/record/record.html

@@ -19,6 +19,10 @@
                                 <input type="text" class="time-input" placeholder="请选择告警时间" name="dataTime"/>
                             </li>
                             <li>
+                                <label>告警编号;接口对应的编号:</label>
+                                <input type="text" name="alarmCode"/>
+                            </li>
+                            <li>
                                 <label>创建人:</label>
                                 <input type="text" name="createdBy"/>
                             </li>
@@ -97,6 +101,10 @@
                     title: '告警类型'
                 },
                 {
+                    field: 'alarmCode',
+                    title: '告警编号;接口对应的编号'
+                },
+                {
                     field: 'createdBy',
                     title: '创建人'
                 },

+ 32 - 12
ruoyi-admin/src/test/java/com/jjt/DataPF.java

@@ -4,16 +4,21 @@ import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import com.ruoyi.RuoYiApplication;
 import com.ruoyi.biz.domain.TwinDevice;
+import com.ruoyi.biz.domain.TwinRecordAlarms;
 import com.ruoyi.biz.service.IIotService;
-import com.ruoyi.biz.service.ITwinCalc2hrService;
+import com.ruoyi.biz.service.ITaskService;
 import com.ruoyi.biz.service.ITwinDeviceService;
+import com.ruoyi.biz.service.impl.AsyncServiceImpl;
+import javafx.util.Pair;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.EnableAsync;
 
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -23,6 +28,7 @@ import java.util.Map;
  * @author wukai
  * @date 2024/5/7 11:49
  */
+@EnableAsync
 @SpringBootTest(classes = RuoYiApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 public class DataPF {
     @Resource
@@ -32,17 +38,20 @@ public class DataPF {
     @Resource
     private ITwinDeviceService deviceService;
     @Resource
-    private ITwinCalc2hrService calc2hrService;
+    private ITaskService calc2hrService;
+    @Resource
+    private AsyncServiceImpl asyncService;
 
     public static void main(String[] args) {
         LocalDateTime ldt = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);
         //当前时间之前的偶数时间段
-        ldt = ldt.minusHours(2).minusHours(ldt.getHour() % 2);
+        ldt = ldt.minusHours(ldt.getHour() % 2);
         //开始时间需要向前取一秒
         LocalDateTime start = ldt.minusSeconds(1);
         //获取时段范围 时间 1=0-2点 2=2-4
         int period = start.getHour() / 2 + 1;
         LocalDateTime end = ldt.plusHours(2);
+        System.err.println(start + "" + end);
         Long startTime = start.toInstant(ZoneOffset.of("+8")).toEpochMilli();
         Long endTime = end.toInstant(ZoneOffset.of("+8")).toEpochMilli();
     }
@@ -54,13 +63,20 @@ public class DataPF {
 //        calc2hrService.calc("2024-05-12");
 //        calc2hrService.calc("2024-05-13");
 //        calc2hrService.calc("2024-05-14");
-        calc2hrService.calc("2024-05-15");
-//        String table = "root.tl.suxi.knittings106_plc1";
-////        long startTime = 1715601599000l;
-////        long endTime = 1715608800000l;
-//        long startTime = 1715588663000l;
-//        long endTime = 1715588783000l;
-//        Map<String, Object> map = calc2hrService.calc(table, startTime, endTime);
+//        calc2hrService.calc("2024-05-15");
+        calc2hrService.calc("2024-05-16");
+        calc2hrService.calc("2024-05-17");
+        calc2hrService.calc("2024-05-18");
+        calc2hrService.calc("2024-05-19");
+        calc2hrService.calc("2024-05-20");
+//        String table = "root.tl.suxi.knittings97_plc1";
+//        long startTime = 1715709599000l;
+//        long endTime = 1715716800000l;
+////        long startTime = 1715939999000l;
+////        System.err.println(new Date(startTime));
+////        long endTime = 1715954400000l;
+////        System.err.println(new Date(endTime));
+//        Map<String, Object> map = asyncService.calc(table, startTime, endTime);
 //        System.err.println(map);
 //        float[] total = (float[]) map.get("total");
 //        for (float d : total) {
@@ -71,6 +87,10 @@ public class DataPF {
 //        for (int d : times) {
 //            System.err.println(d);
 //        }
+//        List<Pair<String, Long>> alarmRecord = (List<Pair<String, Long>>) map.get("alarmRecord");
+//        alarmRecord.forEach(pair -> {
+//            System.err.println(pair.getKey() + "\t" + pair.getValue());
+//        });
 //        System.err.println(map.get("alarms"));
     }
 
@@ -78,7 +98,7 @@ public class DataPF {
     void test() {
         deviceService.selectTwinDeviceList(new TwinDevice()).forEach(twinDevice -> {
             String table = twinDevice.getDevicePath();
-            String sql = "select Alarm_unit_27 from %s where Alarm_unit_27<>0 limit 1000";
+            String sql = "select Capacity_data_2,Capacity_data_37,Capacity_data_38,Capacity_data_39,Capacity_data_42,Capacity_data_43,Capacity_data_44,Capacity_data_48 from %s where Alarm_unit_27<>0 limit 1000";
             sql = String.format(sql, table);
             JSONObject jsonObject = iotService.query(sql);
 
@@ -86,7 +106,7 @@ public class DataPF {
             JSONArray values = data.getJSONArray("values");
             JSONArray timestamps = data.getJSONArray("timestamps");
             if (timestamps.size() > 0) {
-                System.err.println(table+"\t"+timestamps.get(0));
+                System.err.println(table + "\t" + timestamps.get(0));
             }
         });
     }

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 2
ruoyi-admin/src/test/java/com/jjt/DataProcess.java


+ 1 - 14
ruoyi-admin/src/test/java/com/jjt/DataProcess2hr.java

@@ -81,24 +81,11 @@ public class DataProcess2hr {
 
     @Test
     void process(String table, String where) {
-        String uri = "http://192.168.66.190:81/api/cnv-device/data-point/timeseries/query";
-        JSONObject object = new JSONObject();
         String sql = "select Capacity_data_2,Capacity_data_39,Capacity_data_44,Capacity_data_48" +
                 " from " + table +
                 " where " + where;
-        object.set("sql", sql);
-        HttpRequest request = HttpUtil.createPost(uri);//.setHttpProxy("127.0.0.1", 5343);
-        request.setMethod(Method.POST);
-        String token = iotService.getToken();
-        request.header("Blade-Auth", "bearer " + token);
-        request.body(object.toString());
-        HttpResponse execute = request.execute();
-        if (!execute.isOk()) {
-            throw new RuntimeException(execute.body());
-        }
-        String res = UnicodeUtil.toString(execute.body());
 //        System.err.println(res);
-        JSONObject jsonObject = JSONUtil.parseObj(res, true);
+        JSONObject jsonObject = iotService.query(sql);
         JSONObject data = jsonObject.getJSONObject("data");
         JSONArray values = data.getJSONArray("values");
         JSONArray columnNames = data.getJSONArray("columnNames");

+ 0 - 20
ruoyi-admin/src/test/java/com/jjt/TwinApplicationTests.java

@@ -1,20 +0,0 @@
-package com.jjt;
-
-import com.ruoyi.biz.service.IIotService;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import javax.annotation.Resource;
-
-@SpringBootTest
-class TwinApplicationTests {
-    @Resource
-    IIotService iotService;
-
-    @Test
-    void contextLoads() {
-        String token = iotService.getToken();
-        System.err.println(token);
-    }
-
-}

+ 25 - 21
ruoyi-common/src/main/java/com/ruoyi/common/config/thread/ThreadPoolConfig.java

@@ -1,13 +1,14 @@
 package com.ruoyi.common.config.thread;
 
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadPoolExecutor;
+import com.ruoyi.common.utils.Threads;
 import org.apache.commons.lang3.concurrent.BasicThreadFactory;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
-import com.ruoyi.common.utils.Threads;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
 
 /**
  * 线程池配置
@@ -15,23 +16,29 @@ import com.ruoyi.common.utils.Threads;
  * @author ruoyi
  **/
 @Configuration
-public class ThreadPoolConfig
-{
-    // 核心线程池大小
-    private int corePoolSize = 50;
+public class ThreadPoolConfig {
+    /**
+     * 核心线程池大小
+     */
+    private int corePoolSize = 20;
 
-    // 最大可创建的线程数
-    private int maxPoolSize = 200;
+    /**
+     * 最大可创建的线程数
+     */
+    private int maxPoolSize = 20;
 
-    // 队列最大长度
-    private int queueCapacity = 1000;
+    /**
+     * 队列最大长度
+     */
+    private int queueCapacity = 100;
 
-    // 线程池维护线程所允许的空闲时间
+    /**
+     * 线程池维护线程所允许的空闲时间
+     */
     private int keepAliveSeconds = 300;
 
     @Bean(name = "threadPoolTaskExecutor")
-    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
-    {
+    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         executor.setMaxPoolSize(maxPoolSize);
         executor.setCorePoolSize(corePoolSize);
@@ -46,15 +53,12 @@ public class ThreadPoolConfig
      * 执行周期性或定时任务
      */
     @Bean(name = "scheduledExecutorService")
-    protected ScheduledExecutorService scheduledExecutorService()
-    {
+    protected ScheduledExecutorService scheduledExecutorService() {
         return new ScheduledThreadPoolExecutor(corePoolSize,
                 new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
-                new ThreadPoolExecutor.CallerRunsPolicy())
-        {
+                new ThreadPoolExecutor.CallerRunsPolicy()) {
             @Override
-            protected void afterExecute(Runnable r, Throwable t)
-            {
+            protected void afterExecute(Runnable r, Throwable t) {
                 super.afterExecute(r, t);
                 Threads.printException(r, t);
             }

+ 3 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/Tools.java

@@ -1,5 +1,8 @@
 package com.ruoyi.common.utils;
 
+import com.ruoyi.common.json.JSONObject;
+import com.sun.deploy.net.HttpResponse;
+
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels