live.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. <template>
  2. <div id="devicePosition" style="width:100vw; height: 91vh">
  3. <el-container v-loading="loading" style="height: 91vh;" element-loading-text="拼命加载中">
  4. <el-aside width="300px" style="background-color: #ffffff">
  5. <DeviceTree :clickEvent="clickEvent" :contextMenuEvent="contextMenuEvent"></DeviceTree>
  6. </el-aside>
  7. <el-container>
  8. <el-header height="5vh" style="text-align: left;font-size: 17px;line-height:5vh">
  9. 分屏:
  10. <i class="el-icon-full-screen btn" :class="{active:spilt==1}" @click="spilt=1"/>
  11. <i class="el-icon-menu btn" :class="{active:spilt==4}" @click="spilt=4"/>
  12. <i class="el-icon-s-grid btn" :class="{active:spilt==9}" @click="spilt=9"/>
  13. </el-header>
  14. <el-main style="padding: 0;">
  15. <div style="width: 99%;height: 85vh;display: flex;flex-wrap: wrap;background-color: #000;">
  16. <div v-for="i in spilt" :key="i" class="play-box"
  17. :style="liveStyle" :class="{redborder:playerIdx == (i-1)}"
  18. @click="playerIdx = (i-1)">
  19. <div v-if="!videoUrl[i-1]" style="color: #ffffff;font-size: 30px;font-weight: bold;">{{ i }}</div>
  20. <player ref="player" v-else :videoUrl="videoUrl[i-1]" fluent autoplay @screenshot="shot"
  21. @destroy="destroy"/>
  22. </div>
  23. </div>
  24. </el-main>
  25. </el-container>
  26. </el-container>
  27. </div>
  28. </template>
  29. <script>
  30. import uiHeader from "../layout/UiHeader.vue";
  31. import player from './common/jessibuca.vue'
  32. import DeviceTree from './common/DeviceTree.vue'
  33. export default {
  34. name: "live",
  35. components: {
  36. uiHeader, player, DeviceTree
  37. },
  38. data() {
  39. return {
  40. videoUrl: [''],
  41. spilt: 1,//分屏
  42. playerIdx: 0,//激活播放器
  43. updateLooper: 0, //数据刷新轮训标志
  44. count: 15,
  45. total: 0,
  46. //channel
  47. loading: false
  48. };
  49. },
  50. mounted() {
  51. },
  52. created() {
  53. this.checkPlayByParam()
  54. },
  55. computed: {
  56. liveStyle() {
  57. let style = {width: '100%', height: '100%'}
  58. switch (this.spilt) {
  59. case 4:
  60. style = {width: '49%', height: '49%'}
  61. break
  62. case 9:
  63. style = {width: '32%', height: '32%'}
  64. break
  65. }
  66. this.$nextTick(() => {
  67. for (let i = 0; i < this.spilt; i++) {
  68. const player = this.$refs.player
  69. player && player[i] && player[i].updatePlayerDomSize()
  70. }
  71. })
  72. return style
  73. }
  74. },
  75. watch: {
  76. spilt(newValue) {
  77. console.log("切换画幅;" + newValue)
  78. let that = this
  79. for (let i = 1; i <= newValue; i++) {
  80. if (!that.$refs['player' + i]) {
  81. continue
  82. }
  83. this.$nextTick(() => {
  84. if (that.$refs['player' + i] instanceof Array) {
  85. that.$refs['player' + i][0].resize()
  86. } else {
  87. that.$refs['player' + i].resize()
  88. }
  89. })
  90. }
  91. window.localStorage.setItem('split', newValue)
  92. },
  93. '$route.fullPath': 'checkPlayByParam'
  94. },
  95. destroyed() {
  96. clearTimeout(this.updateLooper);
  97. },
  98. methods: {
  99. destroy(idx) {
  100. console.log(idx);
  101. this.clear(idx.substring(idx.length - 1))
  102. },
  103. clickEvent: function (data) {
  104. if (data.channelId && data.subCount == 0) {
  105. this.sendDevicePush(data)
  106. }
  107. },
  108. contextMenuEvent: function (data) {
  109. },
  110. //通知设备上传媒体流
  111. sendDevicePush: function (itemData) {
  112. if (itemData.status === 0) {
  113. this.$message.error('设备离线!');
  114. return
  115. }
  116. this.save(itemData)
  117. let deviceId = itemData.deviceId;
  118. // this.isLoging = true;
  119. let channelId = itemData.channelId;
  120. console.log("通知设备推流1:" + deviceId + " : " + channelId);
  121. let idxTmp = this.playerIdx
  122. let that = this;
  123. this.loading = true
  124. this.$axios({
  125. method: 'get',
  126. url: '/api/play/start/' + deviceId + '/' + channelId
  127. }).then(function (res) {
  128. // that.isLoging = false;
  129. console.log('=====----=====')
  130. console.log(res)
  131. if (res.data.code == 0 && res.data.data) {
  132. itemData.playUrl = res.data.data.httpsFlv
  133. that.setPlayUrl(res.data.data.ws_flv, idxTmp)
  134. } else {
  135. that.$message.error(res.data.msg);
  136. }
  137. }).catch(function (e) {
  138. }).finally(() => {
  139. that.loading = false
  140. });
  141. },
  142. setPlayUrl(url, idx) {
  143. this.$set(this.videoUrl, idx, url)
  144. let _this = this
  145. setTimeout(() => {
  146. window.localStorage.setItem('videoUrl', JSON.stringify(_this.videoUrl))
  147. }, 100)
  148. },
  149. checkPlayByParam() {
  150. let {deviceId, channelId} = this.$route.query
  151. if (deviceId && channelId) {
  152. this.sendDevicePush({deviceId, channelId})
  153. }
  154. },
  155. shot(e) {
  156. // console.log(e)
  157. // send({code:'image',data:e})
  158. var base64ToBlob = function (code) {
  159. let parts = code.split(';base64,');
  160. let contentType = parts[0].split(':')[1];
  161. let raw = window.atob(parts[1]);
  162. let rawLength = raw.length;
  163. let uInt8Array = new Uint8Array(rawLength);
  164. for (let i = 0; i < rawLength; ++i) {
  165. uInt8Array[i] = raw.charCodeAt(i);
  166. }
  167. return new Blob([uInt8Array], {
  168. type: contentType
  169. });
  170. };
  171. let aLink = document.createElement('a');
  172. let blob = base64ToBlob(e); //new Blob([content]);
  173. let evt = document.createEvent("HTMLEvents");
  174. evt.initEvent("click", true, true); //initEvent 不加后两个参数在FF下会报错 事件类型,是否冒泡,是否阻止浏览器的默认行为
  175. aLink.download = '截图';
  176. aLink.href = URL.createObjectURL(blob);
  177. aLink.click();
  178. },
  179. save(item) {
  180. let dataStr = window.localStorage.getItem('playData') || '[]'
  181. let data = JSON.parse(dataStr);
  182. data[this.playerIdx] = item
  183. window.localStorage.setItem('playData', JSON.stringify(data))
  184. },
  185. clear(idx) {
  186. let dataStr = window.localStorage.getItem('playData') || '[]'
  187. let data = JSON.parse(dataStr);
  188. data[idx - 1] = null;
  189. console.log(data);
  190. window.localStorage.setItem('playData', JSON.stringify(data))
  191. },
  192. }
  193. };
  194. </script>
  195. <style>
  196. .btn {
  197. margin: 0 10px;
  198. }
  199. .btn:hover {
  200. color: #409EFF;
  201. }
  202. .btn.active {
  203. color: #409EFF;
  204. }
  205. .redborder {
  206. border: 2px solid red !important;
  207. }
  208. .play-box {
  209. background-color: #000000;
  210. border: 2px solid #505050;
  211. display: flex;
  212. align-items: center;
  213. justify-content: center;
  214. }
  215. </style>
  216. <style>
  217. .videoList {
  218. display: flex;
  219. flex-wrap: wrap;
  220. align-content: flex-start;
  221. }
  222. .video-item {
  223. position: relative;
  224. width: 15rem;
  225. height: 10rem;
  226. margin-right: 1rem;
  227. background-color: #000000;
  228. }
  229. .video-item-img {
  230. position: absolute;
  231. top: 0;
  232. bottom: 0;
  233. left: 0;
  234. right: 0;
  235. margin: auto;
  236. width: 100%;
  237. height: 100%;
  238. }
  239. .video-item-img:after {
  240. content: "";
  241. display: inline-block;
  242. position: absolute;
  243. z-index: 2;
  244. top: 0;
  245. bottom: 0;
  246. left: 0;
  247. right: 0;
  248. margin: auto;
  249. width: 3rem;
  250. height: 3rem;
  251. background-image: url("../assets/loading.png");
  252. background-size: cover;
  253. background-color: #000000;
  254. }
  255. .video-item-title {
  256. position: absolute;
  257. bottom: 0;
  258. color: #000000;
  259. background-color: #ffffff;
  260. line-height: 1.5rem;
  261. padding: 0.3rem;
  262. width: 14.4rem;
  263. }
  264. .baidumap {
  265. width: 100%;
  266. height: 100%;
  267. border: none;
  268. position: absolute;
  269. left: 0;
  270. top: 0;
  271. right: 0;
  272. bottom: 0;
  273. margin: auto;
  274. }
  275. /* 去除百度地图版权那行字 和 百度logo */
  276. .baidumap > .BMap_cpyCtrl {
  277. display: none !important;
  278. }
  279. .baidumap > .anchorBL {
  280. display: none !important;
  281. }
  282. </style>