test/src/views/lps/aqsbss/video.vue

320 lines
10 KiB
Vue
Raw Normal View History

2025-03-30 22:20:09 +08:00
<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>