Commit ff6c5ef57dbca0b883905c9a1aff3d6a488e1965

Authored by 王鑫
1 parent 5077713e

fix():添加FTP配置,添加历史视频回放在多人情况下的友好提示

Showing 52 changed files with 2446 additions and 712 deletions
@@ -95,6 +95,19 @@ @@ -95,6 +95,19 @@
95 </profiles> 95 </profiles>
96 96
97 <dependencies> 97 <dependencies>
  98 + <!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
  99 + <dependency>
  100 + <groupId>commons-net</groupId>
  101 + <artifactId>commons-net</artifactId>
  102 + <version>3.9.0</version>
  103 + </dependency>
  104 +
  105 + <!-- hutool -->
  106 + <dependency>
  107 + <groupId>cn.hutool</groupId>
  108 + <artifactId>hutool-all</artifactId>
  109 + <version>5.7.22</version>
  110 + </dependency>
98 <dependency> 111 <dependency>
99 <groupId>org.springframework.boot</groupId> 112 <groupId>org.springframework.boot</groupId>
100 <artifactId>spring-boot-starter-data-redis</artifactId> 113 <artifactId>spring-boot-starter-data-redis</artifactId>
@@ -176,13 +189,6 @@ @@ -176,13 +189,6 @@
176 <scope>system</scope> 189 <scope>system</scope>
177 <systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath> 190 <systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath>
178 </dependency> 191 </dependency>
179 - <dependency>  
180 - <groupId>com.kingbase</groupId>  
181 - <artifactId>kingbase8</artifactId>  
182 - <version>8.6.0</version>  
183 - <scope>system</scope>  
184 - <systemPath>${basedir}/libs/jdbc-x86/kingbase8-8.6.0.jar</systemPath>  
185 - </dependency>  
186 192
187 <!--Mybatis分页插件 --> 193 <!--Mybatis分页插件 -->
188 <dependency> 194 <dependency>
@@ -210,14 +216,6 @@ @@ -210,14 +216,6 @@
210 <version>3.6.1</version> 216 <version>3.6.1</version>
211 </dependency> 217 </dependency>
212 218
213 -  
214 - <!--在线文档 -->  
215 - <dependency>  
216 - <groupId>org.springdoc</groupId>  
217 - <artifactId>springdoc-openapi-ui</artifactId>  
218 - <version>1.6.10</version>  
219 - </dependency>  
220 -  
221 <dependency> 219 <dependency>
222 <groupId>com.github.xiaoymin</groupId> 220 <groupId>com.github.xiaoymin</groupId>
223 <artifactId>knife4j-springdoc-ui</artifactId> 221 <artifactId>knife4j-springdoc-ui</artifactId>
@@ -290,12 +288,6 @@ @@ -290,12 +288,6 @@
290 <version>2.7</version> 288 <version>2.7</version>
291 </dependency> 289 </dependency>
292 290
293 - <dependency>  
294 - <groupId>com.xiaoleilu</groupId>  
295 - <artifactId>hutool-all</artifactId>  
296 - <version>3.1.0</version>  
297 - </dependency>  
298 -  
299 <!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 --> 291 <!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 -->
300 <!-- <dependency>--> 292 <!-- <dependency>-->
301 <!-- <groupId>net.sf.kxml</groupId>--> 293 <!-- <groupId>net.sf.kxml</groupId>-->
@@ -361,12 +353,6 @@ @@ -361,12 +353,6 @@
361 <artifactId>guava</artifactId> 353 <artifactId>guava</artifactId>
362 <version>32.1.3-jre</version> 354 <version>32.1.3-jre</version>
363 </dependency> 355 </dependency>
364 -  
365 - <dependency>  
366 - <groupId>org.springframework.boot</groupId>  
367 - <artifactId>spring-boot-starter-test</artifactId>  
368 - <scope>test</scope>  
369 - </dependency>  
370 </dependencies> 356 </dependencies>
371 357
372 <build> 358 <build>
src/main/java/com/genersoft/iot/vmp/TCPClient.java
@@ -7,7 +7,7 @@ import java.net.Socket; @@ -7,7 +7,7 @@ import java.net.Socket;
7 public class TCPClient { 7 public class TCPClient {
8 public static void main(String[] args) throws Exception{ 8 public static void main(String[] args) throws Exception{
9 //创建socket,并指定连接的是本机的端口号为65000的服务器socket 9 //创建socket,并指定连接的是本机的端口号为65000的服务器socket
10 - Socket socket = new Socket("118.113.164.50",3333); 10 + Socket socket = new Socket("61.169.120.202",40000);
11 //获取输出流 11 //获取输出流
12 OutputStream os = socket.getOutputStream(); 12 OutputStream os = socket.getOutputStream();
13 //获取输入流 13 //获取输入流
src/main/java/com/genersoft/iot/vmp/TCPServer.java
@@ -6,7 +6,7 @@ import java.net.Socket; @@ -6,7 +6,7 @@ import java.net.Socket;
6 public class TCPServer { 6 public class TCPServer {
7 public static void main(String[] args) throws Exception{ 7 public static void main(String[] args) throws Exception{
8 //创建socket,并将socket绑定到65000端口 8 //创建socket,并将socket绑定到65000端口
9 - ServerSocket ss = new ServerSocket(30020); 9 + ServerSocket ss = new ServerSocket(30000);
10 //死循环,使得socket一直等待并处理客户端发送过来的请求 10 //死循环,使得socket一直等待并处理客户端发送过来的请求
11 while(true){ 11 while(true){
12 //监听65000端口,直到客户端返回连接信息后才返回 12 //监听65000端口,直到客户端返回连接信息后才返回
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -60,7 +60,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @@ -60,7 +60,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
60 @Autowired 60 @Autowired
61 private JwtAuthenticationFilter jwtAuthenticationFilter; 61 private JwtAuthenticationFilter jwtAuthenticationFilter;
62 62
63 - public static final List<String> ALLOWED_IPS = Arrays.asList("192.169.1.88", "127.0.0.1"); 63 + public static final List<String> ALLOWED_IPS = Arrays.asList("192.169.1.97", "127.0.0.1");
64 64
65 65
66 /** 66 /**
src/main/java/com/genersoft/iot/vmp/jtt1078/app/VideoServerApp.java
1 package com.genersoft.iot.vmp.jtt1078.app; 1 package com.genersoft.iot.vmp.jtt1078.app;
2 2
  3 +import cn.hutool.core.collection.ConcurrentHashSet;
3 import com.genersoft.iot.vmp.jtt1078.http.GeneralResponseWriter; 4 import com.genersoft.iot.vmp.jtt1078.http.GeneralResponseWriter;
4 import com.genersoft.iot.vmp.jtt1078.http.NettyHttpServerHandler; 5 import com.genersoft.iot.vmp.jtt1078.http.NettyHttpServerHandler;
5 import com.genersoft.iot.vmp.jtt1078.publisher.PublishManager; 6 import com.genersoft.iot.vmp.jtt1078.publisher.PublishManager;
@@ -7,7 +8,6 @@ import com.genersoft.iot.vmp.jtt1078.server.Jtt1078Handler; @@ -7,7 +8,6 @@ import com.genersoft.iot.vmp.jtt1078.server.Jtt1078Handler;
7 import com.genersoft.iot.vmp.jtt1078.server.Jtt1078MessageDecoder; 8 import com.genersoft.iot.vmp.jtt1078.server.Jtt1078MessageDecoder;
8 import com.genersoft.iot.vmp.jtt1078.server.SessionManager; 9 import com.genersoft.iot.vmp.jtt1078.server.SessionManager;
9 import com.genersoft.iot.vmp.jtt1078.util.Configs; 10 import com.genersoft.iot.vmp.jtt1078.util.Configs;
10 -import com.xiaoleilu.hutool.collection.ConcurrentHashSet;  
11 import io.netty.bootstrap.ServerBootstrap; 11 import io.netty.bootstrap.ServerBootstrap;
12 import io.netty.channel.*; 12 import io.netty.channel.*;
13 import io.netty.channel.nio.NioEventLoopGroup; 13 import io.netty.channel.nio.NioEventLoopGroup;
src/main/java/com/genersoft/iot/vmp/jtt1078/server/Jtt1078Handler.java
@@ -17,7 +17,10 @@ import org.springframework.context.ApplicationContext; @@ -17,7 +17,10 @@ import org.springframework.context.ApplicationContext;
17 import org.springframework.data.redis.core.StringRedisTemplate; 17 import org.springframework.data.redis.core.StringRedisTemplate;
18 18
19 import java.math.BigDecimal; 19 import java.math.BigDecimal;
  20 +import java.text.SimpleDateFormat;
  21 +import java.util.Date;
20 import java.util.Set; 22 import java.util.Set;
  23 +import java.util.concurrent.ConcurrentHashMap;
21 import java.util.concurrent.TimeUnit; 24 import java.util.concurrent.TimeUnit;
22 25
23 import static com.genersoft.iot.vmp.VManageBootstrap.getBean; 26 import static com.genersoft.iot.vmp.VManageBootstrap.getBean;
@@ -25,13 +28,18 @@ import static com.genersoft.iot.vmp.VManageBootstrap.getBean; @@ -25,13 +28,18 @@ import static com.genersoft.iot.vmp.VManageBootstrap.getBean;
25 /** 28 /**
26 * Created by matrixy on 2019/4/9. 29 * Created by matrixy on 2019/4/9.
27 */ 30 */
28 -public class Jtt1078Handler extends SimpleChannelInboundHandler<Packet>  
29 -{ 31 +public class Jtt1078Handler extends SimpleChannelInboundHandler<Packet> {
30 private static ApplicationContext applicationContext; 32 private static ApplicationContext applicationContext;
31 static Logger logger = LoggerFactory.getLogger(Jtt1078Handler.class); 33 static Logger logger = LoggerFactory.getLogger(Jtt1078Handler.class);
32 private static final AttributeKey<Session> SESSION_KEY = AttributeKey.valueOf("session-key"); 34 private static final AttributeKey<Session> SESSION_KEY = AttributeKey.valueOf("session-key");
33 private Integer port; 35 private Integer port;
34 36
  37 + private String time;
  38 +
  39 + private static final DataBuffer simFlowDataBuffer = getBean(DataBuffer.class);
  40 +
  41 + private static final ConcurrentHashMap<String, SimFlow> sizeMap = new ConcurrentHashMap<>();
  42 +
35 public Jtt1078Handler(Integer port) { 43 public Jtt1078Handler(Integer port) {
36 this.port = port; 44 this.port = port;
37 } 45 }
@@ -43,37 +51,51 @@ public class Jtt1078Handler extends SimpleChannelInboundHandler&lt;Packet&gt; @@ -43,37 +51,51 @@ public class Jtt1078Handler extends SimpleChannelInboundHandler&lt;Packet&gt;
43 * 流来 51 * 流来
44 */ 52 */
45 @Override 53 @Override
46 - protected void channelRead0(ChannelHandlerContext ctx, Packet packet) throws Exception  
47 - { 54 + protected void channelRead0(ChannelHandlerContext ctx, Packet packet) throws Exception {
48 io.netty.channel.Channel nettyChannel = ctx.channel(); 55 io.netty.channel.Channel nettyChannel = ctx.channel();
49 packet.seek(8); 56 packet.seek(8);
50 String sim = packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD(); 57 String sim = packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD();
51 int channel = packet.nextByte() & 0xff; 58 int channel = packet.nextByte() & 0xff;
52 String tag = sim + "-" + channel; 59 String tag = sim + "-" + channel;
53 tag = tag.replaceAll("^0+", ""); 60 tag = tag.replaceAll("^0+", "");
54 - if (port != null){ 61 + if (port != null) {
55 Set<String> set = Jt1078OfCarController.map.get(port); 62 Set<String> set = Jt1078OfCarController.map.get(port);
56 String findSet = Jt1078OfCarController.getFindSet(set, tag); 63 String findSet = Jt1078OfCarController.getFindSet(set, tag);
57 - if (findSet != null){ 64 + if (findSet != null) {
58 tag = findSet + "_" + port; 65 tag = findSet + "_" + port;
59 - }else { 66 + } else {
60 return; 67 return;
61 } 68 }
62 } 69 }
63 StringRedisTemplate redisTemplate = getBean(StringRedisTemplate.class); 70 StringRedisTemplate redisTemplate = getBean(StringRedisTemplate.class);
64 - if (redisTemplate.opsForSet().add("tag:" + tag, tag) > 0){ 71 + if (redisTemplate.opsForSet().add("tag:" + tag, tag) > 0) {
65 redisTemplate.expire("tag:" + tag, 60, TimeUnit.SECONDS); 72 redisTemplate.expire("tag:" + tag, 60, TimeUnit.SECONDS);
66 - logger.info("[ {} ] --> 流接收成功 ",tag);  
67 - }else { 73 + logger.info("[ {} ] --> 流接收成功 ", tag);
  74 + } else {
68 redisTemplate.expire("tag:" + tag, 60, TimeUnit.SECONDS); 75 redisTemplate.expire("tag:" + tag, 60, TimeUnit.SECONDS);
69 } 76 }
70 - double num = new BigDecimal(packet.size()).divide(new BigDecimal(1024 * 1024 * 1024), 10, BigDecimal.ROUND_HALF_UP).doubleValue();  
71 - DataBuffer simFlowDataBuffer = getBean(DataBuffer.class);  
72 - if (simFlowDataBuffer != null) {  
73 - simFlowDataBuffer.setValue(SimFlow.build(sim,String.valueOf(channel),num)); 77 + String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
  78 +
  79 + String key = sim + "-" + channel;
  80 + if (sizeMap.containsKey(key)){
  81 + SimFlow simFlow = sizeMap.get(key);
  82 + simFlow.setFlow(simFlow.getFlow() + packet.size());
  83 + simFlow.setCount(simFlow.getCount() + 1);
  84 + }else {
  85 + sizeMap.put(key, SimFlow.builder().sim(sim).count(1).flow((long) packet.size()).channel(channel).time(format).build());
74 } 86 }
75 - if (SessionManager.contains(nettyChannel, "tag") == false)  
76 - { 87 + if (time == null || !time.equals(format)) {
  88 + time = format;
  89 + sizeMap.entrySet().forEach(entry -> {
  90 + SimFlow value = entry.getValue();
  91 + logger.debug("{} === {}次 === {} 流来的大小 {} ", value.getTime(), value.getCount(), value.getSim() + "-" + value.getChannel(), value.getFlow());
  92 + if (simFlowDataBuffer != null) {
  93 + simFlowDataBuffer.setValue(value);
  94 + }
  95 + });
  96 + sizeMap.clear();
  97 + }
  98 + if (SessionManager.contains(nettyChannel, "tag") == false) {
77 Channel chl = PublishManager.getInstance().open(tag); 99 Channel chl = PublishManager.getInstance().open(tag);
78 SessionManager.set(nettyChannel, "tag", tag); 100 SessionManager.set(nettyChannel, "tag", tag);
79 logger.info("start publishing: {} -> {}-{}", Long.toHexString(chl.hashCode() & 0xffffffffL), sim, channel); 101 logger.info("start publishing: {} -> {}-{}", Long.toHexString(chl.hashCode() & 0xffffffffL), sim, channel);
@@ -92,19 +114,15 @@ public class Jtt1078Handler extends SimpleChannelInboundHandler&lt;Packet&gt; @@ -92,19 +114,15 @@ public class Jtt1078Handler extends SimpleChannelInboundHandler&lt;Packet&gt;
92 114
93 int pt = packet.seek(5).nextByte() & 0x7f; 115 int pt = packet.seek(5).nextByte() & 0x7f;
94 116
95 - if (dataType == 0x00 || dataType == 0x01 || dataType == 0x02)  
96 - { 117 + if (dataType == 0x00 || dataType == 0x01 || dataType == 0x02) {
97 // 碰到结束标记时,序号+1 118 // 碰到结束标记时,序号+1
98 - if (pkType == 0 || pkType == 2)  
99 - { 119 + if (pkType == 0 || pkType == 2) {
100 sequence += 1; 120 sequence += 1;
101 SessionManager.set(nettyChannel, "video-sequence", sequence); 121 SessionManager.set(nettyChannel, "video-sequence", sequence);
102 } 122 }
103 long timestamp = packet.seek(16).nextLong(); 123 long timestamp = packet.seek(16).nextLong();
104 PublishManager.getInstance().publishVideo(tag, sequence, timestamp, pt, packet.seek(lengthOffset + 2).nextBytes()); 124 PublishManager.getInstance().publishVideo(tag, sequence, timestamp, pt, packet.seek(lengthOffset + 2).nextBytes());
105 - }  
106 - else if (dataType == 0x03)  
107 - { 125 + } else if (dataType == 0x03) {
108 long timestamp = packet.seek(16).nextLong(); 126 long timestamp = packet.seek(16).nextLong();
109 byte[] data = packet.seek(lengthOffset + 2).nextBytes(); 127 byte[] data = packet.seek(lengthOffset + 2).nextBytes();
110 PublishManager.getInstance().publishAudio(tag, sequence, timestamp, pt, data); 128 PublishManager.getInstance().publishAudio(tag, sequence, timestamp, pt, data);
@@ -112,15 +130,13 @@ public class Jtt1078Handler extends SimpleChannelInboundHandler&lt;Packet&gt; @@ -112,15 +130,13 @@ public class Jtt1078Handler extends SimpleChannelInboundHandler&lt;Packet&gt;
112 } 130 }
113 131
114 @Override 132 @Override
115 - public void channelInactive(ChannelHandlerContext ctx) throws Exception  
116 - { 133 + public void channelInactive(ChannelHandlerContext ctx) throws Exception {
117 super.channelInactive(ctx); 134 super.channelInactive(ctx);
118 release(ctx.channel()); 135 release(ctx.channel());
119 } 136 }
120 137
121 @Override 138 @Override
122 - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception  
123 - { 139 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
124 // super.exceptionCaught(ctx, cause); 140 // super.exceptionCaught(ctx, cause);
125 cause.printStackTrace(); 141 cause.printStackTrace();
126 release(ctx.channel()); 142 release(ctx.channel());
@@ -133,17 +149,15 @@ public class Jtt1078Handler extends SimpleChannelInboundHandler&lt;Packet&gt; @@ -133,17 +149,15 @@ public class Jtt1078Handler extends SimpleChannelInboundHandler&lt;Packet&gt;
133 IdleStateEvent event = (IdleStateEvent) evt; 149 IdleStateEvent event = (IdleStateEvent) evt;
134 if (event.state() == IdleState.READER_IDLE) { 150 if (event.state() == IdleState.READER_IDLE) {
135 String tag = SessionManager.get(ctx.channel(), "tag"); 151 String tag = SessionManager.get(ctx.channel(), "tag");
136 - logger.info("read timeout: {}",tag); 152 + logger.info("read timeout: {}", tag);
137 release(ctx.channel()); 153 release(ctx.channel());
138 } 154 }
139 } 155 }
140 } 156 }
141 157
142 - private void release(io.netty.channel.Channel channel)  
143 - { 158 + private void release(io.netty.channel.Channel channel) {
144 String tag = SessionManager.get(channel, "tag"); 159 String tag = SessionManager.get(channel, "tag");
145 - if (tag != null)  
146 - { 160 + if (tag != null) {
147 logger.info("close netty channel: {}", tag); 161 logger.info("close netty channel: {}", tag);
148 PublishManager.getInstance().close(tag); 162 PublishManager.getInstance().close(tag);
149 } 163 }
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/Jt1078OfCarController.java
@@ -12,6 +12,8 @@ import com.alibaba.fastjson2.JSONObject; @@ -12,6 +12,8 @@ import com.alibaba.fastjson2.JSONObject;
12 import com.genersoft.iot.vmp.conf.MediaConfig; 12 import com.genersoft.iot.vmp.conf.MediaConfig;
13 import com.genersoft.iot.vmp.conf.StreamProxyTask; 13 import com.genersoft.iot.vmp.conf.StreamProxyTask;
14 import com.genersoft.iot.vmp.conf.exception.ControllerException; 14 import com.genersoft.iot.vmp.conf.exception.ControllerException;
  15 +import com.genersoft.iot.vmp.conf.security.JwtUtils;
  16 +import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
15 import com.genersoft.iot.vmp.jtt1078.app.VideoServerApp; 17 import com.genersoft.iot.vmp.jtt1078.app.VideoServerApp;
16 import com.genersoft.iot.vmp.jtt1078.publisher.PublishManager; 18 import com.genersoft.iot.vmp.jtt1078.publisher.PublishManager;
17 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; 19 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
@@ -26,7 +28,6 @@ import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.Jt1078ConfigBean; @@ -26,7 +28,6 @@ import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.Jt1078ConfigBean;
26 import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.RtspConfigBean; 28 import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.RtspConfigBean;
27 import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.TuohuaConfigBean; 29 import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.TuohuaConfigBean;
28 import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.PatrolDataReq; 30 import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.PatrolDataReq;
29 -import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow;  
30 import com.genersoft.iot.vmp.vmanager.jt1078.platform.handler.HttpClientUtil; 31 import com.genersoft.iot.vmp.vmanager.jt1078.platform.handler.HttpClientUtil;
31 import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.FlowService; 32 import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.FlowService;
32 import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.Jt1078OfService; 33 import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.Jt1078OfService;
@@ -43,10 +44,7 @@ import org.slf4j.Logger; @@ -43,10 +44,7 @@ import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory; 44 import org.slf4j.LoggerFactory;
44 import org.springframework.beans.factory.annotation.Autowired; 45 import org.springframework.beans.factory.annotation.Autowired;
45 import org.springframework.beans.factory.annotation.Value; 46 import org.springframework.beans.factory.annotation.Value;
46 -import org.springframework.data.redis.core.Cursor;  
47 -import org.springframework.data.redis.core.RedisCallback;  
48 import org.springframework.data.redis.core.RedisTemplate; 47 import org.springframework.data.redis.core.RedisTemplate;
49 -import org.springframework.data.redis.core.ScanOptions;  
50 import org.springframework.util.Base64Utils; 48 import org.springframework.util.Base64Utils;
51 import org.springframework.web.bind.annotation.*; 49 import org.springframework.web.bind.annotation.*;
52 import sun.misc.Signal; 50 import sun.misc.Signal;
@@ -54,6 +52,7 @@ import sun.misc.SignalHandler; @@ -54,6 +52,7 @@ import sun.misc.SignalHandler;
54 52
55 import javax.annotation.Resource; 53 import javax.annotation.Resource;
56 import javax.crypto.Cipher; 54 import javax.crypto.Cipher;
  55 +import javax.servlet.http.HttpServletRequest;
57 import javax.validation.constraints.NotBlank; 56 import javax.validation.constraints.NotBlank;
58 import java.io.ByteArrayOutputStream; 57 import java.io.ByteArrayOutputStream;
59 import java.io.IOException; 58 import java.io.IOException;
@@ -109,7 +108,7 @@ public class Jt1078OfCarController { @@ -109,7 +108,7 @@ public class Jt1078OfCarController {
109 //存储历史端口 key -->端口 value ---> sim-channel-startTime-endTime-port 108 //存储历史端口 key -->端口 value ---> sim-channel-startTime-endTime-port
110 public static final ConcurrentHashMap<Integer, Set<String>> map = new ConcurrentHashMap<>(); 109 public static final ConcurrentHashMap<Integer, Set<String>> map = new ConcurrentHashMap<>();
111 110
112 - private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,40,TimeUnit.SECONDS,new ArrayBlockingQueue<>(10)); 111 + private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 40, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
113 112
114 @Value("${spring.profiles.active}") 113 @Value("${spring.profiles.active}")
115 private String profilesActive; 114 private String profilesActive;
@@ -118,11 +117,6 @@ public class Jt1078OfCarController { @@ -118,11 +117,6 @@ public class Jt1078OfCarController {
118 public Jt1078OfCarController() { 117 public Jt1078OfCarController() {
119 } 118 }
120 119
121 - @GetMapping("/flow/countList/{timeType}/{statisticsType}/{time}")  
122 - public Map<String, SimFlow> flowCountList(@PathVariable String statisticsType, @PathVariable String time, @PathVariable String timeType) {  
123 - return flowService.getList(timeType, statisticsType, time);  
124 - }  
125 -  
126 @GetMapping({"/company/tree"}) 120 @GetMapping({"/company/tree"})
127 public Map<String, Object> requestTreeOfCompany() { 121 public Map<String, Object> requestTreeOfCompany() {
128 Map<String, Object> resultMap = new HashMap(); 122 Map<String, Object> resultMap = new HashMap();
@@ -154,6 +148,7 @@ public class Jt1078OfCarController { @@ -154,6 +148,7 @@ public class Jt1078OfCarController {
154 return resultMap; 148 return resultMap;
155 } 149 }
156 150
  151 +
157 /** 152 /**
158 * redis清除在线车辆 153 * redis清除在线车辆
159 */ 154 */
@@ -163,8 +158,10 @@ public class Jt1078OfCarController { @@ -163,8 +158,10 @@ public class Jt1078OfCarController {
163 redisTemplate.delete(carId); 158 redisTemplate.delete(carId);
164 } 159 }
165 } 160 }
  161 +
166 /** 162 /**
167 * redis存储在线车辆 163 * redis存储在线车辆
  164 + *
168 * @param linesCars 165 * @param linesCars
169 */ 166 */
170 public HashMap<String, Object> storageRedisTree(List<HashMap<String, Object>> linesCars) { 167 public HashMap<String, Object> storageRedisTree(List<HashMap<String, Object>> linesCars) {
@@ -214,6 +211,7 @@ public class Jt1078OfCarController { @@ -214,6 +211,7 @@ public class Jt1078OfCarController {
214 211
215 /** 212 /**
216 * 请求设备推送流 213 * 请求设备推送流
  214 + *
217 * @param sim sim号 215 * @param sim sim号
218 * @param channel 通道号 216 * @param channel 通道号
219 * @return 217 * @return
@@ -221,14 +219,14 @@ public class Jt1078OfCarController { @@ -221,14 +219,14 @@ public class Jt1078OfCarController {
221 @GetMapping({"/send/request/io/{sim}/{channel}"}) 219 @GetMapping({"/send/request/io/{sim}/{channel}"})
222 public StreamContent sendIORequest(@PathVariable String sim, @PathVariable String channel) { 220 public StreamContent sendIORequest(@PathVariable String sim, @PathVariable String channel) {
223 if (StringUtils.isBlank(sim)) { 221 if (StringUtils.isBlank(sim)) {
224 - throw new ControllerException(-100,"sim 不能为空"); 222 + throw new ControllerException(-100, "sim 不能为空");
225 } 223 }
226 if (StringUtils.isBlank(channel)) { 224 if (StringUtils.isBlank(channel)) {
227 throw new ControllerException(-100, "channel 不能为空"); 225 throw new ControllerException(-100, "channel 不能为空");
228 } 226 }
229 String stream = StringUtils.join(new String[]{sim, "-", channel}); 227 String stream = StringUtils.join(new String[]{sim, "-", channel});
230 StreamContent streamContent = getStreamContentPlayURL(stream); 228 StreamContent streamContent = getStreamContentPlayURL(stream);
231 - if (Objects.isNull(streamContent) || StringUtils.isBlank(streamContent.getWs_flv())){ 229 + if (Objects.isNull(streamContent) || StringUtils.isBlank(streamContent.getWs_flv())) {
232 sendIORequest(stream); 230 sendIORequest(stream);
233 } 231 }
234 streamContent = getStreamContent(stream); 232 streamContent = getStreamContent(stream);
@@ -239,6 +237,7 @@ public class Jt1078OfCarController { @@ -239,6 +237,7 @@ public class Jt1078OfCarController {
239 237
240 /** 238 /**
241 * 批量请求设备推送流 239 * 批量请求设备推送流
  240 + *
242 * @param streamList 流唯一值集合 {sim-channel} 241 * @param streamList 流唯一值集合 {sim-channel}
243 */ 242 */
244 @PostMapping({"/beachSend/request/io"}) 243 @PostMapping({"/beachSend/request/io"})
@@ -256,6 +255,7 @@ public class Jt1078OfCarController { @@ -256,6 +255,7 @@ public class Jt1078OfCarController {
256 255
257 /** 256 /**
258 * 视频巡查功能开启 257 * 视频巡查功能开启
  258 + *
259 * @param PatrolDataReqList 视频巡查请求对象 259 * @param PatrolDataReqList 视频巡查请求对象
260 */ 260 */
261 @PostMapping({"/startPatrol/request/io"}) 261 @PostMapping({"/startPatrol/request/io"})
@@ -278,13 +278,14 @@ public class Jt1078OfCarController { @@ -278,13 +278,14 @@ public class Jt1078OfCarController {
278 * 关闭视频巡查 (必须在关闭按钮后关闭,否则流量在一直消耗) 278 * 关闭视频巡查 (必须在关闭按钮后关闭,否则流量在一直消耗)
279 */ 279 */
280 @GetMapping("/stopPatrol/request/io") 280 @GetMapping("/stopPatrol/request/io")
281 - public void stopPatrol(){ 281 + public void stopPatrol() {
282 Set<Object> keys = redisTemplate.keys("patrol:stream:*"); 282 Set<Object> keys = redisTemplate.keys("patrol:stream:*");
283 redisTemplate.delete(keys); 283 redisTemplate.delete(keys);
284 } 284 }
285 285
286 /** 286 /**
287 * 获取播放地址对外接口 287 * 获取播放地址对外接口
  288 + *
288 * @param sim 289 * @param sim
289 * @param channel 290 * @param channel
290 * @return 291 * @return
@@ -292,7 +293,7 @@ public class Jt1078OfCarController { @@ -292,7 +293,7 @@ public class Jt1078OfCarController {
292 @PostMapping("/send/request/getPlay") 293 @PostMapping("/send/request/getPlay")
293 public Object sendGetPlay(@RequestParam String sim, @RequestParam String channel) { 294 public Object sendGetPlay(@RequestParam String sim, @RequestParam String channel) {
294 if (StringUtils.isBlank(sim)) { 295 if (StringUtils.isBlank(sim)) {
295 - throw new ControllerException(-100,"sim 不能为空"); 296 + throw new ControllerException(-100, "sim 不能为空");
296 } 297 }
297 if (StringUtils.isBlank(channel)) { 298 if (StringUtils.isBlank(channel)) {
298 throw new ControllerException(-100, "channel 不能为空"); 299 throw new ControllerException(-100, "channel 不能为空");
@@ -302,21 +303,21 @@ public class Jt1078OfCarController { @@ -302,21 +303,21 @@ public class Jt1078OfCarController {
302 StreamPushItem streamPushItem = streamPushController.getStreamPushItem(sim, channel); 303 StreamPushItem streamPushItem = streamPushController.getStreamPushItem(sim, channel);
303 StreamContent playUrl = null; 304 StreamContent playUrl = null;
304 if (null != streamPushItem) { 305 if (null != streamPushItem) {
305 - playUrl = streamPushController.getPlayUrl(streamPushItem.getApp(), stream, streamPushItem.getMediaServerId());  
306 - if (playUrl != null){  
307 - return StreamPlayPath.build(playUrl,stream); 306 + playUrl = streamPushController.getPlayUrl(streamPushItem.getApp(), stream, streamPushItem.getMediaServerId());
  307 + if (playUrl != null) {
  308 + return StreamPlayPath.build(playUrl, stream);
308 } 309 }
309 } 310 }
310 HashMap<String, Object> resultMap = new HashMap<>(); 311 HashMap<String, Object> resultMap = new HashMap<>();
311 - sendIORequest(stream); 312 + sendIORequest(stream);
312 try { 313 try {
313 Thread.sleep(4000); 314 Thread.sleep(4000);
314 } catch (InterruptedException e) { 315 } catch (InterruptedException e) {
315 throw new RuntimeException(e); 316 throw new RuntimeException(e);
316 } 317 }
317 - if (map.get("code").equals("1")){ 318 + if (map.get("code").equals("1")) {
318 319
319 - while (true){ 320 + while (true) {
320 streamPushItem = streamPushController.getStreamPushItem(sim, channel); 321 streamPushItem = streamPushController.getStreamPushItem(sim, channel);
321 if (null == streamPushItem) { 322 if (null == streamPushItem) {
322 try { 323 try {
@@ -327,7 +328,7 @@ public class Jt1078OfCarController { @@ -327,7 +328,7 @@ public class Jt1078OfCarController {
327 continue; 328 continue;
328 } 329 }
329 playUrl = streamPushController.getPlayUrl(streamPushItem.getApp(), stream, streamPushItem.getMediaServerId()); 330 playUrl = streamPushController.getPlayUrl(streamPushItem.getApp(), stream, streamPushItem.getMediaServerId());
330 - if (playUrl == null){ 331 + if (playUrl == null) {
331 try { 332 try {
332 Thread.sleep(1000); 333 Thread.sleep(1000);
333 } catch (InterruptedException e) { 334 } catch (InterruptedException e) {
@@ -335,7 +336,7 @@ public class Jt1078OfCarController { @@ -335,7 +336,7 @@ public class Jt1078OfCarController {
335 } 336 }
336 continue; 337 continue;
337 } 338 }
338 - return StreamPlayPath.build(playUrl,stream); 339 + return StreamPlayPath.build(playUrl, stream);
339 } 340 }
340 } 341 }
341 throw new RuntimeException("获取视频失败"); 342 throw new RuntimeException("获取视频失败");
@@ -344,7 +345,8 @@ public class Jt1078OfCarController { @@ -344,7 +345,8 @@ public class Jt1078OfCarController {
344 345
345 /** 346 /**
346 * 请求设备开始推流 347 * 请求设备开始推流
347 - * @param stream 流唯一标识 348 + *
  349 + * @param stream 流唯一标识
348 */ 350 */
349 public void sendIORequest(String stream) { 351 public void sendIORequest(String stream) {
350 352
@@ -373,7 +375,7 @@ public class Jt1078OfCarController { @@ -373,7 +375,7 @@ public class Jt1078OfCarController {
373 HttpClientPostEntity entity1 = httpClientUtil.doPost(url, msg, jsessionid); 375 HttpClientPostEntity entity1 = httpClientUtil.doPost(url, msg, jsessionid);
374 chooseEntity(entity1, url, false); 376 chooseEntity(entity1, url, false);
375 log.info("发送[ {} ]推流指令成功 ===》 {}", stream, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); 377 log.info("发送[ {} ]推流指令成功 ===》 {}", stream, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
376 - } catch (Exception e) { 378 + } catch (Exception e) {
377 log.error("发送推流指令异常;[{}], [{}], [{}]", url, msg, e.getMessage()); 379 log.error("发送推流指令异常;[{}], [{}], [{}]", url, msg, e.getMessage());
378 throw new ControllerException(ErrorCode.ERROR420); 380 throw new ControllerException(ErrorCode.ERROR420);
379 } 381 }
@@ -667,11 +669,18 @@ public class Jt1078OfCarController { @@ -667,11 +669,18 @@ public class Jt1078OfCarController {
667 @PathVariable @NotBlank(message = "channel 不能为空") String channel, 669 @PathVariable @NotBlank(message = "channel 不能为空") String channel,
668 @PathVariable @NotBlank(message = "开始时间不能为空") String startTime, 670 @PathVariable @NotBlank(message = "开始时间不能为空") String startTime,
669 @PathVariable @NotBlank(message = "结束时间不能为空") String endTime, 671 @PathVariable @NotBlank(message = "结束时间不能为空") String endTime,
670 - String channelMapping) { 672 + String channelMapping, HttpServletRequest request) {
  673 + String header = request.getHeader("access-token");
  674 + JwtUser jwtUser = JwtUtils.verifyToken(header);
  675 + String key = StringUtils.join(new String[]{"history:", sim, "-", channel});
  676 + Set<Object> keys = redisTemplate.keys(key + ":*");
  677 + String userKey = StringUtils.join(new String[]{key, ":", jwtUser.getUserName()});
  678 + if (CollectionUtils.isNotEmpty(keys) && !keys.contains(userKey)) {
  679 + throw new ControllerException(400, "该通道被其他用户占用,请浏览其他通道");
  680 + }
671 Map<String, Object> resultMap = new HashMap(); 681 Map<String, Object> resultMap = new HashMap();
672 startTime = this.formatTime(startTime); 682 startTime = this.formatTime(startTime);
673 endTime = this.formatTime(endTime); 683 endTime = this.formatTime(endTime);
674 - String key = StringUtils.join(new String[]{sim, "-", channel});  
675 channelMapping = StringUtils.join(new String[]{sim, "-", channel,"-",startTime,"-",endTime}); 684 channelMapping = StringUtils.join(new String[]{sim, "-", channel,"-",startTime,"-",endTime});
676 Integer historyPort = createHistoryPort(channelMapping); 685 Integer historyPort = createHistoryPort(channelMapping);
677 channelMapping = StringUtils.join(new String[]{channelMapping,"_", String.valueOf(historyPort)}); 686 channelMapping = StringUtils.join(new String[]{channelMapping,"_", String.valueOf(historyPort)});
@@ -703,7 +712,6 @@ public class Jt1078OfCarController { @@ -703,7 +712,6 @@ public class Jt1078OfCarController {
703 this.redisTemplate.opsForValue().set("tag:history:httpPort:" + channelMapping, entity.getHttpPort(), 2L, TimeUnit.DAYS); 712 this.redisTemplate.opsForValue().set("tag:history:httpPort:" + channelMapping, entity.getHttpPort(), 2L, TimeUnit.DAYS);
704 this.redisTemplate.opsForValue().set("tag:history:httpPort:time:" + channelMapping, (new Date()).getTime(), StreamProxyTask.TIME_OUT, TimeUnit.SECONDS); 713 this.redisTemplate.opsForValue().set("tag:history:httpPort:time:" + channelMapping, (new Date()).getTime(), StreamProxyTask.TIME_OUT, TimeUnit.SECONDS);
705 msg = this.jt1078ConfigBean.formatMessageHistoryPlayRTSP(sim, channel, startTime, endTime, this.rtspConfigBean, entity.getPort()); 714 msg = this.jt1078ConfigBean.formatMessageHistoryPlayRTSP(sim, channel, startTime, endTime, this.rtspConfigBean, entity.getPort());
706 -  
707 HttpClientPostEntity entity1 = this.httpClientUtil.doPost(url, msg, (String) null); 715 HttpClientPostEntity entity1 = this.httpClientUtil.doPost(url, msg, (String) null);
708 chooseEntity(entity1, url, true); 716 chooseEntity(entity1, url, true);
709 resultMap.put("code", "1"); 717 resultMap.put("code", "1");
@@ -712,7 +720,7 @@ public class Jt1078OfCarController { @@ -712,7 +720,7 @@ public class Jt1078OfCarController {
712 resultMap.put("data", streamContent); 720 resultMap.put("data", streamContent);
713 return resultMap; 721 return resultMap;
714 } 722 }
715 - }catch (Exception e) { 723 + } catch (Exception e) {
716 log.error("发送推流指令异常;[{}], [{}], [{}]", url, msg, e.getMessage()); 724 log.error("发送推流指令异常;[{}], [{}], [{}]", url, msg, e.getMessage());
717 throw new ControllerException(-20, "发送推流指令异常"); 725 throw new ControllerException(-20, "发送推流指令异常");
718 } 726 }
@@ -721,7 +729,7 @@ public class Jt1078OfCarController { @@ -721,7 +729,7 @@ public class Jt1078OfCarController {
721 /** 729 /**
722 * 从set<String>中找到对应唯一的sim-channel值 730 * 从set<String>中找到对应唯一的sim-channel值
723 */ 731 */
724 - public static String getFindSet(Set<String> set,String targetString) { 732 + public static String getFindSet(Set<String> set, String targetString) {
725 for (String str : set) { 733 for (String str : set) {
726 if (str.startsWith(targetString)) { 734 if (str.startsWith(targetString)) {
727 return str; // 找到匹配项后立即返回 735 return str; // 找到匹配项后立即返回
@@ -729,6 +737,7 @@ public class Jt1078OfCarController { @@ -729,6 +737,7 @@ public class Jt1078OfCarController {
729 } 737 }
730 return null; 738 return null;
731 } 739 }
  740 +
732 /** 741 /**
733 * 从形如"sim-channel-start-end"的字符串中提取第二个'-'之前的值。 742 * 从形如"sim-channel-start-end"的字符串中提取第二个'-'之前的值。
734 */ 743 */
@@ -749,6 +758,7 @@ public class Jt1078OfCarController { @@ -749,6 +758,7 @@ public class Jt1078OfCarController {
749 return null; // 如果少于两个'-',则返回null 758 return null; // 如果少于两个'-',则返回null
750 } 759 }
751 } 760 }
  761 +
752 /** 762 /**
753 * 遍历Map,寻找第一个不包含指定string的Set<String>, 763 * 遍历Map,寻找第一个不包含指定string的Set<String>,
754 * 将该string添加到Set中并返回对应的key,如果没有找到则返回null。 764 * 将该string添加到Set中并返回对应的key,如果没有找到则返回null。
@@ -757,7 +767,7 @@ public class Jt1078OfCarController { @@ -757,7 +767,7 @@ public class Jt1078OfCarController {
757 // 使用entrySet()方法直接获取键值对进行迭代,效率更高 767 // 使用entrySet()方法直接获取键值对进行迭代,效率更高
758 for (Map.Entry<Integer, Set<String>> entry : map.entrySet()) { 768 for (Map.Entry<Integer, Set<String>> entry : map.entrySet()) {
759 Set<String> set = entry.getValue(); 769 Set<String> set = entry.getValue();
760 - if (set.contains(targetString)){ 770 + if (set.contains(targetString)) {
761 return entry.getKey(); 771 return entry.getKey();
762 } 772 }
763 // 如果当前Set不包含目标字符串,则添加并返回key 773 // 如果当前Set不包含目标字符串,则添加并返回key
@@ -766,8 +776,8 @@ public class Jt1078OfCarController { @@ -766,8 +776,8 @@ public class Jt1078OfCarController {
766 set.add(targetString); 776 set.add(targetString);
767 if (secondDashValue != null && findSet == null) { 777 if (secondDashValue != null && findSet == null) {
768 return entry.getKey(); // 立即返回对应的key,不再继续查找 778 return entry.getKey(); // 立即返回对应的key,不再继续查找
769 - }else {  
770 - clearMap(String.valueOf(entry.getKey()),findSet); 779 + } else {
  780 + clearMap(String.valueOf(entry.getKey()), findSet);
771 } 781 }
772 } 782 }
773 return null; // 如果所有Set都包含目标字符串,则返回null 783 return null; // 如果所有Set都包含目标字符串,则返回null
@@ -776,7 +786,7 @@ public class Jt1078OfCarController { @@ -776,7 +786,7 @@ public class Jt1078OfCarController {
776 /** 786 /**
777 * 清理map中的值 787 * 清理map中的值
778 */ 788 */
779 - public void clearMap(String key,String value) { 789 + public void clearMap(String key, String value) {
780 if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) { 790 if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
781 Set<String> strings = map.get(Integer.valueOf(key)); 791 Set<String> strings = map.get(Integer.valueOf(key));
782 if (strings == null) { 792 if (strings == null) {
@@ -790,48 +800,48 @@ public class Jt1078OfCarController { @@ -790,48 +800,48 @@ public class Jt1078OfCarController {
790 throw new RuntimeException(e); 800 throw new RuntimeException(e);
791 } 801 }
792 String[] split = value.split("-"); 802 String[] split = value.split("-");
793 - stopHistory(split[1],split[0]); 803 + stopHistory(split[1], split[0]);
794 strings.remove(value); 804 strings.remove(value);
795 } 805 }
796 - }else { 806 + } else {
797 log.error("清理端口缓存错误 !!!"); 807 log.error("清理端口缓存错误 !!!");
798 } 808 }
799 } 809 }
800 810
801 /** 811 /**
802 * 创建历史端口 812 * 创建历史端口
  813 + *
803 * @param key 通道唯一值 814 * @param key 通道唯一值
804 */ 815 */
805 - public Integer createHistoryPort(String key){ 816 + public Integer createHistoryPort(String key) {
806 Integer port = addStringToFirstNonContainingSet(key); 817 Integer port = addStringToFirstNonContainingSet(key);
807 if (port == null) { 818 if (port == null) {
808 - throw new RuntimeException(String.format("[ %s ]通道观看人数太多,请等待 !!!",key)); 819 + throw new RuntimeException(String.format("[ %s ]通道观看人数太多,请等待 !!!", key));
809 } 820 }
810 try { 821 try {
811 - if (redisTemplate.opsForValue().get("history:port:"+port) == null) { 822 + if (redisTemplate.opsForValue().get("history:port:" + port) == null) {
812 startPost(port); 823 startPost(port);
813 - redisTemplate.opsForValue().set("history:port:"+port, port); 824 + redisTemplate.opsForValue().set("history:port:" + port, port);
814 } 825 }
815 return port; 826 return port;
816 } catch (Exception e) { 827 } catch (Exception e) {
817 - log.error("{}",e.getMessage(),e); 828 + log.error("{}", e.getMessage(), e);
818 throw new RuntimeException(String.format("[ %s ]端口启动异常", port)); 829 throw new RuntimeException(String.format("[ %s ]端口启动异常", port));
819 } 830 }
820 } 831 }
821 832
822 /** 833 /**
823 * 启动历史端口监听 834 * 启动历史端口监听
  835 + *
824 * @param port 端口 836 * @param port 端口
825 */ 837 */
826 private void startPost(Integer port) throws Exception { 838 private void startPost(Integer port) throws Exception {
827 VideoServerApp videoServerApp = new VideoServerApp(); 839 VideoServerApp videoServerApp = new VideoServerApp();
828 840
829 VideoServerApp.VideoServer videoServer = videoServerApp.getVideoServer(port); 841 VideoServerApp.VideoServer videoServer = videoServerApp.getVideoServer(port);
830 - Signal.handle(new Signal("TERM"), new SignalHandler()  
831 - { 842 + Signal.handle(new Signal("TERM"), new SignalHandler() {
832 @Override 843 @Override
833 - public void handle(Signal signal)  
834 - { 844 + public void handle(Signal signal) {
835 videoServer.shutdown(); 845 videoServer.shutdown();
836 } 846 }
837 }); 847 });
@@ -840,7 +850,7 @@ public class Jt1078OfCarController { @@ -840,7 +850,7 @@ public class Jt1078OfCarController {
840 850
841 851
842 @Nullable 852 @Nullable
843 - private StreamContent getStreamContent(String stream){ 853 + private StreamContent getStreamContent(String stream) {
844 854
845 StreamContent streamContent = this.getStreamContentPlayURL(stream); 855 StreamContent streamContent = this.getStreamContentPlayURL(stream);
846 if (Objects.isNull(streamContent) || StringUtils.isEmpty(streamContent.getWs_flv())) { 856 if (Objects.isNull(streamContent) || StringUtils.isEmpty(streamContent.getWs_flv())) {
@@ -863,8 +873,6 @@ public class Jt1078OfCarController { @@ -863,8 +873,6 @@ public class Jt1078OfCarController {
863 * @return 873 * @return
864 */ 874 */
865 private StreamContent requestStreamContent(int count, String stream, int httpPort) { 875 private StreamContent requestStreamContent(int count, String stream, int httpPort) {
866 -  
867 -  
868 StreamContent streamContent = this.getStreamContentPlayURL(stream); 876 StreamContent streamContent = this.getStreamContentPlayURL(stream);
869 return streamContent; 877 return streamContent;
870 } 878 }
@@ -975,35 +983,6 @@ public class Jt1078OfCarController { @@ -975,35 +983,6 @@ public class Jt1078OfCarController {
975 } 983 }
976 984
977 /** 985 /**
978 - * 获取所有匹配模式 jt1078:server:port:* 的键,并找到其中剩余时间最短的键。  
979 - */  
980 - public String findKeyWithShortestTTL(String keyMatch) {  
981 - String shortestTTLKey = null;  
982 - long shortestTTL = Long.MAX_VALUE;  
983 - // 使用 SCAN 命令遍历键空间  
984 - Cursor<byte[]> cursor = redisTemplate.execute(  
985 - (RedisCallback<Cursor<byte[]>>) connection -> {  
986 - ScanOptions options = ScanOptions.scanOptions().match(keyMatch).count(100).build();  
987 - return connection.scan(options);  
988 - });  
989 -  
990 - if (cursor != null) {  
991 - while (cursor.hasNext()) {  
992 - byte[] keyBytes = cursor.next();  
993 - String key = new String(keyBytes);  
994 -  
995 - // 获取当前键的 TTL  
996 - Long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS);  
997 - if (ttl != null && ttl >= 0 && ttl < shortestTTL) {  
998 - shortestTTL = ttl;  
999 - shortestTTLKey = key;  
1000 - }  
1001 - }  
1002 - }  
1003 - return shortestTTLKey;  
1004 - }  
1005 -  
1006 - /**  
1007 * 创建监听者 986 * 创建监听者
1008 * 987 *
1009 * @param channelMapping 988 * @param channelMapping
@@ -1040,13 +1019,13 @@ public class Jt1078OfCarController { @@ -1040,13 +1019,13 @@ public class Jt1078OfCarController {
1040 1019
1041 if (flag) { 1020 if (flag) {
1042 if (StringUtils.isNoneBlank(new CharSequence[]{rsultMap.get("msg") + ""})) { 1021 if (StringUtils.isNoneBlank(new CharSequence[]{rsultMap.get("msg") + ""})) {
1043 - throw new ControllerException(304, String.valueOf(rsultMap.get("msg"))); 1022 + throw new ControllerException(304, String.valueOf(rsultMap.get("msg")));
1044 } 1023 }
1045 } 1024 }
1046 } catch (Exception var6) { 1025 } catch (Exception var6) {
1047 Exception e = var6; 1026 Exception e = var6;
1048 - log.error("entity.getResultStr():{{}}", entity.getResultStr(), e.getMessage(), e);  
1049 - throw new ControllerException(500,e.getMessage()); 1027 + log.error("entity.getResultStr():{{}}", entity.getResultStr(), e.getMessage());
  1028 + throw new ControllerException(500, e.getMessage());
1050 } 1029 }
1051 } 1030 }
1052 } 1031 }
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/config/DataBuffer.java
@@ -29,8 +29,12 @@ public class DataBuffer&lt;T&gt; { @@ -29,8 +29,12 @@ public class DataBuffer&lt;T&gt; {
29 29
30 public List<T> getDataList(){ 30 public List<T> getDataList(){
31 if (booleanValue.getAndSet(!booleanValue.get())){ 31 if (booleanValue.getAndSet(!booleanValue.get())){
32 - return new ArrayList<>(trueQueue); 32 + ArrayList<T> list = new ArrayList<>(trueQueue);
  33 + trueQueue.clear();
  34 + return list;
33 } 35 }
34 - return new ArrayList<>(falseQueue); 36 + ArrayList<T> list = new ArrayList<>(falseQueue);
  37 + falseQueue.clear();
  38 + return list;
35 } 39 }
36 } 40 }
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/config/DataBufferConfig.java
@@ -63,10 +63,10 @@ public class DataBufferConfig { @@ -63,10 +63,10 @@ public class DataBufferConfig {
63 SimFlow simFlow = flowService.selectOne(value); 63 SimFlow simFlow = flowService.selectOne(value);
64 if (simFlow == null) { 64 if (simFlow == null) {
65 boolean b = flowService.addFlow(value); 65 boolean b = flowService.addFlow(value);
66 - log.info("流量信息添加 {} ",b?"成功":"失败"); 66 + log.debug("流量信息添加 {} ",b?"成功":"失败");
67 }else { 67 }else {
68 boolean b = flowService.updateFlow(value); 68 boolean b = flowService.updateFlow(value);
69 - log.info("修改库中流量信息 {} ",b?"成功":"失败"); 69 + log.debug("修改库中流量信息 {} ",b?"成功":"失败");
70 } 70 }
71 }); 71 });
72 } 72 }
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/config/FtpConfigBean.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.jt1078.platform.config;
  2 +
  3 +import lombok.Data;
  4 +import org.springframework.boot.context.properties.ConfigurationProperties;
  5 +import org.springframework.context.annotation.Configuration;
  6 +
  7 +/**
  8 + * Ftp配置
  9 + *
  10 + * @Author WangXin
  11 + * @Data 2025/2/11
  12 + * @Version 1.0.0
  13 + */
  14 +@Data
  15 +@Configuration
  16 +@ConfigurationProperties(prefix = "ftp")
  17 +public class FtpConfigBean {
  18 +
  19 + private String basePath;
  20 + /**
  21 + * ftp地址
  22 + */
  23 + private String host;
  24 + private String httpPath;
  25 + /**
  26 + *
  27 + */
  28 + private String filePathPrefix;
  29 + /**
  30 + * 密码
  31 + */
  32 + private String password;
  33 + /**
  34 + * 端口
  35 + */
  36 + private Integer port;
  37 + /**
  38 + * 用户名
  39 + */
  40 + private String username;
  41 + /**
  42 + * 失败重试次数 -1为一直重试
  43 + */
  44 + private Integer retryTimes;
  45 + /**
  46 + * 失败重试间隔时间
  47 + */
  48 + private Integer retryWaitTimes;
  49 +}
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/config/Jt1078ConfigBean.java
1 -package com.genersoft.iot.vmp.vmanager.jt1078.platform.config; import com.genersoft.iot.vmp.vmanager.jt1078.platform.Jt1078OfCarController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.*; @Component public class Jt1078ConfigBean { @Value("${tuohua.bsth.jt1078.url}") private String jt1078Url; @Value("${tuohua.bsth.jt1078.sendPort}") private String jt1078SendPort; @Value("${tuohua.bsth.jt1078.stopSendPort}") private String stopSendPort; @Value("${tuohua.bsth.jt1078.historyListPort}") private String historyListPort; @Value("${tuohua.bsth.jt1078.playHistoryPort}") private String playHistoryPort; @Value("${tuohua.bsth.jt1078.ports}") private String portsOf1078; @Value("${tuohua.bsth.jt1078.pushURL}") private String pushURL; @Value("${tuohua.bsth.jt1078.stopPushURL}") private String stopPUshURL; private Integer start1078Port; private Integer end1078Port; @Value("${tuohua.bsth.jt1078.get.url}") private String getURL; @Value("${tuohua.bsth.jt1078.addPortVal}") private Integer addPort; @Value("${tuohua.bsth.jt1078.ws}") private String ws; @Value("${tuohua.bsth.jt1078.wss}") private String wss; @Value("${tuohua.bsth.jt1078.downloadFLV}") private String downloadFlv; @Value("${tuohua.bsth.jt1078.port}") private Integer port; @Value("${tuohua.bsth.jt1078.httpPort}") private Integer httpPort; @Value("${spring.profiles.active}") private String profilesActive; @Value("${media.pushKey}") private String pushKey; @Resource private RedisTemplate<String, Integer> redisTemplate; public Integer getPort() { if (port == null) { return 30000; } return port; } public Integer getHttpPort() { if (httpPort == null) { return 30000; } return httpPort; } private Integer getIntPort() { return profilesActive.equals("wx-local") ? 10000 : 0; } @PostConstruct public void initMap() { Set<String> historyPortKeys = redisTemplate.keys("history:port:*"); Set<String> keys = redisTemplate.keys("tag:*"); Set<String> patrolKeys = redisTemplate.keys("patrol:stream:*"); if (!historyPortKeys.isEmpty()) { keys.addAll(historyPortKeys); } if (!patrolKeys.isEmpty()) { keys.addAll(patrolKeys); } if (keys != null) { redisTemplate.delete(keys); } Map<Integer, Set<String>> hashMap = new HashMap<>(); for (int number = getStart1078Port(); number <= getEnd1078Port(); number++) { hashMap.put(number, new HashSet<>()); } Jt1078OfCarController.map.putAll(hashMap); } private static final String SEND_IO_MESSAGE_RTSP = "{ \"messageId\": 37121, \"properties\": 0, \"clientId\": \"{clientId}\", \"serialNo\": \"1\", \"ip\": \"{ip}\", \"tcpPort\": \"{tcpPort}\", \"udpPort\": \"{udpPort}\", \"channelNo\": \"{channelNo}\", \"mediaType\": \"1\", \"streamType\": \"1\"}"; private static final String SEND_IO_MESSAGE_RTSP_STOP = "{\"messageId\": 37122,\"properties\": 0,\"clientId\": \"{clientId}\",\"serialNo\": \"1\",\"channelNo\": \"{channelNo}\",\"command\": \"0\",\"closeType\": \"0\",\"streamType\": \"1\"}"; private static final String SEND_IO_HISTORY_RTSP = "{\"msgid\":37381,\"clientId\":\"{clientId}\",\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"channelId\":{channelNo}}"; private static final String SEND_IO_PLAY_RTSP = "{\"ip\":\"{ip}\",\"tcpPort\":{tcpPort},\"udpPort\":{udpPort},\"channelNo\":\"{channelNo}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"playbackType\":0,\"playbackSpeed\":1,\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"clientId\":\"{sim}\",\"messageId\":37377}"; public String formatMessageId(String sim, String channel, RtspConfigBean configBean, Integer port) { String msg = StringUtils.replace("{ \"messageId\": 37121, \"properties\": 0, \"clientId\": \"{clientId}\", \"serialNo\": \"1\", \"ip\": \"{ip}\", \"tcpPort\": \"{tcpPort}\", \"udpPort\": \"{udpPort}\", \"channelNo\": \"{channelNo}\", \"mediaType\": \"1\", \"streamType\": \"1\"}", "{clientId}", sim); msg = StringUtils.replace(msg, "{tcpPort}", (port.intValue() + getIntPort() + getAddPort()) + ""); msg = StringUtils.replace(msg, "{udpPort}", (port.intValue() + getIntPort() + getAddPort()) + ""); msg = StringUtils.replace(msg, "{channelNo}", channel); return StringUtils.replace(msg, "{ip}", configBean.getRtspIp()); } public String formatMessageStop(String sim, String channel) { String msg = StringUtils.replace("{\"messageId\": 37122,\"properties\": 0,\"clientId\": \"{clientId}\",\"serialNo\": \"1\",\"channelNo\": \"{channelNo}\",\"command\": \"0\",\"closeType\": \"0\",\"streamType\": \"1\"}", "{clientId}", sim); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatMessageHistoryListRTSP(String sim, String channel, String startTime, String endTime) { String msg = StringUtils.replace("{\"msgid\":37381,\"clientId\":\"{clientId}\",\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"channelId\":{channelNo}}", "{clientId}", sim); msg = StringUtils.replace(msg, "{startTime}", startTime); msg = StringUtils.replace(msg, "{endTime}", endTime); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatMessageHistoryPlayRTSP(String sim, String channel, String startTime, String endTime, RtspConfigBean configBean, Integer port) { String msg = StringUtils.replace("{\"ip\":\"{ip}\",\"tcpPort\":{tcpPort},\"udpPort\":{udpPort},\"channelNo\":\"{channelNo}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"playbackType\":0,\"playbackSpeed\":1,\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"clientId\":\"{sim}\",\"messageId\":37377}", "{clientId}", sim); msg = StringUtils.replace(msg, "{startTime}", startTime); msg = StringUtils.replace(msg, "{endTime}", endTime); msg = StringUtils.replace(msg, "{channelNo}", channel); msg = StringUtils.replace(msg, "{tcpPort}", (port.intValue() + getIntPort() +getAddPort()) + ""); msg = StringUtils.replace(msg, "{udpPort}", (port.intValue() + getIntPort() + getAddPort()) + ""); msg = StringUtils.replace(msg, "{sim}", sim); return StringUtils.replace(msg, "{ip}", configBean.getRtspIp()); } public String formatMessageHistoryStopRTSP(String sim, String channel, RtspConfigBean configBean) { String msg = StringUtils.replace("{\"playbackMode\":2,\"channelNo\":{channelNo},\"playbackSpeed\":0,\"clientId\":\"{sim}\"}", "{sim}", sim); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatPushURL(String pushKey, int port, int httpPort) { String msg = StringUtils.replace(this.pushURL, "{pushKey}", pushKey); msg = StringUtils.replace(msg, "{port}", String.valueOf(port)); return StringUtils.replace(msg, "{httpPort}", String.valueOf(httpPort)); } public String formatStopPushURL(String pushKey, int port, int httpPort) { String msg = StringUtils.replace(this.stopPUshURL, "{pushKey}", pushKey); msg = StringUtils.replace(msg, "{port}", String.valueOf(port)); return StringUtils.replace(msg, "{httpPort}", String.valueOf(httpPort)); } public String formatVideoURL(String stream) { String url = StringUtils.replace(getGetURL(), "{stream}", stream); if (!StringUtils.endsWith(url, ".flv")) { url = url + ".flv"; } return url; } public String getJt1078Url() { return this.jt1078Url; } public String getJt1078SendPort() { return this.jt1078SendPort; } public String getStopSendPort() { return this.stopSendPort; } public String getHistoryListPort() { return this.historyListPort; } public String getPlayHistoryPort() { return this.playHistoryPort; } public String getPushURL() { return this.pushURL; } public Integer getStart1078Port() { if (Objects.isNull(this.start1078Port)) this.start1078Port = Integer.valueOf(Integer.parseInt(StringUtils.substringBefore(this.portsOf1078, ","))); return this.start1078Port; } public Integer getEnd1078Port() { if (Objects.isNull(this.end1078Port)) this.end1078Port = Integer.valueOf(Integer.parseInt(StringUtils.substringAfter(this.portsOf1078, ","))); return this.end1078Port; } public String getPushKey(){ if (Objects.isNull(this.pushKey)){ this.pushKey = "?callId=41db35390ddad33f83944f44b8b75ded"; } return "?callId="+this.pushKey; } public String getStopPUshURL() { return this.stopPUshURL; } public String getGetURL() { return this.getURL; } public Integer getAddPort() { return this.addPort; } public String getWs() { return this.ws; } public String getWss() { return this.wss; } public String getDownloadFlv() { return downloadFlv; } public String getPortsOf1078() { return portsOf1078; } }  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +package com.genersoft.iot.vmp.vmanager.jt1078.platform.config; import com.genersoft.iot.vmp.vmanager.jt1078.platform.Jt1078OfCarController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.*; @Component public class Jt1078ConfigBean { @Value("${tuohua.bsth.jt1078.url}") private String jt1078Url; @Value("${tuohua.bsth.jt1078.sendPort}") private String jt1078SendPort; @Value("${tuohua.bsth.jt1078.stopSendPort}") private String stopSendPort; @Value("${tuohua.bsth.jt1078.historyListPort}") private String historyListPort; @Value("${tuohua.bsth.jt1078.playHistoryPort}") private String playHistoryPort; @Value("${tuohua.bsth.jt1078.ports}") private String portsOf1078; @Value("${tuohua.bsth.jt1078.pushURL}") private String pushURL; @Value("${tuohua.bsth.jt1078.stopPushURL}") private String stopPUshURL; private Integer start1078Port; private Integer end1078Port; @Value("${tuohua.bsth.jt1078.get.url}") private String getURL; @Value("${tuohua.bsth.jt1078.addPortVal}") private Integer addPort; @Value("${tuohua.bsth.jt1078.ws}") private String ws; @Value("${tuohua.bsth.jt1078.wss}") private String wss; @Value("${tuohua.bsth.jt1078.downloadFLV}") private String downloadFlv; @Value("${tuohua.bsth.jt1078.port}") private Integer port; @Value("${tuohua.bsth.jt1078.httpPort}") private Integer httpPort; @Value("${spring.profiles.active}") private String profilesActive; @Value("${media.pushKey}") private String pushKey; @Resource private RedisTemplate<String, Integer> redisTemplate; public Integer getPort() { if (port == null) { return 30000; } return port; } public Integer getHttpPort() { if (httpPort == null) { return 30000; } return httpPort; } private Integer getIntPort() { return profilesActive.equals("wx-local") ? 10000 : 0; } @PostConstruct public void initMap() { Set<String> historyPortKeys = redisTemplate.keys("history:port:*"); Set<String> keys = redisTemplate.keys("tag:*"); Set<String> patrolKeys = redisTemplate.keys("patrol:stream:*"); if (!historyPortKeys.isEmpty()) { keys.addAll(historyPortKeys); } if (!patrolKeys.isEmpty()) { keys.addAll(patrolKeys); } if (keys != null) { redisTemplate.delete(keys); } Map<Integer, Set<String>> hashMap = new HashMap<>(); for (int number = getStart1078Port(); number <= getEnd1078Port(); number++) { hashMap.put(number, new HashSet<>()); } Jt1078OfCarController.map.putAll(hashMap); } private static final String SEND_IO_MESSAGE_RTSP = "{ \"messageId\": 37121, \"properties\": 0, \"clientId\": \"{clientId}\", \"serialNo\": \"1\", \"ip\": \"{ip}\", \"tcpPort\": \"{tcpPort}\", \"udpPort\": \"{udpPort}\", \"channelNo\": \"{channelNo}\", \"mediaType\": \"1\", \"streamType\": \"1\"}"; private static final String SEND_IO_MESSAGE_RTSP_STOP = "{\"messageId\": 37122,\"properties\": 0,\"clientId\": \"{clientId}\",\"serialNo\": \"1\",\"channelNo\": \"{channelNo}\",\"command\": \"0\",\"closeType\": \"0\",\"streamType\": \"1\"}"; private static final String SEND_IO_HISTORY_RTSP = "{\"msgid\":37381,\"clientId\":\"{clientId}\",\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"channelId\":{channelNo}}"; private static final String SEND_IO_PLAY_RTSP = "{\"ip\":\"{ip}\",\"tcpPort\":{tcpPort},\"udpPort\":{udpPort},\"channelNo\":\"{channelNo}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"playbackType\":0,\"playbackSpeed\":1,\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"clientId\":\"{sim}\",\"messageId\":37377}"; public String formatMessageId(String sim, String channel, RtspConfigBean configBean, Integer port) { String msg = StringUtils.replace("{ \"messageId\": 37121, \"properties\": 0, \"clientId\": \"{clientId}\", \"serialNo\": \"1\", \"ip\": \"{ip}\", \"tcpPort\": \"{tcpPort}\", \"udpPort\": \"{udpPort}\", \"channelNo\": \"{channelNo}\", \"mediaType\": \"1\", \"streamType\": \"1\"}", "{clientId}", sim); msg = StringUtils.replace(msg, "{tcpPort}", (port.intValue() + getIntPort() + getAddPort()) + ""); msg = StringUtils.replace(msg, "{udpPort}", (port.intValue() + getIntPort() + getAddPort()) + ""); msg = StringUtils.replace(msg, "{channelNo}", channel); return StringUtils.replace(msg, "{ip}", configBean.getRtspIp()); } public String formatMessageStop(String sim, String channel) { String msg = StringUtils.replace("{\"messageId\": 37122,\"properties\": 0,\"clientId\": \"{clientId}\",\"serialNo\": \"1\",\"channelNo\": \"{channelNo}\",\"command\": \"0\",\"closeType\": \"0\",\"streamType\": \"1\"}", "{clientId}", sim); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatMessageHistoryListRTSP(String sim, String channel, String startTime, String endTime) { String msg = StringUtils.replace("{\"msgid\":37381,\"clientId\":\"{clientId}\",\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"mediaType\":0,\"streamType\":1,\"storageType\":0,\"channelNo\":{channelNo}}", "{clientId}", sim); msg = StringUtils.replace(msg, "{startTime}", startTime); msg = StringUtils.replace(msg, "{endTime}", endTime); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatMessageHistoryPlayRTSP(String sim, String channel, String startTime, String endTime, RtspConfigBean configBean, Integer port) { String msg = StringUtils.replace("{\"ip\":\"{ip}\",\"tcpPort\":{tcpPort},\"udpPort\":{udpPort},\"channelNo\":\"{channelNo}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"playbackType\":0,\"playbackSpeed\":1,\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"clientId\":\"{sim}\",\"messageId\":37377}", "{clientId}", sim); msg = StringUtils.replace(msg, "{startTime}", startTime); msg = StringUtils.replace(msg, "{endTime}", endTime); msg = StringUtils.replace(msg, "{channelNo}", channel); msg = StringUtils.replace(msg, "{tcpPort}", (port.intValue() + getIntPort() +getAddPort()) + ""); msg = StringUtils.replace(msg, "{udpPort}", (port.intValue() + getIntPort() + getAddPort()) + ""); msg = StringUtils.replace(msg, "{sim}", sim); return StringUtils.replace(msg, "{ip}", configBean.getRtspIp()); } public String formatMessageHistoryStopRTSP(String sim, String channel, RtspConfigBean configBean) { String msg = StringUtils.replace("{\"playbackMode\":2,\"channelNo\":{channelNo},\"playbackSpeed\":0,\"clientId\":\"{sim}\"}", "{sim}", sim); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatPushURL(String pushKey, int port, int httpPort) { String msg = StringUtils.replace(this.pushURL, "{pushKey}", pushKey); msg = StringUtils.replace(msg, "{port}", String.valueOf(port)); return StringUtils.replace(msg, "{httpPort}", String.valueOf(httpPort)); } public String formatStopPushURL(String pushKey, int port, int httpPort) { String msg = StringUtils.replace(this.stopPUshURL, "{pushKey}", pushKey); msg = StringUtils.replace(msg, "{port}", String.valueOf(port)); return StringUtils.replace(msg, "{httpPort}", String.valueOf(httpPort)); } public String formatVideoURL(String stream) { String url = StringUtils.replace(getGetURL(), "{stream}", stream); if (!StringUtils.endsWith(url, ".flv")) { url = url + ".flv"; } return url; } public String getJt1078Url() { return this.jt1078Url; } public String getJt1078SendPort() { return this.jt1078SendPort; } public String getStopSendPort() { return this.stopSendPort; } public String getHistoryListPort() { return this.historyListPort; } public String getPlayHistoryPort() { return this.playHistoryPort; } public String getPushURL() { return this.pushURL; } public Integer getStart1078Port() { if (Objects.isNull(this.start1078Port)) this.start1078Port = Integer.valueOf(Integer.parseInt(StringUtils.substringBefore(this.portsOf1078, ","))); return this.start1078Port; } public Integer getEnd1078Port() { if (Objects.isNull(this.end1078Port)) this.end1078Port = Integer.valueOf(Integer.parseInt(StringUtils.substringAfter(this.portsOf1078, ","))); return this.end1078Port; } public String getPushKey(){ if (Objects.isNull(this.pushKey)){ this.pushKey = "?callId=41db35390ddad33f83944f44b8b75ded"; } return "?callId="+this.pushKey; } public String getStopPUshURL() { return this.stopPUshURL; } public String getGetURL() { return this.getURL; } public Integer getAddPort() { return this.addPort; } public String getWs() { return this.ws; } public String getWss() { return this.wss; } public String getDownloadFlv() { return downloadFlv; } public String getPortsOf1078() { return portsOf1078; } }
3 \ No newline at end of file 3 \ No newline at end of file
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/config/TuohuaConfigBean.java
1 package com.genersoft.iot.vmp.vmanager.jt1078.platform.config; 1 package com.genersoft.iot.vmp.vmanager.jt1078.platform.config;
2 2
  3 +import cn.hutool.core.convert.Convert;
3 import com.alibaba.fastjson2.JSON; 4 import com.alibaba.fastjson2.JSON;
4 import com.genersoft.iot.vmp.vmanager.jt1078.platform.ben.HttpClientPostEntity; 5 import com.genersoft.iot.vmp.vmanager.jt1078.platform.ben.HttpClientPostEntity;
  6 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.CarData;
5 import com.genersoft.iot.vmp.vmanager.jt1078.platform.handler.HttpClientUtil; 7 import com.genersoft.iot.vmp.vmanager.jt1078.platform.handler.HttpClientUtil;
6 -import com.xiaoleilu.hutool.convert.Convert; 8 +import lombok.extern.slf4j.Slf4j;
7 import org.apache.commons.collections4.CollectionUtils; 9 import org.apache.commons.collections4.CollectionUtils;
8 -import org.apache.commons.lang3.RandomUtils;  
9 import org.apache.commons.lang3.StringUtils; 10 import org.apache.commons.lang3.StringUtils;
10 import org.springframework.beans.factory.annotation.Autowired; 11 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.beans.factory.annotation.Value; 12 import org.springframework.beans.factory.annotation.Value;
12 import org.springframework.data.redis.core.RedisTemplate; 13 import org.springframework.data.redis.core.RedisTemplate;
13 import org.springframework.stereotype.Component; 14 import org.springframework.stereotype.Component;
14 15
  16 +import javax.annotation.PostConstruct;
  17 +import javax.annotation.Resource;
15 import java.security.MessageDigest; 18 import java.security.MessageDigest;
16 import java.util.*; 19 import java.util.*;
  20 +import java.util.concurrent.ConcurrentHashMap;
17 import java.util.stream.Collectors; 21 import java.util.stream.Collectors;
18 22
19 /** 23 /**
20 * @author liujun 24 * @author liujun
21 * @date 2024年10月23日 13:34 25 * @date 2024年10月23日 13:34
22 */ 26 */
  27 +@Slf4j
23 @Component 28 @Component
24 public class TuohuaConfigBean { 29 public class TuohuaConfigBean {
25 30
@@ -50,6 +55,8 @@ public class TuohuaConfigBean { @@ -50,6 +55,8 @@ public class TuohuaConfigBean {
50 @Value("${spring.profiles.active}") 55 @Value("${spring.profiles.active}")
51 private String profileActive; 56 private String profileActive;
52 57
  58 + public static final ConcurrentHashMap<String, CarData> map = new ConcurrentHashMap<>();
  59 +
53 @Autowired 60 @Autowired
54 private RedisTemplate redisTemplate; 61 private RedisTemplate redisTemplate;
55 62
@@ -111,6 +118,19 @@ public class TuohuaConfigBean { @@ -111,6 +118,19 @@ public class TuohuaConfigBean {
111 return Objects.isNull(postEntity) ? null : postEntity.getResultStr(); 118 return Objects.isNull(postEntity) ? null : postEntity.getResultStr();
112 } 119 }
113 120
  121 + @Resource
  122 + private HttpClientUtil httpClientUtil;
  123 +
  124 + @PostConstruct
  125 + public void init() {
  126 + try {
  127 + String carJson = requestCars(httpClientUtil, String.valueOf(100));
  128 + setMap(carJson);
  129 + } catch (Exception e) {
  130 + throw new RuntimeException(e);
  131 + }
  132 + }
  133 +
114 public String requestCars(HttpClientUtil httpClientUtil, String companyId) throws Exception { 134 public String requestCars(HttpClientUtil httpClientUtil, String companyId) throws Exception {
115 String nonce = random(6); 135 String nonce = random(6);
116 String timestamp = String.valueOf(new Date().getTime()); 136 String timestamp = String.valueOf(new Date().getTime());
@@ -140,6 +160,30 @@ public class TuohuaConfigBean { @@ -140,6 +160,30 @@ public class TuohuaConfigBean {
140 return (List<HashMap>) JSON.parseArray(postEntity.getResultStr(), HashMap.class); 160 return (List<HashMap>) JSON.parseArray(postEntity.getResultStr(), HashMap.class);
141 } 161 }
142 162
  163 + public void setMap(String json){
  164 + List<CarData> carData = JSON.parseArray(json, CarData.class);
  165 + int count = 1;
  166 + if (CollectionUtils.isNotEmpty(carData)) {
  167 + if (StringUtils.equals(profileActive, "wx-local")) {
  168 + CarData value = carData.get(0);
  169 + value.setSim("123456789011");
  170 + map.put(value.getSim(), value);
  171 + }else {
  172 + for (CarData carDatum : carData) {
  173 + log.debug("{} ----》 {}",count++,JSON.toJSONString(carDatum));
  174 + if (carDatum == null || carDatum.getSim() == null) {
  175 + continue;
  176 + }
  177 + map.put(carDatum.getSim(), carDatum);
  178 + }
  179 + }
  180 + }
  181 + }
  182 +
  183 + public static CarData getCarData(String sim){
  184 + return map.get(sim);
  185 + }
  186 +
143 public List<HashMap<String, Object>> requestOfLineAndCarAndCombationTree(HttpClientUtil httpClientUtil, String companyId) throws Exception { 187 public List<HashMap<String, Object>> requestOfLineAndCarAndCombationTree(HttpClientUtil httpClientUtil, String companyId) throws Exception {
144 String lineJson = requestLine(httpClientUtil, companyId); 188 String lineJson = requestLine(httpClientUtil, companyId);
145 String carJson = requestCars(httpClientUtil, companyId); 189 String carJson = requestCars(httpClientUtil, companyId);
@@ -163,7 +207,10 @@ public class TuohuaConfigBean { @@ -163,7 +207,10 @@ public class TuohuaConfigBean {
163 List<HashMap> carJsonListFinal = carJsonList; 207 List<HashMap> carJsonListFinal = carJsonList;
164 208
165 List<HashMap<String, Object>> returnData = new ArrayList<>(); 209 List<HashMap<String, Object>> returnData = new ArrayList<>();
  210 +
  211 +
166 if (linesSize > 0) { 212 if (linesSize > 0) {
  213 + setMap(carJson);
167 List<HashMap<String, Object>> lines = linesJsonList.stream().map(hashMap -> { 214 List<HashMap<String, Object>> lines = linesJsonList.stream().map(hashMap -> {
168 String code = convertStr(hashMap.get("lineCode")); 215 String code = convertStr(hashMap.get("lineCode"));
169 String name = convertStr(hashMap.get("name")); 216 String name = convertStr(hashMap.get("name"));
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/controller/FTPController.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.jt1078.platform.controller;
  2 +
  3 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.FTPService;
  4 +import org.springframework.web.bind.annotation.*;
  5 +
  6 +import javax.annotation.Resource;
  7 +
  8 +/**
  9 + * FTP控制层
  10 + *
  11 + * @Author WangXin
  12 + * @Data 2025/2/11
  13 + * @Version 1.0.0
  14 + */
  15 +@RestController
  16 +@RequestMapping("/ftp")
  17 +public class FTPController {
  18 +
  19 + @Resource
  20 + private FTPService ftpService;
  21 +
  22 + /**
  23 + * 文件上传
  24 + * @param sim sim号
  25 + * @param channel 通道号
  26 + * @param startTime 起始时间
  27 + * @param endTime 终止时间
  28 + * @return 上传结果
  29 + */
  30 + @GetMapping("/uploadFile/{sim}/{channel}/{startTime}/{endTime}")
  31 + public String uploadFile(@PathVariable String sim,
  32 + @PathVariable Integer channel,
  33 + @PathVariable String startTime,
  34 + @PathVariable String endTime) {
  35 + return ftpService.uploadFile(sim, channel, startTime, endTime);
  36 + }
  37 +}
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/controller/FlowController.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.jt1078.platform.controller;
  2 +
  3 +import com.genersoft.iot.vmp.conf.exception.ServiceException;
  4 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow;
  5 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.FlowService;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +import org.springframework.web.bind.annotation.GetMapping;
  8 +import org.springframework.web.bind.annotation.PathVariable;
  9 +import org.springframework.web.bind.annotation.RequestMapping;
  10 +import org.springframework.web.bind.annotation.RestController;
  11 +
  12 +import javax.annotation.Resource;
  13 +import java.util.Date;
  14 +import java.util.List;
  15 +
  16 +/**
  17 + * 流量统计控制层
  18 + *
  19 + * @Author WangXin
  20 + * @Data 2025/2/10
  21 + * @Version 1.0.0
  22 + */
  23 +@RestController
  24 +@RequestMapping("/flow")
  25 +public class FlowController {
  26 +
  27 + @Resource
  28 + private FlowService flowService;
  29 +
  30 + @GetMapping("/list/{timeType}/{statisticsType}/{time}/{sim}")
  31 + public List<SimFlow> list(@PathVariable String statisticsType,
  32 + @PathVariable String time,
  33 + @PathVariable String timeType,
  34 + @PathVariable String sim) throws ServiceException {
  35 + return flowService.getList(timeType, statisticsType, time, sim);
  36 + }
  37 +}
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/domain/ApiResult.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +import lombok.experimental.SuperBuilder;
  7 +
  8 +/**
  9 + * 大邑APi返回结果集
  10 + *
  11 + * @Author WangXin
  12 + * @Data 2025/2/11
  13 + * @Version 1.0.0
  14 + */
  15 +
  16 +@Data
  17 +@SuperBuilder
  18 +@AllArgsConstructor
  19 +@NoArgsConstructor
  20 +public class ApiResult {
  21 + /**
  22 + * 响应码(成功:200;客户端错误:400-499;服务端错误:500-599)
  23 + */
  24 + private Integer code;
  25 + /**
  26 + * 响应消息
  27 + */
  28 + private String msg;
  29 + /**
  30 + * 响应消息详情
  31 + */
  32 + private String detailMsg;
  33 + /**
  34 + * 响应消息体
  35 + */
  36 + private ApiResultData data;
  37 +}
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/domain/ApiResultData.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +import lombok.experimental.SuperBuilder;
  7 +
  8 +/**
  9 + * 大邑Api响应消息体
  10 + * @Author WangXin
  11 + * @Data 2025/2/11
  12 + * @Version 1.0.0
  13 + */
  14 +
  15 +@Data
  16 +@SuperBuilder
  17 +@AllArgsConstructor
  18 +@NoArgsConstructor
  19 +public class ApiResultData {
  20 + /**
  21 + * 终端手机号
  22 + */
  23 + private String clientId;
  24 + /**
  25 + * 应答流水号
  26 + */
  27 + private Integer responseSerialNo;
  28 + /**
  29 + * 应答Id
  30 + */
  31 + private Integer responseMessageId;
  32 + /**
  33 + * 结果:0.成功 1.失败 2.消息有误 3.不支持 4.报警处理确认
  34 + */
  35 + private Integer resultCode;
  36 +}
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/domain/SimFlow.java
1 package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain; 1 package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain;
2 2
3 import com.fasterxml.jackson.annotation.JsonFormat; 3 import com.fasterxml.jackson.annotation.JsonFormat;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Data;
  6 +import lombok.NoArgsConstructor;
  7 +import lombok.experimental.SuperBuilder;
4 import org.springframework.format.annotation.DateTimeFormat; 8 import org.springframework.format.annotation.DateTimeFormat;
5 9
6 import java.text.SimpleDateFormat; 10 import java.text.SimpleDateFormat;
@@ -13,53 +17,19 @@ import java.util.Date; @@ -13,53 +17,19 @@ import java.util.Date;
13 * @Data 2025/1/7 17 * @Data 2025/1/7
14 * @Version 1.0.0 18 * @Version 1.0.0
15 */ 19 */
  20 +@Data
  21 +@SuperBuilder
  22 +@AllArgsConstructor
  23 +@NoArgsConstructor
16 public class SimFlow { 24 public class SimFlow {
17 25
18 private String id; 26 private String id;
19 private String sim; 27 private String sim;
20 - private String channel;  
21 - private Double flow; 28 + private Integer channel;
  29 + private Long flow;
  30 + private Integer count;
22 private String time; 31 private String time;
23 -  
24 - public String getId() {  
25 - return id;  
26 - }  
27 -  
28 - public void setId(String id) {  
29 - this.id = id;  
30 - }  
31 -  
32 - public String getSim() {  
33 - return sim;  
34 - }  
35 -  
36 - public void setSim(String sim) {  
37 - this.sim = sim;  
38 - }  
39 -  
40 - public String getChannel() {  
41 - return channel;  
42 - }  
43 -  
44 - public void setChannel(String channel) {  
45 - this.channel = channel;  
46 - }  
47 -  
48 - public Double getFlow() {  
49 - return flow;  
50 - }  
51 -  
52 - public void setFlow(Double flow) {  
53 - this.flow = flow;  
54 - }  
55 -  
56 - public String getTime() {  
57 - return time;  
58 - }  
59 -  
60 - public void setTime(String time) {  
61 - this.time = time;  
62 - } 32 + private CarData carData;
63 33
64 @Override 34 @Override
65 public String toString() { 35 public String toString() {
@@ -72,13 +42,4 @@ public class SimFlow { @@ -72,13 +42,4 @@ public class SimFlow {
72 sb.append('}'); 42 sb.append('}');
73 return sb.toString(); 43 return sb.toString();
74 } 44 }
75 -  
76 - public static SimFlow build(String sim, String channel, Double flow) {  
77 - SimFlow simFlow = new SimFlow();  
78 - simFlow.setSim(sim);  
79 - simFlow.setChannel(channel);  
80 - simFlow.setFlow(flow);  
81 - simFlow.setTime(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));  
82 - return simFlow;  
83 - }  
84 } 45 }
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/domain/UploadFileReq.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +import lombok.experimental.SuperBuilder;
  7 +
  8 +/**
  9 + * 文件上传请求对象
  10 + *
  11 + * @Author WangXin
  12 + * @Data 2025/2/11
  13 + * @Version 1.0.0
  14 + */
  15 +@Data
  16 +@SuperBuilder
  17 +@AllArgsConstructor
  18 +@NoArgsConstructor
  19 +public class UploadFileReq {
  20 +
  21 + /**
  22 + * 终端手机号
  23 + */
  24 + private String clientId;
  25 + /**
  26 + * FTP服务器地址
  27 + */
  28 + private String ip;
  29 + /**
  30 + * FTP服务器端口
  31 + */
  32 + private Integer port;
  33 + /**
  34 + * FTP服务器用户名
  35 + */
  36 + private String username;
  37 + /**
  38 + * FTP服务器密码
  39 + */
  40 + private String password;
  41 + /**
  42 + * 文件上传路径
  43 + */
  44 + private String path;
  45 + /**
  46 + * 逻辑通道号
  47 + */
  48 + private Integer channelNo;
  49 + /**
  50 + * 开始时间
  51 + */
  52 + private String startTime;
  53 + /**
  54 + * 结束时间
  55 + */
  56 + private String endTime;
  57 + /**
  58 + * 报警标志0~31(参考808协议文档报警标志位定义)
  59 + */
  60 + private Integer warnBit1 = 0;
  61 + /**
  62 + * 报警标志32~63
  63 + */
  64 + private Integer warnBit2 = 0;
  65 + /**
  66 + * 音视频资源类型:0.音视频 1.音频 2.视频 3.视频或音视频
  67 + */
  68 + private Integer mediaType = 0;
  69 + /**
  70 + * 码流类型:0.所有码流 1.主码流 2.子码流
  71 + */
  72 + private Integer streamType = 1;
  73 + /**
  74 + * 存储位置:0.所有存储器 1.主存储器 2.灾备存储器
  75 + */
  76 + private Integer storageType = 0;
  77 + /**
  78 + * 任务执行条件(用bit位表示):[0]WIFI下可下载 [1]LAN连接时可下载 [2]3G/4G连接时可下载
  79 + */
  80 + private Integer condition = 0;
  81 +}
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/handler/HttpClientUtil.java
@@ -38,6 +38,7 @@ public class HttpClientUtil { @@ -38,6 +38,7 @@ public class HttpClientUtil {
38 private static final Logger log = LoggerFactory.getLogger(HttpClientUtil.class); 38 private static final Logger log = LoggerFactory.getLogger(HttpClientUtil.class);
39 39
40 public HttpClientPostEntity doPost(String url, Map<String, String> params, String jsessionid) throws URISyntaxException, IOException { 40 public HttpClientPostEntity doPost(String url, Map<String, String> params, String jsessionid) throws URISyntaxException, IOException {
  41 + long startTime = System.currentTimeMillis();
41 // 创建Httpclient对象 42 // 创建Httpclient对象
42 DefaultHttpClient httpclient = getHttpClient(); 43 DefaultHttpClient httpclient = getHttpClient();
43 // 定义请求的参数 44 // 定义请求的参数
@@ -64,7 +65,7 @@ public class HttpClientUtil { @@ -64,7 +65,7 @@ public class HttpClientUtil {
64 response = httpclient.execute(httpPost); 65 response = httpclient.execute(httpPost);
65 // 判断返回状态是否为200 66 // 判断返回状态是否为200
66 if (response.getStatusLine().getStatusCode() == 200) { 67 if (response.getStatusLine().getStatusCode() == 200) {
67 - return combationReturnObj(response, httpclient,url, null); 68 + return combationReturnObj(response, httpclient,url, null,startTime);
68 } 69 }
69 } finally { 70 } finally {
70 if (response != null) { 71 if (response != null) {
@@ -76,6 +77,7 @@ public class HttpClientUtil { @@ -76,6 +77,7 @@ public class HttpClientUtil {
76 } 77 }
77 78
78 public HttpClientPostEntity doPost(String url, String requestBody, String jsessionid) throws URISyntaxException, IOException { 79 public HttpClientPostEntity doPost(String url, String requestBody, String jsessionid) throws URISyntaxException, IOException {
  80 + long startTime = System.currentTimeMillis();
79 // 创建Httpclient对象 81 // 创建Httpclient对象
80 DefaultHttpClient httpclient = getHttpClient(); 82 DefaultHttpClient httpclient = getHttpClient();
81 // 定义请求的参数 83 // 定义请求的参数
@@ -99,7 +101,7 @@ public class HttpClientUtil { @@ -99,7 +101,7 @@ public class HttpClientUtil {
99 response = httpclient.execute(httpPost); 101 response = httpclient.execute(httpPost);
100 // 判断返回状态是否为200 102 // 判断返回状态是否为200
101 if (response.getStatusLine().getStatusCode() == 200) { 103 if (response.getStatusLine().getStatusCode() == 200) {
102 - return combationReturnObj(response, httpclient,url,requestBody); 104 + return combationReturnObj(response, httpclient,url,requestBody,startTime);
103 } 105 }
104 } catch (Exception e) { 106 } catch (Exception e) {
105 log.error("请求数据异常", e); 107 log.error("请求数据异常", e);
@@ -130,6 +132,7 @@ public class HttpClientUtil { @@ -130,6 +132,7 @@ public class HttpClientUtil {
130 } 132 }
131 133
132 public HttpClientPostEntity doGet(String url, String jsessionid) throws URISyntaxException, IOException { 134 public HttpClientPostEntity doGet(String url, String jsessionid) throws URISyntaxException, IOException {
  135 + long startTime = System.currentTimeMillis();
133 // 创建Httpclient对象 136 // 创建Httpclient对象
134 DefaultHttpClient httpclient = getHttpClient(); 137 DefaultHttpClient httpclient = getHttpClient();
135 // 定义请求的参数 138 // 定义请求的参数
@@ -151,7 +154,7 @@ public class HttpClientUtil { @@ -151,7 +154,7 @@ public class HttpClientUtil {
151 response = httpclient.execute(httpGet); 154 response = httpclient.execute(httpGet);
152 // 判断返回状态是否为200 155 // 判断返回状态是否为200
153 if (response.getStatusLine().getStatusCode() == 200) { 156 if (response.getStatusLine().getStatusCode() == 200) {
154 - return combationReturnObj(response, httpclient,url,null); 157 + return combationReturnObj(response, httpclient,url,null,startTime);
155 } 158 }
156 } finally { 159 } finally {
157 if (response != null) { 160 if (response != null) {
@@ -204,7 +207,7 @@ public class HttpClientUtil { @@ -204,7 +207,7 @@ public class HttpClientUtil {
204 * @throws IOException 207 * @throws IOException
205 */ 208 */
206 @NotNull 209 @NotNull
207 - private static HttpClientPostEntity combationReturnObj(CloseableHttpResponse response, DefaultHttpClient httpclient,String url,String requestBody) throws IOException { 210 + private static HttpClientPostEntity combationReturnObj(CloseableHttpResponse response, DefaultHttpClient httpclient,String url,String requestBody,long startTime) throws IOException {
208 HttpEntity httpEntity = response.getEntity(); 211 HttpEntity httpEntity = response.getEntity();
209 212
210 CookieStore cookieStore = httpclient.getCookieStore(); 213 CookieStore cookieStore = httpclient.getCookieStore();
@@ -213,7 +216,7 @@ public class HttpClientUtil { @@ -213,7 +216,7 @@ public class HttpClientUtil {
213 HttpClientPostEntity postEntity = new HttpClientPostEntity(); 216 HttpClientPostEntity postEntity = new HttpClientPostEntity();
214 postEntity.setCookieStore(cookieStore); 217 postEntity.setCookieStore(cookieStore);
215 postEntity.setResultStr(result); 218 postEntity.setResultStr(result);
216 - log.info("url:{};requestBody:{};response :{}",url,requestBody,"请求成功"); 219 + log.info("url:{};requestBody:{};response :{}; 耗时: {}s ",url,requestBody,"请求成功",System.currentTimeMillis()-startTime);
217 return postEntity; 220 return postEntity;
218 } 221 }
219 222
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/mapper/FlowMapper.java
@@ -16,30 +16,39 @@ public interface FlowMapper { @@ -16,30 +16,39 @@ public interface FlowMapper {
16 16
17 @Select(value = {" <script>" + 17 @Select(value = {" <script>" +
18 "SELECT " + 18 "SELECT " +
19 - " <if test=\"time != null and time == 'day'\" >" + 19 + " <if test=\"timeType != null and timeType == 'day'\" >" +
20 " `time`," + 20 " `time`," +
21 " </if>" + 21 " </if>" +
22 - " <if test=\"time != null and time == 'year'\" >" + 22 + " <if test=\"timeType != null and timeType == 'year'\" >" +
23 " YEAR(`time`) `time`," + 23 " YEAR(`time`) `time`," +
24 " </if>" + 24 " </if>" +
25 - " <if test=\"time != null and time == 'month'\" >" + 25 + " <if test=\"timeType != null and timeType == 'month'\" >" +
26 " CONCAT(YEAR(`time`),'-',MONTH(`time`)) `time`," + 26 " CONCAT(YEAR(`time`),'-',MONTH(`time`)) `time`," +
27 " </if>" + 27 " </if>" +
28 - " `sim`, `channel`, SUM(flow) flow" + 28 + " `sim`, `channel`, SUM(flow) flow " +
  29 + " <if test=\"statisticsType!=null and statisticsType !='' and statisticsType == 'All'\"> " +
  30 + " ,COUNT(DISTINCT sim) count " +
  31 + " </if>" +
29 " FROM `wvp_sim_flow`" + 32 " FROM `wvp_sim_flow`" +
30 " <where> " + 33 " <where> " +
31 - " <if test=\"time != null and time != '' and statisticsType = 'day'\">" + 34 + " <if test=\"time != null and time != 'null' and time != 'undefined' and time != '' and timeType == 'day'\">" +
32 " AND time = #{time}" + 35 " AND time = #{time}" +
33 " </if>" + 36 " </if>" +
34 - " <if test=\"time != null and time != '' and statisticsType = 'month'\">" + 37 + " <if test=\"time != null and time != 'null' and time != 'undefined' and time != '' and timeType == 'month'\">" +
35 " AND CONCAT(YEAR(`time`),'-',MONTH(`time`)) = #{time}" + 38 " AND CONCAT(YEAR(`time`),'-',MONTH(`time`)) = #{time}" +
36 " </if>" + 39 " </if>" +
37 - " <if test=\"time != null and time != '' and statisticsType = 'year'\">" + 40 + " <if test=\"time != null and time != 'null' and time != 'undefined' and time != '' and timeType == 'year'\">" +
38 " AND YEAR(`time`) = #{time}" + 41 " AND YEAR(`time`) = #{time}" +
39 " </if>" + 42 " </if>" +
  43 + " <if test=\"sim != null and sim != '' and sim != 'null' and sim != 'undefined'\"> " +
  44 + " AND sim like CONCAT('%',#{sim})" +
  45 + " </if>" +
40 " </where>" + 46 " </where>" +
41 - " GROUP BY sim " +  
42 - " <if test=\"statisticsType!=null and statisticsType !='' and statisticsType = 'channel' \">" + 47 + " <trim prefix=\"GROUP BY\" prefixOverrides=\",\">" +
  48 + " <if test=\"statisticsType!=null and statisticsType !='' and statisticsType != 'All'\"> " +
  49 + " ,sim " +
  50 + " </if>" +
  51 + " <if test=\"statisticsType!=null and statisticsType !='' and statisticsType == 'channel' \">" +
43 " ,`channel` " + 52 " ,`channel` " +
44 " </if>" + 53 " </if>" +
45 " <if test=\"timeType == 'day'\">" + 54 " <if test=\"timeType == 'day'\">" +
@@ -51,10 +60,11 @@ public interface FlowMapper { @@ -51,10 +60,11 @@ public interface FlowMapper {
51 " <if test=\"timeType == 'month'\" >" + 60 " <if test=\"timeType == 'month'\" >" +
52 " ,CONCAT(YEAR(`time`),'-',MONTH(`time`))" + 61 " ,CONCAT(YEAR(`time`),'-',MONTH(`time`))" +
53 " </if>" + 62 " </if>" +
  63 + "</trim>" +
54 " ORDER BY `time` DESC " + 64 " ORDER BY `time` DESC " +
55 " </script>"} 65 " </script>"}
56 ) 66 )
57 - List<SimFlow> getList(@Param("timeType") String timeType, @Param("statisticsType") String statisticsType, @Param("time") String time); 67 + List<SimFlow> getList(@Param("timeType") String timeType, @Param("statisticsType") String statisticsType, @Param("time") String time, @Param("sim") String sim);
58 68
59 @Insert( 69 @Insert(
60 "INSERT INTO " + 70 "INSERT INTO " +
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/remote/DaYiApi.java
1 package com.genersoft.iot.vmp.vmanager.jt1078.platform.remote; 1 package com.genersoft.iot.vmp.vmanager.jt1078.platform.remote;
2 2
3 import com.dtflys.forest.annotation.Address; 3 import com.dtflys.forest.annotation.Address;
  4 +import com.dtflys.forest.annotation.JSONBody;
  5 +import com.dtflys.forest.annotation.Post;
  6 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.ApiResult;
  7 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.UploadFileReq;
4 import com.genersoft.iot.vmp.vmanager.jt1078.platform.remote.cnofig.DaYiAddressSourceConfig; 8 import com.genersoft.iot.vmp.vmanager.jt1078.platform.remote.cnofig.DaYiAddressSourceConfig;
5 9
6 /** 10 /**
@@ -11,4 +15,13 @@ import com.genersoft.iot.vmp.vmanager.jt1078.platform.remote.cnofig.DaYiAddressS @@ -11,4 +15,13 @@ import com.genersoft.iot.vmp.vmanager.jt1078.platform.remote.cnofig.DaYiAddressS
11 */ 15 */
12 @Address(source = DaYiAddressSourceConfig.class) 16 @Address(source = DaYiAddressSourceConfig.class)
13 public interface DaYiApi { 17 public interface DaYiApi {
  18 +
  19 + /**
  20 + * 文件上传指令
  21 + * @param uploadFileReq 上传文件请求对象
  22 + * @return 结果集
  23 + */
  24 + @Post("/9206")
  25 + ApiResult uploadFile(@JSONBody UploadFileReq uploadFileReq);
  26 +
14 } 27 }
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/remote/cnofig/DaYiAddressSourceConfig.java
@@ -17,10 +17,8 @@ import static com.genersoft.iot.vmp.vmanager.util.URLParser.parseURL; @@ -17,10 +17,8 @@ import static com.genersoft.iot.vmp.vmanager.util.URLParser.parseURL;
17 @Configuration 17 @Configuration
18 public class DaYiAddressSourceConfig implements AddressSource { 18 public class DaYiAddressSourceConfig implements AddressSource {
19 19
20 - @Value("${tuohua.bsth.login.rest.baseURL}") 20 + @Value("${tuohua.bsth.jt1078.new_url}")
21 public String baseURL; 21 public String baseURL;
22 - @Value("${tuohua.bsth.login.rest.password}")  
23 - private String restPassword;  
24 22
25 @Override 23 @Override
26 public ForestAddress getAddress(ForestRequest request) { 24 public ForestAddress getAddress(ForestRequest request) {
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/service/FTPService.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.jt1078.platform.service;
  2 +
  3 +/**
  4 + * @Author WangXin
  5 + * @Data 2025/2/11
  6 + * @Version 1.0.0
  7 + */
  8 +public interface FTPService {
  9 + /**
  10 + * 文件上传
  11 + * @param sim sim号
  12 + * @param channel 通道号
  13 + * @param startTime 起始时间
  14 + * @param endTime 终止时间
  15 + * @return 上传结果
  16 + */
  17 + String uploadFile(String sim, Integer channel, String startTime, String endTime);
  18 +}
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/service/FlowService.java
1 package com.genersoft.iot.vmp.vmanager.jt1078.platform.service; 1 package com.genersoft.iot.vmp.vmanager.jt1078.platform.service;
2 2
  3 +import com.genersoft.iot.vmp.conf.exception.ServiceException;
3 import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow; 4 import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow;
4 5
  6 +import java.util.Date;
5 import java.util.List; 7 import java.util.List;
6 -import java.util.Map;  
7 8
8 /** 9 /**
9 * @Author WangXin 10 * @Author WangXin
@@ -13,10 +14,12 @@ import java.util.Map; @@ -13,10 +14,12 @@ import java.util.Map;
13 public interface FlowService { 14 public interface FlowService {
14 /** 15 /**
15 * 流量列表 16 * 流量列表
16 - * @param timeType 时间类型 17 + *
  18 + * @param timeType 时间类型
17 * @param statisticsType 统计类型 19 * @param statisticsType 统计类型
  20 + * @param sim
18 */ 21 */
19 - Map<String, SimFlow> getList(String timeType, String statisticsType, String time); 22 + List<SimFlow> getList(String timeType, String statisticsType, String time, String sim) throws ServiceException;
20 23
21 /** 24 /**
22 * 批量添加流量记录 25 * 批量添加流量记录
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/service/impl/FTPServiceImpl.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.jt1078.platform.service.impl;
  2 +
  3 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.FtpConfigBean;
  4 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.ApiResult;
  5 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.UploadFileReq;
  6 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.remote.DaYiApi;
  7 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.FTPService;
  8 +import org.springframework.stereotype.Service;
  9 +
  10 +import javax.annotation.Resource;
  11 +
  12 +/**
  13 + * @Author WangXin
  14 + * @Data 2025/2/11
  15 + * @Version 1.0.0
  16 + */
  17 +@Service
  18 +public class FTPServiceImpl implements FTPService {
  19 +
  20 + @Resource
  21 + private DaYiApi daYiApi;
  22 + @Resource
  23 + private FtpConfigBean ftpConfigBean;
  24 +
  25 +
  26 + @Override
  27 + public String uploadFile(String sim, Integer channel, String startTime, String endTime) {
  28 +
  29 + ApiResult apiResult = daYiApi.uploadFile(
  30 + UploadFileReq.builder()
  31 + .ip(ftpConfigBean.getHost())
  32 + .port(ftpConfigBean.getPort())
  33 + .password(ftpConfigBean.getPassword())
  34 + .username(ftpConfigBean.getUsername())
  35 + .clientId(sim)
  36 + .startTime(startTime)
  37 + .endTime(endTime)
  38 + .channelNo(channel)
  39 + .build());
  40 + return apiResult.getMsg();
  41 + }
  42 +}
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/service/impl/FlowServiceImpl.java
1 package com.genersoft.iot.vmp.vmanager.jt1078.platform.service.impl; 1 package com.genersoft.iot.vmp.vmanager.jt1078.platform.service.impl;
2 2
  3 +import com.genersoft.iot.vmp.conf.exception.ServiceException;
3 import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow; 4 import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow;
4 import com.genersoft.iot.vmp.vmanager.jt1078.platform.mapper.FlowMapper; 5 import com.genersoft.iot.vmp.vmanager.jt1078.platform.mapper.FlowMapper;
5 import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.FlowService; 6 import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.FlowService;
6 import org.springframework.stereotype.Service; 7 import org.springframework.stereotype.Service;
7 8
8 import javax.annotation.Resource; 9 import javax.annotation.Resource;
9 -import java.util.*; 10 +import java.util.List;
  11 +import java.util.UUID;
10 import java.util.stream.Collectors; 12 import java.util.stream.Collectors;
11 13
  14 +import static com.genersoft.iot.vmp.vmanager.jt1078.platform.config.TuohuaConfigBean.getCarData;
  15 +
12 /** 16 /**
13 * @Author WangXin 17 * @Author WangXin
14 * @Data 2025/1/7 18 * @Data 2025/1/7
@@ -21,11 +25,12 @@ public class FlowServiceImpl implements FlowService { @@ -21,11 +25,12 @@ public class FlowServiceImpl implements FlowService {
21 private FlowMapper flowMapper; 25 private FlowMapper flowMapper;
22 26
23 @Override 27 @Override
24 - public Map<String, SimFlow> getList(String timeType, String statisticsType, String time) {  
25 - List<SimFlow> list = flowMapper.getList(timeType, statisticsType, time);  
26 -  
27 -  
28 - return null; 28 + public List<SimFlow> getList(String timeType, String statisticsType, String time, String sim) throws ServiceException {
  29 + if (timeType != null && "day".equals(timeType) && time != null && !"null".equals(time)) {
  30 + time = time.split(" ")[0];
  31 + }
  32 + return flowMapper.getList(timeType, statisticsType, time, sim)
  33 + .stream().peek(simFlow -> simFlow.setCarData(getCarData(simFlow.getSim()))).collect(Collectors.toList());
29 } 34 }
30 35
31 @Override 36 @Override
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
1 package com.genersoft.iot.vmp.vmanager.streamProxy; 1 package com.genersoft.iot.vmp.vmanager.streamProxy;
2 2
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
4 -import com.genersoft.iot.vmp.common.GeneralCallback;  
5 import com.genersoft.iot.vmp.common.StreamInfo; 4 import com.genersoft.iot.vmp.common.StreamInfo;
6 import com.genersoft.iot.vmp.conf.UserSetting; 5 import com.genersoft.iot.vmp.conf.UserSetting;
7 import com.genersoft.iot.vmp.conf.exception.ControllerException; 6 import com.genersoft.iot.vmp.conf.exception.ControllerException;
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
@@ -30,13 +30,11 @@ import org.springframework.http.HttpStatus; @@ -30,13 +30,11 @@ import org.springframework.http.HttpStatus;
30 import org.springframework.http.ResponseEntity; 30 import org.springframework.http.ResponseEntity;
31 import org.springframework.stereotype.Controller; 31 import org.springframework.stereotype.Controller;
32 import org.springframework.util.ObjectUtils; 32 import org.springframework.util.ObjectUtils;
33 -import org.springframework.util.StringUtils;  
34 import org.springframework.web.bind.annotation.*; 33 import org.springframework.web.bind.annotation.*;
35 import org.springframework.web.context.request.async.DeferredResult; 34 import org.springframework.web.context.request.async.DeferredResult;
36 import org.springframework.web.multipart.MultipartFile; 35 import org.springframework.web.multipart.MultipartFile;
37 36
38 import javax.annotation.Resource; 37 import javax.annotation.Resource;
39 -import javax.servlet.ServletException;  
40 import javax.servlet.http.HttpServletRequest; 38 import javax.servlet.http.HttpServletRequest;
41 import java.io.IOException; 39 import java.io.IOException;
42 import java.io.InputStream; 40 import java.io.InputStream;
src/main/java/com/genersoft/iot/vmp/vmanager/util/FTPUtils.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.util;
  2 +
  3 +import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.FtpConfigBean;
  4 +import lombok.extern.log4j.Log4j2;
  5 +import org.apache.commons.net.ftp.FTPClient;
  6 +import org.apache.commons.net.ftp.FTPReply;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import javax.annotation.Resource;
  10 +import java.io.IOException;
  11 +
  12 +/**
  13 + * FTP工具类
  14 + *
  15 + * @Author WangXin
  16 + * @Data 2025/2/11
  17 + * @Version 1.0.0
  18 + */
  19 +@Log4j2
  20 +@Component
  21 +public class FTPUtils {
  22 +
  23 + @Resource
  24 + private FtpConfigBean ftpConfigBean;
  25 +
  26 + private FTPClient connectFtpServer() {
  27 + FTPClient ftpClient = new FTPClient();
  28 + ftpClient.setConnectTimeout(1000 * 60);
  29 + ftpClient.setControlEncoding("utf-8");
  30 + ftpClient.enterLocalPassiveMode();
  31 +
  32 + int retryTimes = ftpConfigBean.getRetryTimes(); // 假设getRetryTimes方法返回int类型的重试次数,-1表示无限重试
  33 + boolean isConnected = false;
  34 + int attempts = 0;
  35 +
  36 + while (!isConnected && (retryTimes == -1 || attempts < retryTimes)) {
  37 + try {
  38 + int replyCode;
  39 + ftpClient.connect(ftpConfigBean.getHost());
  40 + ftpClient.login(ftpConfigBean.getUsername(), ftpConfigBean.getPassword());
  41 + replyCode = ftpClient.getReplyCode();
  42 +
  43 + if (!FTPReply.isPositiveCompletion(replyCode)) {
  44 + log.info("连接FTP服务器 {} 失败", ftpConfigBean.getHost());
  45 + ftpClient.disconnect();
  46 + attempts++;
  47 + if (retryTimes != -1) {
  48 + log.info("第 {} 次尝试连接失败, 将重新连接", attempts);
  49 + }
  50 + continue; // 连接不成功,继续循环
  51 + }
  52 + isConnected = true;
  53 + log.info("replyCode:{}", replyCode);
  54 + } catch (IOException e) {
  55 + log.error("连接失败: {}", e.toString());
  56 + attempts++;
  57 + if (retryTimes != -1) {
  58 + log.info("第 {} 次尝试连接失败, 错误信息: {}", attempts, e.getMessage());
  59 + }
  60 + try {
  61 + // 等待一段时间再重试
  62 + Thread.sleep(ftpConfigBean.getRetryWaitTimes());
  63 + } catch (InterruptedException ie) {
  64 + Thread.currentThread().interrupt();
  65 + }
  66 + }
  67 + }
  68 + if (!isConnected) {
  69 + log.error("无法连接到FTP服务器,已达到最大重试次数");
  70 + return null;
  71 + }
  72 + return ftpClient;
  73 + }
  74 +}
src/main/java/com/genersoft/iot/vmp/vmanager/util/RsRequestUtils.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.util;
  2 +
  3 +import cn.hutool.http.HttpUtil;
  4 +import org.slf4j.Logger;
  5 +import org.slf4j.LoggerFactory;
  6 +
  7 +import java.security.MessageDigest;
  8 +import java.util.*;
  9 +
  10 +/**
  11 + * RS 接口调用工具类
  12 + * Created by panzhao on 2017/8/2.
  13 + */
  14 +public class RsRequestUtils {
  15 +
  16 + private static String password;
  17 +
  18 + static {
  19 + password = "f8267b7bc5e51994bab57c8e8884f203609d1dc3";
  20 + }
  21 +
  22 + static Logger logger = LoggerFactory.getLogger(RsRequestUtils.class);
  23 +
  24 + /**
  25 + * 生成参数字符串
  26 + *
  27 + * @return
  28 + */
  29 + public static String getParams() {
  30 + String rs = "";
  31 + try {
  32 + String nonce = getNonce(6);
  33 + long t = System.currentTimeMillis();
  34 +
  35 + Map<String, String> map = new HashMap<>();
  36 + map.put("password", password);
  37 + map.put("timestamp", t + "");
  38 + map.put("nonce", nonce);
  39 +
  40 + String sign = getSHA1(map);
  41 +
  42 + rs = "?password=" + password + "&timestamp=" + t + "&nonce=" + nonce + "&sign=" + sign;
  43 + } catch (Exception e) {
  44 + logger.error("", e);
  45 + }
  46 + return rs;
  47 + }
  48 +
  49 + /**
  50 + * 生成参数字符串
  51 + *
  52 + * @return
  53 + */
  54 + public static String getParams(Map<String, String> paramMap) {
  55 + StringBuilder rs = new StringBuilder("?");
  56 + try {
  57 + String nonce = getNonce(6);
  58 + long t = System.currentTimeMillis();
  59 +
  60 + paramMap.put("password", password);
  61 + paramMap.put("timestamp", t + "");
  62 + paramMap.put("nonce", nonce);
  63 +
  64 + String sign = getSHA1(paramMap);
  65 + paramMap.put("sign", sign);
  66 +
  67 + Set<String> ks = paramMap.keySet();
  68 + for (String k : ks) {
  69 + rs.append(k + "=" + paramMap.get(k) + "&");
  70 + }
  71 + rs.deleteCharAt(rs.length() - 1);
  72 + } catch (Exception e) {
  73 + logger.error("", e);
  74 + }
  75 + return rs.toString();
  76 + }
  77 +
  78 + /**
  79 + * 生成随机字符串
  80 + *
  81 + * @return
  82 + */
  83 + public static String getNonce(int length) {
  84 + String base = "abcdefghijklmnopqrstuvwxyz0123456789";
  85 + Random random = new Random();
  86 + StringBuffer sb = new StringBuffer();
  87 + for (int i = 0; i < length; i++) {
  88 + int number = random.nextInt(base.length());
  89 + sb.append(base.charAt(number));
  90 + }
  91 + return sb.toString();
  92 + }
  93 +
  94 + private static String getSHA1(Map<String, String> map) throws Exception {
  95 + try {
  96 + String[] array = new String[map.size()];
  97 + map.values().toArray(array);
  98 + StringBuffer sb = new StringBuffer();
  99 + // 字符串排序
  100 + Arrays.sort(array);
  101 + for (int i = 0; i < array.length; i++) {
  102 + sb.append(array[i]);
  103 + }
  104 + String str = sb.toString();
  105 + // SHA1签名生成
  106 + MessageDigest md = MessageDigest.getInstance("SHA-1");
  107 + md.update(str.getBytes());
  108 + byte[] digest = md.digest();
  109 + StringBuffer hexStr = new StringBuffer();
  110 + String shaHex;
  111 + for (int i = 0; i < digest.length; i++) {
  112 + shaHex = Integer.toHexString(digest[i] & 0xFF);
  113 + if (shaHex.length() < 2) {
  114 + hexStr.append(0);
  115 + }
  116 + hexStr.append(shaHex);
  117 + }
  118 + return hexStr.toString();
  119 + } catch (Exception e) {
  120 + throw e;
  121 + }
  122 + }
  123 +
  124 + public static void main(String[] args) {
  125 +// StringBuilder rs = null;
  126 +// try {
  127 +// rs = HttpClientUtils.get("http://106.14.30.180:9089/webservice/rest/schedule_real/execs?password=e126853c7f6f43b4857fa8dfe3b28b5d90be9e68&timestamp=1587101390953&nonce=z5uefd&sign=cbdc60ec931cdf8f4b45104ddd6809a16f82e76f");
  128 +// } catch (Exception e) {
  129 +// e.printStackTrace();
  130 +// }
  131 + String lineInfoUrl = "http://58.34.47.74:9089/webservice/rest/line/company/55" + RsRequestUtils.getParams();
  132 + String lineInfoJson = HttpUtil.get(lineInfoUrl);
  133 + System.out.println(lineInfoUrl);
  134 +// System.out.println(rs.toString());
  135 +// List<ScheduleRealInfo> list = JSONArray.parseArray(rs.toString(), ScheduleRealInfo.class);
  136 +// System.out.println(list.size());
  137 +
  138 + }
  139 +}
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
@@ -182,7 +182,6 @@ public class ApiStreamController { @@ -182,7 +182,6 @@ public class ApiStreamController {
182 result.setResult(resultJjson); 182 result.setResult(resultJjson);
183 } 183 }
184 }); 184 });
185 -  
186 return result; 185 return result;
187 } 186 }
188 187
src/main/resources/application-dev100.yml
@@ -31,7 +31,7 @@ spring: @@ -31,7 +31,7 @@ spring:
31 master: 31 master:
32 type: com.zaxxer.hikari.HikariDataSource 32 type: com.zaxxer.hikari.HikariDataSource
33 driver-class-name: com.mysql.cj.jdbc.Driver 33 driver-class-name: com.mysql.cj.jdbc.Driver
34 - url: jdbc:mysql://192.168.169.100:3306/wvp4?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=TRUE&serverTimezone=PRC&useSSL=false&allowMultiQueries=true 34 + url: jdbc:mysql://192.168.169.100:3306/wvp4?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=TRUE&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&sessionVariables=sql_mode='NO_ENGINE_SUBSTITUTION'&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
35 username: root 35 username: root
36 password: guzijian 36 password: guzijian
37 hikari: 37 hikari:
@@ -141,13 +141,14 @@ tuohua: @@ -141,13 +141,14 @@ tuohua:
141 historyUdpPort: 9999 141 historyUdpPort: 9999
142 ip : 61.169.120.202 142 ip : 61.169.120.202
143 jt1078: 143 jt1078:
144 - ports: 9101,9600 144 + ports: 49101,49200
145 port: 9100 145 port: 9100
146 httpPort: 3333 146 httpPort: 3333
147 addPortVal: 0 147 addPortVal: 0
148 pushURL: http://127.0.0.1:3333/new/server/{pushKey}/{port}/{httpPort} 148 pushURL: http://127.0.0.1:3333/new/server/{pushKey}/{port}/{httpPort}
149 stopPushURL: http://127.0.0.1:3333/stop/channel/{pushKey}/{port}/{httpPort} 149 stopPushURL: http://127.0.0.1:3333/stop/channel/{pushKey}/{port}/{httpPort}
150 url: http://192.168.168.152:8100/device/{0} 150 url: http://192.168.168.152:8100/device/{0}
  151 + new_url: http://192.168.168.152:8100/device
151 historyListPort: 9205 152 historyListPort: 9205
152 playHistoryPort: 9201 153 playHistoryPort: 9201
153 sendPort: 9101 154 sendPort: 9101
@@ -159,3 +160,31 @@ tuohua: @@ -159,3 +160,31 @@ tuohua:
159 url: http://192.168.169.100:3333/video/{stream}.flv 160 url: http://192.168.169.100:3333/video/{stream}.flv
160 playURL: /play/wasm/ws%3A%2F%2F{ip}%3A{port}%2Fschedule%2F{sim}-{channel}.live.flv%3FcallId%{publickey} 161 playURL: /play/wasm/ws%3A%2F%2F{ip}%3A{port}%2Fschedule%2F{sim}-{channel}.live.flv%3FcallId%{publickey}
161 162
  163 +ftp:
  164 + basePath: /wvp-local
  165 + host: 192.168.169.100
  166 + httpPath: ftp://192.168.169.100
  167 + filePathPrefix: http://192.168.169.100:10021/wvp-local
  168 + password: ftpadmin
  169 + port: 21
  170 + username: ftp@123
  171 + retryTimes: 5
  172 + retryWaitTimes: 3000
  173 +
  174 +forest:
  175 + backend: okhttp3 # 后端HTTP框架(默认为 okhttp3)
  176 + max-connections: 1000 # 连接池最大连接数(默认为 500)
  177 + max-route-connections: 500 # 每个路由的最大连接数(默认为 500)
  178 + max-request-queue-size: 100 # [自v1.5.22版本起可用] 最大请求等待队列大小
  179 + max-async-thread-size: 300 # [自v1.5.21版本起可用] 最大异步线程数
  180 + max-async-queue-size: 16 # [自v1.5.22版本起可用] 最大异步线程池队列大小
  181 + timeout: 3000 # [已不推荐使用] 请求超时时间,单位为毫秒(默认为 3000)
  182 + connect-timeout: 3000 # 连接超时时间,单位为毫秒(默认为 timeout)
  183 + read-timeout: 3000 # 数据读取超时时间,单位为毫秒(默认为 timeout)
  184 + max-retry-count: 0 # 请求失败后重试次数(默认为 0 次不重试)
  185 + # ssl-protocol: TLS # 单向验证的HTTPS的默认TLS协议(默认为 TLS)
  186 + log-enabled: true # 打开或关闭日志(默认为 true)
  187 + log-request: true # 打开/关闭Forest请求日志(默认为 true)
  188 + log-response-status: true # 打开/关闭Forest响应状态日志(默认为 true)
  189 + log-response-content: true # 打开/关闭Forest响应内容日志(默认为 false)
  190 +# async-mode: platform # [自v1.5.27版本起可用] 异步模式(默认为 platform)
src/test/java/com/genersoft/iot/vmp/jt1078/JT1078ServerTest.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.jt1078;  
2 -  
3 -import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template;  
4 -import com.genersoft.iot.vmp.jt1078.codec.netty.TcpServer;  
5 -import com.genersoft.iot.vmp.jt1078.proc.response.J9102;  
6 -import com.genersoft.iot.vmp.jt1078.proc.response.J9201;  
7 -import com.genersoft.iot.vmp.jt1078.proc.response.J9202;  
8 -import com.genersoft.iot.vmp.jt1078.proc.response.J9205;  
9 -  
10 -import java.util.Scanner;  
11 -  
12 -/**  
13 - * @author QingtaiJiang  
14 - * @date 2023/4/28 14:22  
15 - * @email qingtaij@163.com  
16 - */  
17 -public class JT1078ServerTest {  
18 -  
19 - private static final JT1078Template jt1078Template = new JT1078Template();  
20 -  
21 - public static void main(String[] args) {  
22 - System.out.println("Starting jt1078 server...");  
23 - TcpServer tcpServer = new TcpServer(21078);  
24 - tcpServer.start();  
25 - System.out.println("Start jt1078 server success!");  
26 -  
27 -  
28 - Scanner s = new Scanner(System.in);  
29 - while (true) {  
30 - String code = s.nextLine();  
31 - switch (code) {  
32 - case "1":  
33 - test9102();  
34 - break;  
35 - case "2":  
36 - test9201();  
37 - break;  
38 - case "3":  
39 - test9202();  
40 - break;  
41 - case "4":  
42 - test9205();  
43 - break;  
44 - default:  
45 - break;  
46 - }  
47 - }  
48 - }  
49 -  
50 - private static void test9102() {  
51 - J9102 j9102 = new J9102();  
52 - j9102.setChannel(1);  
53 - j9102.setCommand(0);  
54 - j9102.setCloseType(0);  
55 - j9102.setStreamType(0);  
56 -  
57 - String s = jt1078Template.stopLive("18864197066", j9102, 6);  
58 - System.out.println(s);  
59 - }  
60 -  
61 - private static void test9201() {  
62 - J9201 j9201 = new J9201();  
63 - j9201.setIp("192.168.1.1");  
64 - j9201.setChannel(1);  
65 - j9201.setTcpPort(7618);  
66 - j9201.setUdpPort(7618);  
67 - j9201.setType(0);  
68 - j9201.setRate(0);  
69 - j9201.setStorageType(0);  
70 - j9201.setPlaybackType(0);  
71 - j9201.setPlaybackSpeed(0);  
72 - j9201.setStartTime("230428134100");  
73 - j9201.setEndTime("230428134200");  
74 -  
75 - String s = jt1078Template.startBackLive("18864197066", j9201, 6);  
76 - System.out.println(s);  
77 - }  
78 -  
79 - private static void test9202() {  
80 - J9202 j9202 = new J9202();  
81 -  
82 - j9202.setChannel(1);  
83 - j9202.setPlaybackType(2);  
84 - j9202.setPlaybackSpeed(0);  
85 - j9202.setPlaybackTime("230428134100");  
86 -  
87 - String s = jt1078Template.controlBackLive("18864197066", j9202, 6);  
88 - System.out.println(s);  
89 - }  
90 -  
91 - private static void test9205() {  
92 - J9205 j9205 = new J9205();  
93 - j9205.setChannelId(1);  
94 - j9205.setStartTime("230428134100");  
95 - j9205.setEndTime("230428134100");  
96 - j9205.setMediaType(0);  
97 - j9205.setStreamType(0);  
98 - j9205.setStorageType(0);  
99 -  
100 - String s = jt1078Template.queryBackTime("18864197066", j9205, 6);  
101 - System.out.println(s);  
102 - }  
103 -}  
web_src/config/index.js
@@ -11,14 +11,14 @@ module.exports = { @@ -11,14 +11,14 @@ module.exports = {
11 assetsPublicPath: "/", 11 assetsPublicPath: "/",
12 proxyTable: { 12 proxyTable: {
13 "/debug": { 13 "/debug": {
14 - target: "http://127.0.0.1:28080", 14 + target: "http://127.0.0.1:16030",
15 changeOrigin: true, 15 changeOrigin: true,
16 pathRewrite: { 16 pathRewrite: {
17 "^/debug": "/", 17 "^/debug": "/",
18 }, 18 },
19 }, 19 },
20 "/static/snap": { 20 "/static/snap": {
21 - target: "http://127.0.0.1:28080", 21 + target: "http://127.0.0.1:16030",
22 changeOrigin: true, 22 changeOrigin: true,
23 // pathRewrite: { 23 // pathRewrite: {
24 // '^/static/snap': '/static/snap' 24 // '^/static/snap': '/static/snap'
web_src/src/components/DeviceList1078.vue
1 <template> 1 <template>
2 - <div id="devicePosition" style="width:100vw; height: 91vh"> 2 + <div v-loading="loading" id="devicePosition" style="width:100vw; height: 91vh">
3 <el-container v-loading="loading" style="height: 91vh;" element-loading-text="拼命加载中"> 3 <el-container v-loading="loading" style="height: 91vh;" element-loading-text="拼命加载中">
4 <el-aside width="300px" style="background-color: #ffffff"> 4 <el-aside width="300px" style="background-color: #ffffff">
5 - <div class="device-tree-main-box">  
6 - <div id="DeviceTree" style="width: 100%;height: 100%; background-color: #FFFFFF; overflow: auto">  
7 - <el-container>  
8 - <el-header>设备列表</el-header>  
9 - <el-main style="background-color: #ffffff;">  
10 - <tree :nodes="nodes" @onClick="onClick" @onCheck="onCheck" @onExpand="onExpand"  
11 - @onRightClick="treeRightMenuFun" @onCreated="handleCreated" :props="defaultProps"/>  
12 - </el-main>  
13 - </el-container>  
14 - </div>  
15 - </div> 5 + <device1078-tree :tree-data="sourceValue" @node-click="nodeClick"></device1078-tree>
16 </el-aside> 6 </el-aside>
17 <el-container> 7 <el-container>
18 <el-header height="5vh" style="text-align: left;font-size: 17px;line-height:5vh;width:90%"> 8 <el-header height="5vh" style="text-align: left;font-size: 17px;line-height:5vh;width:90%">
19 -  
20 <i class="el-icon-s-platform btn" :class="{active:spilt==1}" @click="spiltClickFun(1)"/> 9 <i class="el-icon-s-platform btn" :class="{active:spilt==1}" @click="spiltClickFun(1)"/>
21 <i class="el-icon-menu btn" :class="{active:spilt==4}" @click="spiltClickFun(4)"/> 10 <i class="el-icon-menu btn" :class="{active:spilt==4}" @click="spiltClickFun(4)"/>
22 <i class="el-icon-s-grid btn" :class="{active:spilt==9}" @click="spiltClickFun(9)"/> 11 <i class="el-icon-s-grid btn" :class="{active:spilt==9}" @click="spiltClickFun(9)"/>
23 <i class="el-icon-full-screen btn" :class="{active:spilt==12}" @click="spiltClickFun(12)"/> 12 <i class="el-icon-full-screen btn" :class="{active:spilt==12}" @click="spiltClickFun(12)"/>
24 -  
25 <el-button size="mini" style="margin-left: 15px;" @click="oneClickPlayback()">一键播放车辆视频</el-button> 13 <el-button size="mini" style="margin-left: 15px;" @click="oneClickPlayback()">一键播放车辆视频</el-button>
26 <el-button size="mini" style="margin-left: 15px;" @click="closeSelectItem()">关闭选中画面流</el-button> 14 <el-button size="mini" style="margin-left: 15px;" @click="closeSelectItem()">关闭选中画面流</el-button>
27 <el-button size="mini" style="margin-left: 15px;" @click="closeSelectCarItem()">一键关闭选中车辆流</el-button> 15 <el-button size="mini" style="margin-left: 15px;" @click="closeSelectCarItem()">一键关闭选中车辆流</el-button>
28 - <el-button size="mini" style="margin-left: 15px;" @click="inspectionsDialog">视屏巡查</el-button> 16 + <el-button size="mini" style="margin-left: 15px;" @click="inspectionsDialog" v-if="patrolValue" type="danger">
  17 + 视屏巡查中
  18 + </el-button>
  19 + <el-button size="mini" style="margin-left: 15px;" @click="inspectionsDialog" v-else>视屏巡查</el-button>
29 </el-header> 20 </el-header>
30 -  
31 <el-main style="padding: 0;"> 21 <el-main style="padding: 0;">
32 - <div class="scroll-container" style="width: 100%;height: 85vh;display: flex;flex-wrap: wrap;background-color: #000;"> 22 + <div class="scroll-container"
  23 + style="width: 100%;height: 85vh;display: flex;flex-wrap: wrap;background-color: #000;">
33 <div v-for="i in spilt" :key="i" class="play-box" 24 <div v-for="i in spilt" :key="i" class="play-box"
34 :style="liveStyle" :class="{redborder:playerIdx == (i-1)}" 25 :style="liveStyle" :class="{redborder:playerIdx == (i-1)}"
35 @click="playerIdx = (i-1)"> 26 @click="playerIdx = (i-1)">
@@ -58,18 +49,55 @@ @@ -58,18 +49,55 @@
58 49
59 <el-dialog title="视屏巡查设置" width="600" append-to-body 50 <el-dialog title="视屏巡查设置" width="600" append-to-body
60 :close-on-click-modal="false" 51 :close-on-click-modal="false"
61 - :visible.sync="showVideoDialog" >  
62 - <tree-transfer  
63 - style="text-align: left; display: inline-block"  
64 - :to_data="targetValue"  
65 - :filter="true"  
66 - :title="['源列表', '巡查列表']"  
67 - @change="handleChange"  
68 - :from_data="sourceValue">  
69 - </tree-transfer> 52 + :visible.sync="showVideoDialog" v-loading="loading">
  53 + <el-card class="box-card">
  54 + <tree-transfer
  55 + :disabled="patrolValue"
  56 + style="text-align: left; display: inline-block;"
  57 + :to_data="targetValue"
  58 + :defaultExpandedKeys="expandedKeys"
  59 + node_key="id"
  60 + :filter="true"
  61 + :title="['源列表', '巡查列表']"
  62 + :from_data="sourceValue"
  63 + :defaultProps="treeProps"
  64 + :filter-node="filterNode"
  65 + class="inspections-tree"
  66 + height="500px">
  67 + </tree-transfer>
  68 + </el-card>
  69 + <el-card class="box-card">
  70 + <div slot="header" class="clearfix">
  71 + <span style="font-size: math">巡查时间间隔</span>
  72 + </div>
  73 + <el-time-select
  74 + v-model="timerTime"
  75 + :picker-options="{
  76 + start: '00:30',
  77 + step: '00:30',
  78 + end: '5:00'
  79 + }"
  80 + placeholder="选择巡查时间"
  81 + :disabled="patrolValue">
  82 + </el-time-select>
  83 + </el-card>
  84 + <el-card class="box-card">
  85 + <div slot="header" class="clearfix">
  86 + <span style="font-size: math">巡查宫格数量</span>
  87 + </div>
  88 + <el-select v-model="patrolCell" placeholder="placeholder" :disabled="patrolValue">
  89 + <el-option
  90 + v-for="item in patrolCellList"
  91 + :key="item"
  92 + :label="item"
  93 + :value="item">
  94 + </el-option>
  95 + </el-select>
  96 + </el-card>
70 <div slot="footer" class="dialog-footer"> 97 <div slot="footer" class="dialog-footer">
71 - <el-button type="primary" @click="submitForm">确 定</el-button>  
72 - <el-button @click="cancel">取 消</el-button> 98 + <el-button type="danger" v-if="patrolValue" @click="closeInspections">关闭</el-button>
  99 + <el-button type="primary" v-else @click="openInspections">开启</el-button>
  100 + <el-button @click="showVideoDialog = false">取 消</el-button>
73 </div> 101 </div>
74 </el-dialog> 102 </el-dialog>
75 </div> 103 </div>
@@ -80,34 +108,60 @@ import uiHeader from &quot;../layout/UiHeader.vue&quot;; @@ -80,34 +108,60 @@ import uiHeader from &quot;../layout/UiHeader.vue&quot;;
80 import player from './common/jessibuca.vue'; 108 import player from './common/jessibuca.vue';
81 import DeviceTree from './common/DeviceTree.vue' 109 import DeviceTree from './common/DeviceTree.vue'
82 import treeTransfer from "el-tree-transfer"; 110 import treeTransfer from "el-tree-transfer";
  111 +import {parseTime} from "../../utils/ruoyi";
  112 +import Device1078Tree from "./JT1078Components/deviceList/Device1078Tree.vue";
  113 +
83 export default { 114 export default {
84 name: "live", 115 name: "live",
85 components: { 116 components: {
  117 + Device1078Tree,
86 uiHeader, player, DeviceTree, tree, treeTransfer 118 uiHeader, player, DeviceTree, tree, treeTransfer
87 }, 119 },
88 data() { 120 data() {
89 return { 121 return {
90 - //穿梭框数据-----------↓ 122 + //车辆列表过滤
  123 + filterText: '',
  124 + //穿梭框巡查数据-----------↓
  125 + //穿梭框默认展开
  126 + expandedKeys: [],
  127 + // 批次获取器
  128 + batchFetcher: null,
91 //源列表数据 129 //源列表数据
92 sourceValue: [], 130 sourceValue: [],
  131 + //原始sim列表 (sim对象)
  132 + simList: [],
93 //目标列表数据 133 //目标列表数据
94 targetValue: [], 134 targetValue: [],
  135 + //巡查播放原始列表
  136 + lastTargetValue: [],
  137 + //巡查过滤列表 (sim)
  138 + lastTargetValueFilter: [],
  139 + //现在正在播放的列表
  140 + nowPlayArray: [],
95 //prop参数 141 //prop参数
96 - treeProps:{ 142 + treeProps: {
97 children: 'children', 143 children: 'children',
98 - label: 'label',  
99 - name: 'name' 144 + label: 'name',
  145 + disabled: 'disabled',
100 }, 146 },
101 //巡查按钮 147 //巡查按钮
102 patrolValue: false, 148 patrolValue: false,
103 - //巡查数据定时器  
104 - carInfoTimeout: '', 149 + //巡查宫格数量
  150 + patrolCell: 9,
  151 + //巡查宫格下拉框数据
  152 + patrolCellList: [1, 4, 9, 12],
  153 + //巡查时间
  154 + timerTime: '00:30',
105 //巡查定时器 155 //巡查定时器
106 - timer : '', 156 + fetchInterval: null,
107 //上线车辆 157 //上线车辆
108 onlineCar: new Map(), 158 onlineCar: new Map(),
  159 + //车辆数据定时器
  160 + carInfoTimeout: null,
109 //车载key集合 161 //车载key集合
110 onlineCarKeys: [], 162 onlineCarKeys: [],
  163 + //树节点对象
  164 + simNodeData: null,
111 videoUrl: [''], 165 videoUrl: [''],
112 videoUrlHistory: "", 166 videoUrlHistory: "",
113 spilt: 1,//分屏 167 spilt: 1,//分屏
@@ -167,6 +221,7 @@ export default { @@ -167,6 +221,7 @@ export default {
167 }, 221 },
168 created() { 222 created() {
169 this.checkPlayByParam(); 223 this.checkPlayByParam();
  224 + this.getCarInfoBuffer()
170 }, 225 },
171 beforeDestroy() { 226 beforeDestroy() {
172 if (!this.isEmpty(this.timer)) { 227 if (!this.isEmpty(this.timer)) {
@@ -224,85 +279,493 @@ export default { @@ -224,85 +279,493 @@ export default {
224 } 279 }
225 }, 280 },
226 methods: { 281 methods: {
227 - handleChange(value, direction, movedKeys) {  
228 - console.log(value, direction, movedKeys); 282 + /**
  283 + * 统计树节点下一级有多少在线数量
  284 + */
  285 + statisticsOnline(data) {
  286 + for (let i in data) {
  287 + console.log(data[i].abnormalStatus === undefined && data[i].children && data[i].children.length > 0)
  288 + if (data[i].abnormalStatus === undefined && data[i].children && data[i].children.length > 0) {
  289 + data[i].onlineData = data[i].children.filter(item => item.abnormalStatus === 1);
  290 + }
  291 + }
  292 + },
  293 + /**
  294 + * 树点击事件
  295 + */
  296 + nodeClick(data, node) {
  297 + if (data.children && data.children.length > 0 && data.abnormalStatus) {
  298 + this.simNodeData = data
  299 + } else if (data.children === undefined) {
  300 + this.simNodeData = node.parent.data
  301 + this.openPlay(data, this.playerIdx);
  302 + }
  303 + },
  304 + /**
  305 + * 模糊查询树
  306 + */
  307 + filterNode(value, data) {
  308 + console.log(data)
  309 + if (!value) return true;
  310 + return this.findSearKey(data, value)
  311 + },
  312 + /**
  313 + * 递归搜索父级是否包含关键字
  314 + */
  315 + findSearKey(node, key) {
  316 + if (node.name.indexOf(key) !== -1) {
  317 + return true;
  318 + } else {
  319 + if (node.parent === undefined || node.parent === null) {
  320 + return false;
  321 + } else {
  322 + return this.findSearKey(node.parent, key);
  323 + }
  324 + }
  325 + },
  326 + /**
  327 + * 处理返回的tree数据
  328 + */
  329 + processingTreeData(data, pid, parent) {
  330 + for (let i in data) {
  331 + data[i].pid = pid
  332 + data[i].parent = parent;
  333 + if (data[i].children || (Array.isArray(data[i].children) && data[i].abnormalStatus === undefined)) {
  334 + this.processingTreeData(data[i].children, data[i].id, data[i]);
  335 + } else {
  336 + data[i].name = data[i].code
  337 + if (data[i].abnormalStatus !== 1) {
  338 + data[i].disabled = true;
  339 + let targetValue = this.targetValue;
  340 + if (targetValue.length > 0) {
  341 + this.disableItemsByName(targetValue, data[i].name);
  342 + }
  343 + }
  344 + this.addChannels(data[i])
  345 + }
  346 + }
  347 + },
  348 + /**
  349 + * 原始sim列表数据 (用来验证视屏巡查车辆是否在线)
  350 + * @param data 查询后台树列表
  351 + */
  352 + processingSimList(data) {
  353 + if (data && data.length > 0) {
  354 + for (let i in data) {
  355 + if (data[i].children === undefined && data[i].abnormalStatus) {
  356 + this.simList.push(data[i]);
  357 + } else if (data[i].children && data[i].children.length > 0) {
  358 + this.processingSimList(data[i].children);
  359 + }
  360 + }
  361 + }
229 }, 362 },
230 - //查询车辆信息  
231 - getCarInfo(){ 363 + /**
  364 + * 处理巡查列表数据
  365 + */
  366 + disableItemsByName(arr, targetName) {
  367 + arr.forEach(item => {
  368 + // 检查当前项是否是对象并且包含 name 属性且值为 targetName
  369 + if (item && typeof item === 'object' && item.name === targetName) {
  370 + item.disabled = true;
  371 + }
  372 + // 如果当前项有 children 属性且是数组,则递归调用自身
  373 + if (item && Array.isArray(item.children)) {
  374 + this.disableItemsByName(item.children, targetName);
  375 + }
  376 + });
  377 + },
  378 + /**
  379 + * 查询车辆信息
  380 + */
  381 + getCarInfoBuffer() {
  382 + this.loading = true;
  383 + this.getCarInfo()
  384 + },
  385 + getCarInfo() {
232 this.$axios({ 386 this.$axios({
233 method: 'get', 387 method: 'get',
234 url: `/api/jt1078/query/car/tree/100`, 388 url: `/api/jt1078/query/car/tree/100`,
235 - }).then((res) => { 389 + }).then(res => {
236 if (res && res.data && res.data.data) { 390 if (res && res.data && res.data.data) {
237 if (res.data.data.code == 1) { 391 if (res.data.data.code == 1) {
238 - l  
239 -  
240 -  
241 - 392 + //处理数据
  393 + this.simList = []
  394 + this.processingSimList(res.data.data.result)
  395 + this.processingTreeData(res.data.data.result, 0);
  396 + this.statisticsOnline(res.data.data.result)
  397 + console.log(res.data.data.result)
  398 + this.sourceValue = res.data.data.result;
  399 + this.loading = false
  400 + //定时更新数据
  401 + let this_ = this
242 this.carInfoTimeout = setTimeout(function () { 402 this.carInfoTimeout = setTimeout(function () {
243 - this.getCarInfo()  
244 - }, 15000); 403 + this_.getCarInfo()
  404 + }, 45000);
245 } else if (res.data.data.message) { 405 } else if (res.data.data.message) {
246 this.$message.error(res.data.data.message); 406 this.$message.error(res.data.data.message);
247 } 407 }
248 } else { 408 } else {
249 this.$message.error("请求错误,请刷新再试"); 409 this.$message.error("请求错误,请刷新再试");
250 } 410 }
  411 + this.loading = false
  412 + }).catch(error => {
  413 + this.$message.error(error.message);
251 }) 414 })
252 }, 415 },
253 - inspectionsDialog(){  
254 - if (this.nodes.length < 1) {  
255 -  
256 - } 416 + /**
  417 + * 打开巡查设置悬浮框
  418 + */
  419 + inspectionsDialog() {
257 this.showVideoDialog = true 420 this.showVideoDialog = true
258 }, 421 },
259 -  
260 - //视频巡查按钮改变事件  
261 - videoPatrolChange(newValue) {  
262 - if (newValue) {  
263 - this.videoPatrolStart();  
264 - }else {  
265 - if (!this.isEmpty(this.timer)) {  
266 - //关闭巡查定时器  
267 - clearInterval(this.timer);  
268 - } 422 + /**
  423 + * 添加通道
  424 + */
  425 + addChannels(data) {
  426 + let labels = ['ADAS', 'DSM', '路况', '司机', '整车前', '中门', '倒车', '前门客流', '后面客流'];
  427 + let children = [];
  428 + for (let i in labels) {
  429 + children.push({
  430 + id: `${data.id}_${data.sim}_${Number(i) + Number(1)}`,
  431 + pid: data.id,
  432 + name: labels[i],
  433 + disabled: data.disabled,
  434 + parent: data
  435 + })
  436 + }
  437 + data.children = children;
  438 + },
  439 + /**
  440 + * 巡查时间转换器
  441 + */
  442 + timerTimeConvertor() {
  443 + switch (this.timerTime) {
  444 + case "00:30":
  445 + return 30000
  446 + case "01:00":
  447 + return 30000 * 2
  448 + case "01:30":
  449 + return 30000 * 3
  450 + case "02:00":
  451 + return 30000 * 4
  452 + case "02:30":
  453 + return 30000 * 5
  454 + case "03:00":
  455 + return 30000 * 6
  456 + case "03:30":
  457 + return 30000 * 7
  458 + case "04:00":
  459 + return 30000 * 8
  460 + case "04:30":
  461 + return 30000 * 9
  462 + case "05:00":
  463 + return 30000 * 10
  464 + default:
  465 + return null
269 } 466 }
270 }, 467 },
271 - //开启巡查定时器  
272 - videoPatrolStart(itemData){  
273 - let onlineCarKeys = this.onlineCarKeys;  
274 - if (!onlineCarKeys || onlineCarKeys.length === 0 ) {  
275 - this.$message.error("没有在线设备") 468 + /**
  469 + * 巡查开启按钮
  470 + */
  471 + openInspections() {
  472 + let time = this.timerTimeConvertor();
  473 + this.spilt = this.patrolCell;
  474 + if (time == null) {
  475 + this.$message.error("时间选择错误 ==> [ " + this.timerTime + " ]")
  476 + console.log("时间选择结果为 ===> [ " + time + " ]")
  477 + }
  478 + let targetValue = this.targetValue;
  479 + if (targetValue === undefined || targetValue === null || targetValue.length === 0) {
  480 + this.$message.error("未选择巡查对象")
276 return 481 return
277 } 482 }
278 - let count = this.onlineCarKeys.length - 1;  
279 - setInterval(() => {  
280 - if (itemData){  
281 - this.sendDevicePush(itemData);  
282 - itemData = null  
283 - }else {  
284 - if (count == -1){  
285 - count = this.onlineCarKeys.length - 1 483 + this.startFetching(time)
  484 + this.showVideoDialog = false
  485 + },
  486 + /**
  487 + * 巡查树数组只获取最后一级的一维数组
  488 + * @param array 原数组
  489 + */
  490 + getLastElementsOfInnerArrays(array) {
  491 + const result = [];
  492 +
  493 + //递归取值
  494 + function traverse(arr) {
  495 + for (let item of arr) {
  496 + let children = item.children;
  497 + if (children !== undefined && Array.isArray(children)) {
  498 + traverse(children);
  499 + } else if (children === undefined) {
  500 + result.push(item)
  501 + } else {
  502 + console.log("数据格式有误 ==> { " + item + " }")
  503 + }
  504 + }
  505 + }
  506 +
  507 + //开启递归取值
  508 + traverse(array);
  509 + return result;
  510 + },
  511 + /**
  512 + * 巡查关闭按钮
  513 + */
  514 + closeInspections() {
  515 + this.stopPatrol()
  516 + this.patrolValue = false
  517 + clearInterval(this.fetchInterval);
  518 + let nowPlayArray = this.nowPlayArray;
  519 + for (let index in nowPlayArray) {
  520 + this.setPlayUrl(null, index)
  521 + }
  522 + },
  523 + /**
  524 + * 后台关闭视频巡查
  525 + */
  526 + stopPatrol() {
  527 + this.$axios({
  528 + method: 'get',
  529 + url: `/api/jt1078/query/stopPatrol/request/io`,
  530 + }).then((res) => {
  531 + if (res.data.code === 0) {
  532 + this.$message.success("视频巡查已关闭")
  533 + } else {
  534 + this.$message.error("视频巡查已关闭失败, 请联系管理员");
  535 + }
  536 + });
  537 + },
  538 + /**
  539 + * 后台开启视频巡查
  540 + */
  541 + startPatrol(data) {
  542 + this.$axios({
  543 + method: 'post',
  544 + url: `/api/jt1078/query/startPatrol/request/io`,
  545 + data: data,
  546 + headers: {
  547 + 'Content-Type': 'application/json', // 设置请求头
  548 + }
  549 + }).then((res) => {
  550 + if (res.data.code === 0) {
  551 + console.log("视频巡查已开启 ===》 " + res.data.msg)
  552 + this.$message.success("视频巡查已开启");
  553 + } else {
  554 + console.log("视频巡查开启失败 ===》 " + res.data.msg)
  555 + this.$message.error("视频巡查开启失败, 请联系管理员");
  556 + }
  557 + });
  558 + },
  559 + /**
  560 + * 巡查对话框取消按钮
  561 + */
  562 + cancel() {
  563 + this.loading = true;
  564 + this.targetValue = [];
  565 + this.timerTime = '00:30'
  566 + },
  567 + /**
  568 + * 开启推流视频播放
  569 + */
  570 + openPlay(data, idxTmp, fun) {
  571 + console.log("开启视频播放入参数据 ===》 [ " + data + " ]")
  572 + let id = data.id;
  573 + if (id === undefined || id === null) {
  574 + console.log("id 内容为 :" + id)
  575 + return;
  576 + }
  577 + console.log("id 内容为 :" + id)
  578 + let arr = id.split('_');
  579 + if (arr === undefined || arr === null || arr.length !== 3) {
  580 + console.log("split 内容为 :" + arr)
  581 + return;
  582 + }
  583 + this.$axios({
  584 + method: 'get',
  585 + url: '/api/jt1078/query/send/request/io/' + arr[1] + '/' + arr[2]
  586 + }).then(res => {
  587 + if (res.data.code === 0 && res.data.data) {
  588 + let videoUrl;
  589 + this.downloadURL = res.data.data.flv;
  590 + if (location.protocol === "https:") {
  591 + videoUrl = res.data.data.wss_flv;
  592 + } else {
  593 + videoUrl = res.data.data.ws_flv;
286 } 594 }
287 - let onlineCarKey = onlineCarKeys[count];  
288 - let split = onlineCarKey.split("-");  
289 - let onlineCar = this.onlineCar.get(split[0])  
290 - let sim = onlineCar.sim  
291 - let data = {  
292 - channelId: split[1],  
293 - deviceId: sim,  
294 - sim: sim 595 + data.playUrl = videoUrl;
  596 + this.setPlayUrl(videoUrl, idxTmp);
  597 + } else {
  598 + if (!this.isEmpty(res.data.data) && !this.isEmpty(res.data.data.msg)) {
  599 + this.$message.error(res.data.data.msg);
  600 + } else {
  601 + this.$message.error(res.data.msg);
295 } 602 }
296 - this.sendDevicePush(data);  
297 - count --;  
298 } 603 }
299 - },30000) 604 + if (fun) {
  605 + fun();
  606 + }
  607 + })
  608 + },
  609 + /**
  610 + * 批量开启推流视频播放
  611 + * @param data 视频推流参数集合 Array
  612 + */
  613 + // openBatchPlay(data) {
  614 + // if (data === undefined || !Array.isArray(data)) {
  615 + // return;
  616 + // }
  617 + // console.log("批量开启推流视频播放 ----》"+data)
  618 + // let index = 0;
  619 + // this.cycleBatchPlay(data, index)
  620 + // },
  621 + cycleBatchPlay(data, index) {
  622 + if (data === undefined || data[index] === undefined) {
  623 + return;
  624 + }
  625 + let this_i = this
  626 + this.openPlay(data[index], Number(index), function () {
  627 + index++
  628 + this_i.cycleBatchPlay(data, index)
  629 + });
  630 + },
  631 + /**
  632 + * 发送请求验证车辆是否在线
  633 + * @param item
  634 + * @returns {boolean|*}
  635 + */
  636 + checkStatus(item) {
  637 + if (this.lastTargetValueFilter.includes(item)) {
  638 + return true
  639 + }
  640 + if (this.simList) {
  641 + let find = this.simList.find(simData => simData.sim === item && simData.abnormalStatus !== 1);
  642 + //没找到则为离线 反之在线
  643 + console.log("find ===> " + find)
  644 + let f = (find === undefined)
  645 + if (f) {
  646 + this.lastTargetValueFilter.push(item)
  647 + }
  648 + return !f
  649 + }
  650 + return true; // 直接返回预定义的在线状态
  651 + },
  652 + /**
  653 + * 批量验证车辆在线情况
  654 + * @param items
  655 + * @returns {*}
  656 + */
  657 + validateItemsOnline(items) {
  658 + // 检查所有提供的 items 是否在线,并返回过滤后的在线 items
  659 + const onlineItems = items.filter(item => this.checkStatus(item.id.split('_')[1]));
  660 + if (onlineItems.length !== items.length) {
  661 + console.warn("有车辆下线");
  662 + }
  663 + this.nowPlayArray = items;
  664 + return onlineItems;
  665 + },
  666 + /**
  667 + * 循环从数组中取出一定数量的值
  668 + * @param array 原数组
  669 + * @param batchSize 取出的数量
  670 + * @returns {function(): *[]} 取出的结果
  671 + */
  672 + // createBatchFetcher(array, batchSize) {
  673 + // let currentIndex = 0;
  674 + // array = array.slice(); // 创建数组副本以避免修改原始数组
  675 + // return function fetchNextBatch() {
  676 + // const result = [];
  677 + // for (let i = 0; i < batchSize; i++) {
  678 + // if (currentIndex >= array.length) {
  679 + // currentIndex = 0; // 当达到数组末尾时重置索引
  680 + // }
  681 + // result.push(array[currentIndex]);
  682 + // currentIndex++;
  683 + // }
  684 + // return result;
  685 + // };
  686 + // },
  687 + createBatchFetcher(array, batchSize) {
  688 + let currentIndex = 0;
  689 + const originalArray = array.slice(); // 创建原始数组副本
  690 +
  691 + return function fetchNextBatch() {
  692 + const result = [];
  693 + for (let i = 0; i < batchSize && currentIndex < originalArray.length; i++) {
  694 + result.push(originalArray[currentIndex]);
  695 + currentIndex++;
  696 + }
  697 + return result;
  698 + };
  699 + },
  700 + /**
  701 + * 开启视频巡查
  702 + * @param items 选择巡查的对象
  703 + * @param time
  704 + */
  705 + startFetching(time) {
  706 + this.lastTargetValue = this.getLastElementsOfInnerArrays(this.targetValue);
  707 + console.log("targetValue ===> " + this.targetValue);
  708 + console.log("lastTargetValue ===> " + this.lastTargetValue);
  709 + if (!this.patrolValue && this.lastTargetValue.length > 0) {
  710 + // 在初始化 batchFetcher 之前验证 items 是否全部在线
  711 + this.lastTargetValue = this.validateItemsOnline(this.lastTargetValue);
  712 + if (this.lastTargetValue.length === 0) {
  713 + console.warn("【车辆全部下线】请重新选择");
  714 + return;
  715 + }
  716 + this.startPatrol(this.lastTargetValue)
  717 + this.batchFetcher = this.createBatchFetcher(this.lastTargetValue, this.spilt);
  718 + // 立即执行一次 fetchNextBatch 并等待其完成
  719 + let data = this.fetchNextBatch();
  720 + console.log(parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}') + " 视频巡查数组 ===》 " + data);
  721 + this.beachSendIORequest(this.convertBeachList(data));
  722 + // 设置定时器以定期获取批次
  723 + this.fetchInterval = setInterval(() => {
  724 + let data = this.fetchNextBatch();
  725 + console.log(parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}') + " 视频巡查数组 ===》 " + data);
  726 + this.beachSendIORequest(this.convertBeachList(data));
  727 + }, time);
  728 + this.patrolValue = true;
  729 + }
  730 + },
  731 + /**
  732 + * 数组转换 (方便批量发送请求)
  733 + */
  734 + convertBeachList(data) {
  735 + if (data && data.length > 0) {
  736 + return data.map(item => item.id.split('_').slice(1).join('-'))
  737 + }
  738 + },
  739 + /**
  740 + * 更新巡查播放列表
  741 + */
  742 + fetchNextBatch() {
  743 + // 在每次获取批次前验证在线状态
  744 + const updatedItems = this.validateItemsOnline(this.lastTargetValue);
  745 + if (updatedItems.length === 0) {
  746 + this.$message.error("车辆已全部下线,已关闭 【视屏巡查】")
  747 + this.stopFetching();
  748 + return
  749 + }
  750 + if (updatedItems.length !== this.lastTargetValue.length) {
  751 + // 更新 items 和 batchFetcher
  752 + this.lastTargetValue = updatedItems;
  753 + this.batchFetcher = this.createBatchFetcher(updatedItems, this.spilt);
  754 + }
  755 + const batch = this.batchFetcher();
  756 + this.nowPlayArray = batch;
  757 + return batch
  758 + },
  759 + /**
  760 + * 关闭视频巡查
  761 + */
  762 + stopFetching() {
  763 + if (this.isFetching) {
  764 + clearInterval(this.fetchInterval);
  765 + this.fetchInterval = null;
  766 + this.isFetching = false;
  767 + }
300 }, 768 },
301 -  
302 -  
303 -  
304 -  
305 -  
306 destroy(idx) { 769 destroy(idx) {
307 this.clear(idx.substring(idx.length - 1)) 770 this.clear(idx.substring(idx.length - 1))
308 }, 771 },
@@ -313,73 +776,75 @@ export default { @@ -313,73 +776,75 @@ export default {
313 this.closeLoading(); 776 this.closeLoading();
314 return false; 777 return false;
315 } else { 778 } else {
316 - this.isSendDevicePush(data,this.patrolValue); 779 + this.isSendDevicePush(data, this.patrolValue);
317 } 780 }
318 } 781 }
319 }, 782 },
320 contextMenuEvent: function (device, event, data, isCatalog) { 783 contextMenuEvent: function (device, event, data, isCatalog) {
321 }, 784 },
322 isSendDevicePush(itemData, patrolValue) { 785 isSendDevicePush(itemData, patrolValue) {
323 - if (patrolValue){ 786 + if (patrolValue) {
324 this.videoPatrolStart(itemData); 787 this.videoPatrolStart(itemData);
325 - }else { 788 + } else {
326 this.sendDevicePush(itemData); 789 this.sendDevicePush(itemData);
327 } 790 }
328 }, 791 },
329 //通知设备上传媒体流 792 //通知设备上传媒体流
330 - sendDevicePush: function (itemData, fun) {  
331 - // if (itemData.status === 0) {  
332 - // this.$message.error('设备离线!');  
333 - // return  
334 - // } 793 + sendDevicePush(itemData, fun) {
335 this.save(itemData) 794 this.save(itemData)
336 let deviceId = itemData.deviceId; 795 let deviceId = itemData.deviceId;
337 - // this.isLoging = true;  
338 let channelId = itemData.channelId; 796 let channelId = itemData.channelId;
339 if (this.isEmpty(deviceId)) { 797 if (this.isEmpty(deviceId)) {
340 this.$message.error("没有获取到sim卡,请检查设备是否接入"); 798 this.$message.error("没有获取到sim卡,请检查设备是否接入");
341 this.closeLoading(); 799 this.closeLoading();
342 - if (fun) {fun();} 800 + if (fun) {
  801 + fun();
  802 + }
343 return; 803 return;
344 } 804 }
345 console.log("通知设备推流1:" + deviceId + " : " + channelId); 805 console.log("通知设备推流1:" + deviceId + " : " + channelId);
346 let idxTmp = this.playerIdx 806 let idxTmp = this.playerIdx
347 - let that = this;  
348 this.$axios({ 807 this.$axios({
349 method: 'get', 808 method: 'get',
350 url: '/api/jt1078/query/send/request/io/' + deviceId + '/' + channelId 809 url: '/api/jt1078/query/send/request/io/' + deviceId + '/' + channelId
351 - }).then(function (res) {  
352 - if (res.data.code === 0 && res.data.data && (res.data.data.code === "1" || res.data.data.code == 1)) { 810 + }).then(res => {
  811 + console.log(res)
  812 + if (res.data.code === 0 && res.data.data) {
353 let videoUrl; 813 let videoUrl;
354 - that.port = res.data.data.port;  
355 - that.httpPort = res.data.data.httpPort;  
356 - that.stream = res.data.data.stream;  
357 - console.log(res.data.data.data);  
358 - if (!that.isEmpty(res.data.data.data)) {  
359 - that.downloadURL = res.data.data.data.flv; 814 + this.port = res.data.data.port;
  815 + this.httpPort = res.data.data.httpPort;
  816 + this.stream = res.data.data.stream;
  817 + console.log(res.data.data);
  818 + if (!this.isEmpty(res.data.data)) {
  819 + this.downloadURL = res.data.data.flv;
360 if (location.protocol === "https:") { 820 if (location.protocol === "https:") {
361 - videoUrl = res.data.data.data.wss_flv; 821 + videoUrl = res.data.data.wss_flv;
362 } else { 822 } else {
363 - videoUrl = res.data.data.data.ws_flv; 823 + videoUrl = res.data.data.ws_flv;
364 } 824 }
365 console.log(videoUrl); 825 console.log(videoUrl);
366 itemData.playUrl = videoUrl; 826 itemData.playUrl = videoUrl;
367 - that.setPlayUrl(videoUrl, idxTmp); 827 + this.setPlayUrl(videoUrl, idxTmp);
368 } 828 }
369 } else { 829 } else {
370 - if (!that.isEmpty(res.data.data) && !that.isEmpty(res.data.data.msg)) {  
371 - that.$message.error(res.data.data.msg);  
372 - } else {  
373 - that.$message.error(res.data.msg);  
374 - } 830 + this.$message.error(res.data.msg);
  831 + }
  832 + if (fun) {
  833 + fun();
375 } 834 }
376 - if (fun) {fun();}  
377 }).catch(function (e) { 835 }).catch(function (e) {
378 - if (fun) {fun();} 836 + if (fun) {
  837 + fun();
  838 + }
379 }).finally(() => { 839 }).finally(() => {
380 this.closeLoading(); 840 this.closeLoading();
381 }); 841 });
382 }, 842 },
  843 + /**
  844 + * 播放器赋值
  845 + * @param url 播放内容路径
  846 + * @param idx 播放的id
  847 + */
383 setPlayUrl(url, idx) { 848 setPlayUrl(url, idx) {
384 this.$set(this.videoUrl, idx, url) 849 this.$set(this.videoUrl, idx, url)
385 let _this = this 850 let _this = this
@@ -394,7 +859,7 @@ export default { @@ -394,7 +859,7 @@ export default {
394 } 859 }
395 }, 860 },
396 shot(e) { 861 shot(e) {
397 - // console.log(e) 862 + console.log(e)
398 // send({code:'image',data:e}) 863 // send({code:'image',data:e})
399 var base64ToBlob = function (code) { 864 var base64ToBlob = function (code) {
400 let parts = code.split(';base64,'); 865 let parts = code.split(';base64,');
@@ -430,6 +895,7 @@ export default { @@ -430,6 +895,7 @@ export default {
430 console.log(data); 895 console.log(data);
431 window.localStorage.setItem('playData', JSON.stringify(data)) 896 window.localStorage.setItem('playData', JSON.stringify(data))
432 }, 897 },
  898 +
433 initTreeData() { 899 initTreeData() {
434 this.showLoading(); 900 this.showLoading();
435 this.$axios({ 901 this.$axios({
@@ -449,6 +915,7 @@ export default { @@ -449,6 +915,7 @@ export default {
449 this.closeLoading(); 915 this.closeLoading();
450 }); 916 });
451 }, 917 },
  918 +
452 initDate(nodes, datas) { 919 initDate(nodes, datas) {
453 if (nodes && datas) { 920 if (nodes && datas) {
454 let len = datas.length; 921 let len = datas.length;
@@ -486,21 +953,10 @@ export default { @@ -486,21 +953,10 @@ export default {
486 onClick(evt, treeId, treeNode) { 953 onClick(evt, treeId, treeNode) {
487 this.combationChildNode(treeNode); 954 this.combationChildNode(treeNode);
488 }, 955 },
489 - onCheck(evt, treeId, treeNode) {  
490 -  
491 - },  
492 beforeExpand(treeId, treeNode) { 956 beforeExpand(treeId, treeNode) {
493 957
494 return true; 958 return true;
495 }, 959 },
496 - onExpand(evt, treeId, treeNode) {  
497 - this.combationChildNode(treeNode);  
498 - },  
499 - handleCreated(ztreeObj) {  
500 - this.ztreeObj = ztreeObj;  
501 - this.ztreeObj.setting.view.nameIsHTML = true;  
502 -  
503 - },  
504 combationChildNode(treeNo) { 960 combationChildNode(treeNo) {
505 this.ztreeNode = treeNo; 961 this.ztreeNode = treeNo;
506 if (treeNo.seachChild && (treeNo.seachChild == 'true')) { 962 if (treeNo.seachChild && (treeNo.seachChild == 'true')) {
@@ -561,6 +1017,9 @@ export default { @@ -561,6 +1017,9 @@ export default {
561 this.closeLoading(); 1017 this.closeLoading();
562 } 1018 }
563 }, 1019 },
  1020 + /**
  1021 + * 添加通道
  1022 + */
564 addChannel(treeNo) { 1023 addChannel(treeNo) {
565 let labels = ['ADAS', 'DSM', '路况', '司机', '整车前', '中门', '倒车', '前门客流', '后面客流']; 1024 let labels = ['ADAS', 'DSM', '路况', '司机', '整车前', '中门', '倒车', '前门客流', '后面客流'];
566 let children = []; 1025 let children = [];
@@ -593,8 +1052,9 @@ export default { @@ -593,8 +1052,9 @@ export default {
593 this.initDate(children, res.data.data.result); 1052 this.initDate(children, res.data.data.result);
594 this.ztreeObj.addNodes(treeNo, -1, children, true); 1053 this.ztreeObj.addNodes(treeNo, -1, children, true);
595 treeNo.seachChild = 'true'; 1054 treeNo.seachChild = 'true';
  1055 + let _this = this;
596 this.carPlayTimer = setTimeout(function () { 1056 this.carPlayTimer = setTimeout(function () {
597 - this.requestChildNode1(); 1057 + _this.requestChildNode1();
598 }, 15000); 1058 }, 15000);
599 } else if (res.data.data.message) { 1059 } else if (res.data.data.message) {
600 this.$message.error(res.data.data.message); 1060 this.$message.error(res.data.data.message);
@@ -673,25 +1133,6 @@ export default { @@ -673,25 +1133,6 @@ export default {
673 } 1133 }
674 }); 1134 });
675 }, 1135 },
676 - sendIORequestStop1(sim, channel, fun) {  
677 - if (this.isEmpty(sim) || this.isEmpty(channel)) {  
678 - console.log("sim:" + sim + ";channel:" + channel);  
679 - if (fun) {  
680 - fun();  
681 - }  
682 - return;  
683 - }  
684 - this.videoUrl = [''];  
685 - this.$axios({  
686 - method: 'get',  
687 - url: `/api/jt1078/query/send/stop/io/` + sim + "/" + channel,  
688 - }).then((res) => {  
689 - console.log(res);  
690 - if (fun) {  
691 - fun();  
692 - }  
693 - });  
694 - },  
695 isEmpty(val) { 1136 isEmpty(val) {
696 return null == val || undefined == val || "" == val; 1137 return null == val || undefined == val || "" == val;
697 }, 1138 },
@@ -713,214 +1154,81 @@ export default { @@ -713,214 +1154,81 @@ export default {
713 pageObj.closeLoading(); 1154 pageObj.closeLoading();
714 } 1155 }
715 }, 1156 },
716 - searchHitoryList(){  
717 - if(this.isEmpty(this.carTreeNode)){  
718 - this.$message.error('请选择车辆');  
719 - return;  
720 - }  
721 - if(this.isEmpty(this.sim)){  
722 - this.$message.error('无法获取SIM卡信息,请检查设备');  
723 - return;  
724 - }  
725 -  
726 -  
727 - if(this.isEmpty(this.channel)){  
728 - this.$message.error('请选择通道');  
729 - return;  
730 - }  
731 -  
732 - if(this.isEmpty(this.startTime)){  
733 - this.$message.error('请选择开始时间');  
734 - return;  
735 - }  
736 -  
737 - if(this.isEmpty(this.endTime)){  
738 - this.$message.error('请选择结束时间');  
739 - return;  
740 - }  
741 -  
742 - this.showLoading();  
743 -  
744 - let pageObj = this;  
745 - this.$axios({  
746 - method: 'get',  
747 - url: '/api/jt1078/query/history/list/' + this.sim + '/' + this.channel+"/"+this.startTime+"/"+this.endTime  
748 - }).then(function (res) {  
749 -  
750 -  
751 - if(res &&res.data && res.data.data && res.data.data.obj && res.data.data.code==1 && res.data.data.obj.data && res.data.data.obj.data.items){  
752 - let length = res.data.data.obj.data.items.length;  
753 - let html = "<div class='historyListDiv'><ul>";  
754 - for (let i = 0; i < length; i++) {  
755 - let item = res.data.data.obj.data.items[i];  
756 - if(item.channelNo === pageObj.channel){  
757 - let title = item.startTime+"——"+item.endTime;  
758 - html+="<li class='historyListLi' click='playHistoryItem()' startTime = '"+item.startTime+"' endTime='"+item.endTime+"' streamType='"+item.streamType+"' title='"+title+"' channelMapping='"+item.channelMapping+"'>"+title+"</li>";  
759 - }  
760 - }  
761 - pageObj.historyPlayListHtml = html+"</ul></div>";  
762 - pageObj.closeLoading();  
763 - }else if(res && res.data && res.data.data && res.data.data.msg){  
764 - pageObj.$message.error(res.data.data.msg);  
765 - pageObj.closeLoading();  
766 - }else{  
767 - pageObj.closeLoading();  
768 - }  
769 - });  
770 - },  
771 - playHistoryItem(e){  
772 - if(this.isEmpty(this.carTreeNode)){  
773 - this.$message.error('请选择车辆');  
774 - return;  
775 - }  
776 - if(this.isEmpty(this.sim)){  
777 - this.$message.error('无法获取SIM卡信息,请检查设备');  
778 - return;  
779 - }  
780 -  
781 -  
782 - if(this.isEmpty(this.channel)){  
783 - this.$message.error('请选择通道');  
784 - return;  
785 - }  
786 -  
787 - if(this.isEmpty(this.startTime)){  
788 - this.$message.error('请选择开始时间');  
789 - return;  
790 - }  
791 -  
792 - if(this.isEmpty(this.endTime)){  
793 - this.$message.error('请选择结束时间');  
794 - return;  
795 - }  
796 -  
797 - let pageObj = this;  
798 -  
799 -  
800 - this.videoUrl =[];  
801 -  
802 -  
803 - pageObj.$axios({  
804 - method: 'get',  
805 - url: '/api/jt1078/query/send/request/io/history/' + pageObj.sim + '/' + pageObj.channel+"/"+e.target.getAttribute('startTime')+"/"+e.target.getAttribute('endTime')+"/"+e.target.getAttribute('channelMapping')  
806 - }).then(function (res) {  
807 -  
808 -  
809 - if (res.data && res.data.data && res.data.data.data) {  
810 - let videoUrl1;  
811 - if (location.protocol === "https:") {  
812 - videoUrl1 = res.data.data.data.wss_flv;  
813 - } else {  
814 - videoUrl1 = res.data.data.data.ws_flv;  
815 - }  
816 - pageObj.downloadURL = res.data.data.data.flv;  
817 - pageObj.port=res.data.data.port;  
818 - pageObj.httpPort = res.data.data.httpPort;  
819 - pageObj.stream = res.data.data.stream;  
820 - pageObj.videoUrlHistory = videoUrl1;  
821 -  
822 - let itemData = new Object();  
823 - itemData.deviceId = pageObj.sim;  
824 - // this.isLoging = true;  
825 - itemData.channelId= pageObj.channel;  
826 - itemData.playUrl = videoUrl1;  
827 - console.log(pageObj.playerIdx);  
828 -  
829 - pageObj.setPlayUrl(videoUrl1, 0);  
830 - pageObj.hisotoryPlayFlag = true;  
831 - // pageObj.$nextTick(() => {  
832 - // pageObj.createdPlay();  
833 - // pageObj.closeLoading();  
834 - // })  
835 - } else if(res.data.data && res.data.data.msg){  
836 - pageObj.$message.error(res.data.data.msg);  
837 - } else if(res.data.msg){  
838 - pageObj.$message.error(res.data.msg);  
839 - }else if(res.msg){  
840 - pageObj.$message.error(res.msg);  
841 - }  
842 - pageObj.closeLoading();  
843 - });  
844 -  
845 - }, 1157 + /**
  1158 + * 视频一键播放
  1159 + */
846 oneClickPlayback() { 1160 oneClickPlayback() {
847 - if (this.isEmpty(this.carTreeNode)) { 1161 + if (this.isEmpty(this.simNodeData)) {
848 this.$message.error('请选择车辆'); 1162 this.$message.error('请选择车辆');
849 return; 1163 return;
850 } 1164 }
851 - if (this.isEmpty(this.carTreeNode.abnormalStatus)) { 1165 + if (this.isEmpty(this.simNodeData.abnormalStatus)) {
852 this.$message.error('请检查车辆状态'); 1166 this.$message.error('请检查车辆状态');
853 return; 1167 return;
854 } 1168 }
855 - if (this.carTreeNode.abnormalStatus != 1) { 1169 + if (this.simNodeData.abnormalStatus != 1) {
856 this.$message.error('车辆设备离线,请检查设备'); 1170 this.$message.error('车辆设备离线,请检查设备');
857 return; 1171 return;
858 } 1172 }
859 - if (this.isEmpty(this.sim)) { 1173 + if (this.isEmpty(this.simNodeData.sim)) {
860 this.$message.error('无法获取SIM卡信息,请检查设备'); 1174 this.$message.error('无法获取SIM卡信息,请检查设备');
861 return; 1175 return;
862 } 1176 }
863 - this.spilt = 12;  
864 - this.playOneAllChannel(0); 1177 + this.spilt = 9;
  1178 + let data = Array.from({length: this.spilt}, (_, i) => `${this.simNodeData.sim}-${i + 1}`);
  1179 + this.beachSendIORequest(data);
865 }, 1180 },
866 - playOneAllChannel(channel) {  
867 - if (channel == 9) {  
868 - return;  
869 - }  
870 - let item = new Object();  
871 - item.deviceId = this.sim;  
872 - item.channelId = 1 + channel;  
873 - this.playerIdx = channel;  
874 - let that = this;  
875 - this.sendDevicePush(item, function () {  
876 - that.playOneAllChannel(1 + channel);  
877 - }); 1181 + /**
  1182 + * 批量发送推流请求
  1183 + * @param data
  1184 + */
  1185 + beachSendIORequest(data) {
  1186 + console.log(data)
  1187 + this.$axios({
  1188 + method: 'post',
  1189 + url: '/api/jt1078/query/beachSend/request/io',
  1190 + data: data,
  1191 + headers: {
  1192 + 'Content-Type': 'application/json', // 设置请求头
  1193 + }
  1194 + }).then(
  1195 + res => {
  1196 + let dataList = res.data.data;
  1197 + console.log(dataList);
  1198 + if (res.data.code == 0 && dataList != null && dataList.length >= 0) {
  1199 + for (let i in dataList) {
  1200 + this.setPlayUrl(dataList[i].ws_flv, i);
  1201 + }
  1202 + } else {
  1203 + this.$message.error(res.data.msg);
  1204 + }
  1205 + }
  1206 + )
878 }, 1207 },
  1208 + // playOneAllChannel(channel) {
  1209 + // if (channel == 9) {
  1210 + // return;
  1211 + // }
  1212 + // let item = new Object();
  1213 + // item.deviceId = this.sim;
  1214 + // item.channelId = 1 + channel;
  1215 + // this.playerIdx = channel;
  1216 + //
  1217 + // this.sendDevicePush(item);
  1218 + // },
879 spiltClickFun(val) { 1219 spiltClickFun(val) {
880 this.spilt = val; 1220 this.spilt = val;
881 if (val - 1 < this.playerIdx) { 1221 if (val - 1 < this.playerIdx) {
882 this.playerIdx = val - 1; 1222 this.playerIdx = val - 1;
883 } 1223 }
884 }, 1224 },
885 - downloadFunction(){  
886 - console.log(this.downloadURL);  
887 -  
888 - if(this.isEmpty(this.downloadURL)){  
889 - return;  
890 - }  
891 -  
892 - window.open(this.downloadURL,"_download");  
893 - },  
894 -  
895 closeSelectItem() { 1225 closeSelectItem() {
896 console.log("============================>" + this.playerIdx); 1226 console.log("============================>" + this.playerIdx);
897 this.setPlayUrl(null, this.playerIdx) 1227 this.setPlayUrl(null, this.playerIdx)
898 - // this.videoUrl[this.playerIdx]=null;  
899 - // this.sendIORequestStop1(this.sim,this.playerIdx+1);  
900 }, 1228 },
901 closeSelectCarItem() { 1229 closeSelectCarItem() {
902 for (let index = 0; index < 9; index++) { 1230 for (let index = 0; index < 9; index++) {
903 this.setPlayUrl(null, index) 1231 this.setPlayUrl(null, index)
904 - // this.videoUrl[this.playerIdx]=null;  
905 - this.sendIORequestStop1(this.sim, index + 1);  
906 - }  
907 - },  
908 - treeRightMenuFun(event, treeId, treeNode) {  
909 - if (treeNode.type == '301' || treeNode.type == 301) {  
910 - this.rightMenuId = "carRMenu";  
911 - this.showRMenu(event);  
912 - this.carTreeNode = treeNode;  
913 - this.sim = treeNode.sim;  
914 - this.channel = null;  
915 - } else if (treeNode.type == '401' || treeNode.type == 401) {  
916 - this.rightMenuId = "channelCarRMenu";  
917 - this.showRMenu(event);  
918 - this.channel = treeNode.id;  
919 - } else {  
920 - this.carTreeNode = null;  
921 - this.sim = null;  
922 - this.channel = null;  
923 - hidden();  
924 } 1232 }
925 }, 1233 },
926 showRMenu(event) { 1234 showRMenu(event) {
@@ -947,14 +1255,26 @@ export default { @@ -947,14 +1255,26 @@ export default {
947 } 1255 }
948 }; 1256 };
949 </script> 1257 </script>
950 -<style> 1258 +<style scoped>
  1259 +.inspections-tree >>> .el-tree {
  1260 + padding-bottom: 22px;
  1261 +}
  1262 +
  1263 +.device-list-tree >>> .el-tree {
  1264 + padding-bottom: 13px;
  1265 +}
  1266 +
  1267 +.device-list-tree >>> .el-tree-node__content {
  1268 + padding-bottom: 13px;
  1269 + height: 20px;
  1270 +}
  1271 +
951 .device-tree-main-box { 1272 .device-tree-main-box {
952 text-align: left; 1273 text-align: left;
953 } 1274 }
954 1275
955 .btn { 1276 .btn {
956 margin: 0 10px; 1277 margin: 0 10px;
957 -  
958 } 1278 }
959 1279
960 .btn:hover { 1280 .btn:hover {
@@ -963,7 +1283,6 @@ export default { @@ -963,7 +1283,6 @@ export default {
963 1283
964 .btn.active { 1284 .btn.active {
965 color: #409EFF; 1285 color: #409EFF;
966 -  
967 } 1286 }
968 1287
969 .redborder { 1288 .redborder {
@@ -995,7 +1314,6 @@ export default { @@ -995,7 +1314,6 @@ export default {
995 overflow-x: hidden; 1314 overflow-x: hidden;
996 } 1315 }
997 1316
998 -  
999 /* 菜单的样式 */ 1317 /* 菜单的样式 */
1000 .rMenu { 1318 .rMenu {
1001 position: absolute; 1319 position: absolute;
@@ -1026,8 +1344,7 @@ export default { @@ -1026,8 +1344,7 @@ export default {
1026 li#menu-item-delete, li#menu-item-rename { 1344 li#menu-item-delete, li#menu-item-rename {
1027 margin-top: 1px; 1345 margin-top: 1px;
1028 } 1346 }
1029 -</style>  
1030 -<style> 1347 +
1031 .videoList { 1348 .videoList {
1032 display: flex; 1349 display: flex;
1033 flex-wrap: wrap; 1350 flex-wrap: wrap;
@@ -1106,6 +1423,7 @@ li#menu-item-delete, li#menu-item-rename { @@ -1106,6 +1423,7 @@ li#menu-item-delete, li#menu-item-rename {
1106 overflow-y: auto; /* 内容超出时显示垂直滚动条 */ 1423 overflow-y: auto; /* 内容超出时显示垂直滚动条 */
1107 overflow-x: hidden; /* 隐藏水平滚动条 */ 1424 overflow-x: hidden; /* 隐藏水平滚动条 */
1108 } 1425 }
  1426 +
1109 .transfer-footer { 1427 .transfer-footer {
1110 margin-left: 20px; 1428 margin-left: 20px;
1111 padding: 6px 5px; 1429 padding: 6px 5px;
web_src/src/components/FlowStatistics.vue 0 → 100644
  1 +<template>
  2 + <div style="width: 2000px;">
  3 + <el-container v-loading="loading" style="height: 100%;width: 100%" element-loading-text="拼命加载中">
  4 + <div style="width:100%;display: flex;flex-direction: column;justify-content: space-between;">
  5 + <div class="block" style="width: 100%;text-align:left;margin-bottom:15px;">
  6 + <el-card class="box-card" style="width: 100%">
  7 + <el-form>
  8 + <el-col :span="4">
  9 + <el-form-item label="时间类型">
  10 + <el-select v-model="timeType" placeholder="请选择时间类型">
  11 + <el-option
  12 + v-for="item in timeList"
  13 + :key="item.value"
  14 + :label="item.label"
  15 + :value="item.value"
  16 + @change="getDatesByTimeFrame">
  17 + </el-option>
  18 + </el-select>
  19 + </el-form-item>
  20 + </el-col>
  21 + <el-col :span="4">
  22 + <el-form-item label="日期">
  23 + <el-date-picker
  24 + v-model="time"
  25 + align="right"
  26 + type="date"
  27 + placeholder="选择日期"
  28 + :picker-options="pickerOptions" v-if="timeType === 'day'"/>
  29 + <el-date-picker
  30 + v-model="time"
  31 + value-format="yyyy-M"
  32 + type="month"
  33 + placeholder="选择月" v-if="timeType === 'month'"/>
  34 + <el-date-picker
  35 + v-model="time"
  36 + type="year"
  37 + placeholder="选择年" v-if="timeType === 'year'"/>
  38 + </el-form-item>
  39 + </el-col>
  40 + <el-col :span="4" v-if="statisticsType !== 'All'">
  41 + <el-form-item label="车辆">
  42 + <car-tree-one v-model="sim_channel"/>
  43 + </el-form-item>
  44 + </el-col>
  45 + <el-col :span="5">
  46 + <el-form-item label="统计类型">
  47 + <el-select v-model="statisticsType" placeholder="请选择统计类型" @change="searchFlowList">
  48 + <el-option
  49 + v-for="item in statisticsList"
  50 + :key="item.value"
  51 + :label="item.label"
  52 + :value="item.value"
  53 + >
  54 + </el-option>
  55 + </el-select>
  56 + </el-form-item>
  57 + </el-col>
  58 + <el-col :span="3">
  59 + <el-form-item>
  60 + <el-button @click="searchFlowList()">搜索</el-button>
  61 + </el-form-item>
  62 + </el-col>
  63 + </el-form>
  64 + </el-card>
  65 + </div>
  66 + <div style="width: 100%;display:flex;flex-direction:row; justify-content:space-between;">
  67 + <el-card class="box-card" style="width: 100%;height: 80vh">
  68 + <el-table
  69 + :data="tableData"
  70 + height="250"
  71 + border
  72 + style="width: 100%;height: 75vh;">
  73 + <el-table-column
  74 + prop="time"
  75 + label="日期"
  76 + >
  77 + </el-table-column>
  78 + <el-table-column
  79 + label="车辆自编号" v-if="statisticsType !== 'All'">
  80 + <template slot-scope="scope">
  81 + <span>{{ `${scope.row.carData.nbbm} ` }}</span>
  82 + <el-button type="text" @click="clickInformation(scope.row)">[详细信息]</el-button>
  83 + </template>
  84 + </el-table-column>
  85 + <el-table-column
  86 + prop="channel"
  87 + label="通道号"
  88 + v-if="statisticsType === 'channel'">
  89 + </el-table-column>
  90 + <el-table-column
  91 + prop="count"
  92 + label="统计车辆数"
  93 + v-if="statisticsType === 'All'">
  94 + </el-table-column>
  95 + <el-table-column
  96 + prop="flow"
  97 + label="流量">
  98 + <template slot-scope="scope">
  99 + {{ formattedBytes(scope.row.flow) }}
  100 + </template>
  101 + </el-table-column>
  102 + </el-table>
  103 + </el-card>
  104 + </div>
  105 + </div>
  106 + <el-dialog
  107 + :title="`${information.nbbm}车辆详细信息`"
  108 + :visible.sync="open"
  109 + width="30%"
  110 + :before-close="handleClose">
  111 + <el-descriptions class="margin-top" :column="1" border>
  112 + <el-descriptions-item>
  113 + <template slot="label">
  114 + 车辆自编号
  115 + </template>
  116 + {{ information.nbbm }}
  117 + </el-descriptions-item>
  118 + <el-descriptions-item>
  119 + <template slot="label">
  120 + sim卡号
  121 + </template>
  122 + {{ information.sim }}
  123 + </el-descriptions-item>
  124 + <el-descriptions-item v-if="information.lineName">
  125 + <template slot="label">
  126 + 线路名称
  127 + </template>
  128 + {{ information.lineName }}
  129 + </el-descriptions-item>
  130 + <el-descriptions-item v-if="information.carPlate">
  131 + <template slot="label">
  132 + <i class="el-icon-tickets"></i>
  133 + 车牌号
  134 + </template>
  135 + {{ information.carPlate }}
  136 + </el-descriptions-item>
  137 + </el-descriptions>
  138 + <span slot="footer" class="dialog-footer">
  139 + <el-button @click="closeInformation">关闭</el-button>
  140 + </span>
  141 + </el-dialog>
  142 + </el-container>
  143 + </div>
  144 +</template>
  145 +
  146 +<script>
  147 +//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等),
  148 +//例如:import 《组件名称》 from '《组件路径》,
  149 +import player from "./common/jessibuca.vue";
  150 +import CarTree from "./JT1078Components/cascader/CarTree.vue";
  151 +import HistoricalData from "./JT1078Components/historical/HistoricalDataTree.vue";
  152 +import {parseTime} from "../../utils/ruoyi";
  153 +import CarTreeOne from "./JT1078Components/cascader/CarTreeOne.vue";
  154 +
  155 +export default {
  156 + //import引入的组件需要注入到对象中才能使用"
  157 + components: {CarTreeOne, HistoricalData, CarTree, player},
  158 + props: {},
  159 + data() {
  160 + //这里存放数据"
  161 + return {
  162 + open: false,
  163 + information: {},
  164 + tableData: [],
  165 + historyData: [],
  166 + //遮罩层
  167 + loading: false,
  168 + //sim号和通道号,格式为:sim-channel
  169 + sim_channel: null,
  170 + //选择时间
  171 + time: '',
  172 + //时间类型
  173 + timeType: 'day',
  174 + //统计类型
  175 + statisticsType: 'sim',
  176 + //时间选择下拉框
  177 + timeList: [
  178 + {value: 'day', label: '按天统计'},
  179 + {value: 'month', label: '按月统计'},
  180 + {value: 'year', label: '按年统计'},
  181 + ],
  182 + //统计类型
  183 + statisticsList: [
  184 + {value: 'sim', label: '按车辆统计'},
  185 + {value: 'channel', label: '按通道统计'},
  186 + {value: 'All', label: '全量统计'},
  187 + ],
  188 + //日期快捷选择
  189 + pickerOptions: {
  190 + disabledDate(time) {
  191 + return time.getTime() > Date.now();
  192 + },
  193 + shortcuts: [{
  194 + text: '今天',
  195 + onClick(picker) {
  196 + picker.$emit('pick', new Date());
  197 + }
  198 + }, {
  199 + text: '昨天',
  200 + onClick(picker) {
  201 + const date = new Date();
  202 + date.setTime(date.getTime() - 3600 * 1000 * 24);
  203 + picker.$emit('pick', date);
  204 + }
  205 + }, {
  206 + text: '一周前',
  207 + onClick(picker) {
  208 + const date = new Date();
  209 + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
  210 + picker.$emit('pick', date);
  211 + }
  212 + }]
  213 + },
  214 + };
  215 + },
  216 + //计算属性 类似于data概念",
  217 + computed: {},
  218 + //监控data中的数据变化",
  219 + watch: {
  220 + timeType() {
  221 + this.getDatesByTimeFrame()
  222 + }
  223 + },
  224 + //方法集合",
  225 + methods: {
  226 + /**
  227 + * 搜索流量统计数据
  228 + */
  229 + searchFlowList() {
  230 + this.loading = true
  231 + let simChannel = null;
  232 + console.log(this.sim_channel);
  233 + if (this.sim_channel) {
  234 + simChannel = this.sim_channel[this.sim_channel.length - 1];
  235 + }
  236 + this.$axios({
  237 + method: "GET",
  238 + url: "/flow/list/" + this.timeType + "/" + this.statisticsType + "/" + this.time + "/" + simChannel,
  239 + }).then(res => {
  240 + this.tableData = res.data.data
  241 + this.loading = false
  242 + })
  243 + },
  244 + destroy(idx) {
  245 + console.log(idx);
  246 + this.clear(idx.substring(idx.length - 1))
  247 + },
  248 + /**
  249 + * 获取时间
  250 + */
  251 + getDatesByTimeFrame() {
  252 + const today = new Date();
  253 + switch (this.timeType.toLowerCase()) {
  254 + case 'day':
  255 + this.time = parseTime(today, '{y}-{m}-{d} {h}:{i}:{s}');
  256 + break;
  257 +
  258 + case 'month':
  259 + let time = parseTime(today, '{y}-{m}');
  260 + let split = time.split('-');
  261 + this.time = split[1].substring(0, 1) === '0' ? split[0] + '-' + split[1].substring(1, 2) : time;
  262 + break;
  263 +
  264 + case 'year':
  265 + this.time = parseTime(today, '{y}');
  266 + break;
  267 + default:
  268 + console.log('Invalid time frame provided.');
  269 + }
  270 + this.searchFlowList()
  271 + },
  272 + /**
  273 + * 流量换算
  274 + */
  275 + formattedBytes(value) {
  276 + if (value >= 1024 * 1024 * 1024) { // GB
  277 + return `${(value / (1024 * 1024 * 1024)).toFixed(2)} GB`;
  278 + } else if (value >= 1024 * 1024) { // MB
  279 + return `${(value / (1024 * 1024)).toFixed(2)} MB`;
  280 + } else if (value >= 1024) { // KB
  281 + return `${(value / 1024).toFixed(2)} KB`;
  282 + } else { // Bytes
  283 + return `${value} Bytes`;
  284 + }
  285 + },
  286 + handleClose(done) {
  287 + this.$confirm('确认关闭?')
  288 + .then(_ => {
  289 + done();
  290 + })
  291 + .catch(_ => {
  292 + });
  293 + },
  294 + /**
  295 + * 详细信息按钮
  296 + */
  297 + clickInformation(val) {
  298 + if (val) {
  299 + this.open = true;
  300 + this.information = val.carData
  301 + } else {
  302 + this.$message.error("车辆信息有误")
  303 + }
  304 + },
  305 + /**
  306 + * 关闭框
  307 + */
  308 + closeInformation() {
  309 + this.open = false;
  310 + this.information = {};
  311 + }
  312 + },
  313 + //生命周期 - 创建完成(可以访问当前this实例)",
  314 + created() {
  315 + this.getDatesByTimeFrame()
  316 + this.searchFlowList();
  317 + },
  318 + //生命周期 - 挂载完成(可以访问DOM元素)",
  319 + mounted() {
  320 + },
  321 + beforeCreate() {
  322 + }, //生命周期 - 创建之前",
  323 + beforeMount() {
  324 + }, //生命周期 - 挂载之前",
  325 + beforeUpdate() {
  326 + }, //生命周期 - 更新之前",
  327 + updated() {
  328 + }, //生命周期 - 更新之后",
  329 + beforeDestroy() {
  330 + }, //生命周期 - 销毁之前",
  331 + destroyed() {
  332 + }, //生命周期 - 销毁完成",
  333 + activated() {
  334 + } //如果页面有keep-alive缓存功能,这个函数会触发",
  335 +};
  336 +</script>
  337 +<style scoped>
  338 +.device-tree-main-box {
  339 + text-align: left;
  340 +}
  341 +
  342 +.btn {
  343 + margin: 0 10px;
  344 +
  345 +}
  346 +
  347 +.btn:hover {
  348 + color: #409EFF;
  349 +}
  350 +
  351 +.btn.active {
  352 + color: #409EFF;
  353 +
  354 +}
  355 +
  356 +.redborder {
  357 + border: 2px solid red !important;
  358 +}
  359 +
  360 +.play-box {
  361 + background-color: #000000;
  362 + border: 2px solid #505050;
  363 + display: flex;
  364 + align-items: center;
  365 + justify-content: center;
  366 +}
  367 +
  368 +.historyListLi {
  369 + width: 97%;
  370 + white-space: nowrap;
  371 + text-overflow: ellipsis;
  372 + cursor: pointer;
  373 + padding: 3px;
  374 + margin-bottom: 6px;
  375 + border: 1px solid #000000;
  376 +}
  377 +
  378 +.historyListDiv {
  379 + height: 80vh;
  380 + width: 100%;
  381 + overflow-y: auto;
  382 + overflow-x: hidden;
  383 +}
  384 +
  385 +
  386 +/* 菜单的样式 */
  387 +.rMenu {
  388 + position: absolute;
  389 + top: 0;
  390 + display: none;
  391 + margin: 0;
  392 + padding: 0;
  393 + text-align: left;
  394 + border: 1px solid #BFBFBF;
  395 + border-radius: 3px;
  396 + background-color: #EEE;
  397 + box-shadow: 0 0 10px #AAA;
  398 +}
  399 +
  400 +.rMenu li {
  401 + width: 170px;
  402 + list-style: none outside none;
  403 + cursor: default;
  404 + color: #666;
  405 + margin-left: -20px;
  406 +}
  407 +
  408 +.rMenu li:hover {
  409 + color: #EEE;
  410 + background-color: #666;
  411 +}
  412 +
  413 +li#menu-item-delete, li#menu-item-rename {
  414 + margin-top: 1px;
  415 +}
  416 +</style>
  417 +<style>
  418 +.videoList {
  419 + display: flex;
  420 + flex-wrap: wrap;
  421 + align-content: flex-start;
  422 +}
  423 +
  424 +.video-item {
  425 + position: relative;
  426 + width: 15rem;
  427 + height: 10rem;
  428 + margin-right: 1rem;
  429 + background-color: #000000;
  430 +}
  431 +
  432 +.video-item-img {
  433 + position: absolute;
  434 + top: 0;
  435 + bottom: 0;
  436 + left: 0;
  437 + right: 0;
  438 + margin: auto;
  439 + width: 100%;
  440 + height: 100%;
  441 +}
  442 +
  443 +.video-item-img:after {
  444 + content: "";
  445 + display: inline-block;
  446 + position: absolute;
  447 + z-index: 2;
  448 + top: 0;
  449 + bottom: 0;
  450 + left: 0;
  451 + right: 0;
  452 + margin: auto;
  453 + width: 3rem;
  454 + height: 3rem;
  455 + background-image: url("../assets/loading.png");
  456 + background-size: cover;
  457 + background-color: #000000;
  458 +}
  459 +
  460 +.video-item-title {
  461 + position: absolute;
  462 + bottom: 0;
  463 + color: #000000;
  464 + background-color: #ffffff;
  465 + line-height: 1.5rem;
  466 + padding: 0.3rem;
  467 + width: 14.4rem;
  468 +}
  469 +
  470 +.baidumap {
  471 + width: 100%;
  472 + height: 100%;
  473 + border: none;
  474 + position: absolute;
  475 + left: 0;
  476 + top: 0;
  477 + right: 0;
  478 + bottom: 0;
  479 + margin: auto;
  480 +}
  481 +
  482 +/* 去除百度地图版权那行字 和 百度logo */
  483 +.baidumap > .BMap_cpyCtrl {
  484 + display: none !important;
  485 +}
  486 +
  487 +.baidumap > .anchorBL {
  488 + display: none !important;
  489 +}
  490 +</style>
web_src/src/components/HistoricalRecord.vue
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 <div style="width:100%;display: flex;flex-direction: column;justify-content: space-between;"> 4 <div style="width:100%;display: flex;flex-direction: column;justify-content: space-between;">
5 <div class="block" style="width: 99%;text-align:left;margin-bottom:15px;"> 5 <div class="block" style="width: 99%;text-align:left;margin-bottom:15px;">
6 <el-card class="box-card" style="width: 100%"> 6 <el-card class="box-card" style="width: 100%">
7 - <car-tree v-model="sim_channel"/> 7 + <car-tree v-model="sim_channel" />
8 <el-date-picker 8 <el-date-picker
9 v-model="date" 9 v-model="date"
10 align="right" 10 align="right"
@@ -26,14 +26,14 @@ @@ -26,14 +26,14 @@
26 </div> 26 </div>
27 27
28 <div style="width: 100%;display:flex;flex-direction:row; justify-content:space-between;"> 28 <div style="width: 100%;display:flex;flex-direction:row; justify-content:space-between;">
29 - <div style="width:20%;height: 80vh" > 29 + <div style="width:22%;height: 80vh" >
30 <historical-data :history-data="historyData" @click="clickHistoricalPlay" /> 30 <historical-data :history-data="historyData" @click="clickHistoricalPlay" />
31 </div> 31 </div>
32 - <div style="width: 78%;"> 32 + <div style="width: 77%;">
33 <div style="width: 99%;height: 80vh;display: flex;flex-wrap: wrap;background-color: #000;"> 33 <div style="width: 99%;height: 80vh;display: flex;flex-wrap: wrap;background-color: #000;">
34 - <div v-if="!videoUrl[0]" style="color: #ffffff;font-size: 30px;font-weight: bold;"></div>  
35 - <player ref="player" v-else :videoUrl="videoUrl[0]" fluent autoplay @screenshot="shot"  
36 - @destroy="destroy" style="width: 100%;height: 100%;"/> 34 + <div v-if="!videoUrl[0]" style="color: #ffffff;font-size: 30px;font-weight: bold;"></div>
  35 + <player ref="player" v-else :videoUrl="videoUrl[0]" fluent autoplay @screenshot="shot"
  36 + @destroy="destroy" style="width: 100%;height: 100%;"/>
37 </div> 37 </div>
38 </div> 38 </div>
39 </div> 39 </div>
@@ -109,10 +109,6 @@ export default { @@ -109,10 +109,6 @@ export default {
109 clickHistoricalPlay(data) { 109 clickHistoricalPlay(data) {
110 this.playHistoryItem(data) 110 this.playHistoryItem(data)
111 }, 111 },
112 - simChannelChange(val) {  
113 - console.log(val);  
114 - console.log(this.sim_channel)  
115 - },  
116 /** 112 /**
117 * 下载历史视频 113 * 下载历史视频
118 */ 114 */
@@ -135,6 +131,7 @@ export default { @@ -135,6 +131,7 @@ export default {
135 return; 131 return;
136 } 132 }
137 let split = simChannel[simChannel.length - 1].split('-'); 133 let split = simChannel[simChannel.length - 1].split('-');
  134 + console.log("simChannel:",simChannel)
138 let sim = split[0]; 135 let sim = split[0];
139 if (this.isEmpty(sim)) { 136 if (this.isEmpty(sim)) {
140 this.$message.error('无法获取SIM卡信息,请检查设备'); 137 this.$message.error('无法获取SIM卡信息,请检查设备');
@@ -155,13 +152,16 @@ export default { @@ -155,13 +152,16 @@ export default {
155 url: '/api/jt1078/query/history/list/' + sim + '/' + channel + "/" + this.startTime + "/" + this.endTime 152 url: '/api/jt1078/query/history/list/' + sim + '/' + channel + "/" + this.startTime + "/" + this.endTime
156 }).then( 153 }).then(
157 res=>{ 154 res=>{
  155 + console.log(res.data)
158 let items = res.data.data.obj.data.items; 156 let items = res.data.data.obj.data.items;
159 if (res && res.data && res.data.data && res.data.data.obj && res.data.data.code == 1 && res.data.data.obj.data && items) { 157 if (res && res.data && res.data.data && res.data.data.obj && res.data.data.code == 1 && res.data.data.obj.data && items) {
160 for (let i in items) { 158 for (let i in items) {
161 - items[i].sim = res.data.data.obj.data.clientId; 159 + items[i].sim = sim;
  160 + items[i].channel = channel
162 items[i].name = items[i].startTime + '-' + items[i].endTime; 161 items[i].name = items[i].startTime + '-' + items[i].endTime;
163 } 162 }
164 this.historyData = items 163 this.historyData = items
  164 + console.log(this.historyData)
165 this.loading = false 165 this.loading = false
166 } else if (res && res.data && res.data.data && res.data.data.msg) { 166 } else if (res && res.data && res.data.data && res.data.data.msg) {
167 this.$message.error(res.data.data.msg); 167 this.$message.error(res.data.data.msg);
@@ -169,7 +169,10 @@ export default { @@ -169,7 +169,10 @@ export default {
169 } else { 169 } else {
170 this.loading = false 170 this.loading = false
171 } 171 }
172 - }); 172 + }).cache(res => {
  173 + this.$message.error(res.msg);
  174 + this.loading = false
  175 + })
173 }, 176 },
174 /** 177 /**
175 * 时间转换 178 * 时间转换
@@ -213,7 +216,7 @@ export default { @@ -213,7 +216,7 @@ export default {
213 this.videoUrl = []; 216 this.videoUrl = [];
214 this.$axios({ 217 this.$axios({
215 method: 'get', 218 method: 'get',
216 - url: '/api/jt1078/query/send/request/io/history/' + e.sim + '/' + e.channelNo + "/" + e.startTime + "/" + e.endTime + "/" + e.channelMapping 219 + url: '/api/jt1078/query/send/request/io/history/' + e.sim + '/' + e.channel + "/" + e.startTime + "/" + e.endTime + "/" + e.channelMapping
217 }).then(res=> { 220 }).then(res=> {
218 if (res.data && res.data.data && res.data.data.data) { 221 if (res.data && res.data.data && res.data.data.data) {
219 let videoUrl1; 222 let videoUrl1;
web_src/src/components/JT1078Components/cascader/CarTree.vue
@@ -73,6 +73,7 @@ @@ -73,6 +73,7 @@
73 if (res.data.data.code == 1) { 73 if (res.data.data.code == 1) {
74 let data1 = res.data.data.result; 74 let data1 = res.data.data.result;
75 this.addChannel(data1); 75 this.addChannel(data1);
  76 + console.log(data1)
76 } else if (res.data.data.message) { 77 } else if (res.data.data.message) {
77 this.$message.error(res.data.data.message); 78 this.$message.error(res.data.data.message);
78 } 79 }
web_src/src/components/JT1078Components/cascader/CarTreeOne.vue 0 → 100644
  1 +<template>
  2 + <el-cascader
  3 + placeholder="请选择/搜索车辆"
  4 + :options="options"
  5 + filterable
  6 + clearable
  7 + :props="prop"
  8 + v-model="valueList"
  9 + @change="getValue">
  10 + </el-cascader>
  11 +</template>
  12 +
  13 +<script>
  14 +//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等),
  15 +//例如:import 《组件名称》 from '《组件路径》,
  16 + export default {
  17 + //import引入的组件需要注入到对象中才能使用"
  18 + components: {},
  19 + props: {
  20 + value: {
  21 + type: Array,
  22 + default: []
  23 + }
  24 + },
  25 + data() {
  26 + //这里存放数据"
  27 + return {
  28 + options: [],
  29 + prop: {
  30 + value: 'sim',
  31 + label: `name`,
  32 + children: 'children'
  33 + },
  34 +
  35 + };
  36 + },
  37 + //计算属性 类似于data概念",
  38 + computed: {
  39 + valueList: {
  40 + get(){
  41 + let value = this.value;
  42 + if (value || value === null || value.length === 0) {
  43 + return value
  44 + }
  45 + return value[ value.length - 1 ];
  46 + },
  47 + set(val){
  48 + if (val || val === null || val.length === 0) {
  49 + this.$emit("input",val)
  50 + }
  51 + return val[ val.length - 1 ]
  52 + }
  53 + }
  54 + },
  55 + //监控data中的数据变化",
  56 + watch: {},
  57 + //方法集合",
  58 + methods: {
  59 + getValue(val){
  60 + console.log(val)
  61 + },
  62 + /**
  63 + * 查询级联数据列表
  64 + */
  65 + initTreeData() {
  66 + this.$axios({
  67 + method: 'get',
  68 + url: `/api/jt1078/query/car/tree/` + 100,
  69 + }).then((res) => {
  70 + if (res && res.data && res.data.data) {
  71 + if (res.data.data.code == 1) {
  72 + let data1 = res.data.data.result;
  73 + this.addChannel(data1);
  74 + console.log(data1)
  75 + } else if (res.data.data.message) {
  76 + this.$message.error(res.data.data.message);
  77 + }
  78 + } else {
  79 + this.$message.error("请求错误,请刷新再试");
  80 + }
  81 +
  82 + });
  83 + },
  84 + /**
  85 + * 整理数据结构
  86 + * @param treeNo
  87 + */
  88 + addChannel(data) {
  89 + for (let i in data) {
  90 + if (data[i] && data[i].sim){
  91 + data[i].name = data[i].code;
  92 + }else if (data[i].children && data[i].children.length > 0){
  93 + this.addChannel(data[i].children);
  94 + }
  95 + }
  96 + this.options = data
  97 + },
  98 + },
  99 + //生命周期 - 创建完成(可以访问当前this实例)",
  100 + created() {
  101 + this.initTreeData();
  102 + },
  103 + //生命周期 - 挂载完成(可以访问DOM元素)",
  104 + mounted() {
  105 + },
  106 + beforeCreate() {
  107 + }, //生命周期 - 创建之前",
  108 + beforeMount() {
  109 + }, //生命周期 - 挂载之前",
  110 + beforeUpdate() {
  111 + }, //生命周期 - 更新之前",
  112 + updated() {
  113 + }, //生命周期 - 更新之后",
  114 + beforeDestroy() {
  115 + }, //生命周期 - 销毁之前",
  116 + destroyed() {
  117 + }, //生命周期 - 销毁完成",
  118 + activated() {
  119 + } //如果页面有keep-alive缓存功能,这个函数会触发",
  120 + };
  121 +</script>
  122 +<style scoped>
  123 +
  124 +</style>
web_src/src/components/JT1078Components/deviceList/Device1078Tree.vue 0 → 100644
  1 +<template>
  2 + <div class="device-tree-main-box">
  3 + <div id="DeviceTree" style="width: 100%;height: 100%; background-color: #FFFFFF; overflow: auto">
  4 + <el-container>
  5 + <el-header>设备列表</el-header>
  6 + <el-main style="background-color: #ffffff;">
  7 + <el-input
  8 + placeholder="输入关键字进行过滤"
  9 + v-model="filterText">
  10 + </el-input>
  11 + <el-tree
  12 + class="filter-tree"
  13 + :data="treeData"
  14 + :props="defaultProps"
  15 + :default-expanded-keys="expandedKeys"
  16 + node-key="id"
  17 + ref="tree"
  18 + :filter-node-method="filterNode"
  19 + :check-strictly="true"
  20 + @node-click="nodeClick"
  21 + @node-contextmenu="nodeContextmenu"
  22 + @node-expand="handleNodeExpand"
  23 + @node-collapse="handleNodeCollapse"
  24 + style="margin-top: 10px"
  25 + >
  26 + <span class="custom-tree-node" slot-scope="{ node, data }">
  27 + <span v-if="data.abnormalStatus !== undefined && data.children && data.abnormalStatus === 1">
  28 + <i class="el-icon-location" style="color: #409EFF"></i>{{ `${data.name}(在线)` }}
  29 + </span>
  30 + <span v-if="data.abnormalStatus !== undefined && data.abnormalStatus === 20">
  31 + <i class="el-icon-location" style="color: #909399"></i>{{ `${data.name}(离线)` }}
  32 + </span>
  33 + <span v-if="data.abnormalStatus !== undefined && data.abnormalStatus === 10">
  34 + <i class="el-icon-location" style="color: #909399"></i>{{ `${data.name}(未接入)` }}
  35 + </span>
  36 + <span v-if="data.abnormalStatus === undefined && data.children ">
  37 + {{ `${data.name}(${data.onlineData.length}/${data.children.length})` }}
  38 + </span>
  39 + <span v-if="data.abnormalStatus === undefined && data.children === undefined ">
  40 + <i class="el-icon-video-camera-solid">&nbsp;&nbsp;</i>{{ `${data.name}` }}
  41 + </span>
  42 + </span>
  43 + </el-tree>
  44 + </el-main>
  45 + </el-container>
  46 + </div>
  47 + </div>
  48 +</template>
  49 +
  50 +<script>
  51 +//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等),
  52 +//例如:import 《组件名称》 from '《组件路径》,
  53 +
  54 +export default {
  55 + //import引入的组件需要注入到对象中才能使用"
  56 + components: {},
  57 + props: {
  58 + //树 数据
  59 + treeData: {
  60 + type: Array,
  61 + default: []
  62 + },
  63 + },
  64 + data() {
  65 + //这里存放数据"
  66 + return {
  67 + //搜索值
  68 + filterText: '',
  69 + //默认的prop
  70 + defaultProps: {
  71 + label: 'name',
  72 + children: 'children',
  73 + },
  74 + pointsList: [],
  75 + expandedKeys: []
  76 + };
  77 + },
  78 + //计算属性 类似于data概念",
  79 + computed: {
  80 + },
  81 + //监控data中的数据变化",
  82 + watch: {
  83 + filterText(val) {
  84 + this.$refs.tree.filter(val);
  85 + },
  86 + treeData(val) {
  87 + console.log(val);
  88 + this.treeData = val
  89 + }
  90 + },
  91 + //方法集合",
  92 + methods: {
  93 + handleNodeExpand(data, node, el) {
  94 + if (!this.expandedKeys.includes(node.key)) {
  95 + this.expandedKeys.push(node.key);
  96 + }
  97 + },
  98 + handleNodeCollapse(data, node, el) {
  99 + const index = this.expandedKeys.indexOf(node.key);
  100 + if (index > -1) {
  101 + this.expandedKeys.splice(index, 1);
  102 + }
  103 + },
  104 + /**
  105 + * 模糊查询树
  106 + */
  107 + filterNode(value, data, node) {
  108 + if (!value) return true;
  109 + return this.findSearKey(node, value)
  110 + },
  111 + /**
  112 + * 点击事件
  113 + */
  114 + nodeClick(data, node, fun){
  115 + console.log(data)
  116 + console.log("node ===> ", node)
  117 + this.$emit('node-click', data, node);
  118 + },
  119 + nodeContextmenu(event, data, node, fun){
  120 +
  121 + },
  122 + //递归搜索父级是否包含关键字
  123 + findSearKey(node, key) {
  124 + if (node.label.indexOf(key) !== -1) {
  125 + return true;
  126 + } else {
  127 + if (node.parent.parent == null) {
  128 + return false;
  129 + } else {
  130 + return this.findSearKey(node.parent, key);
  131 + }
  132 + }
  133 + },
  134 + },
  135 + //生命周期 - 创建完成(可以访问当前this实例)",
  136 + created() {
  137 + },
  138 + //生命周期 - 挂载完成(可以访问DOM元素)",
  139 + mounted() {
  140 + },
  141 + beforeCreate() {
  142 + }, //生命周期 - 创建之前",
  143 + beforeMount() {
  144 + }, //生命周期 - 挂载之前",
  145 + beforeUpdate() {
  146 + }, //生命周期 - 更新之前",
  147 + updated() {
  148 + }, //生命周期 - 更新之后",
  149 + beforeDestroy() {
  150 + }, //生命周期 - 销毁之前",
  151 + destroyed() {
  152 + }, //生命周期 - 销毁完成",
  153 + activated() {
  154 + } //如果页面有keep-alive缓存功能,这个函数会触发",
  155 + };
  156 +</script>
  157 +<style scoped>
  158 +
  159 +</style>
web_src/src/components/JT1078Components/echarts/BarChart.vue 0 → 100644
  1 +<template>
  2 + <div :class="className" :style="{height:height,width:width}" />
  3 +</template>
  4 +
  5 +<script>
  6 +import * as echarts from 'echarts'
  7 +require('echarts/theme/macarons') // echarts theme
  8 +import resize from './mixins/resize'
  9 +
  10 +const animationDuration = 6000
  11 +
  12 +export default {
  13 + mixins: [resize],
  14 + props: {
  15 + className: {
  16 + type: String,
  17 + default: 'chart'
  18 + },
  19 + width: {
  20 + type: String,
  21 + default: '100%'
  22 + },
  23 + height: {
  24 + type: String,
  25 + default: '300px'
  26 + },
  27 + data: {
  28 + type: Object,
  29 + required: true
  30 + }
  31 + },
  32 + data() {
  33 + return {
  34 + chart: null
  35 + }
  36 + },
  37 + mounted() {
  38 + this.$nextTick(() => {
  39 + this.initChart()
  40 + })
  41 + },
  42 + beforeDestroy() {
  43 + if (!this.chart) {
  44 + return
  45 + }
  46 + this.chart.dispose()
  47 + this.chart = null
  48 + },
  49 + methods: {
  50 + initChart() {
  51 + this.chart = echarts.init(this.$el, 'macarons')
  52 +
  53 + this.chart.setOption()
  54 + }
  55 + }
  56 +}
  57 +</script>
web_src/src/components/JT1078Components/historical/HistoricalDataTree.vue
1 <template> 1 <template>
2 - <el-card class="box-card" style="width: 100%;height: 100%">  
3 - <el-tree v-if="historyData.length > 0" :data="historyData">  
4 - <span class="custom-tree-node" slot-scope="{ node , data }">  
5 - <span>  
6 - <el-button @click="clickButton(data)" style="margin-top: 30px;margin-left: -12px">{{ data.name }}</el-button>  
7 - </span>  
8 - </span>  
9 - </el-tree>  
10 - <el-empty v-else></el-empty>  
11 - </el-card> 2 + <div style="width: 100%;height: 80vh" class="page-container">
  3 + <el-card class="box-card" >
  4 + <div class="scroll-container">
  5 + <el-scrollbar style="height: 79vh">
  6 + <el-tree v-if="historyData.length > 0" :data="historyData" class="historical-list-tree">
  7 + <span class="custom-tree-node" slot-scope="{ node , data }">
  8 + <el-button @click="clickButton(data)" >{{ data.name }}</el-button>
  9 + </span>
  10 + </el-tree>
  11 + <el-empty v-else></el-empty>
  12 + </el-scrollbar>
  13 + </div>
  14 + </el-card>
  15 + </div>
12 </template> 16 </template>
13 <script> 17 <script>
14 export default { 18 export default {
15 name: 'historical-data', 19 name: 'historical-data',
16 props: { 20 props: {
17 - historyData: {} 21 + historyData: {
  22 + type: Array,
  23 + default: []
  24 + }
18 }, 25 },
19 //计算属性 类似于data概念", 26 //计算属性 类似于data概念",
20 computed: {}, 27 computed: {},
@@ -49,11 +56,23 @@ export default { @@ -49,11 +56,23 @@ export default {
49 } //如果页面有keep-alive缓存功能,这个函数会触发", 56 } //如果页面有keep-alive缓存功能,这个函数会触发",
50 }; 57 };
51 </script> 58 </script>
52 -<style>  
53 - 59 +<style scoped>
  60 +.page-container {
  61 + display: flex;
  62 + flex-direction: column;
  63 + height: 100vh; /* 视口高度的 100% */
  64 +}
  65 +.box-card {
  66 + flex-grow: 1;
  67 + display: flex;
  68 + flex-direction: column;
  69 +}
54 70
  71 +.scroll-container {
  72 + flex-grow: 1;
  73 + overflow: hidden; /* 确保内容不会溢出 */
  74 +}
55 /* 菜单的样式 */ 75 /* 菜单的样式 */
56 -  
57 .rMenu li { 76 .rMenu li {
58 width: 170px; 77 width: 170px;
59 list-style: none outside none; 78 list-style: none outside none;
@@ -66,9 +85,11 @@ export default { @@ -66,9 +85,11 @@ export default {
66 color: #EEE; 85 color: #EEE;
67 background-color: #666; 86 background-color: #666;
68 } 87 }
69 -.el-tree-node__content {  
70 - padding-bottom: 30px; 88 +.historical-list-tree >>> .el-tree-node__content {
  89 + padding: 15px;
71 height: 20px; 90 height: 20px;
72 } 91 }
73 - 92 +.historical-list-tree {
  93 + margin: 10px 0 20px 0;
  94 +}
74 </style> 95 </style>
web_src/src/components/common/jessibuca.vue
@@ -11,8 +11,6 @@ @@ -11,8 +11,6 @@
11 </div> 11 </div>
12 <div class="buttons-box-right"> 12 <div class="buttons-box-right">
13 <span class="jessibuca-btn">{{ kBps }} kb/s</span> 13 <span class="jessibuca-btn">{{ kBps }} kb/s</span>
14 - <!-- <i class="iconfont icon-file-record1 jessibuca-btn"></i>-->  
15 - <!-- <i class="iconfont icon-xiangqing2 jessibuca-btn" ></i>-->  
16 <i class="iconfont icon-camera1196054easyiconnet jessibuca-btn" @click="screenshot" 14 <i class="iconfont icon-camera1196054easyiconnet jessibuca-btn" @click="screenshot"
17 style="font-size: 1rem !important"></i> 15 style="font-size: 1rem !important"></i>
18 <i class="iconfont icon-shuaxin11 jessibuca-btn" @click="playBtnClick"></i> 16 <i class="iconfont icon-shuaxin11 jessibuca-btn" @click="playBtnClick"></i>
@@ -156,7 +154,7 @@ export default { @@ -156,7 +154,7 @@ export default {
156 let _this = this; 154 let _this = this;
157 jessibuca.on("pause", function () { 155 jessibuca.on("pause", function () {
158 _this.playing = false; 156 _this.playing = false;
159 - 157 +
160 }); 158 });
161 jessibuca.on("play", function () { 159 jessibuca.on("play", function () {
162 _this.playing = true; 160 _this.playing = true;
web_src/src/components/console.vue
@@ -65,7 +65,7 @@ import consoleNodeLoad from &#39;./console/ConsoleNodeLoad.vue&#39; @@ -65,7 +65,7 @@ import consoleNodeLoad from &#39;./console/ConsoleNodeLoad.vue&#39;
65 import consoleDisk from './console/ConsoleDisk.vue' 65 import consoleDisk from './console/ConsoleDisk.vue'
66 import consoleResource from './console/ConsoleResource.vue' 66 import consoleResource from './console/ConsoleResource.vue'
67 import configInfo from './dialog/configInfo.vue' 67 import configInfo from './dialog/configInfo.vue'
68 - 68 +import consoleFlow from './console/ConsoleFlow.vue'
69 import echarts from 'echarts'; 69 import echarts from 'echarts';
70 70
71 export default { 71 export default {
@@ -80,6 +80,7 @@ export default { @@ -80,6 +80,7 @@ export default {
80 consoleDisk, 80 consoleDisk,
81 consoleResource, 81 consoleResource,
82 configInfo, 82 configInfo,
  83 + consoleFlow,
83 }, 84 },
84 data() { 85 data() {
85 return { 86 return {
web_src/src/components/console/ConsoleFlow.vue 0 → 100644
  1 +<template>
  2 + <div id="ConsoleNodeLoad" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
  3 + <car-tree :value="value" />
  4 + <ve-histogram ref="consoleNodeLoad" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" :legend-visible="true"></ve-histogram>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +
  10 +import CarTree from "../JT1078Components/cascader/CarTree.vue";
  11 +
  12 +export default {
  13 + name: 'ConsoleNodeLoad',
  14 + components: {CarTree},
  15 + data() {
  16 + return {
  17 + value: null,
  18 + chartData: {
  19 + columns: [],
  20 + rows: []
  21 + },
  22 + chartSettings: {
  23 + labelMap: {},
  24 + },
  25 + extend: {
  26 + title: {
  27 + show: true,
  28 + text: "流量统计",
  29 + left: "center",
  30 + top: 20,
  31 +
  32 + },
  33 + legend: {
  34 + left: "center",
  35 + bottom: "15px",
  36 + },
  37 + label: {
  38 + show: true,
  39 + position: "top"
  40 + }
  41 + }
  42 + };
  43 + },
  44 + mounted() {
  45 + this.$nextTick(_ => {
  46 + setTimeout(()=>{
  47 + this.$refs.consoleNodeLoad.echarts.resize()
  48 + }, 100)
  49 + })
  50 + },
  51 + destroyed() {
  52 + },
  53 + methods: {
  54 + setData: function(data) {
  55 + this.chartData .rows = data;
  56 + }
  57 + }
  58 +};
  59 +</script>
web_src/src/components/console/ConsoleNodeLoad.vue
@@ -6,7 +6,6 @@ @@ -6,7 +6,6 @@
6 6
7 <script> 7 <script>
8 8
9 -  
10 import moment from "moment/moment"; 9 import moment from "moment/moment";
11 10
12 export default { 11 export default {
@@ -55,7 +54,7 @@ export default { @@ -55,7 +54,7 @@ export default {
55 }, 54 },
56 methods: { 55 methods: {
57 setData: function(data) { 56 setData: function(data) {
58 - this.chartData .rows = data; 57 + this.chartData.rows = data;
59 } 58 }
60 59
61 } 60 }
web_src/src/layout/UiHeader.vue
@@ -10,6 +10,8 @@ @@ -10,6 +10,8 @@
10 10
11 <el-menu-item index="/historicalRecord">历史记录</el-menu-item> 11 <el-menu-item index="/historicalRecord">历史记录</el-menu-item>
12 12
  13 + <el-menu-item index="/flowStatistics">流量统计</el-menu-item>
  14 +
13 <el-menu-item v-if="editUser" index="/userManager">用户管理</el-menu-item> 15 <el-menu-item v-if="editUser" index="/userManager">用户管理</el-menu-item>
14 16
15 <!-- <el-submenu index="/setting">--> 17 <!-- <el-submenu index="/setting">-->
web_src/src/router/index.js
@@ -27,6 +27,7 @@ import web from &#39;../components/setting/Web.vue&#39; @@ -27,6 +27,7 @@ import web from &#39;../components/setting/Web.vue&#39;
27 import wasmPlayer from '../components/common/jessibuca.vue' 27 import wasmPlayer from '../components/common/jessibuca.vue'
28 import rtcPlayer from '../components/dialog/rtcPlayer.vue' 28 import rtcPlayer from '../components/dialog/rtcPlayer.vue'
29 import historicalRecord from "../components/HistoricalRecord.vue"; 29 import historicalRecord from "../components/HistoricalRecord.vue";
  30 +import flowStatistics from "../components/FlowStatistics.vue";
30 31
31 const originalPush = VueRouter.prototype.push 32 const originalPush = VueRouter.prototype.push
32 VueRouter.prototype.push = function push(location) { 33 VueRouter.prototype.push = function push(location) {
@@ -66,6 +67,10 @@ export default new VueRouter({ @@ -66,6 +67,10 @@ export default new VueRouter({
66 component: historicalRecord, 67 component: historicalRecord,
67 }, 68 },
68 { 69 {
  70 + path: '/flowStatistics',
  71 + component: flowStatistics,
  72 + },
  73 + {
69 path: '/minhang/deviceList', 74 path: '/minhang/deviceList',
70 name: 'minhang', 75 name: 'minhang',
71 component: minhang, 76 component: minhang,
web_src/static/css/iconfont.css
1 @font-face { 1 @font-face {
2 font-family: "iconfont"; /* Project id 1291092 */ 2 font-family: "iconfont"; /* Project id 1291092 */
3 - src: url('iconfont.woff2?t=1673251105600') format('woff2'), 3 + src: url('../../../../wvp-jtt1078-pro/wvp-jtt1078-ui/src/assets/iconfont/iconfont.woff2?t=1673251105600') format('woff2'),
4 url('iconfont.woff?t=1673251105600') format('woff'), 4 url('iconfont.woff?t=1673251105600') format('woff'),
5 url('iconfont.ttf?t=1673251105600') format('truetype'); 5 url('iconfont.ttf?t=1673251105600') format('truetype');
6 } 6 }
web_src/static/css/iconfont.woff2 deleted 100644 → 0
No preview for this file type
web_src/static/file/推流通道导入.zip deleted 100644 → 0
No preview for this file type
web_src/static/js/config.js
1 -window.baseUrl = "http://118.113.164.50:18989"; 1 +const baseUrl = `${window.location.protocol}//${window.location.hostname}${window.location.port ? ':' + window.location.port : ''}`;
  2 +
  3 +window.baseUrl = baseUrl;
2 4
3 // map组件全局参数, 注释此内容可以关闭地图功能 5 // map组件全局参数, 注释此内容可以关闭地图功能
4 window.mapParam = { 6 window.mapParam = {