Przeglądaj źródła

视频完整功能

liuxing 1 rok temu
rodzic
commit
9b2022ddb3

+ 443 - 2
app/src/components/Camera.vue

@@ -4,17 +4,95 @@
       您的浏览器不支持 video 标签。
     </video>
     <div class="mask" @click="showVideo(id)"></div>
+    <div class="txt">{{ name }}</div>
+
+    <basic-modal
+      width="80%"
+      top="120px"
+      ref="cameraModal"
+      title="视频监控"
+      :appendToBody="true"
+      @opened="opened"
+    >
+      <div class="camera-container">
+        <div class="left">
+          <el-select
+            v-model="param.qx"
+            placeholder="区域"
+            clearable
+            @change="changeArea"
+          >
+            <el-option
+              :value="item.areaTitle"
+              :label="item.areaTitle"
+              v-for="(item, index) in areaData"
+              :key="index"
+            ></el-option>
+          </el-select>
+          <div class="tree-container">
+            <el-tree
+              class="carema-tree"
+              :data="treeData"
+              v-loading="treeLoading"
+              highlight-current
+              :expand-on-click-node="true"
+              ref="tree"
+              @node-click="handleNodeClick"
+              node-key="id"
+            >
+              <template slot-scope="{ node, data }">
+                <div class="tree-node" :title="node.label" :id="data.id">
+                  {{ node.label }}
+                </div>
+              </template>
+            </el-tree>
+          </div>
+        </div>
+        <div class="right" v-loading="rightLoading">
+          <video
+            :src="rightUrl"
+            v-if="rightUrl"
+            width="100%"
+            height="100%"
+            autoplay
+            muted
+            controls
+          >
+            您的浏览器不支持 video 标签。
+          </video>
+          <!-- <iframe :src="rightUrl" v-if="rightUrl" /> -->
+          <div class="empty" v-if="rightUrl === ''">暂无播放资源</div>
+          <div class="txt">{{ rightName }}</div>
+        </div>
+      </div>
+    </basic-modal>
   </div>
 </template>
 <script>
 import { getCameraUrl } from "@/api/camera.js";
+import { getDeviceList } from "@/api/iot.js";
+import { area } from "@/api/area";
 export default {
   name: "CameraContainer",
   components: {},
   data() {
     return {
       url: null,
+      name: null,
       loading: false,
+      treeData: [],
+      treeLoading: false,
+      tmpData: [],
+      rightUrl: null,
+      rightName: null,
+      rightLoading: false,
+      areaData: [],
+      param: {
+        qx: null,
+      },
+      currentId: null,
+      currentExpand: [],
+      nodeParentAll: [],
     };
   },
   props: {
@@ -26,29 +104,125 @@ export default {
       type: Array,
       default: [],
     },
+    zjid: {
+      type: String,
+      default: null,
+    },
+    qx: {
+      type: String,
+      default: null,
+    },
   },
   mounted() {
     this.getData();
+    this.getAreaList();
   },
   methods: {
+    // 通过节点的key(这里使用的是数据中的code属性,node-key="code")获取并高亮显示指定节点,并展开其所有父级节点
+    getAndExpandAll(nodeKey) {
+      if (nodeKey) {
+        this.$nextTick(() => {
+          // 等待树组件渲染完成再执行相关操作
+          // 获取节点
+          const node = this.$refs.tree.getNode(nodeKey);
+          if (node) {
+            // 获取其所有父级节点
+            this.getParentAll(node);
+            console.log(this.nodeParentAll);
+            if (this.nodeParentAll.length > 0) {
+              // 将获取到的所有父级节点进行展开
+              for (var i = 0, n = this.nodeParentAll.length; i < n; i++) {
+                this.$refs.tree.store.nodesMap[
+                  this.nodeParentAll[i].data.id
+                ].expanded = true;
+              }
+            }
+
+            // 将节点高亮显示
+            this.$refs.tree.setCurrentKey(nodeKey);
+            this.handleNodeClick({ id: nodeKey })
+          }
+        });
+      }
+    },
+    // 获取所有父级节点
+    getParentAll(node) {
+      if (node) {
+        this.nodeParentAll = [];
+        // 节点的第一个父级
+        var parentNode = node.parent;
+        // level为节点的层级 level=1 为顶级节点
+        for (var j = 0, lv = node.level; j < lv; j++) {
+          if (parentNode.level > 0) {
+            // 将所有父级节点放入集合中
+            this.nodeParentAll.push(parentNode);
+          }
+          // 继续获取父级节点的父级节点
+          parentNode = parentNode.parent;
+        }
+
+        if (this.nodeParentAll.length > 1) {
+          // 如果集合长度>1 则将数组进行倒叙.reverse() 其是就是将所有节点按照 从 顶级节点 依次往下排
+          this.nodeParentAll.reverse();
+        }
+      }
+    },
+    opened() {
+      if (this.currentId) {
+        this.getAndExpandAll(this.currentId);
+
+        // 定位到选中的节点
+        const node = document.getElementById(this.currentId);
+
+        setTimeout(function () {
+          node.scrollIntoView();
+        }, 500);
+      }
+    },
+    changeArea() {
+      this.getDevices();
+    },
+    getAreaList() {
+      area({
+        pageNum: 1,
+        pageSize: 100,
+      }).then((res) => {
+        this.areaData = res.data.rows;
+      });
+    },
+    handleNodeClick(data) {
+      this.rightUrl = null;
+      if (data.id) {
+        // 获取播放地址
+        this.rightLoading = true;
+        getCameraUrl(data.id).then((res) => {
+          this.rightLoading = false;
+          this.rightUrl = res.data.data[0].mp4;
+          this.rightName = res.data.data[0].deviceName;
+        });
+      }
+    },
     getData() {
       this.loading = true;
       // TO-DO
       getCameraUrl(this.id).then((res) => {
         this.loading = false;
         this.url = res.data.data[0].mp4;
+        this.name = res.data.data[0].deviceName;
         if (!this.url && this.byList && this.byList.length > 0) {
           this.loading = true;
           getCameraUrl(this.byList[this.byList.length - 1].sbbm).then(
             (res2) => {
               this.loading = false;
               this.url = res2.data.data[0].mp4;
+              this.name = res2.data.data[0].deviceName;
               if (!this.url) {
                 this.loading = true;
                 getCameraUrl(this.byList[this.byList.length - 2].sbbm).then(
                   (res3) => {
                     this.loading = false;
                     this.url = res3.mp4;
+                    this.name = res3.data.data[0].deviceName;
                   }
                 );
               }
@@ -60,10 +234,84 @@ export default {
       // this.url =
       //   "https://ycjk.cq119.gov.cn/rtp/77746e2c33126146cb83c81be23d0492.live.mp4?deviceId=50015200002000000001&key=";
     },
-    showVideo(id) {
-      console.log(id);
+    async showVideo(id) {
+      await this.getDevices();
 
+      // 选中当前
+      this.currentId = id;
+      // console.log(this.currentId);
       // 弹窗显示视频播放组件
+      this.showModal("cameraModal");
+    },
+    async getDevices() {
+      this.treeLoading = true;
+      let caremaData = [];
+      // 获取视频数据
+      const deviceParam = {
+        pageNum: 1,
+        pageSize: 10000,
+        qx: this.param.qx === "重庆市" ? "" : this.param.qx,
+        zt: "在线",
+        sblx: "生命通道监测",
+      };
+      if (this.jzid) {
+        deviceParam.jzid = this.jzid;
+      }
+      const res = await getDeviceList(deviceParam);
+      caremaData = caremaData.concat(res.data.rows);
+
+      const deviceParam2 = {
+        pageNum: 1,
+        pageSize: 10000,
+        qx: this.param.qx === "重庆市" ? "" : this.param.qx,
+        zt: "在线",
+        sblx: "消防控制室监控",
+      };
+      if (this.jzid) {
+        deviceParam2.jzid = this.jzid;
+      }
+      const res2 = await getDeviceList(deviceParam2);
+      caremaData = caremaData.concat(res2.data.rows);
+      console.log(caremaData);
+      this.tmpData = caremaData;
+      this.createTreeDate(caremaData);
+      this.treeLoading = false;
+    },
+    createTreeDate(caremaData) {
+      // 区县第一级
+      const qxData = [];
+      caremaData.forEach((p) => {
+        if (!qxData.find((k) => k.label === p.qx)) {
+          qxData.push({
+            id: p.qx,
+            label: p.qx,
+            children: [],
+            disabled: true,
+          });
+        }
+      });
+
+      qxData.forEach((p) => {
+        p.children.push({
+          id: p.id + "-生命通道监测",
+          label: "生命通道监测",
+          children: caremaData
+            .filter((k) => k.qx === p.label && k.sblx === "生命通道监测")
+            .map((i) => {
+              return { label: i.sbmc, id: i.sbbm };
+            }),
+        });
+        p.children.push({
+          id: p.id + "-消防控制室监控",
+          label: "消防控制室监控",
+          children: caremaData
+            .filter((k) => k.qx === p.label && k.sblx === "消防控制室监控")
+            .map((i) => {
+              return { label: i.sbmc, id: i.sbbm };
+            }),
+        });
+      });
+      this.treeData = qxData;
     },
   },
 };
@@ -84,5 +332,198 @@ export default {
     z-index: 99;
     cursor: pointer;
   }
+  .txt {
+    position: absolute;
+    font-family: "Abel";
+    font-style: normal;
+    font-weight: 400;
+    font-size: 14px;
+    line-height: 24px;
+    right: 11px;
+    top: 6px;
+  }
+}
+
+.camera-container {
+  width: 100%;
+  height: auto;
+  display: flex;
+  background: rgba(0, 16, 55, 0.94);
+
+  .left {
+    width: 300px;
+    height: auto;
+    padding: 0 30px 0 22px;
+
+    .tree-container {
+      width: 300px;
+      height: 540px;
+      overflow-y: auto;
+      margin-top: 15px;
+    }
+  }
+  .right {
+    width: 50%;
+    flex-grow: 1;
+    height: 600px;
+    box-sizing: border-box;
+    position: relative;
+    .txt {
+      position: absolute;
+      font-family: "Abel";
+      font-style: normal;
+      font-weight: 400;
+      font-size: 14px;
+      line-height: 24px;
+      right: 20px;
+      top: 10px;
+    }
+  }
+}
+
+.carema-tree {
+  background: transparent !important;
+  color: #f5fdff !important;
+}
+
+::v-deep(
+    .el-tree--highlight-current
+      .el-tree-node.is-current
+      > .el-tree-node__content
+  ) {
+  background: linear-gradient(
+    180deg,
+    rgba(0, 148, 255, 0.5) 0%,
+    rgba(0, 148, 255, 0) 100%
+  ) !important;
+  border-radius: 4px;
+  margin-left: 36px;
+  margin-right: 13px;
+  padding-left: 0 !important;
+  overflow: hidden;
+}
+::v-deep(.el-tree-node__content:hover) {
+  // background: linear-gradient(
+  //   180deg,
+  //   rgba(0, 148, 255, 0.5) 0%,
+  //   rgba(0, 148, 255, 0) 100%
+  // ) !important;
+  // border-radius: 4px;
+  // margin-left: 36px;
+  // margin-right: 13px;
+  // padding-left: 0 !important;
+  // overflow: hidden;
+  background: transparent !important;
+}
+::v-deep(.el-tree-node:focus > .el-tree-node__content) {
+  background: transparent !important;
+}
+
+.tree-node {
+  width: 90%;
+  height: 30px;
+  line-height: 30px;
+  box-sizing: border-box;
+  overflow: hidden;
+  margin-right: 13px;
+}
+
+video {
+  object-fit: fill;
+}
+
+.empty {
+  text-align: center;
+  padding-top: 200px;
+}
+
+/** 滚动条 */
+::-webkit-scrollbar,
+::-webkit-scrollbar,
+::-webkit-scrollbar,
+::-webkit-scrollbar {
+  /*滚动条整体样式*/
+  width: 8px;
+  /*高宽分别对应横竖滚动条的尺寸*/
+  height: 8px;
+}
+
+::-webkit-scrollbar-thumb,
+::-webkit-scrollbar-thumb,
+::-webkit-scrollbar-thumb,
+::-webkit-scrollbar-thumb {
+  /*滚动条里面小方块*/
+  border-radius: 4px;
+  /* box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); */
+  background: rgba(0, 213, 255, 0.73);
+  opacity: 0.7;
+}
+
+::-webkit-scrollbar-track,
+::-webkit-scrollbar-track,
+::-webkit-scrollbar-track,
+::-webkit-scrollbar-track {
+  /*滚动条里面轨道*/
+  /* box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); */
+  border-radius: 3px;
+  background: rgba(0, 213, 255, 0.3);
+  opacity: 0.7;
+}
+
+.camera-container {
+  display: flex;
+  gap: 2px;
+  ::v-deep(.el-select) {
+    width: 100%;
+    height: 40px;
+    .el-input__inner {
+      border-radius: 0px;
+      font-size: 18px;
+      border: 0px;
+      color: #9bc3ff;
+      background: url("../assets/images/border.png") no-repeat;
+      background-size: 100% 100%;
+      background-color: transparent;
+    }
+    .el-input__inner::placeholder {
+      color: #9bc3ff;
+    }
+    .el-input .el-select__caret {
+      color: #9bc3ff;
+    }
+  }
+
+  ::v-deep(.el-input.search-box-input) {
+    .el-input__inner {
+      border-radius: 0px;
+      font-size: 18px;
+      border: 1px solid #132444;
+      color: #9bc3ff;
+      background-color: transparent;
+    }
+    .el-input__inner::placeholder {
+      color: #6c83a7;
+    }
+  }
+
+  ::v-deep(.el-button) {
+    border: none;
+    width: 120px;
+    height: 40px;
+    color: #9bc3ff;
+    background: url("../assets/images/border.png") no-repeat;
+    background-size: 100% 100%;
+    background-color: transparent;
+    display: flex;
+    &::after {
+      content: "";
+      display: inline-block;
+      background: url("../assets/images/search-box-icon.png") no-repeat;
+      width: 20px;
+      height: 20px;
+      margin-left: 5px;
+      margin-top: 2px;
+    }
+  }
 }
 </style>

+ 12 - 1
app/src/views/Detail/components/BuildingInfo.vue

@@ -30,7 +30,7 @@
         <el-row class="row">
           <el-col :span="8">
             <span>使用功能:</span>
-            <p :title="''"></p>
+            <p :title="getSygn()">{{ getSygn() }}</p>
           </el-col>
           <el-col :span="8">
             <span>建成年代:</span>
@@ -213,6 +213,17 @@ export default {
         }
       });
     },
+    getSygn() {
+      if (this.detail.jzdx.indexOf("住宅") >= 0) {
+        return "住宅建筑";
+      } else if (this.detail.jzdx.indexOf("公共") >= 0) {
+        return "公共建筑";
+      } else if (this.detail.jzdx.indexOf("工业") >= 0) {
+        return "工业建筑";
+      }
+
+      return null;
+    },
   },
   created() {
     this.srcList = [

+ 11 - 0
app/src/views/Detail/components/VideoInfo.vue

@@ -186,8 +186,19 @@ export default {
         pageNum: 1,
         pageSize: 20,
         zt: "在线",
+        sblx: "生命通道监测",
       }).then((res) => {
         this.caremaList = res.data.rows;
+
+        getDeviceList({
+          jzid: this.detail.id,
+          pageNum: 1,
+          pageSize: 20,
+          zt: "在线",
+          sblx: "消防控制室监控",
+        }).then((res) => {
+          this.caremaList = this.caremaList.concat(res.data.rows);
+        });
       });
     },
     getJrsList() {

+ 2 - 2
app/src/views/Iot/components/IotVideo.vue

@@ -4,11 +4,11 @@
       <el-carousel-item v-for="i in count" :key="i">
         <div class="v-one" v-if="getVideo(i)">
           <Camera :id="getVideo(i).sbbm" :byList="byList" />
-          <div class="txt">{{ getVideo(i).sbmc }}</div>
+          <!-- <div class="txt">{{ getVideo(i).sbmc }}</div> -->
         </div>
         <div class="v-one" v-if="getVideo(i + 1)">
           <Camera :id="getVideo(i + 1).sbbm" :byList="byList" />
-          <div class="txt">{{ getVideo(i).sbmc }}</div>
+          <!-- <div class="txt">{{ getVideo(i + 1).sbmc }}</div> -->
         </div>
       </el-carousel-item>
     </el-carousel>

+ 1 - 0
app/src/views/Iot/index.vue

@@ -142,6 +142,7 @@ export default {
 
       this.caremaData = showCaremarData;
       this.caremaList = caremaData;
+      console.log(this.caremaData);
     },
   },
   created() {

+ 5 - 1
components/BasicModal/index.vue

@@ -20,6 +20,10 @@ export default {
       type: String,
       default: "1456px",
     },
+    appendToBody: {
+      type: Boolean,
+      default: false,
+    },
   },
   methods: {
     showModal() {
@@ -34,7 +38,7 @@ export default {
 
 <template>
   <el-dialog
-    :append-to-body="false"
+    :append-to-body="this.appendToBody"
     :modal-append-to-body="false"
     :visible.sync="visible"
     :top="top"