Commit c6e8b341f3e266c857622e59d67edd1457be144e
1 parent
d881c982
web页面集成
Showing
13 changed files
with
1597 additions
and
0 deletions
web_src/src/assets/loading.png
0 → 100644
2.7 KB
web_src/src/assets/login-bg.jpg
0 → 100644
3.97 KB
web_src/src/assets/login-cloud.png
0 → 100644
3.31 KB
web_src/src/assets/logo.png
0 → 100644
6.69 KB
web_src/src/assets/play.png
0 → 100644
546 Bytes
web_src/src/components/Loading.vue
0 → 100644
| 1 | +//loading效果组件 | ||
| 2 | + | ||
| 3 | +<template> | ||
| 4 | +<div class="loadEffect" :style="{marginTop: marginTop? marginTop : '50%'}"> | ||
| 5 | + <span class="ld-span"></span> | ||
| 6 | + <span class="ld-span"></span> | ||
| 7 | + <span class="ld-span"></span> | ||
| 8 | + <span class="ld-span"></span> | ||
| 9 | + <span class="ld-span"></span> | ||
| 10 | + <span class="ld-span"></span> | ||
| 11 | + <span class="ld-span"></span> | ||
| 12 | + <span class="ld-span"></span> | ||
| 13 | +</div> | ||
| 14 | +</template> | ||
| 15 | + | ||
| 16 | +<script> | ||
| 17 | +export default { | ||
| 18 | + name: 'Loading', | ||
| 19 | + props: ["marginTop"] | ||
| 20 | + | ||
| 21 | +} | ||
| 22 | +</script> | ||
| 23 | + | ||
| 24 | +<style scoped> | ||
| 25 | +.loadEffect{ | ||
| 26 | + width: 100px; | ||
| 27 | + height: 100px; | ||
| 28 | + position: relative; | ||
| 29 | + margin: 0 auto; | ||
| 30 | + position: relative; | ||
| 31 | + top:-50px; | ||
| 32 | + margin-top:50%; | ||
| 33 | + transform: scale(.5) | ||
| 34 | +} | ||
| 35 | +.loadEffect .ld-span{ | ||
| 36 | + display: inline-block; | ||
| 37 | + width: 20px; | ||
| 38 | + height: 20px; | ||
| 39 | + border-radius: 50%; | ||
| 40 | + background: #67e7d5; | ||
| 41 | + position: absolute; | ||
| 42 | + -webkit-animation: load 1.04s ease infinite; | ||
| 43 | +} | ||
| 44 | +@-webkit-keyframes load{ | ||
| 45 | + 0%{ | ||
| 46 | + -webkit-transform: scale(1.2); | ||
| 47 | + opacity: 1; | ||
| 48 | + } | ||
| 49 | + 100%{ | ||
| 50 | + -webkit-transform: scale(.3); | ||
| 51 | + opacity: 0.5; | ||
| 52 | + } | ||
| 53 | +} | ||
| 54 | +.loadEffect .ld-span:nth-child(1){ | ||
| 55 | + left: 0; | ||
| 56 | + top: 50%; | ||
| 57 | + margin-top:-10px; | ||
| 58 | + -webkit-animation-delay:0.13s; | ||
| 59 | +} | ||
| 60 | +.loadEffect .ld-span:nth-child(2){ | ||
| 61 | + left: 14px; | ||
| 62 | + top: 14px; | ||
| 63 | + -webkit-animation-delay:0.26s; | ||
| 64 | +} | ||
| 65 | +.loadEffect .ld-span:nth-child(3){ | ||
| 66 | + left: 50%; | ||
| 67 | + top: 0; | ||
| 68 | + margin-left: -10px; | ||
| 69 | + -webkit-animation-delay:0.39s; | ||
| 70 | +} | ||
| 71 | +.loadEffect .ld-span:nth-child(4){ | ||
| 72 | + top: 14px; | ||
| 73 | + right:14px; | ||
| 74 | + -webkit-animation-delay:0.52s; | ||
| 75 | +} | ||
| 76 | +.loadEffect .ld-span:nth-child(5){ | ||
| 77 | + right: 0; | ||
| 78 | + top: 50%; | ||
| 79 | + margin-top:-10px; | ||
| 80 | + -webkit-animation-delay:0.65s; | ||
| 81 | +} | ||
| 82 | +.loadEffect .ld-span:nth-child(6){ | ||
| 83 | + right: 14px; | ||
| 84 | + bottom:14px; | ||
| 85 | + -webkit-animation-delay:0.78s; | ||
| 86 | +} | ||
| 87 | +.loadEffect .ld-span:nth-child(7){ | ||
| 88 | + bottom: 0; | ||
| 89 | + left: 50%; | ||
| 90 | + margin-left: -10px; | ||
| 91 | + -webkit-animation-delay:0.91s; | ||
| 92 | +} | ||
| 93 | +.loadEffect .ld-span:nth-child(8){ | ||
| 94 | + bottom: 14px; | ||
| 95 | + left: 14px; | ||
| 96 | + -webkit-animation-delay:1.04s; | ||
| 97 | +} | ||
| 98 | +</style> |
web_src/src/components/Login.vue
0 → 100644
| 1 | +<template> | ||
| 2 | +<div class="login" id="login"> | ||
| 3 | + <a href="javascript:;" class="log-close"><i class="icons close"></i></a> | ||
| 4 | + <div class="log-bg"> | ||
| 5 | + <div class="log-cloud cloud1"></div> | ||
| 6 | + <div class="log-cloud cloud2"></div> | ||
| 7 | + <div class="log-cloud cloud3"></div> | ||
| 8 | + <div class="log-cloud cloud4"></div> | ||
| 9 | + | ||
| 10 | + <div class="log-logo">Welcome!</div> | ||
| 11 | + <div class="log-text"></div> | ||
| 12 | + </div> | ||
| 13 | + <div class="log-email"> | ||
| 14 | + <input type="text" placeholder="用户名" :class="'log-input' + (username==''?' log-input-empty':'')" v-model="username"><input type="password" placeholder="密码" :class="'log-input' + (password==''?' log-input-empty':'')" v-model="password"> | ||
| 15 | + <a href="javascript:;" class="log-btn" @click="login" >登录</a> | ||
| 16 | + </div> | ||
| 17 | + <Loading v-if="isLoging" marginTop="-30%"></Loading> | ||
| 18 | +</div> | ||
| 19 | +</template> | ||
| 20 | + | ||
| 21 | +<script> | ||
| 22 | +import Loading from './Loading.vue' | ||
| 23 | +import crypto from 'crypto' | ||
| 24 | +export default { | ||
| 25 | + name: 'Login', | ||
| 26 | + data(){ | ||
| 27 | + return { | ||
| 28 | + isLoging: false, | ||
| 29 | + username: '', | ||
| 30 | + password: '' | ||
| 31 | + } | ||
| 32 | + }, | ||
| 33 | + components:{ | ||
| 34 | + Loading | ||
| 35 | + }, | ||
| 36 | + created(){ | ||
| 37 | + var that = this; | ||
| 38 | + document.onkeydown = function(e) { | ||
| 39 | + var key = window.event.keyCode; | ||
| 40 | + if (key == 13) { | ||
| 41 | + that.login(); | ||
| 42 | + } | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + }, | ||
| 46 | + methods:{ | ||
| 47 | + | ||
| 48 | + //登录逻辑 | ||
| 49 | + login(){ | ||
| 50 | + if(this.username!='' && this.password!=''){ | ||
| 51 | + this.toLogin(); | ||
| 52 | + } | ||
| 53 | + }, | ||
| 54 | + | ||
| 55 | + //登录请求 | ||
| 56 | + toLogin(){ | ||
| 57 | + | ||
| 58 | + //一般要跟后端了解密码的加密规则 | ||
| 59 | + //这里例子用的哈希算法来自./js/sha1.min.js | ||
| 60 | + | ||
| 61 | + //需要想后端发送的登录参数 | ||
| 62 | + let loginParam = { | ||
| 63 | + username: this.username, | ||
| 64 | + password: crypto.createHash('md5').update(this.password, "utf8").digest('hex') | ||
| 65 | + } | ||
| 66 | + var that = this; | ||
| 67 | + //设置在登录状态 | ||
| 68 | + this.isLoging = true; | ||
| 69 | + | ||
| 70 | + this.$axios.get("/auth/login",{ | ||
| 71 | + params: loginParam | ||
| 72 | + } ) | ||
| 73 | + .then(function (res) { | ||
| 74 | + console.log(JSON.stringify(res)); | ||
| 75 | + if (res.data == "success") { | ||
| 76 | + that.$cookies.set("session", {"username": that.username}) ; | ||
| 77 | + //登录成功后 | ||
| 78 | + that.$router.push('/'); | ||
| 79 | + } | ||
| 80 | + }) | ||
| 81 | + .catch(function (error) { | ||
| 82 | + console.log(error); | ||
| 83 | + }); | ||
| 84 | + | ||
| 85 | + | ||
| 86 | + | ||
| 87 | + }, | ||
| 88 | + setCookie: function (cname, cvalue, exdays) { | ||
| 89 | + var d = new Date(); | ||
| 90 | + d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); | ||
| 91 | + var expires = "expires=" + d.toUTCString(); | ||
| 92 | + console.info(cname + "=" + cvalue + "; " + expires); | ||
| 93 | + document.cookie = cname + "=" + cvalue + "; " + expires; | ||
| 94 | + console.info(document.cookie); | ||
| 95 | + }, | ||
| 96 | + } | ||
| 97 | +} | ||
| 98 | +</script> | ||
| 99 | + | ||
| 100 | +<style scoped> | ||
| 101 | +.login{position: fixed; overflow: hidden;left: 50%; margin-left: -250px; top:50%; margin-top: -350px; width: 500px; min-height: 555px; z-index: 10; right: 140px; background: #fff;-webkit-border-radius: 5px; | ||
| 102 | +-moz-border-radius: 5px; | ||
| 103 | +-ms-border-radius: 5px; | ||
| 104 | +-o-border-radius: 5px; | ||
| 105 | +border-radius: 5px; -webkit-box-shadow: 0px 3px 16px -5px #070707; box-shadow: 0px 3px 16px -5px #070707} | ||
| 106 | +.log-close{display: block; position: absolute; top:12px; right: 12px; opacity: 1;} | ||
| 107 | +.log-close:hover .icons{transform: rotate(180deg);} | ||
| 108 | +.log-close .icons{opacity: 1; transition: all .3s} | ||
| 109 | +.log-cloud{background-image: url(../assets/login-cloud.png); width: 63px ;height: 40px; position: absolute; z-index: 1} | ||
| 110 | +.login .cloud1{top:21px; left: -30px; transform: scale(.6); animation: cloud1 20s linear infinite;} | ||
| 111 | +.login .cloud2{top:87px; right: 20px; animation: cloud2 19s linear infinite;} | ||
| 112 | +.login .cloud3{top:160px; left: 5px;transform: scale(.8);animation: cloud3 21s linear infinite;} | ||
| 113 | +.login .cloud4{top:150px; left: -40px;transform: scale(.4);animation: cloud4 19s linear infinite;} | ||
| 114 | +.log-bg{background: url(../assets/login-bg.jpg); width: 100%; height: 312px; overflow: hidden;} | ||
| 115 | +.log-logo{height: 80px; margin: 120px auto 25px; text-align: center; color: #1fcab3; font-weight: bold; font-size: 40px;} | ||
| 116 | +.log-text{color: #57d4c3; font-size: 13px; text-align: center; margin: 0 auto;} | ||
| 117 | +.log-logo,.log-text{z-index: 2} | ||
| 118 | +.icons{background:url(../assets/icons.png) no-repeat; display: inline-block;} | ||
| 119 | +.close{height:16px;width:16px;background-position:-13px 0;} | ||
| 120 | +.login-email{height:17px;width:29px;background-position:-117px 0;} | ||
| 121 | + | ||
| 122 | +.log-btns{padding: 15px 0; margin: 0 auto;} | ||
| 123 | +.log-btn{width:402px; display: block; text-align: left; line-height: 50px;margin:0 auto 15px; height:50px; color:#fff; font-size:13px;-webkit-border-radius: 5px; background-color: #3B5999; | ||
| 124 | +-moz-border-radius: 5px; | ||
| 125 | +-ms-border-radius: 5px; | ||
| 126 | +-o-border-radius: 5px; | ||
| 127 | +border-radius: 5px; | ||
| 128 | +position: relative;} | ||
| 129 | +.log-btn.tw{background-color: #13B4E9} | ||
| 130 | +.log-btn.email{background-color: #50E3CE} | ||
| 131 | +.log-btn:hover,.log-btn:focus{color: #fff; opacity: .8;} | ||
| 132 | + | ||
| 133 | +.log-email{text-align: center; margin-top: 20px;} | ||
| 134 | +.log-email .log-btn{background-color: #50E3CE;text-align: center;} | ||
| 135 | +.log-input-empty{border: 1px solid #f37474 !important;} | ||
| 136 | +.isloading{background: #d6d6d6} | ||
| 137 | +.log-btn .icons{margin-left: 30px; vertical-align: middle;} | ||
| 138 | +.log-btn .text{left: 95px; line-height: 50px; text-align: left; position: absolute;} | ||
| 139 | +.log-input{width: 370px;overflow: hidden; padding: 0 15px;font-size: 13px; border: 1px solid #EBEBEB; margin:0 auto 15px; height: 48px; line-height: 48px; -webkit-border-radius: 5px; | ||
| 140 | +-moz-border-radius: 5px; | ||
| 141 | +-ms-border-radius: 5px; | ||
| 142 | +-o-border-radius: 5px; | ||
| 143 | +border-radius: 5px;} | ||
| 144 | +.log-input.warn{border: 1px solid #f88787} | ||
| 145 | + | ||
| 146 | + @-webkit-keyframes cloud1 { | ||
| 147 | + 0%{left: 200px} | ||
| 148 | + 100%{left:-130px;} | ||
| 149 | +} | ||
| 150 | +@keyframes cloud1{ | ||
| 151 | + 0%{left: 200px} | ||
| 152 | + 100%{left:-130px;} | ||
| 153 | +} | ||
| 154 | + | ||
| 155 | + @-webkit-keyframes cloud2 { | ||
| 156 | + 0%{left:500px;} | ||
| 157 | + 100%{left:-90px;} | ||
| 158 | +} | ||
| 159 | +@keyframes cloud2{ | ||
| 160 | + 0%{left:500px;} | ||
| 161 | + 100%{left:-90px;} | ||
| 162 | +} | ||
| 163 | + | ||
| 164 | +@-webkit-keyframes cloud3 { | ||
| 165 | + 0%{left:620px;} | ||
| 166 | + 100%{left:-70px;} | ||
| 167 | +} | ||
| 168 | +@keyframes cloud3{ | ||
| 169 | + 0%{left:620px;} | ||
| 170 | + 100%{left:-70px;} | ||
| 171 | +}@-webkit-keyframes cloud4 { | ||
| 172 | + 0%{left:100px;} | ||
| 173 | + 100%{left:-70px;} | ||
| 174 | +} | ||
| 175 | +@keyframes cloud4{ | ||
| 176 | + 0%{left:100px;} | ||
| 177 | + 100%{left:-70px;} | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +</style> |
web_src/src/components/UiHeader.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div id="UiHeader"> | ||
| 3 | + <el-menu router :default-active="this.$route.path" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" mode="horizontal"> | ||
| 4 | + <el-menu-item index="/">控制台</el-menu-item> | ||
| 5 | + <el-menu-item index="/videoList">设备列表</el-menu-item> | ||
| 6 | + <!-- <el-menu-item index="/videoReplay">录像回看</el-menu-item> --> | ||
| 7 | + <!-- <el-menu-item index="4">级联设置</el-menu-item> --> | ||
| 8 | + <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item> | ||
| 9 | + </el-menu> | ||
| 10 | + </div> | ||
| 11 | +</template> | ||
| 12 | + | ||
| 13 | +<script> | ||
| 14 | +export default { | ||
| 15 | + name: "UiHeader", | ||
| 16 | + methods:{ | ||
| 17 | + | ||
| 18 | + loginout(){ | ||
| 19 | + // 删除cookie,回到登录页面 | ||
| 20 | + this.$cookies.remove("session"); | ||
| 21 | + this.$router.push('/login'); | ||
| 22 | + }, | ||
| 23 | + } | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +</script> | ||
| 0 | \ No newline at end of file | 27 | \ No newline at end of file |
web_src/src/components/channelList.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div id="channelList"> | ||
| 3 | + <el-container> | ||
| 4 | + | ||
| 5 | + <el-header> | ||
| 6 | + <uiHeader></uiHeader> | ||
| 7 | + </el-header> | ||
| 8 | + <el-main> | ||
| 9 | + <div style="background-color: #FFFFFF; position: relative; padding: 1rem 0.5rem 0.5rem 0.5rem; text-align: center;"> | ||
| 10 | + <span style="font-size: 1rem; font-weight: 500; ">通道列表({{parentChannelId ==0 ? deviceId:parentChannelId}})</span> | ||
| 11 | + | ||
| 12 | + </div> | ||
| 13 | + <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;"> | ||
| 14 | + <el-button icon="el-icon-arrow-left" size="mini" style="margin-right: 1rem;" @click="showDevice">返回</el-button> | ||
| 15 | + 搜索: <el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字" prefix-icon="el-icon-search" v-model="searchSrt" clearable> </el-input> | ||
| 16 | + | ||
| 17 | + 通道类型: <el-select size="mini" @change="search" style="margin-right: 1rem;" v-model="channelType" placeholder="请选择" default-first-option> | ||
| 18 | + <el-option label="全部" value="" ></el-option> | ||
| 19 | + <el-option label="设备" value="false"></el-option> | ||
| 20 | + <el-option label="子目录" value="true" ></el-option> | ||
| 21 | + </el-select> | ||
| 22 | + 在线状态: <el-select size="mini" @change="search" v-model="online" placeholder="请选择" default-first-option> | ||
| 23 | + <el-option label="全部" value=""></el-option> | ||
| 24 | + <el-option label="在线" value="on"></el-option> | ||
| 25 | + <el-option label="离线" value="off"></el-option> | ||
| 26 | + </el-select> | ||
| 27 | + | ||
| 28 | + </div> | ||
| 29 | + <devicePlayer ref="devicePlayer"></devicePlayer> | ||
| 30 | + <!--设备列表--> | ||
| 31 | + <el-table ref="channelListTable" :data="deviceChannelList" :height="winHeight" border style="width: 100%"> | ||
| 32 | + <el-table-column prop="channelId" label="通道编号" width="210"> | ||
| 33 | + </el-table-column> | ||
| 34 | + <el-table-column prop="name" label="通道名称" width="500"> | ||
| 35 | + </el-table-column> | ||
| 36 | + <el-table-column prop="subCount" label="子节点数"> | ||
| 37 | + </el-table-column> | ||
| 38 | + <el-table-column prop="ptztypeText" label="云台类型"> | ||
| 39 | + </el-table-column> | ||
| 40 | + <el-table-column label="操作" width="240" align="center" fixed="right"> | ||
| 41 | + <template slot-scope="scope"> | ||
| 42 | + <el-button size="mini" icon="el-icon-video-play" v-if="scope.row.parental == 0" @click="sendDevicePush(scope.row)">预览视频</el-button> | ||
| 43 | + <el-button size="mini" icon="el-icon-s-open" type="primary" v-if="scope.row.parental == 1" @click="changeSubchannel(scope.row)">查看子目录</el-button> | ||
| 44 | + <!-- <el-button size="mini" @click="sendDevicePush(scope.row)">录像查询</el-button> --> | ||
| 45 | + </template> | ||
| 46 | + </el-table-column> | ||
| 47 | + </el-table> | ||
| 48 | + <el-pagination | ||
| 49 | + style="float: right" | ||
| 50 | + @size-change="handleSizeChange" | ||
| 51 | + @current-change="currentChange" | ||
| 52 | + :current-page="currentPage" | ||
| 53 | + :page-size="count" | ||
| 54 | + :page-sizes="[15, 20, 30, 50]" | ||
| 55 | + layout="total, sizes, prev, pager, next" | ||
| 56 | + :total="total"> | ||
| 57 | + </el-pagination> | ||
| 58 | + | ||
| 59 | + </el-main> | ||
| 60 | + </el-container> | ||
| 61 | + </div> | ||
| 62 | +</template> | ||
| 63 | + | ||
| 64 | +<script> | ||
| 65 | + import devicePlayer from './gb28181/devicePlayer.vue' | ||
| 66 | + import uiHeader from './UiHeader.vue' | ||
| 67 | + export default { | ||
| 68 | + name: 'channelList', | ||
| 69 | + components: { | ||
| 70 | + devicePlayer, | ||
| 71 | + uiHeader | ||
| 72 | + }, | ||
| 73 | + data() { | ||
| 74 | + return { | ||
| 75 | + deviceId: this.$route.params.deviceId, | ||
| 76 | + parentChannelId: this.$route.params.parentChannelId, | ||
| 77 | + deviceChannelList: [], | ||
| 78 | + videoComponentList: [], | ||
| 79 | + currentPlayerInfo: {}, //当前播放对象 | ||
| 80 | + updateLooper: 0, //数据刷新轮训标志 | ||
| 81 | + searchSrt: "", | ||
| 82 | + channelType: "", | ||
| 83 | + online: "", | ||
| 84 | + winHeight: window.innerHeight - 250, | ||
| 85 | + currentPage: parseInt(this.$route.params.page), | ||
| 86 | + count: parseInt(this.$route.params.count), | ||
| 87 | + total:0, | ||
| 88 | + beforeUrl:"/videoList" | ||
| 89 | + }; | ||
| 90 | + }, | ||
| 91 | + | ||
| 92 | + mounted() { | ||
| 93 | + this.initData(); | ||
| 94 | + // this.updateLooper = setInterval(this.initData, 10000); | ||
| 95 | + }, | ||
| 96 | + destroyed() { | ||
| 97 | + this.$destroy('videojs'); | ||
| 98 | + clearTimeout(this.updateLooper); | ||
| 99 | + }, | ||
| 100 | + methods: { | ||
| 101 | + initData: function() { | ||
| 102 | + if (this.parentChannelId == "" || this.parentChannelId == 0 ) { | ||
| 103 | + this.getDeviceChannelList(); | ||
| 104 | + }else{ | ||
| 105 | + this.showSubchannels(); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + }, | ||
| 109 | + initParam: function(){ | ||
| 110 | + this.deviceId= this.$route.params.deviceId; | ||
| 111 | + this.parentChannelId= this.$route.params.parentChannelId; | ||
| 112 | + this.currentPage= parseInt(this.$route.params.page); | ||
| 113 | + this.count= parseInt(this.$route.params.count); | ||
| 114 | + if (this.parentChannelId == "" || this.parentChannelId == 0 ) { | ||
| 115 | + this.beforeUrl = "/videoList" | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + }, | ||
| 119 | + currentChange: function(val){ | ||
| 120 | + var url = `/${this.$router.currentRoute.name}/${this.deviceId}/${this.parentChannelId}/${this.count}/${val}` | ||
| 121 | + console.log(url) | ||
| 122 | + this.$router.push(url).then(()=>{ | ||
| 123 | + this.initParam(); | ||
| 124 | + this.initData(); | ||
| 125 | + }) | ||
| 126 | + }, | ||
| 127 | + handleSizeChange: function(val){ | ||
| 128 | + var url = `/${this.$router.currentRoute.name}/${this.$router.params.deviceId}/${this.$router.params.parentChannelId}/${val}/1` | ||
| 129 | + this.$router.push(url).then(()=>{ | ||
| 130 | + this.initParam(); | ||
| 131 | + this.initData(); | ||
| 132 | + }) | ||
| 133 | + | ||
| 134 | + }, | ||
| 135 | + getDeviceChannelList: function() { | ||
| 136 | + let that = this; | ||
| 137 | + console.log(this.currentPage - 1) | ||
| 138 | + | ||
| 139 | + this.$axios.get(`/api/devices/${this.$route.params.deviceId}/channels`,{ | ||
| 140 | + params: { | ||
| 141 | + page: that.currentPage - 1, | ||
| 142 | + count: that.count, | ||
| 143 | + query: that.searchSrt, | ||
| 144 | + online: that.online, | ||
| 145 | + channelType: that.channelType | ||
| 146 | + } | ||
| 147 | + } ) | ||
| 148 | + .then(function (res) { | ||
| 149 | + console.log(res); | ||
| 150 | + that.total = res.data.total; | ||
| 151 | + that.deviceChannelList = res.data.data; | ||
| 152 | + // 防止出现表格错位 | ||
| 153 | + that.$nextTick(()=>{ | ||
| 154 | + that.$refs.channelListTable.doLayout(); | ||
| 155 | + }) | ||
| 156 | + }) | ||
| 157 | + .catch(function (error) { | ||
| 158 | + console.log(error); | ||
| 159 | + }); | ||
| 160 | + | ||
| 161 | + }, | ||
| 162 | + | ||
| 163 | + | ||
| 164 | + //gb28181平台对接 | ||
| 165 | + //刷新设备信息 | ||
| 166 | + refDevice: function(itemData) { | ||
| 167 | + ///api/devices/{deviceId}/sync | ||
| 168 | + console.log("刷新对应设备:" + itemData.deviceId); | ||
| 169 | + this.$axios({ | ||
| 170 | + method: 'post', | ||
| 171 | + url: '/api/devices/' + itemData.deviceId + '/sync' | ||
| 172 | + }).then(function(res) { | ||
| 173 | + // console.log("刷新设备结果:"+JSON.stringify(res)); | ||
| 174 | + }).catch(function(e) { | ||
| 175 | + that.$message({ | ||
| 176 | + showClose: true, | ||
| 177 | + message: '请求成功', | ||
| 178 | + type: 'success' | ||
| 179 | + }); | ||
| 180 | + });; | ||
| 181 | + }, | ||
| 182 | + //通知设备上传媒体流 | ||
| 183 | + sendDevicePush: function(itemData) { | ||
| 184 | + let deviceId = this.deviceId; | ||
| 185 | + | ||
| 186 | + let channelId = itemData.channelId; | ||
| 187 | + console.log("通知设备推流1:" + deviceId + " : " + channelId); | ||
| 188 | + let that = this; | ||
| 189 | + this.$axios({ | ||
| 190 | + method: 'get', | ||
| 191 | + url: '/api/play/' + deviceId + '/' + channelId | ||
| 192 | + }).then(function(res) { | ||
| 193 | + let ssrc = res.data.ssrc; | ||
| 194 | + that.$refs.devicePlayer.play(res.data,deviceId,channelId); | ||
| 195 | + }).catch(function(e) { | ||
| 196 | + }); | ||
| 197 | + }, | ||
| 198 | + showDevice: function(){ | ||
| 199 | + this.$router.push(this.beforeUrl).then(()=>{ | ||
| 200 | + this.initParam(); | ||
| 201 | + this.initData(); | ||
| 202 | + }) | ||
| 203 | + }, | ||
| 204 | + changeSubchannel(itemData) { | ||
| 205 | + console.log(this.$router.currentRoute) | ||
| 206 | + this.beforeUrl = this.$router.currentRoute.path; | ||
| 207 | + | ||
| 208 | + var url = `/${this.$router.currentRoute.name}/${this.$router.currentRoute.params.deviceId}/${itemData.channelId}/${this.$router.currentRoute.params.count}/1` | ||
| 209 | + this.$router.push(url).then(()=>{ | ||
| 210 | + this.searchSrt= ""; | ||
| 211 | + this.channelType= ""; | ||
| 212 | + this.online= ""; | ||
| 213 | + this.initParam(); | ||
| 214 | + this.initData(); | ||
| 215 | + }) | ||
| 216 | + }, | ||
| 217 | + showSubchannels: function(channelId){ | ||
| 218 | + let that = this; | ||
| 219 | + | ||
| 220 | + this.$axios.get(`/api/subChannels/${this.deviceId}/${this.parentChannelId}/channels`,{ | ||
| 221 | + params: { | ||
| 222 | + page: that.currentPage - 1, | ||
| 223 | + count: that.count, | ||
| 224 | + query: that.searchSrt, | ||
| 225 | + online: that.online, | ||
| 226 | + channelType: that.channelType | ||
| 227 | + } | ||
| 228 | + } ) | ||
| 229 | + .then(function (res) { | ||
| 230 | + that.total = res.data.total; | ||
| 231 | + that.deviceChannelList = res.data.data; | ||
| 232 | + // 防止出现表格错位 | ||
| 233 | + that.$nextTick(()=>{ | ||
| 234 | + that.$refs.channelListTable.doLayout(); | ||
| 235 | + }) | ||
| 236 | + }) | ||
| 237 | + .catch(function (error) { | ||
| 238 | + console.log(error); | ||
| 239 | + }); | ||
| 240 | + }, | ||
| 241 | + search: function() { | ||
| 242 | + console.log(this.searchSrt) | ||
| 243 | + this.currentPage = 1; | ||
| 244 | + this.total = 0; | ||
| 245 | + this.initData(); | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + } | ||
| 249 | + }; | ||
| 250 | +</script> | ||
| 251 | + | ||
| 252 | +<style> | ||
| 253 | + .videoList { | ||
| 254 | + display: flex; | ||
| 255 | + flex-wrap: wrap; | ||
| 256 | + align-content: flex-start; | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + .video-item { | ||
| 260 | + position: relative; | ||
| 261 | + width: 15rem; | ||
| 262 | + height: 10rem; | ||
| 263 | + margin-right: 1rem; | ||
| 264 | + background-color: #000000; | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + .video-item-img { | ||
| 268 | + position: absolute; | ||
| 269 | + top: 0; | ||
| 270 | + bottom: 0; | ||
| 271 | + left: 0; | ||
| 272 | + right: 0; | ||
| 273 | + margin: auto; | ||
| 274 | + width: 100%; | ||
| 275 | + height: 100%; | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + .video-item-img:after { | ||
| 279 | + content: ""; | ||
| 280 | + display: inline-block; | ||
| 281 | + position: absolute; | ||
| 282 | + z-index: 2; | ||
| 283 | + top: 0; | ||
| 284 | + bottom: 0; | ||
| 285 | + left: 0; | ||
| 286 | + right: 0; | ||
| 287 | + margin: auto; | ||
| 288 | + width: 3rem; | ||
| 289 | + height: 3rem; | ||
| 290 | + background-image: url("../assets/loading.png"); | ||
| 291 | + background-size: cover; | ||
| 292 | + background-color: #000000; | ||
| 293 | + } | ||
| 294 | + | ||
| 295 | + .video-item-title { | ||
| 296 | + position: absolute; | ||
| 297 | + bottom: 0; | ||
| 298 | + color: #000000; | ||
| 299 | + background-color: #ffffff; | ||
| 300 | + line-height: 1.5rem; | ||
| 301 | + padding: 0.3rem; | ||
| 302 | + width: 14.4rem; | ||
| 303 | + } | ||
| 304 | +</style> |
web_src/src/components/control.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div id="app"> | ||
| 3 | + <el-container> | ||
| 4 | + <el-header> | ||
| 5 | + <uiHeader></uiHeader> | ||
| 6 | + </el-header> | ||
| 7 | + <el-main> | ||
| 8 | + <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> | ||
| 9 | + <span style="font-size: 1rem; font-weight: bold;">控制台</span> | ||
| 10 | + <div style="position: absolute; right: 1rem; top: 0.3rem;"> | ||
| 11 | + <el-popover placement="bottom" width="750" height="300" trigger="click"> | ||
| 12 | + <div style="height: 600px;overflow:auto;"> | ||
| 13 | + <table class="table-c" cellspacing="0"> | ||
| 14 | + <tr v-for="(value, key, index) in serverConfig"> | ||
| 15 | + <td style="width: 18rem; text-align: right;">{{ key }}</td> | ||
| 16 | + <td style="width: 33rem; text-align:left">{{ value }}</td> | ||
| 17 | + </tr> | ||
| 18 | + </table> | ||
| 19 | + </div> | ||
| 20 | + <el-button type="primary" slot="reference" size="mini" @click="getServerConfig()">查看服务器配置</el-button> | ||
| 21 | + </el-popover> | ||
| 22 | + <el-button style="margin-left: 1rem;" type="danger" size="mini" @click="reStartServer()">重启服务器</el-button> | ||
| 23 | + </div> | ||
| 24 | + </div> | ||
| 25 | + <el-row :gutter="30"> | ||
| 26 | + <el-col :span="12"><div class="control-table" id="ThreadsLoad">table1</div></el-col> | ||
| 27 | + <el-col :span="12"><div class="control-table" id="WorkThreadsLoad">table2</div></el-col> | ||
| 28 | + </el-row> | ||
| 29 | + <el-table :data="allSessionData" style="margin-top: 1rem;"> | ||
| 30 | + <el-table-column prop="peer_ip" label="远端"></el-table-column> | ||
| 31 | + <el-table-column prop="local_ip" label="本地"></el-table-column> | ||
| 32 | + <el-table-column prop="typeid" label="类型"></el-table-column> | ||
| 33 | + <el-table-column align="right"> | ||
| 34 | + <template slot="header" slot-scope="scope"> | ||
| 35 | + <el-button icon="el-icon-refresh-right" circle @click="getAllSession()"></el-button> | ||
| 36 | + </template> | ||
| 37 | + <template slot-scope="scope"> | ||
| 38 | + <el-button @click.native.prevent="deleteRow(scope.$index, allSessionData)" type="text" size="small">移除</el-button> | ||
| 39 | + </template> | ||
| 40 | + </el-table-column> | ||
| 41 | + </el-table> | ||
| 42 | + | ||
| 43 | + </el-main> | ||
| 44 | + <!-- <el-footer style="position: absolute; bottom: 0; width: 100%;">ZLMediaKit-VUE_UI v1</el-footer> --> | ||
| 45 | + </el-container> | ||
| 46 | + | ||
| 47 | + </div> | ||
| 48 | +</template> | ||
| 49 | + | ||
| 50 | +<script> | ||
| 51 | + | ||
| 52 | +import uiHeader from './UiHeader.vue' | ||
| 53 | + | ||
| 54 | +import echarts from 'echarts'; | ||
| 55 | +export default { | ||
| 56 | + name: 'app', | ||
| 57 | + components: { | ||
| 58 | + echarts, | ||
| 59 | + uiHeader | ||
| 60 | + }, | ||
| 61 | + data() { | ||
| 62 | + return { | ||
| 63 | + tableOption: { | ||
| 64 | + // legend: {}, | ||
| 65 | + xAxis: {}, | ||
| 66 | + yAxis: {}, | ||
| 67 | + label: {}, | ||
| 68 | + tooltip: {}, | ||
| 69 | + dataZoom: [], | ||
| 70 | + series: [] | ||
| 71 | + }, | ||
| 72 | + table1Option: { | ||
| 73 | + // legend: {}, | ||
| 74 | + xAxis: {}, | ||
| 75 | + yAxis: {}, | ||
| 76 | + label: {}, | ||
| 77 | + tooltip: {}, | ||
| 78 | + series: [] | ||
| 79 | + }, | ||
| 80 | + mChart: null, | ||
| 81 | + mChart1: null, | ||
| 82 | + charZoomStart: 0, | ||
| 83 | + charZoomEnd: 100, | ||
| 84 | + chartInterval: 0, //更新图表统计图定时任务标识 | ||
| 85 | + allSessionData: [], | ||
| 86 | + visible: false, | ||
| 87 | + serverConfig: {} | ||
| 88 | + }; | ||
| 89 | + }, | ||
| 90 | + mounted() { | ||
| 91 | + this.getAllSession(); | ||
| 92 | + this.initTable(); | ||
| 93 | + this.updateData(); | ||
| 94 | + this.chartInterval = setInterval(this.updateData, 3000); | ||
| 95 | + }, | ||
| 96 | + destroyed() { | ||
| 97 | + clearInterval(this.chartInterval); //释放定时任务 | ||
| 98 | + }, | ||
| 99 | + methods: { | ||
| 100 | + updateData: function() { | ||
| 101 | + this.getThreadsLoad(); | ||
| 102 | + }, | ||
| 103 | + /** | ||
| 104 | + * 获取线程状态 | ||
| 105 | + */ | ||
| 106 | + getThreadsLoad: function() { | ||
| 107 | + let that = this; | ||
| 108 | + this.$axios({ | ||
| 109 | + method: 'get', | ||
| 110 | + url: '/zlm/index/api/getThreadsLoad' | ||
| 111 | + }).then(function(res) { | ||
| 112 | + if (res.data.code == 0) { | ||
| 113 | + that.tableOption.xAxis.data.push(new Date().toLocaleTimeString()); | ||
| 114 | + that.table1Option.xAxis.data.push(new Date().toLocaleTimeString()); | ||
| 115 | + | ||
| 116 | + for (var i = 0; i < res.data.data.length; i++) { | ||
| 117 | + if (that.tableOption.series[i] === undefined) { | ||
| 118 | + let data = { | ||
| 119 | + data: [], | ||
| 120 | + type: 'line' | ||
| 121 | + }; | ||
| 122 | + let data1 = { | ||
| 123 | + data: [], | ||
| 124 | + type: 'line' | ||
| 125 | + }; | ||
| 126 | + data.data.push(res.data.data[i].delay); | ||
| 127 | + data1.data.push(res.data.data[i].load); | ||
| 128 | + that.tableOption.series.push(data); | ||
| 129 | + that.table1Option.series.push(data1); | ||
| 130 | + } else { | ||
| 131 | + that.tableOption.series[i].data.push(res.data.data[i].delay); | ||
| 132 | + that.table1Option.series[i].data.push(res.data.data[i].load); | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | + that.tableOption.dataZoom[0].start = that.charZoomStart; | ||
| 136 | + that.tableOption.dataZoom[0].end = that.charZoomEnd; | ||
| 137 | + that.table1Option.dataZoom[0].start = that.charZoomStart; | ||
| 138 | + that.table1Option.dataZoom[0].end = that.charZoomEnd; | ||
| 139 | + //that.myChart = echarts.init(document.getElementById('ThreadsLoad')); | ||
| 140 | + that.myChart.setOption(that.tableOption, true); | ||
| 141 | + // that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad')); | ||
| 142 | + that.myChart1.setOption(that.table1Option, true); | ||
| 143 | + } | ||
| 144 | + }); | ||
| 145 | + }, | ||
| 146 | + initTable: function() { | ||
| 147 | + let that = this; | ||
| 148 | + this.tableOption.xAxis = { | ||
| 149 | + type: 'category', | ||
| 150 | + data: [], // x轴数据 | ||
| 151 | + name: '时间', // x轴名称 | ||
| 152 | + // x轴名称样式 | ||
| 153 | + nameTextStyle: { | ||
| 154 | + fontWeight: 300, | ||
| 155 | + fontSize: 15 | ||
| 156 | + } | ||
| 157 | + }; | ||
| 158 | + this.tableOption.yAxis = { | ||
| 159 | + type: 'value', | ||
| 160 | + name: '延迟率', // y轴名称 | ||
| 161 | + boundaryGap: [0, '100%'], | ||
| 162 | + max: 100, | ||
| 163 | + axisLabel: { | ||
| 164 | + show: true, | ||
| 165 | + interval: 'auto', | ||
| 166 | + formatter: '{value} %' | ||
| 167 | + }, | ||
| 168 | + // y轴名称样式 | ||
| 169 | + nameTextStyle: { | ||
| 170 | + fontWeight: 300, | ||
| 171 | + fontSize: 15 | ||
| 172 | + } | ||
| 173 | + }; | ||
| 174 | + this.tableOption.dataZoom = [ | ||
| 175 | + { | ||
| 176 | + show: true, | ||
| 177 | + start: this.charZoomStart, | ||
| 178 | + end: this.charZoomEnd | ||
| 179 | + } | ||
| 180 | + ]; | ||
| 181 | + this.myChart = echarts.init(document.getElementById('ThreadsLoad')); | ||
| 182 | + this.myChart.setOption(this.tableOption); | ||
| 183 | + this.myChart.on('dataZoom', function(event) { | ||
| 184 | + if (event.batch) { | ||
| 185 | + that.charZoomStart = event.batch[0].start; | ||
| 186 | + that.charZoomEnd = event.batch[0].end; | ||
| 187 | + } else { | ||
| 188 | + that.charZoomStart = event.start; | ||
| 189 | + that.charZoomEnd = event.end; | ||
| 190 | + } | ||
| 191 | + }); | ||
| 192 | + | ||
| 193 | + this.table1Option.xAxis = { | ||
| 194 | + type: 'category', | ||
| 195 | + data: [], // x轴数据 | ||
| 196 | + name: '时间', // x轴名称 | ||
| 197 | + // x轴名称样式 | ||
| 198 | + nameTextStyle: { | ||
| 199 | + fontWeight: 300, | ||
| 200 | + fontSize: 15 | ||
| 201 | + } | ||
| 202 | + }; | ||
| 203 | + this.table1Option.yAxis = { | ||
| 204 | + type: 'value', | ||
| 205 | + name: '负载率', // y轴名称 | ||
| 206 | + boundaryGap: [0, '100%'], | ||
| 207 | + max: 100, | ||
| 208 | + axisLabel: { | ||
| 209 | + show: true, | ||
| 210 | + interval: 'auto', | ||
| 211 | + formatter: '{value} %' | ||
| 212 | + }, | ||
| 213 | + // y轴名称样式 | ||
| 214 | + nameTextStyle: { | ||
| 215 | + fontWeight: 300, | ||
| 216 | + fontSize: 15 | ||
| 217 | + } | ||
| 218 | + }; | ||
| 219 | + this.table1Option.dataZoom = [ | ||
| 220 | + { | ||
| 221 | + show: true, | ||
| 222 | + start: this.charZoomStart, | ||
| 223 | + end: this.charZoomEnd | ||
| 224 | + } | ||
| 225 | + ]; | ||
| 226 | + this.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad')); | ||
| 227 | + this.myChart1.setOption(this.table1Option); | ||
| 228 | + this.myChart1.on('dataZoom', function(event) { | ||
| 229 | + if (event.batch) { | ||
| 230 | + that.charZoomStart = event.batch[0].start; | ||
| 231 | + that.charZoomEnd = event.batch[0].end; | ||
| 232 | + } else { | ||
| 233 | + that.charZoomStart = event.start; | ||
| 234 | + that.charZoomEnd = event.end; | ||
| 235 | + } | ||
| 236 | + }); | ||
| 237 | + }, | ||
| 238 | + | ||
| 239 | + getAllSession: function() { | ||
| 240 | + let that = this; | ||
| 241 | + that.allSessionData = []; | ||
| 242 | + console.log("地址:"+'/zlm/index/api/getAllSession'); | ||
| 243 | + this.$axios({ | ||
| 244 | + method: 'get', | ||
| 245 | + url: '/zlm/index/api/getAllSession' | ||
| 246 | + }).then(function(res) { | ||
| 247 | + res.data.data.forEach(item => { | ||
| 248 | + let data = { | ||
| 249 | + peer_ip: item.peer_ip, | ||
| 250 | + local_ip: item.local_ip, | ||
| 251 | + typeid: item.typeid, | ||
| 252 | + id: item.id | ||
| 253 | + }; | ||
| 254 | + that.allSessionData.push(data); | ||
| 255 | + }); | ||
| 256 | + }); | ||
| 257 | + }, | ||
| 258 | + getServerConfig: function() { | ||
| 259 | + let that = this; | ||
| 260 | + this.$axios({ | ||
| 261 | + method: 'get', | ||
| 262 | + url: '/zlm/index/api/getServerConfig' | ||
| 263 | + }).then(function(res) { | ||
| 264 | + that.serverConfig = res.data.data[0]; | ||
| 265 | + that.visible = true; | ||
| 266 | + }); | ||
| 267 | + }, | ||
| 268 | + reStartServer: function() { | ||
| 269 | + let that = this; | ||
| 270 | + this.$confirm('此操作将重启媒体服务器, 是否继续?', '提示', { | ||
| 271 | + confirmButtonText: '确定', | ||
| 272 | + cancelButtonText: '取消', | ||
| 273 | + type: 'warning' | ||
| 274 | + }).then(() => { | ||
| 275 | + let that = this; | ||
| 276 | + this.$axios({ | ||
| 277 | + method: 'get', | ||
| 278 | + url: '/zlm/index/api/restartServer' | ||
| 279 | + }).then(function(res) { | ||
| 280 | + that.getAllSession(); | ||
| 281 | + if (res.data.code == 0) { | ||
| 282 | + that.$message({ | ||
| 283 | + type: 'success', | ||
| 284 | + message: '操作完成' | ||
| 285 | + }); | ||
| 286 | + } | ||
| 287 | + }); | ||
| 288 | + }); | ||
| 289 | + }, | ||
| 290 | + deleteRow: function(index, tabledata) { | ||
| 291 | + let that = this; | ||
| 292 | + this.$confirm('此操作将断开该通信链路, 是否继续?', '提示', { | ||
| 293 | + confirmButtonText: '确定', | ||
| 294 | + cancelButtonText: '取消', | ||
| 295 | + type: 'warning' | ||
| 296 | + }) | ||
| 297 | + .then(() => { | ||
| 298 | + that.deleteSession(tabledata[index].id); | ||
| 299 | + }) | ||
| 300 | + .catch(() => { | ||
| 301 | + console.log('id:' + JSON.stringify(tabledata[index])); | ||
| 302 | + this.$message({ | ||
| 303 | + type: 'info', | ||
| 304 | + message: '已取消删除' | ||
| 305 | + }); | ||
| 306 | + }); | ||
| 307 | + console.log(JSON.stringify(tabledata[index])); | ||
| 308 | + }, | ||
| 309 | + deleteSession: function(id) { | ||
| 310 | + let that = this; | ||
| 311 | + this.$axios({ | ||
| 312 | + method: 'get', | ||
| 313 | + url: '/zlm/index/api/kick_session&id=' + id | ||
| 314 | + }).then(function(res) { | ||
| 315 | + that.getAllSession(); | ||
| 316 | + that.$message({ | ||
| 317 | + type: 'success', | ||
| 318 | + message: '删除成功!' | ||
| 319 | + }); | ||
| 320 | + }); | ||
| 321 | + } | ||
| 322 | + } | ||
| 323 | +}; | ||
| 324 | +</script> | ||
| 325 | + | ||
| 326 | +<style> | ||
| 327 | +#app { | ||
| 328 | + height: 100%; | ||
| 329 | +} | ||
| 330 | +.control-table { | ||
| 331 | + background-color: #ffffff; | ||
| 332 | + height: 25rem; | ||
| 333 | +} | ||
| 334 | +.table-c { | ||
| 335 | + border-right: 1px solid #dcdcdc; | ||
| 336 | + border-bottom: 1px solid #dcdcdc; | ||
| 337 | +} | ||
| 338 | +.table-c td { | ||
| 339 | + border-left: 1px solid #dcdcdc; | ||
| 340 | + border-top: 1px solid #dcdcdc; | ||
| 341 | + padding: 0.2rem; | ||
| 342 | +} | ||
| 343 | +.el-table { | ||
| 344 | + width: 99.9% !important; | ||
| 345 | +} | ||
| 346 | +</style> |
web_src/src/components/gb28181/devicePlayer.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div id="devicePlayer"> | ||
| 3 | + <el-dialog title="视频播放" top="0" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="stop()"> | ||
| 4 | + <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" fluent autoplay live stretch></LivePlayer> | ||
| 5 | + <div id="shared" style="text-align: right; margin-top: 1rem;"> | ||
| 6 | + <el-tabs v-model="tabActiveName"> | ||
| 7 | + <el-tab-pane label="媒体流信息" name="media"> | ||
| 8 | + <div style="margin-bottom: 0.5rem;"> | ||
| 9 | + <el-button type="primary" size="small" @click="playRecord(true, '')">播放</el-button> | ||
| 10 | + <el-button type="primary" size="small" @click="startRecord()">录制</el-button> | ||
| 11 | + <el-button type="primary" size="small" @click="stopRecord()">停止录制</el-button> | ||
| 12 | + </div> | ||
| 13 | + <div style="display: flex; margin-bottom: 0.5rem; height: 2.5rem;"> | ||
| 14 | + <span style="width: 5rem; line-height: 2.5rem; text-align: right;">播放地址:</span> | ||
| 15 | + <el-input v-model="getPlayerShared.sharedUrl" :disabled="true" v-on:click.native="copySharedInfo(getPlayerShared.sharedUrl)"></el-input> | ||
| 16 | + </div> | ||
| 17 | + <div style="display: flex; margin-bottom: 0.5rem; height: 2.5rem;"> | ||
| 18 | + <span style="width: 5rem; line-height: 2.5rem; text-align: right;">iframe:</span> | ||
| 19 | + <el-input v-model="getPlayerShared.sharedIframe" :disabled="true" v-on:click.native="copySharedInfo(getPlayerShared.sharedIframe)"></el-input> | ||
| 20 | + </div> | ||
| 21 | + <div style="display: flex; margin-bottom: 0.5rem; height: 2.5rem;"> | ||
| 22 | + <span style="width: 5rem; line-height: 2.5rem; text-align: right;">资源地址:</span> | ||
| 23 | + <el-input v-model="getPlayerShared.sharedRtmp" :disabled="true" v-on:click.native="copySharedInfo(getPlayerShared.sharedRtmp)"></el-input> | ||
| 24 | + </div> | ||
| 25 | + </el-tab-pane> | ||
| 26 | + <!--{"code":0,"data":{"paths":["22-29-30.mp4"],"rootPath":"/home/kkkkk/Documents/ZLMediaKit/release/linux/Debug/www/record/hls/kkkkk/2020-05-11/"}}--> | ||
| 27 | + <el-tab-pane label="录像查询" name="second"> | ||
| 28 | + <el-date-picker v-model="videoHistory.startTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="开始时间" | ||
| 29 | + @change="recordList()"></el-date-picker> | ||
| 30 | + <el-date-picker v-model="videoHistory.endTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="结束时间" | ||
| 31 | + @change="recordList()"></el-date-picker> | ||
| 32 | + <el-table :data="videoHistory.searchHistoryResult" style="width: 100%"> | ||
| 33 | + <el-table-column label="名称" prop="name" width="150"></el-table-column> | ||
| 34 | + <el-table-column label="文件" prop="filePath" width="300"></el-table-column> | ||
| 35 | + <el-table-column label="开始时间" prop="startTime" width="160"></el-table-column> | ||
| 36 | + <el-table-column label="结束时间" prop="endTime" width="160"></el-table-column> | ||
| 37 | + | ||
| 38 | + <el-table-column label="操作"> | ||
| 39 | + <template slot-scope="scope"> | ||
| 40 | + <el-button type="primary" size="mini" @click="playRecord(false, scope.row)">播放</el-button> | ||
| 41 | + </template> | ||
| 42 | + </el-table-column> | ||
| 43 | + </el-table> | ||
| 44 | + </el-tab-pane> | ||
| 45 | + <!--遥控界面--> | ||
| 46 | + <el-tab-pane label="云台控制" name="third"> | ||
| 47 | + <div style="display: flex; justify-content: center;"> | ||
| 48 | + <div class="control-wrapper"> | ||
| 49 | + <div class="control-btn control-top" @mousedown="ptzCamera(0, 1, 0)" @mouseup="ptzCamera(0, 0, 0)"> | ||
| 50 | + <i class="el-icon-caret-top"></i> | ||
| 51 | + <div class="control-inner-btn control-inner"></div> | ||
| 52 | + </div> | ||
| 53 | + <div class="control-btn control-left" @mousedown="ptzCamera(1, 0, 0)" @mouseup="ptzCamera(0, 0, 0)"> | ||
| 54 | + <i class="el-icon-caret-left"></i> | ||
| 55 | + <div class="control-inner-btn control-inner"></div> | ||
| 56 | + </div> | ||
| 57 | + <div class="control-btn control-bottom" @mousedown="ptzCamera(0, 2, 0)" @mouseup="ptzCamera(0, 0, 0)"> | ||
| 58 | + <i class="el-icon-caret-bottom"></i> | ||
| 59 | + <div class="control-inner-btn control-inner"></div> | ||
| 60 | + </div> | ||
| 61 | + <div class="control-btn control-right" @mousedown="ptzCamera(2, 0, 0)" @mouseup="ptzCamera(0, 0, 0)"> | ||
| 62 | + <i class="el-icon-caret-right"></i> | ||
| 63 | + <div class="control-inner-btn control-inner"></div> | ||
| 64 | + </div> | ||
| 65 | + <div class="control-round"> | ||
| 66 | + <div class="control-round-inner"><i class="fa fa-pause-circle"></i></div> | ||
| 67 | + </div> | ||
| 68 | + | ||
| 69 | + <div style="position: absolute; left: 7.25rem; top: 1.25rem" @mousedown="ptzCamera(0, 0, 2)" @mouseup="ptzCamera(0, 0, 0)"><i | ||
| 70 | + class="el-icon-zoom-in" style="font-size: 1.875rem;"></i></div> | ||
| 71 | + <div style="position: absolute; left: 7.25rem; top: 3.25rem; font-size: 1.875rem;" @mousedown="ptzCamera(0, 0, 1)" | ||
| 72 | + @mouseup="ptzCamera(0, 0, 0)"><i class="el-icon-zoom-out"></i></div> | ||
| 73 | + </div> | ||
| 74 | + </div> | ||
| 75 | + | ||
| 76 | + </el-tab-pane> | ||
| 77 | + </el-tabs> | ||
| 78 | + </div> | ||
| 79 | + </el-dialog> | ||
| 80 | + </div> | ||
| 81 | +</template> | ||
| 82 | + | ||
| 83 | +<script> | ||
| 84 | + import LivePlayer from '@liveqing/liveplayer' | ||
| 85 | + export default { | ||
| 86 | + name: 'devicePlayer', | ||
| 87 | + props: {}, | ||
| 88 | + components: { | ||
| 89 | + LivePlayer | ||
| 90 | + }, | ||
| 91 | + computed: { | ||
| 92 | + getPlayerShared: function() { | ||
| 93 | + return { | ||
| 94 | + sharedUrl: window.location.host + '/' + this.videoUrl, | ||
| 95 | + sharedIframe: '<iframe src="' + window.location.host + '/' + this.videoUrl + '"></iframe>', | ||
| 96 | + sharedRtmp: this.videoUrl | ||
| 97 | + }; | ||
| 98 | + } | ||
| 99 | + }, | ||
| 100 | + created() { | ||
| 101 | + // this.videoHistory.searchHistoryResult = falsificationData.recordData.recordList; | ||
| 102 | + }, | ||
| 103 | + data() { | ||
| 104 | + return { | ||
| 105 | + video:'http://lndxyj.iqilu.com/public/upload/2019/10/14/8c001ea0c09cdc59a57829dabc8010fa.mp4', | ||
| 106 | + videoUrl: '', | ||
| 107 | + videoHistory: { | ||
| 108 | + startTime: '', | ||
| 109 | + endTime: '', | ||
| 110 | + searchHistoryResult: [] //媒体流历史记录搜索结果 | ||
| 111 | + }, | ||
| 112 | + showVideoDialog: false, | ||
| 113 | + normalssrc: '', | ||
| 114 | + ssrc: '', | ||
| 115 | + deviceId: '', | ||
| 116 | + channelId: '', | ||
| 117 | + tabActiveName: 'media' | ||
| 118 | + }; | ||
| 119 | + }, | ||
| 120 | + methods: { | ||
| 121 | + | ||
| 122 | + play: function(streamInfo, deviceId, channelId) { | ||
| 123 | + this.ssrc = streamInfo.ssrc; | ||
| 124 | + this.deviceId = deviceId; | ||
| 125 | + this.channelId = channelId; | ||
| 126 | + this.videoUrl = streamInfo.flv + "?" + new Date().getTime(); | ||
| 127 | + this.showVideoDialog = true; | ||
| 128 | + console.log(this.ssrc); | ||
| 129 | + }, | ||
| 130 | + stop: function() { | ||
| 131 | + console.log('关闭视频'); | ||
| 132 | + this.$refs.videoPlayer.pause(); | ||
| 133 | + this.videoUrl = ''; | ||
| 134 | + this.showVideoDialog = false; | ||
| 135 | + this.$axios({ | ||
| 136 | + method: 'post', | ||
| 137 | + url: '/api/play/' + this.ssrc + '/stop' | ||
| 138 | + }).then(function(res) { | ||
| 139 | + console.log(JSON.stringify(res)); | ||
| 140 | + }); | ||
| 141 | + | ||
| 142 | + this.$axios({ | ||
| 143 | + method: 'post', | ||
| 144 | + url: '/api/playback/' + this.ssrc + '/stop' | ||
| 145 | + }).then(function(res) { | ||
| 146 | + console.log(JSON.stringify(res)); | ||
| 147 | + }); | ||
| 148 | + }, | ||
| 149 | + copySharedInfo: function(data) { | ||
| 150 | + console.log('复制内容:' + data); | ||
| 151 | + let _this = this; | ||
| 152 | + this.$copyText(data).then( | ||
| 153 | + function(e) { | ||
| 154 | + _this.$message({ | ||
| 155 | + showClose: true, | ||
| 156 | + message: '复制成功', | ||
| 157 | + type: 'success' | ||
| 158 | + }); | ||
| 159 | + }, | ||
| 160 | + function(e) { | ||
| 161 | + _this.$message({ | ||
| 162 | + showClose: true, | ||
| 163 | + message: '复制失败,请手动复制', | ||
| 164 | + type: 'error' | ||
| 165 | + }); | ||
| 166 | + } | ||
| 167 | + ); | ||
| 168 | + }, | ||
| 169 | + | ||
| 170 | + recordList: function() { | ||
| 171 | + if (!this.videoHistory.startTime || !this.videoHistory.endTime) { | ||
| 172 | + return; | ||
| 173 | + } | ||
| 174 | + let that = this; | ||
| 175 | + this.$axios({ | ||
| 176 | + method: 'get', | ||
| 177 | + url: '/api/record/' + this.deviceId + '/' + this.channelId + '?startTime=' + this.videoHistory | ||
| 178 | + .startTime + '&endTime=' + this.videoHistory.endTime | ||
| 179 | + }).then(function(res) { | ||
| 180 | + console.log(JSON.stringify(res)); | ||
| 181 | + }).catch(function(e) { | ||
| 182 | + // that.videoHistory.searchHistoryResult = falsificationData.recordData; | ||
| 183 | + }); | ||
| 184 | + | ||
| 185 | + }, | ||
| 186 | + playRecord: function(isBackLive, rowData) { | ||
| 187 | + let that = this; | ||
| 188 | + if(isBackLive){ | ||
| 189 | + this.videoUrl=this.getVideoUrlBySsrc(this.normalssrc); | ||
| 190 | + return; | ||
| 191 | + } | ||
| 192 | + this.$axios({ | ||
| 193 | + method: 'get', | ||
| 194 | + url: '/api/playback/' + this.deviceId + '/' + this.channelId + '?startTime=' + rowData.startTime + '&endTime=' + | ||
| 195 | + rowData.endTime | ||
| 196 | + }).then(function(res) { | ||
| 197 | + let ssrc = res.data.ssrc; | ||
| 198 | + that.videoUrl = that.getVideoUrlBySsrc(ssrc); | ||
| 199 | + //that.videoUrl='http://hls.cntv.kcdnvip.com/asp/hls/main/0303000a/3/default/f466089412c04a759c5515dbfcc3ac3d/main.m3u8?maxbr=2048'; | ||
| 200 | + }); | ||
| 201 | + | ||
| 202 | + }, | ||
| 203 | + ptzCamera: function(leftRight, upDown, zoom) { | ||
| 204 | + console.log('云台控制:' + leftRight + ' : ' + upDown + " : " + zoom); | ||
| 205 | + let that = this; | ||
| 206 | + this.$axios({ | ||
| 207 | + method: 'post', | ||
| 208 | + url: '/api/ptz/' + this.deviceId + '/' + this.channelId + '?leftRight=' + leftRight + '&upDown=' + upDown + | ||
| 209 | + '&inOut=' + zoom + '&moveSpeed=50&zoomSpeed=50' | ||
| 210 | + }).then(function(res) {}); | ||
| 211 | + }, | ||
| 212 | + //////////////////////播放器事件处理////////////////////////// | ||
| 213 | + videoError:function(e){ | ||
| 214 | + console.log("播放器错误:"+JSON.stringify(e)); | ||
| 215 | + } | ||
| 216 | + } | ||
| 217 | + }; | ||
| 218 | +</script> | ||
| 219 | + | ||
| 220 | +<style> | ||
| 221 | + .control-wrapper { | ||
| 222 | + position: relative; | ||
| 223 | + width: 6.25rem; | ||
| 224 | + height: 6.25rem; | ||
| 225 | + max-width: 6.25rem; | ||
| 226 | + max-height: 6.25rem; | ||
| 227 | + margin: 0 auto; | ||
| 228 | + border-radius: 100%; | ||
| 229 | + float: left; | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | + .control-btn { | ||
| 233 | + display: flex; | ||
| 234 | + justify-content: center; | ||
| 235 | + position: absolute; | ||
| 236 | + width: 44%; | ||
| 237 | + height: 44%; | ||
| 238 | + border-radius: 5px; | ||
| 239 | + border: 1px solid #78aee4; | ||
| 240 | + box-sizing: border-box; | ||
| 241 | + transition: all 0.3s linear; | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + .control-btn i { | ||
| 245 | + font-size: 20px; | ||
| 246 | + color: #78aee4; | ||
| 247 | + display: flex; | ||
| 248 | + justify-content: center; | ||
| 249 | + align-items: center; | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + .control-round { | ||
| 253 | + position: absolute; | ||
| 254 | + top: 21%; | ||
| 255 | + left: 21%; | ||
| 256 | + width: 58%; | ||
| 257 | + height: 58%; | ||
| 258 | + background: #fff; | ||
| 259 | + border-radius: 100%; | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | + .control-round-inner { | ||
| 263 | + position: absolute; | ||
| 264 | + left: 15%; | ||
| 265 | + top: 15%; | ||
| 266 | + display: flex; | ||
| 267 | + justify-content: center; | ||
| 268 | + align-items: center; | ||
| 269 | + width: 70%; | ||
| 270 | + height: 70%; | ||
| 271 | + font-size: 40px; | ||
| 272 | + color: #78aee4; | ||
| 273 | + border: 1px solid #78aee4; | ||
| 274 | + border-radius: 100%; | ||
| 275 | + transition: all 0.3s linear; | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + .control-inner-btn { | ||
| 279 | + position: absolute; | ||
| 280 | + width: 60%; | ||
| 281 | + height: 60%; | ||
| 282 | + background: #fafafa; | ||
| 283 | + } | ||
| 284 | + | ||
| 285 | + .control-top { | ||
| 286 | + top: -8%; | ||
| 287 | + left: 27%; | ||
| 288 | + transform: rotate(-45deg); | ||
| 289 | + border-radius: 5px 100% 5px 0; | ||
| 290 | + } | ||
| 291 | + | ||
| 292 | + .control-top i { | ||
| 293 | + transform: rotate(45deg); | ||
| 294 | + border-radius: 5px 100% 5px 0; | ||
| 295 | + } | ||
| 296 | + | ||
| 297 | + .control-top .control-inner { | ||
| 298 | + left: -1px; | ||
| 299 | + bottom: 0; | ||
| 300 | + border-top: 1px solid #78aee4; | ||
| 301 | + border-right: 1px solid #78aee4; | ||
| 302 | + border-radius: 0 100% 0 0; | ||
| 303 | + } | ||
| 304 | + | ||
| 305 | + .control-top .fa { | ||
| 306 | + transform: rotate(45deg) translateY(-7px); | ||
| 307 | + } | ||
| 308 | + | ||
| 309 | + .control-left { | ||
| 310 | + top: 27%; | ||
| 311 | + left: -8%; | ||
| 312 | + transform: rotate(45deg); | ||
| 313 | + border-radius: 5px 0 5px 100%; | ||
| 314 | + } | ||
| 315 | + | ||
| 316 | + .control-left i { | ||
| 317 | + transform: rotate(-45deg); | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + .control-left .control-inner { | ||
| 321 | + right: -1px; | ||
| 322 | + top: -1px; | ||
| 323 | + border-bottom: 1px solid #78aee4; | ||
| 324 | + border-left: 1px solid #78aee4; | ||
| 325 | + border-radius: 0 0 0 100%; | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + .control-left .fa { | ||
| 329 | + transform: rotate(-45deg) translateX(-7px); | ||
| 330 | + } | ||
| 331 | + | ||
| 332 | + .control-right { | ||
| 333 | + top: 27%; | ||
| 334 | + right: -8%; | ||
| 335 | + transform: rotate(45deg); | ||
| 336 | + border-radius: 5px 100% 5px 0; | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + .control-right i { | ||
| 340 | + transform: rotate(-45deg); | ||
| 341 | + } | ||
| 342 | + | ||
| 343 | + .control-right .control-inner { | ||
| 344 | + left: -1px; | ||
| 345 | + bottom: -1px; | ||
| 346 | + border-top: 1px solid #78aee4; | ||
| 347 | + border-right: 1px solid #78aee4; | ||
| 348 | + border-radius: 0 100% 0 0; | ||
| 349 | + } | ||
| 350 | + | ||
| 351 | + .control-right .fa { | ||
| 352 | + transform: rotate(-45deg) translateX(7px); | ||
| 353 | + } | ||
| 354 | + | ||
| 355 | + .control-bottom { | ||
| 356 | + left: 27%; | ||
| 357 | + bottom: -8%; | ||
| 358 | + transform: rotate(45deg); | ||
| 359 | + border-radius: 0 5px 100% 5px; | ||
| 360 | + } | ||
| 361 | + | ||
| 362 | + .control-bottom i { | ||
| 363 | + transform: rotate(-45deg); | ||
| 364 | + } | ||
| 365 | + | ||
| 366 | + .control-bottom .control-inner { | ||
| 367 | + top: -1px; | ||
| 368 | + left: -1px; | ||
| 369 | + border-bottom: 1px solid #78aee4; | ||
| 370 | + border-right: 1px solid #78aee4; | ||
| 371 | + border-radius: 0 0 100% 0; | ||
| 372 | + } | ||
| 373 | + | ||
| 374 | + .control-bottom .fa { | ||
| 375 | + transform: rotate(-45deg) translateY(7px); | ||
| 376 | + } | ||
| 377 | +</style> |
web_src/src/components/videoList.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div id="app"> | ||
| 3 | + <el-container> | ||
| 4 | + | ||
| 5 | + <el-header> | ||
| 6 | + <uiHeader></uiHeader> | ||
| 7 | + </el-header> | ||
| 8 | + <el-main> | ||
| 9 | + <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> | ||
| 10 | + <span style="font-size: 1rem; font-weight: bold;">设备列表</span> | ||
| 11 | + <div style="position: absolute; right: 1rem; top: 0.3rem;"> | ||
| 12 | + <el-button icon="el-icon-refresh-right" circle size="mini" @click="getDeviceList()"></el-button> | ||
| 13 | + </div> | ||
| 14 | + </div> | ||
| 15 | + <devicePlayer ref="devicePlayer"></devicePlayer> | ||
| 16 | + <!--设备列表--> | ||
| 17 | + <el-table :data="deviceList" border style="width: 100%" :height="winHeight"> | ||
| 18 | + <el-table-column prop="name" label="名称" width="180" align="center"> | ||
| 19 | + </el-table-column> | ||
| 20 | + <el-table-column prop="deviceId" label="设备编号" width="240" align="center"> | ||
| 21 | + </el-table-column> | ||
| 22 | + <el-table-column label="地址" width="180" align="center"> | ||
| 23 | + <template slot-scope="scope"> | ||
| 24 | + <div slot="reference" class="name-wrapper"> | ||
| 25 | + <el-tag size="medium">{{ scope.row.host.address }}</el-tag> | ||
| 26 | + </div> | ||
| 27 | + </template> | ||
| 28 | + </el-table-column> | ||
| 29 | + <el-table-column prop="manufacturer" label="厂家" align="center"> | ||
| 30 | + </el-table-column> | ||
| 31 | + <el-table-column prop="model" label="固件版本" align="center"> | ||
| 32 | + </el-table-column> | ||
| 33 | + <el-table-column prop="transport" label="通讯方式" align="center"> | ||
| 34 | + </el-table-column> | ||
| 35 | + <el-table-column prop="channelCount" label="通道数" align="center"> | ||
| 36 | + </el-table-column> | ||
| 37 | + <el-table-column label="状态" width="180" align="center"> | ||
| 38 | + <template slot-scope="scope"> | ||
| 39 | + <div slot="reference" class="name-wrapper"> | ||
| 40 | + <el-tag size="medium">{{ scope.row.online==1?'在线' :'离线'}}</el-tag> | ||
| 41 | + </div> | ||
| 42 | + </template> | ||
| 43 | + </el-table-column> | ||
| 44 | + | ||
| 45 | + <el-table-column label="操作" width="240" align="center" fixed="right"> | ||
| 46 | + <template slot-scope="scope"> | ||
| 47 | + <el-button size="mini" icon="el-icon-refresh" @click="refDevice(scope.row)">刷新</el-button> | ||
| 48 | + <el-button size="mini" icon="el-icon-s-open" type="primary" @click="showChannelList(scope.row)">查看通道</el-button> | ||
| 49 | + </template> | ||
| 50 | + </el-table-column> | ||
| 51 | + </el-table> | ||
| 52 | + <el-pagination | ||
| 53 | + style="float: right" | ||
| 54 | + @size-change="handleSizeChange" | ||
| 55 | + @current-change="currentChange" | ||
| 56 | + :current-page="currentPage" | ||
| 57 | + :page-size="count" | ||
| 58 | + :page-sizes="[15, 25, 35, 50]" | ||
| 59 | + layout="total, sizes, prev, pager, next" | ||
| 60 | + :total="total"> | ||
| 61 | + </el-pagination> | ||
| 62 | + | ||
| 63 | + </el-main> | ||
| 64 | + </el-container> | ||
| 65 | + </div> | ||
| 66 | +</template> | ||
| 67 | + | ||
| 68 | +<script> | ||
| 69 | + import devicePlayer from './gb28181/devicePlayer.vue' | ||
| 70 | + import uiHeader from './UiHeader.vue' | ||
| 71 | + export default { | ||
| 72 | + name: 'app', | ||
| 73 | + components: { | ||
| 74 | + devicePlayer, | ||
| 75 | + uiHeader | ||
| 76 | + }, | ||
| 77 | + data() { | ||
| 78 | + return { | ||
| 79 | + deviceList: [], //设备列表 | ||
| 80 | + currentDevice: {}, //当前操作设备对象 | ||
| 81 | + | ||
| 82 | + videoComponentList: [], | ||
| 83 | + updateLooper: 0, //数据刷新轮训标志 | ||
| 84 | + currentDeviceChannelsLenth:0, | ||
| 85 | + winHeight: window.innerHeight - 200, | ||
| 86 | + currentPage:1, | ||
| 87 | + count:15, | ||
| 88 | + total:0 | ||
| 89 | + }; | ||
| 90 | + }, | ||
| 91 | + computed: { | ||
| 92 | + getcurrentDeviceChannels: function() { | ||
| 93 | + let data = this.currentDevice['channelMap']; | ||
| 94 | + let channels = null; | ||
| 95 | + if (data) { | ||
| 96 | + channels = Object.keys(data).map(key => { | ||
| 97 | + return data[key]; | ||
| 98 | + }); | ||
| 99 | + this.currentDeviceChannelsLenth = channels.length; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + console.log("数据:" + JSON.stringify(channels)); | ||
| 103 | + return channels; | ||
| 104 | + } | ||
| 105 | + }, | ||
| 106 | + mounted() { | ||
| 107 | + this.initData(); | ||
| 108 | + this.updateLooper = setInterval(this.initData, 10000); | ||
| 109 | + }, | ||
| 110 | + destroyed() { | ||
| 111 | + this.$destroy('videojs'); | ||
| 112 | + clearTimeout(this.updateLooper); | ||
| 113 | + }, | ||
| 114 | + methods: { | ||
| 115 | + initData: function() { | ||
| 116 | + this.getDeviceList(); | ||
| 117 | + }, | ||
| 118 | + currentChange: function(val){ | ||
| 119 | + this.currentPage = val; | ||
| 120 | + this.getDeviceList(); | ||
| 121 | + }, | ||
| 122 | + handleSizeChange: function(val){ | ||
| 123 | + this.count = val; | ||
| 124 | + this.getDeviceList(); | ||
| 125 | + }, | ||
| 126 | + getDeviceList: function() { | ||
| 127 | + let that = this; | ||
| 128 | + | ||
| 129 | + this.$axios.get(`/api/devices`,{ | ||
| 130 | + params: { | ||
| 131 | + page: that.currentPage - 1, | ||
| 132 | + count: that.count | ||
| 133 | + } | ||
| 134 | + } ) | ||
| 135 | + .then(function (res) { | ||
| 136 | + console.log(res); | ||
| 137 | + that.total = res.data.total; | ||
| 138 | + that.deviceList = res.data.data; | ||
| 139 | + }) | ||
| 140 | + .catch(function (error) { | ||
| 141 | + console.log(error); | ||
| 142 | + }); | ||
| 143 | + | ||
| 144 | + }, | ||
| 145 | + showChannelList: function(row) { | ||
| 146 | + console.log(JSON.stringify(row)) | ||
| 147 | + this.$router.push(`/channelList/${row.deviceId}/0/15/1`); | ||
| 148 | + }, | ||
| 149 | + | ||
| 150 | + | ||
| 151 | + //gb28181平台对接 | ||
| 152 | + //刷新设备信息 | ||
| 153 | + refDevice: function(itemData) { | ||
| 154 | + ///api/devices/{deviceId}/sync | ||
| 155 | + console.log("刷新对应设备:" + itemData.deviceId); | ||
| 156 | + this.$axios({ | ||
| 157 | + method: 'post', | ||
| 158 | + url: '/api/devices/' + itemData.deviceId + '/sync' | ||
| 159 | + }).then(function(res) { | ||
| 160 | + // console.log("刷新设备结果:"+JSON.stringify(res)); | ||
| 161 | + }).catch(function(e) { | ||
| 162 | + that.$message({ | ||
| 163 | + showClose: true, | ||
| 164 | + message: '请求成功', | ||
| 165 | + type: 'success' | ||
| 166 | + }); | ||
| 167 | + });; | ||
| 168 | + }, | ||
| 169 | + //通知设备上传媒体流 | ||
| 170 | + sendDevicePush: function(itemData) { | ||
| 171 | + let deviceId = this.currentDevice.deviceId; | ||
| 172 | + let channelId = itemData.channelId; | ||
| 173 | + console.log("通知设备推流1:" + deviceId + " : " + channelId); | ||
| 174 | + let that = this; | ||
| 175 | + this.$axios({ | ||
| 176 | + method: 'get', | ||
| 177 | + url: '/api/play/' + deviceId + '/' + channelId | ||
| 178 | + }).then(function(res) { | ||
| 179 | + let ssrc = res.data.ssrc; | ||
| 180 | + that.$refs.devicePlayer.play(ssrc,deviceId,channelId); | ||
| 181 | + }).catch(function(e) { | ||
| 182 | + }); | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + } | ||
| 186 | + }; | ||
| 187 | +</script> | ||
| 188 | + | ||
| 189 | +<style> | ||
| 190 | + .videoList { | ||
| 191 | + display: flex; | ||
| 192 | + flex-wrap: wrap; | ||
| 193 | + align-content: flex-start; | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + .video-item { | ||
| 197 | + position: relative; | ||
| 198 | + width: 15rem; | ||
| 199 | + height: 10rem; | ||
| 200 | + margin-right: 1rem; | ||
| 201 | + background-color: #000000; | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + .video-item-img { | ||
| 205 | + position: absolute; | ||
| 206 | + top: 0; | ||
| 207 | + bottom: 0; | ||
| 208 | + left: 0; | ||
| 209 | + right: 0; | ||
| 210 | + margin: auto; | ||
| 211 | + width: 100%; | ||
| 212 | + height: 100%; | ||
| 213 | + } | ||
| 214 | + | ||
| 215 | + .video-item-img:after { | ||
| 216 | + content: ""; | ||
| 217 | + display: inline-block; | ||
| 218 | + position: absolute; | ||
| 219 | + z-index: 2; | ||
| 220 | + top: 0; | ||
| 221 | + bottom: 0; | ||
| 222 | + left: 0; | ||
| 223 | + right: 0; | ||
| 224 | + margin: auto; | ||
| 225 | + width: 3rem; | ||
| 226 | + height: 3rem; | ||
| 227 | + background-image: url("../assets/loading.png"); | ||
| 228 | + background-size: cover; | ||
| 229 | + background-color: #000000; | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | + .video-item-title { | ||
| 233 | + position: absolute; | ||
| 234 | + bottom: 0; | ||
| 235 | + color: #000000; | ||
| 236 | + background-color: #ffffff; | ||
| 237 | + line-height: 1.5rem; | ||
| 238 | + padding: 0.3rem; | ||
| 239 | + width: 14.4rem; | ||
| 240 | + } | ||
| 241 | +</style> |
web_src/src/main.js
0 → 100644
| 1 | +import Vue from 'vue'; | ||
| 2 | +import App from './App.vue'; | ||
| 3 | +Vue.config.productionTip = false; | ||
| 4 | +import ElementUI from 'element-ui'; | ||
| 5 | +import 'element-ui/lib/theme-chalk/index.css'; | ||
| 6 | +import router from './router/index.js'; | ||
| 7 | +import axios from 'axios'; | ||
| 8 | +import VueCookies from 'vue-cookies'; | ||
| 9 | + | ||
| 10 | +import echarts from 'echarts'; | ||
| 11 | +import VueClipboard from 'vue-clipboard2' | ||
| 12 | +Vue.use(VueClipboard) | ||
| 13 | +Vue.use(ElementUI); | ||
| 14 | +Vue.use(VueCookies); | ||
| 15 | +Vue.prototype.$axios = axios; | ||
| 16 | + | ||
| 17 | +axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : ""; | ||
| 18 | + | ||
| 19 | +Vue.prototype.$cookies.config(60*30); | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +new Vue({ | ||
| 23 | + router: router, | ||
| 24 | + render: h => h(App), | ||
| 25 | +}).$mount('#app') |