|
|
@@ -0,0 +1,191 @@
|
|
|
+<template>
|
|
|
+ <div class="deviceLive">
|
|
|
+ <div class="deviceLive-frames">
|
|
|
+ <EasyPlayer :url="state.playerUrl" />
|
|
|
+ </div>
|
|
|
+ <div class="deviceLive-operation">
|
|
|
+ <a-select style="width:150px;margin-right: 13px;" placeholder="摄像头" v-model:value="state.cameraValue">
|
|
|
+ <a-select-option v-for="item in state.cameraList" :key="item.value" :value="item.value"
|
|
|
+ @click="onCameraSelect(item)">
|
|
|
+ {{ item.label }}
|
|
|
+ </a-select-option>
|
|
|
+ </a-select>
|
|
|
+ <a-select style="width:150px;margin-right: 13px;" placeholder="清晰度" v-model:value="state.clarityValue"
|
|
|
+ @select="onClaritySelect">
|
|
|
+ <a-select-option v-for="item in clarityList" :key="item.value" :value="item.value">
|
|
|
+ {{ item.label }}
|
|
|
+ </a-select-option>
|
|
|
+ </a-select>
|
|
|
+ <a-button style="margin-right: 13px;" type="primary" large @click="onStart">播放</a-button>
|
|
|
+ <a-button type="primary" large @click="onStop">停止</a-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { reactive, onMounted } from 'vue';
|
|
|
+import { message } from 'ant-design-vue';
|
|
|
+import EasyPlayer from '/@/components/easyPlayer/index.vue';
|
|
|
+import { CURRENT_CONFIG as config } from '/@/api/http/config';
|
|
|
+import { getLiveCapacity, startLivestream, stopLivestream } from '/@/api/manage';
|
|
|
+
|
|
|
+interface Props {
|
|
|
+ sn: string,
|
|
|
+};
|
|
|
+
|
|
|
+const props = withDefaults(defineProps<Props>(), {
|
|
|
+
|
|
|
+});
|
|
|
+
|
|
|
+interface SelectOption {
|
|
|
+ value: any,
|
|
|
+ label: string,
|
|
|
+ more?: any
|
|
|
+}
|
|
|
+
|
|
|
+const clarityList: SelectOption[] = [
|
|
|
+ {
|
|
|
+ value: 0,
|
|
|
+ label: '自适应'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 1,
|
|
|
+ label: '流畅'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 2,
|
|
|
+ label: '标清'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 3,
|
|
|
+ label: '高清'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 4,
|
|
|
+ label: '超清'
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+interface State {
|
|
|
+ cameraList: SelectOption[],
|
|
|
+ cameraValue?: string,
|
|
|
+ videoList: SelectOption[],
|
|
|
+ videoValue?: string,
|
|
|
+ clarityValue: number,
|
|
|
+ videoId: string,
|
|
|
+ playerUrl: string,
|
|
|
+}
|
|
|
+
|
|
|
+const state: State = reactive({
|
|
|
+ cameraList: [],
|
|
|
+ cameraValue: undefined,
|
|
|
+ videoList: [],
|
|
|
+ videoValue: undefined,
|
|
|
+ clarityValue: 0,
|
|
|
+ videoId: '',
|
|
|
+ playerUrl: '',
|
|
|
+})
|
|
|
+
|
|
|
+const fetchLiveCapacity = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getLiveCapacity({});
|
|
|
+ if (res.code === 0) {
|
|
|
+ const deviceInfo = res.data.filter((item: any) => item.sn === props.sn)[0];
|
|
|
+ const cameraList = deviceInfo.cameras_list.map((item: any) => {
|
|
|
+ return {
|
|
|
+ label: item.name,
|
|
|
+ value: item.index,
|
|
|
+ more: item.videos_list
|
|
|
+ }
|
|
|
+ })
|
|
|
+ state.cameraList = cameraList;
|
|
|
+ }
|
|
|
+ } catch (e: any) {
|
|
|
+ message.destroy();
|
|
|
+ message.error(e);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ await fetchLiveCapacity()
|
|
|
+})
|
|
|
+
|
|
|
+const onCameraSelect = (record: SelectOption) => {
|
|
|
+ state.cameraValue = record.value;
|
|
|
+ if (!record.more) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const videoList = record.more.map((ele: any) => {
|
|
|
+ return {
|
|
|
+ label: ele.type,
|
|
|
+ value: ele.index,
|
|
|
+ more: ele.switch_video_types
|
|
|
+ }
|
|
|
+ })
|
|
|
+ state.videoList = videoList;
|
|
|
+ if (videoList.length === 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const firstVideo: SelectOption = videoList[0];
|
|
|
+ state.videoValue = firstVideo.value;
|
|
|
+}
|
|
|
+
|
|
|
+const onClaritySelect = (value: any) => {
|
|
|
+ state.clarityValue = value;
|
|
|
+}
|
|
|
+
|
|
|
+const onStart = async () => {
|
|
|
+ const { cameraValue, videoValue } = state;
|
|
|
+ if (!cameraValue) {
|
|
|
+ return message.warn('请选择摄像头');
|
|
|
+ }
|
|
|
+ const videoId = `${props.sn}/${cameraValue}/${videoValue || 'normal-0'}`;
|
|
|
+ state.videoId = videoId;
|
|
|
+ const liveURL = config.rtmpURL;
|
|
|
+ try {
|
|
|
+ const res = await startLivestream({
|
|
|
+ url: liveURL,
|
|
|
+ video_id: videoId,
|
|
|
+ url_type: 1,// RTMP
|
|
|
+ video_quality: state.clarityValue
|
|
|
+ });
|
|
|
+ const playerUrl = res.data.url
|
|
|
+ state.playerUrl = playerUrl;
|
|
|
+ message.success('已开启直播');
|
|
|
+ } catch (e: any) {
|
|
|
+ message.destroy();
|
|
|
+ message.error(e);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const onStop = async () => {
|
|
|
+ const { cameraValue, videoValue } = state;
|
|
|
+ if (!cameraValue) {
|
|
|
+ return message.warn('请选择摄像头');
|
|
|
+ }
|
|
|
+ const videoId = `${props.sn}/${cameraValue}/${videoValue || 'normal-0'}`;
|
|
|
+ const res = await stopLivestream({
|
|
|
+ video_id: videoId,
|
|
|
+ });
|
|
|
+ if (res.code === 0) {
|
|
|
+ state.videoId = '';
|
|
|
+ state.playerUrl = '';
|
|
|
+ message.success('已停止直播');
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.deviceLive {
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ &-frames {
|
|
|
+ width: 100%;
|
|
|
+ height: 300px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &-operation {
|
|
|
+ margin-top: 20px;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|