Monitor.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. <template>
  2. <div class="monitor-container">
  3. <el-breadcrumb separator-class="el-icon-arrow-right">
  4. <el-breadcrumb-item>监控系统</el-breadcrumb-item>
  5. <el-breadcrumb-item>监控</el-breadcrumb-item>
  6. </el-breadcrumb>
  7. <div class="monitor-wrap">
  8. <div class="video-box">
  9. <div
  10. class="video-container"
  11. ref="videoContainerRef"
  12. :style="{width:'100%',height:divMainHeight}"
  13. >
  14. <!-- 插件播放 -->
  15. <div v-show="playType==1" v-html="html" style="width:100%;height:100%"></div>
  16. <!-- 非插件播放 ,默认非插件播放-->
  17. <div
  18. v-show="playType==0"
  19. :class="{'videoItem':true,'a1':divNum==1,'a4':divNum==4,'a9':divNum==9,'selected':count==selected}"
  20. v-for="count in divNum"
  21. :key="count"
  22. @click="selectVideo(count)"
  23. >
  24. <video
  25. :id="'my-video'+count"
  26. class="video-js vjs-default-skin"
  27. controls
  28. autoplay
  29. muted
  30. style="width:100%;height:100%"
  31. ></video>
  32. </div>
  33. </div>
  34. <div v-show="playType==0" class="split-screen">
  35. <span class="sp sp01" @click="splitView(1)"></span>
  36. <span class="sp sp02" @click="splitView(4)"></span>
  37. <span class="sp sp03" @click="splitView(9)"></span>
  38. </div>
  39. </div>
  40. <div class="nav-box">
  41. <ul class="viewLists">
  42. <li
  43. v-for="(item,index) in Idlist"
  44. :key="index"
  45. :class="{'active':activeIndex==index}"
  46. @click="selectEquip(item.device_id,item.jktype,index)"
  47. >
  48. <span :class="['dot',item.status==1?'onLine':'outLine']"></span>
  49. {{item | formatName}}
  50. <span
  51. @click.stop="viewPhoto(item.device_id)"
  52. class="viewPhoto"
  53. v-if="item.photo_num"
  54. >查看图片</span>
  55. </li>
  56. </ul>
  57. <div class="splitPage" onselectstart="return false">
  58. <span class="arrow el-icon-caret-top" @click="splitPage('jian')"></span>
  59. <span>{{currPage}}</span>
  60. <span>/</span>
  61. <span>{{totalPage}}</span>
  62. <span class="arrow el-icon-caret-bottom" @click="splitPage('jia')"></span>
  63. </div>
  64. <div class="direc">
  65. <div @click="configCamera('takephoto','')" class="cameraCtr"></div>
  66. <div @mousedown="configCamera('move',0)" @mouseup="stopConfigCamera()" class="upCtr"></div>
  67. <div @mousedown="configCamera('move',1)" @mouseup="stopConfigCamera()" class="downCtr"></div>
  68. <div @mousedown="configCamera('move',2)" @mouseup="stopConfigCamera()" class="leftCtr"></div>
  69. <div @mousedown="configCamera('move',3)" @mouseup="stopConfigCamera()" class="rightCtr"></div>
  70. </div>
  71. <div class="btnBox">
  72. <div class="zoom">
  73. <!-- 无论插件还是费插件都可以放大缩小 -->
  74. <span class="addCtr" @mousedown="configCamera('move',8)" @mouseup="stopConfigCamera()"></span>
  75. <span class="reduceCtr" @mousedown="configCamera('move',9)" @mouseup="stopConfigCamera()"></span>
  76. </div>
  77. <div v-show="playBackCtr" class="playBack" id="playBack"></div>
  78. <div v-show="playType==0" @click="checkPlayType(1)" class="playtype1"></div>
  79. <div v-show="playType==1" @click="checkPlayType(0)" class="playtype0"></div>
  80. <div @click="addEquip()" class="addequip"></div>
  81. </div>
  82. </div>
  83. </div>
  84. <!-- 拍照 -->
  85. <el-dialog title="手动下载" :visible.sync="takePhotoDialogVisible" width="30%">
  86. <el-input type="textarea" id="picUrl" v-model="picUrl"></el-input>
  87. <span slot="footer" class="dialog-footer">
  88. <el-button @click="dialogVisible = false">取 消</el-button>
  89. <el-button type="primary" @click="copyPicUrl">复制</el-button>
  90. </span>
  91. </el-dialog>
  92. <!-- 查看回放 -->
  93. <el-dialog title="查看回放" :visible.sync="playBackDialogVisible" width="30%">
  94. <div>123</div>
  95. </el-dialog>
  96. </div>
  97. </template>
  98. <script>
  99. import '@/plugin/ezuikit.js'
  100. import videojs from 'video.js'
  101. import 'videojs-contrib-hls'
  102. import 'video.js/dist/video-js.css'
  103. videojs.options.flash.swf = '/js/video-js.swf'
  104. export default {
  105. data() {
  106. return {
  107. currPage: 1, //当前分页
  108. totalPage: 0, //总分页
  109. id: '', //右侧菜单选中的设备ID
  110. activeIndex: 0, //控制设备列表选中状态
  111. jktype: '', //为1有回放,否则无回放
  112. playBackCtr: false, //控制回放按钮显示
  113. divNum: 1, //默认分屏数量
  114. hlsHdSrc: '',
  115. rtmpHdSrc: '',
  116. player: null, //videojs的对象
  117. takePhotoDialogVisible: false, //拍照弹框
  118. Idlist: [], //右侧设备列表
  119. divMainHeight: '', //视频盒子高度
  120. selected: 1, //默认选中第一个视频窗口
  121. playType: 0, //0:直播 ; 1:插件
  122. html: '', //插件播放内容
  123. picUrl: '', //视频拍照地址
  124. playBackDialogVisible: false,
  125. mapTojkId: this.$route.query.id, //四情基地监控设备id
  126. mapTojktype: this.$route.query.jktype, //四情基地监控设备jktype
  127. player: {}
  128. }
  129. },
  130. filters: {
  131. formatName: function (value) {
  132. //设备名字
  133. if (value.equip_name) {
  134. return value.equip_name
  135. } else {
  136. return '设备' + value.device_id
  137. }
  138. }
  139. },
  140. mounted() {
  141. this.getJkList()
  142. this.windowResize()
  143. window.onresize = () => {
  144. this.windowResize()
  145. }
  146. },
  147. //注销window.onresize事件
  148. destroyed() {
  149. window.onresize = null
  150. this.player.dispose()
  151. },
  152. methods: {
  153. viewPhoto(id) {
  154. this.$router.push('/index/photoView/' + id)
  155. },
  156. //获取视频列表
  157. getJkList() {
  158. this.$axios({
  159. method: 'POST',
  160. url: '/api/api_gateway?method=camera.camera_manage.list_camera',
  161. data: this.qs.stringify({ page: this.currPage })
  162. }).then((res) => {
  163. if (res.data.message == '') {
  164. this.Idlist = res.data.data.data
  165. this.totalPage = Math.ceil(res.data.data.counts / 10)
  166. if (this.mapTojkId && this.mapTojktype) {
  167. //基地展示跳转过来
  168. this.selectEquip(this.mapTojkId, this.mapTojktype, 99999)
  169. } else {
  170. this.selectEquip(this.Idlist[0].device_id, this.Idlist[0].jktype, 0)
  171. }
  172. }
  173. })
  174. },
  175. //视频分页
  176. splitPage(str) {
  177. if (str == 'jian') {
  178. if (this.currPage > 1) {
  179. this.currPage--
  180. this.getJkList()
  181. }
  182. } else {
  183. if (this.currPage < this.totalPage) {
  184. this.currPage++
  185. this.getJkList()
  186. }
  187. }
  188. },
  189. //关闭方向
  190. stopConfigCamera() {
  191. this.$axios({
  192. method: 'POST',
  193. url: '/api/api_gateway?method=camera.camera_manage.ctrl_camera',
  194. data: this.qs.stringify({
  195. device_id: this.id,
  196. ctrl: 'stop'
  197. })
  198. })
  199. },
  200. //上下左右和拍照
  201. configCamera(ctrl, movenum) {
  202. if (ctrl == 'takephoto') {
  203. this.$axios({
  204. method: 'POST',
  205. url: '/api/api_gateway?method=camera.camera_manage.camera_takephoto',
  206. data: this.qs.stringify({
  207. device_id: this.id
  208. })
  209. }).then((res) => {
  210. let data = JSON.parse(res.data.data)
  211. if (data.code == 200) {
  212. this.picUrl = data.data.picUrl
  213. this.takePhotoDialogVisible = true
  214. } else {
  215. this.$message.error(data.msg)
  216. }
  217. })
  218. } else {
  219. //上下左右、放大、缩小
  220. this.$axios({
  221. method: 'POST',
  222. url: '/api/api_gateway?method=camera.camera_manage.ctrl_camera',
  223. data: this.qs.stringify({
  224. device_id: this.id,
  225. ctrl: ctrl,
  226. movenum: movenum
  227. })
  228. }).then((res) => {
  229. // if (res.data.message == '') {
  230. // this.$message.success('指令下发成功')
  231. // // this.stopConfigCamera() //关闭方向
  232. // }
  233. })
  234. }
  235. },
  236. //选中右侧菜单设备
  237. selectEquip(device_id, jktype, index) {
  238. this.jktype = jktype
  239. this.activeIndex = index //菜单选中状态
  240. this.id = device_id //保存选中的设备id
  241. if (jktype) {
  242. //控制回放按钮显示
  243. this.playBackCtr = true
  244. } else {
  245. this.playBackCtr = false
  246. }
  247. this.$axios({
  248. url: '/api/api_gateway?method=camera.camera_manage.addr_camera',
  249. method: 'POST',
  250. data: this.qs.stringify({ device_id: device_id })
  251. }).then((res) => {
  252. if (res.data.message == '') {
  253. var data = eval('(' + res.data.data + ')')
  254. this.hlsHdSrc = data.hlsHd
  255. this.rtmpHdSrc = data.rtmp
  256. if (this.playType == 1) {
  257. //插件
  258. this.html =
  259. '<video id="myPlayer" autoplay controls playsInline webkit-playsinline style="width:100%; height:100%;"><source src="' +
  260. this.rtmpHdSrc +
  261. '" type="application/x-mpegURL"></video>'
  262. setTimeout(() => {
  263. this.player = new EZUIKit.EZUIPlayer(myPlayer)
  264. this.player.play()
  265. }, 1000)
  266. } else if (this.playType == 0) {
  267. //非插件
  268. this.$nextTick(() => {
  269. this.player = videojs('my-video' + this.selected)
  270. this.player.reset()
  271. this.player.src({
  272. src: this.hlsHdSrc,
  273. type: 'application/x-mpegURL'
  274. })
  275. this.player.play()
  276. this.player.load()
  277. })
  278. }
  279. }
  280. })
  281. },
  282. //函数:获取尺寸
  283. windowResize() {
  284. // console.log(this.$refs.videoContainerRef.offsetWidth);
  285. this.divMainHeight =
  286. (this.$refs.videoContainerRef.offsetWidth * 8) / 16 + 22 + 'px'
  287. },
  288. //点击分屏
  289. splitView(num) {
  290. this.player = null
  291. this.divNum = num
  292. this.selected = 1
  293. },
  294. //点击视频
  295. selectVideo(i) {
  296. this.selected = i
  297. },
  298. //播放模式切换,插件/视频直播
  299. checkPlayType(i) {
  300. this.playType = i
  301. this.selectEquip(this.id, this.jktype, this.activeIndex)
  302. },
  303. //复制拍照地址
  304. copyPicUrl() {
  305. document.getElementById('picUrl').select()
  306. this.$message({
  307. showClose: true,
  308. message: '手动复制,在浏览器打开,另存为'
  309. })
  310. },
  311. //添加设备
  312. addEquip() {
  313. this.$prompt('添加设备id', '提示', {
  314. confirmButtonText: '确定',
  315. cancelButtonText: '取消'
  316. })
  317. .then(({ value }) => {
  318. this.$axios({
  319. method: 'POST',
  320. url: '/api/api_gateway?method=camera.camera_manage.add_camera',
  321. data: this.qs.stringify({ device_id: value })
  322. }).then((res) => {
  323. if (res.data.message == '') {
  324. console.log(456)
  325. this.getJkList()
  326. }
  327. })
  328. })
  329. .catch(() => {
  330. this.$message({
  331. type: 'info',
  332. message: '取消添加'
  333. })
  334. })
  335. }
  336. }
  337. }
  338. </script>
  339. <style lang='less' scoped>
  340. .monitor-container {
  341. display: flex;
  342. flex-direction: column;
  343. height: 100%;
  344. .monitor-wrap {
  345. display: flex;
  346. justify-content: space-between;
  347. background: #323a47;
  348. flex: 1;
  349. .video-box {
  350. flex: 1;
  351. padding: 10px;
  352. .video-container {
  353. width: 100%;
  354. background: rgb(97, 93, 93);
  355. display: flex;
  356. flex-wrap: wrap;
  357. .videoItem {
  358. border: 1px solid #000;
  359. box-sizing: border-box;
  360. }
  361. .videoItem:hover {
  362. border-color: aquamarine;
  363. }
  364. .selected {
  365. border: 1px solid aquamarine;
  366. }
  367. .a1 {
  368. width: 100%;
  369. height: 100%;
  370. }
  371. .a4 {
  372. width: 50%;
  373. height: 50%;
  374. }
  375. .a9 {
  376. width: 33.3%;
  377. height: 33.3%;
  378. }
  379. }
  380. .split-screen {
  381. display: flex;
  382. justify-content: flex-start;
  383. padding: 15px 0;
  384. .sp {
  385. width: 17px;
  386. height: 17px;
  387. display: inline-block;
  388. margin-right: 10px;
  389. cursor: pointer;
  390. }
  391. .sp01 {
  392. background: url(../../../assets/images/forecasting/monitor/sp1.png);
  393. }
  394. .sp02 {
  395. background: url(../../../assets/images/forecasting/monitor/sp2.png);
  396. }
  397. .sp03 {
  398. background: url(../../../assets/images/forecasting/monitor/sp3.png);
  399. }
  400. .sp01:hover {
  401. background: url(../../../assets/images/forecasting/monitor/sp1-active.png);
  402. }
  403. .sp02:hover {
  404. background: url(../../../assets/images/forecasting/monitor/sp2-active.png);
  405. }
  406. .sp03:hover {
  407. background: url(../../../assets/images/forecasting/monitor/sp3-active.png);
  408. }
  409. }
  410. }
  411. .nav-box {
  412. width: 240px;
  413. background: #474e60;
  414. color: #fff;
  415. font-size: 14px;
  416. .viewLists {
  417. height: 50%;
  418. overflow: auto;
  419. li {
  420. padding-left: 25px;
  421. padding-right: 25px;
  422. line-height: 50px;
  423. cursor: pointer;
  424. .viewPhoto {
  425. color: #eba219;
  426. float: right;
  427. font-size: 12px;
  428. cursor: pointer;
  429. }
  430. .viewPhoto:hover {
  431. text-decoration: underline;
  432. }
  433. .dot {
  434. display: inline-block;
  435. width: 7px;
  436. height: 7px;
  437. border-radius: 100%;
  438. margin-right: 15px;
  439. }
  440. .onLine {
  441. background: #15bb88;
  442. }
  443. .outLine {
  444. background: #c1c1c1;
  445. }
  446. }
  447. li.active {
  448. background: #37414d;
  449. color: yellow;
  450. }
  451. li:hover {
  452. background: #37414d;
  453. }
  454. }
  455. .splitPage {
  456. height: 3%;
  457. margin-top: 2%;
  458. text-align: center;
  459. color: #15bb88;
  460. -webkit-user-select: none;
  461. -moz-user-select: none;
  462. -ms-user-select: none;
  463. .arrow {
  464. font-size: 20px;
  465. cursor: pointer;
  466. }
  467. }
  468. .direc {
  469. text-align: center;
  470. width: 100%;
  471. height: 20%;
  472. margin: 5% 0 5% 0;
  473. position: relative;
  474. background: url(../../../assets/images/forecasting/monitor/direction-btn.png)
  475. no-repeat center;
  476. background-size: contain;
  477. & > div {
  478. position: absolute;
  479. width: 50px;
  480. height: 50px;
  481. cursor: pointer;
  482. }
  483. .upCtr {
  484. top: 10px;
  485. left: 50%;
  486. margin-left: -25px;
  487. }
  488. .downCtr {
  489. bottom: 10px;
  490. left: 50%;
  491. margin-left: -25px;
  492. }
  493. .leftCtr {
  494. top: 50%;
  495. left: 28px;
  496. margin-top: -25px;
  497. }
  498. .rightCtr {
  499. top: 50%;
  500. right: 28px;
  501. margin-top: -25px;
  502. }
  503. .cameraCtr {
  504. top: 0;
  505. bottom: 0;
  506. left: 0;
  507. right: 0;
  508. margin: auto;
  509. }
  510. }
  511. .btnBox {
  512. height: 15%;
  513. .zoom,
  514. .playBack,
  515. .playtype0,
  516. .playtype1,
  517. .addequip {
  518. width: 140px;
  519. height: 32px;
  520. margin: auto;
  521. margin-bottom: 10px;
  522. cursor: pointer;
  523. }
  524. .zoom {
  525. background: no-repeat center / 100%
  526. url(../../../assets/images/forecasting/monitor/zoom-btn.png);
  527. display: flex;
  528. & > span {
  529. flex: 1;
  530. height: 32px;
  531. }
  532. }
  533. .playBack {
  534. background: url(../../../assets/images/forecasting/monitor/playback-btn.png)
  535. no-repeat center;
  536. }
  537. .playtype0 {
  538. background: url(../../../assets/images/forecasting/monitor/playtype0.png)
  539. no-repeat center;
  540. margin-bottom: 10px;
  541. }
  542. .playtype1 {
  543. background: url(../../../assets/images/forecasting/monitor/playtype1.png)
  544. no-repeat center;
  545. margin-bottom: 10px;
  546. }
  547. .addequip {
  548. background: url(../../../assets/images/forecasting/monitor/addequip.png)
  549. no-repeat center;
  550. margin-bottom: 10px;
  551. }
  552. }
  553. }
  554. }
  555. }
  556. </style>