瀏覽代碼

告警管理 初版提交

tl 6 月之前
父節點
當前提交
d749977ecd
共有 21 個文件被更改,包括 692 次插入146 次删除
  1. 48 0
      cpp-admin/src/main/java/com/cpp/web/controller/alarm/AbnormalAlarmController.java
  2. 9 2
      cpp-admin/src/main/java/com/cpp/web/domain/AbnormalAlarm.java
  3. 1 1
      cpp-admin/src/main/java/com/cpp/web/domain/BaseCppEntity.java
  4. 52 0
      cpp-admin/src/main/java/com/cpp/web/job/ScheduledJob.java
  5. 8 0
      cpp-admin/src/main/java/com/cpp/web/mapper/AbnormalAlarmMapper.java
  6. 0 15
      cpp-admin/src/main/java/com/cpp/web/service/AbnormalAlarmService.java
  7. 9 17
      cpp-admin/src/main/java/com/cpp/web/service/accuracy/CalcAccuracy.java
  8. 23 0
      cpp-admin/src/main/java/com/cpp/web/service/alarm/AbnormalAlarmService.java
  9. 104 0
      cpp-admin/src/main/java/com/cpp/web/service/alarm/AlarmLog.java
  10. 87 0
      cpp-admin/src/main/java/com/cpp/web/service/alarm/AppenderFactory.java
  11. 57 0
      cpp-admin/src/main/java/com/cpp/web/service/alarm/impl/AbnormalAlarmServiceImpl.java
  12. 4 11
      cpp-admin/src/main/java/com/cpp/web/service/cloud/CloudFileParsing.java
  13. 8 18
      cpp-admin/src/main/java/com/cpp/web/service/datafactory/SftpFileParsing.java
  14. 8 11
      cpp-admin/src/main/java/com/cpp/web/service/datafactory/impl/ParsingStatusServiceImpl.java
  15. 0 23
      cpp-admin/src/main/java/com/cpp/web/service/impl/AbnormalAlarmServiceImpl.java
  16. 29 0
      cpp-admin/src/main/java/com/cpp/web/utils/LogUtil.java
  17. 0 46
      cpp-admin/src/main/java/com/cpp/web/utils/MessageUtils.java
  18. 2 2
      cpp-admin/src/main/java/com/cpp/web/utils/NumberUtil.java
  19. 1 0
      cpp-ui/src/assets/icons/svg/alarm1.svg
  20. 0 0
      cpp-ui/src/assets/icons/svg/alarm2.svg
  21. 242 0
      cpp-ui/src/views/abnormalAlarm/index.vue

+ 48 - 0
cpp-admin/src/main/java/com/cpp/web/controller/alarm/AbnormalAlarmController.java

@@ -0,0 +1,48 @@
+package com.cpp.web.controller.alarm;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cpp.common.core.domain.R;
+
+import com.cpp.web.domain.AbnormalAlarm;
+import com.cpp.web.domain.enums.AlarmEnum;
+import com.cpp.web.domain.station.ElectricField;
+import com.cpp.web.service.alarm.AbnormalAlarmService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+
+/**
+ * 异常告警
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("abnormalAlarm")
+public class AbnormalAlarmController {
+    private final AbnormalAlarmService abnormalAlarmService;
+
+    @GetMapping("/getByTimeBetweenAndAlarmTypeAndStationCode")
+    public R getByTimeBetweenAndAlarmTypeAndStationCode(Long currentPage, Long pageSize, Long startTime, Long endTime, AlarmEnum alarmType, String stationCode) {
+        Page page = new Page(currentPage, pageSize);
+        page.setMaxLimit((long) -1);
+        return R.ok(abnormalAlarmService.page(page, abnormalAlarmService.findByTimeBetweenAndAlarmTypeAndStationCode(new Date(startTime), new Date(endTime), alarmType, stationCode)));
+    }
+
+
+    @GetMapping("/acknowledgeByStationCode")
+    public R acknowledgeByStationCode(String stationCode) {
+        return R.ok(abnormalAlarmService.updateAllStatus1(stationCode));
+    }
+
+    @PostMapping("/save")
+    public R save(@RequestBody AbnormalAlarm abnormalAlarm) {
+        return R.ok(abnormalAlarmService.saveOrUpdate(abnormalAlarm));
+    }
+
+
+    @GetMapping("/getCountByStatusAndStationCode")
+    public R getCountByStatus(Integer status,String stationCode) {
+        return R.ok(abnormalAlarmService.countByStatusAndStationCode(status,stationCode));
+    }
+
+}

+ 9 - 2
cpp-admin/src/main/java/com/cpp/web/domain/AbnormalAlarm.java

@@ -3,10 +3,13 @@ package com.cpp.web.domain;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.cpp.web.domain.enums.AlarmEnum;
 import com.cpp.web.domain.enums.DataSourcesEnum;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.annotations.ApiModel;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
+import java.util.Date;
+
 /**
  * 异常告警实体(包括站端云端中心侧的关键信息)
  *
@@ -41,6 +44,11 @@ public class AbnormalAlarm extends BaseCppEntity {
      */
     private Integer status = 0;
 
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
+    private Date startTime = new Date();
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
+    private Date endTime;
 
     public AbnormalAlarm(DataSourcesEnum alarmSource, AlarmEnum alarmType, String msg, String stationCode) {
         this.alarmSource = alarmSource;
@@ -49,6 +57,5 @@ public class AbnormalAlarm extends BaseCppEntity {
         super.setStationCode(stationCode);
     }
 
-    public AbnormalAlarm() {
-    }
+    public AbnormalAlarm() {}
 }

+ 1 - 1
cpp-admin/src/main/java/com/cpp/web/domain/BaseCppEntity.java

@@ -39,7 +39,7 @@ public class BaseCppEntity implements Serializable {
     /** 创建时间 */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @TableField(value = "create_time" , fill = FieldFill.INSERT)
-    private Date createTime;
+    private Date createTime = new Date();
 
 //    /** 更新者 */
 //    @TableField(value = "update_by" , fill = FieldFill.INSERT_UPDATE)

+ 52 - 0
cpp-admin/src/main/java/com/cpp/web/job/ScheduledJob.java

@@ -0,0 +1,52 @@
+package com.cpp.web.job;
+
+import com.cpp.web.service.accuracy.CalcAccuracy;
+import com.cpp.web.service.alarm.AlarmLog;
+import com.cpp.web.service.datafactory.SftpFileParsing;
+import lombok.RequiredArgsConstructor;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/**
+ * 定时任务管理类
+ */
+@RequiredArgsConstructor
+@Component
+public class ScheduledJob implements ApplicationRunner {
+    private final SftpFileParsing sftpFileParsing;
+
+    private final CalcAccuracy calcAccuracy;
+
+    /**
+     * 解析文件定时任务
+     */
+//    @Scheduled(fixedRate = 60000L)
+    public void parsingFile() {
+        sftpFileParsing.parsingFile();
+    }
+
+
+    /**
+     * 计算准确率定时任务
+     */
+//    @Scheduled(cron = "0 17 9 * * *")
+    public void calculate() {
+        calcAccuracy.calculate();
+    }
+
+    /**
+     * 告警消纳定时任务
+     */
+//    @Scheduled(fixedRate = 60000L)
+    public void e() {
+        AlarmLog.getInstance().eliminate();
+    }
+
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        AlarmLog.getInstance().initMap();
+    }
+}

+ 8 - 0
cpp-admin/src/main/java/com/cpp/web/mapper/AbnormalAlarmMapper.java

@@ -4,6 +4,9 @@ package com.cpp.web.mapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.cpp.web.domain.AbnormalAlarm;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
 
 /**
  * 告警信息 mapper
@@ -14,4 +17,9 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface AbnormalAlarmMapper extends BaseMapper<AbnormalAlarm> {
 
+    @Update("update cpp_abnormal_alarm set status = 1 where status = 0 and station_code = '${stationCode}'")
+    Boolean updateAllStatus1(@Param("stationCode") String stationCode);
+
+    @Select("select count(*) from cpp_abnormal_alarm where status = ${status} and station_code = '${stationCode}'")
+    int countByStatusAndStationCode(@Param("status") Integer status, @Param("stationCode") String stationCode);
 }

+ 0 - 15
cpp-admin/src/main/java/com/cpp/web/service/AbnormalAlarmService.java

@@ -1,15 +0,0 @@
-package com.cpp.web.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.cpp.web.domain.AbnormalAlarm;
-
-/**
- * 告警信息业务层接口
- *
- * @author tl
- * @date 2022-05-11 09:51:21
- */
-public interface AbnormalAlarmService extends IService<AbnormalAlarm> {
-
-
-}

+ 9 - 17
cpp-admin/src/main/java/com/cpp/web/service/accuracy/CalcAccuracy.java

@@ -1,29 +1,15 @@
 package com.cpp.web.service.accuracy;
 
-import com.cpp.common.utils.spring.SpringUtils;
 import com.cpp.system.service.ISysConfigService;
 import com.cpp.web.domain.accuracy.AccuracyPassRate;
 import com.cpp.web.domain.station.ElectricField;
 import com.cpp.web.domain.station.PowerStationStatusData;
-import com.cpp.web.domain.station.enums.ElectricFieldTypeEnum;
-import com.cpp.web.service.cloud.ForecastPowerShortTermCloudService;
-import com.cpp.web.service.cloud.ForecastPowerUltraShortTermCloudService;
 import com.cpp.web.service.station.*;
 import com.cpp.web.utils.DateTimeUtil;
-import com.syjy.calculate.entity.CalculateRequest;
-import com.syjy.calculate.entity.CalculateResult;
-import com.syjy.calculate.entity.CalculationFormula;
-import com.syjy.calculate.entity.CalculationInfo;
-import com.syjy.calculate.repository.CalculationFormulaRepository;
-import com.syjy.calculate.service.AccuracyPassRateCalculateService;
 import lombok.RequiredArgsConstructor;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
-import java.math.BigDecimal;
 import java.util.*;
-import java.util.stream.Collectors;
-
 
 @Service
 @RequiredArgsConstructor
@@ -36,10 +22,8 @@ public class CalcAccuracy {
     private final List<CalculateInterface> calculateInterfaces;
 
     /**
-     * 计算方法
+     * 执行准确率计算
      */
-//    @Scheduled(cron = "0 51 1 * * *")
-//    @Scheduled(fixedRate = 60000L)
     public void calculate() {
         Long day = 86400000L;
         Long now = System.currentTimeMillis();
@@ -66,6 +50,14 @@ public class CalcAccuracy {
         }
     }
 
+
+    /**
+     * 集合交集判断(此方法还需优化写法)
+     *
+     * @param strings
+     * @param stringList
+     * @return
+     */
     public Boolean listHasIntersection(List<String> strings, List<String> stringList) {
         for (String string : strings) {
             for (String s : stringList) {

+ 23 - 0
cpp-admin/src/main/java/com/cpp/web/service/alarm/AbnormalAlarmService.java

@@ -0,0 +1,23 @@
+package com.cpp.web.service.alarm;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cpp.web.domain.AbnormalAlarm;
+import com.cpp.web.domain.enums.AlarmEnum;
+
+import java.util.Date;
+
+/**
+ * 告警信息业务层接口
+ *
+ * @author tl
+ * @date 2022-05-11 09:51:21
+ */
+public interface AbnormalAlarmService extends IService<AbnormalAlarm> {
+
+    QueryWrapper<AbnormalAlarm> findByTimeBetweenAndAlarmTypeAndStationCode(Date startTime, Date endTime, AlarmEnum alarmType, String stationCode);
+
+    Boolean updateAllStatus1(String stationCode);
+
+    int countByStatusAndStationCode(Integer status, String stationCode);
+}

+ 104 - 0
cpp-admin/src/main/java/com/cpp/web/service/alarm/AlarmLog.java

@@ -0,0 +1,104 @@
+package com.cpp.web.service.alarm;
+
+import ch.qos.logback.classic.Logger;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cpp.common.utils.spring.SpringUtils;
+import com.cpp.web.domain.AbnormalAlarm;
+import com.cpp.web.domain.enums.AlarmEnum;
+import com.cpp.web.domain.enums.DataSourcesEnum;
+import com.cpp.web.utils.LogUtil;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * 告警日志类
+ */
+public class AlarmLog {
+
+    //实时告警map
+    private Map<String, AlarmDto> alarmDtoMap = new ConcurrentHashMap<>();
+
+    private Logger logger = new AppenderFactory().getAppender();
+
+    public static final AlarmLog getInstance() {
+        return LazyHolder.INSTANCE;
+    }
+
+    private static class LazyHolder {
+        private static final AlarmLog INSTANCE = new AlarmLog();
+    }
+
+
+    public void info(DataSourcesEnum alarmSource, AlarmEnum alarmType, String info, String stationCode) {
+
+        String key = alarmSource.getCode() + "_" + alarmType.getCode() + "_" + info + "_" + stationCode;
+        if (alarmDtoMap.containsKey(key)) {
+            alarmDtoMap.get(key).setUpdateTime(new Date());
+        } else {
+            AbnormalAlarm abnormalAlarm = new AbnormalAlarm(alarmSource, alarmType, info, stationCode);
+            SpringUtils.getBean(AbnormalAlarmService.class).save(abnormalAlarm);
+            AlarmDto alarmDto = new AlarmDto(abnormalAlarm, new Date());
+            alarmDtoMap.put(key, alarmDto);
+        }
+
+        logger.info(LogUtil.format("【场站编号:{}】,【业务类型:{}-{}】,【告警内容:{}】", stationCode, alarmSource.getMessage(), alarmType.getMessage(), info));
+
+    }
+
+
+    @Data
+    public class AlarmDto {
+        private AbnormalAlarm abnormalAlarm;
+
+        private Date updateTime;
+
+        public AlarmDto(AbnormalAlarm abnormalAlarm, Date updateTime) {
+            this.abnormalAlarm = abnormalAlarm;
+            this.updateTime = updateTime;
+        }
+    }
+
+
+    /**
+     * 定时清理
+     */
+    public void eliminate() {
+        List<String> keys = new ArrayList<>();
+        List<AbnormalAlarm> abnormalAlarms = new ArrayList<>();
+
+        //告警时效20分钟,20分钟内无重复告警将结束实时告警
+        Date date = new Date(System.currentTimeMillis() - 1200000L);
+        for (Map.Entry<String, AlarmDto> stringAlarmDtoEntry : alarmDtoMap.entrySet()) {
+            AlarmDto alarmDto = stringAlarmDtoEntry.getValue();
+            if (alarmDto.getUpdateTime().before(date)) {
+                keys.add(stringAlarmDtoEntry.getKey());
+                AbnormalAlarm abnormalAlarm = alarmDto.getAbnormalAlarm();
+                abnormalAlarm.setEndTime(alarmDto.getUpdateTime());
+                abnormalAlarms.add(abnormalAlarm);
+            }
+        }
+
+        if (keys.size() > 0) {
+            keys.forEach(k -> alarmDtoMap.remove(k));
+            SpringUtils.getBean(AbnormalAlarmService.class).saveOrUpdateBatch(abnormalAlarms);
+        }
+    }
+
+
+    /**
+     * 初始化告警信息
+     */
+    public void initMap() {
+        List<AbnormalAlarm> abnormalAlarms = SpringUtils.getBean(AbnormalAlarmService.class).list(Wrappers.lambdaQuery(AbnormalAlarm.class).select().isNull(AbnormalAlarm::getEndTime));
+        for (AbnormalAlarm abnormalAlarm : abnormalAlarms) {
+            String key = abnormalAlarm.getAlarmSource().getCode() + "_" + abnormalAlarm.getAlarmType().getCode() + "_" + abnormalAlarm.getMsg() + "_" + abnormalAlarm.getStationCode();
+            alarmDtoMap.put(key, new AlarmDto(abnormalAlarm, new Date()));
+        }
+    }
+}

+ 87 - 0
cpp-admin/src/main/java/com/cpp/web/service/alarm/AppenderFactory.java

@@ -0,0 +1,87 @@
+package com.cpp.web.service.alarm;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.filter.ThresholdFilter;
+import ch.qos.logback.core.rolling.RollingFileAppender;
+import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
+import ch.qos.logback.core.util.FileSize;
+import ch.qos.logback.core.util.OptionHelper;
+import com.cpp.web.utils.ParsingFileUtil;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 创建动态日志
+ *
+ * @author xsl
+ * @version 3.0
+ */
+public class AppenderFactory {
+    private final String logLevel = "debug";
+    private final String totalSizeCap = "20480MB";
+    private final String maxFileSize = "50MB";
+    private final String maxHistory = "90";
+
+    /**
+     * 通过传入的名字和级别,动态设置appender
+     *
+     * @return
+     */
+    public Logger getAppender() {
+        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+        //这里是可以用来设置appender的,在xml配置文件里面,是这种形式:
+        RollingFileAppender appender = new RollingFileAppender();
+        //这里设置级别过滤器
+        ThresholdFilter levelFilter = createLevelFilter(this.logLevel);
+        levelFilter.start();
+        appender.addFilter(levelFilter);
+        // 但可以使用<contextName>设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改。
+        appender.setContext(context);
+        //appender的name属性
+        appender.setName("alarm");
+        appender.setAppend(true);
+        appender.setPrudent(false);
+        //设置文件创建时间及大小的类
+        SizeAndTimeBasedRollingPolicy policy = new SizeAndTimeBasedRollingPolicy();
+        //文件名格式
+        String fp = OptionHelper.substVars(ParsingFileUtil.getLogsPath() + "/" + "%d{yyyy-MM-dd}" + "/" + "alarm.%d{yyyy-MM-dd}.%i.log", context);
+        //最大日志文件大小
+        policy.setMaxFileSize(FileSize.valueOf(this.maxFileSize));
+        //设置文件名模式
+        policy.setFileNamePattern(fp);
+        //设置日志文件保留天数
+        policy.setMaxHistory(Integer.parseInt(this.maxHistory));
+        //总大小限制
+        policy.setTotalSizeCap(FileSize.valueOf(this.totalSizeCap));
+        //设置父节点是appender
+        policy.setParent(appender);
+        // 但可以使用<contextName>设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改。
+        policy.setContext(context);
+        policy.setCleanHistoryOnStart(true);
+        policy.start();
+        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
+        //设置上下文,每个logger都关联到logger上下文,默认上下文名称为default。
+        // 但可以使用<contextName>设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改。
+        encoder.setContext(context);
+        //设置格式
+        encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n");
+        encoder.start();
+        //加入下面两个节点
+        appender.setRollingPolicy(policy);
+        appender.setEncoder(encoder);
+        appender.start();
+        Logger logger = context.getLogger("alarm");
+        //设置不向上级打印信息
+        logger.setAdditive(false);
+        logger.addAppender(appender);
+        return logger;
+    }
+
+    private ThresholdFilter createLevelFilter(String level) {
+        ThresholdFilter levelFilter = new ThresholdFilter();
+        levelFilter.setLevel(level);
+        levelFilter.start();
+        return levelFilter;
+    }
+}

+ 57 - 0
cpp-admin/src/main/java/com/cpp/web/service/alarm/impl/AbnormalAlarmServiceImpl.java

@@ -0,0 +1,57 @@
+package com.cpp.web.service.alarm.impl;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cpp.web.domain.AbnormalAlarm;
+import com.cpp.web.domain.enums.AlarmEnum;
+import com.cpp.web.mapper.AbnormalAlarmMapper;
+import com.cpp.web.service.alarm.AbnormalAlarmService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 告警信息层实现类
+ *
+ * @author tl
+ * @date 2022-05-11 18:07:03
+ */
+@AllArgsConstructor
+@Slf4j
+@Service
+public class AbnormalAlarmServiceImpl extends ServiceImpl<AbnormalAlarmMapper, AbnormalAlarm> implements AbnormalAlarmService {
+
+    @Override
+    public QueryWrapper<AbnormalAlarm> findByTimeBetweenAndAlarmTypeAndStationCode(Date startTime, Date endTime, AlarmEnum alarmType, String stationCode) {
+
+
+        QueryWrapper<AbnormalAlarm> wrapper = new QueryWrapper<>();
+        if (startTime != null && !endTime.equals("")&& endTime != null && !endTime.equals("")) {
+            wrapper.and(w->w.between("start_time",startTime,endTime).or().between("end_time",startTime,endTime));
+        }
+        if (alarmType != null && !alarmType.equals("")) {
+            wrapper.eq("alarm_type", alarmType);
+        }
+
+        if (stationCode != null && !stationCode.equals("")) {
+            wrapper.eq("station_code", stationCode);
+        }
+        return wrapper;
+    }
+
+    @Override
+    public Boolean updateAllStatus1(String stationCode) {
+        return baseMapper.updateAllStatus1(stationCode);
+    }
+
+    @Override
+    public int countByStatusAndStationCode(Integer status, String stationCode) {
+        return baseMapper.countByStatusAndStationCode(status,stationCode);
+    }
+
+}

+ 4 - 11
cpp-admin/src/main/java/com/cpp/web/service/cloud/CloudFileParsing.java

@@ -8,12 +8,9 @@ import com.cpp.web.domain.datafactory.ParsingLog;
 import com.cpp.web.domain.datafactory.enums.FileTypeEnum;
 import com.cpp.web.domain.enums.AlarmEnum;
 import com.cpp.web.domain.enums.DataSourcesEnum;
-import com.cpp.web.service.AbnormalAlarmService;
+import com.cpp.web.service.alarm.AbnormalAlarmService;
 import com.cpp.web.service.datafactory.ParsingLogService;
-import com.cpp.web.utils.DateTimeUtil;
-import com.cpp.web.utils.NumberUtils;
-import com.cpp.web.utils.ParsingFileUtil;
-import com.cpp.web.utils.ParsingUtil;
+import com.cpp.web.utils.*;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FileUtils;
@@ -89,7 +86,6 @@ public class CloudFileParsing {
         if (files.size() > 0) {
 
             List<ParsingLog> parsingLogs = new ArrayList<>();
-            List<AbnormalAlarm> abnormalAlarms = new ArrayList<>();
 
             // 循环文件并解析
             for (File file : files) {
@@ -173,7 +169,7 @@ public class CloudFileParsing {
                         moveFile(file);
                     } else {
                         parsingLog.setParsingFileStatus("失败");
-                        abnormalAlarms.add(new AbnormalAlarm(DataSourcesEnum.E2, AlarmEnum.E4, parsingLog.getParsingDescribe(), ""));
+                        LogUtil.info(DataSourcesEnum.E2, AlarmEnum.E4, parsingLog.getParsingDescribe(), "");
                         //移除文件备份到error文件下
                         moveFileError(file);
                     }
@@ -183,9 +179,6 @@ public class CloudFileParsing {
             if (parsingLogs.size() > 0) {
                 parsingLogService.saveBatch(parsingLogs);
             }
-            if (abnormalAlarms.size() > 0) {
-                abnormalAlarmService.saveBatch(abnormalAlarms);
-            }
         }
 
 
@@ -247,7 +240,7 @@ public class CloudFileParsing {
                             nwpData.setForecastModel(forecastModel);
                             nwpData.setStationCode(stationCode);
                             nwpData.setTime(time);//采集时间 与 短期预测时间关联
-                            nwpData.setT(NumberUtils.subtract(new BigDecimal(datas[6]), new BigDecimal("273.15")));//温度
+                            nwpData.setT(NumberUtil.subtract(new BigDecimal(datas[6]), new BigDecimal("273.15")));//温度
 
                             nwpData.setSenf(new BigDecimal(datas[11]).setScale(2, RoundingMode.HALF_UP));//感热
                             nwpData.setSwr(new BigDecimal(datas[9]).setScale(2, RoundingMode.HALF_UP));//短波辐射(相当于总辐射)

+ 8 - 18
cpp-admin/src/main/java/com/cpp/web/service/datafactory/SftpFileParsing.java

@@ -1,12 +1,8 @@
 package com.cpp.web.service.datafactory;
 
 import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.extra.ftp.Ftp;
-import cn.hutool.extra.ftp.FtpConfig;
-import cn.hutool.extra.ftp.FtpMode;
 import cn.hutool.extra.ssh.JschUtil;
 import cn.hutool.extra.ssh.Sftp;
-import com.cpp.web.domain.AbnormalAlarm;
 import com.cpp.web.domain.datafactory.SftpChannel;
 import com.cpp.web.domain.datafactory.ParsingLog;
 import com.cpp.web.domain.datafactory.ParsingType;
@@ -14,9 +10,8 @@ import com.cpp.web.domain.datafactory.dto.ParsingResultDto;
 import com.cpp.web.domain.enums.AlarmEnum;
 import com.cpp.web.domain.enums.DataSourcesEnum;
 import com.cpp.web.domain.station.ElectricField;
-import com.cpp.web.service.AbnormalAlarmService;
 import com.cpp.web.service.station.ElectricFieldService;
-import com.cpp.web.utils.MessageUtils;
+import com.cpp.web.utils.LogUtil;
 import com.cpp.web.utils.ParsingFileUtil;
 import com.jcraft.jsch.ChannelSftp;
 import com.jcraft.jsch.JSch;
@@ -26,7 +21,6 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.time.DateFormatUtils;
 import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
@@ -56,12 +50,11 @@ public class SftpFileParsing {
 
     private final ParsingLogService parsingLogService;
 
-    private final AbnormalAlarmService abnormalAlarmService;
-
     private final File PARSING_FILE_TEMP_DIR = ParsingFileUtil.checkGetPath(ParsingFileUtil.getSftpDownload() + File.separator + "temp");
     private final File PARSING_FILE_SUCCESS_DIR = ParsingFileUtil.checkGetPath(ParsingFileUtil.getSftpDownload() + File.separator + "success");
     private final File PARSING_FILE_FAIL_DIR = ParsingFileUtil.checkGetPath(ParsingFileUtil.getSftpDownload() + File.separator + "fail");
 
+//    private AlarmLog alarmLog = AlarmLog.getInstance();
 //    private final ThreadPoolTaskExecutor executor;
 
     /**
@@ -76,9 +69,7 @@ public class SftpFileParsing {
      * @param
      * @return
      */
-//    @Scheduled(fixedRate = 300000L)
-//    @Scheduled(fixedRate = 60000L)
-    public void parsingFileJob() {
+    public void parsingFile() {
 
 
         log.info("-----------------开始执行FTP文件解析任务----------------------");
@@ -116,7 +107,6 @@ public class SftpFileParsing {
      */
     private void parsingFile(List<ParsingType> parsingTypes, List<ElectricField> channelElectricFields, Sftp sftp) {
         List<ParsingLog> parsingLogs = new ArrayList<>();
-        List<AbnormalAlarm> abnormalAlarms = new ArrayList<>();
         for (ParsingType parsingType : parsingTypes) {
 //            executor.execute(new Runnable() {
 //                @Override
@@ -138,10 +128,12 @@ public class SftpFileParsing {
                             ParsingLog parsingLog = new ParsingLog();
                             Date now = new Date();
                             parsingLog.setParsingTime(now);
+                            parsingLog.setFileName(fileName);
                             ParsingResultDto parsingResultDto = parsingInterface.parsing(file, electricField.getStationCode());
                             parsingLog.setParsingDescribe(parsingResultDto.getMessage());
                             parsingLog.setFileType(parsingType.getFileType());
                             parsingLog.setDataSources(DataSourcesEnum.E1);
+                            parsingLog.setStationCode(electricField.getStationCode());
                             if (parsingResultDto.getStatus().equals("fail")) {
                                 try {
                                     File failFileDir = new File(PARSING_FILE_FAIL_DIR.getPath() + File.separator + DateFormatUtils.format(now, "yyyy-MM-dd"));
@@ -159,7 +151,8 @@ public class SftpFileParsing {
                                 file.delete();//失败删除本地文件,等待下次下载
                                 parsingLog.setParsingFileStatus("失败");
 
-                                abnormalAlarms.add(new AbnormalAlarm(DataSourcesEnum.E3, AlarmEnum.E4, MessageUtils.format("无法解析场站端文件:{}", fileName), electricField.getStationCode()));
+
+                                LogUtil.info(DataSourcesEnum.E3, AlarmEnum.E4, LogUtil.format("无法解析场站端文件:{}", fileName), electricField.getStationCode());
 
                             } else {
                                 sftp.delFile(ftpUrl + "/" + fileName);//成功删除ftp上的文件
@@ -182,7 +175,7 @@ public class SftpFileParsing {
                             }
                             parsingLogs.add(parsingLog);
                         } catch (Exception e) {
-                            abnormalAlarms.add(new AbnormalAlarm(DataSourcesEnum.E3, AlarmEnum.E4, MessageUtils.format("无法解析场站端文件:{}", fileName), electricField.getStationCode()));
+                            LogUtil.info(DataSourcesEnum.E3, AlarmEnum.E4, LogUtil.format("无法解析场站端文件:{}", fileName), electricField.getStationCode());
                             log.error("下载并解析文件{}时异常", fileName, e);
                         }
 
@@ -195,9 +188,6 @@ public class SftpFileParsing {
         }
 
         parsingLogService.saveBatch(parsingLogs);
-
-        abnormalAlarmService.saveBatch(abnormalAlarms);
-
     }
 
 

+ 8 - 11
cpp-admin/src/main/java/com/cpp/web/service/datafactory/impl/ParsingStatusServiceImpl.java

@@ -7,9 +7,9 @@ import com.cpp.web.domain.datafactory.dto.ParsingResultDto;
 import com.cpp.web.domain.datafactory.enums.FileTypeEnum;
 import com.cpp.web.domain.enums.AlarmEnum;
 import com.cpp.web.domain.enums.DataSourcesEnum;
-import com.cpp.web.service.AbnormalAlarmService;
+import com.cpp.web.service.alarm.AbnormalAlarmService;
 import com.cpp.web.service.datafactory.ParsingInterface;
-import com.cpp.web.utils.MessageUtils;
+import com.cpp.web.utils.LogUtil;
 import com.cpp.web.utils.ParsingFileUtil;
 import lombok.AllArgsConstructor;
 import lombok.Data;
@@ -57,10 +57,8 @@ public class ParsingStatusServiceImpl implements ParsingInterface {
 
             String json = ParsingFileUtil.getStr(file);
             StationStatusDto stationStatusDto = JSONUtil.parse(json).toBean(StationStatusDto.class);
-            List<AbnormalAlarm> abnormalAlarms = stationStatusDto.generateAbnormalAlarm(stationCode);
-            if (abnormalAlarms.size() > 0) {
-                abnormalAlarmService.saveBatch(abnormalAlarms);
-            }
+            stationStatusDto.generateAbnormalAlarm(stationCode);
+
 
             log.info("解析RP文件:{} 成功! O(∩_∩)O", file.getName());
             parsingResultDto.setStatus("success");
@@ -90,29 +88,28 @@ public class ParsingStatusServiceImpl implements ParsingInterface {
          *
          * @return
          */
-        private List<AbnormalAlarm> generateAbnormalAlarm(String stationCode) {
+        private void generateAbnormalAlarm(String stationCode) {
 
             List<AbnormalAlarm> list = new ArrayList<>();
             if (this.channelErrors != null) {
                 for (ChannelError channelError : this.channelErrors) {
-                    list.add(new AbnormalAlarm(DataSourcesEnum.E1, AlarmEnum.E1, channelError.getMsg(), stationCode));
+                    LogUtil.info(DataSourcesEnum.E1, AlarmEnum.E1, channelError.getMsg(), stationCode);
                 }
             }
 
 
             if (this.uploadFiles != null) {
                 for (UploadFile uploadFile : this.uploadFiles) {
-                    list.add(new AbnormalAlarm(DataSourcesEnum.E1, AlarmEnum.E2, MessageUtils.format("站端[{}]类型文件:【{}】未上报!", uploadFile.getType(), uploadFile.getName()), stationCode));
+                    LogUtil.info(DataSourcesEnum.E1, AlarmEnum.E2, LogUtil.format("站端[{}]类型文件:【{}】未上报!", uploadFile.getType(), uploadFile.getName()), stationCode);
                 }
             }
 
             if (this.hardDiskCapacity != null) {
                 if (this.hardDiskCapacity.compareTo(new BigDecimal(95)) > -1) {
-                    list.add(new AbnormalAlarm(DataSourcesEnum.E1, AlarmEnum.E3, MessageUtils.format("站端磁盘空间达到 {}%,请关注!", this.hardDiskCapacity), stationCode));
+                    LogUtil.info(DataSourcesEnum.E1, AlarmEnum.E3, LogUtil.format("站端磁盘空间达到 {}%,请关注!", this.hardDiskCapacity), stationCode);
                 }
             }
 
-            return list;
         }
     }
 

+ 0 - 23
cpp-admin/src/main/java/com/cpp/web/service/impl/AbnormalAlarmServiceImpl.java

@@ -1,23 +0,0 @@
-package com.cpp.web.service.impl;
-
-
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.cpp.web.domain.AbnormalAlarm;
-import com.cpp.web.mapper.AbnormalAlarmMapper;
-import com.cpp.web.service.AbnormalAlarmService;
-import lombok.AllArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-/**
- * 告警信息层实现类
- *
- * @author tl
- * @date 2022-05-11 18:07:03
- */
-@AllArgsConstructor
-@Slf4j
-@Service
-public class AbnormalAlarmServiceImpl extends ServiceImpl<AbnormalAlarmMapper, AbnormalAlarm> implements AbnormalAlarmService {
-
-}

+ 29 - 0
cpp-admin/src/main/java/com/cpp/web/utils/LogUtil.java

@@ -0,0 +1,29 @@
+package com.cpp.web.utils;
+
+import com.cpp.web.domain.AbnormalAlarm;
+import com.cpp.web.domain.enums.AlarmEnum;
+import com.cpp.web.domain.enums.DataSourcesEnum;
+import com.cpp.web.service.alarm.AlarmLog;
+
+import java.math.BigDecimal;
+
+/**
+ * 信息拼装工具类
+ *
+ * @Author: tl
+ * @Date: 2023/8/1 15:30
+ */
+public class LogUtil {
+
+  public static String format(String message, Object... args) {
+    for (Object arg : args) {
+      message = message.replaceFirst("\\{\\}", arg.toString());
+    }
+    return message;
+  }
+
+  public static void info(DataSourcesEnum dataSources,AlarmEnum alarmEnum,String info,String stationCode){
+    AlarmLog.getInstance().info(dataSources, alarmEnum,info,stationCode);
+  }
+
+}

+ 0 - 46
cpp-admin/src/main/java/com/cpp/web/utils/MessageUtils.java

@@ -1,46 +0,0 @@
-package com.cpp.web.utils;
-
-import java.math.BigDecimal;
-
-/**
- * 信息拼装工具类
- *
- * @Author: tl
- * @Date: 2023/8/1 15:30
- */
-public class MessageUtils {
-
-
-  public static String normal(String methodName) {
-    return methodName + "【结果正常】";
-
-  }
-
-  public static String abnormal(String methodName) {
-    return methodName + "×结果异常×";
-  }
-
-  public static String insufficient(String methodName) {
-    return methodName + "【所需数据不足,暂不进行此项校验】";
-  }
-
-  public static String success(String methodName, BigDecimal value) {
-    return methodName + "【尝试修复成功,结果为: {" + value + "}】";
-  }
-
-  public static String fail(String methodName) {
-    return methodName + "×尝试修复失败×";
-  }
-
-
-
-
-
-  public static String format(String message, Object... args) {
-    for (Object arg : args) {
-      message = message.replaceFirst("\\{\\}", arg.toString());
-    }
-    return message;
-  }
-
-}

+ 2 - 2
cpp-admin/src/main/java/com/cpp/web/utils/NumberUtils.java → cpp-admin/src/main/java/com/cpp/web/utils/NumberUtil.java

@@ -11,8 +11,8 @@ import java.math.BigDecimal;
  * @version 2.0
  */
 @Slf4j
-public class NumberUtils {
-    private NumberUtils() {
+public class NumberUtil {
+    private NumberUtil() {
     }
 
     /**

+ 1 - 0
cpp-ui/src/assets/icons/svg/alarm1.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1728642003080" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4966" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 960c-247.424 0-448-200.576-448-448 0-247.424 200.576-448 448-448 247.424 0 448 200.576 448 448C960 759.424 759.424 960 512 960L512 960zM512 163.584C319.552 163.584 163.584 319.552 163.584 512c0 192.448 155.968 348.48 348.416 348.48 192.448 0 348.416-156.032 348.416-348.416C860.416 319.68 704.448 163.584 512 163.584L512 163.584zM776 400.576l-316.8 316.8c-9.728 9.728-25.472 9.728-35.2 0l-176-176c-9.728-9.728-9.728-25.472 0-35.2l35.2-35.2c9.728-9.728 25.472-9.728 35.2 0L441.6 594.176l264-264c9.728-9.728 25.472-9.728 35.2 0l35.2 35.2C785.728 375.104 785.728 390.848 776 400.576L776 400.576z" p-id="4967" fill="#1296db"></path></svg>

File diff suppressed because it is too large
+ 0 - 0
cpp-ui/src/assets/icons/svg/alarm2.svg


+ 242 - 0
cpp-ui/src/views/abnormalAlarm/index.vue

@@ -0,0 +1,242 @@
+<template>
+  <div class="app-container">
+    <div class="dark-el-input dark-el-button">
+      <div style="position:absolute;text-align: right;width: 95%">
+        <span  v-loading="loading"><svg-icon slot="prefix" icon-class="alarm1" class="el-input__icon input-icon"/> {{this.alarm1}} <svg-icon slot="prefix" icon-class="alarm2" class="el-input__icon input-icon"/> {{this.alarm2}}</span>
+      </div>
+      <el-form ref="queryForm" size="small" :inline="true" popper-class="cpp-popper">
+        <el-form-item label="时间">
+          <el-date-picker
+            :clearable="false"
+            v-model="dateTime"
+            type="datetimerange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            :default-time="['00:00:00', '23:45:00']" popper-class="cpp-popper"
+          />
+        </el-form-item>
+        <el-form-item label="场站名称">
+          <el-select v-model="stationCode" placeholder="请选择" popper-class="cpp-popper">
+            <el-option
+              v-for="item in stationList"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value">
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="告警类型">
+          <el-select v-model="alarmType" clearable popper-class="cpp-popper">
+            <el-option
+              v-for="item in alarmTypes"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value">
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" style="margin-left: 5px" icon="el-icon-search" @click="beforeQuery">查询
+          </el-button>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" style="margin-left: 5px" icon="el-icon-search" @click="beforeQuery">导出
+          </el-button>
+        </el-form-item>
+
+        <br/>
+        <el-form-item>
+          <el-button type="primary" style="margin-left: 5px" @click="acknowledgeByStationCode">全部确认
+          </el-button>
+        </el-form-item>
+      </el-form>
+
+    </div>
+    <div style="padding-top: 10px">
+      <vxe-table
+        ref="xTable"
+        align="center"
+        class="mytable-style"
+        auto-resize
+        border
+        resizable
+        export-config
+        highlight-current-row
+        show-overflow
+        :data="tableData"
+        :loading="loading"
+        :radio-config="{trigger: 'row'}">
+        <vxe-table-column field="stationCode" title="所属场站" :formatter="stationCodeFormat"></vxe-table-column>
+        <vxe-table-column field="startTime" title="开始时间"></vxe-table-column>
+        <vxe-table-column field="endTime" title="结束时间"></vxe-table-column>
+        <vxe-table-column field="alarmType" title="告警类型" :formatter="alarmTypeFormat"></vxe-table-column>
+        <vxe-table-column field="msg" title="告警描述"></vxe-table-column>
+        <vxe-table-column field="voltage" title="操作人"></vxe-table-column>
+        <vxe-table-column field="" title="操作">
+          <template v-slot="{ row }">
+            <svg-icon v-if="row.status !== 0" slot="prefix" icon-class="alarm1" class="el-input__icon input-icon"/>
+            <svg-icon v-if="row.status === 0" slot="prefix" icon-class="alarm2" class="el-input__icon input-icon"  @click="acknowledge(row)"/>
+          </template>
+        </vxe-table-column>
+      </vxe-table>
+      <vxe-pager
+        background
+        :loading="loading"
+        :current-page.sync="currentPage"
+        :page-size.sync="pageSize"
+        :total="total"
+        @page-change="handlePageChange"
+        :layouts="['PrevJump', 'PrevPage', 'JumpNumber', 'NextPage', 'NextJump', 'Sizes', 'FullJump', 'Total']">
+      </vxe-pager>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'inverterinfo',
+  data() {
+    return {
+      alarmType: '',
+      alarmTypes: [
+        {
+          label: "站端通道告警",
+          value: "E1"
+        },
+        {
+          label: "站端上报告警",
+          value: "E2"
+        },
+        {
+          label: "站端硬件报警",
+          value: "E3"
+        },
+        {
+          label: "中心解析告警",
+          value: "E4"
+        },
+        {
+          label: "通用告警",
+          value: "E5"
+        }
+      ],
+      dateTime: [new Date(new Date().toLocaleDateString()).getTime(), new Date(new Date().toLocaleDateString()).getTime() + 60 * 60 * 24 * 1000 - 5 * 1000 * 60],
+      total: 0,
+      sortOrder: 'asc',
+      pageSize: 10,
+      currentPage: 1,
+      stationList: [],
+      stationCode: [],
+      searchForm: {},
+      tableData: [],
+      loading: false,
+      alarm1: 0,
+      alarm2: 0
+    }
+  },
+  created() {
+    // 获取场站下拉列表
+    this.getStationCode()
+  },
+  mounted() {
+
+  },
+  computed: {},
+  methods: {
+    beforeQuery() {
+      this.currentPage = 1
+      this.pageSize = 10
+      this.dataQuery()
+    },
+    stationCodeFormat({cellValue, row, column}) {
+      const item = this.stationList.find(item => item.value === cellValue)
+      return item ? item.label : ''
+    },
+    alarmTypeFormat({cellValue, row, column}){
+      const item = this.alarmTypes.find(item => item.value === cellValue)
+      return item ? item.label : ''
+    },
+    handlePageChange({currentPage, pageSize}) {
+      this.currentPage = currentPage
+      this.pageSize = pageSize
+      this.dataQuery();
+    },
+    dataQuery() {
+      let startTime = Math.round(this.dateTime[0])
+      let endTime = Math.round(this.dateTime[1])
+      if (endTime <= startTime) {
+        this.$message.error("开始时间不能大于结束时间")
+        return
+      }
+
+      this.loading = true
+      let queryParams = {
+        "currentPage": this.currentPage,
+        "pageSize": this.pageSize,
+        "stationCode": this.stationCode,
+        "alarmType": this.alarmType,
+        "startTime":startTime,
+        "endTime":endTime
+      }
+
+      this.$axios.get('/abnormalAlarm/getByTimeBetweenAndAlarmTypeAndStationCode', {params: queryParams}).then(response => {
+        this.tableData = response.data.records
+        this.total = response.data.total
+
+        this.$axios.get('/abnormalAlarm/getCountByStatusAndStationCode', {params: {
+            "status": 0,
+            "stationCode": this.stationCode,
+          }}).then(response => {
+            this.alarm2 = response.data
+            this.alarm1 = this.total - this.alarm2
+          this.loading = false
+        })
+      }).catch(() => {
+        this.loading = false
+      })
+    },
+    async getStationCode() {
+      await this.$axios({url: '/electricfield/all', method: 'get'}).then(response => {
+        this.stationList = response.data
+        if (this.stationList.length > 0) {
+          this.stationCode = this.stationList[0].value
+          this.dataQuery()
+        }
+      })
+    },
+    acknowledgeByStationCode(){
+      this.$confirm('是否确认执行当前场站全部确认操作?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$axios.get('/abnormalAlarm/acknowledgeByStationCode', {params: {
+            "stationCode": this.stationCode,
+          }}).then(response => {
+          this.beforeQuery()
+          this.$message.info("确认成功!")
+
+        }).catch(() => {
+          this.loading = false
+        })
+      })
+    },
+    acknowledge(row){
+      this.$confirm('是否确认执行【'+row.msg+'】确认操作?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        row.status = 1
+        this.$axios.post('/abnormalAlarm/save',row).then(response => {
+          this.$message.info("【"+row.msg+"】 已确认!")
+          this.beforeQuery()
+        }).catch(() => {
+          this.loading = false
+        })
+      })
+    }
+  }
+}
+</script>

Some files were not shown because too many files changed in this diff