feat: 同步
This commit is contained in:
320
src/views/lps/aqsbss/video.vue
Normal file
320
src/views/lps/aqsbss/video.vue
Normal file
@ -0,0 +1,320 @@
|
||||
<template>
|
||||
<div class="bigBox">
|
||||
<MOSTY.FromPage title="预制点选择" @closeDialog="black">
|
||||
<template #content>
|
||||
<div class="main">
|
||||
<div class="left">
|
||||
<video controls style="width:100%;height:100%;object-fit:fill" id='videoElement'></video>
|
||||
</div>
|
||||
<div class="right">
|
||||
<MOSTY.Assort title="方向控制" style="padding: 10px" />
|
||||
<div class="controller">
|
||||
<div v-for="btn in directionButton" :key="btn.key"
|
||||
:class="[btn.value !== 9 ? 'sector' : '', btn.key]" :title="btn.label"
|
||||
@mousedown="handleRegulate(btn, 0)" @mouseup="handleRegulate(btn, 1)">
|
||||
<el-icon>
|
||||
<CaretLeft />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<MOSTY.Assort title="预制点" style="padding: 10px" />
|
||||
<div style="text-align: left;" class="ml10">
|
||||
<el-button size="small" @click="createPrefabricatedPoints()">创建</el-button>
|
||||
</div>
|
||||
<el-table size="small" :data="pointList" style="width: 100%">
|
||||
<el-table-column prop="presetPointName" label="名称" />
|
||||
<el-table-column label="操作">
|
||||
<template #default="{ row }">
|
||||
<span class="operedit" @click="selectPoint(row)">
|
||||
<el-icon>
|
||||
<Position />
|
||||
</el-icon>选择</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="black"> <el-icon>
|
||||
<DocumentDelete />
|
||||
</el-icon>关闭</el-button>
|
||||
</template>
|
||||
</MOSTY.FromPage>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, onMounted, getCurrentInstance, reactive } from "vue";
|
||||
import * as MOSTY from "@/components/MyComponents/index";
|
||||
import { ElMessage, ElMessageBox } from "element-plus"
|
||||
import { getApi, postApi } from "@/api/tobAcco_api.js";
|
||||
const { proxy } = getCurrentInstance();
|
||||
let cameraDirectionControl = reactive({ stepX: 4, stepY: 4 })
|
||||
let listOfPreFabricatedCameraPoints = ref([])
|
||||
let hls = null
|
||||
let pointList = ref([])
|
||||
const props = defineProps({
|
||||
sbbh: {
|
||||
type: String,
|
||||
default: '1003105'
|
||||
},
|
||||
tddh: {
|
||||
type: String,
|
||||
default: '1003105$1$0$0'
|
||||
}
|
||||
});
|
||||
const directionButton = reactive([
|
||||
{ label: "上", key: "up", value: 1 },
|
||||
{ label: "右上", key: "up-right", value: 7 },
|
||||
{ label: "右", key: "right", value: 4 },
|
||||
{ label: "右下", key: "down-right", value: 8 },
|
||||
{ label: "下", key: "down", value: 2 },
|
||||
{ label: "左下", key: "down-left", value: 6 },
|
||||
{ label: "左", key: "left", value: 3 },
|
||||
{ label: "左上", key: "up-left", value: 5 },
|
||||
{ label: "中心", key: "center", value: 9 }]
|
||||
)
|
||||
const emit = defineEmits("saveSuccess");
|
||||
onMounted(() => {
|
||||
initVideo(props.tddh)
|
||||
getPointList()
|
||||
});
|
||||
|
||||
/**
|
||||
* 创建预设点
|
||||
*/
|
||||
const createPrefabricatedPoints = () => {
|
||||
ElMessageBox.prompt("输入预制点名称", "预制点创建", {
|
||||
confirmButtonText: "确认",
|
||||
cancelButtonText: "取消",
|
||||
inputPattern: /\S/,
|
||||
inputErrorMessage: "预制点名称不能为空"
|
||||
}).then(({ value }) => {
|
||||
let data = {
|
||||
presetPointCode: generateUniqueCode(listOfPreFabricatedCameraPoints.value),
|
||||
operateType: 3,
|
||||
presetPointName: value
|
||||
}
|
||||
cameraPreFabricationPointSetting(data)
|
||||
}).catch((err) => {
|
||||
ElMessage({
|
||||
type: "info",
|
||||
message: "Input canceled"
|
||||
})
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 设置功能预制点
|
||||
* @param data
|
||||
*/
|
||||
const cameraPreFabricationPointSetting = async (data) => {
|
||||
await postApi({ ...data, channelId: props.tddh }, "/mosty-lps/daSdk/operatePresetPoint")
|
||||
await getPointList()
|
||||
}
|
||||
/**
|
||||
* 生成唯一编码
|
||||
* @param presetArray
|
||||
* @returns {string}
|
||||
*/
|
||||
function generateUniqueCode(presetArray) {
|
||||
const existingCodes = new Set(presetArray.map(item => item.presetPointCode))
|
||||
let code
|
||||
do {
|
||||
const num = Math.floor(Math.random() * 256) + 1
|
||||
code = num.toString().padStart(3, "0")
|
||||
if (existingCodes.size >= 256) throw new Error("所有可能的编码都已被占用")
|
||||
} while (existingCodes.has(code))
|
||||
return code
|
||||
}
|
||||
/**
|
||||
* 保存预制点
|
||||
* @param data
|
||||
*/
|
||||
const selectPoint = (data) => {
|
||||
emit("saveSuccess", data);
|
||||
}
|
||||
/**
|
||||
* 获取预置点
|
||||
* @param id
|
||||
*/
|
||||
const getPointList = async () => {
|
||||
let data = await postApi({ channelId: props.tddh }, "/mosty-lps/daSdk/getPresetPoints")
|
||||
if (data instanceof Array) pointList.value = data
|
||||
}
|
||||
/**
|
||||
* 摄像头方向控制
|
||||
* @param btn
|
||||
* @param type
|
||||
*/
|
||||
const handleRegulate = async (btn, type) => {
|
||||
cameraDirectionControl.channelId = props.tddh
|
||||
cameraDirectionControl.command = !type ? 1 : 0
|
||||
cameraDirectionControl.direct = btn.value
|
||||
await postApi(cameraDirectionControl, "/mosty-lps/daSdk/operateDirect")
|
||||
}
|
||||
/**
|
||||
* 初始化摄像头设备
|
||||
* @param channelId
|
||||
* @param domId
|
||||
*/
|
||||
const initVideo = async (channelId) => {
|
||||
if (hls !== null) hls.destroy()
|
||||
const videoElement = document.getElementById("videoElement")
|
||||
//调用Hls.isSupported()检查浏览器是否支持MSE
|
||||
let data = await postApi({ channelId, "streamType": 1, type: "hls" }, "/mosty-lps/daSdk/realtime")
|
||||
if (proxy?.$Hls.isSupported()) {
|
||||
hls = new Hls()
|
||||
hls.attachMedia(videoElement)
|
||||
hls.on(Hls.Events.MEDIA_ATTACHED, async () => {
|
||||
hls.loadSource(data)
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, () => videoElement.play())
|
||||
})
|
||||
return
|
||||
} else if (videoElement.canPlayType("application/vnd.apple.mpegurl")) {
|
||||
// 如果支持原生播放
|
||||
videoElement.src = data
|
||||
videoElement.addEventListenter("canplay", () => videoElement.play())
|
||||
return
|
||||
}
|
||||
ElMessage.error("当前环境不支持初始化")
|
||||
}
|
||||
const black = () => {
|
||||
emit("saveSuccess");
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bigBox {
|
||||
.main {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
|
||||
.left {
|
||||
width: 75%;
|
||||
height: 100%;
|
||||
border: 1px solid grey;
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 25%;
|
||||
height: 100%;
|
||||
border: 1px solid grey;
|
||||
|
||||
.controller {
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: rotate(22deg);
|
||||
box-shadow: var(--panel-head-box-shadow);
|
||||
border-radius: 50%;
|
||||
z-index: 9;
|
||||
|
||||
.sector {
|
||||
width: 194px;
|
||||
height: 194px;
|
||||
background-color: #f6f4f4;
|
||||
clip-path: polygon(50% 50%, 100% 50%, 100% 3%);
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--core-hover-color);
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 63px;
|
||||
transform: rotate(-200deg);
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
/* 各个方向的扇形按钮 */
|
||||
.up {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
.right {
|
||||
transform: rotate(0deg);
|
||||
|
||||
.el-icon {
|
||||
transform: rotate(-202deg);
|
||||
}
|
||||
}
|
||||
|
||||
.down-right {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.down {
|
||||
transform: rotate(90deg);
|
||||
|
||||
.el-icon {
|
||||
transform: rotate(-204deg);
|
||||
}
|
||||
}
|
||||
|
||||
.down-left {
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
|
||||
.left {
|
||||
transform: rotate(180deg);
|
||||
|
||||
.el-icon {
|
||||
transform: rotate(-200deg);
|
||||
}
|
||||
}
|
||||
|
||||
.up-left {
|
||||
transform: rotate(225deg);
|
||||
}
|
||||
|
||||
.up {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
.up-right {
|
||||
transform: rotate(315deg);
|
||||
}
|
||||
|
||||
/* 中心的圆形空心区域 */
|
||||
.center {
|
||||
position: absolute;
|
||||
transform: translate(-50%, -50%);
|
||||
/* 将中心定位到控制器的中心 */
|
||||
width: 65px;
|
||||
height: 65px;
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
background-color: var(--core-button-normal-bg-color);
|
||||
border: 1px solid var(--core-border-color);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
|
||||
z-index: 10;
|
||||
/* 确保中心区域在其他扇形之上 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--core-hover-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
display: block !important;
|
||||
padding: 0 14px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user