Переглянути джерело

1.步骤表添加dataExpression步骤表达式表示当前步骤数据的生成式
2.更新参数方法调整设置上下文数据的逻辑,处理由于没有数据而设置失败的报错的问题
3.更新获取料速的方法
4.优化压差不符合标准压差就传标记符号

wangxiaofei 2 місяців тому
батько
коміт
b8e9c2e951
23 змінених файлів з 301 додано та 174 видалено
  1. 36 9
      taphole-common/src/main/java/com/sckj/common/util/ExcelUtils.java
  2. 5 2
      taphole-iron/src/main/java/com/sckj/iron/constant/StepConstans.java
  3. 2 2
      taphole-iron/src/main/java/com/sckj/iron/entity/TIronStep.java
  4. 4 4
      taphole-iron/src/main/java/com/sckj/iron/service/impl/TIronStepServiceImpl.java
  5. 2 2
      taphole-iron/src/main/java/com/sckj/iron/service/impl/TIronVisualScreenServiceImpl.java
  6. 81 79
      taphole-iron/src/main/java/com/sckj/iron/socketio/DeviceEventListener.java
  7. 4 6
      taphole-iron/src/main/java/com/sckj/iron/validate/TIronStepCreateValidate.java
  8. 3 4
      taphole-iron/src/main/java/com/sckj/iron/validate/TIronStepSearchValidate.java
  9. 4 5
      taphole-iron/src/main/java/com/sckj/iron/validate/TIronStepUpdateValidate.java
  10. 3 3
      taphole-iron/src/main/java/com/sckj/iron/vo/IronStepVO.java
  11. 2 4
      taphole-iron/src/main/java/com/sckj/iron/vo/TIronStepDetailVo.java
  12. 2 4
      taphole-iron/src/main/java/com/sckj/iron/vo/TIronStepListedVo.java
  13. 5 2
      taphole-l2-start/src/main/java/com/sckj/l2start/listener/L2EventListener.java
  14. 7 1
      taphole-l2/src/main/java/com/sckj/l2/mapper/TL2MaterialMapper.java
  15. 5 16
      taphole-l2/src/main/java/com/sckj/l2/service/impl/TL2DataServiceImpl.java
  16. 8 8
      taphole-l2/src/main/java/com/sckj/l2/service/impl/TL2MaterialServiceImpl.java
  17. 10 0
      taphole-l2/src/main/resources/mapper/TL2MaterialMapper.xml
  18. 68 22
      taphole-opc/src/main/java/com/sckj/opc/dataservice/HDServiceImpl.java
  19. 24 1
      taphole-opc/src/main/java/com/sckj/opc/dto/HDRecordExport.java
  20. 11 0
      taphole-opc/src/main/java/com/sckj/opc/service/OPCPointServiceImpl.java
  21. 11 0
      taphole-opc/src/main/java/com/sckj/opc/service/THdTagServiceImpl.java
  22. 2 0
      taphole-opc/src/main/java/com/sckj/opc/validate/THdTagSearchValidate.java
  23. 2 0
      taphole-opc/src/main/java/com/sckj/opc/validate/TOpcPointSearchValidate.java

+ 36 - 9
taphole-common/src/main/java/com/sckj/common/util/ExcelUtils.java

@@ -19,14 +19,41 @@ public class ExcelUtils {
      * @throws IOException
      */
     public static void exportExcel(List<?> data, Class<?> clazz, String sheetName, String fileName, HttpServletResponse response) throws IOException {
-        String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20");
-        response.setContentType("application/vnd.ms-excel");
-        response.setCharacterEncoding("utf8");
-        response.setHeader("Content-disposition", "attachment;filename=" + encodedFileName);
-        ServletOutputStream outputStream = response.getOutputStream();
-        EasyExcel.write(outputStream, clazz)
-                .sheet(sheetName)
-                .doWrite(data);
-        outputStream.close();
+        if (data == null || data.isEmpty()) {
+            throw new IllegalArgumentException("导出数据不能为空");
+        }
+        
+        ServletOutputStream outputStream = null;
+        try {
+            // 设置响应头
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            response.setCharacterEncoding("UTF-8");
+            response.setHeader("Cache-Control", "no-cache");
+            response.setHeader("Pragma", "no-cache");
+            response.setDateHeader("Expires", 0);
+            
+            // 文件名编码处理
+            String encodedFileName = URLEncoder.encode(fileName + ".xlsx", "UTF-8").replace("+", "%20");
+            response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
+            
+            outputStream = response.getOutputStream();
+            
+            // 使用EasyExcel导出
+            EasyExcel.write(outputStream, clazz)
+                    .sheet(sheetName)
+                    .doWrite(data);
+                    
+            outputStream.flush();
+        } catch (Exception e) {
+            throw new IOException("Excel导出失败: " + e.getMessage(), e);
+        } finally {
+            if (outputStream != null) {
+                try {
+                    outputStream.close();
+                } catch (IOException e) {
+                    // 忽略关闭异常
+                }
+            }
+        }
     }
 }

+ 5 - 2
taphole-iron/src/main/java/com/sckj/iron/constant/StepConstans.java

@@ -7,14 +7,17 @@ public class StepConstans {
     //炉前申请出铁
     public static final String STEP_LQSQCT = "lqsqct";
 
-    //预判和确认出铁
+    //炉内确认出铁
     public static final String STEP_LNCT = "lnct";
 
     //铁量差
     public static final String STEP_TLC = "tlc";
 
+    //高炉生产情况
+    public static final String STEP_GLSCQK = "glscqk";
+
     //高炉压差
-    public static final String STEP_GLYC = "glyc";
+    public static final String STEP_YC = "yc";
 
     //料速
     public static final String STEP_LS = "ls";

+ 2 - 2
taphole-iron/src/main/java/com/sckj/iron/entity/TIronStep.java

@@ -56,8 +56,8 @@ public class TIronStep implements Serializable {
     @ApiModelProperty(value = "排序")
     private Integer sort;
 
-    @ApiModelProperty(value = "订阅点名称(通道.设备.标识)")
-    private String pointName;
+    @ApiModelProperty(value = "数据表达式")
+    private String dataExpression;
 
     @ApiModelProperty(value = "步骤名称表达式")
     private String stepNameExpression;

+ 4 - 4
taphole-iron/src/main/java/com/sckj/iron/service/impl/TIronStepServiceImpl.java

@@ -123,8 +123,8 @@ public class TIronStepServiceImpl extends ServiceImpl<TIronStepMapper, TIronStep
         if(ObjectUtils.isNotEmpty(searchValidate.getConfirmMode())){
             queryWrapper.lambda().eq(TIronStep::getConfirmMode, searchValidate.getConfirmMode());
         }
-        if(ObjectUtils.isNotEmpty(searchValidate.getPointName())){
-            queryWrapper.lambda().like(TIronStep::getPointName, searchValidate.getPointName());
+        if(ObjectUtils.isNotEmpty(searchValidate.getDataExpression())){
+            queryWrapper.lambda().like(TIronStep::getDataExpression, searchValidate.getDataExpression());
         }
 
         queryWrapper.orderByAsc(Arrays.asList("sort"));
@@ -198,7 +198,7 @@ public class TIronStepServiceImpl extends ServiceImpl<TIronStepMapper, TIronStep
         model.setNodeType(createValidate.getNodeType());
         model.setStatus(createValidate.getStatus());
         model.setConfirmMode(createValidate.getConfirmMode());
-        model.setPointName(createValidate.getPointName());
+        model.setDataExpression(createValidate.getDataExpression());
         tIronStepMapper.insert(model);
         refreshTreeSteps();
     }
@@ -228,7 +228,7 @@ public class TIronStepServiceImpl extends ServiceImpl<TIronStepMapper, TIronStep
         model.setNodeType(updateValidate.getNodeType());
         model.setStatus(updateValidate.getStatus());
         model.setConfirmMode(updateValidate.getConfirmMode());
-        model.setPointName(updateValidate.getPointName());
+        model.setDataExpression(updateValidate.getDataExpression());
         tIronStepMapper.updateById(model);
         refreshTreeSteps();
     }

+ 2 - 2
taphole-iron/src/main/java/com/sckj/iron/service/impl/TIronVisualScreenServiceImpl.java

@@ -248,7 +248,7 @@ public class TIronVisualScreenServiceImpl {
                     for (IronTrendL1DTO ironTrendL1DTO : car1List) {
                         if (sdfMinute.format(ironTrendL1DTO.getCreateTime()).equals(string)) {
                             Map<String, Object> map = new HashMap<>();
-                            map.put("value", ironTrendL1DTO.getData());
+                            map.put("value", ironTrendL1DTO.getData()+"#");
                             map.put("xAxis", sdfMinute.format(ironTrendL1DTO.getCreateTime()));
                             map.put("yAxis", data);
                             mapList.add(map);
@@ -257,7 +257,7 @@ public class TIronVisualScreenServiceImpl {
                     for (IronTrendL1DTO ironTrendL1DTO : car2List) {
                         if (sdfMinute.format(ironTrendL1DTO.getCreateTime()).equals(string)) {
                             Map<String, Object> map = new HashMap<>();
-                            map.put("value", ironTrendL1DTO.getData());
+                            map.put("value", ironTrendL1DTO.getData()+"#");
                             map.put("xAxis", sdfMinute.format(ironTrendL1DTO.getCreateTime()));
                             map.put("yAxis", data);
                             mapList.add(map);

+ 81 - 79
taphole-iron/src/main/java/com/sckj/iron/socketio/DeviceEventListener.java

@@ -22,12 +22,12 @@ import com.sckj.iron.vo.IronStepVO;
 import com.sckj.l2.dto.TrendRequest;
 import com.sckj.l2.entity.TL2Data;
 import com.sckj.l2.service.impl.TL2DataServiceImpl;
+import com.sckj.l2.service.impl.TL2MaterialServiceImpl;
 import com.sckj.opc.dataservice.HDServiceImpl;
 import com.sckj.opc.dataservice.OPCDAServiceImpl;
 import com.sckj.opc.entity.OPCData;
 import com.sckj.opc.service.OPCDataServiceImpl;
 import com.sckj.opc.service.THdTagServiceImpl;
-import com.sckj.opc.utils.CustomUtil;
 import com.sckj.warn.entity.TAudio;
 import com.sckj.warn.service.impl.TAudioServiceImpl;
 import com.sckj.warn.service.impl.TExceptionLogServiceImpl;
@@ -126,6 +126,9 @@ public class DeviceEventListener extends AbstractEventListener { //
     @Resource
     TIronVisualScreenServiceImpl tIronVisualScreenService;
 
+    @Resource
+    TL2MaterialServiceImpl tl2MaterialService;
+
     //铁水成分
     private static final String IRON_ELEMENT = "ironElement";
     //铁水温度
@@ -344,38 +347,34 @@ public class DeviceEventListener extends AbstractEventListener { //
             for (TIronParam mIronParam : mIronParams) {
                 if (Objects.equals(mIronParam.getParamName(), ParamsConstants.iron_speed)) {
                     StandardConstans.STANDARD_SPEED = mIronParam.getParamValue();
+                    mContext.setVariable(ExpressionConstants.stdSpeedMin, Double.parseDouble(StandardConstans.STANDARD_SPEED.split("-")[0]));
+                    mContext.setVariable(ExpressionConstants.stdSpeedMax, Double.parseDouble(StandardConstans.STANDARD_SPEED.split("-")[1]));
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.pressure_diff_value)) {
                     StandardConstans.STANDARD_PRESSURE_DIFF = Double.parseDouble(mIronParam.getParamValue());
+                    mContext.setVariable(ExpressionConstants.stdPressureDiff, StandardConstans.STANDARD_PRESSURE_DIFF);
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.iron_time)) {
                     StandardConstans.STANDARD_IRON_TIME = mIronParam.getParamValue();
+                    mContext.setVariable(ExpressionConstants.stdIronTimeMin, Double.parseDouble(StandardConstans.STANDARD_IRON_TIME.split("-")[0]));
+                    mContext.setVariable(ExpressionConstants.stdIronTimeMax, Double.parseDouble(StandardConstans.STANDARD_IRON_TIME.split("-")[1]));
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.server_url)) {
                     SERVER_URL = mIronParam.getParamValue();
+                    mContext.setVariable(ExpressionConstants.stdServerUrl, SERVER_URL);
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.ironwater_temp)) {
                     StandardConstans.STANDARD_TEMP = mIronParam.getParamValue();
+                    mContext.setVariable(ExpressionConstants.stdTempMin, Double.parseDouble(StandardConstans.STANDARD_TEMP.split("-")[0]));
+                    mContext.setVariable(ExpressionConstants.stdTempMax, Double.parseDouble(StandardConstans.STANDARD_TEMP.split("-")[1]));
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.open_hour)) {
                     StandardConstans.STANDARD_OPEN_HOUR = Integer.parseInt(mIronParam.getParamValue());
+                    mContext.setVariable(ExpressionConstants.stdOpenHour, StandardConstans.STANDARD_OPEN_HOUR);
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.iron_weight)) {
                     StandardConstans.STANDARD_IRON_WEIGHT = mIronParam.getParamValue();
+                    mContext.setVariable(ExpressionConstants.stdIronWeightMin, Double.parseDouble(StandardConstans.STANDARD_IRON_WEIGHT.split("-")[0]));
+                    mContext.setVariable(ExpressionConstants.stdIronWeightMax, Double.parseDouble(StandardConstans.STANDARD_IRON_WEIGHT.split("-")[1]));
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.open_machine_value)) {
                     StandardConstans.STANDARD_OPEN_MACHINE_LOCATION = Double.parseDouble(mIronParam.getParamValue());
                 } else if (Objects.equals(mIronParam.getParamName(), ParamsConstants.mud_machine_value)) {
                     StandardConstans.STANDARD_MUD_MACHINE_PRESSURE = Double.parseDouble(mIronParam.getParamValue());
                 }
-//                mContext.setVariable(ExpressionConstants.stdSpeed, STANDARD_SPEED.get());
-                mContext.setVariable(ExpressionConstants.stdSpeedMin, Double.parseDouble(StandardConstans.STANDARD_SPEED.split("-")[0]));
-                mContext.setVariable(ExpressionConstants.stdSpeedMax, Double.parseDouble(StandardConstans.STANDARD_SPEED.split("-")[1]));
-                mContext.setVariable(ExpressionConstants.stdPressureDiff, StandardConstans.STANDARD_PRESSURE_DIFF);
-//                mContext.setVariable(ExpressionConstants.stdIronTime, STANDARD_IRON_TIME.get());
-                mContext.setVariable(ExpressionConstants.stdIronTimeMin, Double.parseDouble(StandardConstans.STANDARD_IRON_TIME.split("-")[0]));
-                mContext.setVariable(ExpressionConstants.stdIronTimeMax, Double.parseDouble(StandardConstans.STANDARD_IRON_TIME.split("-")[1]));
-                mContext.setVariable(ExpressionConstants.stdServerUrl, SERVER_URL);
-//                mContext.setVariable(ExpressionConstants.stdTemp, STANDARD_TEMP_DIFF);
-                mContext.setVariable(ExpressionConstants.stdTempMin, Double.parseDouble(StandardConstans.STANDARD_TEMP.split("-")[0]));
-                mContext.setVariable(ExpressionConstants.stdTempMax, Double.parseDouble(StandardConstans.STANDARD_TEMP.split("-")[1]));
-                mContext.setVariable(ExpressionConstants.stdOpenHour, StandardConstans.STANDARD_OPEN_HOUR);
-//                mContext.setVariable(ExpressionConstants.stdIronWeight, STANDARD_IRON_WEIGHT);
-                mContext.setVariable(ExpressionConstants.stdIronWeightMin, Double.parseDouble(StandardConstans.STANDARD_IRON_WEIGHT.split("-")[0]));
-                mContext.setVariable(ExpressionConstants.stdIronWeightMax, Double.parseDouble(StandardConstans.STANDARD_IRON_WEIGHT.split("-")[1]));
             }
             log.info("STANDARD_SPEED: {},PRESSURE_DIFF_VALUE:{}", StandardConstans.STANDARD_SPEED, StandardConstans.STANDARD_PRESSURE_DIFF);
             log.info("IRON_TIME: {},SERVER_URL:{}", StandardConstans.STANDARD_IRON_TIME, SERVER_URL);
@@ -484,10 +483,10 @@ public class DeviceEventListener extends AbstractEventListener { //
                 if (NODE.equalsIgnoreCase(stepDTO.getNodeType())) {
                     //处理子项
                     for (IronStepVO child : stepDTO.getChilds()) {
-                        if (StepConstans.STEP_GLYC.equals(child.getIdentifier())) {
+                        if (StepConstans.STEP_GLSCQK.equals(child.getIdentifier())) {
                             for (IronStepVO grandChild : child.getChilds()) {
                                 if (StepConstans.STEP_LS.equals(grandChild.getIdentifier())) {
-                                    grandChild.setData(RedisUtils.getFixedLatestElement("materialSpeed"));
+                                    grandChild.setData(tl2MaterialService.getMaterialSpeedOneHourAgo());
                                 }
                             }
                         } else if (StepConstans.STEP_TLC.equals(child.getIdentifier())) {
@@ -635,7 +634,7 @@ public class DeviceEventListener extends AbstractEventListener { //
                         if (count >= triggerCount1) {
                             PushData.send2Warn(WarnData.warnClose("铁水流速过快告警", closureAlarmUrl));
                             taskExecutor.submit(() -> {
-                                exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("7000").exceptionDesc(String.format("流速%s吨/分钟",mContext.lookupVariable(ExpressionConstants.rtIronSpeed))).build());
+                                exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("7000").exceptionDesc(String.format("流速%s吨/分钟", mContext.lookupVariable(ExpressionConstants.rtIronSpeed))).build());
                                 //推送预警列表
                                 getExceptionList();
                             });
@@ -657,7 +656,7 @@ public class DeviceEventListener extends AbstractEventListener { //
                         if (count >= triggerCount2) {
                             PushData.send2Warn(WarnData.warnClose("铁水流速过慢告警", closureAlarmUrl));
                             taskExecutor.submit(() -> {
-                                exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("8000").exceptionDesc(String.format("流速%s吨/分钟",mContext.lookupVariable(ExpressionConstants.rtIronSpeed))).build());
+                                exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("8000").exceptionDesc(String.format("流速%s吨/分钟", mContext.lookupVariable(ExpressionConstants.rtIronSpeed))).build());
                                 //推送预警列表
                                 getExceptionList();
                             });
@@ -679,7 +678,7 @@ public class DeviceEventListener extends AbstractEventListener { //
                         if (count >= triggerCount3) {
                             PushData.send2Warn(WarnData.warnClose("铁水流速过慢告警", closureAlarmUrl));
                             taskExecutor.submit(() -> {
-                                exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("8000").exceptionDesc(String.format("流速%s吨/分钟",mContext.lookupVariable(ExpressionConstants.rtIronSpeed))).build());
+                                exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("8000").exceptionDesc(String.format("流速%s吨/分钟", mContext.lookupVariable(ExpressionConstants.rtIronSpeed))).build());
                                 //推送预警列表
                                 getExceptionList();
                             });
@@ -733,7 +732,7 @@ public class DeviceEventListener extends AbstractEventListener { //
                     if (!RangeUtils.isInRange(StandardConstans.STANDARD_IRON_TIME, getIronElapsedMinute())) {
                         PushData.send2Warn(WarnData.warnTappingTimeout("出铁时间过长告警", tappingTimeoutAlramUrl));
                         taskExecutor.submit(() -> {
-                            exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("3000").exceptionDesc("出铁时间过长告警").build());
+                            exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("3000").exceptionDesc(String.format("出铁时间:%s分钟", getIronElapsedMinute())).build());
                             //推送预警列表
                             getExceptionList();
                         });
@@ -884,7 +883,7 @@ public class DeviceEventListener extends AbstractEventListener { //
                             tappingWarnCountMap.put(modelKey, count);
                             if (count >= triggerCount) {
                                 PushData.send2Warn(WarnData.warnTapping("急需出铁告警", tappingAlramUrl));
-                                exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("10000").exceptionDesc("压差异常,当前压差:" + mContext.lookupVariable("yc")).build());
+                                exceptionLogService.add(TExceptionLogCreateValidate.builder().exceptionType("10000").exceptionDesc(String.format("压差压差超过:%s,请降低送风流量,并操作出铁",String.valueOf(mContext.lookupVariable(ExpressionConstants.stdPressureDiff)))).build());
                                 tappingWarnCountMap.put(modelKey, 0);
                                 //推送预警列表
                                 getExceptionList();
@@ -963,6 +962,7 @@ public class DeviceEventListener extends AbstractEventListener { //
                 RealtimeData realtimeData = new RealtimeData();
                 realtimeData.setValue(opcData.getData());
                 realtimeData.setDesc("出铁状态");
+                realtimeData.setExtra(opcData.getData());
                 mRealtimeStatus.put(IRON_STATUS, realtimeData);
 
                 double currentVal = Double.parseDouble(opcData.getData().toString());
@@ -1010,11 +1010,13 @@ public class DeviceEventListener extends AbstractEventListener { //
                         RealtimeData realtimeData = new RealtimeData();
                         realtimeData.setValue(1);
                         realtimeData.setDesc("摆动溜嘴的摆动方向");
+                        realtimeData.setExtra(opcData.getData());
                         mRealtimeStatus.put(CHONGZ_STATUS, realtimeData);
                     } else {
                         RealtimeData realtimeData = new RealtimeData();
                         realtimeData.setValue(0);
                         realtimeData.setDesc("摆动溜嘴的摆动方向");
+                        realtimeData.setExtra(opcData.getData());
                         mRealtimeStatus.put(CHONGZ_STATUS, realtimeData);
                     }
                 } else {
@@ -1035,11 +1037,13 @@ public class DeviceEventListener extends AbstractEventListener { //
                         RealtimeData realtimeData = new RealtimeData();
                         realtimeData.setValue(2);
                         realtimeData.setDesc("摆动溜嘴的摆动方向");
+                        realtimeData.setExtra(opcData.getData());
                         mRealtimeStatus.put(CHONGZ_STATUS, realtimeData);
                     } else {
                         RealtimeData realtimeData = new RealtimeData();
                         realtimeData.setValue(0);
                         realtimeData.setDesc("摆动溜嘴的摆动方向");
+                        realtimeData.setExtra(opcData.getData());
                         mRealtimeStatus.put(CHONGZ_STATUS, realtimeData);
                     }
                 } else {
@@ -1068,34 +1072,40 @@ public class DeviceEventListener extends AbstractEventListener { //
                 RealtimeData realtimeData = new RealtimeData();
                 realtimeData.setValue(isRising ? 1 : 0);
                 realtimeData.setDesc("出渣状态");
+                realtimeData.setExtra(opcData.getData());
                 mRealtimeStatus.put(CHUZ_STATUS, realtimeData);
             } else if (opcData.getPointName().contains(SubscribeTagConstants.TAG_SZB_STATUS(opcData.getServerType()))
                     || opcData.getPointName().contains(SubscribeTagConstants.TAG_CZF_STATUS(opcData.getServerType()))
             ) {
                 RealtimeData realtimeData = new RealtimeData();
-                Boolean value = mParser.parseExpression("#szxt999 > 0 and #szb999 > 0").getValue(mContext, Boolean.class);
+                Boolean value = mParser.parseExpression("#subszb41 > 0 and #subczf41 > 0").getValue(mContext, Boolean.class);
                 realtimeData.setValue(Boolean.TRUE.equals(value) ? 1 : 0);
                 realtimeData.setDesc("冲渣状态");
+                realtimeData.setExtra(opcData.getData());
                 mRealtimeStatus.put(CHONGZ_STATUS, realtimeData);
             } else if (opcData.getPointName().contains(SubscribeTagConstants.TAG_KKJ_STATUS(opcData.getServerType()))) {
                 //开口机状态
                 RealtimeData realtimeData = new RealtimeData();
                 realtimeData.setValue(Double.parseDouble(opcData.getData().toString()) >= StandardConstans.STANDARD_OPEN_MACHINE_LOCATION ? 1 : 0);
                 realtimeData.setDesc("开口机状态");
+                realtimeData.setExtra(opcData.getData());
                 mRealtimeStatus.put(KKJ_STATUS, realtimeData);
+                log.info("开口机信息:数据:{},标准:{}", opcData.getData(), StandardConstans.STANDARD_OPEN_MACHINE_LOCATION);
             } else if (opcData.getPointName().contains(SubscribeTagConstants.TAG_NPXZYY(opcData.getServerType()))) {
                 //泥炮堵口状态
                 RealtimeData realtimeData = new RealtimeData();
                 realtimeData.setValue(Double.parseDouble(opcData.getData().toString()) >= StandardConstans.STANDARD_MUD_MACHINE_PRESSURE ? 1 : 0);
                 realtimeData.setDesc("泥炮堵口状态");
+                realtimeData.setExtra(opcData.getData());
                 mRealtimeStatus.put(NPDK_STATUS, realtimeData);
+                log.info("泥炮堵口信息:数据:{},标准:{}", opcData.getData(), StandardConstans.STANDARD_MUD_MACHINE_PRESSURE);
             }
 
         }
 
         TL2Data fixedLatestElement = null;
         try {
-            fixedLatestElement = (TL2Data) RedisUtils.getFixedLatestElement(IRON_ELEMENT);
+            fixedLatestElement = (TL2Data) RedisUtils.getFixedLatestElement("l2IronData");
         } catch (Exception e) {
 
         }
@@ -1149,49 +1159,30 @@ public class DeviceEventListener extends AbstractEventListener { //
     }
 
     private synchronized void operate(OPCData mOPCData) {
-        String pointName = mOPCData.getPointName();
-        Object data = mOPCData.getData();
-        for (IronStepVO stepDTO : mSteps) {
-            if (NODE.equalsIgnoreCase(stepDTO.getNodeType())) {
-                //处理子项
-                for (IronStepVO child : stepDTO.getChilds()) {
-                    for (IronStepVO childchild : child.getChilds()) {
-
-                        //plc的point和step的point一致
-                        String newPointName = childchild.getPointName();
-
-                        if (ObjectUtils.isEmpty(newPointName)) {
-                            continue;
-                        }
-                        newPointName = CustomUtil.createNewPointName(newPointName, activeProfiles, mOPCData.getServerType());
-                        if (Objects.equals(newPointName, pointName)) {
-                            //3.创建变量上下文,设置变量
-                            childchild.setData(data);
-                        }
-                    }
-                    String newPointName = child.getPointName();
-                    if (ObjectUtils.isEmpty(newPointName)) {
-                        continue;
-                    }
-                    newPointName = CustomUtil.createNewPointName(newPointName, activeProfiles, mOPCData.getServerType());
-                    if (Objects.equals(newPointName, pointName)) {
-                        child.setData(data);
-                    }
-                }
-            }
-        }
-
         setStepResult(mSteps);
-
-
         PushData.send2Operation(mSteps, ironLoading1.get());
-
     }
 
     private String stepLogId;
 
     //计算每步结果为0(不通过)或者为1(通过)
     private synchronized void setStepResult(List<IronStepVO> mSteps) {
+        // 原有逻辑
+        boolean foundFalsePass = false;
+        //发现第一个pass是false,后续都为false,包括父项、子项、孙子项
+        for (IronStepVO stepDTO : mSteps) {
+            for (IronStepVO child : stepDTO.getChilds()) {
+                for (IronStepVO grandchild : child.getChilds()) {
+                    //孙子项 验证是否通过
+                    foundFalsePass = isFoundFalsePass(grandchild, foundFalsePass);
+                }
+                //子项 验证是否通过
+                foundFalsePass = isFoundFalsePass(child, foundFalsePass);
+            }
+            //父项 验证是否通过
+            foundFalsePass = isFoundFalsePass(stepDTO, foundFalsePass);
+        }
+
         // 检查ironLoading1是否从1变为0
         if (lastIronLoading1 == 1 && ironLoading1.get() == 0) {
             setAllStepPassResult(mSteps, 0);
@@ -1202,28 +1193,13 @@ public class DeviceEventListener extends AbstractEventListener { //
         if (mSteps != null && !mSteps.isEmpty()) {
             lastStep = mSteps.get(mSteps.size() - 1);
         }
-        // 1. 如果最后一个步骤为lqctcz且passResult为1,并且ironLoading1为1,则所有步骤passResult都保持为1
+        // 1. 如果最后一个步骤为 lnct 且passResult为1,并且ironLoading1为1,则所有步骤passResult都保持为1
         if (lastStep != null && StepConstans.STEP_LNCT.equals(lastStep.getIdentifier()) && lastStep.getPassResult() == 1 && ironLoading1.get() == 1) {
             setAllStepPassResult(mSteps, 1);
             lastIronLoading1 = ironLoading1.get();
             return;
         }
 
-        // 原有逻辑
-        boolean foundFalsePass = false;
-        //发现第一个pass是false,后续都为false,包括父项、子项、孙子项
-        for (IronStepVO stepDTO : mSteps) {
-            for (IronStepVO child : stepDTO.getChilds()) {
-                for (IronStepVO grandchild : child.getChilds()) {
-                    //孙子项 验证是否通过
-                    foundFalsePass = isFoundFalsePass(grandchild, foundFalsePass);
-                }
-                //子项 验证是否通过
-                foundFalsePass = isFoundFalsePass(child, foundFalsePass);
-            }
-            //父项 验证是否通过
-            foundFalsePass = isFoundFalsePass(stepDTO, foundFalsePass);
-        }
         // 最后更新lastIronLoading1
         lastIronLoading1 = ironLoading1.get();
     }
@@ -1282,6 +1258,16 @@ public class DeviceEventListener extends AbstractEventListener { //
      * @param stepVO
      */
     private void validateStepPass(IronStepVO stepVO) {
+        String dataExpression = stepVO.getDataExpression();
+        if (ObjectUtils.isNotEmpty(dataExpression)) {
+            try {
+                Object value = mParser.parseExpression(dataExpression).getValue(mContext, Object.class);
+                stepVO.setData(value);
+            } catch (Exception e) {
+                //log.info("{}执行失败", dataExpression);
+            }
+        }
+
         //根据唯一名称设置环境变量
         mContext.setVariable(stepVO.getIdentifier(), stepVO.getData());
         String flowName = "";
@@ -1301,12 +1287,11 @@ public class DeviceEventListener extends AbstractEventListener { //
         //非流程必须项,直接放行
         if ("0".equals(stepVO.getRequired())) {
             stepVO.setPassResult(1);
-            return;
         }
 
+        boolean result = true;
         //通过条件不为空执行表达式
         if (ObjectUtils.isNotEmpty(stepVO.getStepCondition())) {
-            boolean result = false;
             try {
                 result = mParser.parseExpression(stepVO.getStepCondition()).getValue(mContext, Boolean.class);
             } catch (Exception e) {
@@ -1315,6 +1300,22 @@ public class DeviceEventListener extends AbstractEventListener { //
             stepVO.setPassResult(result ? 1 : 0);
         }
 
+        if ("yc".equals(stepVO.getIdentifier())) {
+            Map<String, Object> extraInfo = new HashMap<>();
+            if (result) {
+                extraInfo.put("colorFlag", "0");
+            } else {
+                extraInfo.put("colorFlag", "-1");
+            }
+            stepVO.setExtraInfo(extraInfo);
+        }
+
+
+        //非流程必须项,直接放行
+        if ("0".equals(stepVO.getRequired())) {
+            stepVO.setPassResult(1);
+        }
+
     }
 
     /***
@@ -1391,9 +1392,10 @@ public class DeviceEventListener extends AbstractEventListener { //
                     realtimeData.setValue(child.getPassResult());
                     realtimeData.setDesc("鱼雷罐车到位状态");
                     mRealtimeStatus.put(YLGC_STATUS, realtimeData);
+                    PushData.send2RealtimeStatus(mRealtimeStatus);
                 }
 
-                PushData.send2RealtimeStatus(mRealtimeStatus);
+
             }
         }
 

+ 4 - 6
taphole-iron/src/main/java/com/sckj/iron/validate/TIronStepCreateValidate.java

@@ -3,10 +3,9 @@ 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;
-import java.util.Date;
-import java.util.Date;
-import javax.validation.constraints.*;
 
 @Data
 @ApiModel("出铁步骤配置创建参数")
@@ -54,8 +53,7 @@ public class TIronStepCreateValidate implements Serializable {
     @ApiModelProperty(value = "确认方式(1自动 2手动)")
     private String confirmMode;
 
-    @NotNull(message = "pointName参数缺失")
-    @ApiModelProperty(value = "订阅点名称(通道.设备.标识)")
-    private String pointName;
+    @ApiModelProperty(value = "数据表达式")
+    private String dataExpression;
 
 }

+ 3 - 4
taphole-iron/src/main/java/com/sckj/iron/validate/TIronStepSearchValidate.java

@@ -3,9 +3,8 @@ package com.sckj.iron.validate;
 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("出铁步骤配置搜素参数")
@@ -43,7 +42,7 @@ public class TIronStepSearchValidate implements Serializable {
     @ApiModelProperty(value = "确认方式(1自动 2手动)")
     private String confirmMode;
 
-    @ApiModelProperty(value = "订阅点名称(通道.设备.标识)")
-    private String pointName;
+    @ApiModelProperty(value = "数据表达式")
+    private String dataExpression;
 
 }

+ 4 - 5
taphole-iron/src/main/java/com/sckj/iron/validate/TIronStepUpdateValidate.java

@@ -1,11 +1,11 @@
 package com.sckj.iron.validate;
 
-import com.sckj.common.validator.annotation.IDMust;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+
+import javax.validation.constraints.NotNull;
 import java.io.Serializable;
-import javax.validation.constraints.*;
 
 /**
  * 出铁步骤配置参数
@@ -57,8 +57,7 @@ public class TIronStepUpdateValidate implements Serializable {
     @ApiModelProperty(value = "确认方式(1自动 2手动)")
     private String confirmMode;
 
-    @NotNull(message = "pointName参数缺失")
-    @ApiModelProperty(value = "订阅点名称(通道.设备.标识)")
-    private String pointName;
+    @ApiModelProperty(value = "数据表达式")
+    private String dataExpression;
 
 }

+ 3 - 3
taphole-iron/src/main/java/com/sckj/iron/vo/IronStepVO.java

@@ -30,8 +30,8 @@ public class IronStepVO {
     @ApiModelProperty(value = "节点类型(start、end、node、child)")
     private String nodeType;
 
-    @ApiModelProperty(value = "订阅点名称(通道.设备.标识)")
-    private String pointName;
+    @ApiModelProperty(value = "数据表达式")
+    private String dataExpression;
 
     @ApiModelProperty(value = "通过条件")
     private String stepCondition;
@@ -65,7 +65,7 @@ public class IronStepVO {
 
     private List<IronStepVO> childs;
 
-    private Map<String,Object>[] extraInfo;
+    private Map<String,Object> extraInfo;
 
 
 }

+ 2 - 4
taphole-iron/src/main/java/com/sckj/iron/vo/TIronStepDetailVo.java

@@ -5,8 +5,6 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
-import java.util.Date;
-import java.util.Date;
 
 @Data
 @ApiModel("出铁步骤配置详情Vo")
@@ -44,8 +42,8 @@ public class TIronStepDetailVo implements Serializable {
     @ApiModelProperty(value = "确认方式(1自动 2手动)")
     private String confirmMode;
 
-    @ApiModelProperty(value = "订阅点名称(通道.设备.标识)")
-    private String pointName;
+    @ApiModelProperty(value = "数据表达式")
+    private String dataExpression;
 
 
 }

+ 2 - 4
taphole-iron/src/main/java/com/sckj/iron/vo/TIronStepListedVo.java

@@ -5,8 +5,6 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
-import java.util.Date;
-import java.util.Date;
 
 @Data
 @ApiModel("出铁步骤配置列表Vo")
@@ -44,8 +42,8 @@ public class TIronStepListedVo implements Serializable {
     @ApiModelProperty(value = "确认方式(1自动 2手动)")
     private String confirmMode;
 
-    @ApiModelProperty(value = "订阅点名称(通道.设备.标识)")
-    private String pointName;
+    @ApiModelProperty(value = "数据表达式")
+    private String dataExpression;
 
 
 }

+ 5 - 2
taphole-l2-start/src/main/java/com/sckj/l2start/listener/L2EventListener.java

@@ -80,10 +80,13 @@ public class L2EventListener extends AbstractEventListener {
                 boolean dataResult = tl2DataService.saveOrUpdate(tl2Data);
             });
             taskExecutor.submit(() -> {
-                RedisUtils.addFixedElement("ironElement", tl2Data, 10);
+                RedisUtils.addFixedElement("l2IronData", tl2Data, 10);
             });
             taskExecutor.submit(() -> {
-                RedisUtils.addFixedElement("materialSpeed", dataList.get(22), 10);
+                RedisUtils.addFixedElement("l2MaterialSpeed", dataList.get(22), 10);
+            });
+            taskExecutor.submit(() -> {
+                RedisUtils.addFixedElement("l2IronMaterial",tl2Material, 10);
             });
             //boolean dataResult = tl2DataService.saveOrUpdate(tl2Data);
             //log.info("tl2Material:{},tl2Data:{}", materialResult, dataResult);

+ 7 - 1
taphole-l2/src/main/java/com/sckj/l2/mapper/TL2MaterialMapper.java

@@ -3,6 +3,7 @@ package com.sckj.l2.mapper;
 import com.sckj.common.core.basics.IBaseMapper;
 import com.sckj.l2.entity.TL2Material;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
 
 /**
  * 出铁后Mapper
@@ -10,5 +11,10 @@ import org.apache.ibatis.annotations.Mapper;
  */
 @Mapper
 public interface TL2MaterialMapper extends IBaseMapper<TL2Material> {
-
+    @Select({
+            "SELECT ROUND(COALESCE(SUM(CAST(theory_weight AS DECIMAL(18,2))), 0) / 100, 2)",
+            "FROM t_l2_material",
+            "WHERE load_material_time >= DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 HOUR), '%Y%m%d%H%i%s')"
+    })
+    Double geTotalTheoryWeightInLastHour();
 }

+ 5 - 16
taphole-l2/src/main/java/com/sckj/l2/service/impl/TL2DataServiceImpl.java

@@ -97,41 +97,30 @@ public class TL2DataServiceImpl extends ServiceImpl<TL2DataMapper, TL2Data> {
 
 
     /***
-     * 获取最新2条数据
+     * 获取4高炉1号铁口最新2条数据
      * @return
      */
     public List<TL2Data> getTappedLatest2Datas() {
         LambdaQueryWrapper<TL2Data> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.isNotNull(TL2Data::getIronNo).isNotNull(TL2Data::getIronWeight).isNotNull(TL2Data::getCalcWeight).orderByDesc(TL2Data::getIronNo).last("limit 2");
+        queryWrapper.eq(TL2Data::getTapholeId,"1").isNotNull(TL2Data::getIronNo).isNotNull(TL2Data::getIronWeight).isNotNull(TL2Data::getCalcWeight).orderByDesc(TL2Data::getIronNo).last("limit 2");
         List<TL2Data> list = list(queryWrapper);
         return list;
     }
 
     /***
-     * 获取最新1条数据
+     * 获取4高炉1号铁口最新1条数据
      * @return
      */
     public TL2Data getLatestData() {
         LambdaQueryWrapper<TL2Data> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.isNotNull(TL2Data::getIronNo).orderByDesc(TL2Data::getIronNo).last("limit 1");
+        queryWrapper.eq(TL2Data::getTapholeId,"1").isNotNull(TL2Data::getIronNo).orderByDesc(TL2Data::getIronNo).last("limit 1");
         List<TL2Data> list = list(queryWrapper);
         return ObjectUtils.isEmpty(list) ? null : list.get(0);
     }
 
-    /***
-     * 获取正在出铁的数据
-     * 标记正在出铁的数据:出铁号有了,但是出铁量还没出来,理论铁量也在实时更新
-     * @return
-     */
-    public TL2Data getTappingData() {
-        LambdaQueryWrapper<TL2Data> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.isNotNull(TL2Data::getIronNo).isNull(TL2Data::getIronWeight).isNotNull(TL2Data::getCalcWeight).orderByDesc(TL2Data::getIronNo).last("limit 1");
-        List<TL2Data> list = list(queryWrapper);
-        return ObjectUtils.isEmpty(list) ? null : list.get(0);
-    }
 
     /***
-     * 获取最新6条数据
+     * 查询出铁数据
      * @return
      */
     public List<TL2Data> queryIronData(TL2Data tl2Data) {

+ 8 - 8
taphole-l2/src/main/java/com/sckj/l2/service/impl/TL2MaterialServiceImpl.java

@@ -1,12 +1,11 @@
 package com.sckj.l2.service.impl;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.sckj.l2.entity.TL2Material;
 import com.sckj.l2.mapper.TL2MaterialMapper;
 import org.springframework.stereotype.Service;
 
-import java.util.List;
+import javax.annotation.Resource;
 
 /**
  * L2数据
@@ -17,15 +16,16 @@ import java.util.List;
 public class TL2MaterialServiceImpl extends ServiceImpl<TL2MaterialMapper, TL2Material> {
 
 
+    @Resource
+    TL2MaterialMapper tl2MaterialMapper;
+
     /***
-     * 获取最新2条数据
+     * 获取料速
      * @return
      */
-    public List<TL2Material> getLatest2Data() {
-        LambdaQueryWrapper<TL2Material> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.isNotNull(TL2Material::getChargeNo).orderByDesc(TL2Material::getChargeNo).last("limit 2");
-        List<TL2Material> list = list(queryWrapper);
-        return list;
+    public double getMaterialSpeedOneHourAgo() {
+        Double result = tl2MaterialMapper.geTotalTheoryWeightInLastHour();
+        return result != null ? result : 0.0;
     }
 
 

+ 10 - 0
taphole-l2/src/main/resources/mapper/TL2MaterialMapper.xml

@@ -0,0 +1,10 @@
+<?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">
+<mapper namespace="com.sckj.l2.mapper.TL2MaterialMapper">
+
+
+
+
+
+
+</mapper>

+ 68 - 22
taphole-opc/src/main/java/com/sckj/opc/dataservice/HDServiceImpl.java

@@ -775,10 +775,11 @@ public class HDServiceImpl {
                     while (true) {
                         List<HDRecord> tempRawRecordList = dp.queryTagHisRawRecords(tagID, st, et);
                         rawRecordsList.addAll(tempRawRecordList);
-                        // 限制最大返回条数
-//                        if (rawRecordsList.size() >= MAX_RECORD_COUNT) {
-//                            return rawRecordsList.subList(0, MAX_RECORD_COUNT);
-//                        }
+                        // 限制最大返回条数,避免内存溢出
+                        if (rawRecordsList.size() >= MAX_RECORD_COUNT) {
+                            log.warn("查询数据量过大({}条),已限制为{}条", rawRecordsList.size(), MAX_RECORD_COUNT);
+                            return rawRecordsList.subList(0, MAX_RECORD_COUNT);
+                        }
                         if (tempRawRecordList.size() == 65535) { // 时间范围内记录条数超出65535,以最后一条记录的timestamp作为endTime继续查询
                             et = dateFormat.parse(rawRecordsList.get(65534).getTimeStampStr());
                         } else {
@@ -926,29 +927,74 @@ public class HDServiceImpl {
 
         List<HDRecordExport> hdRecordExportList = new ArrayList<>();
 
-        List<HDRecord> hdRecords = queryTagHisRawRecords(tagID, startTime, endTime);
-        if (ObjectUtils.isNotEmpty(hdRecords)) {
-            for (HDRecord hdRecord : hdRecords) {
-                hdRecordExportList.add(
-                        HDRecordExport.builder()
-                                .data(hdRecord.getValueStr())
-                                .sourceTime(hdRecord.getTimeStampStr())
-                                .belongTagID(hdRecord.getBelongTagID())
-                                .build());
+        try {
+            List<HDRecord> hdRecords = queryTagHisRawRecords(tagID, startTime, endTime);
+            if (ObjectUtils.isNotEmpty(hdRecords)) {
+                // 限制导出数据量,避免Excel文件过大
+                int maxExportCount = 50000; // 限制最大导出5万条记录
+                if (hdRecords.size() > maxExportCount) {
+                    log.warn("导出数据量过大({}条),已限制为{}条", hdRecords.size(), maxExportCount);
+                    hdRecords = hdRecords.subList(0, maxExportCount);
+                }
+                
+                for (HDRecord hdRecord : hdRecords) {
+                    HDRecordExport exportRecord = HDRecordExport.builder()
+                            .data(hdRecord.getValueStr())
+                            .sourceTime(hdRecord.getTimeStampStr())
+                            .belongTagID(hdRecord.getBelongTagID())
+                            .build();
+                    
+                    // 使用内置的数据验证和清理方法
+                    exportRecord.validateAndClean();
+                    hdRecordExportList.add(exportRecord);
+                }
+                
+                // 生成安全的文件名
+                String fileName = generateSafeFileName(opcPointDTO.getTagName(), opcPointDTO.getTagDesc());
+                
+                // 设置响应头
+                response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+                response.setCharacterEncoding("UTF-8");
+                response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + ".xlsx\"");
+                
+                // 导出Excel
+                ExcelUtils.exportExcel(hdRecordExportList, HDRecordExport.class, "数据记录", fileName, response);
+                
+                log.info("成功导出{}条记录到Excel文件: {}", hdRecordExportList.size(), fileName);
+            } else {
+                throw new OperateException("查询时间段内无数据");
             }
-            ExcelUtils.exportExcel(hdRecordExportList, HDRecordExport.class, opcPointDTO.getTagName(), sanitizeFileName(opcPointDTO.getTagDesc(), System.getProperty("os.name").toLowerCase().contains("windows")), response);
+        } catch (Exception e) {
+            log.error("导出Excel失败: tagID={}, startTime={}, endTime={}, error={}", 
+                     tagID, startTime, endTime, e.getMessage(), e);
+            throw new OperateException("导出失败: " + e.getMessage());
         }
-
     }
 
-    public static String sanitizeFileName(String input, boolean isWindows) {
-        if (isWindows) {
-            // 移除Windows非法字符
-            return input.replaceAll("[<>:\"/\\\\|?*]", "");
-        } else {
-            // 移除Linux非法字符(主要是斜杠)
-            return input.replaceAll("/", "");
+    /**
+     * 生成安全的文件名
+     */
+    private String generateSafeFileName(String tagName, String tagDesc) {
+        String baseName = tagName != null ? tagName : "未知标签";
+        String desc = tagDesc != null ? tagDesc : "";
+        
+        // 组合文件名
+        String fileName = baseName + "_" + desc;
+        
+        // 移除所有非法字符
+        fileName = fileName.replaceAll("[<>:\"/\\\\|?*\\x00-\\x1F]", "");
+        
+        // 限制文件名长度
+        if (fileName.length() > 100) {
+            fileName = fileName.substring(0, 100);
+        }
+        
+        // 确保文件名不为空
+        if (fileName.trim().isEmpty()) {
+            fileName = "export_data_" + System.currentTimeMillis();
         }
+        
+        return fileName.trim();
     }
 
 

+ 24 - 1
taphole-opc/src/main/java/com/sckj/opc/dto/HDRecordExport.java

@@ -35,6 +35,29 @@ public class HDRecordExport  implements Serializable {
     @ColumnWidth(25)
     private Integer belongTagID;
 
-
+    /**
+     * 数据验证和清理
+     */
+    public void validateAndClean() {
+        // 清理数据字段
+        if (this.data != null) {
+            // 移除控制字符
+            this.data = this.data.replaceAll("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]", "");
+            // 限制长度
+            if (this.data.length() > 32767) {
+                this.data = this.data.substring(0, 32767);
+            }
+        }
+        
+        // 验证时间字段
+        if (this.sourceTime == null || this.sourceTime.trim().isEmpty()) {
+            this.sourceTime = "未知时间";
+        }
+        
+        // 验证ID字段
+        if (this.belongTagID == null) {
+            this.belongTagID = 0;
+        }
+    }
 
 }

+ 11 - 0
taphole-opc/src/main/java/com/sckj/opc/service/OPCPointServiceImpl.java

@@ -15,6 +15,7 @@ import com.sckj.opc.validate.TOpcPointSearchValidate;
 import com.sckj.opc.validate.TOpcPointUpdateValidate;
 import com.sckj.opc.vo.TOpcPointDetailVo;
 import com.sckj.opc.vo.TOpcPointListedVo;
+import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
@@ -69,6 +70,16 @@ public class OPCPointServiceImpl extends ServiceImpl<OPCPointMapper, OPCPoint> {
                 "=:saveDb@save_db:str",
         });
 
+        if(searchValidate != null) {
+            if(ObjectUtils.isNotEmpty(searchValidate.getIdentifierNonNull())) {
+                if("1".equals(searchValidate.getIdentifierNonNull())) {
+                    queryWrapper.isNotNull("identifier");
+                }else if("0".equals(searchValidate.getIdentifierNonNull())) {
+                    queryWrapper.isNull("identifier");
+                }
+            }
+        }
+
         IPage<OPCPoint> iPage = tOpcPointMapper.selectPage(new Page<>(page, limit), queryWrapper);
 
         List<TOpcPointListedVo> list = new LinkedList<>();

+ 11 - 0
taphole-opc/src/main/java/com/sckj/opc/service/THdTagServiceImpl.java

@@ -14,6 +14,7 @@ import com.sckj.opc.validate.THdTagSearchValidate;
 import com.sckj.opc.validate.THdTagUpdateValidate;
 import com.sckj.opc.vo.THdTagDetailVo;
 import com.sckj.opc.vo.THdTagListedVo;
+import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
@@ -61,6 +62,16 @@ public class THdTagServiceImpl  extends ServiceImpl<THdTagMapper, THdTag> {
             "=:saveDb@save_db:str",
         });
 
+        if(searchValidate != null) {
+            if(ObjectUtils.isNotEmpty(searchValidate.getIdentifierNonNull())) {
+                if("1".equals(searchValidate.getIdentifierNonNull())) {
+                    queryWrapper.isNotNull("identifier");
+                }else if("0".equals(searchValidate.getIdentifierNonNull())) {
+                    queryWrapper.isNull("identifier");
+                }
+            }
+        }
+
         IPage<THdTag> iPage = tHdTagMapper.selectPage(new Page<>(page, limit), queryWrapper);
 
         List<THdTagListedVo> list = new LinkedList<>();

+ 2 - 0
taphole-opc/src/main/java/com/sckj/opc/validate/THdTagSearchValidate.java

@@ -51,4 +51,6 @@ public class THdTagSearchValidate implements Serializable {
     @ApiModelProperty(value = "是否入库(0-否,1-是)")
     private String saveDb;
 
+    @ApiModelProperty(value = "唯一名称非空")
+    private String identifierNonNull;
 }

+ 2 - 0
taphole-opc/src/main/java/com/sckj/opc/validate/TOpcPointSearchValidate.java

@@ -54,4 +54,6 @@ public class TOpcPointSearchValidate implements Serializable {
     @ApiModelProperty(value = "是否入库(0-否,1-是)")
     private String saveDb;
 
+    @ApiModelProperty(value = "唯一名称非空")
+    private String identifierNonNull;
 }