nursing_unit_vue/src/views/iot/tplink/camera/components/CameraPreviewModal.vue

470 lines
13 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>
<!-- <j-modal :title="title" :width="width" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭"> -->
<a-drawer :title="title" :width="width" v-model:visible="visible" :closable="true"
:footer-style="{ textAlign: 'right' }" @close="handleCancel">
<div v-if="showCamera">
<CameraPreviewForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false">
</CameraPreviewForm>
</div>
<template #footer>
<view style="display: flex;align-items: center; width: 100%;justify-content: space-between;">
<a-col :span="20" style="text-align: center;margin-top: 15px;margin-bottom: 15px;">
<!-- 对讲停止对讲 切换 -->
<!-- <img src="../../../../../assets/iot/monitor_1.png" class="buttonImg"/> -->
<span class="buttonSpan djImg" @click="startPhone" v-show="!izPhone"><span
style="margin-left:30px;">对讲</span></span>
<span class="buttonSpan djImg" @click="stopPhone" v-show="izPhone"><span
style="margin-left:30px;">结束</span></span>
<!-- 流畅超清 切换 -->
<span class="buttonSpan qxdImg" @click="switchResolution"><span style="margin-left:30px;">{{ resolution
}}</span></span>
<!-- 录制结束录制 切换 -->
<span class="buttonSpan lzImg" @click="recordingStart" v-show="!izRecording"><span
style="margin-left:30px;">录制</span></span>
<span class="buttonSpan lzImg" @click="recordingEnd" v-show="izRecording"><span
style="margin-left:30px;">结束</span></span>
<span class="buttonSpan jtImg" @click="screenshot"><span style="margin-left:30px;">截图</span></span>
<span class="buttonSpan bjImg" @click="manualAlarm"><span style="margin-left:30px;">报警</span></span>
<a-popover>
<template #content>
<div style="text-align: center;">
<div class="selectDiv" @click="setFishEyeDisplayMode('ORIGIN')">原图</div>
<div class="selectDiv" @click="setFishEyeDisplayMode('FISHEYE_360D')">360全景</div>
<div class="selectDiv" @click="setFishEyeDisplayMode('FISHEYE_180D')">180全景</div>
<div class="selectDiv" @click="setFishEyeDisplayMode('FISHEYE_WIN_PLANE_TOP_QUAD')">四分屏</div>
<div class="selectDiv" @click="setFishEyeDisplayMode('FISHEYE_LONGITUDE')">全景拉伸</div>
</div>
</template>
<span class="buttonSpan fpImg"><span style="margin-left:30px;">分屏</span></span>
</a-popover>
<a-popover>
<template #content>
<div style="text-align: center;">
<div class="selectDiv" @click="changeSwitch('flip_type', 'off')">关闭</div>
<div class="selectDiv" @click="changeSwitch('flip_type', 'left_and_right')">左右</div>
<div class="selectDiv" @click="changeSwitch('flip_type', 'up_and_down')">上下</div>
<div class="selectDiv" @click="changeSwitch('flip_type', 'center')">中心</div>
</div>
</template>
<span class="buttonSpan hmxzImg"><span style="margin-left:30px;">画面旋转</span></span>
</a-popover>
</a-col>
<a-button type="primary" style="margin-right: 8px" @click="handleCancel">关闭</a-button>
</view>
</template>
</a-drawer>
<!-- </j-modal> -->
</template>
<script lang="ts" setup>
import CameraPreviewForm from './CameraPreviewForm.vue'
import JModal from '/@/components/Modal/src/JModal/JModal.vue';
const title = ref<string>('');
const width = ref<string>('70%');
const visible = ref<boolean>(false);
const showCamera = ref<boolean>(false);
const disableSubmit = ref<boolean>(false);
const registerForm = ref();
const emit = defineEmits(['register', 'success', 'ok']);
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,
motionCtrl
} 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 formData = reactive<Record<string, any>>({
//预览通道参数
deviceIndex: '',//设备索引
streamType: 1,//码流类型 0 代表主码流1 代码子码流
//视频预览参数
url: '',//预览通道对应的URL
backupUrl: '',//备选URL当流媒体服务器存在内外网IP配置时该字段不为null
wsUrl: '',//用于建立ws连接传输视频帧信息
wssUrl: '',//用于建立wss接传输视频帧信息
flip_type: '',//画面镜像旋转: "off"//关闭 "left_and_right"//左右 "up_and_down"//上下 "center"//中心
zoom: 1, //变焦
sliderValue: 1,//滑动条的值
ptz: 0,//是否有云台
smartCode: 0,//是否可变焦
});
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 });
/**
* 编辑
* @param record
*/
async function edit(record) {
title.value = record.deviceName;
showCamera.value = true;
visible.value = true;
nextTick(() => {
registerForm.value.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();
}
/**
* 确定按钮点击事件
*/
function handleOk() {
registerForm.value.submitForm();
}
/**
* form保存回调事件
*/
function submitCallback() {
handleCancel();
}
/**
* 取消按钮回调事件
*/
function handleCancel() {
visible.value = false;
nextTick(() => {
registerForm.value.destroy();
showCamera.value = false;
});
}
/**
* 开始电话
*/
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;
}
/**
* 创建预览
*/
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(() => {
}); // 销毁
player.value = null;
}
console.log("🌊 ~ createPreview ~ a:", formData)
const TumsPlayer = window['tums-player'].default;
player.value = new TumsPlayer('video-container-preview', {
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(value) {
player.value.setFishEyeDisplayMode(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);
});
}
defineExpose({
edit,
disableSubmit,
});
</script>
<style lang="less">
/**隐藏样式-modal确定按钮 */
.jee-hidden {
display: none !important;
}
.ant-modal-body {
height: auto !important;
overflow: hidden !important;
}
</style>
<style lang="less" scoped>
.selectDiv {
text-align: center;
border: 1px solid white;
padding: 3px 10px;
width: 100px;
margin-top: 5px;
}
.selectDiv:hover {
border: 1px solid #f4f5fa;
background: #f4f5fa;
color: #037FEA;
border-radius: 10px;
cursor: pointer;
}
.buttonSpan {
display: inline-flex;
align-items: flex-end;
margin-left: 20px;
//border: 1px solid #f6faff;
padding: 6px 6px;
}
.buttonSpan:hover {
//border: 1px solid #1ea0fa;
color: #1ea0fa;
border-radius: 10px;
cursor: pointer;
}
.djImg {
background: url('../../../../../assets/iot/monitor_1.png') left/contain no-repeat;
}
.djImg:hover {
background: url('../../../../../assets/iot/monitor_1_1.png') left/contain no-repeat;
}
.qxdImg {
background: url('../../../../../assets/iot/monitor_5.png') left/contain no-repeat;
}
.qxdImg:hover {
background: url('../../../../../assets/iot/monitor_5_1.png') left/contain no-repeat;
}
.lzImg {
background: url('../../../../../assets/iot/monitor_4.png') left/contain no-repeat;
}
.lzImg:hover {
background: url('../../../../../assets/iot/monitor_4_1.png') left/contain no-repeat;
}
.jtImg {
background: url('../../../../../assets/iot/monitor_3.png') left/contain no-repeat;
}
.jtImg:hover {
background: url('../../../../../assets/iot/monitor_3_1.png') left/contain no-repeat;
}
.bjImg {
background: url('../../../../../assets/iot/monitor_8.png') left/contain no-repeat;
}
.bjImg:hover {
background: url('../../../../../assets/iot/monitor_8_1.png') left/contain no-repeat;
}
.fpImg {
background: url('../../../../../assets/iot/monitor_6.png') left/contain no-repeat;
}
.fpImg:hover {
background: url('../../../../../assets/iot/monitor_6_1.png') left/contain no-repeat;
}
.hmxzImg {
background: url('../../../../../assets/iot/monitor_7.png') left/contain no-repeat;
}
.hmxzImg:hover {
background: url('../../../../../assets/iot/monitor_7_1.png') left/contain no-repeat;
}
</style>