视频回放
This commit is contained in:
		| @@ -24,6 +24,7 @@ | ||||
|           <AiMonitor :isShowBar="isShowBar" :src="m.url" type="slw" :name="m.name" @close="removeMonitor(i)" ref="AiMonitor"></AiMonitor> | ||||
|         </div> | ||||
|       </div> | ||||
|       <Synergy v-if="!isShowBar" style="width: 100%; height: 68px;"></Synergy> | ||||
|     </div> | ||||
|     <ai-dialog title="修改名称" :visible.sync="dialog" width="500px" @onConfirm="handleSubmit(selected)" | ||||
|                @closed="selected={}"> | ||||
| @@ -45,10 +46,11 @@ | ||||
|   import DeviceSlider from "../components/deviceSlider" | ||||
|   import LocateDialog from "../components/locateDialog" | ||||
|   import AiMonitor from "../components/AiSlwVideo" | ||||
|   import Synergy from "../components/Synergy" | ||||
|  | ||||
|   export default { | ||||
|     name: "AppISManage", | ||||
|     components: {LocateDialog, DeviceSlider, AiMonitor}, | ||||
|     components: {LocateDialog, DeviceSlider, AiMonitor, Synergy}, | ||||
|     label: "监控实况", | ||||
|     props: { | ||||
|       instance: Function, | ||||
|   | ||||
| @@ -192,7 +192,7 @@ | ||||
|         setTimeout(() => { | ||||
|           this.width = document.querySelector(`#${this.videoId}`).offsetWidth + 'px' | ||||
|           this.$nextTick(() => { | ||||
|             this.$refs.timeline.init() | ||||
|             this.$refs.timeline && this.$refs.timeline.init() | ||||
|           }) | ||||
|         }, 60) | ||||
|       }, | ||||
|   | ||||
							
								
								
									
										513
									
								
								packages/IntelligentSecurity/components/Synergy.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										513
									
								
								packages/IntelligentSecurity/components/Synergy.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,513 @@ | ||||
| <template> | ||||
|   <div class="synergr" :id="videoId" @mousemove.stop="onMousemove" @mouseup="onMouseUp" @mouseleave="isHide = true" v-if="isInit"> | ||||
|     <canvas | ||||
|       id="canvas" | ||||
|       :style="{height: '28px'}" | ||||
|       v-if="canvasWidth" | ||||
|       :width="canvasWidth" | ||||
|       height="28"> | ||||
|     </canvas> | ||||
|     <div class="time" v-show="!isHide" :style="{left: left + 'px'}">{{ time }}</div> | ||||
|     <img | ||||
|       @mousedown="onDragDown" | ||||
|       class="drag-img" | ||||
|       :style="{left: x + 'px'}" | ||||
|       src="https://cdn.cunwuyun.cn/slw2.0/images/drag.png" /> | ||||
|     <div class="slw-bottom"> | ||||
|       <div class="action-bar"> | ||||
|         <div class="left"> | ||||
|           <!-- <div | ||||
|             class="volume" | ||||
|             @mouseleave.stop="isShowVolume = false"> | ||||
|             <img  | ||||
|               @mouseenter.stop="isShowVolume = true" | ||||
|               src="https://cdn.cunwuyun.cn/slw2.0/images/sound.png"> | ||||
|             <div class="volume-slider" :class="[isShowVolume ? 'active' : '']"> | ||||
|               <el-slider | ||||
|                 input-size="mini" | ||||
|                 v-model="volume" | ||||
|                 vertical | ||||
|                 @change="onVolume" | ||||
|                 height="80px"> | ||||
|               </el-slider> | ||||
|             </div> | ||||
|           </div> --> | ||||
|           <div class="play-status"> | ||||
|             <div class="live" v-if="isLiveing"> | ||||
|               <span class="label"></span> | ||||
|               <i>直播中</i> | ||||
|               <em>{{ form.date }}</em> | ||||
|             </div> | ||||
|             <div v-else class="back-btn" @click="isLiveing = true">回到直播</div> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="right"> | ||||
|           <el-tooltip effect="dark" content="选择日期" placement="top"> | ||||
|             <img src="https://cdn.cunwuyun.cn/slw2.0/images/date.png" @click="isShowDate = true"> | ||||
|           </el-tooltip> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <ai-dialog | ||||
|       title="选择日期" | ||||
|       :visible.sync="isShowDate" | ||||
|       width="520px" | ||||
|       @onConfirm="onConfirm"> | ||||
|       <el-form class="ai-form" ref="form" :model="form" label-width="80px" size="small"> | ||||
|         <el-form-item label="选择日期" prop="date" :rules="[{ required: true, message: '请选择日期', trigger: 'change' }]"> | ||||
|           <el-date-picker | ||||
|             value-format="yyyy-MM-DD" | ||||
|             v-model="form.date" | ||||
|             type="date" | ||||
|             placeholder="选择日期"> | ||||
|           </el-date-picker> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import Timeline from './Timeline' | ||||
|  | ||||
|   export default { | ||||
|     props: ['src', 'name', 'isShowBar'], | ||||
|  | ||||
|     name: 'slwVideo', | ||||
|  | ||||
|     components: { | ||||
|       Timeline | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         canvasWidth: 0, | ||||
|         currIndex: 0, | ||||
|         isShowDate: false, | ||||
|         isShow: true, | ||||
|         isShowVolume: false, | ||||
|         isLiveing: true, | ||||
|         form: { | ||||
|           date: '' | ||||
|         }, | ||||
|         isInit: false, | ||||
|         left: 0, | ||||
|         date: '', | ||||
|         scale: 4, | ||||
|         width: '', | ||||
|         isHide: false, | ||||
|         x: 0, | ||||
|         time: '', | ||||
|         videoId: `synergr-${new Date().getTime()}`, | ||||
|         isFullscreen: false | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     watch: { | ||||
|       src: { | ||||
|         handler (val) { | ||||
|           if (val) { | ||||
|             this.isShow = false | ||||
|  | ||||
|             this.$nextTick(() => { | ||||
|               this.isShow = true | ||||
|             }) | ||||
|           } | ||||
|         }, | ||||
|         immediate: true, | ||||
|         deep: true | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     mounted () { | ||||
|       this.form.date = this.$moment(new Date()).format('YYYY-MM-DD') | ||||
|       this.$nextTick(() => { | ||||
|         this.init() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onMousemove (e) { | ||||
|         const canvasInfo = document.querySelector(`#canvas`).getBoundingClientRect() | ||||
|         const seconds = 24 * 60 * 60 | ||||
|  | ||||
|         if (e.clientY - canvasInfo.top < 29) { | ||||
|           const x = e.clientX - canvasInfo.left | ||||
|           const unit = seconds / this.canvasWidth * x | ||||
|           this.left = x | ||||
|           this.time = this.secTotime(unit) | ||||
|           this.isHide = false | ||||
|  | ||||
|           if (!this.isChoose) return | ||||
|           this.x = e.clientX - canvasInfo.left - 4 | ||||
|           this.ratioW = this.x / this.canvasWidth | ||||
|         } else { | ||||
|           this.isHide = true | ||||
|         } | ||||
|       }, | ||||
|  | ||||
|       onDragDown () { | ||||
|         this.$emit('pause') | ||||
|         clearInterval(this.timer) | ||||
|         this.timer = null | ||||
|         this.isChoose = true | ||||
|       }, | ||||
|  | ||||
|       onMouseUp () { | ||||
|         this.isChoose = false | ||||
|       }, | ||||
|  | ||||
|       init () { | ||||
|         this.$nextTick(() => { | ||||
|           this.isInit = true | ||||
|           this.$nextTick(() => { | ||||
|             this.canvasWidth = document.querySelector(`#${this.videoId}`).offsetWidth | ||||
|             this.canvasHeight = document.querySelector(`#${this.videoId}`).offsetHeight | ||||
|  | ||||
|             this.$nextTick(() => { | ||||
|               const el = document.querySelector(`#canvas`) | ||||
|               this.ctx = el.getContext('2d') | ||||
|               this.ctx.width  = document.querySelector(`#${this.videoId}`).offsetWidth | ||||
|               this.ctx.height  = document.querySelector(`#${this.videoId}`).offsetHeight | ||||
|  | ||||
|               if (this.x > 0) { | ||||
|                 this.x = this.canvasWidth * this.ratioW | ||||
|               } else { | ||||
|                 this.initNowTime() | ||||
|               } | ||||
|  | ||||
|               this.renderTimeLine() | ||||
|               this.countdown() | ||||
|             }) | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       countdown () { | ||||
|         this.timer = setInterval(() => { | ||||
|           this.initNowTime() | ||||
|         }, 1000) | ||||
|       }, | ||||
|  | ||||
|       drawLine(ctx, options) { | ||||
|         const { beginX, beginY, endX, endY, lineColor, lineWidth } = options | ||||
|         ctx.beginPath() | ||||
|         ctx.lineWidth = lineWidth | ||||
|         ctx.moveTo(beginX, beginY) | ||||
|         ctx.lineTo(endX, endY) | ||||
|         ctx.strokeStyle = lineColor | ||||
|         ctx.stroke() | ||||
|       }, | ||||
|  | ||||
|       renderTimeLine () { | ||||
|         const ctx = this.ctx | ||||
|         ctx.fillStyle = 'rgba(40, 43, 58, 1)' | ||||
|         ctx.fillRect(0, 0, this.canvasWidth, 28) | ||||
|          | ||||
|         ctx.fillStyle = '#fff' | ||||
|         ctx.font = '12px Arial' | ||||
|         const w = this.canvasWidth / 24  | ||||
|  | ||||
|         for (let i = 1; i < 25; i ++) { | ||||
|           this.drawLine(ctx, { | ||||
|             beginX: i * w, | ||||
|             beginY: 28, | ||||
|             endX: i * w, | ||||
|             endY: i % this.scale === 0 ? 22 : 24, | ||||
|             lineColor: i % this.scale === 0 ? '#000' : '#000', | ||||
|             lineWidth: i % this.scale === 0 ? 1 : 1 | ||||
|           }) | ||||
|  | ||||
|           if (i % this.scale === 0) { | ||||
|             const text = (i < 10 ? '0' + i : i) + ': 00' | ||||
|             const textWidth = ctx.measureText(text).width | ||||
|             if (i === 24) { | ||||
|               ctx.fillText(text, i * w - textWidth, 21) | ||||
|             } else { | ||||
|               ctx.fillText(text, i * w - textWidth / 2, 21) | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|  | ||||
|       initNowTime () { | ||||
|         const date = new Date() | ||||
|         const seconds = date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds() | ||||
|  | ||||
|         this.x = seconds / (24 * 60 * 60) * this.canvasWidth | ||||
|       }, | ||||
|  | ||||
|       secTotime (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.toFixed(0) | ||||
|         }  | ||||
|         return t | ||||
|       }, | ||||
|  | ||||
|       onConfirm () { | ||||
|         this.$refs.form.validate((valid) => { | ||||
|           if (valid) { | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onVolume (e) { | ||||
|         const v = (e / 100).toFixed(1) | ||||
|         const subPage = document.querySelector(`#${this.id}`).contentWindow | ||||
|         subPage.postMessage({ | ||||
|           type: 'volume', | ||||
|           value: Number(v) | ||||
|         }, '*') | ||||
|       }, | ||||
|  | ||||
|       reset () { | ||||
|         setTimeout(() => { | ||||
|           this.width = document.querySelector(`#${this.videoId}`).offsetWidth + 'px' | ||||
|           this.$nextTick(() => { | ||||
|             this.$refs.timeline.init() | ||||
|           }) | ||||
|         }, 60) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   .synergr { | ||||
|     position: relative; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     font-size: 0; | ||||
|     overflow: hidden; | ||||
|     background: rgba(40, 43, 58, 1); | ||||
|  | ||||
|     .time-scale { | ||||
|       display: flex; | ||||
|       position: absolute; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       left: 0; | ||||
|       top: 28px; | ||||
|       z-index: 1; | ||||
|       user-select: none; | ||||
|       width: 12px; | ||||
|       height: 24px; | ||||
|  | ||||
|       span { | ||||
|         width: 2px; | ||||
|         height: 24px; | ||||
|         background: rgba(255, 255, 255, 0.8); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .drag-img { | ||||
|       position: absolute; | ||||
|       left: 0; | ||||
|       top: 0; | ||||
|       z-index: 1; | ||||
|       user-select: none; | ||||
|       cursor: e-resize; | ||||
|       -webkit-user-drag: none; | ||||
|     } | ||||
|  | ||||
|     .time { | ||||
|       position: absolute; | ||||
|       bottom: 40px; | ||||
|       left: 0; | ||||
|       z-index: 1; | ||||
|       padding: 2px 4px; | ||||
|       font-size: 12px; | ||||
|       color: #fff; | ||||
|       background: rgba(0, 0, 0, 1); | ||||
|       transform: translate(-50%, 100%); | ||||
|     } | ||||
|  | ||||
|     .slw-bottom { | ||||
|       width: 100%; | ||||
|       height: 40px; | ||||
|     } | ||||
|  | ||||
|     &:hover { | ||||
|       .slw-title { | ||||
|         transform: translateY(0%); | ||||
|       } | ||||
|       .slw-bottom { | ||||
|         transform: translateY(0%); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .action-bar { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: space-between; | ||||
|       width: 100%; | ||||
|       height: 40px; | ||||
|       padding: 0 16px; | ||||
|       transition: all ease-in-out 0.5s; | ||||
|       background: rgba(46, 53, 75, 1); | ||||
|  | ||||
|       .left { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|  | ||||
|         .play-status { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|  | ||||
|           em { | ||||
|             margin-left: 12px; | ||||
|             font-style: normal; | ||||
|             color: #fff; | ||||
|             font-size: 12px; | ||||
|           } | ||||
|  | ||||
|           .back-btn { | ||||
|             padding: 4px 10px; | ||||
|             border-radius: 6px; | ||||
|             color: #ddd; | ||||
|             font-size: 12px; | ||||
|             cursor: pointer; | ||||
|             background: #343747; | ||||
|  | ||||
|             &:hover { | ||||
|               opacity: 0.6; | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           .live { | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             padding: 2px 5px; | ||||
|             color: rgba(0,255,0,.8); | ||||
|  | ||||
|             i { | ||||
|               font-size: 12px; | ||||
|               font-style: normal; | ||||
|             } | ||||
|  | ||||
|             .label { | ||||
|               width: 6px; | ||||
|               height: 6px; | ||||
|               margin-right: 12px; | ||||
|               background: rgba(0,255,0,.8); | ||||
|               border-radius: 50%; | ||||
|               position: relative; | ||||
|  | ||||
|               &:after { | ||||
|                 content: ""; | ||||
|                 width: 12px; | ||||
|                 height: 12px; | ||||
|                 position: absolute; | ||||
|                 left: 50%; | ||||
|                 top: 50%; | ||||
|                 -webkit-transform: translate(-50%,-50%); | ||||
|                 transform: translate(-50%,-50%); | ||||
|                 border-radius: 50%; | ||||
|                 border: 4px solid rgba(0,255,0,.2); | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .volume { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           position: relative; | ||||
|           height: 100%; | ||||
|  | ||||
|           .volume-slider { | ||||
|             display: none; | ||||
|             position: absolute; | ||||
|             bottom: 20px; | ||||
|             left: 50%; | ||||
|             z-index: -1; | ||||
|             opacity: 0; | ||||
|             padding: 20px 0 10px; | ||||
|             background-color: rgba(0, 0,0,.8); | ||||
|             transform: translate(-50%, 0); | ||||
|             transition: all ease 0.3s; | ||||
|  | ||||
|             &.active { | ||||
|               display: block; | ||||
|               z-index: 1; | ||||
|               opacity: 1; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         img { | ||||
|           cursor: pointer; | ||||
|         } | ||||
|  | ||||
|         .left-btns { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           margin-right: 10px; | ||||
|  | ||||
|           span { | ||||
|             flex: 1; | ||||
|             height: 100%; | ||||
|             line-height: 24px; | ||||
|             background: #222838; | ||||
|             color: #c9c9c9; | ||||
|             font-size: 12px; | ||||
|             cursor: pointer; | ||||
|  | ||||
|             &.active { | ||||
|               color: #fff; | ||||
|               background: linear-gradient(180deg, #28B2EB 0%, #193D91 100%); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .right { | ||||
|         color: #c9c9c9; | ||||
|         font-size: 12px; | ||||
|  | ||||
|         span { | ||||
|           margin-right: 32px; | ||||
|           cursor: pointer; | ||||
|  | ||||
|           &:hover { | ||||
|             opacity: 0.6; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         img { | ||||
|           margin-right: 16px; | ||||
|           cursor: pointer; | ||||
|  | ||||
|           &:last-child { | ||||
|             margin-right: 0; | ||||
|           } | ||||
|  | ||||
|           &:hover { | ||||
|             opacity: 0.6; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       & > div { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
|   <div class="canvas" @mousemove.stop="onMousemove" @mouseup="onMouseUp" @mouseleave="isHide = true" v-if="isInit"> | ||||
|   <div :class="wrapper" class="canvas" @mousemove.stop="onMousemove" @mouseup="onMouseUp" @mouseleave="isHide = true" v-if="isInit"> | ||||
|     <canvas | ||||
|       :id="id" | ||||
|       :style="{height: '52px'}" | ||||
| @@ -32,9 +32,11 @@ | ||||
|         time: '', | ||||
|         left: 0, | ||||
|         x: 0, | ||||
|         ratioW: '', | ||||
|         isHide: true, | ||||
|         isInit: false, | ||||
|         isChoose: false, | ||||
|         wrapper: `canvas-${new Date().getTime()}`, | ||||
|         id: `timeline-${new Date().getTime()}`, | ||||
|         timer: null | ||||
|       } | ||||
| @@ -112,8 +114,8 @@ | ||||
|         this.$nextTick(() => { | ||||
|           this.isInit = true | ||||
|           this.$nextTick(() => { | ||||
|             this.canvasWidth = document.querySelector('.canvas').offsetWidth | ||||
|             this.canvasHeight = document.querySelector('.canvas').offsetHeight | ||||
|             this.canvasWidth = document.querySelector(`.${this.wrapper}`).offsetWidth | ||||
|             this.canvasHeight = document.querySelector(`.${this.wrapper}`).offsetHeight | ||||
|  | ||||
|             this.$nextTick(() => { | ||||
|               const el = document.querySelector(`#${this.id}`) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user