|
|
@@ -7,7 +7,15 @@
|
|
|
clearable
|
|
|
style=" width: 150px;height:28px;"
|
|
|
size="tiny"
|
|
|
- />
|
|
|
+ >
|
|
|
+ <template #suffix>
|
|
|
+ <Icon
|
|
|
+ name="search"
|
|
|
+ size="15"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </n-input>
|
|
|
+
|
|
|
<n-select
|
|
|
v-model:value="selectRow"
|
|
|
:options="option"
|
|
|
@@ -15,11 +23,17 @@
|
|
|
@update:value="onChange"
|
|
|
/>
|
|
|
<n-button
|
|
|
- secondary
|
|
|
size="small"
|
|
|
+ icon-placement="right"
|
|
|
style="margin-left: 10px;"
|
|
|
@click="onChange(selectRow)"
|
|
|
>
|
|
|
+ <template #icon>
|
|
|
+ <Icon
|
|
|
+ name="transh"
|
|
|
+ size="15"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
清空
|
|
|
</n-button>
|
|
|
</div>
|
|
|
@@ -48,6 +62,59 @@
|
|
|
:style="`width:${(100 / selectRow) - 0.05}%;height:${(100 / selectRow) - 0.15}%;`"
|
|
|
>
|
|
|
<div :id="item.id" />
|
|
|
+ <div
|
|
|
+ v-if="item.fluentLiveUrl"
|
|
|
+ class="video-right-item-bar"
|
|
|
+ >
|
|
|
+ <div class="video-right-item-bar-left">
|
|
|
+ <n-tooltip trigger="hover">
|
|
|
+ <template #trigger>
|
|
|
+ <Icon
|
|
|
+ name="capVideo"
|
|
|
+ size="25"
|
|
|
+ :color="item.isCapVideo ? 'red' : 'white'"
|
|
|
+ @click="item.captureVideo()"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ {{ item.isCapVideo ? '停止录屏' : '开始录屏' }}
|
|
|
+ </n-tooltip>
|
|
|
+ <n-tooltip trigger="hover">
|
|
|
+ <template #trigger>
|
|
|
+ <Icon
|
|
|
+ name="image"
|
|
|
+ size="25"
|
|
|
+ @click="item.capturePicture(item.cameraName)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ 截图
|
|
|
+ </n-tooltip>
|
|
|
+ </div>
|
|
|
+ <div class="video-right-item-bar-right">
|
|
|
+ <n-button
|
|
|
+ size="small"
|
|
|
+ icon-placement="right"
|
|
|
+ @click="item.changeCode()"
|
|
|
+ >
|
|
|
+ <template #icon>
|
|
|
+ <Icon
|
|
|
+ name="change"
|
|
|
+ size="20"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ {{ item.isChangeCode ? '子码流' : '主码流' }}
|
|
|
+ </n-button>
|
|
|
+ <n-tooltip trigger="hover">
|
|
|
+ <template #trigger>
|
|
|
+ <Icon
|
|
|
+ name="fullScreen"
|
|
|
+ size="25"
|
|
|
+ @click="item.fullScreen()"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ 全屏
|
|
|
+ </n-tooltip>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
</div>
|
|
|
@@ -56,19 +123,27 @@
|
|
|
|
|
|
<script setup lang='ts'>
|
|
|
import {
|
|
|
- onMounted, onUnmounted, ref, watch
|
|
|
+ onMounted, onUnmounted, ref
|
|
|
} from 'vue'
|
|
|
import EzVideoService from './ezVideo.service'
|
|
|
import { useNotification } from 'naive-ui'
|
|
|
|
|
|
interface VideoItem {
|
|
|
id: string,
|
|
|
- liveUrl: string,
|
|
|
accessToken: string,
|
|
|
- video: undefined | any,
|
|
|
+ video: null | any,
|
|
|
+ isCapVideo: boolean,
|
|
|
+ isChangeCode: boolean,
|
|
|
+ cameraName: string,
|
|
|
+ fluentLiveUrl: string,
|
|
|
+ highLiveUrl: string,
|
|
|
play: (a: number, b: number) => void,
|
|
|
destory: () => void,
|
|
|
- resize: (a: number, b: number) => void
|
|
|
+ resize: (a: number, b: number) => void,
|
|
|
+ fullScreen: () => void,
|
|
|
+ capturePicture: (a: string) => void,
|
|
|
+ captureVideo: () => void,
|
|
|
+ changeCode: () => void
|
|
|
}
|
|
|
|
|
|
const notification = useNotification()
|
|
|
@@ -92,7 +167,9 @@ const treeData = ref([
|
|
|
accessToken: 'at.a82kqljj96ja8ony6e57nrqi4aigp963-7sn8ji0ji3-16njxp9-rmioevhxz',
|
|
|
label: 'test',
|
|
|
key: '1-2-1',
|
|
|
- liveUrl: 'ezopen://aczn1688@open.ys7.com/FH2861570/2.live'
|
|
|
+ fluentLiveUrl: 'ezopen://aczn1688@open.ys7.com/FH2861570/2.live',
|
|
|
+ highLiveUrl: 'ezopen://aczn1688@open.ys7.com/FH2861570/2.live',
|
|
|
+ cameraName: 'test'
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
@@ -115,26 +192,50 @@ function onChange(v: number) {
|
|
|
const ezVideoService = new EzVideoService()
|
|
|
arr.push({
|
|
|
id: `video${k}`,
|
|
|
- liveUrl: '',
|
|
|
accessToken: '',
|
|
|
- video: undefined as any,
|
|
|
+ cameraName: `Test${k}`,
|
|
|
+ video: undefined,
|
|
|
+ isCapVideo: false,
|
|
|
+ isChangeCode: false,
|
|
|
+ fluentLiveUrl: '',
|
|
|
+ highLiveUrl: '',
|
|
|
play(width: number, height: number) {
|
|
|
if (this.video) this.destory()
|
|
|
- if (!width || !height) return
|
|
|
+ if (!width || !height || !this.fluentLiveUrl) return
|
|
|
this.video = ezVideoService.init({
|
|
|
- id: this.id, url: this.liveUrl, accessToken: this.accessToken, width, height
|
|
|
+ id: this.id, url: this.fluentLiveUrl!, accessToken: this.accessToken, width, height
|
|
|
})
|
|
|
},
|
|
|
destory() {
|
|
|
- if (this.video) {
|
|
|
- this.video.stop()
|
|
|
- this.video = undefined
|
|
|
- document.getElementById(this.id)?.remove()
|
|
|
- }
|
|
|
+ if (!this.video) return
|
|
|
+ this.video.stop()
|
|
|
+ this.video = undefined
|
|
|
+ document.getElementById(this.id)?.remove()
|
|
|
},
|
|
|
resize(width: number, height: number) {
|
|
|
if (!width || !height) return
|
|
|
if (this.video) this.video.reSize(width, height)
|
|
|
+ },
|
|
|
+ fullScreen() {
|
|
|
+ if (!this.video) return
|
|
|
+ this.video.fullScreen()
|
|
|
+ },
|
|
|
+ capturePicture(name = 'test') {
|
|
|
+ if (!this.video) return
|
|
|
+ this.video.capturePicture(name)
|
|
|
+ },
|
|
|
+ captureVideo() {
|
|
|
+ if (!this.video) return
|
|
|
+ if (this.isCapVideo) { this.video.stopSave() } else {
|
|
|
+ this.video.startSave()
|
|
|
+ }
|
|
|
+ this.isCapVideo = !this.isCapVideo
|
|
|
+ },
|
|
|
+ changeCode() {
|
|
|
+ if (!this.video) return
|
|
|
+ const url = this.isChangeCode ? this.fluentLiveUrl : this.highLiveUrl
|
|
|
+ this.video.changePlayUrl({ url })
|
|
|
+ this.isChangeCode = !this.isChangeCode
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
@@ -157,7 +258,7 @@ function onDrop(data: any) {
|
|
|
return
|
|
|
}
|
|
|
// 查找没有播放的分屏
|
|
|
- const index = videoItem.value.findIndex((el) => !el.accessToken && !el.liveUrl)
|
|
|
+ const index = videoItem.value.findIndex((el) => !el.accessToken && !el.fluentLiveUrl)
|
|
|
console.log(7777, arr, videoItem.value, index)
|
|
|
if (index < 0) return
|
|
|
for (let k = 0; k < arr.length; k++) {
|
|
|
@@ -165,13 +266,14 @@ function onDrop(data: any) {
|
|
|
const num = index + k
|
|
|
if (num > (videoItem.value.length - 1)) continue
|
|
|
videoItem.value[num].accessToken = el.accessToken
|
|
|
- videoItem.value[num].liveUrl = el.liveUrl
|
|
|
+ videoItem.value[num].fluentLiveUrl = el.fluentLiveUrl!
|
|
|
+ videoItem.value[num].highLiveUrl = el.highLiveUrl!
|
|
|
+ videoItem.value[num].cameraName = el.cameraName
|
|
|
setTimeout(() => {
|
|
|
const dom = document.getElementById('videoBoxs')
|
|
|
videoItem.value[num].play(dom?.clientWidth || 0, dom?.clientHeight || 0)
|
|
|
}, 200)
|
|
|
}
|
|
|
- console.log(888, videoItem.value)
|
|
|
}
|
|
|
|
|
|
onMounted(() => onChange(selectRow.value))
|
|
|
@@ -247,12 +349,57 @@ onUnmounted(() => onChange(selectRow.value))
|
|
|
&-item {
|
|
|
background: black;
|
|
|
overflow: hidden;
|
|
|
+ position: relative;
|
|
|
|
|
|
- &>div {
|
|
|
+ &>div:first-child {
|
|
|
overflow: hidden;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
}
|
|
|
+
|
|
|
+ &:hover &-bar {
|
|
|
+ display: flex;
|
|
|
+ }
|
|
|
+
|
|
|
+ &-bar {
|
|
|
+ position: absolute;
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
+ left: 0;
|
|
|
+ bottom: 0;
|
|
|
+ display: none;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 0 10px;
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
+ color: white;
|
|
|
+
|
|
|
+ &-left,
|
|
|
+ &-right {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ &>svg {
|
|
|
+ outline: none;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ &>svg:not(:first-child) {
|
|
|
+ margin-left: 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.n-button) {
|
|
|
+ --n-height: 25px;
|
|
|
+ --n-text-color: white;
|
|
|
+ --n-text-color-hover: white;
|
|
|
+ --n-border-hover: 1px solid rgba(196, 200, 206, 1);
|
|
|
+ --n-text-color-focus: white;
|
|
|
+ --n-text-color-pressed: white;
|
|
|
+ --n-border-focus: white;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.active {
|