Jelajahi Sumber

新的报警功能开发和完善

王苗苗 4 hari lalu
induk
melakukan
393678635a

+ 506 - 0
slibra-admin/src/main/java/com/slibra/web/controller/business/HandleDataController.java

@@ -2272,14 +2272,520 @@ public class HandleDataController extends BaseController
         BigDecimal jsslSjz = normConfig.getJsslSjz();
         BigDecimal jszdSjz = normConfig.getJszdSjz();
         BigDecimal jsadSjz = normConfig.getJsadSjz();
+        BigDecimal cscodBzz = normConfig.getCscodBzz();
+        BigDecimal cscodGkz = normConfig.getCscodGkz();
+        BigDecimal jscodSjz = normConfig.getJscodSjz();
         //进水总氮超标报警
         BigDecimal jsTn = tXinyiIndustry.getJsTn();
         //进水氨氮超标报警
         BigDecimal jsNh3 = tXinyiIndustry.getJsNh3();
+        //进水Cod报警
+        BigDecimal jsCod = tXinyiIndustry.getJsCod();
+        //出水Cod报警
+        BigDecimal csCod = tXinyiIndustry.getCsCod();
+
         if(!Objects.isNull(jszdSjz) && jszdSjz.compareTo(BigDecimal.ZERO) > 0)
             handleXinYiWarningRecordJSOriginZD(jszdSjz, jsTn, BusinessEnum.WarningCategoryEnum.JS_ZD.getCode(), tXinyiIndustry, normConfig, getCwrwfhzByDetail(jsSlq, tXinyiIndustry.getJsTn(), jsslSjz, normConfig.getJszdSjz()));
         if(!Objects.isNull(jsadSjz) && jsadSjz.compareTo(BigDecimal.ZERO) > 0)
             handleXinYiWarningRecordJSOriginNh3(jsadSjz, jsNh3, BusinessEnum.WarningCategoryEnum.JS_AD.getCode(), tXinyiIndustry, normConfig, getCwrwfhzByDetail(jsSlq, tXinyiIndustry.getJsNh3(), jsslSjz, normConfig.getJsadSjz()));
+        if(!Objects.isNull(cscodBzz) && cscodBzz.compareTo(BigDecimal.ZERO) > 0 && !Objects.isNull(cscodGkz) && cscodGkz.compareTo(BigDecimal.ZERO) > 0)
+            handleXinYiWarningsCsOriginCod(cscodBzz, csCod, cscodGkz, CS_COD.getCode(), tXinyiIndustry, normConfig, getCwrwfhzByDetail(jsSlq, tXinyiIndustry.getJsCod(), jsslSjz, normConfig.getJscodSjz()));
+        if(!Objects.isNull(jscodSjz) && jscodSjz.compareTo(BigDecimal.ZERO) > 0)
+            handleXinYiWarningRecordJSOriginCod(jscodSjz, jsCod, JS_COD.getCode(), tXinyiIndustry, normConfig, getCwrwfhzByDetail(jsSlq, tXinyiIndustry.getJsCod(), jsslSjz, normConfig.getJscodSjz()));
+    }
+
+
+    /**
+     * 不同指标报警规则不一样,全部区分开来处理,此方法为:进水cod
+     * 通过输入的值 生成对应类型的报警对象(进水)- cod
+     *
+     * @param jsBzz
+     * @param currentVal
+     * @param category
+     * @param tXinyiIndustry
+     * @param normConfig
+     * @param cwrwfhz
+     * @return
+     */
+    private void handleXinYiWarningRecordJSOriginCod(BigDecimal jsBzz, BigDecimal currentVal, String category, TXinyiIndustry tXinyiIndustry, TXinyiNormConfig normConfig, BigDecimal cwrwfhz) {
+
+        Date nowDate = DateUtils.getNowDate();
+
+        List<TXinyiIndustry> tXinyiIndustries = this.xinyiIndustryMapper.selectNIndustry(INT_8);
+        if(CollectionUtils.isEmpty(tXinyiIndustries) || tXinyiIndustries.size() < INT_8){
+            log.error("处理生化报警时,获取最近的8条工业库数据失败~~~~~~~");
+            return ;
+        }
+        //拼接决策的最近8小时的值
+        String last8Str = this.getJsCodStrByList(tXinyiIndustries);
+
+
+        //最开始的工艺报警  (超标准工艺报警) 2025年04月16日15:40:23 改成只有超标准才会报警,并且具体逻辑做拆分
+        normalIndustryWarningJsCod(jsBzz, currentVal, category, tXinyiIndustry, normConfig, cwrwfhz, nowDate, tXinyiIndustries);
+
+    }
+
+
+    /**
+     * 最开始的工艺报警  (超标准工艺报警) -- 进水cod
+     * @param jsBzz
+     * @param currentVal
+     * @param category
+     * @param tXinyiIndustry
+     * @param normConfig
+     * @param cwrwfhz
+     * @param nowDate
+     * @param tXinyiIndustries
+     */
+    private void normalIndustryWarningJsCod(BigDecimal jsBzz, BigDecimal currentVal, String category, TXinyiIndustry tXinyiIndustry, TXinyiNormConfig normConfig, BigDecimal cwrwfhz, Date nowDate, List<TXinyiIndustry> tXinyiIndustries) {
+        //新的判断进水氨氮是否超标
+        TXinyiWarningRecord tXinyiWarningRecord = existsNormalJsCod(jsBzz, currentVal, category, cwrwfhz, tXinyiIndustries, normConfig);
+
+        //最近3条输出 连续升高趋势 和 新增的报警都需要
+        //当前状态正常 需要查询历史有无正在报警的数据,如果有,将报警状态改完2(系统自动关闭)
+        List<TXinyiWarningRecord> tXinyiWarningRecords = this.xinyiWarningRecordMapper.selectTXinyiWarningRecordList(TXinyiWarningRecord.builder().type(0).category(category).status(0).build());
+        if(Objects.isNull(tXinyiWarningRecord)){//数据正常,无告警信息
+            if(!CollectionUtils.isEmpty(tXinyiWarningRecords)){
+                log.info( "{}:现在恢复正常,历史报警数据为{}", category,JSON.toJSONString(tXinyiWarningRecords));
+                for (TXinyiWarningRecord xinyiWarningRecord : tXinyiWarningRecords) {
+                    closeWarning(xinyiWarningRecord);
+                }
+            }
+        }else{//有告警信息
+            if(CollectionUtils.isEmpty(tXinyiWarningRecords)){//之前没有告警记录
+                //保存到数据库中
+                //2024年7月15日11:06:16 因为只有一个告警记录,但是如果一直报警,现在报警时间取的是更新时间,兼容第一次报警处理
+                tXinyiWarningRecord.setUpdateTime(nowDate);
+                this.xinyiWarningRecordMapper.insertTXinyiWarningRecord(tXinyiWarningRecord);
+                //继续调用决策
+                this.handleDecision(tXinyiWarningRecord, tXinyiIndustry, normConfig, false, nowDate);
+            }else{
+                log.info("{}:之前已经有过告警记录了,且还是继续报警,无需重复添加报警,但是决策仍然要调用", category);
+                for (TXinyiWarningRecord xinyiWarningRecord : tXinyiWarningRecords) {//理论上只有一个的
+                    //2024年7月5日10:45:24 逻辑调整:更新一直报警的那条记录的显示值
+                    xinyiWarningRecord.setWarningVal(tXinyiWarningRecord.getWarningVal());
+//                        xinyiWarningRecord.setDesignVal(tXinyiWarningRecord.getDesignVal());
+//                        tXinyiWarningRecord.setControlVal(tXinyiWarningRecord.getControlVal());
+                    xinyiWarningRecord.setTime(tXinyiWarningRecord.getTime());
+                    xinyiWarningRecord.setUpdateTime(nowDate);
+                    xinyiWarningRecord.setUpdateBy(WARNING_DEFAULT_CREATE);
+                    //2024年7月15日11:07:33 报警的级别也要重新计算并更新
+                    xinyiWarningRecord.setLevel(tXinyiWarningRecord.getLevel());
+                    //2024年7月31日09:20:47 报警的原因(超标还是超管控也需要更新)
+                    xinyiWarningRecord.setReason(tXinyiWarningRecord.getReason());
+                    //更新数据库
+                    this.xinyiWarningRecordMapper.updateTXinyiWarningRecord(xinyiWarningRecord);
+                    //继续调用决策
+                    this.handleDecision(xinyiWarningRecord, tXinyiIndustry, normConfig, false, nowDate);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * 根据新的规则,判断进水氨氮是否超标,超标了则返回报警对象;没有超标,返回空对象 -- 进水cod
+     *
+     * @param jsBzz
+     * @param currentVal
+     * @param category
+     * @param cwrwfhz
+     * @param tXinyiIndustries
+     * @param normConfig
+     * @return
+     */
+    private TXinyiWarningRecord existsNormalJsCod(BigDecimal jsBzz, BigDecimal currentVal, String category, BigDecimal cwrwfhz, List<TXinyiIndustry> tXinyiIndustries, TXinyiNormConfig normConfig) {
+        boolean flag = false;
+        TXinyiIndustry tXinyiIndustry = tXinyiIndustries.get(INDEX_0);
+        BigDecimal jsCod0 = tXinyiIndustry.getJsCod();
+        BigDecimal jsCod1 = tXinyiIndustries.get(INDEX_1).getJsCod();
+        /*BigDecimal jsCod2 = tXinyiIndustries.get(INDEX_2).getJsCod();
+        BigDecimal jsCod3 = tXinyiIndustries.get(INDEX_3).getJsCod();*/
+        if(!Objects.isNull(jsCod0) && jsCod0.compareTo(jsBzz) > 0 && !Objects.isNull(jsCod1) && jsCod1.compareTo(jsBzz) > 0)
+            flag = true;//在线仪表,连续两个不同的进水COD数据 > 630
+        if(!Objects.isNull(jsCod0) && jsCod0.compareTo(jsBzz) > 0 && !Objects.isNull(jsCod1) && jsCod0.compareTo(jsCod1) > 0)
+            flag = true;//在线仪表,一个进水COD数据 > 630,与前一个数据呈上升趋势
+        BigDecimal jsTn = tXinyiIndustry.getJsTn();
+        BigDecimal jsNh3 = tXinyiIndustry.getJsNh3();
+        BigDecimal jsTp = tXinyiIndustry.getJsTp();
+        if(!Objects.isNull(jsCod0) && jsCod0.compareTo(jsBzz) > 0 && (!Objects.isNull(jsTn) && jsTn.compareTo(BigDecimal.valueOf(65)) > 0
+                || !Objects.isNull(jsNh3) && jsNh3.compareTo(BigDecimal.valueOf(58)) > 0 || !Objects.isNull(jsTp) && jsTp.compareTo(BigDecimal.valueOf(7.1)) > 0))
+            flag = true;
+        if(!flag)
+            return null;
+        //存在符合的报警情况,生成报警对象
+        TXinyiWarningRecord tXinyiWarningRecord = new TXinyiWarningRecord();
+        /*String category = BusinessEnum.WarningCategoryEnum.CS_AD.getCode();*/
+        tXinyiWarningRecord.setStatus(0);
+        tXinyiWarningRecord.setType(0);
+        tXinyiWarningRecord.setCategory(category);
+        tXinyiWarningRecord.setTime(DateUtils.getNowDate());
+        tXinyiWarningRecord.setWarningVal(currentVal);
+        tXinyiWarningRecord.setDesignVal(jsBzz);
+//        tXinyiWarningRecord.setControlVal(csGkz);
+        tXinyiWarningRecord.setCreateBy(WARNING_DEFAULT_CREATE);
+        tXinyiWarningRecord.setCreateTime(DateUtils.getNowDate());
+        tXinyiWarningRecord.setRemark(ZERO_SZ_WARNING.getCode());
+        //2025年02月10日14:45:08 下面是新增加的字段
+        tXinyiWarningRecord.setWaterType(BusinessEnum.WaterTypeEnum.JS.getCode());
+        //超污染物限制:计算公式为:当前氨氮/氨氮设计值 或者 当前氨氮/氨氮管控值(智能工单使用)  这里是出水的 【需要根据超标还是超管控,具体计算】
+        //超污染物负荷值:计算公式为:当前水量与氨氮乘积  /  设计水量与设计进水氨氮的乘积(智能工单使用)
+        tXinyiWarningRecord.setCwrwfhz(cwrwfhz);//2025年02月14日10:48:32 具体的值由上游传过来
+        tXinyiWarningRecord.setReason(category + CHAOBIAO_WARNING);
+        tXinyiWarningRecord.setLevel(WARNING_LEVEL_ONE);
+        tXinyiWarningRecord.setSymbol(BusinessEnum.WarningSymbolEnum.CBZZ.getCode());
+        tXinyiWarningRecord.setCwrwxz(getCwrwxzByDetail(currentVal, normConfig, category, true));//根据当前值和类型以及是否超标处理
+
+        return tXinyiWarningRecord;
+    }
+
+
+    private String getJsCodStrByList(List<TXinyiIndustry> tXinyiIndustries) {
+        int size = tXinyiIndustries.size();
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < size; i++) {
+            TXinyiIndustry tXinyiIndustry = tXinyiIndustries.get(i);
+            //2025年05月08日14:07:50 bug修复:传过来几条数据,都需要拼接
+            if(i < size - 1)
+                sb.append(DecimalUtils.getAbsAndScale(tXinyiIndustry.getJsCod(), INT_2)).append("mg/L、");
+            else
+                sb.append(DecimalUtils.getAbsAndScale(tXinyiIndustry.getJsCod(), INT_2)).append("mg/L。");
+        }
+        return sb.toString();
+    }
+
+
+
+    /**
+     * 通过输入的值 生成对应类型的报警对象(出水)- 新的 按照不同的类型区分了,因为每个报警都不一样了
+     *
+     * @param csBzz
+     * @param currentVal
+     * @param csGkz
+     * @param category
+     * @param tXinyiIndustry
+     * @param normConfig
+     * @param cwrwfhz
+     * 2025年05月14日15:15:48 cod报警比较特殊:没有异常升高、异常偏低、高低值报警;并且把断点和连续不变合成了一个叫 【设备故障的报警】
+     * @return
+     */
+    private void handleXinYiWarningsCsOriginCod(BigDecimal csBzz, BigDecimal currentVal, BigDecimal csGkz, String category, TXinyiIndustry tXinyiIndustry, TXinyiNormConfig normConfig, BigDecimal cwrwfhz) {
+
+        Date nowDate = DateUtils.getNowDate();
+        List<TXinyiIndustry> tXinyiIndustries = this.xinyiIndustryMapper.selectNIndustry(INT_4);
+        if(CollectionUtils.isEmpty(tXinyiIndustries) || tXinyiIndustries.size() < INT_4){
+            log.error("处理生化报警时,获取最近的4条工业库数据失败~~~~~~~");
+            return ;
+        }
+
+//        //拼接决策的最近4小时的值
+//        String last4Str = this.getJsNh3StrByList(tXinyiIndustries);
+//
+//        //报警设备故障
+//        if (existsCsCodDeviceErr(csBzz, currentVal, category, tXinyiIndustry, normConfig, cwrwfhz, tXinyiIndustries, nowDate, last4Str, csGkz))
+//            return;
+
+        //工艺报警
+        //最开始的工艺报警  (超标准工艺报警)
+        normalIndustryWarningCsCod(csBzz, currentVal, category, tXinyiIndustry, normConfig, cwrwfhz, nowDate, tXinyiIndustries, csGkz);
+    }
+
+
+
+    /**
+     * 最开始的工艺报警  (超标准工艺报警) -- 出水cod
+     * @param csBzz
+     * @param currentVal
+     * @param category
+     * @param tXinyiIndustry
+     * @param normConfig
+     * @param cwrwfhz
+     * @param nowDate
+     * @param tXinyiIndustries
+     */
+    private void normalIndustryWarningCsCod(BigDecimal csBzz, BigDecimal currentVal, String category, TXinyiIndustry tXinyiIndustry, TXinyiNormConfig normConfig, BigDecimal cwrwfhz, Date nowDate, List<TXinyiIndustry> tXinyiIndustries, BigDecimal csGkz) {
+        //新的判断进水氨氮是否超标
+        TXinyiWarningRecord tXinyiWarningRecord = existsNormalCsCod(csBzz, currentVal, category, cwrwfhz, tXinyiIndustries, normConfig, csGkz);
+
+        //最近3条输出 连续升高趋势 和 新增的报警都需要
+        //当前状态正常 需要查询历史有无正在报警的数据,如果有,将报警状态改完2(系统自动关闭)
+        List<TXinyiWarningRecord> tXinyiWarningRecords = this.xinyiWarningRecordMapper.selectTXinyiWarningRecordList(TXinyiWarningRecord.builder().type(0).category(category).status(0).build());
+        if(Objects.isNull(tXinyiWarningRecord)){//数据正常,无告警信息
+            if(!CollectionUtils.isEmpty(tXinyiWarningRecords)){
+                log.info( "{}:现在恢复正常,历史报警数据为{}", category,JSON.toJSONString(tXinyiWarningRecords));
+                for (TXinyiWarningRecord xinyiWarningRecord : tXinyiWarningRecords) {
+                    closeWarning(xinyiWarningRecord);
+                }
+            }
+        }else{//有告警信息
+            if(CollectionUtils.isEmpty(tXinyiWarningRecords)){//之前没有告警记录
+                //保存到数据库中
+                //2024年7月15日11:06:16 因为只有一个告警记录,但是如果一直报警,现在报警时间取的是更新时间,兼容第一次报警处理
+                tXinyiWarningRecord.setUpdateTime(nowDate);
+                this.xinyiWarningRecordMapper.insertTXinyiWarningRecord(tXinyiWarningRecord);
+                //继续调用决策
+                this.handleDecision(tXinyiWarningRecord, tXinyiIndustry, normConfig, false, nowDate);
+            }else{
+                log.info("{}:之前已经有过告警记录了,且还是继续报警,无需重复添加报警,但是决策仍然要调用", category);
+                for (TXinyiWarningRecord xinyiWarningRecord : tXinyiWarningRecords) {//理论上只有一个的
+                    //2024年7月5日10:45:24 逻辑调整:更新一直报警的那条记录的显示值
+                    xinyiWarningRecord.setWarningVal(tXinyiWarningRecord.getWarningVal());
+//                        xinyiWarningRecord.setDesignVal(tXinyiWarningRecord.getDesignVal());
+//                        tXinyiWarningRecord.setControlVal(tXinyiWarningRecord.getControlVal());
+                    xinyiWarningRecord.setTime(tXinyiWarningRecord.getTime());
+                    xinyiWarningRecord.setUpdateTime(nowDate);
+                    xinyiWarningRecord.setUpdateBy(WARNING_DEFAULT_CREATE);
+                    //2024年7月15日11:07:33 报警的级别也要重新计算并更新
+                    xinyiWarningRecord.setLevel(tXinyiWarningRecord.getLevel());
+                    //2024年7月31日09:20:47 报警的原因(超标还是超管控也需要更新)
+                    xinyiWarningRecord.setReason(tXinyiWarningRecord.getReason());
+                    //更新数据库
+                    this.xinyiWarningRecordMapper.updateTXinyiWarningRecord(xinyiWarningRecord);
+                    //继续调用决策
+                    this.handleDecision(xinyiWarningRecord, tXinyiIndustry, normConfig, false, nowDate);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * 根据新的规则,判断出水cod是否超标,超标了则返回报警对象;没有超标,返回空对象 -- 出水cod
+     *
+     * @param csBzz
+     * @param currentVal
+     * @param category
+     * @param cwrwfhz
+     * @param tXinyiIndustries
+     * @param normConfig
+     * @return
+     */
+    private TXinyiWarningRecord existsNormalCsCod(BigDecimal csBzz, BigDecimal currentVal, String category, BigDecimal cwrwfhz, List<TXinyiIndustry> tXinyiIndustries, TXinyiNormConfig normConfig, BigDecimal csGkz) {
+        boolean flag = false;
+        TXinyiIndustry tXinyiIndustry = tXinyiIndustries.get(INDEX_0);
+        BigDecimal csCod0 = tXinyiIndustry.getCsCod();
+        BigDecimal csCod1 = tXinyiIndustries.get(INDEX_1).getCsCod();
+        BigDecimal csCod2 = tXinyiIndustries.get(INDEX_2).getCsCod();
+        BigDecimal csCod3 = tXinyiIndustries.get(INDEX_3).getCsCod();
+        if(!Objects.isNull(csCod0) && !Objects.isNull(csCod1) && !Objects.isNull(csCod2) && !Objects.isNull(csCod3)){
+            //出水COD在线仪表 > 40 and 连续4小时
+            if(csCod0.compareTo(csBzz) > 0 && csCod1.compareTo(csBzz) > 0 && csCod2.compareTo(csBzz) > 0 && csCod3.compareTo(csBzz) > 0)
+                flag = true;
+            //出水COD在线仪表 > 40 and 连续三小时数据呈现大于等于上一小时的情况
+            if(csCod0.compareTo(csBzz) > 0 && csCod0.compareTo(csCod1) >= 0 && csCod1.compareTo(csCod2) >= 0 && csCod2.compareTo(csCod3) >= 0)
+                flag = true;
+        }
+        //出水COD在线仪表 > 40 and 出水氨氮连续检测数据 > 4
+        //查询同时刻的化验数据,计算出水氨氮
+        List<TXinyiRobot> tXinyiRobots = this.xinyiRobotMapper.selectTXinyiRobotList(TXinyiRobot.builder().testHour(tXinyiIndustry.getTestHour()).build());
+        if(!CollectionUtils.isEmpty(tXinyiRobots)){
+            TXinyiRobot xinyiRobot = tXinyiRobots.get(0);
+            BigDecimal no3Hlj1JqrTemp = xinyiRobot.getNo3Hlj1Jqr();
+            //#2好氧硝酸盐
+            BigDecimal no3Hlj2JqrTemp = xinyiRobot.getNo3Hlj2Jqr();
+            //1#缺氧出-硝酸盐
+            BigDecimal no3Qyc1JqrTemp = xinyiRobot.getNo3Qyc1Jqr();
+            BigDecimal nh31JqrTemp = xinyiRobot.getNh31Jqr();
+            //2#缺氧出-硝酸盐
+            BigDecimal no3Qyc2JqrTemp = xinyiRobot.getNo3Qyc2Jqr();
+            BigDecimal nh32JqrTemp = xinyiRobot.getNh32Jqr();
+            if (Objects.isNull(no3Qyc1JqrTemp))
+                no3Qyc1JqrTemp = BigDecimal.ZERO;
+            if (Objects.isNull(nh31JqrTemp))
+                nh31JqrTemp = BigDecimal.ZERO;
+            if (Objects.isNull(no3Hlj1JqrTemp))
+                no3Hlj1JqrTemp = BigDecimal.ZERO;
+            BigDecimal anDan1 = no3Qyc1JqrTemp.add(nh31JqrTemp).subtract(no3Hlj1JqrTemp);
+
+            //判断 增加容错
+            if (Objects.isNull(no3Qyc2JqrTemp))
+                no3Qyc2JqrTemp = BigDecimal.ZERO;
+            if (Objects.isNull(nh32JqrTemp))
+                nh32JqrTemp = BigDecimal.ZERO;
+            if (Objects.isNull(no3Hlj2JqrTemp))
+                no3Hlj2JqrTemp = BigDecimal.ZERO;
+            BigDecimal anDan2 = no3Qyc2JqrTemp.add(nh32JqrTemp).subtract(no3Hlj2JqrTemp);
+            BigDecimal divide = anDan1.add(anDan2).divide(DECIMAL_2, INT_2, RoundingMode.HALF_UP);
+            //出水COD在线仪表 > 40 and 出水氨氮连续检测数据 > 4
+            if(!Objects.isNull(csCod0) && csCod0.compareTo(csBzz) > 0 && divide.compareTo(BigDecimal.valueOf(4)) > 0)
+                flag = true;
+        }
+
+
+        if(!flag)
+            return null;
+        //存在符合的报警情况,生成报警对象
+        TXinyiWarningRecord tXinyiWarningRecord = new TXinyiWarningRecord();
+        tXinyiWarningRecord.setStatus(0);
+        tXinyiWarningRecord.setType(0);
+        tXinyiWarningRecord.setCategory(category);
+        tXinyiWarningRecord.setTime(DateUtils.getNowDate());
+        tXinyiWarningRecord.setWarningVal(currentVal);
+        tXinyiWarningRecord.setDesignVal(csBzz);
+        tXinyiWarningRecord.setControlVal(csGkz);
+        tXinyiWarningRecord.setCreateBy(WARNING_DEFAULT_CREATE);
+        tXinyiWarningRecord.setCreateTime(DateUtils.getNowDate());
+        tXinyiWarningRecord.setRemark(ZERO_SZ_WARNING.getCode());
+        //2025年02月10日14:45:08 下面是新增加的字段
+        tXinyiWarningRecord.setWaterType(BusinessEnum.WaterTypeEnum.CS.getCode());
+        //超污染物限制:计算公式为:当前氨氮/氨氮设计值 或者 当前氨氮/氨氮管控值(智能工单使用)  这里是出水的 【需要根据超标还是超管控,具体计算】
+        //超污染物负荷值:计算公式为:当前水量与氨氮乘积  /  设计水量与设计进水氨氮的乘积(智能工单使用)
+        tXinyiWarningRecord.setCwrwfhz(cwrwfhz);//2025年02月14日10:48:32 具体的值由上游传过来
+        tXinyiWarningRecord.setReason(category + CHAOBIAO_WARNING);
+        tXinyiWarningRecord.setLevel(WARNING_LEVEL_ONE);
+        tXinyiWarningRecord.setSymbol(BusinessEnum.WarningSymbolEnum.CBZZ.getCode());
+        tXinyiWarningRecord.setCwrwxz(getCwrwxzByDetail(currentVal, normConfig, category, true));//根据当前值和类型以及是否超标处理
+
+        return tXinyiWarningRecord;
+    }
+
+
+    /**
+     * 查看出水cod是否存在 设备故障 的报警判断,如果存在处理数据,并报警。
+     *
+     * @param csBzz
+     * @param currentVal
+     * @param category
+     * @param tXinyiIndustry
+     * @param normConfig
+     * @param cwrwfhz
+     * @param tXinyiIndustries
+     * @param nowDate
+     * @param last4Str
+     * @param csGkz
+     * @return
+     */
+    private boolean existsCsCodDeviceErr(BigDecimal csBzz, BigDecimal currentVal, String category, TXinyiIndustry tXinyiIndustry, TXinyiNormConfig normConfig, BigDecimal cwrwfhz, List<TXinyiIndustry> tXinyiIndustries, Date nowDate, String last4Str, BigDecimal csGkz) {
+        if(!CollectionUtils.isEmpty(tXinyiIndustries) && tXinyiIndustries.size() == INT_4){
+            //查询同类型的历史报警
+            TXinyiWarningRecord csCodDeviceErrWarning = TXinyiWarningRecord.builder().type(0).category(category).symbol(BusinessEnum.WarningSymbolEnum.DEVICE_ERR_CS_COD.getCode()).status(0).build();
+            List<TXinyiWarningRecord> csCodDeviceErrList = this.xinyiWarningRecordMapper.selectTXinyiWarningRecordList(csCodDeviceErrWarning);
+            //2025年02月21日14:33:37 这里要改成当前值和上个小时比较  上个小时和上上个小时比较
+            if(existsCsCodDeviceErr(tXinyiIndustries)){//这里不能只返回一个布尔类型的结果,因为还要获取百分比的值
+                //关闭同类型的其他报警
+                closeOtherWarningsByCategory(category, BusinessEnum.WarningSymbolEnum.DEVICE_ERR_CS_COD.getCode());
+                //触发报警 并且模拟大模型返回决策问答数据
+                if(CollectionUtils.isEmpty(csCodDeviceErrList)){
+                    //插入该类型报警
+                    csCodDeviceErrWarning.setTime(nowDate);
+                    csCodDeviceErrWarning.setReason(category + BusinessEnum.WarningSymbolEnum.DEVICE_ERR_CS_COD.getMsg());
+                    csCodDeviceErrWarning.setWaterType(BusinessEnum.WaterTypeEnum.CS.getCode());
+                    csCodDeviceErrWarning.setSymbol(BusinessEnum.WarningSymbolEnum.DEVICE_ERR_CS_COD.getCode());
+                    csCodDeviceErrWarning.setCreateBy(WARNING_DEFAULT_CREATE);
+                    csCodDeviceErrWarning.setCreateTime(nowDate);
+                    csCodDeviceErrWarning.setWarningVal(currentVal);
+                    csCodDeviceErrWarning.setDesignVal(csBzz);
+                    csCodDeviceErrWarning.setControlVal(csGkz);
+                    csCodDeviceErrWarning.setRemark(ZERO_SZ_WARNING.getCode());
+                    csCodDeviceErrWarning.setCwrwfhz(cwrwfhz);
+                    csCodDeviceErrWarning.setCwrwxz(getCwrwxzByDetail(currentVal, normConfig, category, true));//根据当前值和类型以及是否超标处理
+                    this.xinyiWarningRecordMapper.insertTXinyiWarningRecord(csCodDeviceErrWarning);
+                    //同时处理决策 不用调用大模型,本地处理问答
+                    addChatRecordByCsCodDeviceErr(csCodDeviceErrWarning, tXinyiIndustry, normConfig, category, last4Str);
+                }else{
+                    //2025年04月16日15:56:47 这种的继续报警,所以决策还需要再次调用一次
+                    //2025年05月08日13:34:23bug修改 这里不能用new的对象 要获取历史报警的值
+//                    addChatRecordByGDZ(warningRecordGDZ, tXinyiIndustry, normConfig, category, exceedVal, resultMap.get(LASTVAL), last8Str);
+                    addChatRecordByCsCodDeviceErr(csCodDeviceErrList.get(0), tXinyiIndustry, normConfig, category, last4Str);
+                }
+                //后续的报警不再进行
+                return true;
+            }else{//不存在 查看历史是否有报警,有的话关闭
+                if(!CollectionUtils.isEmpty(csCodDeviceErrList)){
+                    closeWarning(csCodDeviceErrList.get(0));
+                }
+            }
+        }
+        return false;
+    }
+
+
+
+    /**
+     *
+     * 出水cod - 设备故障 本地决策处理
+     * @param warningRecord
+     * @param tXinyiIndustry
+     * @param normConfig
+     * @param category
+     * @param last4Str
+     */
+    private void addChatRecordByCsCodDeviceErr(TXinyiWarningRecord warningRecord, TXinyiIndustry tXinyiIndustry, TXinyiNormConfig normConfig, String category,String last4Str) {
+        ChatReq chatReq = new ChatReq();
+        //保存聊天记录
+        //将问答更新到数据库中
+        chatReq.setSessionId(IdUtils.simpleUUID());
+        chatReq.setType(1);//0问答 1决策 2本地 3仿真预测
+        chatReq.setModule(3);
+            /*String userId = SecurityUtils.getUserId().toString();
+            String username = SecurityUtils.getUsername();*/
+        chatReq.setUserId(WARNING_DEFAULT_CREATE);
+        String showVal = this.buildShowValue(warningRecord, tXinyiIndustry, normConfig, DateUtils.getNowDate());
+        chatReq.setShowVal(showVal);//前端展示的数据和提问的数据不一致
+        chatReq.setQuestion(BusinessEnum.WarningSymbolEnum.DEVICE_ERR_CS_COD.getMsg());//本地问题
+//        chatReq.setAnswer(category + YCSG_ANSWER_ONE + exceedVal.multiply(BigDecimal_100) + "%" + YCSG_ANSWER_TWO + warningRecord.getWarningVal() + YCSG_ANSWER_THREE);
+        chatReq.setAnswer(CS_COD_DEVICE_ERR_ANSWER_REPLACE.replaceAll("@@@0", category).replaceAll("@@@1", last4Str));//只替换最近8小时的值 和 类型
+        chatReq.setWarningId(String.valueOf(warningRecord.getId()));
+        chatReq.setCounts(1);//问答次数
+
+        chatReq.setCreateBy(WARNING_DEFAULT_CREATE);
+        chatReq.setCreateTime(DateUtils.getNowDate());
+        this.xinyiChatRecordMapper.insertTXinyiChatRecord(chatReq);
+    }
+
+
+    /**
+     * 将此化验类型的其他的报警全部关闭
+     * @param category
+     */
+    private void closeOtherWarningsByCategory(String category, Integer symbol) {
+        List<TXinyiWarningRecord> tXinyiWarningRecords = this.xinyiWarningRecordMapper.getOtherWarningsByCategory(category, symbol);
+        if(!CollectionUtils.isEmpty(tXinyiWarningRecords)){
+            for (TXinyiWarningRecord tXinyiWarningRecord : tXinyiWarningRecords) {
+                this.closeWarning(tXinyiWarningRecord);
+            }
+        }
+    }
+
+
+    private String getJsNh3StrByList(List<TXinyiIndustry> tXinyiIndustries) {
+//        return StringUtil.join(tXinyiIndustries.stream().map(TXinyiIndustry::getJsNh3).collect(Collectors.toList()) , "mg/L、");
+        int size = tXinyiIndustries.size();
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < size; i++) {
+            TXinyiIndustry tXinyiIndustry = tXinyiIndustries.get(i);
+            if(i < size - 1)
+                sb.append(DecimalUtils.getAbsAndScale(tXinyiIndustry.getJsNh3(), INT_2)).append("mg/L、");
+            else
+                sb.append(DecimalUtils.getAbsAndScale(tXinyiIndustry.getJsNh3(), INT_2)).append("mg/L。");
+        }
+        return sb.toString();
+    }
+
+
+    /**
+     * 出水cod是否存在设备故障报警
+     * @param industryList
+     * @return
+     */
+    private boolean existsCsCodDeviceErr(List<TXinyiIndustry> industryList) {
+        boolean result = false;
+        BigDecimal csCod0 = industryList.get(0).getCsCod();
+        BigDecimal csCod1 = industryList.get(1).getCsCod();
+        BigDecimal csCod2 = industryList.get(2).getCsCod();
+        BigDecimal csCod3 = industryList.get(3).getCsCod();
+        //全部为空
+        if(Objects.isNull(csCod0) && Objects.isNull(csCod1) && Objects.isNull(csCod2) && Objects.isNull(csCod3))
+            return true;
+        //数据为0、 数据相同 and 出水COD>40
+        if(!Objects.isNull(csCod0) && !Objects.isNull(csCod1) && !Objects.isNull(csCod2) && !Objects.isNull(csCod3)){
+            if(BigDecimal.ZERO.compareTo(csCod0) == 0 && BigDecimal.ZERO.compareTo(csCod1) == 0 && BigDecimal.ZERO.compareTo(csCod2) == 0 && BigDecimal.ZERO.compareTo(csCod3) == 0)
+                return true;
+            if(csCod0.compareTo(BigDecimal.valueOf(40)) > 0 && csCod0.compareTo(csCod1) == 0 && csCod0.compareTo(csCod2) == 0 && csCod0.compareTo(csCod3) == 0)
+                return true;
+        }
+
+        return result;
     }
 
 

+ 11 - 0
slibra-common/src/main/java/com/slibra/common/constant/MyConstants.java

@@ -575,6 +575,17 @@ public class MyConstants {
             "建议检查仪表运行状态是否存在设备故障等问题。问题解决后,建议继续观察,以确保问题不再复发。\n" +
             "如果长时间持续大于6小时,需完成主管局备案并监测平台标记,必要时采取第三方人工监测,监测周期间隔不大于6小时,数据报送每天不少于4次,监测技术要求可参考HJ91.1执行。";
 
+
+    //出水cod设备故障报警
+    public static final String CS_COD_DEVICE_ERR_ANSWER_REPLACE = "## 解决方案 ##\n" +
+            "## 一、数据表现 ##\n" +
+            "**@@@0**:@@@1\n" +
+            "**@@@0变化趋势**:数据异常\n" +
+            "## 二、原因分析 ##\n" +
+            "出水COD发生数据异常问题,出水COD在线仪表设备可能存在问题\n" +
+            "## 三、解决方案##\n" +
+            "建议检查出水COD在线仪表设备是否存在问题,检查输出模块是否工作正常,确保数据的采集和传输。并可人工采样确认,必要时通知厂家排查设备问题。";
+
     public static void main(String[] args) {
         System.out.println(DecimalUtils.getAbsAndScale(new BigDecimal("2.211"), MyConstants.INT_0));
         System.out.println(DecimalUtils.getAbsAndScaleStr("2.211", MyConstants.INT_0));

+ 1 - 0
slibra-common/src/main/java/com/slibra/common/enums/BusinessEnum.java

@@ -455,6 +455,7 @@ public class BusinessEnum {
         INDUSTRY_SYNC_ERROR(10, "在线仪表数据同步失败"),
         ROBOT_SYNC_ERROR(11, "连续检测数据同步失败"),
         SJYC_GDZ(12, "数据异常"),
+        DEVICE_ERR_CS_COD(13, "设备故障"),
         ;
 
         private final Integer code;

File diff ditekan karena terlalu besar
+ 661 - 178
slibra-quartz/src/main/java/com/slibra/quartz/task/AsyncTask.java


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini