Эх сурвалжийг харах

1.添加工作诊断单独记录
2.模型部分优化
3.L2完善为数据变化才推送

wangxiaofei 4 өдөр өмнө
parent
commit
43af97a31c
32 өөрчлөгдсөн 918 нэмэгдсэн , 251 устгасан
  1. 4 0
      README.md
  2. 20 15
      docker/Dockerfile
  3. 0 3
      docker/docker-compose-l1.yml
  4. 4 5
      docker/docker-compose.yml
  5. 1 1
      docker/docker部署流程.md
  6. 8 0
      taphole-admin/pom.xml
  7. 1 1
      taphole-admin/src/main/resources/application-dev.yml
  8. 53 0
      taphole-admin/src/main/resources/application-pre.yml
  9. 2 2
      taphole-admin/src/main/resources/application-test.yml
  10. 53 0
      taphole-iron/src/main/java/com/sckj/iron/constant/ExpressionConstants.java
  11. 4 0
      taphole-iron/src/main/java/com/sckj/iron/constant/ParamsConstants.java
  12. 1 1
      taphole-iron/src/main/java/com/sckj/iron/controller/TCameraController.java
  13. 71 0
      taphole-iron/src/main/java/com/sckj/iron/controller/TIronTestController.java
  14. 11 1
      taphole-iron/src/main/java/com/sckj/iron/controller/TIronVisualScreenController.java
  15. 3 3
      taphole-iron/src/main/java/com/sckj/iron/entity/TIronModel.java
  16. 48 0
      taphole-iron/src/main/java/com/sckj/iron/entity/TIronTest.java
  17. 13 0
      taphole-iron/src/main/java/com/sckj/iron/mapper/TIronTestMapper.java
  18. 10 1
      taphole-iron/src/main/java/com/sckj/iron/service/impl/TIronModelServiceImpl.java
  19. 154 0
      taphole-iron/src/main/java/com/sckj/iron/service/impl/TIronTestServiceImpl.java
  20. 200 162
      taphole-iron/src/main/java/com/sckj/iron/socketio/DeviceEventListener.java
  21. 1 1
      taphole-iron/src/main/java/com/sckj/iron/socketio/PushData.java
  22. 32 0
      taphole-iron/src/main/java/com/sckj/iron/validate/TIronTestCreateValidate.java
  23. 36 0
      taphole-iron/src/main/java/com/sckj/iron/validate/TIronTestSearchValidate.java
  24. 41 0
      taphole-iron/src/main/java/com/sckj/iron/validate/TIronTestUpdateValidate.java
  25. 33 0
      taphole-iron/src/main/java/com/sckj/iron/vo/TIronTestDetailVo.java
  26. 39 0
      taphole-iron/src/main/java/com/sckj/iron/vo/TIronTestListedVo.java
  27. 3 1
      taphole-l2-start/src/main/java/com/sckj/l2start/listener/L2EventListener.java
  28. 53 38
      taphole-opc/src/main/java/com/sckj/opc/dataservice/HDServiceImpl.java
  29. 3 0
      taphole-opc/src/main/java/com/sckj/opc/entity/OPCData.java
  30. 8 11
      taphole-warn/src/main/java/com/sckj/warn/controller/TExceptionLogController.java
  31. 2 2
      taphole-warn/src/main/java/com/sckj/warn/entity/TExceptionLog.java
  32. 6 3
      taphole-warn/src/main/java/com/sckj/warn/service/impl/TExceptionLogServiceImpl.java

+ 4 - 0
README.md

@@ -39,3 +39,7 @@
 ##4	设备编号管理	自定义设备编号
 ##5	接入协议管理	提供基于网络协议的对接协议管理功能
 ##6	摄像头	实现摄像头基础信息的增删改查;
+
+
+
+BF4_1_IRONNOTCH_RAILLINE_ACPIRON_SPEED1(1TH-1号车受铁速度)获取数据成功,数据:[HDRecord timestamp=2025-05-31 00:24:10:691 value=-677.5031]

+ 20 - 15
docker/Dockerfile

@@ -5,29 +5,34 @@ FROM openjdk:8-jre
 ENV TZ=Asia/Shanghai
 RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
 
+
+# 创建存放库文件的目录
+#RUN mkdir -p /home/taphole/hdsdk/linux
+
+# 复制宿主机的库文件到镜像内
+#COPY hdsdk/linux/*.so.1.0.0 /home/taphole/hdsdk/linux
+
+# 为 /app/libs 目录下所有 .so.1.0.0 文件创建软连接
+#//RUN for file in /home/taphole/hdsdk/linux/*.so.1.0.0; do \
+#//        base_name=$(basename "$file" .so.1.0.0); \
+#//        ln -s "$file" "/home/taphole/hdsdk/linux/${base_name}.so"; \
+#//    done
+
+# 设置 LD_LIBRARY_PATH 环境变量
+#ENV LD_LIBRARY_PATH=/home/taphole/hdsdk/linux:$LD_LIBRARY_PATH
+
+
 # 设置工作目录
 WORKDIR /app
 
 # 复制项目依赖文件
-COPY target/taphole-admin-1.0.0.jar /app/springboot-app.jar
-
-
-# [复制 FFmpeg 静态二进制文件]  ffmpeg和ffprobe请务必要和loadFFmpeg.propertis中的path保持一致
-#COPY ffmpeg/ffmpeg  /usr/local/ffmpeg/bin/ffmpeg
-#COPY ffmpeg/ffprobe /usr/local/ffmpeg/bin/ffprobe
+COPY app/taphole-admin-1.0.0.jar /app/springboot-app.jar
 
-# 确保 FFmpeg 可执行
-#RUN chmod +x /usr/local/ffmpeg/bin/ffmpeg /usr/local/ffmpeg/bin/ffprobe
 
 
 # 暴露应用端口
-EXPOSE 8080 33000
+EXPOSE 8080 33000 4567 8087
 
-# 设置环境变量
-#ENV SPRING_DATASOURCE_URL=jdbc:mysql://<MYSQL_HOST>:<MYSQL_PORT>/<DATABASE_NAME>
-#ENV SPRING_DATASOURCE_USERNAME=<MYSQL_USER>
-#ENV SPRING_DATASOURCE_PASSWORD=<MYSQL_PASSWORD>
-#ENV SPRING_DATASOURCE_DRIVER_CLASS_NAME=com.alibaba.druid.pool.DruidDataSource
 
 # 启动 Spring Boot 应用
-ENTRYPOINT ["java", "-jar", "springboot-app.jar"]
+ENTRYPOINT ["java", "-jar", "springboot-app.jar"]

+ 0 - 3
docker/docker-compose-l1.yml

@@ -99,10 +99,7 @@ services:
       context: ./l1
       dockerfile: Dockerfile
     volumes:
-      # - ./target/taphole-admin-1.0.0.jar:/app/my-springboot-app.jar
-      #- ./target/loadFFmpeg.properties:/app/loadFFmpeg.properties
       - /home/taphole/logs:/app/logs
-      # - /usr/local/ffmpeg/bin:/usr/local/ffmpeg/bin
     ports:
       - "58080:8080"
       - "53000:33000"

+ 4 - 5
docker/docker-compose.yml

@@ -93,10 +93,9 @@ services:
   app:
     image: taphole-app:latest
     container_name: taphole-app
-    restart: always
     build:
-      context: ./app
-      dockerfile: Dockerfile
+      context: .
+      dockerfile: app/Dockerfile
     volumes:
       - /home/taphole/hcsdk/linux:/home/taphole/hcsdk/linux
       - /home/taphole/hdsdk/linux:/home/taphole/hdsdk/linux
@@ -114,6 +113,7 @@ services:
       - SPRING_DATASOURCE_PASSWORD=root
       - SPRING_REDIS_HOST=redis
       - SPRING_REDIS_PORT=6379
+      - LD_LIBRARY_PATH=/home/taphole/hdsdk/linux:$LD_LIBRARY_PATH  # 再次设置库文件路径
     depends_on:
       - mysql
       - redis
@@ -125,7 +125,6 @@ services:
   l2:
     image: taphole-l2:latest
     container_name: taphole-l2
-    restart: always
     build:
       context: ./l2
       dockerfile: Dockerfile
@@ -148,4 +147,4 @@ services:
       - redis
     networks:
       taphole:
-        ipv4_address: 172.28.1.200
+        ipv4_address: 172.28.1.200

+ 1 - 1
docker/docker部署流程.md

@@ -106,7 +106,7 @@
     
     1.ffmpeg静态解压包,内部含有文件:ffmepg  ffprobe
     2.mysql的配置文件mysql.cnf,初始化数据库语句
-    3.target文件夹,存放jar包和loadFFmpeg.propertis
+    3.app文件夹,存放jar包和loadFFmpeg.propertis
 
 六、arm架构
     docker pull --platform linux/arm64/v8 mpromonet/webrtc-streamer:v0.8.8

+ 8 - 0
taphole-admin/pom.xml

@@ -172,6 +172,14 @@
             </properties>
         </profile>
         <profile>
+            <id>pre</id>
+            <properties>
+                <profiles.active>pre</profiles.active>
+                <maven.test.skip>true</maven.test.skip>
+                <project.packaging>jar</project.packaging>
+            </properties>
+        </profile>
+        <profile>
             <id>prodjar</id>
             <properties>
                 <profiles.active>prod</profiles.active>

+ 1 - 1
taphole-admin/src/main/resources/application-dev.yml

@@ -9,7 +9,7 @@ like:
 
 # 服务配置
 server:
-  port: 28080
+  port: 54321
   servlet:
     context-path: /
 

+ 53 - 0
taphole-admin/src/main/resources/application-pre.yml

@@ -0,0 +1,53 @@
+# 项目配置
+like:
+  upload-directory: D:/opt/camera/
+  l2:
+    host: 168.15.14.1
+    port: 4567
+    maxRetries: 10
+    retryInterval: 5000
+
+# 服务配置
+server:
+  port: 54321
+  servlet:
+    context-path: /
+
+# 框架配置
+spring:
+  # 数据源配置
+  datasource:
+    url: jdbc:mysql://117.72.49.153:13306/taphole?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
+    type: com.alibaba.druid.pool.DruidDataSource # 数据源类型
+    driver-class-name: com.mysql.jdbc.Driver # MySql的驱动
+    username: root # 数据库账号
+    password: root # 数据库密码
+  # Redis配置
+  redis:
+    host: 117.72.49.153   # Redis服务地址
+    port: 16379        # Redis端口
+    password:         # Redis密码
+    database: 5       # 数据库索引
+#    lettuce:
+#      pool:
+#        max-wait: 30000 # 连接池最大阻塞等待时间(使用负数表示没有限制,默认-1)
+#        max-active: 100 # 连接池最大连接数(使用负数表示没有限制,默认8)
+#        max-idle: 20    # 连接池中的最大空闲连接(默认8)
+#        min-idle: 0     # 连接池中的最小空闲连接(默认0)
+
+# Mybatis-plus配置 【是否开启SQL日志输出】
+
+socketio:
+ # host: 127.0.0.1		#主机名,默认是 0.0.0.0 (这个设不设置无所谓,因为后面的 SocketConfig 类一般不用设置这个)
+  port: 33000			#监听端口
+  maxFramePayloadLength: 1048576
+  maxHttpContentLength: 1048576
+  bossCount: 1
+  workCount: 100
+  allowCustomRequests: true
+  upgradeTimeout: 1000000		#协议升级超时时间(毫秒),默认10000。HTTP握手升级为ws协议超时时间
+  pingTimeout: 6000000		    #Ping消息超时时间(毫秒),默认60000,这个时间间隔内没有接收到心跳消息就会发送超时事件
+  pingInterval: 25000			#Ping消息间隔(毫秒),默认25000。客户端向服务器发送一条心跳消息间隔
+
+#  configuration:
+#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

+ 2 - 2
taphole-admin/src/main/resources/application-test.yml

@@ -1,6 +1,6 @@
 # 项目配置
 like:
-  upload-directory: /home/document/taphole/target/ # 上传目录
+  upload-directory: /home/document/taphole/app/ # 上传目录
   l2:
     host: 168.15.14.1
     port: 4567
@@ -9,7 +9,7 @@ like:
 
 # 服务配置
 server:
-  port: 28080
+  port: 54321
   servlet:
     context-path: /
 

+ 53 - 0
taphole-iron/src/main/java/com/sckj/iron/constant/ExpressionConstants.java

@@ -0,0 +1,53 @@
+package com.sckj.iron.constant;
+
+/***
+ * 表达式Context变量名
+ * 单位:s
+ */
+public class ExpressionConstants {
+    //标准流速
+    public static final String stdSpeed = "stdSpeed";
+    //标准压差阈值
+    public static final String stdPressureDiff = "stdPressureDiff";
+    //标准出铁时间
+    public static final String stdIronTime = "stdIronTime";
+    //标准服务器地址
+    public static final String stdServerUrl = "stdServerUrl";
+    //标准温差阈值
+    public static final String stdTempDiff = "stdTempDiff";
+    //标准开口耗时
+    public static final String stdOpenHour = "stdOpenHour";
+    //标准出铁量
+    public static final String stdIronWeight = "stdIronWeight";
+
+
+    //实时数据
+
+    //4号铁口状态
+    public static final String rtIron01State = "rtIron01State";
+    //4号铁口状态
+    public static final String rtIron02State = "rtIron02State";
+    //4号铁口状态
+    public static final String rtIron03State = "rtIron03State";
+    //4号铁口状态
+    public static final String rtIron04State = "rtIron04State";
+    //出铁速度
+    public static final String rtIronSpeed = "rtIronSpeed";
+    //出铁重量
+    public static final String rtIronWeight = "rtIronWeight";
+    //铁水温度
+    public static final String rtIronTemp = "rtIronTemp";
+    //出铁耗时
+    public static final String rtIronCosttime = "rtIronCosttime";
+
+    //铁水温差
+    public static final String rtIronTempDiff = "rtIronTempDiff";
+
+    //实际数据
+    //开口深度
+    public static final String openDepth = "openDepth";
+
+    //平均出铁速度
+    public static final String avgIronSpeed = "avgIronSpeed";
+
+}

+ 4 - 0
taphole-iron/src/main/java/com/sckj/iron/constant/ParamsConstants.java

@@ -13,6 +13,10 @@ public class ParamsConstants {
     public static final String iron_time = "iron_time";
     //server_url
     public static final String server_url = "server_url";
+    //server_url
+    public static final String ironwater_temp = "ironwater_temp";
+    public static final String open_hour = "open_hour";
+    public static final String iron_weight = "iron_weight";
 
     //开口预警
     public static final String open_warn = "open_warn";

+ 1 - 1
taphole-iron/src/main/java/com/sckj/iron/controller/TCameraController.java

@@ -107,7 +107,7 @@ public class TCameraController {
     })
     @PostMapping("/startBackTranscode")
     public AjaxResult startBackTranscode(Long id,
-                                         @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startTime,
+                                         @RequestParam(required = false)  @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startTime,
                                          @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endTime) {
         CameraDTO cameraDTO = new CameraDTO();
         cameraDTO.setId(id);

+ 71 - 0
taphole-iron/src/main/java/com/sckj/iron/controller/TIronTestController.java

@@ -0,0 +1,71 @@
+package com.sckj.iron.controller;
+
+import com.sckj.common.aop.Log;
+import com.sckj.common.core.AjaxResult;
+import com.sckj.common.core.PageResult;
+import com.sckj.common.validate.commons.IdValidate;
+import com.sckj.common.validate.commons.PageValidate;
+import com.sckj.common.validator.annotation.IDMust;
+import com.sckj.iron.service.impl.TIronTestServiceImpl;
+import com.sckj.iron.validate.TIronTestCreateValidate;
+import com.sckj.iron.validate.TIronTestSearchValidate;
+import com.sckj.iron.validate.TIronTestUpdateValidate;
+import com.sckj.iron.vo.TIronTestDetailVo;
+import com.sckj.iron.vo.TIronTestListedVo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+@RestController
+@RequestMapping("api/test")
+@Api(tags = "出铁诊断管理")
+public class TIronTestController {
+
+    @Resource
+    TIronTestServiceImpl iTIronTestService;
+
+    @GetMapping("/list")
+    @ApiOperation(value="出铁诊断列表")
+    public AjaxResult<PageResult<TIronTestListedVo>> list(@Validated PageValidate pageValidate,
+                                                          @Validated TIronTestSearchValidate searchValidate) {
+        PageResult<TIronTestListedVo> list = iTIronTestService.list(pageValidate, searchValidate);
+        return AjaxResult.success(list);
+    }
+
+    @GetMapping("/detail")
+    @ApiOperation(value="出铁诊断详情")
+    public AjaxResult<TIronTestDetailVo> detail(@Validated @IDMust() @RequestParam("id") Integer id) {
+        TIronTestDetailVo detail = iTIronTestService.detail(id);
+        return AjaxResult.success(detail);
+    }
+
+    @Log(title = "出铁诊断新增")
+    @PostMapping("/add")
+    @ApiOperation(value="出铁诊断新增")
+    public AjaxResult<Object> add(@Validated @RequestBody TIronTestCreateValidate createValidate) {
+        iTIronTestService.add(createValidate);
+        return AjaxResult.success();
+    }
+
+    @Log(title = "出铁诊断编辑")
+    @PostMapping("/edit")
+    @ApiOperation(value="出铁诊断编辑")
+    public AjaxResult<Object> edit(@Validated @RequestBody TIronTestUpdateValidate updateValidate) {
+        iTIronTestService.edit(updateValidate);
+        return AjaxResult.success();
+    }
+
+    @Log(title = "出铁诊断删除")
+    @PostMapping("/del")
+    @ApiOperation(value="出铁诊断删除")
+    public AjaxResult<Object> del(@Validated @RequestBody IdValidate idValidate) {
+        iTIronTestService.del(idValidate.getId());
+        return AjaxResult.success();
+    }
+
+
+
+}

+ 11 - 1
taphole-iron/src/main/java/com/sckj/iron/controller/TIronVisualScreenController.java

@@ -8,8 +8,8 @@ import com.sckj.common.aop.NotPower;
 import com.sckj.common.core.AjaxResult;
 import com.sckj.device.validate.TCameraUpdateDTO;
 import com.sckj.iron.dto.*;
-import com.sckj.iron.entity.TIronData;
 import com.sckj.iron.entity.TIronParam;
+import com.sckj.iron.entity.TIronTest;
 import com.sckj.iron.service.impl.*;
 import com.sckj.iron.validate.IronLoginValidate;
 import com.sckj.iron.validate.TIronDataSearchScreenValidate;
@@ -74,6 +74,9 @@ public class TIronVisualScreenController {
     @Resource
     OPCDataServiceImpl opcDataService;
 
+    @Resource
+    TIronTestServiceImpl iTIronTestService;
+
     private static final int DATA_COUNT = 6;
 
     @NotLogin
@@ -270,5 +273,12 @@ public class TIronVisualScreenController {
         return AjaxResult.success(mapList);
     }
 
+    @PostMapping("/getLatest")
+    @ApiOperation(value = "最新出铁诊断")
+    public AjaxResult<TIronTest> getLatest() {
+        TIronTest one = iTIronTestService.getLatest();
+        return AjaxResult.success(one);
+    }
+
 
 }

+ 3 - 3
taphole-iron/src/main/java/com/sckj/iron/entity/TIronModel.java

@@ -1,8 +1,6 @@
 package com.sckj.iron.entity;
 
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.*;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -48,6 +46,7 @@ public class TIronModel implements Serializable {
     private String modelDesc;
 
     @ApiModelProperty(value = "模型存储位置")
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
     private String modelPath;
 
     @ApiModelProperty(value = "状态(1正常 0停用)")
@@ -57,6 +56,7 @@ public class TIronModel implements Serializable {
     private Integer sort;
 
     @ApiModelProperty(value = "音频外键")
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
     private Long audioId;
 
 }

+ 48 - 0
taphole-iron/src/main/java/com/sckj/iron/entity/TIronTest.java

@@ -0,0 +1,48 @@
+package com.sckj.iron.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@ApiModel("出铁诊断实体")
+@TableName("t_iron_test")
+public class TIronTest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+
+    @ApiModelProperty(value = "创建时间")
+    private Date createTime;
+
+    @ApiModelProperty(value = "更新人")
+    private String updateBy;
+
+    @ApiModelProperty(value = "更新时间")
+    private Date updateTime;
+
+    @TableId(value="id", type= IdType.AUTO)
+    @ApiModelProperty(value = "")
+    private Long id;
+
+    @ApiModelProperty(value = "诊断状态(1正常 0异常)")
+    private String testStatus;
+
+    @ApiModelProperty(value = "鱼雷罐车车号")
+    private String testDesc;
+
+    @ApiModelProperty(value = "铁口区域编号")
+    private String tapholeId;
+
+    @ApiModelProperty(value = "高炉编号")
+    private String boilerId;
+
+}

+ 13 - 0
taphole-iron/src/main/java/com/sckj/iron/mapper/TIronTestMapper.java

@@ -0,0 +1,13 @@
+package com.sckj.iron.mapper;
+
+import com.sckj.common.core.basics.IBaseMapper;
+import com.sckj.iron.entity.TIronTest;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 出铁诊断Mapper
+ * @author LikeAdmin
+ */
+@Mapper
+public interface TIronTestMapper extends IBaseMapper<TIronTest> {
+}

+ 10 - 1
taphole-iron/src/main/java/com/sckj/iron/service/impl/TIronModelServiceImpl.java

@@ -172,6 +172,7 @@ public class TIronModelServiceImpl extends ServiceImpl<TIronModelMapper, TIronMo
         model.setModelDesc(updateValidate.getModelDesc());
         model.setStatus(updateValidate.getStatus());
         model.setSort(updateValidate.getSort());
+        model.setAudioId(updateValidate.getAudioId());
         String path = updateValidate.getModelPath();
         if (ObjectUtils.isNotEmpty(path)) {
             String relativeUrl = UrlUtils.toRelativeUrl(path);
@@ -180,7 +181,15 @@ public class TIronModelServiceImpl extends ServiceImpl<TIronModelMapper, TIronMo
 //            File file = new File(YmlUtils.get("like.upload-directory") + relativeUrl);
             try {
                 Path filePath = Paths.get(modelFilePath);
+                boolean exists = Files.exists(filePath);
+                if (!exists) {
+                    log.error("{}路径不存在", modelFilePath);
+                    model.setModelPath(null);
+                    return;
+                }
+
                 List<String> lines = Files.readAllLines(filePath);
+
                 StringBuilder content = new StringBuilder();
                 for (String line : lines) {
                     content.append(line);
@@ -203,7 +212,7 @@ public class TIronModelServiceImpl extends ServiceImpl<TIronModelMapper, TIronMo
                 e.printStackTrace();
             }
         } else {
-            model.setModelPath(null);
+            model.setModelPath("");
         }
         tIronModelMapper.updateById(model);
         refreshModel();

+ 154 - 0
taphole-iron/src/main/java/com/sckj/iron/service/impl/TIronTestServiceImpl.java

@@ -0,0 +1,154 @@
+package com.sckj.iron.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sckj.common.core.PageResult;
+import com.sckj.common.exception.OperateException;
+import com.sckj.common.validate.commons.PageValidate;
+import com.sckj.iron.entity.TIronTest;
+import com.sckj.iron.mapper.TIronTestMapper;
+import com.sckj.iron.validate.TIronTestCreateValidate;
+import com.sckj.iron.validate.TIronTestSearchValidate;
+import com.sckj.iron.validate.TIronTestUpdateValidate;
+import com.sckj.iron.vo.TIronTestDetailVo;
+import com.sckj.iron.vo.TIronTestListedVo;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import javax.annotation.Resource;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * 出铁诊断实现类
+ *
+ * @author LikeAdmin
+ */
+@Service
+public class TIronTestServiceImpl extends ServiceImpl<TIronTestMapper, TIronTest> {
+
+    @Resource
+    TIronTestMapper tIronTestMapper;
+
+    /**
+     * 出铁诊断列表
+     *
+     * @param pageValidate   分页参数
+     * @param searchValidate 搜索参数
+     * @return PageResult<TIronTestListedVo>
+     * @author LikeAdmin
+     */
+    public PageResult<TIronTestListedVo> list(PageValidate pageValidate, TIronTestSearchValidate searchValidate) {
+        Integer page = pageValidate.getPageNo();
+        Integer limit = pageValidate.getPageSize();
+
+        QueryWrapper<TIronTest> queryWrapper = new QueryWrapper<>();
+        queryWrapper.orderByDesc("id");
+
+        tIronTestMapper.setSearch(queryWrapper, searchValidate, new String[]{
+                "=:createBy@create_by:str",
+                "datetime:createTimeStart-createTimeEnd@create_time:str",
+                "=:testStatus@test_status:str",
+                "like:testDesc@test_desc:str",
+                "=:tapholeId@taphole_id:str",
+                "=:boilerId@boiler_id:str",
+        });
+
+        IPage<TIronTest> iPage = tIronTestMapper.selectPage(new Page<>(page, limit), queryWrapper);
+
+        List<TIronTestListedVo> list = new LinkedList<>();
+        for (TIronTest item : iPage.getRecords()) {
+            TIronTestListedVo vo = new TIronTestListedVo();
+            BeanUtils.copyProperties(item, vo);
+            list.add(vo);
+        }
+
+        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), list);
+    }
+
+    /**
+     * 出铁诊断详情
+     *
+     * @param id 主键参数
+     * @return TIronTest
+     * @author LikeAdmin
+     */
+
+    public TIronTestDetailVo detail(Integer id) {
+        TIronTest model = tIronTestMapper.selectOne(
+                new QueryWrapper<TIronTest>()
+                        .eq("id", id)
+                        .last("limit 1"));
+
+        Assert.notNull(model, "数据不存在");
+
+        TIronTestDetailVo vo = new TIronTestDetailVo();
+        BeanUtils.copyProperties(model, vo);
+        return vo;
+    }
+
+    /**
+     * 出铁诊断新增
+     *
+     * @param createValidate 参数
+     * @author LikeAdmin
+     */
+
+    public void add(TIronTestCreateValidate createValidate) {
+        TIronTest model = new TIronTest();
+        model.setTestStatus(createValidate.getTestStatus());
+        model.setTestDesc(createValidate.getTestDesc());
+        model.setTapholeId(createValidate.getTapholeId());
+        model.setBoilerId(createValidate.getBoilerId());
+        tIronTestMapper.insert(model);
+    }
+
+    /**
+     * 出铁诊断编辑
+     *
+     * @param updateValidate 参数
+     * @author LikeAdmin
+     */
+
+    public void edit(TIronTestUpdateValidate updateValidate) {
+        TIronTest model = tIronTestMapper.selectOne(
+                new QueryWrapper<TIronTest>()
+                        .eq("id", updateValidate.getId())
+                        .last("limit 1"));
+
+        Assert.notNull(model, "数据不存在!");
+
+        model.setId(updateValidate.getId());
+        model.setTestStatus(updateValidate.getTestStatus());
+        model.setTestDesc(updateValidate.getTestDesc());
+        model.setTapholeId(updateValidate.getTapholeId());
+        model.setBoilerId(updateValidate.getBoilerId());
+        tIronTestMapper.updateById(model);
+    }
+
+    /**
+     * 出铁诊断删除
+     *
+     * @param id 主键ID
+     * @author LikeAdmin
+     */
+
+    public void del(Integer id) {
+        TIronTest model = tIronTestMapper.selectOne(
+                new QueryWrapper<TIronTest>()
+                        .eq("id", id)
+                        .last("limit 1"));
+
+        Assert.notNull(model, "数据不存在!");
+
+        tIronTestMapper.delete(new QueryWrapper<TIronTest>().eq("id", id));
+    }
+
+    public TIronTest getLatest() {
+        return this.lambdaQuery().orderByDesc(TIronTest::getCreateTime).list().stream().findFirst().orElseThrow(()->new OperateException("未查询到数据"));
+    }
+
+}

+ 200 - 162
taphole-iron/src/main/java/com/sckj/iron/socketio/DeviceEventListener.java

@@ -10,6 +10,7 @@ import com.sckj.common.eventbus.EventListener;
 import com.sckj.common.manager.ScheduledTaskManager;
 import com.sckj.common.socketio.SocketUtil;
 import com.sckj.common.util.RedisUtils;
+import com.sckj.iron.constant.ExpressionConstants;
 import com.sckj.iron.constant.ParamsConstants;
 import com.sckj.iron.constant.SubscribeTagConstants;
 import com.sckj.iron.constant.TaskNameConstants;
@@ -17,17 +18,13 @@ import com.sckj.iron.dto.IronStepDTO;
 import com.sckj.iron.dto.IronTimeNoDTO;
 import com.sckj.iron.dto.RealtimeData;
 import com.sckj.iron.dto.WarnData;
-import com.sckj.iron.entity.TIronModel;
-import com.sckj.iron.entity.TIronParam;
-import com.sckj.iron.entity.TIronSchedule;
-import com.sckj.iron.entity.TIronStepLog;
+import com.sckj.iron.entity.*;
 import com.sckj.iron.service.impl.*;
 import com.sckj.iron.util.LocalDateUtils;
 import com.sckj.iron.vo.IronStepVO;
 import com.sckj.l2.entity.TL2Data;
 import com.sckj.l2.service.impl.L2DataServiceImpl;
 import com.sckj.l2.service.impl.TL2DataServiceImpl;
-import com.sckj.l2.service.impl.TL2MaterialServiceImpl;
 import com.sckj.opc.dataservice.HDServiceImpl;
 import com.sckj.opc.entity.OPCData;
 import com.sckj.opc.service.OPCDataServiceImpl;
@@ -92,10 +89,6 @@ public class DeviceEventListener extends EventListener { //
     @Resource
     TL2DataServiceImpl tl2DataService;
 
-    //参数
-    @Resource
-    TL2MaterialServiceImpl tl2MaterialService;
-
     @Resource
     L2DataServiceImpl l2DataServiceImpl;
 
@@ -108,9 +101,6 @@ public class DeviceEventListener extends EventListener { //
     @Resource
     TAudioServiceImpl audioService;
 
-//    @Resource
-//    OPCDAServiceImpl opcdaService;
-
     @Resource
     TIronModelServiceImpl ironModelService;
 
@@ -127,6 +117,10 @@ public class DeviceEventListener extends EventListener { //
     @Resource
     HDServiceImpl hdService;
 
+    //异常诊断
+    @Resource
+    TIronTestServiceImpl iTIronTestService;
+
     //炉前申请出铁
     private static final String STEP_LQSQCT = "lqsqct";
 
@@ -146,8 +140,6 @@ public class DeviceEventListener extends EventListener { //
     private static final String IRON_WEIGHT = "ironWeight";
     //出铁状态
     private static final String IRON_STATUS = "ironStatus";
-    //总干量
-    private static final String IRON_TOTAL_DRY = "ironTotalDry";
 
     //鱼雷罐车
     private static final String CAR_STATUS = "ylgc";
@@ -159,7 +151,7 @@ public class DeviceEventListener extends EventListener { //
     private static final String FLUSH_STATUS = "flushStatus";
 
     // 1.创建表达式解析器
-    private SpelExpressionParser parser = new SpelExpressionParser();
+    private static final SpelExpressionParser mParser = new SpelExpressionParser();
 
     // 2.创建变量上下文,设置变量
     private StandardEvaluationContext mContext = new StandardEvaluationContext();
@@ -177,13 +169,13 @@ public class DeviceEventListener extends EventListener { //
 
     //铁口出铁状态
     //1 出铁中    0 出铁结束
-    private AtomicInteger ironLoading1 = new AtomicInteger(0);
+    private AtomicDouble ironLoading1 = new AtomicDouble(0);
     //
-    private AtomicInteger ironLoading2 = new AtomicInteger(0);
+    private AtomicDouble ironLoading2 = new AtomicDouble(0);
     //
-    private AtomicInteger ironLoading3 = new AtomicInteger(0);
+    private AtomicDouble ironLoading3 = new AtomicDouble(0);
     //
-    private AtomicInteger ironLoading4 = new AtomicInteger(0);
+    private AtomicDouble ironLoading4 = new AtomicDouble(0);
 
     //出铁步骤
     private List<IronStepVO> mSteps;
@@ -212,11 +204,20 @@ public class DeviceEventListener extends EventListener { //
     //标准流速
     private AtomicDouble STANDARD_SPEED = new AtomicDouble(0);
 
-    //压差阈值
-    private AtomicDouble PRESSURE_DIFF_VALUE = new AtomicDouble(0);
+    //标准压差阈值
+    private AtomicDouble STANDARD_PRESSURE_DIFF = new AtomicDouble(0);
+
+    //标准出铁时间
+    private AtomicDouble STANDARD_IRON_TIME = new AtomicDouble(0);
+
+    //标准温差阈值
+    private AtomicInteger STANDARD_TEMP_DIFF = new AtomicInteger(0);
+
+    //标准开口耗时
+    private AtomicDouble STANDARD_OPEN_HOUR = new AtomicDouble(0);
+
+    private AtomicDouble STANDARD_IRON_WEIGHT = new AtomicDouble(0);
 
-    //出铁时间
-    private AtomicDouble IRON_TIME = new AtomicDouble(0);
 
     //实时温度最大值
     private AtomicDouble tempMax = new AtomicDouble(0);
@@ -224,13 +225,11 @@ public class DeviceEventListener extends EventListener { //
     //实时温度最小值
     private AtomicDouble tempMin = new AtomicDouble(0);
 
-
     private String SERVER_URL = "";
 
     //实时出铁总重量/总流量
     private BigDecimal mTotalWeight = BigDecimal.ZERO;
-    //总干量
-//    private BigDecimal mTotalDry = BigDecimal.ZERO;
+
     //出铁耗时(单位:秒)
     private AtomicInteger mSecondsElapsed = new AtomicInteger(0);
 
@@ -271,17 +270,20 @@ public class DeviceEventListener extends EventListener { //
     }
 
 
-    //打泥量选择公式
+    //打泥量选择公式模型
     private TIronModel modelHitMud;
 
-    /// 堵口预警
+    // 堵口预警模型
     private TIronModel modelClosureWarn1;
     private TIronModel modelClosureWarn2;
     private TIronModel modelClosureWarn3;
 
-    //出铁诊断
+    //出铁诊断模型
     private TIronModel modelTappingTest;
 
+    //预警出铁模型
+    private TIronModel modelTappingWarn;
+
 
     /***
      * 更新模型
@@ -292,6 +294,7 @@ public class DeviceEventListener extends EventListener { //
         modelClosureWarn2 = ironModelService.lambdaQuery().eq(TIronModel::getModelName, "closure_warn2").one();
         modelClosureWarn3 = ironModelService.lambdaQuery().eq(TIronModel::getModelName, "closure_warn3").one();
         modelTappingTest = ironModelService.lambdaQuery().eq(TIronModel::getModelName, "tapping_test").one();
+        modelTappingWarn = ironModelService.lambdaQuery().eq(TIronModel::getModelName, "tapping_warn").one();
     }
 
     private void getAudios() {
@@ -318,21 +321,35 @@ public class DeviceEventListener extends EventListener { //
      * 更新参数
      */
     private void getIronParams() {
-        List<TIronParam> mIronParams = ironParamService.lambdaQuery().eq(TIronParam::getStatus, "1").in(TIronParam::getParamType, "iron_judge", "iron_judge_extra", "scheduledtime", "server_info").orderByAsc(TIronParam::getSort).list();
+        List<TIronParam> mIronParams = ironParamService.lambdaQuery().eq(TIronParam::getStatus, "1").in(TIronParam::getParamType, "iron_judge", "iron_judge_extra", "server_info").orderByAsc(TIronParam::getSort).list();
         if (ObjectUtils.isNotEmpty(mIronParams)) {
             for (TIronParam mIronParam : mIronParams) {
                 if (Objects.equals(mIronParam.getParamName(), ParamsConstants.iron_speed)) {
                     STANDARD_SPEED = new AtomicDouble(Double.parseDouble(mIronParam.getParamValue()));
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.pressure_diff_value)) {
-                    PRESSURE_DIFF_VALUE = new AtomicDouble(Double.parseDouble(mIronParam.getParamValue()));
+                    STANDARD_PRESSURE_DIFF = new AtomicDouble(Double.parseDouble(mIronParam.getParamValue()));
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.iron_time)) {
-                    IRON_TIME = new AtomicDouble(Double.parseDouble(mIronParam.getParamValue()));
+                    STANDARD_IRON_TIME = new AtomicDouble(Double.parseDouble(mIronParam.getParamValue()));
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.server_url)) {
                     SERVER_URL = mIronParam.getParamValue();
+                } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.ironwater_temp)) {
+                    STANDARD_TEMP_DIFF = new AtomicInteger(Integer.parseInt(mIronParam.getParamValue()));
+                } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.open_hour)) {
+                    STANDARD_OPEN_HOUR = new AtomicDouble(Double.parseDouble(mIronParam.getParamValue()));
+                } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.iron_weight)) {
+                    STANDARD_IRON_WEIGHT = new AtomicDouble(Double.parseDouble(mIronParam.getParamValue()));
                 }
+
+                mContext.setVariable(ExpressionConstants.stdSpeed, STANDARD_SPEED.get());
+                mContext.setVariable(ExpressionConstants.stdPressureDiff, STANDARD_PRESSURE_DIFF.get());
+                mContext.setVariable(ExpressionConstants.stdIronTime, STANDARD_IRON_TIME.get());
+                mContext.setVariable(ExpressionConstants.stdServerUrl, SERVER_URL);
+                mContext.setVariable(ExpressionConstants.stdTempDiff, STANDARD_TEMP_DIFF);
+                mContext.setVariable(ExpressionConstants.stdOpenHour, STANDARD_OPEN_HOUR);
+                mContext.setVariable(ExpressionConstants.stdIronWeight, STANDARD_IRON_WEIGHT);
             }
-            log.info("STANDARD_SPEED: {},PRESSURE_DIFF_VALUE:{}", STANDARD_SPEED, PRESSURE_DIFF_VALUE);
-            log.info("IRON_TIME: {},SERVER_URL:{}", IRON_TIME, SERVER_URL);
+            log.info("STANDARD_SPEED: {},PRESSURE_DIFF_VALUE:{}", STANDARD_SPEED, STANDARD_PRESSURE_DIFF);
+            log.info("IRON_TIME: {},SERVER_URL:{}", STANDARD_IRON_TIME, SERVER_URL);
         }
     }
 
@@ -389,6 +406,14 @@ public class DeviceEventListener extends EventListener { //
      */
     @Subscribe
     public void onMessageEvent(OPCData opcData) {
+        Object obj = opcData.getData();
+        if (obj.toString().contains(".")) {
+            String s = obj.toString().split("\\.")[0];
+//            double value = ((Number) obj).doubleValue();
+            //String formattedValue = String.format("%.2f", value);
+            opcData.setData(Double.parseDouble(s));
+        }
+
         //异步保存OPC数据
         taskExecutor.submit(() -> {
             opcDataService.save(opcData);
@@ -398,9 +423,9 @@ public class DeviceEventListener extends EventListener { //
 
         //实时数据
         taskExecutor.submit(() -> {
-
+            setRealtimeDataAndStatus(opcData, null);
         });
-        setRealtimeDataAndStatus(opcData, null);
+
     }
 
     //出铁次数编号
@@ -439,7 +464,7 @@ public class DeviceEventListener extends EventListener { //
         if (ObjectUtils.isNotEmpty(latestData)) {
             ironTimeNoDTO.setIronNo(latestData.getIronNo());
         }
-        ironTimeNoDTO.setDesc(String.format("%s第%s次出铁", dateString, ironTimeNoDTO.getIronNo()));
+        ironTimeNoDTO.setDesc(String.format("第%s次出铁", ironTimeNoDTO.getIronNo()));
         PushData.send2IronTimeNo(ironTimeNoDTO);
     }
 
@@ -545,6 +570,10 @@ public class DeviceEventListener extends EventListener { //
         //关闭定时任务:出铁预警、开口预警
         //开启定时任务:出铁超时报警、堵口预警、打泥量选择计算、
 
+        //清空出铁总量、出铁计时
+        mTotalWeight = BigDecimal.ZERO;
+        mSecondsElapsed.set(0);
+
         scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_TAPPING_WARN);
         scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_TAPPING_TIMEOUT_WARN);
 
@@ -557,27 +586,27 @@ public class DeviceEventListener extends EventListener { //
 
         }
 
+        //模型四:堵口模型
         if ("1".equals(scheduleClosureWarn.getStatus())) {
             //堵口预警
             scheduledTaskManager.addTask(scheduleClosureWarn.getName(), scheduleClosureWarn.getDelay(), scheduleClosureWarn.getPeriod(), TimeUnit.SECONDS, () -> {
                 //堵口预警
                 String modelExpression1 = modelClosureWarn1.getModelExpression();
 
-                SpelExpressionParser parser = new SpelExpressionParser();
-                Expression expression1 = parser.parseExpression(modelExpression1);
+                Expression expression1 = mParser.parseExpression(modelExpression1);
 
                 StandardEvaluationContext context = new StandardEvaluationContext();
                 // 设置占位符对应的值
-                context.setVariable("ironSpeed", speed1.get() > speed2.get() ? speed1.get() : speed2.get());
-                context.setVariable("iron01State", ironLoading1);
-                context.setVariable("iron02State", ironLoading2);
-                context.setVariable("iron03State", ironLoading3);
-                context.setVariable("iron04State", ironLoading4);
-                context.setVariable("standardSpeed", STANDARD_SPEED.get());
-                //计算打泥量
-                //计算理论铁量= 矿批 × 综合品位 × 1.06,其中矿批是指L2中的干量
                 boolean result1 = expression1.getValue(context, Boolean.class);
 
+                log.info("1号车受铁速度:{}", speed1.get());
+                log.info("2号车受铁速度:{}", speed2.get());
+                log.info("标准受铁速度:{},", STANDARD_SPEED.get());
+                log.info("1号铁口出铁状态:{}", ironLoading1.get());
+                log.info("2号铁口出铁状态:{}", ironLoading2.get());
+                log.info("3号铁口出铁状态:{}", ironLoading3.get());
+                log.info("4号铁口出铁状态:{}", ironLoading4.get());
+
                 if (result1) {
                     //流速过大可能是由于铁口深度不足或发生跑大流问题,则提示将当前铁口堵口
                     PushData.send2Warn(WarnData.warnClose("流速过快,请将当前铁口堵口", closureAlarmUrl));
@@ -588,81 +617,56 @@ public class DeviceEventListener extends EventListener { //
                 }
 
                 String modelExpression2 = modelClosureWarn2.getModelExpression();
-                Expression expression2 = parser.parseExpression(modelExpression2);
+                Expression expression2 = mParser.parseExpression(modelExpression2);
                 boolean result2 = expression2.getValue(context, Boolean.class);
                 if (result2) {
-
+                    //若流速过小,但其它铁口正在出铁,则提示将当前铁口堵口
+                    PushData.send2Warn(WarnData.warnClose("流速过小,请将当前铁口堵口", closureAlarmUrl));
+                    taskExecutor.submit(() -> {
+                        exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("4").exceptionDesc("流速过小,请将当前铁口堵口").build());
+                    });
                     return;
                 }
 
                 String modelExpression3 = modelClosureWarn3.getModelExpression();
-                Expression expression3 = parser.parseExpression(modelExpression3);
+                Expression expression3 = mParser.parseExpression(modelExpression3);
                 boolean result3 = expression3.getValue(context, Boolean.class);
 
                 if (result3) {
-
+                    PushData.send2Warn(WarnData.warnClose("流速过小且其他铁口均未出铁,请先将其它铁口打开,再进行堵口", closureAlarmUrl));
+                    taskExecutor.submit(() -> {
+                        exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("4").exceptionDesc("流速过小且其他铁口均未出铁,请先将其它铁口打开,再进行堵口").build());
+                    });
                 }
 
-//                if (speed1.get() > STANDARD_SPEED.get() || speed2.get() > STANDARD_SPEED.get()) {
-//                    log.info("堵口预警:【speed1】:{},【speed2】:{},【standard_speed】:{},", speed1.get(), speed2.get(), STANDARD_SPEED.get());
-//
-//                    //流速过大可能是由于铁口深度不足或发生跑大流问题,则提示将当前铁口堵口
-//                    PushData.send2Warn(WarnData.warnClose("流速过快,请将当前铁口堵口", closureAlarmUrl));
-//                    taskExecutor.submit(() -> {
-//                        exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("4").exceptionDesc("流速过快,请将当前铁口堵口").build());
-//                    });
-//                } else if ((speed1.get() < STANDARD_SPEED.get() || speed2.get() < STANDARD_SPEED.get()) && (ironLoading2.get() || ironLoading3.get() || ironLoading4.get())) {
-//                    log.info("堵口预警一:【speed1】:{},【speed2】:{},【standard_speed】:{},", speed1.get(), speed2.get(), STANDARD_SPEED.get());
-//                    log.info("堵口预警一:【ironLoading1】:{},【ironLoading2】:{},【ironLoading3】:{},【ironLoading4】:{}", ironLoading1.get(), ironLoading2.get(), ironLoading3.get(), ironLoading4.get());
-//
-//
-//                    //若流速过小,但其它铁口正在出铁,则提示将当前铁口堵口
-//                    PushData.send2Warn(WarnData.warnClose("流速过小,请将当前铁口堵口", closureAlarmUrl));
-//                    taskExecutor.submit(() -> {
-//                        exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("4").exceptionDesc("流速过小,请将当前铁口堵口").build());
-//                    });
-//                } else if ((speed1.get() < STANDARD_SPEED.get() || speed2.get() < STANDARD_SPEED.get()) && (!ironLoading2.get() && !ironLoading3.get() && !ironLoading4.get())) {
-//                    log.info("堵口预警二:【speed1】:{},【speed2】:{},【standard_speed】:{},", speed1.get(), speed2.get(), STANDARD_SPEED.get());
-//                    log.info("堵口预警二:【ironLoading1】:{},【ironLoading2】:{},【ironLoading3】:{},【ironLoading4】:{}", ironLoading1.get(), ironLoading2.get(), ironLoading3.get(), ironLoading4.get());
-//
-//
-//                    //若流速过小且其他铁口均未出铁,则提示先将其它铁口打开,再进行堵口
-//                    PushData.send2Warn(WarnData.warnClose("请先打开其它铁口,再堵口", closureAlarmUrl));
-//                    taskExecutor.submit(() -> {
-//                        exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("4").exceptionDesc("请先打开其它铁口,再堵口").build());
-//                    });
-//                }
+
             });
         }
 
 
+        //模型二:打泥量选择模型
         if ("1".equals(scheduleHitMud.getStatus())) {
             //xxx分钟出铁后开始计算打泥量,通过打泥量公式
-            //打泥量公式关联因素:铁口深度、钻杆直径、
-            //调用打泥量模型,计算预计使用多少打泥量进行堵口
+            //打泥量公式关联因素:铁口深度、钻杆直径、调用打泥量模型,计算预计使用多少打泥量进行堵口
             scheduledTaskManager.addTask(scheduleHitMud.getName(), scheduleHitMud.getDelay(), scheduleHitMud.getPeriod(), TimeUnit.SECONDS, () -> {
                 log.info("打泥量预计:{}", modelHitMud);
-                TL2Data tappingData = tl2DataService.getTappingData();
+                TL2Data tappingData = tl2DataService.getLatestData();
                 if (ObjectUtils.isNotEmpty(tappingData) && ObjectUtils.isNotEmpty(modelHitMud)) {
                     log.info("开口深度openDepth(mm):{}", tappingData.getOpenDepth());
-                    log.info("Tap对应铁水估计铁量ironWeight(t): {}", tappingData.getCalcWeight());
-                    log.info("出铁时间ironCosttime(min): {}", getIronElapsedMinute());
-                    log.info("平均流速ironSpeed(t/s): {}", speed1.get() > speed2.get() ? speed1.get() : speed2.get());
+                    log.info("Tap对应铁水估计铁量rtIronWeight(t): {}", mTotalWeight.doubleValue());
+                    log.info("出铁时间rtIronCosttime(min): {}", getIronElapsedMinute());
+                    log.info("平均流速rtIronSpeed(t/s): {}", speed1.get() > speed2.get() ? speed1.get() : speed2.get());
 
                     try {
                         String modelExpression = modelHitMud.getModelExpression();
-                        log.info("打泥量计算公式:{}", modelExpression);
-                        SpelExpressionParser parser = new SpelExpressionParser();
-                        Expression expression = parser.parseExpression(modelExpression);
-                        StandardEvaluationContext context = new StandardEvaluationContext();
+
+                        Expression expression = mParser.parseExpression(modelExpression);
                         // 设置占位符对应的值
-                        context.setVariable("openDepth", tappingData.getOpenDepth());
-                        context.setVariable("ironWeight", tappingData.getCalcWeight());
-                        context.setVariable("ironCosttime", getIronElapsedMinute());
-                        context.setVariable("ironSpeed", speed1.get() > speed2.get() ? speed1.get() : speed2.get());
+                        mContext.setVariable(ExpressionConstants.openDepth, tappingData.getOpenDepth());
+                        mContext.setVariable(ExpressionConstants.rtIronWeight, mTotalWeight.doubleValue());
+                        mContext.setVariable(ExpressionConstants.rtIronCosttime, getIronElapsedMinute());
                         //计算打泥量
-                        //计算理论铁量= 矿批 × 综合品位 × 1.06,其中矿批是指L2中的干量
-                        int result = (int) ((double) expression.getValue(context));
+                        int result = (int) ((double) expression.getValue(mContext));
                         // 使用 DecimalFormat 保留两位小数
 //                    DecimalFormat decimalFormat = new DecimalFormat("#.00");
 //                    String formattedResult = decimalFormat.format(result);
@@ -672,19 +676,17 @@ public class DeviceEventListener extends EventListener { //
                         e.printStackTrace();
                     }
                 }
-
-
-                scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_HIT_MUD);
+                scheduledTaskManager.cancelTask(scheduleHitMud.getName());
             });
         }
 
 
+        //出铁超时报警
         if ("1".equals(scheduleTappingTimeoutWarn.getStatus())) {
-            //出铁超时报警
             scheduledTaskManager.addTask(scheduleTappingTimeoutWarn.getName(), scheduleTappingTimeoutWarn.getDelay(), scheduleTappingTimeoutWarn.getPeriod(), TimeUnit.SECONDS, () -> {
                 int seconds = mSecondsElapsed.get();
-                log.info("已出铁时间min:{},标准出铁时间IRON_TIME:{}", seconds, IRON_TIME.get());
-                if (seconds > IRON_TIME.get() * 60) {
+                // log.info("已出铁时间(秒):{},标准出铁时间(秒):{}", seconds, STANDARD_IRON_TIME.get());
+                if (seconds > STANDARD_IRON_TIME.get()) {
                     PushData.send2Warn(WarnData.warnTappingTimeout("出铁时间超时", tappingTimeoutAlramUrl));
                     taskExecutor.submit(() -> {
                         exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("2").exceptionDesc("出铁时间超过设定时间").build());
@@ -699,16 +701,14 @@ public class DeviceEventListener extends EventListener { //
     //1号铁口结束出铁的操作项目
     private void taphole1End() {
         //由 1-> 0 表明1号铁口结束出铁
-        mTotalWeight = BigDecimal.ZERO;
-//        mTotalDry = BigDecimal.ZERO;
-//        scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_OPEN_WARN);
-        scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_CLOSURE_WARN);
 
+        scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_CLOSURE_WARN);
         scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_HIT_MUD);
         scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_TAPPING_CONSTTIME);
         scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_TAPPING_TIMEOUT_WARN);
-        mSecondsElapsed.set(0);
+
         getIronTime();
+        getIronTimeNo();
         mSteps = ironStepService.getTreeSteps();
 
         //开口
@@ -717,69 +717,92 @@ public class DeviceEventListener extends EventListener { //
         PushData.send2CancelWarn(WarnData.warnClose("出铁结束", ""));
         //出铁预警
         PushData.send2CancelWarn(WarnData.warnTapping("出铁结束", ""));
+        //清空打泥量
+        PushData.send2IronHitMud("");
 
 //        recordAfter();
 //        recordBlock();
 
+        //模型一 : 出铁工作诊断模型
         if ("1".equals(scheduleTappingTest.getStatus())) {
-            //开始出铁诊断
             //获取开口耗时、出铁时间、实际出铁量、平均铁水流速、平均铁水温度等数据,进行阈值判定,诊断出铁是否正常
-            //xxx分钟延迟
+            //结束后xxx秒后诊断
             scheduledTaskManager.addTask(scheduleTappingTest.getName(), scheduleTappingTest.getDelay(), scheduleTappingTest.getPeriod(), TimeUnit.SECONDS, () -> {
                 //堵口预警
                 log.info("出铁结束,定时任务:{},出铁诊断", TaskNameConstants.TASKNAME_TAPPING_TEST);
                 TL2Data fixedLatestElement = (TL2Data) RedisUtils.getFixedLatestElement(IRON_ELEMENT);
-                //平均温度
-                Double mudWeight = fixedLatestElement.getAvgTemp();
-                //出铁时间
-                //String ironCosttime = fixedLatestElement.getI
-                //实际出铁量
-                Double ironWeight = fixedLatestElement.getIronWeight();
-
-//            TIronData ironData = new TIronData();
-//            BeanUtils.copyProperties(ironData, fixedLatestElement);
-//
-//            ironDataService.save(ironData);
 
                 try {
                     String modelExpression = modelTappingTest.getModelExpression();
                     if (ObjectUtils.isNotEmpty(modelExpression)) {
                         log.info("出铁诊断计算公式:{}", modelExpression);
-                        SpelExpressionParser parser = new SpelExpressionParser();
-                        Expression expression = parser.parseExpression(modelExpression);
-                        StandardEvaluationContext context = new StandardEvaluationContext();
                         // 设置占位符对应的值
-                        context.setVariable("ironTime", getIronElapsedMinute());
-                        context.setVariable("ironWeight", mTotalWeight.doubleValue());
-                        context.setVariable("ironSpeed", mTotalWeight.doubleValue() / (getIronElapsedMinute() == 0 ? 1 : getIronElapsedMinute()));
-                        context.setVariable("ironTempChange", tempMax.get() - tempMin.get());
-                        String result = expression.getValue(context, String.class);
+                        mContext.setVariable(ExpressionConstants.rtIronCosttime, getIronElapsedMinute());
+                        mContext.setVariable(ExpressionConstants.avgIronSpeed, mTotalWeight.doubleValue() / (getIronElapsedMinute() == 0 ? 1 : getIronElapsedMinute()));
                         // 使用 DecimalFormat 保留两位小数
 //                      DecimalFormat decimalFormat = new DecimalFormat("#.00");
 //                      String formattedResult = decimalFormat.format(result);
-                        log.info("出铁诊断结果:{}", result);
+                        String testResultStr = "";
+
+                        String[] split = modelExpression.split("&&");
+                        boolean ironTimeBool = mParser.parseExpression(split[0]).getValue(mContext, Boolean.class);
+
+                        if (ironTimeBool) {
+                            testResultStr += "出铁时间正常,";
+                        } else {
+                            testResultStr += "出铁时间异常,";
+                        }
+
+                        boolean ironWeightBool = mParser.parseExpression(split[1]).getValue(mContext, Boolean.class);
+                        if (ironWeightBool) {
+                            testResultStr += "出铁量正常,";
+                        } else {
+                            testResultStr += "出铁量异常,";
+                        }
+
+                        boolean ironSpeedBool = mParser.parseExpression(split[2]).getValue(mContext, Boolean.class);
+                        if (ironSpeedBool) {
+                            testResultStr += "出铁流速正常,";
+                        } else {
+                            testResultStr += "出铁流速异常,";
+                        }
+
+                        boolean ironTempChangeBool = mParser.parseExpression(split[3]).getValue(mContext, Boolean.class);
+                        if (ironTempChangeBool) {
+                            testResultStr += "铁水温度变化正常。";
+                        } else {
+                            testResultStr += "铁水温度变化异常。";
+                        }
+                        TIronTest ironTest = new TIronTest();
+                        String testStatus = (ironTimeBool && ironWeightBool && ironSpeedBool && ironTempChangeBool) ? "1" : "0";
+                        ironTest.setTestStatus(testStatus);
+                        ironTest.setTestDesc(testResultStr);
+                        iTIronTestService.save(ironTest);
+                        log.info("出铁诊断结果:{}", testResultStr);
                     }
                 } catch (Exception e) {
                     e.printStackTrace();
+                } finally {
+                    scheduledTaskManager.cancelTask(scheduleTappingTest.getName());
                 }
 
-                scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_TAPPING_TEST);
             });
         }
 
-
+        //模型三:预警出铁模型
         if ("1".equals(scheduleTappingWarn.getStatus())) {
             scheduledTaskManager.addTask(scheduleTappingWarn.getName(), scheduleTappingWarn.getDelay(), scheduleTappingWarn.getPeriod(), TimeUnit.SECONDS, () -> {
-                double sfyl = Double.parseDouble(ObjectUtils.defaultIfNull(mContext.lookupVariable("sfyl"), "0").toString());
-                double ldyl = Double.parseDouble(ObjectUtils.defaultIfNull(mContext.lookupVariable("ldyl"), "0").toString());
-                double yc = sfyl - ldyl;
-                log.info("出铁预警:压差:{},标准压差:{},L1出铁状态:{}", yc, PRESSURE_DIFF_VALUE.get(), ironLoading1.get());
-                if (PRESSURE_DIFF_VALUE.get() < yc && ironLoading1.get() == 0) {
-                    PushData.send2Warn(WarnData.warnTapping("压差超过阈值,请出铁", tappingAlramUrl));
-                    exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("4").exceptionDesc("压差超过阈值,请出铁").build());
-                } else {
-//                scheduledTaskManager.cancelTask(TaskNameConstants.TASKNAME_TAPPING_WARN);
-                    PushData.send2CancelWarn(WarnData.warnTapping("压差正常", ""));
+                String modelExpression = modelTappingWarn.getModelExpression();
+                if (ObjectUtils.isNotEmpty(modelExpression)) {
+                    Expression expression = mParser.parseExpression(modelExpression);
+                    // 设置占位符对应的值
+                    Boolean result = expression.getValue(mContext, Boolean.class);
+                    if (result) {
+                        PushData.send2Warn(WarnData.warnTapping("压差超过阈值,请出铁", tappingAlramUrl));
+                        exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("4").exceptionDesc("压差超过阈值,请出铁").build());
+                    } else {
+                        PushData.send2CancelWarn(WarnData.warnTapping("压差正常", ""));
+                    }
                 }
             });
         }
@@ -818,14 +841,16 @@ public class DeviceEventListener extends EventListener { //
 
                 double tempNow = Double.parseDouble(opcData.getData().toString());
 
-                if (tempMax.get() == 0 || tempNow > tempMax.get()) {
+                if (tempMax.get() <= 0 || tempNow > tempMax.get()) {
                     tempMax.set(tempNow);
                 }
 
-                if (tempMin.get() == 0 || tempNow < tempMin.get()) {
+                if (tempMin.get() <= 0 || tempNow < tempMin.get()) {
                     tempMin.set(tempNow);
                 }
 
+                mContext.setVariable(ExpressionConstants.rtIronTemp, opcData.getData());
+                mContext.setVariable(ExpressionConstants.rtIronTempDiff, tempMax.get() - tempMin.get());
 
             } else if (opcData.getPointName().contains(SubscribeTagConstants.TAG_CAR11(opcData.getServerType())) || opcData.getPointName().contains(SubscribeTagConstants.TAG_CAR12(opcData.getServerType()))) {
                 //1TH-1号车受铁速度
@@ -854,6 +879,7 @@ public class DeviceEventListener extends EventListener { //
                     speeds[1] = realtimeData;
                     speed2 = new AtomicDouble(Double.parseDouble(opcData.getData().toString()));
                 }
+                mContext.setVariable(ExpressionConstants.rtIronSpeed, speed1.get() > speed2.get() ? speed1.get() : speed2.get());
 
                 //只在两个都有数据的时候才添加
                 if (ObjectUtils.isNotEmpty(speeds)
@@ -861,7 +887,6 @@ public class DeviceEventListener extends EventListener { //
                         && ObjectUtils.isNotEmpty(speeds[1]) && ObjectUtils.isNotEmpty(speeds[1].getValue())
                 ) {
                     ironSpeed.setTime(LocalDateUtils.formatDate(opcData.getServerTime()));
-
                 }
             } else if (opcData.getPointName().contains(SubscribeTagConstants.TAG_TAPHOLE1_STATUS(opcData.getServerType()))) {
                 RealtimeData realtimeData = new RealtimeData();
@@ -869,23 +894,24 @@ public class DeviceEventListener extends EventListener { //
                 realtimeData.setDesc("出铁状态");
                 mRealtimeStatus.put(IRON_STATUS, realtimeData);
 
-                ironLoading1.set(Integer.parseInt(opcData.getData().toString()));
+                ironLoading1.set(Double.parseDouble(opcData.getData().toString()));
+                mContext.setVariable(ExpressionConstants.rtIron01State, ironLoading1.get());
 
-                if (ironLoading1.get() == 1) {
+                if (ironLoading1.get() > 0) {
                     taphole1Start();
                 } else {
                     taphole1End();
                 }
 
             } else if (opcData.getPointName().contains(SubscribeTagConstants.TAG_TAPHOLE2_STATUS(opcData.getServerType()))) {
-                ironLoading2.set(Integer.parseInt(opcData.getData().toString()));
-
+                ironLoading2.set(Double.parseDouble(opcData.getData().toString()));
+                mContext.setVariable(ExpressionConstants.rtIron02State, ironLoading2.get());
             } else if (opcData.getPointName().contains(SubscribeTagConstants.TAG_TAPHOLE3_STATUS(opcData.getServerType()))) {
-                ironLoading3.set(Integer.parseInt(opcData.getData().toString()));
-
+                ironLoading3.set(Double.parseDouble(opcData.getData().toString()));
+                mContext.setVariable(ExpressionConstants.rtIron03State, ironLoading3.get());
             } else if (opcData.getPointName().contains(SubscribeTagConstants.TAG_TAPHOLE4_STATUS(opcData.getServerType()))) {
-                ironLoading4.set(Integer.parseInt(opcData.getData().toString()));
-
+                ironLoading4.set(Double.parseDouble(opcData.getData().toString()));
+                mContext.setVariable(ExpressionConstants.rtIron04State, ironLoading4.get());
             } else if (opcData.getPointName().contains(SubscribeTagConstants.TAG_IRON_WEIGHT11(opcData.getServerType())) || opcData.getPointName().contains(SubscribeTagConstants.TAG_IRON_WEIGHT12(opcData.getServerType()))) {
                 //铁水流量
                 RealtimeData ironWeight = new RealtimeData();
@@ -897,6 +923,9 @@ public class DeviceEventListener extends EventListener { //
                 mRealtimeData.put(IRON_WEIGHT, ironWeight);
 //                log.info(">>>>>>>>>>>>>{}:{},total:{}", opcData.getPointName(), opcData.getData(), totalWeight.toPlainString());
                 ironWeight.setTime(LocalDateUtils.formatDate(opcData.getServerTime()));
+
+                mContext.setVariable(ExpressionConstants.rtIronWeight, mTotalWeight.doubleValue());
+
             } else if (opcData.getPointName().contains(SubscribeTagConstants.TAG_FLUSH_STATUS(opcData.getServerType()))) {
                 RealtimeData realtimeData = new RealtimeData();
                 realtimeData.setValue(opcData.getData());
@@ -906,7 +935,16 @@ public class DeviceEventListener extends EventListener { //
 
         }
 
-        TL2Data fixedLatestElement = (TL2Data) RedisUtils.getFixedLatestElement(IRON_ELEMENT);
+        TL2Data fixedLatestElement = null;
+        try {
+            fixedLatestElement = (TL2Data) RedisUtils.getFixedLatestElement(IRON_ELEMENT);
+        } catch (Exception e) {
+
+        }
+
+        if (ObjectUtils.isEmpty(fixedLatestElement)) {
+            fixedLatestElement = tl2DataService.getLatestData();
+        }
 
         if (ObjectUtils.isNotEmpty(fixedLatestElement)) {
             //铁水成分
@@ -915,12 +953,12 @@ public class DeviceEventListener extends EventListener { //
             String elementS = fixedLatestElement.getElementS();
 
             RealtimeData realtimeData = new RealtimeData();
-            realtimeData.setValue(elementSi);
+            realtimeData.setValue(new BigDecimal(elementSi).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
             realtimeData.setUnit("%");
             realtimeData.setDesc("硅");
 
             RealtimeData realtimeData2 = new RealtimeData();
-            realtimeData2.setValue(elementS);
+            realtimeData2.setValue(new BigDecimal(elementS).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
             realtimeData2.setUnit("%");
             realtimeData2.setDesc("硫");
 
@@ -958,7 +996,7 @@ public class DeviceEventListener extends EventListener { //
                         if (ObjectUtils.isEmpty(newPointName)) {
                             continue;
                         }
-                        newPointName = CustomUtil.createNewPointName(newPointName, activeProfiles,mOPCData.getServerType());
+                        newPointName = CustomUtil.createNewPointName(newPointName, activeProfiles, mOPCData.getServerType());
                         if (Objects.equals(newPointName, pointName)) {
                             //3.创建变量上下文,设置变量
                             childchild.setData(data);
@@ -968,7 +1006,7 @@ public class DeviceEventListener extends EventListener { //
                     if (ObjectUtils.isEmpty(newPointName)) {
                         continue;
                     }
-                    newPointName = CustomUtil.createNewPointName(newPointName, activeProfiles,mOPCData.getServerType());
+                    newPointName = CustomUtil.createNewPointName(newPointName, activeProfiles, mOPCData.getServerType());
                     if (Objects.equals(newPointName, pointName)) {
                         child.setData(data);
                     }
@@ -1052,10 +1090,10 @@ public class DeviceEventListener extends EventListener { //
         try {
             if ("calc".equalsIgnoreCase(stepVO.getNodeType())) {
                 //含有表达式文字
-                flowName = parser.parseExpression(stepVO.getStepNameExpression()).getValue(mContext, String.class);
+                flowName = mParser.parseExpression(stepVO.getStepNameExpression()).getValue(mContext, String.class);
             } else {
                 //纯文字
-                flowName = parser.parseExpression("'" + stepVO.getStepName() + "'").getValue(mContext, String.class);
+                flowName = mParser.parseExpression("'" + stepVO.getStepName() + "'").getValue(mContext, String.class);
             }
             stepVO.setStepName(flowName);
         } catch (Exception e) {
@@ -1072,7 +1110,7 @@ public class DeviceEventListener extends EventListener { //
         if (ObjectUtils.isNotEmpty(stepVO.getStepCondition())) {
             boolean result = false;
             try {
-                result = parser.parseExpression(stepVO.getStepCondition()).getValue(mContext, Boolean.class);
+                result = mParser.parseExpression(stepVO.getStepCondition()).getValue(mContext, Boolean.class);
             } catch (Exception e) {
                 result = false;
             }
@@ -1090,7 +1128,7 @@ public class DeviceEventListener extends EventListener { //
         String userId;
         if (ObjectUtils.isEmpty(client) || ObjectUtils.isEmpty(userId = SocketUtil.clientUserIds.get(client))) {
             log.info("该客户已下线");
-            PushData.send2Operation("该客户已下线", 0);
+            PushData.send2Operation("该客户已下线", 0.0);
             return null;
         }
         return userId;
@@ -1111,7 +1149,7 @@ public class DeviceEventListener extends EventListener { //
 
         if (ObjectUtils.isEmpty(message)) {
             log.info("请求数据为空");
-            PushData.send2Operation("请求数据为空", 0);
+            PushData.send2Operation("请求数据为空", 0.0);
             return;
         }
 

+ 1 - 1
taphole-iron/src/main/java/com/sckj/iron/socketio/PushData.java

@@ -123,7 +123,7 @@ public class PushData {
      * @param message 发送的消息内容
      * @param isStopSendMsg  是否停止发送信息
      */
-    public static void send2Operation(Object message, Integer isStopSendMsg) {
+    public static void send2Operation(Object message, Double isStopSendMsg) {
         if (SocketUtil.connectMap.isEmpty()) {//|| isStopSendMsg
             return;
         }

+ 32 - 0
taphole-iron/src/main/java/com/sckj/iron/validate/TIronTestCreateValidate.java

@@ -0,0 +1,32 @@
+package com.sckj.iron.validate;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+@ApiModel("出铁诊断创建参数")
+public class TIronTestCreateValidate implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NotNull(message = "testStatus参数缺失")
+    @ApiModelProperty(value = "诊断状态(1正常 0异常)")
+    private String testStatus;
+
+    @NotNull(message = "testDesc参数缺失")
+    @ApiModelProperty(value = "鱼雷罐车车号")
+    private String testDesc;
+
+    @NotNull(message = "tapholeId参数缺失")
+    @ApiModelProperty(value = "铁口区域编号")
+    private String tapholeId;
+
+    @NotNull(message = "boilerId参数缺失")
+    @ApiModelProperty(value = "高炉编号")
+    private String boilerId;
+
+}

+ 36 - 0
taphole-iron/src/main/java/com/sckj/iron/validate/TIronTestSearchValidate.java

@@ -0,0 +1,36 @@
+package com.sckj.iron.validate;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@ApiModel("出铁诊断搜素参数")
+public class TIronTestSearchValidate implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+
+    @ApiModelProperty(value = "开始时间")
+    private String createTimeStart;
+
+    @ApiModelProperty(value = "结束时间")
+    private String createTimeEnd;
+
+    @ApiModelProperty(value = "诊断状态(1正常 0异常)")
+    private String testStatus;
+
+    @ApiModelProperty(value = "鱼雷罐车车号")
+    private String testDesc;
+
+    @ApiModelProperty(value = "铁口区域编号")
+    private String tapholeId;
+
+    @ApiModelProperty(value = "高炉编号")
+    private String boilerId;
+
+}

+ 41 - 0
taphole-iron/src/main/java/com/sckj/iron/validate/TIronTestUpdateValidate.java

@@ -0,0 +1,41 @@
+package com.sckj.iron.validate;
+
+import com.sckj.common.validator.annotation.LongIDMust;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * 出铁诊断参数
+ * @author LikeAdmin
+ */
+@Data
+@ApiModel("出铁诊断更新参数")
+public class TIronTestUpdateValidate implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @LongIDMust(message = "id参数必传且需大于0")
+    @ApiModelProperty(value = "")
+    private Long id;
+
+    @NotNull(message = "testStatus参数缺失")
+    @ApiModelProperty(value = "诊断状态(1正常 0异常)")
+    private String testStatus;
+
+    @NotNull(message = "testDesc参数缺失")
+    @ApiModelProperty(value = "鱼雷罐车车号")
+    private String testDesc;
+
+    @NotNull(message = "tapholeId参数缺失")
+    @ApiModelProperty(value = "铁口区域编号")
+    private String tapholeId;
+
+    @NotNull(message = "boilerId参数缺失")
+    @ApiModelProperty(value = "高炉编号")
+    private String boilerId;
+
+}

+ 33 - 0
taphole-iron/src/main/java/com/sckj/iron/vo/TIronTestDetailVo.java

@@ -0,0 +1,33 @@
+package com.sckj.iron.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Date;
+
+@Data
+@ApiModel("出铁诊断详情Vo")
+public class TIronTestDetailVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "")
+    private Long id;
+
+    @ApiModelProperty(value = "诊断状态(1正常 0异常)")
+    private String testStatus;
+
+    @ApiModelProperty(value = "鱼雷罐车车号")
+    private String testDesc;
+
+    @ApiModelProperty(value = "铁口区域编号")
+    private String tapholeId;
+
+    @ApiModelProperty(value = "高炉编号")
+    private String boilerId;
+
+
+}

+ 39 - 0
taphole-iron/src/main/java/com/sckj/iron/vo/TIronTestListedVo.java

@@ -0,0 +1,39 @@
+package com.sckj.iron.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Date;
+
+@Data
+@ApiModel("出铁诊断列表Vo")
+public class TIronTestListedVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+
+    @ApiModelProperty(value = "创建时间")
+    private String createTime;
+
+    @ApiModelProperty(value = "")
+    private Long id;
+
+    @ApiModelProperty(value = "诊断状态(1正常 0异常)")
+    private String testStatus;
+
+    @ApiModelProperty(value = "鱼雷罐车车号")
+    private String testDesc;
+
+    @ApiModelProperty(value = "铁口区域编号")
+    private String tapholeId;
+
+    @ApiModelProperty(value = "高炉编号")
+    private String boilerId;
+
+
+}

+ 3 - 1
taphole-l2-start/src/main/java/com/sckj/l2start/listener/L2EventListener.java

@@ -77,9 +77,11 @@ public class L2EventListener extends EventListener {
             tl2Data.setOpenDepth(Double.parseDouble(dataList.get(20)));
             tl2Data.setAvgTemp(Double.parseDouble(dataList.get(21)));
             taskExecutor.submit(() -> {
-                RedisUtils.addFixedElement("ironElement", tl2Data, 10);
                 boolean dataResult = tl2DataService.saveOrUpdate(tl2Data);
             });
+            taskExecutor.submit(() -> {
+                RedisUtils.addFixedElement("ironElement", tl2Data, 10);
+            });
             //boolean dataResult = tl2DataService.saveOrUpdate(tl2Data);
 
             //log.info("tl2Material:{},tl2Data:{}", materialResult, dataResult);

+ 53 - 38
taphole-opc/src/main/java/com/sckj/opc/dataservice/HDServiceImpl.java

@@ -29,10 +29,7 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.PreDestroy;
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 
@@ -57,6 +54,8 @@ public class HDServiceImpl {
     private ScheduledTaskManager scheduledTaskManager;
 
     private ConcurrentHashMap<Long, HDDataConnection> mOPCDaClientMap = new ConcurrentHashMap<>();
+    private ConcurrentHashMap<String, HDRecord> mOPCDaPointsMap = new ConcurrentHashMap<>();
+
 
     //存储ihd标记的定时任务
     private Set<String> taskNameSet = new HashSet<>();
@@ -169,28 +168,47 @@ public class HDServiceImpl {
             throw new OperateException("未获取到服务器或标记信息");
         }
         if (ObjectUtils.isEmpty(hdTag.getTagId()) || ObjectUtils.isEmpty(hdTag.getTagName()) || ObjectUtils.isEmpty(hdTag.getPeriod())) {
-            log.warn("subscription point => tagId:{},tagName{},period{}",hdTag.getTagId(),hdTag.getTagName(),hdTag.getPeriod());
+            log.warn("subscription point => tagId:{},tagName{},period{}", hdTag.getTagId(), hdTag.getTagName(), hdTag.getPeriod());
             throw new OperateException("tagId 、tagName、period不能为空");
         }
+
         scheduledTaskManager.addTask(hdTag.getTagName(), 0, hdTag.getPeriod(), TimeUnit.SECONDS, () -> {
             try {
                 final HDDataConnection connection = createConnection(opcServer);
                 HDDataProvider dp = new HDDataProvider(connection);
                 HDRecord record = dp.querySnapshotByTagID(hdTag.getTagId());
+                if (record != null) {
+                    HDRecord previousData = mOPCDaPointsMap.get(hdTag.getTagName());
+
+                    //直接比较原始对象,避免字符串转换误差
+                    boolean isNewData = previousData == null ||
+                            !Objects.equals(previousData.getValueStr(), record.getValueStr());
+
+                    if (isNewData) {
+                        OPCData build = OPCData.builder()
+                                .data(record.getValueStr())
+                                .pointName(hdTag.getTagName())
+                                .belongTagID(record.getBelongTagID())
+                                .sourceTime(new Date(record.getSecond() * 1000))
+                                .serverTime(new Date(record.getSecond() * 1000))
+                                .serverType(opcServer.getType())
+                                .build();
+                        asyncEventBus.post(build);
+                        //使用put原子操作更新数据
+                        mOPCDaPointsMap.put(hdTag.getTagName(), record);
+                    }
+                    if (null != previousData) {
+                        log.info("{}({})当前数据:{},上个数据:{}", hdTag.getTagName(), hdTag.getTagDesc(), record.getValueStr(), previousData.getValueStr());
+                    } else {
+                        log.info("{}({})当前数据:{}", hdTag.getTagName(), hdTag.getTagDesc(), record.getValueStr());
+                    }
+
+                }
+
 
-                OPCData build = OPCData.builder()
-                        .data(record.getValueStr())
-                        .pointName(hdTag.getTagName())
-                        .belongTagID(record.getBelongTagID())
-                        .sourceTime(new Date(record.getSecond() * 1000))
-                        .serverTime(new Date(record.getSecond() * 1000))
-                        .serverType(opcServer.getType())
-                        .build();
-                asyncEventBus.post(build);
-                log.info("{}({})获取数据成功,数据:{}", hdTag.getTagName(),hdTag.getTagDesc(), record);
             } catch (Exception e) {
-               // e.printStackTrace();
-                log.info("{}({})获取数据异常:{}", hdTag.getTagName(),hdTag.getTagDesc(), e.getMessage());
+                // e.printStackTrace();
+                log.info("{}({})获取数据异常:{}", hdTag.getTagName(), hdTag.getTagDesc(), e.getMessage());
             }
         });
     }
@@ -249,7 +267,7 @@ public class HDServiceImpl {
             if (ObjectUtils.isNotEmpty(opcPointList)) {
                 log.info("start point list:");
                 for (THdTag opcPoint : opcPointList) {
-                   // log.info(opcPoint.getTagName());
+                    // log.info(opcPoint.getTagName());
                     createSubscription(opcServer, opcPoint);
                 }
             }
@@ -261,22 +279,19 @@ public class HDServiceImpl {
      * 读取节点数据
      *
      * @param hdTag
-     * @throws Exception
-     *
-     *{
-     *   "code": 200,
-     *   "msg": "成功",
-     *   "data": {
-     *     "second": 1748263901,
-     *     "microSecond": 32,
-     *     "quality": 192,
-     *     "dataType": "FLOAT32",
-     *     "valueStr": "0.0",
-     *     "belongTagID": 180772,
-     *     "timeStampStr": "2025-05-26 20:51:41:032"
-     *   }
-     * }
-     *
+     * @throws Exception {
+     *                   "code": 200,
+     *                   "msg": "成功",
+     *                   "data": {
+     *                   "second": 1748263901,
+     *                   "microSecond": 32,
+     *                   "quality": 192,
+     *                   "dataType": "FLOAT32",
+     *                   "valueStr": "0.0",
+     *                   "belongTagID": 180772,
+     *                   "timeStampStr": "2025-05-26 20:51:41:032"
+     *                   }
+     *                   }
      */
     public HDRecord readTagValue(THdTag hdTag) throws Exception {
         HdTagDTO opcPointDTO = hdTagService.selectInfoWithServer(hdTag);
@@ -308,7 +323,7 @@ public class HDServiceImpl {
         if (ObjectUtils.isEmpty(opcServerList)) {
             throw new OperateException("没有可用的服务器,请确认服务器是否被禁用!");
         }
-        StringBuilder sb  = new StringBuilder("订阅信息:\n");
+        StringBuilder sb = new StringBuilder("订阅信息:\n");
         for (OPCServer opcServer : opcServerList) {
             HDDataConnection connection = null;
             try {
@@ -319,7 +334,7 @@ public class HDServiceImpl {
             if (null == connection) {
                 continue;
             }
-            sb.append("服务器地址:"+opcServer.getIp()+"\n");
+            sb.append("服务器地址:" + opcServer.getIp() + "\n");
 //            try {
             QueryWrapper<THdTag> pointQueryWrapper = new QueryWrapper<>();
             pointQueryWrapper.lambda().eq(THdTag::getStatus, "1");
@@ -336,7 +351,7 @@ public class HDServiceImpl {
                     }
                     if (ObjectUtils.isEmpty(basicTag)) {
 //                        log.info("{}未查询到信息", opcPoint.getTagName());
-                        sb.append("编号:"+opcPoint.getId()+",tageId:"+basicTag.getId()+",tageName:"+opcPoint.getTagName()+",tageType:"+basicTag.getTagDataType().name()+"\n");
+                        sb.append("编号:" + opcPoint.getId() + ",tageId:" + basicTag.getId() + ",tageName:" + opcPoint.getTagName() + ",tageType:" + basicTag.getTagDataType().name() + "\n");
                         continue;
                     }
 //                    log.info("{}查询到信息:TagId:{},TagType:{},Id:{}", opcPoint.getTagName(), basicTag.getId(), basicTag.getTagDataType().name(), opcPoint.getId());
@@ -347,7 +362,7 @@ public class HDServiceImpl {
                     hdTagService.updateById(newTHdTag);
                 }
             }
-            log.info("刷新信息失败:{}",sb.toString());
+            log.info("刷新信息失败:{}", sb.toString());
 //            } catch (HDSdkException e) {
 //                throw new RuntimeException(e);
 //            }

+ 3 - 0
taphole-opc/src/main/java/com/sckj/opc/entity/OPCData.java

@@ -49,4 +49,7 @@ public class OPCData {
     @TableField(exist = false)
     private String serverType;
 
+    @TableField(exist = false)
+    private String dataType;
+
 }

+ 8 - 11
taphole-warn/src/main/java/com/sckj/warn/controller/TExceptionLogController.java

@@ -3,10 +3,10 @@ package com.sckj.warn.controller;
 import com.sckj.common.aop.Log;
 import com.sckj.common.core.AjaxResult;
 import com.sckj.common.core.PageResult;
-import com.sckj.common.util.ExcelUtils;
 import com.sckj.common.validate.commons.IdValidate;
 import com.sckj.common.validate.commons.PageValidate;
 import com.sckj.common.validator.annotation.IDMust;
+import com.sckj.warn.entity.TExceptionLog;
 import com.sckj.warn.service.impl.TExceptionLogServiceImpl;
 import com.sckj.warn.validate.TExceptionLogCreateValidate;
 import com.sckj.warn.validate.TExceptionLogSearchValidate;
@@ -15,15 +15,11 @@ import com.sckj.warn.vo.TExceptionLogDetailVo;
 import com.sckj.warn.vo.TExceptionLogListedVo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
-import java.io.ByteArrayOutputStream;
 import java.util.List;
 
 @RestController
@@ -83,13 +79,14 @@ public class TExceptionLogController {
     @PostMapping("/export")
     @ApiOperation(value = "异常情况记录导出")
     public void exportTExceptionLog(@Validated TExceptionLogSearchValidate searchValidate, HttpServletResponse response) {
-//        ByteArrayOutputStream outputStream = iTExceptionLogService.exportTExceptionLog(searchValidate);
-//        byte[] content = outputStream.toByteArray();
-//        System.out.println("导出的字节长度:" + content.length);
-//        HttpHeaders headers = new HttpHeaders();
-//        headers.add("Content-Disposition", "attachment; filename=ExceptionLog.xlsx");
-//        headers.add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
         iTExceptionLogService.exportExceptionLogList(searchValidate, response);
     }
 
+    @GetMapping("/getLatest")
+    @ApiOperation(value = "最新异常情况记录")
+    public AjaxResult<TExceptionLog> getLatest() {
+        TExceptionLog list = iTExceptionLogService.getLatest();
+        return AjaxResult.success(list);
+    }
+
 }

+ 2 - 2
taphole-warn/src/main/java/com/sckj/warn/entity/TExceptionLog.java

@@ -17,7 +17,7 @@ public class TExceptionLog implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-    @ApiModelProperty(value = "删除标志(1删除 0未删)")
+    @ApiModelProperty(value = "删除标志(1正常 0删除)")
     private String delFlag;
 
     @ApiModelProperty(value = "创建人")
@@ -36,7 +36,7 @@ public class TExceptionLog implements Serializable {
     @ApiModelProperty(value = "主键")
     private Long id;
 
-    @ApiModelProperty(value = "异常类型(开口耗时、出铁时间、出铁量、流速、铁水温度变化)")
+    @ApiModelProperty(value = "异常类型(0正常 1开口耗时、2出铁时间、3出铁量、4流速、5铁水温度变化、6压力值、7急需堵口、8急需出铁 )")
     private String exceptionType;
 
     @ApiModelProperty(value = "异常区域(铁口区域,目前只有1号铁口区域)")

+ 6 - 3
taphole-warn/src/main/java/com/sckj/warn/service/impl/TExceptionLogServiceImpl.java

@@ -3,8 +3,10 @@ package com.sckj.warn.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.sckj.common.core.AjaxResult;
 import com.sckj.common.core.PageResult;
+import com.sckj.common.exception.OperateException;
 import com.sckj.common.util.ExcelUtils;
 import com.sckj.common.validate.commons.PageValidate;
 import com.sckj.warn.dto.WarnDTO;
@@ -40,7 +42,7 @@ import java.util.List;
  * @author zhanghao
  */
 @Service
-public class TExceptionLogServiceImpl  {
+public class TExceptionLogServiceImpl extends ServiceImpl<TExceptionLogMapper, TExceptionLog> {
 
     @Resource
     TExceptionLogMapper tExceptionLogMapper;
@@ -257,6 +259,7 @@ public class TExceptionLogServiceImpl  {
     }
 
 
-
-
+    public TExceptionLog getLatest() {
+        return this.lambdaQuery().orderByDesc(TExceptionLog::getCreateTime).list().stream().findFirst().orElseThrow(()->new OperateException("未查询到数据"));
+    }
 }