Browse Source

增加前后端频率随机数、页面socket交互展示

xusl 1 năm trước cách đây
mục cha
commit
24aa7935cf
27 tập tin đã thay đổi với 734 bổ sung423 xóa
  1. 4 10
      backend/pom.xml
  2. 49 0
      backend/src/main/java/com/jiayue/pfr/PfrApplication.java
  3. 0 20
      backend/src/main/java/com/jiayue/pfr/SsiApplication.java
  4. 1 1
      backend/src/main/java/com/jiayue/pfr/config/ProtocolConfig.java
  5. 1 1
      backend/src/main/java/com/jiayue/pfr/config/SaTokenConfiguration.java
  6. 58 0
      backend/src/main/java/com/jiayue/pfr/config/TestFmRandom.java
  7. 25 0
      backend/src/main/java/com/jiayue/pfr/config/WebSocketConfig.java
  8. 12 0
      backend/src/main/java/com/jiayue/pfr/constant/CacheConstants.java
  9. 0 27
      backend/src/main/java/com/jiayue/pfr/constant/PermissionContextHolder.java
  10. 7 21
      backend/src/main/java/com/jiayue/pfr/controller/cmf/SysParameterController.java
  11. 13 0
      backend/src/main/java/com/jiayue/pfr/dto/FmDataBeanDto.java
  12. 48 0
      backend/src/main/java/com/jiayue/pfr/job/FmJob.java
  13. 2 2
      backend/src/main/java/com/jiayue/pfr/protocol/frequency/DataBean.java
  14. 12 9
      backend/src/main/java/com/jiayue/pfr/protocol/frequency/FmRtuMasterDelimiterHandler.java
  15. 8 7
      backend/src/main/java/com/jiayue/pfr/protocol/frequency/FmRtuMasterHandler.java
  16. 20 0
      backend/src/main/java/com/jiayue/pfr/service/cmf/SysParameterService.java
  17. 44 2
      backend/src/main/java/com/jiayue/pfr/service/cmf/impl/SysParameterServiceImpl.java
  18. 116 0
      backend/src/main/java/com/jiayue/pfr/service/di/WebSocketServer.java
  19. 2 2
      backend/src/main/resources/application.yml
  20. 23 0
      backend/src/main/resources/ehcache-setting.xml
  21. 27 0
      backend/src/main/resources/logback-pfr.xml
  22. 1 1
      backend/src/test/java/com/jiayue/pfr/BaseTest.java
  23. 27 0
      backend/src/test/java/com/jiayue/pfr/Test.java
  24. 1 1
      ui/package.json
  25. 1 0
      ui/src/main.js
  26. 230 317
      ui/src/views/largeScreen/index.vue
  27. 2 2
      ui/src/views/login/index.vue

+ 4 - 10
backend/pom.xml

@@ -208,16 +208,6 @@
             <artifactId>oshi-core</artifactId>
             <version>6.4.0</version>
         </dependency>
-        <dependency>
-            <groupId>net.java.dev.jna</groupId>
-            <artifactId>jna</artifactId>
-            <version>5.13.0</version>
-        </dependency>
-        <dependency>
-            <groupId>net.java.dev.jna</groupId>
-            <artifactId>jna-platform</artifactId>
-            <version>5.13.0</version>
-        </dependency>
         <!-- 解析客户端操作系统、浏览器等 -->
         <dependency>
             <groupId>eu.bitwalker</groupId>
@@ -234,6 +224,10 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-websocket</artifactId>
         </dependency>
+        <dependency>
+            <groupId>net.sf.ehcache</groupId>
+            <artifactId>ehcache</artifactId>
+        </dependency>
     </dependencies>
     <build>
         <finalName>ssi</finalName>

+ 49 - 0
backend/src/main/java/com/jiayue/pfr/PfrApplication.java

@@ -0,0 +1,49 @@
+package com.jiayue.pfr;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import net.sf.ehcache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.ehcache.EhCacheCacheManager;
+import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+
+/**
+ * 启动类
+ *
+ * @author xsl
+ * @version 3.0
+ */
+@SpringBootApplication
+@EnableScheduling
+@EnableCaching
+@MapperScan("com.jiayue.pfr.mapper.*")
+public class PfrApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(PfrApplication.class, args);
+    }
+
+    /**
+     * ecache缓存对象获取
+     */
+    @Bean
+    public EhCacheCacheManager cacheManager(CacheManager cacheManagerFactory) {
+        EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager();
+        ehCacheCacheManager.setCacheManager(cacheManagerFactory);
+        return ehCacheCacheManager;
+    }
+
+    /**
+     * ecache缓存配置加载
+     */
+    @Bean
+    public EhCacheManagerFactoryBean cacheManagerFactory() {
+        EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
+        ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache-setting.xml"));
+        return ehCacheManagerFactoryBean;
+    }
+}

+ 0 - 20
backend/src/main/java/com/jiayue/pfr/SsiApplication.java

@@ -1,20 +0,0 @@
-package com.jiayue.pfr;
-
-import org.mybatis.spring.annotation.MapperScan;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-
-/**
- * 启动类
- *
- * @author xsl
- * @version 3.0
- */
-@SpringBootApplication
-@MapperScan("com.jiayue.pfr.mapper.*")
-public class SsiApplication {
-    public static void main(String[] args) {
-        SpringApplication.run(SsiApplication.class, args);
-    }
-}

+ 1 - 1
backend/src/main/java/com/jiayue/pfr/config/ProtocolConfig.java

@@ -17,7 +17,7 @@ public class ProtocolConfig {
      */
     @Bean
     public void frequencyProtocol() {
-        FmRtuMasterBuilder fmRtuMasterBuilder = new FmRtuMasterBuilder("COM5");
+        FmRtuMasterBuilder fmRtuMasterBuilder = new FmRtuMasterBuilder("COM1");
         fmRtuMasterBuilder.setBaudRate(115200);
         fmRtuMasterBuilder.createByUnBlock();
     }

+ 1 - 1
backend/src/main/java/com/jiayue/pfr/config/SaTokenConfiguration.java

@@ -68,7 +68,7 @@ public class SaTokenConfiguration implements WebMvcConfigurer {
                     System.out.println(SaHolder.getRequest().getRequestPath());
                     SaRouter
                             .match("/**")	// 拦截的 path 列表,可以写多个 */
-                            .notMatch("/user/login","/getVerifyCode","/static/**","/assets/**","/")		// 排除掉的 path 列表,可以写多个
+                            .notMatch("/user/login","/getVerifyCode","/static/**","/assets/**","/","/websocket/testsocket")		// 排除掉的 path 列表,可以写多个
                             .check(r -> StpUtil.checkLogin());		// 要执行的校验动作,可以写完整的 lambda 表达式
 
                     // 更多拦截处理方式,请参考“路由拦截式鉴权”章节 */

+ 58 - 0
backend/src/main/java/com/jiayue/pfr/config/TestFmRandom.java

@@ -0,0 +1,58 @@
+package com.jiayue.pfr.config;
+
+import cn.hutool.core.date.DateUtil;
+import com.jiayue.pfr.constant.CacheConstants;
+import com.jiayue.pfr.protocol.frequency.DataBean;
+import com.jiayue.pfr.protocol.frequency.DataBeanPacker;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.math.BigDecimal;
+import java.security.SecureRandom;
+
+/**
+ * @author jy
+ * @since 2023/11/03
+ */
+@Configuration
+public class TestFmRandom {
+    private SecureRandom random;
+    private BigDecimal minFrequency;
+    private BigDecimal maxFrequency;
+    private long testPrevTime = 0;
+
+    @Bean
+    public void generateFrequency() throws Exception{
+        new Thread(()->{
+            this.random = new SecureRandom();
+            this.minFrequency = new BigDecimal("49.9");
+            this.maxFrequency = new BigDecimal("200.1");
+            while (true){
+                // 返回一个在此范围内(包括边界)的随机BigDecimal值。
+                BigDecimal range = maxFrequency.subtract(minFrequency);
+                BigDecimal fraction = new BigDecimal(random.nextDouble());
+                BigDecimal fm = minFrequency.add(range.multiply(fraction)).setScale(3, BigDecimal.ROUND_HALF_UP);
+                if (testPrevTime==0){
+                    CacheConstants.activePower = fm;
+                }
+                else{
+                    // 判断当前时间与上次时间是否同一秒内
+                    if (DateUtil.date(System.currentTimeMillis()).getSeconds()!=DateUtil.date(testPrevTime).getSeconds()){
+                        CacheConstants.activePower = fm;
+                    }
+                }
+                testPrevTime = System.currentTimeMillis();
+
+                // 往池子里加入频率
+                DataBean dataBean = new DataBean();
+                dataBean.setF(new BigDecimal("50"));
+                DataBeanPacker.getInstance().setLastDataBean(dataBean);
+                try {
+                    Thread.sleep(200);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }).start();
+    }
+}

+ 25 - 0
backend/src/main/java/com/jiayue/pfr/config/WebSocketConfig.java

@@ -0,0 +1,25 @@
+package com.jiayue.pfr.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+/**
+*
+*
+* @author xsl
+* @since 2023/08/21
+*/
+@Configuration
+public class WebSocketConfig {
+    /**
+     * ServerEndpointExporter类的作用是,会扫描所有的服务器端点,
+     * 把带有@ServerEndpoint 注解的所有类都添加进来
+     *
+     */
+    @Bean
+    public ServerEndpointExporter serverEndpointExporter(){
+        return new ServerEndpointExporter();
+    }
+
+}

+ 12 - 0
backend/src/main/java/com/jiayue/pfr/constant/CacheConstants.java

@@ -1,4 +1,11 @@
 package com.jiayue.pfr.constant;
+
+import com.jiayue.pfr.dto.FmDataBeanDto;
+import com.jiayue.pfr.protocol.frequency.DataBean;
+
+import java.math.BigDecimal;
+import java.util.concurrent.ConcurrentHashMap;
+
 /**
  * 缓存的key 常量
  *
@@ -9,4 +16,9 @@ public class CacheConstants {
      * 验证码 redis key
      */
     public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
+
+    public static ConcurrentHashMap<Long, FmDataBeanDto> fmMap = new ConcurrentHashMap<>();
+
+    public static BigDecimal activePower = new BigDecimal(0);
+
 }

+ 0 - 27
backend/src/main/java/com/jiayue/pfr/constant/PermissionContextHolder.java

@@ -1,27 +0,0 @@
-package com.jiayue.pfr.constant;
-
-import cn.hutool.core.convert.Convert;
-import org.springframework.web.context.request.RequestAttributes;
-import org.springframework.web.context.request.RequestContextHolder;
-
-/**
- * 权限信息
- *
- * @author ruoyi
- */
-public class PermissionContextHolder
-{
-    private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT";
-
-    public static void setContext(String permission)
-    {
-        RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,
-                RequestAttributes.SCOPE_REQUEST);
-    }
-
-    public static String getContext()
-    {
-        return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,
-                RequestAttributes.SCOPE_REQUEST));
-    }
-}

+ 7 - 21
backend/src/main/java/com/jiayue/pfr/controller/cmf/SysParameterController.java

@@ -59,13 +59,9 @@ public class SysParameterController {
             } else if (sysParameter.getSysDescribe().length() > 200) {
                 return SaResultRefit.errorTips("参数描述长度不能超过200个字符!");
             }
-            boolean bo = sysParameterService.save(sysParameter);
-            if (bo) {
-                return SaResultRefit.ok("添加参数信息成功");
-            } else {
-                log.error("添加参数信息失败");
-                return SaResultRefit.errorTips("添加参数信息失败");
-            }
+            sysParameterService.add(sysParameter);
+            return SaResultRefit.ok("添加参数信息成功");
+
         } catch (Exception e) {
             throw new CustomException("添加参数信息异常", e);
         }
@@ -118,13 +114,8 @@ public class SysParameterController {
                 return SaResultRefit.errorTips("此数据被操作过,自动刷新列表后请重试操作!");
             }
 
-            boolean bo = sysParameterService.updateById(sysParameter);
-            if (bo) {
-                return SaResultRefit.ok("修改参数信息成功");
-            } else {
-                log.error("修改参数信息失败");
-                return SaResultRefit.errorTips("修改参数信息失败");
-            }
+            sysParameterService.update(sysParameter);
+            return SaResultRefit.ok("修改参数信息成功");
         } catch (Exception e) {
             throw new CustomException("修改参数信息异常", e);
         }
@@ -144,13 +135,8 @@ public class SysParameterController {
                 return SaResultRefit.errorTips("此数据被操作过,自动刷新列表后请重试操作!");
             }
 
-            boolean bo = sysParameterService.removeById(Integer.parseInt(id));
-            if (bo) {
-                return SaResultRefit.ok("删除参数信息成功");
-            } else {
-                log.error("删除用户信息失败");
-                return SaResultRefit.errorTips("删除参数信息失败");
-            }
+            sysParameterService.delete(sysParameter);
+            return SaResultRefit.ok("删除参数信息成功");
         } catch (Exception e) {
             throw new CustomException("删除参数信息异常", e);
         }

+ 13 - 0
backend/src/main/java/com/jiayue/pfr/dto/FmDataBeanDto.java

@@ -0,0 +1,13 @@
+package com.jiayue.pfr.dto;
+
+import lombok.Data;
+import java.math.BigDecimal;
+
+@Data
+public class FmDataBeanDto {
+    private String time;
+    //频率
+    private BigDecimal f=BigDecimal.valueOf(-99);
+    //功率
+    private BigDecimal activePower=BigDecimal.valueOf(-99);
+}

+ 48 - 0
backend/src/main/java/com/jiayue/pfr/job/FmJob.java

@@ -0,0 +1,48 @@
+package com.jiayue.pfr.job;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.json.JSONUtil;
+import com.jiayue.pfr.constant.CacheConstants;
+import com.jiayue.pfr.dto.FmDataBeanDto;
+import com.jiayue.pfr.entity.SysParameter;
+import com.jiayue.pfr.protocol.frequency.DataBean;
+import com.jiayue.pfr.protocol.frequency.DataBeanPacker;
+import com.jiayue.pfr.service.cmf.SysParameterService;
+import com.jiayue.pfr.service.di.WebSocketServer;
+import com.jiayue.pfr.util.DateUtils;
+import org.apache.commons.lang3.time.DateFormatUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import java.util.Date;
+
+/**
+ * 每200毫秒从池子中获取频率等信息
+ * @author jy
+ * @since 2023/10/30
+ */
+@Service
+public class FmJob {
+    @Autowired
+    SysParameterService sysParameterService;
+
+    @Scheduled(fixedRate = 2000)
+    void startFmCal() throws Exception{
+        // 从池子里取频率信息
+        DataBean dataBean = DataBeanPacker.getInstance().getLastDataBean();
+        // 存入应用缓存
+//        long currentTime = System.currentTimeMillis();
+//        FmDataBeanDto fmDataBeanDto = new FmDataBeanDto();
+//        fmDataBeanDto.setF(dataBean.getF());
+//        fmDataBeanDto.setTime(currentTime);
+//        CacheConstants.fmMap.put(currentTime,fmDataBeanDto);
+
+        FmDataBeanDto fmDataBeanDto = new FmDataBeanDto();
+        fmDataBeanDto.setF(dataBean.getF());
+        fmDataBeanDto.setActivePower(CacheConstants.activePower);
+        long currentTime = System.currentTimeMillis();
+        fmDataBeanDto.setTime(DateFormatUtils.format(currentTime, "yyyy-MM-dd HH:mm:ss.SSS"));
+        WebSocketServer.sendInfo(JSONUtil.toJsonStr(fmDataBeanDto));
+
+    }
+}

+ 2 - 2
backend/src/main/java/com/jiayue/pfr/protocol/frequency/DataBean.java

@@ -1,12 +1,12 @@
 package com.jiayue.pfr.protocol.frequency;
 
-import lombok.Setter;
+import lombok.Data;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
 
-@Setter
+@Data
 public class DataBean {
 
     //频率

+ 12 - 9
backend/src/main/java/com/jiayue/pfr/protocol/frequency/FmRtuMasterDelimiterHandler.java

@@ -7,6 +7,8 @@ import lombok.Getter;
 import lombok.Setter;
 import lombok.experimental.Accessors;
 import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import wei.yigulu.netty.AbstractDelimiterHandler;
 import wei.yigulu.utils.DataConvertor;
 
@@ -20,6 +22,7 @@ import wei.yigulu.utils.DataConvertor;
 
 public class FmRtuMasterDelimiterHandler extends AbstractDelimiterHandler {
 
+    private static final Logger fLogger = LoggerFactory.getLogger("FLogger");
 
     private static byte HEAD_TAIL_1 = (byte) 0xff;
 
@@ -39,21 +42,21 @@ public class FmRtuMasterDelimiterHandler extends AbstractDelimiterHandler {
 
     @Override
     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
-        log.info("-----------------------------------------------------------------");
-        log.info("接收到原始的报文 :" + DataConvertor.ByteBuf2String((ByteBuf) msg));
+        fLogger.info("-----------------------------------------------------------------");
+        fLogger.info("接收到原始的报文 :" + DataConvertor.ByteBuf2String((ByteBuf) msg));
         if (isOverMaxLength((ByteBuf) msg)) {
             return;
         }
 
         if (!((cumulation.readableBytes() == 1 && cumulation.getByte(0) == HEAD_TAIL_1) ||
                 cumulation.readableBytes() > 2 && checkHead(cumulation))) {
-            log.warn("该段报文未以ff 55开头");
+            fLogger.warn("该段报文未以ff 55开头");
             int headIndex = getHeadIndex(cumulation.readerIndex(), cumulation.writerIndex(), cumulation, new byte[]{HEAD_TAIL_1, HEAD_TAIL_2});
             if (headIndex != -1) {
-                log.warn("该段报文发现ff 55 的报文片段,,舍弃部分报文:" + DataConvertor.ByteBuf2String(cumulation.readBytes(headIndex+2)));
+                fLogger.warn("该段报文发现ff 55 的报文片段,,舍弃部分报文:" + DataConvertor.ByteBuf2String(cumulation.readBytes(headIndex+2)));
             } else {
-                log.warn("该段报文未发现ff 55 的报文片段,整段报文全部清除");
-                log.warn("这段字节中没有数据头,舍弃:" + DataConvertor.ByteBuf2String(cumulation.readBytes(cumulation.readableBytes())));
+                fLogger.warn("该段报文未发现ff 55 的报文片段,整段报文全部清除");
+                fLogger.warn("这段字节中没有数据头,舍弃:" + DataConvertor.ByteBuf2String(cumulation.readBytes(cumulation.readableBytes())));
                 clearCumulation();
                 return;
             }
@@ -61,11 +64,11 @@ public class FmRtuMasterDelimiterHandler extends AbstractDelimiterHandler {
         while (cumulation.readableBytes() >= LENGTH) {
             ByteBuf byteBuf = cumulation.readBytes(LENGTH);
             if (checkHead(byteBuf) && checkTail(byteBuf)) {
-                log.info("发现符合ff 55开头,ff 55 结尾的56字节报文");
+                fLogger.info("发现符合ff 55开头,ff 55 结尾的56字节报文");
                 ctx.fireChannelRead(byteBuf);
             }else{
-                log.info("该56字节不符合ff 55开头,ff 55 结尾的格式");
-                log.info( DataConvertor.ByteBuf2String(byteBuf));
+                fLogger.info("该56字节不符合ff 55开头,ff 55 结尾的格式");
+                fLogger.info( DataConvertor.ByteBuf2String(byteBuf));
                 byteBuf.release();
             }
         }

+ 8 - 7
backend/src/main/java/com/jiayue/pfr/protocol/frequency/FmRtuMasterHandler.java

@@ -5,7 +5,8 @@ import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.EventLoop;
 import io.netty.channel.SimpleChannelInboundHandler;
 import lombok.Data;
-import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import wei.yigulu.utils.DataConvertor;
 
 import java.util.concurrent.TimeUnit;
@@ -16,9 +17,9 @@ import java.util.concurrent.TimeUnit;
  * @author xiuwei
  */
 @Data
-@Slf4j
 public class FmRtuMasterHandler extends SimpleChannelInboundHandler<ByteBuf> {
 
+    private static final Logger fLogger = LoggerFactory.getLogger("FLogger");
 
     private static final int LEN = 52;
 
@@ -30,7 +31,7 @@ public class FmRtuMasterHandler extends SimpleChannelInboundHandler<ByteBuf> {
 
     @Override
     public void channelActive(ChannelHandlerContext ctx) throws Exception {
-        FmMaster.getLog().info("-----连接串口{}成功-----", this.FmMaster.getCommPortId());
+        fLogger.info("-----连接串口{}成功-----", this.FmMaster.getCommPortId());
     }
 
     /**
@@ -41,11 +42,11 @@ public class FmRtuMasterHandler extends SimpleChannelInboundHandler<ByteBuf> {
      */
     @Override
     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-        FmMaster.getLog().error("串口{}连接中断,正在启动重连机制... ", this.FmMaster.getCommPortId());
+        fLogger.error("串口{}连接中断,正在启动重连机制... ", this.FmMaster.getCommPortId());
         //在客户端与服务端连接过程中如果断连,就会调用的方法
         final EventLoop eventLoop = ctx.channel().eventLoop();
         eventLoop.schedule(() -> {
-            FmMaster.getLog().info("正在重连串口{}", this.FmMaster.getCommPortId());
+            fLogger.info("正在重连串口{}", this.FmMaster.getCommPortId());
             this.FmMaster.create();
         }, 3L, TimeUnit.SECONDS);
     }
@@ -58,12 +59,12 @@ public class FmRtuMasterHandler extends SimpleChannelInboundHandler<ByteBuf> {
      */
     @Override
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
-        FmMaster.getLog().error("串口异常消息:", cause);
+        fLogger.error("串口异常消息:", cause);
     }
 
     @Override
     protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
-       FmMaster.getLog().info("接收到串口{}发来数据帧: <= " + DataConvertor.ByteBuf2String(msg), this.FmMaster.getCommPortId());
+        fLogger.info("接收到串口{}发来数据帧: <= " + DataConvertor.ByteBuf2String(msg), this.FmMaster.getCommPortId());
         if (msg.readableBytes() == LEN) {
             DataBeanPacker.getInstance().decodeAnRecode(msg);
         }

+ 20 - 0
backend/src/main/java/com/jiayue/pfr/service/cmf/SysParameterService.java

@@ -2,6 +2,8 @@ package com.jiayue.pfr.service.cmf;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.jiayue.pfr.entity.SysParameter;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
 * 参数管理接口
@@ -15,4 +17,22 @@ public interface SysParameterService extends IService<SysParameter> {
      * @return SysUser
      */
     String queryByKey(String key,String defaultValue);
+    /**
+     * 新增系统参数
+     *
+     * @param sysParameter 系统参数实体
+     */
+    String add(SysParameter sysParameter);
+    /**
+     * 修改系统参数
+     *
+     * @param sysParameter 系统参数实体
+     */
+    String update(SysParameter sysParameter);
+    /**
+     * 删除系统参数
+     *
+     * @param sysParameter 系统参数实体
+     */
+    void delete(SysParameter sysParameter);
 }

+ 44 - 2
backend/src/main/java/com/jiayue/pfr/service/cmf/impl/SysParameterServiceImpl.java

@@ -1,5 +1,6 @@
 package com.jiayue.pfr.service.cmf.impl;
 
+
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.jiayue.pfr.entity.SysParameter;
@@ -7,8 +8,12 @@ import com.jiayue.pfr.entity.SysParameter;
 import com.jiayue.pfr.mapper.cmf.SysParameterMapper;
 import com.jiayue.pfr.service.cmf.SysParameterService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
-
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
 * 参数管理服务类
@@ -26,7 +31,7 @@ public class SysParameterServiceImpl extends ServiceImpl<SysParameterMapper, Sys
      * @param defaultValue 默认值
      * @return SysParameter
      */
-    @Override
+    @Cacheable(cacheNames = "pfrcache", key = "#key")
     public String queryByKey(String key,String defaultValue){
         LambdaQueryWrapper<SysParameter> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(SysParameter::getSysKey,key);
@@ -35,5 +40,42 @@ public class SysParameterServiceImpl extends ServiceImpl<SysParameterMapper, Sys
             return defaultValue;
         }
         return sysParameter.getSysValue();
+
+
+
+    }
+
+    /**
+     * 新增系统参数
+     *
+     * @param sysParameter 系统参数实体
+     */
+    @Transactional(propagation = Propagation.SUPPORTS)
+    @CachePut(cacheNames = "pfrcache", key = "#sysParameter.sysKey")
+    public String add(SysParameter sysParameter){
+        sysParameterMapper.insert(sysParameter);
+        return sysParameter.getSysValue();
+    }
+
+    /**
+     * 修改系统参数
+     *
+     * @param sysParameter 系统参数实体
+     */
+    @Transactional(propagation = Propagation.SUPPORTS)
+    @CachePut(cacheNames = "pfrcache", key = "#sysParameter.sysKey")
+    public String update(SysParameter sysParameter) {
+        sysParameterMapper.updateById(sysParameter);
+        return sysParameter.getSysValue();
+    }
+    /**
+     * 删除系统参数
+     *
+     * @param sysParameter 系统参数实体
+     */
+    @Transactional(propagation = Propagation.SUPPORTS)
+    @CacheEvict(cacheNames = "pfrcache", key = "#sysParameter.sysKey")
+    public void delete(SysParameter sysParameter){
+        this.sysParameterMapper.deleteById(sysParameter.getId());
     }
 }

+ 116 - 0
backend/src/main/java/com/jiayue/pfr/service/di/WebSocketServer.java

@@ -0,0 +1,116 @@
+package com.jiayue.pfr.service.di;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.util.DateUtils;
+import com.jiayue.pfr.constant.CacheConstants;
+import com.jiayue.pfr.dto.FmDataBeanDto;
+import com.jiayue.pfr.protocol.frequency.DataBean;
+import com.jiayue.pfr.protocol.frequency.DataBeanPacker;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.DateFormatUtils;
+import org.springframework.stereotype.Component;
+
+import javax.websocket.*;
+import javax.websocket.server.ServerEndpoint;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.stream.Collectors;
+
+/**
+*
+*
+* @author xsl
+* @since 2023/08/21
+*/
+@Slf4j
+@Component
+@ServerEndpoint(value = "/websocket/testsocket")
+public class WebSocketServer {
+    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
+    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
+
+    //与某个客户端的连接会话,需要通过它来给客户端发送数据
+    private Session session;
+
+    /**
+     * 连接建立成功调用的方法
+     */
+    @OnOpen
+    public void onOpen(Session session) {
+        this.session = session;
+        //加入set中
+        webSocketSet.add(this);
+        log.info("连接成功");
+//        try {
+//            sendMessage("连接成功");
+//        } catch (IOException e) {
+//            log.error("websocket IO异常");
+//        }
+    }
+
+    /**
+     * 连接关闭调用的方法
+     */
+    @OnClose
+    public void onClose() {
+        log.info("客户端连接关闭");
+        //从set中删除
+        webSocketSet.remove(this);
+    }
+
+    /**
+     * 收到客户端消息后调用的方法
+     *
+     * @param message 客户端发送过来的消息
+     */
+    @OnMessage
+    public void onMessage(String message, Session session) {
+        log.info("来自客户端的消息:" + message);
+
+        //群发消息
+//        for (WebSocketServer item : webSocketSet) {
+//            try {
+//                DataBean dataBean = DataBeanPacker.getInstance().getLastDataBean();
+//                FmDataBeanDto fmDataBeanDto = new FmDataBeanDto();
+//                fmDataBeanDto.setF(dataBean.getF());
+//                long currentTime = System.currentTimeMillis();
+//                fmDataBeanDto.setTime(DateFormatUtils.format(currentTime, "yyyy-MM-dd HH:mm:ss.SSS"));
+//                item.sendMessage(JSONUtil.toJsonStr(fmDataBeanDto));
+//            } catch (IOException e) {
+//                e.printStackTrace();
+//            }
+//        }
+    }
+
+    /**
+     * @param session
+     * @param error
+     */
+    @OnError
+    public void onError(Session session, Throwable error) {
+        log.error("发生错误");
+        error.printStackTrace();
+    }
+
+    public void sendMessage(String message) throws IOException {
+        this.session.getBasicRemote().sendText(message);
+    }
+
+    /**
+     * 群发自定义消息
+     */
+    public static void sendInfo(String message) throws IOException {
+        //群发消息
+        for (WebSocketServer item : webSocketSet) {
+            try {
+                item.sendMessage(message);
+            } catch (IOException e) {
+                continue;
+            }
+        }
+    }
+}

+ 2 - 2
backend/src/main/resources/application.yml

@@ -31,8 +31,8 @@ spring:
 mybatis-plus:
   typeAliasesPackage: com.jiayue.pfr.entity
   configuration:
-#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
-    log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+#    log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
   mapper-locations: classpath:mapper/cmf/*.xml,classpath:mapper/di/*.xml,classpath:mapper/alg/*.xml
   global-config:
     db-column-underline: true

+ 23 - 0
backend/src/main/resources/ehcache-setting.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ehcache>
+  <!-- 指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下 -->
+  <diskStore path="java.io.tmpdir"/>
+
+  <!-- 设定缓存的默认数据过期策略 -->
+  <defaultCache
+    maxElementsInMemory="10000"
+    eternal="false"
+    overflowToDisk="true"
+    diskPersistent="false"
+    diskExpiryThreadIntervalSeconds="120"
+  />
+  <cache name="pfrcache"
+         maxElementsOnDisk="200"
+         maxElementsInMemory="10000"
+         eternal="false"
+         timeToIdleSeconds="120"
+         timeToLiveSeconds="120">
+    <searchable/>
+
+  </cache>
+</ehcache>

+ 27 - 0
backend/src/main/resources/logback-pfr.xml

@@ -65,6 +65,33 @@
     <append>false</append>
   </appender>
 
+  <appender name="F_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
+    <!-- 编码 -->
+    <!--<Encoding>UTF-8</Encoding>-->
+    <!-- 按照时间来 -->
+    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+      <!--日志文件输出的文件名-->
+      <FileNamePattern>${logbase}/%d{yyyy-MM-dd}/frequency.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
+      <!--日志文件保留天数-->
+      <MaxHistory>180</MaxHistory>
+      <maxFileSize>10MB</maxFileSize>
+      <totalSizeCap>1024MB</totalSizeCap>
+      <cleanHistoryOnStart>true</cleanHistoryOnStart>
+    </rollingPolicy>
+    <!-- 布局 -->
+    <encoder>
+      <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
+      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+      <charset>UTF-8</charset>
+    </encoder>
+    <append>false</append>
+  </appender>
+
+  <logger name="FLogger">
+    <level value="info" /><!-- "TRACE", "DEBUG" -->
+    <appender-ref ref="F_LOG" />
+  </logger>
+
   <logger name="com.jiayue" level="info" additivity="true">
     <appender-ref ref="logFile"/>
   </logger>

+ 1 - 1
backend/src/test/java/com/jiayue/pfr/BaseTest.java

@@ -16,7 +16,7 @@ import org.springframework.web.context.WebApplicationContext;
  * @since 2018/10/11 12:47
  */
 @RunWith(SpringJUnit4ClassRunner.class)
-@SpringBootTest(classes = SsiApplication.class, properties = "spring.config.location=classpath:/application.yml")
+@SpringBootTest(classes = PfrApplication.class, properties = "spring.config.location=classpath:/application.yml")
 @WebAppConfiguration(value = "src/main/java")
 //@ContextHierarchy({ @ContextConfiguration(name = "parent", classes = { WebSecurityConfig.class}) })
 //@Transactional

+ 27 - 0
backend/src/test/java/com/jiayue/pfr/Test.java

@@ -0,0 +1,27 @@
+package com.jiayue.pfr;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @author jy
+ * @since 2023/10/30
+ */
+public class Test {
+    public static void main(String[] args) throws Exception{
+        int i=0;
+        while (true){
+            System.out.println(i);
+            int finalI = i;
+            CompletableFuture cf = CompletableFuture.runAsync(()->{
+                new Test().second(finalI);
+            });
+
+            Thread.sleep(1000L);
+            i++;
+        }
+    }
+
+    public void second(int i){
+        System.out.println("第二个方法接收:"+i);
+    }
+}

+ 1 - 1
ui/package.json

@@ -20,7 +20,7 @@
     "axios": "0.24.0",
     "clipboard": "2.0.8",
     "core-js": "3.25.3",
-    "echarts": "5.4.0",
+    "echarts": "^4.8.0",
     "element-ui": "2.15.12",
     "file-saver": "2.0.5",
     "fingerprintjs2": "^2.1.4",

+ 1 - 0
ui/src/main.js

@@ -13,6 +13,7 @@ import App from './App'
 import store from './store'
 import router, {resetRouter} from './router'
 import echarts from 'echarts'
+Vue.prototype.$echarts = echarts
 import '@/icons' // icon
 import '@/permission' // permission control
 import qs from  'qs'

+ 230 - 317
ui/src/views/largeScreen/index.vue

@@ -1,217 +1,263 @@
 <template>
   <div class="largeScreen">
     <div class="topTiltle">
-      <div class="timeBox">运行日:{{ time }}</div>
       <span class="largescreentitle">一次调频系统</span>
       <div class="btuGroup"><span class="topRightBtuBg topRightBtu" style="cursor: pointer;" @click="push()">后台管理</span>
       </div>
     </div>
-    <div class="largeScreen-main-container">
-      <div class="largeScreen-main-top-container">
-        <div class="barBox">
-          <div class="barTitle">
-            <img src="../../assets/largeScreen/tiltleLeftSign.png" height="30px" style="margin-right: 1%">
-            中长期电量
-          </div>
-          <electricity-bar/>
-        </div>
-        <div class="lineStyle"></div>
-        <div class="barBox">
-          <div class="barTitle" style="margin-left: 0px">
-            <img src="../../assets/largeScreen/tiltleLeftSign.png" height="30px" style="margin-right: 1%">
-            月交易电量
-          </div>
-          <day-income/>
-        </div>
-        <div class="lineStyle"></div>
-        <div class="barBox">
-          <div class="barTitle" style="margin-left: 0px">
-            <img src="../../assets/largeScreen/tiltleLeftSign.png" height="30px" style="margin-right: 1%">
-            月发电收益
-          </div>
-          <real-income/>
-        </div>
-        <div class="lineStyle"></div>
-        <div class="barBox">
-          <div class="barTitle" style="margin-left: 0px">
-            <img src="../../assets/largeScreen/tiltleLeftSign.png" height="30px" style="margin-right: 1%">
-            月策略增益
-          </div>
-          <strategy-gain/>
-        </div>
-      </div>
-      <!--  交易流程  -->
-      <div class="largeScreen-main-middle-container">
-        <div class="barTitle" style="margin-top: .5%;margin-left: .5%;">
-          <img src="../../assets/largeScreen/tiltleLeftSign.png" height="30px" style="margin-right: 1%">
-          交易流程
-        </div>
-        <div class="bg">
-          <div style="margin-top:.5%;display: flex;flex-direction: column;justify-content: space-between;height: calc(52vh)">
-            <div>
-              <span style="margin-left: .5%;font-size: 16px;font-weight: bold;text-shadow: 2px 2px 3px #f9e32f;">竞价日(d-1)</span>
-              <div style="display: flex;flex-direction: column;align-items: center">
-                <div
-                  style="width: 98%;height: calc(17vh);display: flex;flex-direction: column;justify-content: space-between;">
-                  <div style="margin-left:18%;margin-top:.5%;display: flex;">
-                    <div class="flowTopBtu topRightBtu" style="margin-left: 2%;cursor: pointer;"
-                         @click="showDialog('市场披露数据','publicData')">获取披露数据
-                    </div>
-                    <div class="flowTopBtu topRightBtu" style="margin-left: 2%;cursor: pointer;"
-                         @click="showDialog('负荷预测分析','loadForecasting')">负荷预测
-                    </div>
-                    <div class="flowTopBtu topRightBtu" style="margin-left: 2%;cursor: pointer;"
-                         @click="showDialog('电价预测分析','paPriceChart')">日前电价预测
-                    </div>
-                    <div class="flowTopBtu topRightBtu" style="margin-left: 2%;cursor: pointer;"
-                         @click="showDialog('日前价差分析','priceDiffAnalysis')">日前策略
-                    </div>
-                    <div class="flowTopBtu topRightBtu" style="margin-left: 2%;cursor: pointer;"
-                         @click="showDialog('短期曲线调整','shortForecastChart')">短期曲线上报
-                    </div>
-                    <div class="flowTopBtu topRightBtu" style="margin-left: 23%;cursor: pointer;"
-                         @click="showDialog('日前收益测算','gainEstimation')">收益评估</div>
-                  </div>
-
-                  <div style="margin-top: 1.5%;display: flex;width: 98%;">
-                    <div class="flowBottomBtu topRightBtu">机组信息申报</div>
-                    <div class="flowBottomBtu topRightBtu" style="margin-left: 2%">发布边界信息</div>
-                    <div class="flowBottomBtu topRightBtu" style="margin-left: 35%">日前交易申报</div>
-                    <div class="flowBottomBtu topRightBtu" style="margin-left: 2%">日前预出清</div>
-                    <div class="flowBottomBtu topRightBtu" style="margin-left: 12%">发布预出清结果</div>
-                  </div>
-                </div>
-              </div>
-            </div>
-
-            <div>
-              <span style="margin-left: .5%;font-size: 16px;font-weight: bold;text-shadow: 2px 2px 3px #f9e32f;">运行日(d)</span>
-              <div style="display: flex;flex-direction: column;align-items: center;">
-                <div
-                  style="width: 98%;height: calc(18vh);display: flex;flex-direction: column;justify-content: space-between;">
-                  <div style="display: flex;justify-content: flex-end;">
-                    <div
-                      style="margin-top: 1.5%;margin-right: 10%;width: 70%;display: flex;flex-direction:row-reverse;">
-                      <div class="flowBottomBtu topRightBtu">获取最新边界条件</div>
-                      <div class="flowBottomBtu topRightBtu" style="margin-right: 30%">实时市场出清计算</div>
-                      <div class="flowBottomBtu topRightBtu" style="margin-right: 5%">发布出清结果</div>
-                    </div>
-                  </div>
-
-                  <div style="display: flex;justify-content: flex-end">
-                    <div
-                      style="width:100%;margin-top: 1%;margin-bottom: .5%;margin-right: 20%;display: flex;flex-direction: row-reverse;">
-                      <div class="flowTopBtu topRightBtu" style="cursor: pointer;"
-                           @click="showDialog('实时电价预测','rtPriceChart')">实时电价预测
-                      </div>
-                      <div class="flowTopBtu topRightBtu" style="margin-right: 5%">交易测算</div>
-                      <div class="flowTopBtu topRightBtu" style="margin-right: 32%;cursor: pointer;"
-                           @click="showDialog('市场披露数据','publicData')">获取披露数据
-                      </div>
-                      <div class="flowTopBtu topRightBtu" style="margin-right: 12%;cursor: pointer;"
-                           @click="showDialog('复盘分析','reviewAnalysis')">复盘分析
-                      </div>
-                    </div>
-                  </div>
-
-                </div>
-              </div>
-            </div>
-          </div>
-
-        </div>
-
-      </div>
-
-      <!--  负荷预测弹框    -->
-      <div class="dialogInfoBg" v-if="dialogShow">
-        <!--   弹框头     -->
-        <div class="rightTiltleTextBg">
-          <div class="rightMainTitle">
-            <span>{{ dialogTitle }}</span>
-            <div @click="dialogShow = false">
-              <img src="../../assets/largeScreen/guanbixiao.png" width="25px" style="cursor: pointer">
-            </div>
-          </div>
-
-        </div>
-        <!--    弹框主体    -->
-        <div>
-          <component :is="componentName"></component>
-        </div>
-      </div>
-    </div>
+    <div id="fline" style="width: 900px;height: 450px"></div>
   </div>
 </template>
 
 <script>
-import electricityBar from './components/electricityBar'
-import dayIncome from './components/dayIncome'
-import realIncome from './components/realIncome'
-import strategyGain from './components/strategyGain'
-import loadForecasting from './components/loadForecasting'
-import paPriceChart from './components/paPriceChart'
-import shortForecastChart from './components/shortForecastChart'
-import publicData from './components/publicData'
-import priceDiffAnalysis from './components/priceDiffAnalysis'
-import gainEstimation from "./components/gainEstimation";
-import reviewAnalysis from "./components/reviewAnalysis";
-import rtPriceChart from "./components/rtPriceChart";
+// import electricityBar from './components/electricityBar'
 
 export default {
   name: "index",
-  components: {
-    electricityBar,
-    dayIncome,
-    realIncome,
-    strategyGain,
-    loadForecasting,
-    paPriceChart,
-    shortForecastChart,
-    publicData,
-    priceDiffAnalysis,
-    gainEstimation,
-    reviewAnalysis,
-    rtPriceChart
-  },
   data() {
     return {
+      fmMinTime:null,
+      fmMaxTime:null,
+      fms:[],
+      activePower:[],
+      datas:[],
+      chart: null,
       time: '',
       dialogTitle: '负载预测',
       dialogShow: false,
-      componentName: 'loadForecasting'
+      componentName: 'loadForecasting',
+      websock: null, //建立的连接
+      lockReconnect: false, //是否真正建立连接
+      timeout: 200, //20秒一次心跳
+      timeoutObj: null, //心跳心跳倒计时
+      serverTimeoutObj: null, //心跳倒计时
+      timeoutnum: null, //断开 重连倒计时
+      fmOption:null
     }
   },
   mounted() {
-    this.formatTime()
-    // this.timer = setInterval(this.formatTime, 1000 * 60)
+    this.init()
+  },
+  created() {
+    // //页面刚进入时开启长连接
+    this.initWebSocket();
+
   },
   destroyed() {
-    clearInterval(this.timer)
-    this.timer = null
+    //页面销毁时关闭长连接
+    clearTimeout(this.timeoutObj);
+    console.log('数据大屏销毁websocket')
+    // console.log('销毁页面')
+    this.websocketclose();
+    this.chart.clear()
   },
   methods: {
-    showDialog(title, componentName) {
-      this.dialogTitle = title
-      this.componentName = componentName
-      this.dialogShow = true
+    init(){
+      let chartDom = document.getElementById('fline');
+      this.chart = this.$echarts.init(chartDom);
+      // this.datas=[["2021-01-04 08:14:42",150], ["2021-01-04 08:14:56.200",230], ["2021-01-04 08:14:56.600",224], ["2021-01-04 08:15:34",218], ["2021-01-04 08:15:50",135], ["2021-01-04 08:16:12",147], ["2021-01-04 08:17:17",260]];
+      // this.fms=[50, 49.8 ,50.1,50, 50,50, 50];
+      // this.fms=[[]]
+      var fmColors= ['#FF0000', '#00FF00']
+      let _this = this
+      this.fmOption= {
+        color: fmColors,
+          title: {
+          text: '有功➖频率实时图',
+            textStyle: {
+            fontSize: 16,
+              color:"#fff"
+          },
+          top: 10,
+            left: 10
+        },
+        legend: {
+          icon:'roundRect',
+            data: ['功率', '频率'],
+            textStyle: {
+            color: "#fff",
+          },
+          selectedMode:false,
+        },
+        grid: {
+          top: '17%',
+            left: '3%',
+            right: '4%',
+            bottom: '8%',
+            containLabel: true
+        },
+        tooltip: {
+          trigger: 'axis',
+            formatter: function(params) {
+            var temp = "";
+            // if (params[0]!=undefined && params[1]!=undefined){
+            //   temp = "时间:"+_this.$echarts.format.formatTime('hh:mm:ss.SSS', params[0].name) + "<br/>" + "有功:" + params[0].data[1]+ " MW<br/>" + "频率:" + params[0].data[1]+" Hz";
+              temp = "时间:"+_this.$echarts.format.formatTime('hh:mm:ss.SSS', params[0].name);
+            // }
+
+            return temp;
+          },
+        },
+        xAxis: {
+          type: 'time',
+            min: this.fmMinTime,
+            max: this.fmMaxTime,
+            interval: 1000*20,
+            axisLine: {
+            lineStyle: {
+              color: "#fff",
+            }
+          },
+          splitLine: {
+            show: false
+          },
+          axisLabel: {
+            formatter: function (value, index) {
+              return _this.$echarts.format.formatTime('hh:mm:ss', value); // 格式为年月日
+            }
+          }
+        },
+        yAxis: [
+          {
+            type: 'value',
+            axisLine: {
+              lineStyle: {
+                color: "#fff",
+              }
+            },
+            position: 'left',
+            name: '功率',
+            min: -1,
+            max: [],
+            interval: 50,
+            axisLabel: {
+              formatter: '{value} MW'
+            },
+          },
+          {
+            type: 'value',
+            axisLine: {
+              lineStyle: {
+                color: "#fff",
+              }
+            },
+            splitLine: {show: false},
+            position: 'right',
+            name: '频率',
+            min: 48,
+            max: 51.5,
+            interval: 0.05,
+            axisLabel: {
+              formatter: '{value} Hz'
+            },
+          },
+
+        ],
+          series: [
+          {
+            name:'功率',
+            data: this.datas,
+            type: 'line',
+            symbol: 'none',
+          },
+          {
+            name:'频率',
+            yAxisIndex: 1,
+            data: this.fms,
+            type: 'line',
+            symbol: 'none',
+            // hoverAnimation: false,
+          },
+        ]
+      }
+
+      this.fmOption.yAxis[0].max=300
+      this.chart.setOption(this.fmOption,true)
     },
     push() {
       this.$router.push({path: "/"})
     },
-    /*时间格式化*/
-    formatTime() {
-      this.time = ''
-      let date = new Date()
-      let year = date.getFullYear();                // 年
-      let month = date.getMonth() + 1;        // 月
-      let day = date.getDate();
-      // let hour = date.getHours();                   // 获取当前小时数(0-23)
-      // let minutes = date.getMinutes();
-      if (month < 10) month = "0" + month;
-      // if (day < 10) day = "0" + day;
-      // if (minutes < 10) minutes = "0" + minutes;
-      this.time = year + "年" + month + "月" + day + "日  ";
+    // 字符串时间转化成时间戳
+    getDateFromString(str) {
+      var reg = /^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/;
+      var temp = str.match(reg);
+      var result = "";
+      if (temp) {
+        result = new Date(temp[1], temp[2] - 1, temp[3], temp[4], temp[5], temp[6]);
+      }
+      return result;
+    },
+
+    initWebSocket() {
+      //建立连接
+      //初始化weosocket
+      // let tokenStr = localStorage.getItem("jy")
+      let visitPort
+      if (process.env.NODE_ENV=='development'){
+        visitPort = '443'
+      }
+      else {
+        visitPort = '443'
+      }
+      let wsuri = 'wss:'+location.host.split(':')[0]+ ':443/websocket/testsocket';
+      //建立连接
+      this.websock = new WebSocket(wsuri);
+      //连接成功
+      this.websock.onopen = this.websocketonopen;
+      //连接错误
+      this.websock.onerror = this.websocketonerror;
+      //接收信息
+      this.websock.onmessage = this.websocketonmessage;
+      //连接关闭
+      this.websock.onclose = this.websocketclose;
+    },
+    start() {
+      //开启心跳
+      var self = this;
+      self.timeoutObj && clearTimeout(self.timeoutObj);
+      // self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj);
+      self.timeoutObj = setTimeout(function() {
+        self.websock.send("heartbeat");
+      }, self.timeout);
+    },
+    websocketonopen() {
+
+    },
+    websocketonerror(e) {
+
+    },
+    websocketclose(e) {
+      console.log("前端连接已关闭");
+      this.websock.close()
+    },
+    websocketonmessage(event) {
+      //接收服务器推送的信息
+      //打印收到服务器的内容
+      // console.log("收到服务器信息",event.data);
+      let data=event.data
+      var tempFm = JSON.parse(data)
+      // 存入频率数组
+      this.fms.push({name: tempFm.time, value: [tempFm.time, tempFm.f]})
+      this.activePower.push({name: tempFm.time, value: [tempFm.time, tempFm.activePower]})
+      if (this.fms.length>600){
+        this.fms.shift()
+        this.activePower.shift()
+      }
+      // 对时间轴最大最小时间更新
+        this.fmMaxTime=tempFm.time
+        let tempTime=new Date(tempFm.time)
+        this.fmMinTime=new Date(tempTime.valueOf()-1000*60*2)
+
+        this.fmOption.xAxis.min=this.fmMinTime
+        this.fmOption.xAxis.max=this.fmMaxTime
+
+        this.fmOption.series[0].data=this.activePower
+        this.fmOption.series[1].data=this.fms
+        this.chart.setOption(this.fmOption,true)
+    },
+    websocketsend(msg) {
+      //向服务器发送信息
+      this.websock.send(msg);
     }
   }
 }
@@ -254,15 +300,6 @@ export default {
   color: transparent;
 }
 
-.timeBox {
-  position: absolute;
-  left: 2%;
-  top: 0;
-  font-size: 20px;
-  line-height: 40px;
-  font-family: timeFont !important;
-}
-
 .btuGroup {
   position: absolute;
   right: 0;
@@ -281,12 +318,6 @@ export default {
   height: 50px;
 }
 
-.bg {
-  background: url(../../assets/largeScreen/line.png) 100% no-repeat;
-  background-size: 100% 100%;
-  height: 90%;
-}
-
 .topRightBtu {
   display: flex;
   align-items: center;
@@ -311,15 +342,6 @@ export default {
   justify-content: space-around;
 }
 
-.largeScreen-main-middle-container {
-  margin-top: 1%;
-  width: 98%;
-  height: calc(58vh);
-  border-width: 1px;
-  border-radius: 5px;
-  border-color: aqua;
-  box-shadow: 1px 0px 10px 2px aqua
-}
 
 .lineStyle {
   width: 1px;
@@ -342,117 +364,8 @@ export default {
   margin-top: 1.5%;
 }
 
-.arrow {
-  background-image: url("../../assets/largeScreen/arrow.gif");
-  width: 48px;
-  height: 48px;
-  transform: scale(.5);
-  position: absolute;
-  left: 87%
-}
-
-.lineDiv {
-  width: 25%;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  position: relative
-}
-
-.jiantou {
-  background-image: url("../../assets/largeScreen/jiantou.png");
-  width: 200px;
-  height: 200px;
-  transform: scale(.17);
-  position: absolute;
-  left: 40%;
-}
-
-.arrowLeft {
-  background-image: url("../../assets/largeScreen/arrowLeft.png");
-  width: 200px;
-  height: 200px;
-  transform: scale(.17);
-  position: absolute;
-  left: 30%;
-}
-
-.arrowDown {
-  background-image: url("../../assets/largeScreen/arrowDown.png");
-  width: 200px;
-  height: 200px;
-  transform: scale(.17);
-}
-
-.arrowUpper {
-  background-image: url("../../assets/largeScreen/arrowUpper.png");
-  width: 200px;
-  height: 200px;
-  transform: scale(.17);
-}
-
-.solidLine {
-  width: 100%;
-  height: 1px;
-  border-width: 1px;
-  border-style: solid;
-  border-color: aqua
-}
-
-.dashedLine {
-  width: 200px;
-  height: 1px;
-  border-width: 1px;
-  border-style: dashed;
-  border-color: aqua
-}
-
-.flowBottomBtu {
-  width: 170px;
-  height: 40px;
-  font-size: 18px;
-  font-weight: bold;
-  border: 0.5px solid #2fff82;
-  box-shadow: inset rgb(0 255 234) -1px 0px 17px;
-}
-
-.flowTopBtu {
-  width: 130px;
-  height: 40px;
-  font-size: 18px;
-  font-weight: bold;
-  border: 0.5px solid #ffc92f;
-  box-shadow: inset rgb(255 207 0) -1px 0px 16px;
-}
 
-.dialogInfoBg {
-  /*background: url(../../assets/largeScreen/dialogBg.png) 100% no-repeat;*/
-  /*background-size: 100% 100%;*/
-  background: rgb(1 30 40);
-  box-shadow: inset 0px 0px 11px 3px #01f4f475;
-  padding: 1%;
-  width: 55%;
-  position: absolute;
-  top: 20%;
-  left: 22%;
-}
 
-.rightTiltleTextBg {
-  height: 32px;
-  background: url(../../assets/largeScreen/leftTitleBg.png) 100% no-repeat;
-  background-size: 100% 100%;
-}
-
-.rightMainTitle {
-  color: rgb(144, 226, 255);
-  font-size: 20px;
-  font-weight: 550;
-  margin-left: 8%;
-  position: relative;
-  top: -25%;
-  display: flex;
-  justify-content: space-between;
-}
 
 @font-face {
   font-family: timeFont;

+ 2 - 2
ui/src/views/login/index.vue

@@ -133,7 +133,7 @@ export default {
             Fingerprint2.getV18(function (result) {
               resolve(result)
             })
-          }, 500)
+          }, 100)
         }
       })
     },
@@ -149,7 +149,7 @@ export default {
         this.captchaText = res.data.captchaText
       }).catch((error) => {
       })
-    }, 1000),
+    }, 300),
     updateCaptcha() {
       // 更新验证码
       this.getCaptcha()