hzd 1 år sedan
förälder
incheckning
370bb17ba7
100 ändrade filer med 9024 tillägg och 11 borttagningar
  1. 13 0
      application/admin/controller/Camera.php
  2. 50 0
      application/admin/controller/Dahua.php
  3. 1719 0
      application/admin/view/camera/index.html
  4. 15 10
      application/admin/view/index/def.html
  5. 5 1
      application/common.php
  6. 2 0
      public/.htaccess
  7. 0 0
      public/camera/.htaccess
  8. 1787 0
      public/camera/box.html
  9. 523 0
      public/camera/component/holder.vue
  10. 124 0
      public/camera/component/search-input.vue
  11. 409 0
      public/camera/component/timer.vue
  12. 18 0
      public/camera/config.js
  13. 918 0
      public/camera/css/demo.css
  14. 1719 0
      public/camera/demo.html
  15. 1722 0
      public/camera/demo.php
  16. BIN
      public/camera/img/Thumbs.db
  17. BIN
      public/camera/img/favicon.ico
  18. BIN
      public/camera/img/ptz/center.png
  19. BIN
      public/camera/img/ptz/center_disable.png
  20. BIN
      public/camera/img/ptz/center_hover.png
  21. BIN
      public/camera/img/ptz/center_pressed.png
  22. BIN
      public/camera/img/ptz/control_bg.png
  23. BIN
      public/camera/img/ptz/control_bg_Down.png
  24. BIN
      public/camera/img/ptz/control_bg_Left.png
  25. BIN
      public/camera/img/ptz/control_bg_LeftDown.png
  26. BIN
      public/camera/img/ptz/control_bg_LeftUp.png
  27. BIN
      public/camera/img/ptz/control_bg_Right.png
  28. BIN
      public/camera/img/ptz/control_bg_RightDown.png
  29. BIN
      public/camera/img/ptz/control_bg_RightUp.png
  30. BIN
      public/camera/img/ptz/control_bg_Up.png
  31. BIN
      public/camera/img/ptz/down.png
  32. BIN
      public/camera/img/ptz/down_disabled.png
  33. BIN
      public/camera/img/ptz/down_hover.png
  34. BIN
      public/camera/img/ptz/down_pressed.png
  35. BIN
      public/camera/img/ptz/hide.png
  36. BIN
      public/camera/img/ptz/hide_sel.png
  37. BIN
      public/camera/img/ptz/left.png
  38. BIN
      public/camera/img/ptz/left_disabled.png
  39. BIN
      public/camera/img/ptz/left_hover.png
  40. BIN
      public/camera/img/ptz/left_pressed.png
  41. BIN
      public/camera/img/ptz/northEast.png
  42. BIN
      public/camera/img/ptz/northEast_disabled.png
  43. BIN
      public/camera/img/ptz/northEast_hover.png
  44. BIN
      public/camera/img/ptz/northEast_pressed.png
  45. BIN
      public/camera/img/ptz/northWest.png
  46. BIN
      public/camera/img/ptz/northWest_disabled.png
  47. BIN
      public/camera/img/ptz/northWest_hover.png
  48. BIN
      public/camera/img/ptz/northWest_pressed.png
  49. BIN
      public/camera/img/ptz/ptzEx2/ApertureDown_d.png
  50. BIN
      public/camera/img/ptz/ptzEx2/ApertureDown_h.png
  51. BIN
      public/camera/img/ptz/ptzEx2/ApertureDown_n.png
  52. BIN
      public/camera/img/ptz/ptzEx2/ApertureDown_p.png
  53. BIN
      public/camera/img/ptz/ptzEx2/ApertureUp_d.png
  54. BIN
      public/camera/img/ptz/ptzEx2/ApertureUp_h.png
  55. BIN
      public/camera/img/ptz/ptzEx2/ApertureUp_n.png
  56. BIN
      public/camera/img/ptz/ptzEx2/ApertureUp_p.png
  57. BIN
      public/camera/img/ptz/ptzEx2/Cruise-h.png
  58. BIN
      public/camera/img/ptz/ptzEx2/Cruise-n.png
  59. BIN
      public/camera/img/ptz/ptzEx2/FocusDown_d.png
  60. BIN
      public/camera/img/ptz/ptzEx2/FocusDown_h.png
  61. BIN
      public/camera/img/ptz/ptzEx2/FocusDown_n.png
  62. BIN
      public/camera/img/ptz/ptzEx2/FocusDown_p.png
  63. BIN
      public/camera/img/ptz/ptzEx2/FocusUp_d.png
  64. BIN
      public/camera/img/ptz/ptzEx2/FocusUp_h.png
  65. BIN
      public/camera/img/ptz/ptzEx2/FocusUp_n.png
  66. BIN
      public/camera/img/ptz/ptzEx2/FocusUp_p.png
  67. BIN
      public/camera/img/ptz/ptzEx2/Ok-h.png
  68. BIN
      public/camera/img/ptz/ptzEx2/Prepoint-h.png
  69. BIN
      public/camera/img/ptz/ptzEx2/add-h.png
  70. BIN
      public/camera/img/ptz/ptzEx2/add-n.png
  71. BIN
      public/camera/img/ptz/ptzEx2/cancel-h.png
  72. BIN
      public/camera/img/ptz/ptzEx2/cancel-n.png
  73. BIN
      public/camera/img/ptz/ptzEx2/delete-h.png
  74. BIN
      public/camera/img/ptz/ptzEx2/delete-n.png
  75. BIN
      public/camera/img/ptz/ptzEx2/locate-h.png
  76. BIN
      public/camera/img/ptz/ptzEx2/locate-n.png
  77. BIN
      public/camera/img/ptz/ptzEx2/modify-h.png
  78. BIN
      public/camera/img/ptz/ptzEx2/modify-n.png
  79. BIN
      public/camera/img/ptz/ptzEx2/ok-n.png
  80. BIN
      public/camera/img/ptz/ptzEx2/play-h.png
  81. BIN
      public/camera/img/ptz/ptzEx2/play-n.png
  82. BIN
      public/camera/img/ptz/ptzEx2/prepoint-n.png
  83. BIN
      public/camera/img/ptz/ptzEx2/scaleAdd_d.png
  84. BIN
      public/camera/img/ptz/ptzEx2/scaleAdd_h.png
  85. BIN
      public/camera/img/ptz/ptzEx2/scaleAdd_n.png
  86. BIN
      public/camera/img/ptz/ptzEx2/scaleAdd_p.png
  87. BIN
      public/camera/img/ptz/ptzEx2/scaleMinus_d.png
  88. BIN
      public/camera/img/ptz/ptzEx2/scaleMinus_h.png
  89. BIN
      public/camera/img/ptz/ptzEx2/scaleMinus_n.png
  90. BIN
      public/camera/img/ptz/ptzEx2/scaleMinus_p.png
  91. BIN
      public/camera/img/ptz/ptzEx2/search-h.png
  92. BIN
      public/camera/img/ptz/ptzEx2/search-n.png
  93. BIN
      public/camera/img/ptz/ptzEx2/stop-h.png
  94. BIN
      public/camera/img/ptz/ptzEx2/stop-n.png
  95. BIN
      public/camera/img/ptz/ptzEx2/取消-h.png
  96. BIN
      public/camera/img/ptz/ptzEx2/取消-n.png
  97. BIN
      public/camera/img/ptz/ptzEx2/巡迹-h.png
  98. BIN
      public/camera/img/ptz/ptzEx2/巡迹-n.png
  99. BIN
      public/camera/img/ptz/ptzEx2/扫描-右-h.png
  100. 0 0
      public/camera/img/ptz/ptzEx2/扫描-右.png

+ 13 - 0
application/admin/controller/Camera.php

@@ -0,0 +1,13 @@
+<?php
+namespace app\admin\controller;
+
+class Camera extends Auth
+{
+
+    public function index(){
+        return $this->fetch();
+    }
+
+
+
+}

+ 50 - 0
application/admin/controller/Dahua.php

@@ -0,0 +1,50 @@
+<?php
+namespace app\admin\controller;
+
+use GuzzleHttp\Client;
+use think\Controller;
+use think\Db;
+
+class Dahua extends Base
+{
+    public function index(){
+        $content = file_get_contents('http://127.0.0.1:4481/demo.php');
+        $this->assign('content',$content);
+        return $this->fetch();
+    }
+    public function token(){
+        $client_id = "re4e28ee63ef094215b80fb92eb938bdb9";
+        $client_secret = "9c6570bc78215b6c84e0a0639d50c91a";
+//        $client_id = "re4e28ee63ef094215b80fb92eb938bdb9";
+//        $client_secret = "9c6570bc78215b6c84e0a0639d50c91a";
+        $url = "https://www.cloud-dahua.com/gateway/auth/oauth/token?grant_type=client_credentials&scope=server&client_id={$client_id}&client_secret={$client_secret}";
+        $ret = curl_post($url,[]);
+        $ret = json_decode($ret,true);
+        return json($ret);
+    }
+
+
+    public function device(){
+        $authorization = request()->header()['authorization'];
+//        $authorization = "Bearer 2d99f770-81f3-4921-be31-2d766db87323";
+        $url = "https://www.cloud-dahua.com/gateway/device/api/page";
+        $data = [
+            'pageNum' => 1,
+            'pageSize' => 200
+        ];
+        $ret = curl_post($url,json_encode($data),['Content-Type: application/json','Authorization:'.$authorization]);
+//        halt($ret);
+        $ret = json_decode($ret,true);
+        return json($ret);
+    }
+
+    public function lechange(){
+        $authorization = request()->header()['authorization'];
+        $url = "https://www.cloud-dahua.com/gateway/device/api/lechangeToken";
+        $ret = curl_post($url,[],['Content-Type: application/json','Authorization:'.$authorization]);
+        $ret = json_decode($ret,true);
+        return json($ret);
+    }
+
+
+}

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1719 - 0
application/admin/view/camera/index.html


+ 15 - 10
application/admin/view/index/def.html

@@ -39,7 +39,7 @@
         <div class="gydef-often-module-header">常用模块 </div>
         <div class="gydef-often-module-body">
             <div class="gydef-often-module-body-info" v-for="(item,index) in cyList" :key="index">
-                <a href="javascript:;" @click="godef2Click(item.menu_id)">
+                <a href="javascript:;" @click="godef2Click(item.menu_id,item.url)">
                     <div class="gydef-menu-info-box">
                         <div class="menu-icon">
                             <img :src="item.img" alt="">
@@ -70,7 +70,7 @@
         </div>
         <div class="gydef-group-module-body">
             <div class="gydef-often-module-body-info" v-for="(item,index) in menuList" :key="index">
-                <a href="javascript:;" @click="godef2Click(item.id)">
+                <a href="javascript:;" @click="godef2Click(item.id,item.url)">
                     <div class="gydef-menu-info-box">
                         <div class="menu-icon">
                             <img :src="item.img" alt="">
@@ -198,14 +198,19 @@
                 }
             },
 
-            godef2Click(menuid){
-                let purl = "{:url('Index/umenu')}";
-                $.post(purl,{id:menuid},function () {
-                    // window.location.href = url;
-                });
-                //
-                let url = '{:url("index/def2")}?curmenu=500&menuId='+menuid;
-                window.location.href = url;
+            godef2Click(menuid,url){
+                if(Number(menuid) != 502){
+                    let purl = "{:url('Index/umenu')}";
+                    $.post(purl,{id:menuid},function () {
+                        // window.location.href = url;
+                    });
+                    //
+                    let url = '{:url("index/def2")}?curmenu=500&menuId='+menuid;
+                    window.location.href = url;
+                }else{
+                    window.open(url,"_blank");
+                }
+
             },
 
         }

+ 5 - 1
application/common.php

@@ -1029,8 +1029,12 @@ function diffBetweenTwoDays ($day1, $day2) {
 }
 
 
-function curl_post($url , $data=array()){
+function curl_post($url , $data=array(),$header=[]){
     $ch = curl_init();
+    if(!empty($header)){
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
+        curl_setopt($ch, CURLOPT_HEADER, 0);//返回response头部信息
+    }
     curl_setopt($ch, CURLOPT_URL, $url);
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

+ 2 - 0
public/.htaccess

@@ -6,4 +6,6 @@
   RewriteCond %{REQUEST_FILENAME} !-f
 #  RewriteRule ^(.*)$ index.html/$1 [QSA,PT,L]
   RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1]
+
+  SetEnvIf Authorization ^(.*) HTTP_AUTHORIZATION=$1
 </IfModule>

+ 0 - 0
public/camera/.htaccess


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1787 - 0
public/camera/box.html


+ 523 - 0
public/camera/component/holder.vue

@@ -0,0 +1,523 @@
+
+<template>
+  <el-container class="container">
+    <el-header class="header">
+      <el-row>
+        <el-col :span="20">云台操作</el-col>
+        <el-col :span="4">
+          <i v-show="fold" class="hide-icon pointer" @click="fold = !fold"></i>
+          <i v-show="!fold" class="show-icon pointer" @click="fold = !fold"></i>
+        </el-col>
+      </el-row>
+    </el-header>
+
+    <el-main class="main" v-show="!fold">
+      <!-- 云台圆盘 -->
+      <div class="holder-disc">
+        <div class="s1" :class="brand !== 'lechange' ? 'box' : 'disable-box'">
+          <!-- 左上 -->
+          <i v-show="brand !== 'lechange'" class="north-west-icon" @mousedown="holderClick(false, '4')" @mouseup="holderClick(true, '4')"></i>
+        </div>
+        <div class="s2 box">
+          <!-- 上 -->
+          <i class="north-west-icon" @mousedown="holderClick(false, '0')" @mouseup="holderClick(true, '0')"></i>
+        </div>
+        <div class="s3" :class="brand !== 'lechange' ? 'box' : 'disable-box'">
+          <!-- 右上 -->
+          <i v-show="brand !== 'lechange'" class="north-west-icon" @mousedown="holderClick(false, '6')" @mouseup="holderClick(true, '6')"></i>
+        </div>
+        <div class="s4 box">
+          <!-- 右 -->
+          <i class="north-west-icon" @mousedown="holderClick(false, '3')" @mouseup="holderClick(true, '3')"></i>
+        </div>
+        <div class="s5 box">
+          <!-- 左 -->
+          <i class="north-west-icon" @mousedown="holderClick(false, '2')" @mouseup="holderClick(true, '2')"></i>
+        </div>
+        <div class="s6" :class="brand !== 'lechange' ? 'box' : 'disable-box'">
+          <!-- 左下 -->
+          <i v-show="brand !== 'lechange'" class="north-west-icon" @mousedown="holderClick(false, '5')" @mouseup="holderClick(true, '5')"></i>
+        </div>
+        <div class="s7 box">
+          <!-- 下 -->
+          <i class="north-west-icon" @mousedown="holderClick(false, '1')" @mouseup="holderClick(true, '1')"></i>
+        </div>
+        <div class="s8" :class="brand !== 'lechange' ? 'box' : 'disable-box'">
+          <!-- 右下 -->
+          <i v-show="brand !== 'lechange'" class="north-west-icon" @mousedown="holderClick(false, '7')" @mouseup="holderClick(true, '7')"></i>
+        </div>
+        <div class="center center-icon"></div>
+      </div>
+      <!-- 云台步长 -->
+      <div class="holder-step-length">
+        <el-row>
+          <el-col :span="4" class="lh38 text-right">步长</el-col>
+          <el-col :span="12" :offset="2">
+            <el-slider
+              v-model="stepLength"
+              :min="1"
+              :max="8"
+              :show-tooltip="false"
+            ></el-slider>
+          </el-col>
+          <el-col :span="4" :offset="2" class="lh38">{{ stepLength }}</el-col>
+        </el-row>
+      </div>
+      <!-- 云台操作 -->
+      <div class="holder-operate">
+        <el-row class="operate-row">
+          <el-col :span="8" class="border-right-ccc">
+            <i
+              class="focus-up-icon"
+              title="聚焦+"
+              @mousedown="holderHandle('ptzFocusOperation', true, false)" 
+              @mouseup="holderHandle('ptzFocusOperation', true, true)"
+            ></i>
+            <i
+              class="focus-down-icon"
+              title="聚焦-"
+              @mousedown="holderHandle('ptzFocusOperation', false, false)" 
+              @mouseup="holderHandle('ptzFocusOperation', false, true)"
+            ></i>
+          </el-col>
+          <el-col :span="8" class="border-right-ccc">
+            <i
+              class="scale-add-icon"
+              title="变倍+"
+              @mousedown="holderHandle('ptzZoomOperation', true, false)" 
+              @mouseup="holderHandle('ptzZoomOperation', true, true)"
+            ></i>
+            <i
+              class="scale-minus-icon"
+              title="变倍-"
+              @mousedown="holderHandle('ptzZoomOperation', false, false)" 
+              @mouseup="holderHandle('ptzZoomOperation', false, true)"
+            ></i>
+          </el-col>
+          <el-col :span="8">
+            <i
+              class="aperture-up-icon"
+              title="光圈+"
+              @mousedown="holderHandle('ptzApertureOperation', true, false)" 
+              @mouseup="holderHandle('ptzApertureOperation', true, true)"
+            ></i>
+            <i
+              class="aperture-down-icon"
+              title="光圈-"
+              @mousedown="holderHandle('ptzApertureOperation', false, false)" 
+              @mouseup="holderHandle('ptzApertureOperation', false, true)"
+            ></i>
+          </el-col>
+        </el-row>
+      </div>
+    </el-main>
+  </el-container>
+</template>
+<script>
+module.exports = {
+  data() {
+    return {
+      data: [],
+      value: [1, 4],
+      cruiseForm: {
+        num: "",
+        name: "",
+      },
+      fold: true,
+      moreFold: true,
+      stepLength: 1,
+      searchKey: "",
+      prepointDialogVisible: false,
+      cruiseDialogVisible: false,
+      num: ""
+    };
+  },
+  watch: {
+      fold(val) {
+          this.$emit("switch-fold", val)
+      }
+  },
+  props: {
+    brand: {
+      type: String,
+      default: 'general'
+    }
+  },
+  methods: {
+    holderClick(bStop, direct) {
+      this.$emit("holder-click", {
+        direct: direct,
+        stepLength: this.stepLength,
+        bStop: bStop,
+      });
+    },
+
+    holderHandle(method, add, bStop) {
+      this.$emit("holder-handle", {
+        method: method,
+        bStop: bStop,
+        add: add,
+      });
+    },
+  },
+};
+</script>
+ 
+<style scoped>
+/deep/ .el-transfer-panel {
+  width: 260px;
+}
+/deep/ .cruise-dialog-div .el-transfer__button {
+  border-color: #ee371f;
+  background-color: #ee371f;
+}
+/deep/ .cruise-dialog-div .el-transfer__button.is-disabled {
+  background-color: #fab6b6;
+  border-color: #fab6b6;
+}
+/deep/ .cruise-dialog-div .el-form-item {
+  margin-bottom: 15px;
+}
+
+.empty-prepoint-list {
+  height: 200px;
+  padding-top: 80px;
+  text-align: center;
+  color: #888;
+}
+.prepoint-list-row {
+  padding: 5px 10px;
+  border-bottom: 1px solid #ddd;
+}
+.prepoint-title {
+  width: 60px;
+  line-height: 28px;
+}
+.h200 {
+  height: 200px;
+}
+.mgl70 {
+  margin-left: 70px;
+}
+.mgt5 {
+  margin-top: 5px;
+}
+.pt5 {
+  padding-top: 5px;
+}
+.mgr30 {
+  margin-right: 30px;
+}
+.mgr5 {
+  margin-right: 5px;
+}
+.mgr10 {
+  margin-right: 10px;
+}
+.pdt5 {
+  padding-top: 5px;
+}
+.pdb5 {
+  padding-bottom: 5px;
+}
+.header {
+  color: #000;
+  font-size: 20px;
+}
+.show-icon {
+  background: url("../img/ptz/show.png");
+  background-size: 100% 100%;
+  width: 16px;
+  height: 16px;
+  display: inline-block;
+}
+.hide-icon {
+  background: url("../img/ptz/hide.png");
+  background-size: 100% 100%;
+  width: 16px;
+  height: 16px;
+  display: inline-block;
+}
+.add-icon {
+  background: url("../img/ptz/ptzEx2/add-n.png");
+  background-size: 100% 100%;
+  width: 14px;
+  height: 14px;
+  display: inline-block;
+  vertical-align: middle;
+}
+.add-icon:hover {
+  background: url("../img/ptz/ptzEx2/add-h.png");
+}
+.center-icon {
+  background: url("../img/ptz/center.png") no-repeat top left;
+  width: 48px;
+  height: 48px;
+  display: inline-block;
+}
+
+.operate-row {
+  border-top: 1px solid #ccc;
+  border-bottom: 1px solid #ccc;
+  padding: 5px 0px;
+}
+.operate-row .el-col {
+  text-align: center;
+}
+.border-right-ccc {
+  border-right: 1px solid #ccc;
+}
+.focus-up-icon {
+  background: url("../img/ptz/ptzEx2/FocusUp_n.png");
+  background-size: 100% 100%;
+  width: 20px;
+  height: 20px;
+  display: inline-block;
+  margin-right: 4px;
+}
+.focus-up-icon:hover {
+  background: url("../img/ptz/ptzEx2/FocusUp_h.png");
+  background-size: 100% 100%;
+}
+.focus-down-icon {
+  background: url("../img/ptz/ptzEx2/FocusDown_n.png");
+  background-size: 100% 100%;
+  width: 20px;
+  height: 20px;
+  display: inline-block;
+}
+.focus-down-icon:hover {
+  background: url("../img/ptz/ptzEx2/FocusDown_h.png");
+  background-size: 100% 100%;
+}
+.scale-add-icon {
+  background: url("../img/ptz/ptzEx2/scaleAdd_n.png");
+  background-size: 100% 100%;
+  width: 20px;
+  height: 20px;
+  display: inline-block;
+  margin-right: 4px;
+}
+.scale-add-icon:hover {
+  background: url("../img/ptz/ptzEx2/scaleAdd_h.png");
+  background-size: 100% 100%;
+}
+.scale-minus-icon {
+  background: url("../img/ptz/ptzEx2/scaleMinus_n.png");
+  background-size: 100% 100%;
+  width: 20px;
+  height: 20px;
+  display: inline-block;
+}
+.scale-minus-icon:hover {
+  background: url("../img/ptz/ptzEx2/scaleMinus_h.png");
+  background-size: 100% 100%;
+}
+.aperture-up-icon {
+  background: url("../img/ptz/ptzEx2/ApertureUp_n.png");
+  background-size: 100% 100%;
+  width: 20px;
+  height: 20px;
+  display: inline-block;
+  margin-right: 4px;
+}
+.aperture-up-icon:hover {
+  background: url("../img/ptz/ptzEx2/ApertureUp_h.png");
+  background-size: 100% 100%;
+}
+.aperture-down-icon {
+  background: url("../img/ptz/ptzEx2/ApertureDown_n.png");
+  background-size: 100% 100%;
+  width: 20px;
+  height: 20px;
+  display: inline-block;
+}
+.aperture-down-icon:hover {
+  background: url("../img/ptz/ptzEx2/ApertureDown_h.png");
+  background-size: 100% 100%;
+}
+.p5-10 {
+  padding: 5px 10px;
+}
+.holder-more-row {
+  border-bottom: 1px solid #ccc;
+}
+.prepoint-h-icon {
+  background: url("../img/ptz/ptzEx2/Prepoint-h.png");
+  background-size: 100% 100%;
+  width: 16px;
+  height: 16px;
+  display: inline-block;
+}
+.prepoint-n-icon {
+  background: url("../img/ptz/ptzEx2/prepoint-n.png");
+  background-size: 100% 100%;
+  width: 16px;
+  height: 16px;
+  display: inline-block;
+}
+.prepoint-n-icon:hover {
+  background: url("../img/ptz/ptzEx2/Prepoint-h.png");
+  background-size: 100% 100%;
+}
+.modify-n-icon {
+  background: url("../img/ptz/ptzEx2/modify-n.png");
+  background-size: 100% 100%;
+  width: 14px;
+  height: 14px;
+  display: inline-block;
+  margin-right: 3px;
+}
+.modify-n-icon:hover {
+  background: url("../img/ptz/ptzEx2/modify-h.png");
+  background-size: 100% 100%;
+}
+.delete-n-icon {
+  background: url("../img/ptz/ptzEx2/delete-n.png");
+  background-size: 100% 100%;
+  width: 14px;
+  height: 14px;
+  display: inline-block;
+  margin-right: 3px;
+}
+.delete-n-icon:hover {
+  background: url("../img/ptz/ptzEx2/delete-h.png");
+  background-size: 100% 100%;
+}
+.play-n-icon {
+  background: url("../img/ptz/ptzEx2/play-n.png");
+  background-size: 100% 100%;
+  width: 14px;
+  height: 14px;
+  display: inline-block;
+  margin-right: 3px;
+}
+.play-n-icon:hover {
+  background: url("../img/ptz/ptzEx2/play-h.png");
+  background-size: 100% 100%;
+}
+.cruise-h-icon {
+  background: url("../img/ptz/ptzEx2/Cruise-h.png");
+  background-size: 100% 100%;
+  width: 16px;
+  height: 16px;
+  display: inline-block;
+}
+.cruise-n-icon {
+  background: url("../img/ptz/ptzEx2/Cruise-n.png");
+  background-size: 100% 100%;
+  width: 16px;
+  height: 16px;
+  display: inline-block;
+}
+.cruise-n-icon:hover {
+  background: url("../img/ptz/ptzEx2/Cruise-h.png");
+  background-size: 100% 100%;
+}
+
+.el-icon-caret-top {
+  position: relative;
+  top: 32px;
+  left: 8px;
+  transform: rotate(-64deg);
+  font-size: x-large;
+}
+
+.container {
+  position: absolute;
+  bottom: 0px;
+  background: #fff;
+  width: 100%;
+  height: auto;
+}
+.el-header {
+  background: #ddd;
+}
+.holder-disc {
+  width: 132px;
+  height: 132px;
+  border-radius: 50%;
+  margin-left: 37px;
+  margin-top: 10px;
+}
+
+.holder-disc .box, .holder-disc .disable-box {
+  position: absolute;
+  width: 130px;
+  height: 130px;
+  border-radius: 50%;
+  clip: rect(0px, 65px, 65px, 0);
+  clip-path: polygon(0px 0px, 65px 65px, 0px 65px);
+}
+
+.holder-disc .box {
+  transition: 0.5s;
+  background: #e6e6e6;
+  cursor: pointer;
+}
+
+.holder-disc .disable-box {
+  background: #e6e6e6;
+}
+
+.holder-disc .box:hover {
+  background: #ccc;
+}
+
+.north-west-icon {
+  background: url("../img/ptz/northWest.png") no-repeat top left;
+  width: 13px;
+  height: 13px;
+  display: inline-block;
+  position: relative;
+  top: 40px;
+  left: 16px;
+  transform: rotate(-23deg);
+}
+
+.north-west-icon:hover {
+  background: url("../img/ptz/northWest_hover.png");
+}
+
+.holder-disc .s1 {
+  transform: rotate(22.5deg);
+}
+
+.holder-disc .s2 {
+  transform: rotate(67.5deg);
+}
+
+.holder-disc .s3 {
+  transform: rotate(112.5deg);
+}
+
+.holder-disc .s4 {
+  transform: rotate(157.5deg);
+}
+
+.holder-disc .s5 {
+  transform: rotate(-22.5deg);
+}
+
+.holder-disc .s6 {
+  transform: rotate(-67.5deg);
+}
+
+.holder-disc .s7 {
+  transform: rotate(-112.5deg);
+}
+
+.holder-disc .s8 {
+  transform: rotate(-157.5deg);
+}
+
+.holder-disc .center {
+  position: absolute;
+  left: 78px;
+  top: 112px;
+  border-radius: 50%;
+}
+.lh38 {
+  line-height: 38px;
+}
+</style>

+ 124 - 0
public/camera/component/search-input.vue

@@ -0,0 +1,124 @@
+<!--输入搜索框用此组件,限制了中英文输入长度-->
+<template>
+    <div class="input-box">
+        <!--普通输入框-->
+        <el-input v-model="value" @input="searchInput($event)" :placeholder="placeholdertip" :maxlength="maxLen" :ref="inputName" v-if="mode == 'input'"></el-input>
+        <!--搜索框,支持自动搜索-->
+        <el-input v-if="mode == 'search' && openAutoSearch" :maxlength="maxLen" @compositionend.native="handlecompositionend" @compositionstart.native="handlecompositionstart" size="mini" class="console-tree-search" :placeholder="placeholdertip" suffix-icon="tree-search-icon" @click.native="handleClickOnTableSearchInput" @keyup.native="handleTreeEnter" v-model="value" @input="searchInput($event)" :ref="inputName">
+            <i slot="suffix" v-if="value" @click="handleTreeEnter(value = '')" class="el-input__icon el-icon-circle-close el-input__clear" style="margin-right: 14px;"></i>
+        </el-input>
+        <!--搜索框,支持回车搜索-->
+        <el-input v-if="mode == 'search' && !openAutoSearch" :maxlength="maxLen" size="mini" class="console-tree-search" :placeholder="placeholdertip" suffix-icon="tree-search-icon" @click.native="handleClickOnTableSearchInput" @keyup.enter.native="handleTreeEnter" v-model="value" @input="searchInput($event)" :ref="inputName">
+            <i slot="suffix" v-if="value" @click="handleTreeEnter(value = '')" class="el-input__icon el-icon-circle-close el-input__clear" style="margin-right: 14px;"></i>
+        </el-input>
+    </div>
+</template>
+
+<script>
+    module.exports = {
+        data() {
+            return {
+                compositioning: false,
+                searchTimer: null,
+                keyStatus: null,
+                value: ''
+            }
+        },
+        
+        props: {
+            //输入框提示信息
+            placeholdertip: {
+                type: String,
+            },
+            //输入框模式 input 仅输入功能  search 输入并带搜索功能
+            mode: {
+                default: 'input',
+                type: String
+            },
+            maxLen: {
+                type: Number,
+                default: 120
+            },
+            inputName: {
+                type: String,
+                default: 'searchInput'
+            },
+            //是否开启自动搜索
+            openAutoSearch: {
+                type: Boolean,
+                default: false
+            }
+        },
+        
+        methods: {
+            /**
+            * @method searchInput 输入后把新的搜索值传给父组件,input模式输入后通知父组件
+            */
+            searchInput (value) {
+                if (value.length > this.maxLen) value = value.slice(0, this.maxLen)
+                value = value.trim()
+                this.$emit('input', value)
+            },
+            /**
+             * @method handlecompositionend() 中文输入法
+            */
+            handlecompositionstart() {
+                this.compositioning = true
+            },
+            /**
+             * @method handlecompositionend() 中文输入法输入结束
+            */
+            handlecompositionend() {
+                this.compositioning = false
+            },
+            keydownEvent(e) {
+                //当输入中文按下回车松开时,不会触发keyup事件
+                if (e.code == 'Enter' || e.code == 'NumpadEnter') {
+                    this.keyStatus = 'keyup'
+                } else {
+                    this.keyStatus = 'keydown'
+                }
+            },
+            keyupEvent() {
+                this.keyStatus = 'keyup'
+            },
+            /**
+            * @method handleClickOnTableSearchInput table搜索框点击事件
+            */
+            handleClickOnTableSearchInput(e) {
+                // 如果是点击在搜索图标上,就去查询
+                if (e && e.target && e.target.className && e.target.className.includes('el-input__icon')) this.handleTreeEnter()
+            },
+            /**
+             * @method handleTreeEnter 搜索方法,search模式输入后通知父组件
+            */
+            handleTreeEnter() {
+                //输入防抖
+                clearTimeout(this.searchTimer)
+                //如果还在中文输入
+                if(this.compositioning) return
+                this.searchTimer = setTimeout(() => {
+                    //如果键盘还是按下状态,持续输入
+                    if(this.keyStatus == 'keydown') return
+                    if (this.value.length > this.maxLen) this.value = this.value.slice(0, this.maxLen)
+                    this.value = this.value.trim()
+                    //把搜索值传到父组件
+                    this.$emit('search', this.value)
+                }, 600)
+            }
+        }
+    }
+</script>
+
+<style scoped>
+    .input-box {
+        width: 100%;
+        display: inline-block;
+    }
+    /deep/ i.tree-search-icon {
+        top: 6px;
+    }
+    /deep/ .el-input--suffix .el-input__inner {
+        padding-right: 40px;
+    }
+</style>

+ 409 - 0
public/camera/component/timer.vue

@@ -0,0 +1,409 @@
+
+<template>
+  <div :ref="'timeline-' + guid" class="timeline" ondragstart="return false;" onselectstart="return false;">
+    <p class="timeline-line"></p>
+    <div
+      ref="timeline-main"
+      class="timeline-main"
+      :key="'timeline-main-' + guid"
+      :id="'timeline-main-' + guid"
+    >
+      <!-- 时间段 -->
+      <span
+        v-for="item in timeArr"
+        :key="item + guid"
+        :class="'timeline-text-' + guid"
+        :style="{ paddingRight: paddingRight + 'px' }"
+        >{{ item }}</span>
+      <!-- 录像片段的背景,层级-1 -->
+      <div class="record-bg-div">
+        <span class="record-bg-span" v-for="(record, index) in recordRange" :key="index + guid" :style="{ left: record.left + 'px', width: record.width + 'px' }"></span>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+module.exports = {
+  data() {
+    return {
+      // 时间段数组,不同时间间隔,时间段的数量和值都是不同的
+      timeArr: [],
+      // 时间间隔范围对应的下标
+      intervalNum: 6,
+      // 时间间隔范围对应的秒数,从1分钟到2小时
+      intervalArr: [60, 300, 600, 900, 1800, 3600, 7200],
+      paddingRight: 50,
+      timer: null,
+      // 时间轴所选时间,默认显示12点的位置
+      selectTime: "12:00:00",
+      guid: "",
+      parentWidth: 0,
+      resizeFn: null,
+      // 录像片段的区间信息,包括开始时间结束时间,左边距和宽度
+      recordRange: [],
+      // 上次背景设置日期
+      lastBgSetDate: ''
+    };
+  },
+  props: {
+    // 录像片段
+    recordInfos: {
+      type: Array,
+      default() {
+        return []
+      }
+    }
+  },
+  watch: {
+    // 所选时间变化,触发父页面时间点变化方法
+    selectTime: {
+      handler(val) {
+        if (val) {
+          this.$emit("timer-change", val);
+        }
+      },
+    },
+    // 录像片段变化时,重新设置背景
+    recordInfos: {
+      deep: true,
+      handler(val) {
+        if (val && val.length > 0) {
+          // windowTime格式:2021-07-02 12:10:30
+          this.lastBgSetDate = val[0].windowTime.split(" ")[0]
+          this.setBackground(val)
+        } else {
+          this.recordRange = []
+        }
+      }
+    }
+  },
+  computed: {
+    // 最小右间距
+    minRight() {
+      return Math.ceil(this.parentWidth * 0.03);
+    },
+    // 最大右间距
+    maxRight() {
+      return Math.ceil(this.parentWidth * 0.09);
+    },
+  },
+  methods: {
+    // 时间秒数格式化
+    secToTime(s) {
+      s = Math.floor(s)
+      var t;
+      if (s > -1) {
+        var hour = Math.floor(s / 3600);
+        var min = Math.floor(s / 60) % 60;
+        var sec = s % 60;
+        if (hour < 10) {
+          t = "0" + hour + ":";
+        } else {
+          t = hour + ":";
+        }
+
+        if (min < 10) {
+          t += "0";
+        }
+        t += min + ":";
+        if (sec < 10) {
+          t += "0";
+        }
+        t += sec;
+      }
+
+      return t === '24:00:00' ? '23:59:59' : t;
+    },
+    // 时间转成秒数
+    timeToSec(time) {
+      let arr = time.split(":")
+      let hour = parseInt(arr[0])
+      let min = parseInt(arr[1])
+      let sec = parseInt(arr[2])
+      return hour * 3600 + min * 60 + sec;
+    },
+    // 定位时间,父页面使用
+    positionTime(time) {
+      let second = this.timeToSec(time);
+      let left = second / (24 * 3600 + this.intervalArr[this.intervalNum]) * this.$refs["timeline-main"].offsetWidth;
+      let boxLeft = this.parentWidth / 2 - Math.ceil(left)
+      let mainBox = $("#timeline-main-" + this.guid)[0];
+      mainBox.style.left = boxLeft + "px";
+    },
+    // 设置录像背景
+    setBackground(records) {
+      this.recordRange = []
+      if (records && records.length > 0) {
+        let dayStart = this.lastBgSetDate + " 00:00:00"
+        let dayEnd = this.lastBgSetDate + " 23:59:59"
+        records.forEach(item => {
+          if (item.strBeginTime <= dayEnd) {
+            item.strBeginTime = item.strBeginTime >= dayStart ? item.strBeginTime : dayStart
+            item.strEndTime = item.strEndTime <= dayEnd ? item.strEndTime : dayEnd
+            let location = this.getLocationByTimeRange(item.strBeginTime, item.strEndTime)
+            this.recordRange.push(location)
+          }
+        })
+      }
+    },
+    // 更新录像背景
+    updateBackground() {
+      if (this.recordRange && this.recordRange.length > 0) {
+        let records = JSON.parse(JSON.stringify(this.recordRange))
+        this.recordRange = []
+        for (let index = 0; index < records.length; index++) {
+          let element = this.getLocationByTimeRange(records[index].strBeginTime, records[index].strEndTime)
+          this.recordRange.push(element)
+        }
+      }
+    },
+
+    // 通过时间段获取位置
+    getLocationByTimeRange(beginTime, endTime) {
+      let result = {strBeginTime: beginTime, strEndTime: endTime}
+      let startSecond = this.timeToSec(beginTime.split(" ")[1]);
+      let left = startSecond / (24 * 3600 + this.intervalArr[this.intervalNum]) * this.$refs["timeline-main"].offsetWidth;
+      result.left = left.toFixed(1)
+
+      let endSecond = this.timeToSec(endTime.split(" ")[1]);
+      let width = (endSecond - startSecond) / (24 * 3600 + this.intervalArr[this.intervalNum]) * this.$refs["timeline-main"].offsetWidth;
+      result.width = width.toFixed(1)
+      return result
+    },
+    // 刷新时间点
+    refresh() {
+      var d = new Date();
+      // 初始化时间定为当前的时分
+      let now = 0;
+      this.timeArr = [];
+      //最大时间点24点对应的秒数,也就是86400s
+      let max = 86400;
+      while (now < max) {
+        this.timeArr.push(this.secToTime(now));
+        now += this.intervalArr[this.intervalNum];
+      }
+      this.timeArr.push("23:59:59");
+      let offsetLeft = this.$refs["timeline-main"].offsetLeft;
+      this.$nextTick(() => {
+        let allTimelines = document.querySelectorAll(
+          ".timeline-text-" + this.guid
+        );
+        let offsetWidth = allTimelines[0].offsetWidth;
+        let num = Math.floor((this.parentWidth / 2 - offsetLeft) / offsetWidth)
+        let intervalWidth = this.parentWidth / 2 - offsetLeft - (offsetWidth * num)
+        let nowSecond = this.intervalArr[this.intervalNum] * (num + intervalWidth / offsetWidth) 
+        this.selectTime = this.secToTime(nowSecond)
+
+        // 更新录像背景
+        this.updateBackground()
+      });
+    },
+    // 放大
+    turnUp() {
+      if (this.intervalNum <= 0) {
+        return;
+      }
+      if (this.paddingRight >= this.maxRight) {
+        this.paddingRight = this.minRight;
+        this.intervalNum -= 1;
+      } else {
+        this.paddingRight += 3;
+      }
+
+      // 刷新时间轴
+      this.refresh();
+    },
+    // 缩小
+    turnDown() {
+      if (this.intervalNum >= this.intervalArr.length - 1) {
+        return;
+      }
+      if (this.paddingRight <= this.minRight) {
+        this.paddingRight = this.maxRight;
+        this.intervalNum += 1;
+      } else {
+        this.paddingRight -= 3;
+      }
+
+      // 刷新时间轴
+      this.refresh();
+    },
+
+    // 节流函数
+    throttle(fn, delay) {
+      let timer = null;
+      return function () {
+        if (timer) {
+          return;
+        }
+        timer = setTimeout(() => {
+          fn.apply(this, arguments);
+          timer = null;
+        }, delay);
+      };
+    },
+
+    // 防抖函数
+    debounce(fn, time, timer) {
+      var timer = timer || null;
+      return function () {
+        let args = arguments;
+        clearTimeout(timer);
+        timer = setTimeout(() => {
+          fn.call(this, args);
+        }, time);
+      };
+    },
+  },
+  mounted() {
+    this.parentWidth = this.$refs["timeline-" + this.guid].offsetWidth;
+    this.paddingRight = this.maxRight
+
+    var box = $("#timeline-main-" + this.guid);
+
+    // 初始化默认是12点
+    this.$nextTick(() => {
+      this.positionTime("12:00:00")
+    });
+
+    // 刷新时间轴
+    this.refresh();
+
+    // 时间点右边距增加减少事件
+    const upEvent = this.throttle(this.turnUp, 10);
+    const downEvent = this.throttle(this.turnDown, 10);
+
+    const that = this;
+    // 鼠标滑轮事件
+    var scrollFunc = function (e) {
+      e = e || window.event;
+      // 阻止冒泡和默认行为
+      e.stopPropagation();
+      e.preventDefault(); 
+      if (e.wheelDelta) {
+        //判断浏览器IE,谷歌滑轮事件
+        if (e.wheelDelta > 0) {
+          //当滑轮向上滚动时
+          upEvent();
+        }
+        if (e.wheelDelta < 0) {
+          //当滑轮向下滚动时
+          downEvent();
+        }
+      } else if (e.detail) {
+        //Firefox滑轮事件
+        if (e.detail > 0) {
+          //当滑轮向上滚动时
+          upEvent();
+        }
+        if (e.detail < 0) {
+          //当滑轮向下滚动时
+          downEvent();
+        }
+      }
+      return false;
+    };
+    //给页面绑定滑轮滚动事件
+    if (document.addEventListener) {
+      this.$refs["timeline-main"].addEventListener("DOMMouseScroll", scrollFunc, false);
+    }
+    //滚动滑轮触发scrollFunc方法
+    document.querySelector("#timeline-main-" + this.guid).onmousewheel = scrollFunc;
+
+    
+    var body = $("body");
+    var index = 0;
+    var x1;
+    // 按下鼠标左键
+    box.mousedown(function () {
+      index = 1; //鼠标按下才能触发onmousemove方法
+      var x = event.clientX; //鼠标点击的坐标值,x
+      var left = this.style.left;
+      left = left.substr(0, left.length - 2); //去掉px
+      x1 = parseInt(x - left);
+    });
+    // 鼠标指针在时间轴中移动
+    box.mousemove(function () {
+      if (index === 1) {
+        let allTimelines = document.querySelectorAll(".timeline-text-" + that.guid);
+        let offsetWidth = allTimelines[0].offsetWidth;
+
+        let left = event.clientX - x1;
+        if (left > that.parentWidth / 2) {
+          return;
+        }
+        if (left < 0 && -left + that.parentWidth / 2 > offsetWidth * (allTimelines.length - 1)) {
+          return;
+        }
+        this.style.left = left + "px";
+
+        let num = Math.floor((that.parentWidth / 2 - left) / offsetWidth)
+        let intervalWidth = that.parentWidth / 2 - left - (offsetWidth * num)
+        let nowSecond = that.intervalArr[that.intervalNum] * (num + intervalWidth / offsetWidth) 
+        that.selectTime = that.secToTime(nowSecond)
+      }
+    });
+    // 松开鼠标左键
+    box.mouseup(function () {
+      index = 0;
+    });
+    body.mouseup(function () {
+      index = 0;
+    });
+
+    window.addEventListener("resize", (this.resizeFn = this.debounce(() => {
+        this.parentWidth = this.$refs["timeline-" + this.guid].offsetWidth;
+      }, 50))
+    );
+  },
+  created() {
+    this.guid = Math.ceil((1 + Math.random()) * 100000000);
+  },
+  deactivated() {
+    window.removeEventListener("resize", this.resizeFn);
+  },
+};
+</script>
+ 
+<style>
+.record-bg-span {
+    z-index: -1;
+    background: #EEBBB8;
+    position: absolute;
+    height: 100%;
+}
+.record-bg-div {
+  width: 100%;
+  position: absolute;
+  height: 100%;
+  top: 0;
+}
+.timeline {
+  height: 26px;
+  overflow-x: hidden;
+  background: #eee;
+  position: relative;
+  width: calc(100% - 120px);
+  margin-left: 120px;
+}
+
+.timeline-line {
+  position: absolute;
+    border-right: 1px solid red;
+    left: 50%;
+    height: 26px;
+    margin: 0;
+    z-index: 1;
+}
+
+.timeline-main {
+  -moz-user-select: none;
+  -khtml-user-select: none;
+  user-select: none;
+  position: absolute;
+  left: 0;
+  top: 4px;
+  cursor: pointer;
+  opacity: 0.9;
+}
+</style>

+ 18 - 0
public/camera/config.js

@@ -0,0 +1,18 @@
+// 开放平台环境地址,无需修改
+// const base_url = 'https://www.cloud-dahua.com'
+const base_url = 'http://gyjk.jya-tech.com'
+// const base_url = 'http://gt60.demo.com'
+// 连接websocket默认端口,无需修改
+const websocket_port = '7500'
+
+// 客户端id,获取access_token需要,https://www.cloud-dahua.com/wiki/ 可以查看具体取值方法
+const client_id = 're4e28ee63ef094215b80fb92eb938bdb9'
+// 访问秘钥,获取access_token需要,https://www.cloud-dahua.com/wiki/ 可以查看具体取值方法
+const client_secret = '9c6570bc78215b6c84e0a0639d50c91a'
+
+export default {
+    base_url,
+    client_id,
+    client_secret,
+    websocket_port
+}

+ 918 - 0
public/camera/css/demo.css

@@ -0,0 +1,918 @@
+html, body {
+    height: 100%;
+    width: 100%;
+    margin: 0;
+    padding: 0;
+    font-size: 13px;
+    font-family: "Microsoft YaHei","PingFang SC","Hiragino Sans GB";
+    color: #2e2c2c;
+    background-color: #fff;
+}
+
+#app {
+    height: 100%;
+    width: 100%;
+}
+
+.el-container {
+    height: 100%;
+    display: flex;
+    flex-direction: row;
+    flex: 1;
+    flex-basis: auto;
+    box-sizing: border-box;
+    min-width: 0;
+}
+
+.el-header {
+    background: transparent;
+    color: #fff;
+    text-align: center;
+    line-height: 60px;
+    position: relative;
+    z-index: 10;
+}
+
+html .el-main, body .el-main {
+    padding: 0;
+}
+
+.relative {
+    position: relative;
+}
+
+.text-right {
+    text-align: right;
+}
+
+.float-l {
+    float: left;
+}
+
+ul {
+    list-style: none;
+    margin: 0;
+    padding: 0;
+}
+
+.inline-block {
+    display: inline-block;
+}
+
+.el-dialog__body {
+    padding: 20px;
+}
+
+.w30 {
+    width: 30px;
+}
+
+.w34 {
+    width: 34px;
+    box-sizing: border-box;
+    text-align: center;
+    cursor: pointer;
+}
+
+.w140 {
+    width: 140px;
+}
+
+.w-precent-100 {
+    width: 100%;
+}
+
+.w-precent-3 {
+    width: 3%;
+}
+
+.h40 {
+    height: 40px;
+}
+
+.mg-t-15 {
+    margin-top: 15px;
+}
+
+.mg-0 {
+    margin: 0px;
+}
+
+.el-icon-arrow-left, .el-icon-arrow-right {
+    width: 25px;
+    font-weight: bold;
+    cursor: pointer;
+    text-align: center;
+    font-size: 15px;
+    cursor: pointer;
+}
+
+.select-date {
+    height: 25px;
+    width:138px !important;
+}
+
+.date-panel {
+    width: calc(100% - 240px);
+}
+
+.input-box-client {
+    width: 90%;
+    margin: 5px auto;
+}
+
+.el-input input {
+    border-radius: 0;
+    border: 1px solid #d1d2d3;
+    color: #2e2c2c;
+    font-family: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB";
+}
+
+i.tree-search-icon {
+    position: absolute;
+    cursor: pointer;
+    top: 7px;
+    right: 1px;
+    width: 16px;
+    height: 16px;
+    display: inline-block;
+    background: url('../img/search-N.png') no-repeat;
+    
+}
+i.tree-search-icon:hover {
+    background: url('../img/search-H.png') no-repeat;
+}
+i.tree-search-icon {
+    transition: unset;
+}
+
+.record-normal {
+    background: url("../img/ptz/tool/record-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+
+}
+
+.record-normal:hover {
+    background: url("../img/ptz/tool/record-hover.png");
+}
+
+.recording-normal {
+    background: url("../img/ptz/tool/recording-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.recording-normal:hover {
+    background: url("../img/ptz/tool/recording-hover.png");
+}
+
+.audio-normal {
+    background: url("../img/ptz/tool/audio-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.audio-normal:hover {
+    background: url("../img/ptz/tool/audio-hover.png");
+}
+
+.audio-no-normal {
+    background: url("../img/ptz/tool/audio-no-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.audio-no-normal:hover {
+    background: url("../img/ptz/tool/audio-no-hover.png");
+}
+
+.snap1-icon {
+    background: url("../img/ptz/tool/snap1.png");
+    background-size: 100% 100%;
+    width: 16px;
+    height: 17px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.snap1-icon:hover {
+    background: url("../img/ptz/tool/snap1-h.png");
+}
+
+.talk-normal {
+    background: url("../img/ptz/tool/talk-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.talk-normal:hover {
+    background: url("../img/ptz/tool/talk-hover.png");
+}
+
+.talking-normal {
+    background: url("../img/ptz/tool/talking-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.talking-normal:hover {
+    background: url("../img/ptz/tool/talking-hover.png");
+}
+
+.slow-normal {
+    background: url("../img/ptz/tool/slow-n.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.slow-normal:hover {
+    background: url("../img/ptz/tool/slow-h.png");
+}
+
+.speed-normal {
+    background: url("../img/ptz/tool/speed-n.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.speed-normal:hover {
+    background: url("../img/ptz/tool/speed-h.png");
+}
+
+.play-normal {
+    background: url("../img/ptz/tool/play.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.play-normal:hover {
+    background: url("../img/ptz/tool/play-hover.png");
+}
+
+.pause-normal {
+    background: url("../img/ptz/tool/pause.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.pause-normal:hover {
+    background: url("../img/ptz/tool/pause-hover.png");
+}
+
+.stop-normal {
+    background: url("../img/ptz/tool/stop.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.stop-normal:hover {
+    background: url("../img/ptz/tool/stop-hover.png");
+}
+
+.closeall-normal-icon {
+    background: url("../img/ptz/tool/closeall-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    margin-right: 15px;
+    transform: translate(0, 50%);
+
+}
+
+.closeall-normal-icon:hover {
+    background: url("../img/ptz/tool/closeall-hover.png");
+}
+
+.p4-normal-icon {
+    background: url("../img/ptz/tool/4-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+    position: absolute;
+    right: 305px;
+
+}
+
+.p4-normal-icon:hover {
+    background: url("../img/ptz/tool/4-hover.png");
+}
+
+.download-normal-icon {
+    background: url("../img/ptz/tool/download-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+}
+
+.download-normal-icon:hover {
+    background: url("../img/ptz/tool/download-hover.png");
+}
+
+.screen-normal-icon {
+    background: url("../img/ptz/tool/screen-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+
+}
+
+.screen-normal-icon:hover {
+    background: url("../img/ptz/tool/screen-hover.png");
+}
+
+.p16-normal-icon {
+    background: url("../img/ptz/tool/16-normal.png");
+    background-size: 100% 100%;
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    margin-left: 15px;
+    transform: translate(0, 50%);
+
+}
+
+.p16-normal-icon:hover {
+    background: url("../img/ptz/tool/16-hover.png");
+}
+
+.el-slider-step {
+    width:100px;
+    display:inline-block;
+    position:absolute;
+    right:185px;
+}
+
+.timeline-div {
+    height: 25px;
+    line-height: 25px;
+    margin: 0;
+    width: 100%;
+    background: #fff;
+    border-top: 1px solid #ddd;
+    font-size: 13px;
+}
+.timeline-div p, .timeline-main {
+    margin: 0;
+}
+.time-point {
+    cursor: pointer;
+    border-radius: 50%;    
+    display: inline-block;
+    width: 20px;
+    height: 20px;
+    text-align: center;
+    line-height: 20px;
+}
+.time-point-active {
+    background: red;
+    color: #fff;
+}
+.timeline-no {
+    position: absolute;
+    left: 11px;
+}
+.timeline-no-p {
+    margin: 0;
+    height: 26px;
+    line-height: 26px;
+    color: #999;
+}
+.font-red {
+    color: red;
+}
+.timeline-no-span {
+    display: inline-block;
+    width: 17px;
+    overflow: hidden;
+}
+.timeline-title {
+    width: 85px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    display: inline-block;
+}
+
+.select-date .el-input__icon {
+    line-height: 25px;
+}
+.select-date .el-input__inner {
+    height: 25px;
+    line-height: 25px;
+    border: none;
+}
+.el-time-panel {
+    left: -30px;
+}
+.record-date-form .el-form-item {
+    margin-bottom: 15px;
+}
+
+.tool-span {
+    padding: 3px 5px;
+    border-radius: 2px;
+    background: #6D6F72;
+    color: #fff;
+    margin-left: 15px;
+    font-size: 10px;
+    display: inline-block;
+    position: relative;
+    top: 5px;
+}
+
+.tool-span:hover {
+    background: #F23838;
+}
+
+.tooltip-style {
+    overflow: visible;
+    width: 208px;
+}
+
+.tooltip-style .title {
+    font-weight: bold;
+    margin-bottom: 10px;
+    line-height: 20px;
+}
+
+.tooltip-style .content {
+    line-height: 20px;
+}
+
+.shop-video {
+    color: #2e2c2c;
+}
+
+.shop-video .el-footer {
+    background-color: #ebeced;
+    bottom: 0;
+    border-top: 1px solid #ddd;
+    padding: 0;
+    overflow-y: auto;
+}
+
+.shop-video .el-container {
+    border: 1px solid #ddd;
+    border-top: 0;
+}
+
+.el-aside {
+    background-color: #fff;
+    position: relative;
+    overflow: hidden;
+}
+.el-aside .ztree {
+    position: absolute;
+    width: 100%;
+    top: 43px;
+    bottom: 0;
+}
+
+.shop-tree-box {
+    position: absolute;
+    overflow: hidden;
+    width: 100%;
+    top: 36px;
+    bottom: 0;
+
+    
+}
+.shop-tree-box .el-button--default {
+    background-color: transparent;
+    border-color: transparent;
+}
+
+.holder-fold {
+    bottom: 60px;
+}
+.holder-unfold {
+    bottom: 275px;
+}
+
+.shop-info-photo {
+    width: 200px;
+    height: 100px;
+    margin-top: 15px;
+    margin-right: 25px;
+    float: left;
+    background: #ddd;
+}
+
+.shop-info-ul {
+    overflow: hidden;
+    margin-top: 15px;
+    font-size: 12px;
+}
+.shop-info-li {
+    float: left;
+    width: calc((100% - 80px) / 2);
+    margin-bottom: 20px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    padding-left: 20px;
+}
+
+.li-name {
+    color: #77797c;
+}
+
+.search {
+    width: 180px;
+    margin-top: 15px;
+    margin-left: 10px;
+}
+
+.el-input-group__append {
+    padding: 0 14px;
+}
+
+.focus,
+.no-focus {
+    position: absolute;
+    top: 15px;
+    right: 18px;
+    cursor: pointer;
+}
+
+.focus-icon {
+    display: inline-block;
+    width: 20px;
+    height: 18px;
+    line-height: 20px;
+    vertical-align: bottom;
+    background: url(../img/clientIcon.png) no-repeat;
+    background-position: -1px -82px;
+}
+
+.no-focus-icon {
+    display: inline-block;
+    width: 20px;
+    height: 18px;
+    line-height: 20px;
+    vertical-align: bottom;
+    background: url(../img/clientIcon.png) no-repeat;
+    background-position: -21px -82px;
+}
+
+.evaluate-title {
+    margin: 0;
+    padding: 0;
+    height: 30px;
+    line-height: 30px;
+    padding-left: 15px;
+    font-size: 14px;
+    font-weight: 500;
+    border-bottom: 1px solid #ddd;
+
+    
+}
+
+.el-alert-event {
+    position: absolute;
+    bottom: 40px;
+}
+
+.left-ul {
+    overflow: initial;
+    height: 36px;
+    line-height: 36px;
+    border-bottom: 1px solid #f23838;
+    position: relative;
+
+    
+}
+.left-ul .active {
+    color: #2e2c2c;
+    position: relative;
+}
+.current-icon {
+    position: absolute;
+    bottom: -2px;
+    left: 35px;
+    margin-left: -6px;
+    width: 12px;
+    height: 8px;
+    background: url(../img/up-icon.png)
+}
+.left-li {
+    width: 33%;
+    color: #666;
+    text-align: center;
+    cursor: pointer;
+
+   
+}
+
+.left-li:hover {
+    color: #2e2c2c;
+}
+
+.ztree {
+    overflow: auto;
+}
+
+.shop-name {
+    font-weight: 500;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+
+.shop-channel-icon {
+    width: 35px;
+    height: 35px;
+    margin: 0 auto;
+    background: url(../img/clientIcon.png) no-repeat;
+}
+
+.online-channel-icon {
+    background-position: -623px -4px;
+}
+
+.offLine-channel-icon {
+    background-position: -663px -4px;
+}
+
+.channel-name {
+    color: #777977;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    width: 50%;
+    float: left;
+    text-align: center;
+    cursor: pointer;
+}
+
+.shop-name-text {
+    display: inline-block;
+    width: 80px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    text-align: center;
+    margin: 0 auto;
+}
+
+.vertical-t {
+    vertical-align: top;
+}
+
+.cs-box {
+    padding: 0;
+    height: 100%;
+}
+
+.his-icon {
+    background: url(../img/clientIcon.png);
+    display: inline-block;
+    width: 15px;
+    height: 15px;
+    margin-top: 5px;
+    display: none;
+    float: left;
+    cursor: pointer;
+}
+
+.open-channel {
+    background-position: -263px -84px;
+    display: block;
+}
+
+.close-channel {
+    background-position: -304px -84px;
+    display: block;
+}
+
+.his-active {
+    background-color: #f4e1e1;
+    color: #ee3f1f;
+}
+
+.his-box,
+.attention-box {
+    overflow: auto;
+    position: absolute;
+    top: 36px;
+    right: 0;
+    left: 0;
+    bottom: 0;
+}
+
+.video-shop-task-result {
+    height: 100%;
+}
+
+.red {
+    color: #f23838;
+}
+
+.green {
+    color: #23b85a;
+}
+
+.del,
+.edit {
+    position: absolute;
+    width: 15px;
+    height: 15px;
+    right: 0;
+    display: none;
+}
+
+.text-area {
+    width: 200px;
+    height: 135px;
+}
+
+.mgb0 {
+    margin-bottom: 0;
+}
+
+.submit {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    height: 28px;
+    line-height: 5px;
+    width: 100%;
+}
+
+
+.event-drop-down {
+    width: 200px;
+}
+
+.event-desc {
+    max-width: 220px !important;
+    word-break: break-word;
+    position: absolute;
+    top: 231px;
+    left: 500px;
+}
+
+
+.el-select-dropdown-item {
+    width: 190px;
+}
+
+.cursor {
+    cursor: pointer;
+}
+
+.tooltip-smallItemName {
+    max-width: 200px !important;
+    background: rgba(0, 0, 0, .5) !important;
+}
+
+.videoShopTask-tip.el-tooltip__popper.is-dark {
+    max-width: 200px !important;
+    max-height: 600px !important;
+    overflow: hidden;
+    word-wrap: break-word;
+    word-break: break-all;
+    background: #FFFFE1;
+    color: #000;
+    border: 1px solid #000;
+    border-radius: 0;
+    padding: 3px;
+
+}
+
+.explain-1 {
+    font-weight: bold;
+    margin-top: 3px;
+}
+
+.explain-2 {
+    font-weight: 10px;
+    margin-top: 10px;
+}
+
+.explain-3 {
+    margin-top: 3px;
+}
+
+.percentage-explain {
+    background: url('../img/evaluation-result-percentage-explain.png') no-repeat;
+    width: 20px;
+    height: 20px;
+    margin-top: 3px;
+}
+#showDev_001 {
+    display: none;
+}
+.download-ul {
+    position: absolute;
+    right: 9px;
+    z-index: 1;
+    top: 35px;
+    background-color: #fff;
+    border: 1px solid #ebeef5;
+    border-radius: 4px;
+    box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
+}
+.download-ul li {
+    list-style: none;
+    line-height: 36px;
+    padding: 0 20px;
+    margin: 0;
+    font-size: 14px;
+    color: #606266;
+    cursor: pointer;
+    outline: none;
+}
+
+.download-ul li:hover {
+    background-color: #ecf5ff;
+    color: red;
+}
+
+.el-dropdown-menu__item {
+    line-height: 22px;
+    padding: 0px 12px;
+    font-size: 12px;
+}
+.el-dropdown {
+    font-size: 12px;
+    margin-left: 15px;
+    vertical-align: sub;
+}
+.el-dropdown-menu {
+    padding: 5px 0;
+}
+.fixed-bottom {
+    bottom: 16px !important;
+}
+
+/* 加入组织树层级后删除如下样式 */
+.ztree li span.button.noline_docu {
+    width: 1px !important;
+}
+.ztree .tree-item .node_name {
+    width: 127px !important;
+    vertical-align: top;
+}
+

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1719 - 0
public/camera/demo.html


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1722 - 0
public/camera/demo.php


BIN
public/camera/img/Thumbs.db


BIN
public/camera/img/favicon.ico


BIN
public/camera/img/ptz/center.png


BIN
public/camera/img/ptz/center_disable.png


BIN
public/camera/img/ptz/center_hover.png


BIN
public/camera/img/ptz/center_pressed.png


BIN
public/camera/img/ptz/control_bg.png


BIN
public/camera/img/ptz/control_bg_Down.png


BIN
public/camera/img/ptz/control_bg_Left.png


BIN
public/camera/img/ptz/control_bg_LeftDown.png


BIN
public/camera/img/ptz/control_bg_LeftUp.png


BIN
public/camera/img/ptz/control_bg_Right.png


BIN
public/camera/img/ptz/control_bg_RightDown.png


BIN
public/camera/img/ptz/control_bg_RightUp.png


BIN
public/camera/img/ptz/control_bg_Up.png


BIN
public/camera/img/ptz/down.png


BIN
public/camera/img/ptz/down_disabled.png


BIN
public/camera/img/ptz/down_hover.png


BIN
public/camera/img/ptz/down_pressed.png


BIN
public/camera/img/ptz/hide.png


BIN
public/camera/img/ptz/hide_sel.png


BIN
public/camera/img/ptz/left.png


BIN
public/camera/img/ptz/left_disabled.png


BIN
public/camera/img/ptz/left_hover.png


BIN
public/camera/img/ptz/left_pressed.png


BIN
public/camera/img/ptz/northEast.png


BIN
public/camera/img/ptz/northEast_disabled.png


BIN
public/camera/img/ptz/northEast_hover.png


BIN
public/camera/img/ptz/northEast_pressed.png


BIN
public/camera/img/ptz/northWest.png


BIN
public/camera/img/ptz/northWest_disabled.png


BIN
public/camera/img/ptz/northWest_hover.png


BIN
public/camera/img/ptz/northWest_pressed.png


BIN
public/camera/img/ptz/ptzEx2/ApertureDown_d.png


BIN
public/camera/img/ptz/ptzEx2/ApertureDown_h.png


BIN
public/camera/img/ptz/ptzEx2/ApertureDown_n.png


BIN
public/camera/img/ptz/ptzEx2/ApertureDown_p.png


BIN
public/camera/img/ptz/ptzEx2/ApertureUp_d.png


BIN
public/camera/img/ptz/ptzEx2/ApertureUp_h.png


BIN
public/camera/img/ptz/ptzEx2/ApertureUp_n.png


BIN
public/camera/img/ptz/ptzEx2/ApertureUp_p.png


BIN
public/camera/img/ptz/ptzEx2/Cruise-h.png


BIN
public/camera/img/ptz/ptzEx2/Cruise-n.png


BIN
public/camera/img/ptz/ptzEx2/FocusDown_d.png


BIN
public/camera/img/ptz/ptzEx2/FocusDown_h.png


BIN
public/camera/img/ptz/ptzEx2/FocusDown_n.png


BIN
public/camera/img/ptz/ptzEx2/FocusDown_p.png


BIN
public/camera/img/ptz/ptzEx2/FocusUp_d.png


BIN
public/camera/img/ptz/ptzEx2/FocusUp_h.png


BIN
public/camera/img/ptz/ptzEx2/FocusUp_n.png


BIN
public/camera/img/ptz/ptzEx2/FocusUp_p.png


BIN
public/camera/img/ptz/ptzEx2/Ok-h.png


BIN
public/camera/img/ptz/ptzEx2/Prepoint-h.png


BIN
public/camera/img/ptz/ptzEx2/add-h.png


BIN
public/camera/img/ptz/ptzEx2/add-n.png


BIN
public/camera/img/ptz/ptzEx2/cancel-h.png


BIN
public/camera/img/ptz/ptzEx2/cancel-n.png


BIN
public/camera/img/ptz/ptzEx2/delete-h.png


BIN
public/camera/img/ptz/ptzEx2/delete-n.png


BIN
public/camera/img/ptz/ptzEx2/locate-h.png


BIN
public/camera/img/ptz/ptzEx2/locate-n.png


BIN
public/camera/img/ptz/ptzEx2/modify-h.png


BIN
public/camera/img/ptz/ptzEx2/modify-n.png


BIN
public/camera/img/ptz/ptzEx2/ok-n.png


BIN
public/camera/img/ptz/ptzEx2/play-h.png


BIN
public/camera/img/ptz/ptzEx2/play-n.png


BIN
public/camera/img/ptz/ptzEx2/prepoint-n.png


BIN
public/camera/img/ptz/ptzEx2/scaleAdd_d.png


BIN
public/camera/img/ptz/ptzEx2/scaleAdd_h.png


BIN
public/camera/img/ptz/ptzEx2/scaleAdd_n.png


BIN
public/camera/img/ptz/ptzEx2/scaleAdd_p.png


BIN
public/camera/img/ptz/ptzEx2/scaleMinus_d.png


BIN
public/camera/img/ptz/ptzEx2/scaleMinus_h.png


BIN
public/camera/img/ptz/ptzEx2/scaleMinus_n.png


BIN
public/camera/img/ptz/ptzEx2/scaleMinus_p.png


BIN
public/camera/img/ptz/ptzEx2/search-h.png


BIN
public/camera/img/ptz/ptzEx2/search-n.png


BIN
public/camera/img/ptz/ptzEx2/stop-h.png


BIN
public/camera/img/ptz/ptzEx2/stop-n.png


BIN
public/camera/img/ptz/ptzEx2/取消-h.png


BIN
public/camera/img/ptz/ptzEx2/取消-n.png


BIN
public/camera/img/ptz/ptzEx2/巡迹-h.png


BIN
public/camera/img/ptz/ptzEx2/巡迹-n.png


BIN
public/camera/img/ptz/ptzEx2/扫描-右-h.png


+ 0 - 0
public/camera/img/ptz/ptzEx2/扫描-右.png


Vissa filer visades inte eftersom för många filer har ändrats