From 37a84e66917d6e22e03e31b0a115e2c16d23ed21 Mon Sep 17 00:00:00 2001
From: 朱俊杰 <502612493@qq.com>
Date: 星期四, 10 二月 2022 14:45:33 +0800
Subject: [PATCH] 新增实时监控功能
---
web_src/src/api/deviceApi.js | 19
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.xml | 37 +
src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java | 33
src/main/java/com/genersoft/iot/vmp/utils/node/INode.java | 42 +
src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeMerger.java | 51 ++
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java | 9
web_src/src/components/live.vue | 357 +++++++++++++++
src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java | 20
pom.xml | 11
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java | 7
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java | 8
src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java | 21
src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeManager.java | 68 ++
web_src/src/components/channelTreeItem.vue | 74 +++
src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java | 28 +
src/main/java/com/genersoft/iot/vmp/utils/ObjectUtils.java | 41 +
web_src/src/router/index.js | 5
src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java | 50 ++
web_src/src/components/UiHeader.vue | 1
src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java | 54 ++
web_src/src/components/channelTree.vue | 70 +++
src/main/java/com/genersoft/iot/vmp/utils/CollectionUtil.java | 12
web_src/src/components/jessibuca.vue | 317 +++++++++++++
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java | 3
24 files changed, 1,322 insertions(+), 16 deletions(-)
diff --git a/pom.xml b/pom.xml
index abf4e9c..9331de3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -277,5 +277,16 @@
</plugin>
</plugins>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>src/main/java</directory>
+ <includes>
+ <include>**/*.xml</include>
+ </includes>
+ </resource>
+ </resources>
</build>
</project>
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
index 5e2745a..a188571 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -5,6 +5,7 @@
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
+import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import com.github.pagehelper.PageInfo;
@@ -94,6 +95,13 @@
public List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String query, Boolean hasSubChannel, Boolean online, int start, int limit);
/**
+ * 鑾峰彇鏌愪釜璁惧鐨勯�氶亾鏍�
+ * @param deviceId 璁惧ID
+ * @return
+ */
+ List<DeviceChannelTree> tree(String deviceId);
+
+ /**
* 鑾峰彇鏌愪釜璁惧鐨勯�氶亾鍒楄〃
*
* @param deviceId 璁惧ID
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
index 7f52f79..896d730 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
@@ -201,4 +202,6 @@
@Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND status=1")
List<DeviceChannel> queryOnlineChannelsByDeviceId(String deviceId);
+
+ List<DeviceChannelTree> tree(String deviceId);
}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.xml b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.xml
new file mode 100644
index 0000000..ce69d22
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper">
+
+ <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+ <resultMap id="treeNodeResultMap" type="com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTreeNode">
+ <id column="id" property="id"/>
+ <result column="parentId" property="parentId"/>
+ <result column="status" property="status"/>
+ <result column="title" property="title"/>
+ <result column="value" property="value"/>
+ <result column="key" property="key"/>
+ <result column="deviceId" property="deviceId"/>
+ <result column="channelId" property="channelId"/>
+ <result column="longitude" property="lng"/>
+ <result column="latitude" property="lat"/>
+ </resultMap>
+
+
+ <select id="tree" resultMap="treeNodeResultMap">
+ SELECT
+ channelId,
+ channelId as id,
+ deviceId,
+ parentId,
+ status,
+ name as title,
+ channelId as "value",
+ channelId as "key",
+ channelId,
+ longitude,
+ latitude
+ from device_channel
+ where deviceId = #{deviceId}
+ </select>
+
+</mapper>
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
index f43f92f..57b30f1 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
@@ -13,6 +13,8 @@
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.storager.dao.*;
+import com.genersoft.iot.vmp.utils.node.ForestNodeMerger;
+import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@@ -329,6 +331,11 @@
}
@Override
+ public List<DeviceChannelTree> tree(String deviceId) {
+ return ForestNodeMerger.merge(deviceChannelMapper.tree(deviceId));
+ }
+
+ @Override
public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
return deviceChannelMapper.queryChannels(deviceId, null,null, null, null);
}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/CollectionUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/CollectionUtil.java
new file mode 100644
index 0000000..4f7ca1f
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/CollectionUtil.java
@@ -0,0 +1,12 @@
+package com.genersoft.iot.vmp.utils;
+
+import java.util.Arrays;
+
+public class CollectionUtil {
+
+ public static <T> boolean contains(T[] array, final T element) {
+ return array != null && Arrays.stream(array).anyMatch((x) -> {
+ return ObjectUtils.nullSafeEquals(x, element);
+ });
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/ObjectUtils.java b/src/main/java/com/genersoft/iot/vmp/utils/ObjectUtils.java
new file mode 100644
index 0000000..1f429bc
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/ObjectUtils.java
@@ -0,0 +1,41 @@
+package com.genersoft.iot.vmp.utils;
+
+import java.util.Arrays;
+
+public class ObjectUtils {
+ public static boolean nullSafeEquals(Object o1, Object o2) {
+ if (o1 == o2) {
+ return true;
+ } else if (o1 != null && o2 != null) {
+ if (o1.equals(o2)) {
+ return true;
+ } else {
+ return o1.getClass().isArray() && o2.getClass().isArray() && arrayEquals(o1, o2);
+ }
+ } else {
+ return false;
+ }
+ }
+
+ private static boolean arrayEquals(Object o1, Object o2) {
+ if (o1 instanceof Object[] && o2 instanceof Object[]) {
+ return Arrays.equals((Object[])((Object[])o1), (Object[])((Object[])o2));
+ } else if (o1 instanceof boolean[] && o2 instanceof boolean[]) {
+ return Arrays.equals((boolean[])((boolean[])o1), (boolean[])((boolean[])o2));
+ } else if (o1 instanceof byte[] && o2 instanceof byte[]) {
+ return Arrays.equals((byte[])((byte[])o1), (byte[])((byte[])o2));
+ } else if (o1 instanceof char[] && o2 instanceof char[]) {
+ return Arrays.equals((char[])((char[])o1), (char[])((char[])o2));
+ } else if (o1 instanceof double[] && o2 instanceof double[]) {
+ return Arrays.equals((double[])((double[])o1), (double[])((double[])o2));
+ } else if (o1 instanceof float[] && o2 instanceof float[]) {
+ return Arrays.equals((float[])((float[])o1), (float[])((float[])o2));
+ } else if (o1 instanceof int[] && o2 instanceof int[]) {
+ return Arrays.equals((int[])((int[])o1), (int[])((int[])o2));
+ } else if (o1 instanceof long[] && o2 instanceof long[]) {
+ return Arrays.equals((long[])((long[])o1), (long[])((long[])o2));
+ } else {
+ return o1 instanceof short[] && o2 instanceof short[] && Arrays.equals((short[]) ((short[]) o1), (short[]) ((short[]) o2));
+ }
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java
new file mode 100644
index 0000000..0de2160
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java
@@ -0,0 +1,54 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鑺傜偣鍩虹被
+ *
+ */
+@Data
+public class BaseNode<T> implements INode<T> {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 涓婚敭ID
+ */
+ protected String id;
+
+ /**
+ * 鐖惰妭鐐笽D
+ */
+ protected String parentId;
+
+ /**
+ * 瀛愬瓩鑺傜偣
+ */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ protected List<T> children = new ArrayList<T>();
+
+ /**
+ * 鏄惁鏈夊瓙瀛欒妭鐐�
+ */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private Boolean hasChildren;
+
+ /**
+ * 鏄惁鏈夊瓙瀛欒妭鐐�
+ *
+ * @return Boolean
+ */
+ @Override
+ public Boolean getHasChildren() {
+ if (children.size() > 0) {
+ return true;
+ } else {
+ return this.hasChildren;
+ }
+ }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java
new file mode 100644
index 0000000..0ba7207
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java
@@ -0,0 +1,28 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+/**
+ * 妫灄鑺傜偣绫�
+ *
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class ForestNode extends BaseNode<ForestNode> {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鑺傜偣鍐呭
+ */
+ private Object content;
+
+ public ForestNode(String id, String parentId, Object content) {
+ this.id = id;
+ this.parentId = parentId;
+ this.content = content;
+ }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeManager.java b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeManager.java
new file mode 100644
index 0000000..de98fdc
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeManager.java
@@ -0,0 +1,68 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 妫灄绠$悊绫�
+ *
+ * @author smallchill
+ */
+public class ForestNodeManager<T extends INode<T>> {
+
+ /**
+ * 妫灄鐨勬墍鏈夎妭鐐�
+ */
+ private final ImmutableMap<String, T> nodeMap;
+
+ /**
+ * 妫灄鐨勭埗鑺傜偣ID
+ */
+ private final Map<String, Object> parentIdMap = Maps.newHashMap();
+
+ public ForestNodeManager(List<T> nodes) {
+ nodeMap = Maps.uniqueIndex(nodes, INode::getId);
+ }
+
+ /**
+ * 鏍规嵁鑺傜偣ID鑾峰彇涓�涓妭鐐�
+ *
+ * @param id 鑺傜偣ID
+ * @return 瀵瑰簲鐨勮妭鐐瑰璞�
+ */
+ public INode<T> getTreeNodeAt(String id) {
+ if (nodeMap.containsKey(id)) {
+ return nodeMap.get(id);
+ }
+ return null;
+ }
+
+ /**
+ * 澧炲姞鐖惰妭鐐笽D
+ *
+ * @param parentId 鐖惰妭鐐笽D
+ */
+ public void addParentId(String parentId) {
+ parentIdMap.put(parentId, "");
+ }
+
+ /**
+ * 鑾峰彇鏍戠殑鏍硅妭鐐�(涓�涓.鏋楀搴斿棰楁爲)
+ *
+ * @return 鏍戠殑鏍硅妭鐐归泦鍚�
+ */
+ public List<T> getRoot() {
+ List<T> roots = new ArrayList<>();
+ nodeMap.forEach((key, node) -> {
+ if (node.getParentId() == null || parentIdMap.containsKey(node.getId())) {
+ roots.add(node);
+ }
+ });
+ return roots;
+ }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeMerger.java b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeMerger.java
new file mode 100644
index 0000000..062d4cd
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeMerger.java
@@ -0,0 +1,51 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import com.genersoft.iot.vmp.utils.CollectionUtil;
+
+import java.util.List;
+
+/**
+ * 妫灄鑺傜偣褰掑苟绫�
+ *
+ */
+public class ForestNodeMerger {
+
+ /**
+ * 灏嗚妭鐐规暟缁勫綊骞朵负涓�涓.鏋楋紙澶氭5鏍戯級锛堝~鍏呰妭鐐圭殑children鍩燂級
+ * 鏃堕棿澶嶆潅搴︿负O(n^2)
+ *
+ * @param items 鑺傜偣鍩�
+ * @return 澶氭5鏍戠殑鏍硅妭鐐归泦鍚�
+ */
+ public static <T extends INode<T>> List<T> merge(List<T> items) {
+ ForestNodeManager<T> forestNodeManager = new ForestNodeManager<>(items);
+ items.forEach(forestNode -> {
+ if (forestNode.getParentId() != null) {
+ INode<T> node = forestNodeManager.getTreeNodeAt(forestNode.getParentId());
+ if (node != null) {
+ node.getChildren().add(forestNode);
+ } else {
+ forestNodeManager.addParentId(forestNode.getId());
+ }
+ }
+ });
+ return forestNodeManager.getRoot();
+ }
+
+ public static <T extends INode<T>> List<T> merge(List<T> items, String[] parentIds) {
+ ForestNodeManager<T> forestNodeManager = new ForestNodeManager<>(items);
+ items.forEach(forestNode -> {
+ if (forestNode.getParentId() != null) {
+ INode<T> node = forestNodeManager.getTreeNodeAt(forestNode.getParentId());
+ if (CollectionUtil.contains(parentIds, forestNode.getId())){
+ forestNodeManager.addParentId(forestNode.getId());
+ } else {
+ if (node != null){
+ node.getChildren().add(forestNode);
+ }
+ }
+ }
+ });
+ return forestNodeManager.getRoot();
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/INode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/INode.java
new file mode 100644
index 0000000..4d6ebfc
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/INode.java
@@ -0,0 +1,42 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ *
+ * 鑺傜偣
+ */
+public interface INode<T> extends Serializable {
+
+ /**
+ * 涓婚敭
+ *
+ * @return String
+ */
+ String getId();
+
+ /**
+ * 鐖朵富閿�
+ *
+ * @return String
+ */
+ String getParentId();
+
+ /**
+ * 瀛愬瓩鑺傜偣
+ *
+ * @return List<T>
+ */
+ List<T> getChildren();
+
+ /**
+ * 鏄惁鏈夊瓙瀛欒妭鐐�
+ *
+ * @return Boolean
+ */
+ default Boolean getHasChildren() {
+ return false;
+ }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java
new file mode 100644
index 0000000..9df6f11
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java
@@ -0,0 +1,21 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鏍戝瀷鑺傜偣绫�
+ *
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class TreeNode extends BaseNode<TreeNode> {
+
+ private static final long serialVersionUID = 1L;
+
+ private String title;
+
+ private String key;
+
+ private String value;
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java
new file mode 100644
index 0000000..b147a9e
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java
@@ -0,0 +1,50 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.utils.node.INode;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "DeviceChannelTree瀵硅薄", description = "DeviceChannelTree瀵硅薄")
+public class DeviceChannelTree extends DeviceChannel implements INode<DeviceChannelTree> {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 涓婚敭ID
+ */
+ private String id;
+
+ /**
+ * 鐖惰妭鐐笽D
+ */
+ private String parentId;
+
+ private String parentName;
+
+ /**
+ * 瀛愬瓩鑺傜偣
+ */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private List<DeviceChannelTree> children;
+
+ /**
+ * 鏄惁鏈夊瓙瀛欒妭鐐�
+ */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private Boolean hasChildren;
+
+ @Override
+ public List<DeviceChannelTree> getChildren() {
+ if (this.children == null) {
+ this.children = new ArrayList<>();
+ }
+ return this.children;
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java
new file mode 100644
index 0000000..29d82be
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java
@@ -0,0 +1,20 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+import com.genersoft.iot.vmp.utils.node.TreeNode;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DeviceChannelTreeNode extends TreeNode {
+
+ private Integer status;
+
+ private String deviceId;
+
+ private String channelId;
+
+ private Double lng;
+
+ private Double lat;
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
index f8e2c1c..b4e3eb4 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
@@ -1,32 +1,35 @@
package com.genersoft.iot.vmp.vmanager.bean;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
public class WVPResult<T> {
private int code;
private String msg;
private T data;
- public int getCode() {
- return code;
+ private static final Integer SUCCESS = 200;
+ private static final Integer FAILED = 400;
+
+ public static <T> WVPResult<T> Data(T t, String msg) {
+ return new WVPResult<>(SUCCESS, msg, t);
}
- public void setCode(int code) {
- this.code = code;
+ public static <T> WVPResult<T> Data(T t) {
+ return Data(t, "鎴愬姛");
}
- public String getMsg() {
- return msg;
+ public static <T> WVPResult<T> fail(int code, String msg) {
+ return new WVPResult<>(code, msg, null);
}
- public void setMsg(String msg) {
- this.msg = msg;
+ public static <T> WVPResult<T> fail(String msg) {
+ return fail(FAILED, msg);
}
- public T getData() {
- return data;
- }
-
- public void setData(T data) {
- this.data = data;
- }
}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
index d83094e..d9357d2 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -10,8 +10,10 @@
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@@ -25,6 +27,7 @@
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
+import java.util.List;
import java.util.UUID;
@Api(tags = "鍥芥爣璁惧鏌ヨ", value = "鍥芥爣璁惧鏌ヨ")
@@ -431,5 +434,9 @@
return result;
}
-
+ @GetMapping("/{deviceId}/tree")
+ @ApiOperation(value = "閫氶亾鏍戝舰缁撴瀯", notes = "閫氶亾鏍戝舰缁撴瀯")
+ public WVPResult<List<DeviceChannelTree>> tree(@PathVariable String deviceId) {
+ return WVPResult.Data(storager.tree(deviceId));
+ }
}
diff --git a/web_src/src/api/deviceApi.js b/web_src/src/api/deviceApi.js
new file mode 100644
index 0000000..830164f
--- /dev/null
+++ b/web_src/src/api/deviceApi.js
@@ -0,0 +1,19 @@
+import axios from 'axios';
+
+export const tree = (deviceId) => {
+ return axios({
+ url: `/api/device/query/${deviceId}/tree`,
+ method: 'get'
+ })
+}
+
+export const deviceList = (page, count) => {
+ return axios({
+ method: 'get',
+ url:`/api/device/query/devices`,
+ params: {
+ page,
+ count
+ }
+ })
+}
\ No newline at end of file
diff --git a/web_src/src/components/UiHeader.vue b/web_src/src/components/UiHeader.vue
index 6391fe8..4bbf639 100644
--- a/web_src/src/components/UiHeader.vue
+++ b/web_src/src/components/UiHeader.vue
@@ -2,6 +2,7 @@
<div id="UiHeader">
<el-menu router :default-active="activeIndex" menu-trigger="click" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" mode="horizontal">
<el-menu-item index="/">鎺у埗鍙�</el-menu-item>
+ <el-menu-item index="/live">瀹炴椂鐩戞帶</el-menu-item>
<el-menu-item index="/deviceList">璁惧鍒楄〃</el-menu-item>
<el-menu-item index="/pushVideoList">鎺ㄦ祦鍒楄〃</el-menu-item>
<el-menu-item index="/streamProxyList">鎷夋祦浠g悊</el-menu-item>
diff --git a/web_src/src/components/channelTree.vue b/web_src/src/components/channelTree.vue
new file mode 100644
index 0000000..ae9eac7
--- /dev/null
+++ b/web_src/src/components/channelTree.vue
@@ -0,0 +1,70 @@
+<template>
+ <div>
+ <el-tree :data="channelList" :props="props" @node-click="sendDevicePush">
+ <span slot-scope="{ node }">
+ <span v-if="node.isLeaf">
+ <i class="el-icon-video-camera" :style="{color:node.disabled==1?'#67C23A':'#F56C6C'}"></i>
+ </span>
+ <span v-else>
+ <i class="el-icon-folder"></i>
+ </span>
+ <span>
+ {{ node.label }}
+ </span>
+ </span>
+ </el-tree>
+ </div>
+</template>
+<script>
+import ChannelTreeItem from "@/components/channelTreeItem"
+import {tree} from '@/api/deviceApi'
+
+export default {
+ components: {
+ ChannelTreeItem,
+ },
+ props:{
+ device: {
+ type: Object,
+ required: true
+ }
+ },
+ data() {
+ return {
+ loading: false,
+ channelList: [],
+ props: {
+ label: 'title',
+ children: 'children',
+ isLeaf: 'hasChildren',
+ disabled: 'status'
+ },
+ }
+ },
+ computed: {
+
+ },
+ mounted() {
+ this.leafs = []
+ this.getTree()
+ },
+ methods: {
+ getTree() {
+ this.loading = true
+ var that = this
+ tree(this.device.deviceId).then(function (res) {
+ console.log(res.data.data);
+ that.channelList = res.data.data;
+ that.loading = false;
+ }).catch(function (error) {
+ console.log(error);
+ that.loading = false;
+ });
+ },
+ sendDevicePush(c) {
+ if(c.hasChildren) return
+ this.$emit('sendDevicePush',c)
+ }
+ }
+}
+</script>
\ No newline at end of file
diff --git a/web_src/src/components/channelTreeItem.vue b/web_src/src/components/channelTreeItem.vue
new file mode 100644
index 0000000..7f2a2a5
--- /dev/null
+++ b/web_src/src/components/channelTreeItem.vue
@@ -0,0 +1,74 @@
+<template>
+ <div>
+ <!-- <div :index="item.key" v-for="(item,i) in list" :key="i+'-'">
+ <el-submenu v-if="item.hasChildren">
+ <template slot="title">
+ <i class="el-icon-video-camera"></i>
+ <span slot="title">{{item.title || item.deviceId}}</span>
+ </template>
+ <channel-list :list="item.children" @sendDevicePush="sendDevicePush"></channel-list>
+ </el-submenu>
+ <el-menu-item v-else :index="item.key" @click="sendDevicePush(item)">
+ <template slot="title" >
+ <i class="el-icon-switch-button" :style="{color:item.status==1?'#67C23A':'#F56C6C'}"></i>
+ <span slot="title">{{item.title}}</span>
+ </template>
+ </el-menu-item>
+ </div> -->
+ <div >
+ <template v-if="!item.hasChildren">
+ <el-menu-item :index="item.key" @click="sendDevicePush(item)">
+ <i class="el-icon-video-camera" :style="{color:item.status==1?'#67C23A':'#F56C6C'}"></i>
+ {{item.title}}
+ </el-menu-item>
+ </template>
+
+ <el-submenu v-else :index="item.key">
+ <template slot="title" >
+ <i class="el-icon-location-outline"></i>
+ {{item.title}}
+ </template>
+
+ <template v-for="child in item.children">
+ <channel-item
+ v-if="child.hasChildren"
+ :item="child"
+ :key="child.key"
+ @sendDevicePush="sendDevicePush"/>
+ <el-menu-item v-else :key="child.key" :index="child.key" @click="sendDevicePush(child)">
+ <i class="el-icon-video-camera" :style="{color:child.status==1?'#67C23A':'#F56C6C'}"></i>
+ {{child.title}}
+ </el-menu-item>
+ </template>
+ </el-submenu>
+ </div>
+ </div>
+</template>
+<script>
+export default {
+ name:'ChannelItem',
+ props:{
+ list:Array,
+ channelId: String,
+ item: {
+ type: Object,
+ required: true
+ }
+ },
+ data () {
+ return {
+
+ }
+ },
+ watch: {
+ channelId(val) {
+ console.log(val);
+ }
+ },
+ methods: {
+ sendDevicePush(c) {
+ this.$emit('sendDevicePush',c)
+ }
+ }
+}
+</script>
diff --git a/web_src/src/components/jessibuca.vue b/web_src/src/components/jessibuca.vue
new file mode 100644
index 0000000..b66a9c6
--- /dev/null
+++ b/web_src/src/components/jessibuca.vue
@@ -0,0 +1,317 @@
+<template>
+ <div :id="'jessibuca'+idx" style="width: 100%; height: 100%">
+ <div :id="'container'+idx" ref="container" style="width: 100%; height: 100%; background-color: #000" @dblclick="fullscreenSwich">
+ <div class="buttons-box" :id="'buttonsBox'+idx">
+ <div class="buttons-box-left">
+ <i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick"></i>
+ <i v-if="playing" class="iconfont icon-pause jessibuca-btn" @click="pause"></i>
+ <i class="iconfont icon-stop jessibuca-btn" @click="destroyButton"></i>
+ <i v-if="isNotMute" class="iconfont icon-audio-high jessibuca-btn" @click="jessibuca.mute()"></i>
+ <i v-if="!isNotMute" class="iconfont icon-audio-mute jessibuca-btn" @click="jessibuca.cancelMute()"></i>
+ </div>
+ <div class="buttons-box-right">
+ <span class="jessibuca-btn">{{kBps}} kb/s</span>
+<!-- <i class="iconfont icon-file-record1 jessibuca-btn"></i>-->
+<!-- <i class="iconfont icon-xiangqing2 jessibuca-btn" ></i>-->
+ <i class="iconfont icon-camera1196054easyiconnet jessibuca-btn" @click="screenshot" style="font-size: 1rem !important"></i>
+ <i class="iconfont icon-shuaxin11 jessibuca-btn" @click="playBtnClick"></i>
+ <i v-if="!fullscreen" class="iconfont icon-weibiaoti10 jessibuca-btn" @click="fullscreenSwich"></i>
+ <i v-if="fullscreen" class="iconfont icon-weibiaoti11 jessibuca-btn" @click="fullscreenSwich"></i>
+ </div>
+ </div>
+
+ </div>
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'jessibuca',
+ data() {
+ return {
+ jessibuca: null,
+ playing: false,
+ isNotMute: false,
+ quieting: false,
+ fullscreen: false,
+ loaded: false, // mute
+ speed: 0,
+ performance: "", // 宸ヤ綔鎯呭喌
+ kBps: 0,
+ btnDom: null,
+ videoInfo: null,
+ volume: 1,
+ rotate: 0,
+ vod: true, // 鐐规挱
+ forceNoOffscreen: false,
+ };
+ },
+ props: ['videoUrl', 'error', 'hasAudio', 'height','idx'],
+ mounted () {
+ window.onerror = (msg) => {
+ // console.error(msg)
+ };
+ let paramUrl = decodeURIComponent(this.$route.params.url)
+ this.$nextTick(() =>{
+ let dom = document.getElementById("container"+this.idx);
+ // dom.style.height = (9/16 ) * dom.clientWidth + "px"
+ if (typeof (this.videoUrl) == "undefined") {
+ this.videoUrl = paramUrl;
+ }
+ this.btnDom = document.getElementById("buttonsBox"+this.idx);
+ console.log("鍒濆鍖栨椂鐨勫湴鍧�涓�: " + this.videoUrl)
+ this.play(this.videoUrl)
+ })
+ },
+ watch:{
+ videoUrl(newData, oldData){
+ this.play(newData)
+ },
+ immediate:true
+ },
+ methods: {
+ create(){
+ let options = {};
+ console.log(this.$refs.container)
+ console.log("hasAudio " + !!this.hasAudio)
+
+ this.jessibuca = new window.Jessibuca(Object.assign(
+ {
+ container: this.$refs.container,
+ videoBuffer: 0.2, // 鏈�澶х紦鍐叉椂闀匡紝鍗曚綅绉�
+ isResize: true,
+ decoder: "./static/js/jessibuca/index.js",
+ // text: "WVP-PRO",
+ // background: "bg.jpg",
+ loadingText: "鍔犺浇涓�",
+ hasAudio: !!this.hasAudio,
+ debug: false,
+ timeout:5,
+ supportDblclickFullscreen: false, // 鏄惁鏀寔灞忓箷鐨勫弻鍑讳簨浠讹紝瑙﹀彂鍏ㄥ睆锛屽彇娑堝叏灞忎簨浠躲��
+ operateBtns: {
+ fullscreen: false,
+ screenshot: false,
+ play: false,
+ audio: false,
+ },
+ record: "record",
+ vod: this.vod,
+ forceNoOffscreen: this.forceNoOffscreen,
+ isNotMute: this.isNotMute,
+ },
+ options
+ ));
+
+ let _this = this;
+ this.jessibuca.on("load", function () {
+ console.log("on load init");
+ });
+
+ this.jessibuca.on("log", function (msg) {
+ console.log("on log", msg);
+ });
+ this.jessibuca.on("record", function (msg) {
+ console.log("on record:", msg);
+ });
+ this.jessibuca.on("pause", function () {
+ _this.playing = false;
+ });
+ this.jessibuca.on("play", function () {
+ _this.playing = true;
+ });
+ this.jessibuca.on("fullscreen", function (msg) {
+ console.log("on fullscreen", msg);
+ _this.fullscreen = msg
+ });
+
+ this.jessibuca.on("mute", function (msg) {
+ console.log("on mute", msg);
+ _this.isNotMute = !msg;
+ });
+ this.jessibuca.on("audioInfo", function (msg) {
+ // console.log("audioInfo", msg);
+ });
+
+ this.jessibuca.on("videoInfo", function (msg) {
+ this.videoInfo = msg;
+ // console.log("videoInfo", msg);
+
+ });
+
+ this.jessibuca.on("bps", function (bps) {
+ // console.log('bps', bps);
+
+ });
+ let _ts = 0;
+ this.jessibuca.on("timeUpdate", function (ts) {
+ // console.log('timeUpdate,old,new,timestamp', _ts, ts, ts - _ts);
+ _ts = ts;
+ });
+
+ this.jessibuca.on("videoInfo", function (info) {
+ console.log("videoInfo", info);
+ });
+
+ this.jessibuca.on("error", (error) =>{
+ console.log("error", error);
+ this.pause()
+ });
+
+ this.jessibuca.on("timeout", ()=> {
+ console.log("timeout");
+ // this.pause()
+ this.play(this.videoUrl)
+ });
+
+ this.jessibuca.on('start', function () {
+ console.log('start');
+ })
+
+ this.jessibuca.on("performance", function (performance) {
+ let show = "鍗¢】";
+ if (performance === 2) {
+ show = "闈炲父娴佺晠";
+ } else if (performance === 1) {
+ show = "娴佺晠";
+ }
+ _this.performance = show;
+ });
+ this.jessibuca.on('buffer', function (buffer) {
+ // console.log('buffer', buffer);
+ })
+
+ this.jessibuca.on('stats', function (stats) {
+ // console.log('stats', stats);
+ })
+
+ this.jessibuca.on('kBps', function (kBps) {
+ _this.kBps = Math.round(kBps);
+ });
+
+ // 鏄剧ず鏃堕棿鎴� PTS
+ this.jessibuca.on('videoFrame', function () {
+
+ })
+
+ //
+ this.jessibuca.on('metadata', function () {
+
+ });
+ },
+ playBtnClick: function (event){
+ this.play(this.videoUrl)
+ },
+ play: function (url) {
+ console.log(url)
+
+ if (this.jessibuca) {
+ this.destroy();
+ }
+ if(!url){
+ return
+ }
+ this.create();
+ this.jessibuca.on("play", () => {
+ this.playing = true;
+ this.loaded = true;
+ this.quieting = this.jessibuca.quieting;
+ });
+ if (this.jessibuca.hasLoaded()) {
+ this.jessibuca.play(url);
+ } else {
+ this.jessibuca.on("load", () => {
+ console.log("load 鎾斁")
+ this.jessibuca.play(url);
+ });
+ }
+ },
+ pause: function () {
+ if (this.jessibuca) {
+ this.jessibuca.pause();
+ }
+ this.playing = false;
+ this.err = "";
+ this.performance = "";
+ },
+ destroy: function () {
+ if (this.jessibuca) {
+ this.jessibuca.destroy();
+ }
+ if (document.getElementById("buttonsBox"+this.idx) == null) {
+ document.getElementById("container"+this.idx).appendChild(this.btnDom)
+ }
+ this.jessibuca = null;
+ this.playing = false;
+ this.err = "";
+ this.performance = "";
+
+ },
+ eventcallbacK: function(type, message) {
+ // console.log("player 浜嬩欢鍥炶皟")
+ // console.log(type)
+ // console.log(message)
+ },
+ fullscreenSwich: function (){
+ let isFull = this.isFullscreen()
+ this.jessibuca.setFullscreen(!isFull)
+ this.fullscreen = !isFull;
+ },
+ isFullscreen: function (){
+ return document.fullscreenElement ||
+ document.msFullscreenElement ||
+ document.mozFullScreenElement ||
+ document.webkitFullscreenElement || false;
+ },
+ resize(){
+ this.jessibuca.resize()
+ },
+ screenshot(){
+ this.jessibuca.screenshot('鎴浘','png',0.5)
+ // let base64 = this.jessibuca.screenshot("shot","jpeg",0.5,'base64')
+ // this.$emit('screenshot',base64)
+ },
+ destroyButton() {
+ this.$emit('destroy', this.idx)
+ this.destroy()
+ }
+ },
+ destroyed() {
+ if (this.jessibuca) {
+ this.jessibuca.destroy();
+ }
+ this.playing = false;
+ this.loaded = false;
+ this.performance = "";
+ },
+}
+</script>
+
+<style>
+ .buttons-box{
+ width: 100%;
+ height: 28px;
+ background-color: rgba(43, 51, 63, 0.7);
+ position: absolute;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ left: 0;
+ bottom: 0;
+ user-select: none;
+ z-index: 10;
+ }
+ .jessibuca-btn{
+ width: 20px;
+ color: rgb(255, 255, 255);
+ line-height: 27px;
+ margin: 0px 10px;
+ padding: 0px 2px;
+ cursor: pointer;
+ text-align: center;
+ font-size: 0.8rem !important;
+ }
+ .buttons-box-right {
+ position: absolute;
+ right: 0;
+ }
+</style>
diff --git a/web_src/src/components/live.vue b/web_src/src/components/live.vue
new file mode 100644
index 0000000..beab9e4
--- /dev/null
+++ b/web_src/src/components/live.vue
@@ -0,0 +1,357 @@
+<template>
+ <div id="devicePosition" style="height: 100%">
+ <el-container style="height: 100%">
+ <el-header>
+ <uiHeader></uiHeader>
+ </el-header>
+ <el-container v-loading="loading" element-loading-text="鎷煎懡鍔犺浇涓�">
+ <el-aside width="300px" style="background-color: #ffffff">
+ <div style="text-align: center;padding-top: 20px;">璁惧鍒楄〃</div>
+ <el-menu v-loading="loading">
+ <el-submenu v-for="device in deviceList" :key="device.deviceId" :index="device.deviceId" @click="sendDevicePush(item)">
+ <template slot="title" >
+ <i class="el-icon-location-outline"></i>
+ {{device.name}}
+ </template>
+ <ChannelTree :device="device" @sendDevicePush="sendDevicePush"></ChannelTree>
+ </el-submenu>
+ </el-menu>
+ </el-aside>
+ <el-container>
+ <!-- <LivePlay></LivePlay> -->
+ <el-header height="40px" style="text-align: left;font-size: 17px;line-height: 40px;">
+ 鍒嗗睆:
+ <i class="el-icon-full-screen btn" :class="{active:spilt==1}" @click="spilt=1"/>
+ <i class="el-icon-menu btn" :class="{active:spilt==4}" @click="spilt=4"/>
+ <i class="el-icon-s-grid btn" :class="{active:spilt==9}" @click="spilt=9"/>
+ </el-header>
+ <el-main>
+ <div style="width: 100%;height: calc( 100vh - 110px );display: flex;flex-wrap: wrap;background-color: #000;">
+ <div v-for="i in spilt" :key="i" class="play-box"
+ :style="liveStyle" :class="{redborder:playerIdx == (i-1)}"
+ @click="playerIdx = (i-1)"
+ >
+ <div v-if="!videoUrl[i-1]" style="color: #ffffff;font-size: 30px;font-weight: bold;">{{i}}</div>
+ <player v-else :ref="'player'+i" :videoUrl="videoUrl[i-1]" fluent autoplay :height="true"
+ :idx="'player'+i" @screenshot="shot" @destroy="destroy"></player>
+ <!-- <player v-else ref="'player'+i" :idx="'player'+i" :visible.sync="showVideoDialog" :videoUrl="videoUrl[i-1]" :height="true" :hasAudio="hasAudio" fluent autoplay live ></player> -->
+ </div>
+ </div>
+ </el-main>
+ </el-container>
+ </el-container>
+ </el-container>
+ </div>
+</template>
+
+<script>
+ import uiHeader from "./UiHeader.vue";
+ import player from './jessibuca.vue'
+ import ChannelTree from './channelTree.vue'
+
+ export default {
+ name: "live",
+ components: {
+ uiHeader, player, ChannelTree
+ },
+ data() {
+ return {
+ showVideoDialog: true,
+ hasAudio: false,
+ videoUrl:[''],
+ spilt:1,//鍒嗗睆
+ playerIdx:0,//婵�娲绘挱鏀惧櫒
+
+ deviceList: [], //璁惧鍒楄〃
+ currentDevice: {}, //褰撳墠鎿嶄綔璁惧瀵硅薄
+
+ videoComponentList: [],
+ updateLooper: 0, //鏁版嵁鍒锋柊杞鏍囧織
+ currentDeviceChannelsLenth:0,
+ winHeight: window.innerHeight - 200,
+ currentPage:1,
+ count:15,
+ total:0,
+ getDeviceListLoading: false,
+
+ //channel
+ searchSrt: "",
+ channelType: "",
+ online: "",
+ channelTotal:0,
+ deviceChannelList:[],
+ loading:false
+ };
+ },
+ mounted() {
+ this.initData();
+
+ },
+ created(){
+ this.checkPlayByParam()
+ },
+
+ computed:{
+ liveStyle(){
+ if(this.spilt==1){
+ return {width:'100%',height:'100%'}
+ }else if(this.spilt==4){
+ return {width:'49%',height:'49%'}
+ }else if(this.spilt==9){
+ return {width:'32%',height:'32%'}
+ }
+ }
+ },
+ watch:{
+ spilt(newValue){
+ console.log("鍒囨崲鐢诲箙;"+newValue)
+ let that = this
+ for (let i = 1; i <= newValue; i++) {
+ if(!that.$refs['player'+i]){
+ continue
+ }
+ this.$nextTick(()=>{
+ if(that.$refs['player'+i] instanceof Array){
+ that.$refs['player'+i][0].resize()
+ }else {
+ that.$refs['player'+i].resize()
+ }
+ })
+
+ }
+ window.localStorage.setItem('split',newValue)
+ },
+ '$route.fullPath':'checkPlayByParam'
+ },
+ destroyed() {
+ clearTimeout(this.updateLooper);
+ },
+ methods: {
+ initData: function () {
+ this.getDeviceList();
+
+ },
+ destroy(idx) {
+ console.log(idx);
+ this.clear(idx.substring(idx.length-1))
+ },
+ getDeviceList: function() {
+ let that = this;
+ this.$axios({
+ method: 'get',
+ url:`/api/device/query/devices`,
+ params: {
+ page: that.currentPage,
+ count: that.count
+ }
+ }).then(function (res) {
+ console.log(res.data.list);
+ that.total = res.data.total;
+
+ that.deviceList = res.data.list.map(item=>{return {deviceChannelList:[],...item}});
+ that.getDeviceListLoading = false;
+ }).catch(function (error) {
+ console.log(error);
+ that.getDeviceListLoading = false;
+ });
+ },
+ //閫氱煡璁惧涓婁紶濯掍綋娴�
+ sendDevicePush: function (itemData) {
+ if(itemData.status===0){
+ this.$message.error('璁惧绂荤嚎!');
+ return
+ }
+ this.save(itemData)
+ let deviceId = itemData.deviceId;
+ // this.isLoging = true;
+ let channelId = itemData.channelId;
+ console.log("閫氱煡璁惧鎺ㄦ祦1锛�" + deviceId + " : " + channelId );
+ let idxTmp = this.playerIdx
+ let that = this;
+ this.loading = true
+ this.$axios({
+ method: 'get',
+ url: '/api/play/start/' + deviceId + '/' + channelId
+ }).then(function (res) {
+ // that.isLoging = false;
+ console.log('=====----=====')
+ console.log(res)
+ if (res.data.code == 0 && res.data.data) {
+ itemData.playUrl = res.data.data.httpsFlv
+ that.setPlayUrl(res.data.data.ws_flv,idxTmp)
+ }else {
+ that.$message.error(res.data.msg);
+ }
+ }).catch(function (e) {
+ }).finally(()=>{
+ that.loading = false
+ });
+ },
+ setPlayUrl(url,idx){
+ this.$set(this.videoUrl,idx,url)
+ let _this = this
+ setTimeout(()=>{
+ window.localStorage.setItem('videoUrl',JSON.stringify(_this.videoUrl))
+ },100)
+
+ },
+ checkPlayByParam(){
+ let {deviceId,channelId} = this.$route.query
+ if(deviceId && channelId){
+ this.sendDevicePush({deviceId,channelId})
+ }
+ },
+ convertImageToCanvas(image) {
+ var canvas = document.createElement("canvas");
+ canvas.width = image.width;
+ canvas.height = image.height;
+ canvas.getContext("2d").drawImage(image, 0, 0);
+ return canvas;
+ },
+ shot(e){
+ // console.log(e)
+ // send({code:'image',data:e})
+ var base64ToBlob = function(code) {
+ let parts = code.split(';base64,');
+ let contentType = parts[0].split(':')[1];
+ let raw = window.atob(parts[1]);
+ let rawLength = raw.length;
+ let uInt8Array = new Uint8Array(rawLength);
+ for(let i = 0; i < rawLength; ++i) {
+ uInt8Array[i] = raw.charCodeAt(i);
+ }
+ return new Blob([uInt8Array], {
+ type: contentType
+ });
+ };
+ let aLink = document.createElement('a');
+ let blob = base64ToBlob(e); //new Blob([content]);
+ let evt = document.createEvent("HTMLEvents");
+ evt.initEvent("click", true, true); //initEvent 涓嶅姞鍚庝袱涓弬鏁板湪FF涓嬩細鎶ラ敊 浜嬩欢绫诲瀷锛屾槸鍚﹀啋娉★紝鏄惁闃绘娴忚鍣ㄧ殑榛樿琛屼负
+ aLink.download = '鎴浘';
+ aLink.href = URL.createObjectURL(blob);
+ aLink.click();
+ },
+ save(item){
+ let dataStr = window.localStorage.getItem('playData') || '[]'
+ let data = JSON.parse(dataStr);
+ data[this.playerIdx] = item
+ window.localStorage.setItem('playData',JSON.stringify(data))
+ },
+ clear(idx) {
+ let dataStr = window.localStorage.getItem('playData') || '[]'
+ let data = JSON.parse(dataStr);
+ data[idx-1] = null;
+ console.log(data);
+ window.localStorage.setItem('playData',JSON.stringify(data))
+ },
+ loadAndPlay(){
+ let dataStr = window.localStorage.getItem('playData') || '[]'
+ let data = JSON.parse(dataStr);
+
+ data.forEach((item,i)=>{
+ if(item){
+ this.playerIdx = i
+ this.sendDevicePush(item)
+ }
+ })
+ }
+ }
+ };
+</script>
+<style>
+ .btn{
+ margin: 0 10px;
+
+ }
+ .btn:hover{
+ color: #409EFF;
+ }
+ .btn.active{
+ color: #409EFF;
+
+ }
+ .redborder{
+ border: 2px solid red !important;
+ }
+ .play-box{
+ background-color: #000000;
+ border: 2px solid #505050;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+</style>
+<style>
+ .videoList {
+ display: flex;
+ flex-wrap: wrap;
+ align-content: flex-start;
+ }
+
+ .video-item {
+ position: relative;
+ width: 15rem;
+ height: 10rem;
+ margin-right: 1rem;
+ background-color: #000000;
+ }
+
+ .video-item-img {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ margin: auto;
+ width: 100%;
+ height: 100%;
+ }
+
+ .video-item-img:after {
+ content: "";
+ display: inline-block;
+ position: absolute;
+ z-index: 2;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ margin: auto;
+ width: 3rem;
+ height: 3rem;
+ background-image: url("../assets/loading.png");
+ background-size: cover;
+ background-color: #000000;
+ }
+
+ .video-item-title {
+ position: absolute;
+ bottom: 0;
+ color: #000000;
+ background-color: #ffffff;
+ line-height: 1.5rem;
+ padding: 0.3rem;
+ width: 14.4rem;
+ }
+
+ .baidumap {
+ width: 100%;
+ height: 100%;
+ border: none;
+ position: absolute;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ margin: auto;
+ }
+
+ /* 鍘婚櫎鐧惧害鍦板浘鐗堟潈閭h瀛� 鍜� 鐧惧害logo */
+ .baidumap > .BMap_cpyCtrl {
+ display: none !important;
+ }
+ .baidumap > .anchorBL {
+ display: none !important;
+ }
+</style>
diff --git a/web_src/src/router/index.js b/web_src/src/router/index.js
index 59bbb23..ad573cf 100644
--- a/web_src/src/router/index.js
+++ b/web_src/src/router/index.js
@@ -15,6 +15,7 @@
import web from '../components/setting/Web.vue'
import sip from '../components/setting/Sip.vue'
import media from '../components/setting/Media.vue'
+import live from '../components/live.vue'
import wasmPlayer from '../components/dialog/jessibuca.vue'
import rtcPlayer from '../components/dialog/rtcPlayer.vue'
@@ -35,6 +36,10 @@
component: control,
},
{
+ path: '/live',
+ component: live,
+ },
+ {
path: '/deviceList',
component: deviceList,
},
--
Gitblit v1.8.0