hldy_vue/src/views/iot/tplink/camera/components/CameraPreviewForm.vue

358 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<a-spin :spinning="confirmLoading">
<a-row>
<a-col :span="24">
<div id="video-container"></div>
</a-col>
<a-col :span="24" style="padding: 5px;">
<span style="margin-left: 5px;" v-show="!izPlaying">
<a-button preIcon="ant-design:play-circle-outlined" @click="play">播放</a-button>
</span>
<span style="margin-left: 5px;" v-show="izPlaying">
<a-button preIcon="ant-design:pause-circle-outlined" @click="pause">暂停</a-button>
</span>
<span style="margin-left: 5px;">
<a-button preIcon="ant-design:swap-outlined" @click="switchResolution">{{ resolution }}</a-button>
</span>
<!-- <span style="margin-left: 5px;">
<a-button preIcon="ant-design:phone-outlined" @click="screenshot">巡航*</a-button>
</span>-->
<span style="margin-left: 5px;" v-show="!izPhone">
<a-button preIcon="ant-design:phone-outlined" @click="startPhone">电话</a-button>
</span>
<span style="margin-left: 5px;" v-show="izPhone">
<a-button type="primary" danger ghost preIcon="ant-design:phone-outlined" @click="stopPhone">电话</a-button>
</span>
<span style="margin-left: 15px;">分屏
<a-select
ref="select"
v-model:value="fishEyeDisplayMode"
style="width: 120px"
@focus="focus"
@change="setFishEyeDisplayMode"
>
<a-select-option value="ORIGIN">原图</a-select-option>
<a-select-option value="FISHEYE_360D">360全景</a-select-option>
<a-select-option value="FISHEYE_180D">180全景</a-select-option>
<a-select-option value="FISHEYE_WIN_PLANE_TOP_QUAD">四分屏</a-select-option>
<a-select-option value="FISHEYE_LONGITUDE">全景拉伸</a-select-option>
</a-select>
</span>
</a-col>
<a-col :span="24" style="padding: 5px;">
<span style="margin-left: 5px;">
<a-button preIcon="ant-design:picture-outlined" @click="screenshot">截图</a-button>
</span>
<span style="margin-left: 5px;" v-show="!izRecording">
<a-button preIcon="ant-design:video-camera-outlined" @click="recordingStart">录制</a-button>
</span>
<span style="margin-left: 5px;" v-show="izRecording">
<a-button type="primary" danger ghost preIcon="ant-design:video-camera-outlined" @click="recordingEnd">录制</a-button>
</span>
<span style="margin-left: 15px;">画面翻转
<a-select v-model:value="formData.flip_type" @change="(value) => changeSwitch('flip_type', value)">
<a-select-option value="off">关闭</a-select-option>
<a-select-option value="left_and_right">左右</a-select-option>
<a-select-option value="up_and_down">上下</a-select-option>
<a-select-option value="center">中心</a-select-option>
</a-select>
</span>
<span style="margin-left: 5px;">
<a-button preIcon="ant-design:alert-outlined" @click="manualAlarm">报警</a-button>
</span>
</a-col>
</a-row>
</a-spin>
</template>
<script lang="ts" setup>
import { ref, reactive, defineExpose, nextTick, defineProps, computed, onMounted } from 'vue';
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { getValueType } from '/@/utils';
import { Form } from 'ant-design-vue';
import {
getImageCommon,
getMultitransUrl,
getPreviewUrl,
setImageCommon,
testAudio
} from "../camera.api";
const props = defineProps({
formDisabled: { type: Boolean, default: false },
formData: { type: Object, default: () => ({})},
formBpm: { type: Boolean, default: true }
});
const formRef = ref();
const player = ref();
const resolution = ref<string>('超清');
const izPlaying = ref<boolean>(true);
const izRecording = ref<boolean>(false);
const izPhone = ref<boolean>(false);
const fishEyeDisplayMode = ref<string>('ORIGIN');
const flipType = ref<string>('off');
const useForm = Form.useForm;
const emit = defineEmits(['register', 'ok']);
const formData = reactive<Record<string, any>>({
//预览通道参数
deviceIndex: '',//设备索引
streamType: 0,//码流类型 0 代表主码流1 代码子码流
//视频预览参数
url: '',//预览通道对应的URL
backupUrl: '',//备选URL当流媒体服务器存在内外网IP配置时该字段不为null
wsUrl: '',//用于建立ws连接传输视频帧信息
wssUrl: '',//用于建立wss接传输视频帧信息
flip_type: '',//画面镜像旋转: "off"//关闭 "left_and_right"//左右 "up_and_down"//上下 "center"//中心
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
const confirmLoading = ref<boolean>(false);
//表单验证
const validatorRules = reactive({
});
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: false });
// 表单禁用
const disabled = computed(()=>{
if(props.formBpm === true){
if(props.formData.disabled === false){
return false;
}else{
return true;
}
}
return props.formDisabled;
});
/**
* 详情
*/
async function edit(record) {
await nextTick(() => {
confirmLoading.value=true;
resetFields();
const tmpData = {};
Object.keys(formData).forEach((key) => {
if(record.hasOwnProperty(key)){
tmpData[key] = record[key]
}
})
//赋值
Object.assign(formData, tmpData);
});
createPreview();
getSwitch();
}
/**
* 创建预览
*/
async function createPreview(){
await getPreviewUrl({"deviceIndex":formData.deviceIndex,"streamType":formData.streamType}).then(res=>{
formData.url = res.url;
formData.backupUrl = res.backupUrl;
formData.wsUrl = res.wsUrl;
formData.wssUrl = res.wssUrl;
confirmLoading.value=false;
});
if (player.value){
player.value.destroy().then(() => {
}); // 销毁
}
const TumsPlayer = window['tums-player'].default;
player.value = new TumsPlayer('video-container', {
type: "rtsp", // 协议类型rtsp
url: formData.url, // 取流地址, getPreviewUrl接口获取
// url: formData.backupUrl, // 取流地址, getPreviewUrl接口获取
socket: formData.wssUrl, // websocket地址, getPreviewUrl接口获取
pluginPath: '/static', // 当sdk资源不在根路径下时需配置pluginPath
talkEnable: true,
useMultitrans: true,
});
let isPlaying = player.value.isPlaying();
if (!isPlaying) {
if (player.value.isInit) {
player.value.start();
} else {
player.value.play();
}
izPlaying.value = true;
}
}
/**
* 切换超清/流程
*/
function switchResolution(){
if(formData.streamType == 0){
resolution.value = '流畅';
formData.streamType = 1;
}else{
resolution.value = '超清';
formData.streamType = 0;
}
createMessage.info('正在切换至'+resolution.value);
createPreview();
}
/**
* 播放
*/
function play(){
izPlaying.value = true;
player.value.play();
}
/**
* 暂停
*/
function pause(){
izPlaying.value = false;
player.value.pause();
}
/**
* 截屏
*/
function screenshot(){
player.value.screenshot();
}
/**
* 鱼眼画面显示模式
*/
function setFishEyeDisplayMode(){
player.value.setFishEyeDisplayMode(fishEyeDisplayMode.value);
}
/**
* 获取画面翻转
*/
function getSwitch(){
if(formData.deviceIndex==null){
return
}
getImageCommon({
"deviceIndex": formData.deviceIndex,
"type": "switch"
}).then(res=>{
formData.flip_type = res.flip_type; //画面镜像翻转
});
}
/**
* 画面翻转
*/
function changeSwitch(attr,value){
let param = {};
param[attr] = value;
setImageCommon({
"deviceIndex": formData.deviceIndex,
"type": "switch",
"param": param
}).then(res=>{ });
}
/**
* 手动报警
*/
function manualAlarm(){
let params = {
"deviceIndex": formData.deviceIndex,
"force": 1,
"id": '0'
};
testAudio(params);
}
/**
* 开始录制
*/
function recordingStart(){
izRecording.value = true;
player.value.startRecording({micStream:true}).then((res) => {
// 设置成功返回resolve
}).catch((errData) => {
// 设置失败,包括网络错误以及接口调用报错
// 具体错误见errData.error_code
createMessage.error('录制错误,'+errData.msg);
});
}
/**
* 结束录制
*/
function recordingEnd(){
izRecording.value = false;
let fileName = formData.deviceIndex+'-'+(new Date().getTime());
player.value.stopRecording(fileName, true).then((res) => {
// 设置成功返回resolve
}).catch((errData) => {
// 设置失败,包括网络错误以及接口调用报错
// 具体错误见errData.error_code
createMessage.error('录制错误,'+errData.msg);
});
}
/**
* 开始电话
*/
function startPhone(){
getMultitransUrl({
"videoDevId":formData.deviceIndex
}).then(res=>{
player.value.startVoiceIntercom({
"url": res.url, // 该url为一次性 需要通过接口实时获取
"wssUrl": res.wssUrl,
"mode": "half_duplex"
});
izPhone.value = true;
});
}
/**
* 结束电话
*/
function stopPhone(){
player.value.stopVoiceIntercom();
izPhone.value = false;
}
/**
* 销毁
*/
function destroy(){
if (player){
player.value.destroy().then(() => {
}); // 销毁
}
}
defineExpose({
edit,
destroy
});
</script>
<style lang="less" scoped>
.antd-modal-form {
padding: 14px;
}
#video-container {
padding: 0px 25px;
width: 600px;
height: 500px;
background: #1a1a1a;
}
</style>