项目级页面添加漫游、摄像头、定位设备、无人机、摄像头视频播放

This commit is contained in:
2025-09-09 21:52:59 +08:00
parent 35a7825759
commit d5cf2a600e
7 changed files with 180 additions and 47 deletions

View File

@ -123,6 +123,8 @@ function addPre() {
// 视频播放
function videoPlay(obj: any) {
console.log('objobjobj',obj);
getAccessToken().then((res: any) => {
if (res.code == 200 && obj.deviceSerial) {
flvPlayer.value = new EZUIKit.EZUIKitPlayer({

View File

@ -1,7 +1,7 @@
<template>
<div class="centerPage">
<div class="topPage">
<newMap></newMap>
<newMap :isHide="isHide"></newMap>
</div>
<div class="endPage" :class="{ 'slide-out-down': isHide }">
<Title title="AI安全巡检">
@ -16,7 +16,7 @@
<div class="swiper_content" ref="swiperContent">
<div class="swiper_item" v-for="(item, i) in inspectionList" :key="i">
<img :src="item.picture" alt="安全巡检" class="swiper_img">
<div class="swiper_date">{{ item.createTime.slice(5) }}</div>
<!-- <div class="swiper_date">{{ item.createTime.slice(5) }}</div> -->
<div class="swiper_tip">{{ item.label }}</div>
</div>
</div>

View File

@ -1,11 +1,22 @@
<script setup>
import { onMounted, ref, onUnmounted } from 'vue';
import { onMounted, ref, onUnmounted,defineProps} from 'vue';
import CesiumImageLabelEntity from '../js/CesiumImageLabelEntity.js';
import CesiumFlyToRoamingController from '../js/CesiumFlyToRoamingController.js';
import { setSelect, getSelectList, getGps } from '@/api/projectScreen/index.ts'
import videoDialog from "./video.vue"
const defaultExpandedKeys = [1, 2, 3] //默认展开第一级节点
const defaultCheckedKeys = ref([]) //默认选中节点
const data = ref([]);
const deviceId = ref('');
const videoDialogRef = ref(null);
const props = defineProps({
isHide:{
type:Boolean,
default:true,
}
})
console.log('props', props);
const defaultProps = {
children: 'children',
label: 'label',
@ -58,15 +69,24 @@ function renderDevice(item) {
lat: Number(item.lat),
height: 0
},
imageWidth: 64,
imageHeight: 64,
name: item.label || item.id,
imageUrl: "/assets/demo/avatar.png",
onClick: entityClickHandler
imageUrl: `/image/${item.type}.png`,
onClick: (entity)=>{
entityClickHandler(entity,item);
}
});
window.deviceMap.set(item.id, imageEntity);
}
// 实体的点击事件
function entityClickHandler(entity) {
console.log('entity', entity);
function entityClickHandler(entity,item) {
console.log('entity', entity,item);
if (item.type == 'camera') {
deviceId.value = 'AE9470016';
videoDialogRef.value.show();
videoDialogRef.value.videoPlay(deviceId.value);
}
}
// 初始化地球
function initEarth() {
@ -111,11 +131,6 @@ function loadTiltData(viewer) {
// url:"http://58.17.134.85:7363/yjearth4.0/data/pak/e904acb32aaa8b872c64866ebaaaf5e2"
url: import.meta.env.VITE_EARTH_URL + "/yjearth4.0/data/pak/4eb21d3fc02873092e75640e261544b3"
});
// var tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
// // url: 'http://58.17.134.85:7363/zm/api/v1/data/tileset/b15be28d053fcdd98308bed74c6108e6/tileset.json',
// url:'http://58.17.134.85:7363/yjearth4.0/data/tileset/9c25649daa610a0cfb89e2cbea74bc55/tileset.json'
// }));
// console.log("加载倾斜数据:", tileset);
}
// 获取ArcGIS服务的URL
function getArcGisUrlByType(type) {
@ -134,7 +149,7 @@ function getArcGisUrlByType(type) {
return "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetGray/MapServer";
//暖色底图
case "vec_warm":
return "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetWarm/MapServer";
return "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetWarm/MapServer";
}
}
// 添加ArcGIS图层
@ -218,17 +233,18 @@ onUnmounted(() => {
<template>
<div class="earth-container-big">
<div class="earth" id="earth"></div>
<div class="left">
<div v-show="isHide" class="left">
<div style="width: 100%;height: 100%;">
<el-button type="primary" @click="startRoaming">开始漫游</el-button>
<el-button type="primary" @click="stopRoaming">停止漫游</el-button>
</div>
</div>
<div class="right">
<div v-show="isHide" class="right">
<el-tree show-checkbox :data="data" :props="defaultProps" node-key="id" :expand-on-click-node="false"
:check-on-click-node="false" :check-on-click-leaf="false" :default-expanded-keys="defaultExpandedKeys"
:default-checked-keys="defaultCheckedKeys" @check="handleCheck" @node-click="handleNodeClick" />
</div>
<videoDialog :data="deviceId" ref="videoDialogRef"></videoDialog>
</div>
</template>
<style lang="scss">
@ -255,7 +271,7 @@ onUnmounted(() => {
.right,
.left {
position: absolute;
width: 200px;
width: 400px;
height: 100%;
transform: translateY(-50%);
background-color: #00000052;

View File

@ -0,0 +1,109 @@
<template>
<el-dialog v-model="visible" title="摄像头直播" :width="dialogWidth" :height="dialogHeight" :before-close="handleClose"
destroy-on-close>
<div class="video-container-entity" id="video-container-entity" style="width: 100%; height: 600px"></div>
<!-- <template #footer>
<el-button type="primary" @click="handlesubmit">确定</el-button>
<el-button type="danger" @click="handleClose">关闭</el-button>
</template> -->
</el-dialog>
</template>
<script setup>
import { ref, onMounted, defineEmits, defineProps,onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { getAccessToken } from '@/api/other/ys7Device';
import EZUIKit from 'ezuikit-js';
const emit = defineEmits(['send-data', 'close']);
const props = defineProps({
data: {
type: Object,
default: () => { }
}
});
// 弹窗控制变量
const visible = ref(false);
const dialogWidth = ref('950px');
const dialogHeight = ref('90%');
let loading = ref(true);
const flvPlayer = ref(null);
const show = () => {
visible.value = true;
}
// 关闭弹窗
const handleClose = () => {
visible.value = false;
};
// 处理数据传递
const handlesubmit = () => {
handleClose();
};
// 视频播放
function videoPlay(deviceSerial) {
getAccessToken().then((res) => {
if (res.code == 200 && deviceSerial) {
flvPlayer.value = new EZUIKit.EZUIKitPlayer({
audio: '0',
id: 'video-container-entity',
accessToken: res.data,
url: `ezopen://open.ys7.com/${deviceSerial}/1.hd.live`,
template: 'pcLive',
width: 870,
height: 600,
plugin: ['talk'],
handleError: function (err) {
console.log(err);
if (err?.data?.ret === 20020) {
// 20020 是并发连接限制的错误码
ElMessage.error('当前观看人数已达上限,请稍后再试');
}
}
});
}
});
}
// 组件挂载时设置容器ID
onMounted(() => {
});
// 暴露显示方法给父组件
defineExpose({
show,
videoPlay
});
//
onUnmounted(() => {
});
</script>
<style scoped>
.earth-container {
width: 100%;
height: 600px;
overflow: hidden;
position: relative;
}
:deep(.el-dialog__body) {
padding: 10px;
height: calc(100% - 100px);
overflow: hidden;
}
:deep(.el-dialog) {
display: flex;
flex-direction: column;
max-height: 90vh;
}
:deep(.el-dialog__content) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
</style>

View File

@ -53,8 +53,12 @@ export default class CesiumImageLabelEntity {
// 创建实体
this.entity = this.createEntity();
// 初始化点击事件监听
this.initClickHandler();
// 为实体添加标识,方便后续判断
this.entity._isImageLabelEntity = true;
this.entity._imageLabelInstance = this;
// 初始化全局点击事件(确保只注册一次)
this.initGlobalClickHandler();
}
/**
@ -67,7 +71,7 @@ export default class CesiumImageLabelEntity {
position: Cesium.Cartesian3.fromDegrees(
this.options.position.lng,
this.options.position.lat,
this.options.position.alt
this.options.position.height || 0 // 修复使用height而非alt
),
show: this.options.show,
@ -79,8 +83,7 @@ export default class CesiumImageLabelEntity {
color: this.options.imageColor,
horizontalOrigin: this.options.horizontalOrigin,
verticalOrigin: this.options.verticalOrigin,
// 允许实体被选中
pickable: true
pickable: true // 确保可拾取
},
// 名称标签属性
@ -91,12 +94,10 @@ export default class CesiumImageLabelEntity {
horizontalOrigin: this.options.horizontalOrigin,
verticalOrigin: Cesium.VerticalOrigin.TOP,
pixelOffset: new Cesium.Cartesian2(0, this.options.labelOffsetY),
// 添加背景
backgroundColor: new Cesium.Color(0, 0, 0, 0),
backgroundColor: new Cesium.Color(0, 0, 0, 0.5), // 修复:半透明背景更易点击
backgroundPadding: new Cesium.Cartesian2(5, 5),
showBackground: true,
// 允许标签被选中
pickable: true
pickable: true // 确保可拾取
}
});
@ -107,29 +108,33 @@ export default class CesiumImageLabelEntity {
}
/**
* 初始化点击事件处理器
* 初始化全局点击事件处理器(只注册一次)
*/
initClickHandler() {
// 存储当前实例的引用,方便在回调中使用
const self = this;
// 注册左击事件
this.viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
// 检测是否点击了当前实体
const pickedObject = self.viewer.scene.pick(movement.position);
initGlobalClickHandler() {
// 检查是否已注册全局事件,避免重复注册
if (!this.viewer._imageLabelGlobalClickHandler) {
const handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
// 检查是否点击了当前实体或其实体的子组件billboard、label等
if (Cesium.defined(pickedObject) &&
(pickedObject.id === self.entity ||
pickedObject.id === self.entity.billboard ||
pickedObject.id === self.entity.label)) {
// 如果设置了点击回调,则执行
if (self.onClickCallback && typeof self.onClickCallback === 'function') {
self.onClickCallback(self.entity, movement.position);
handler.setInputAction((movement) => {
const pickedObject = this.viewer.scene.pick(movement.position);
// 判断是否点击了我们创建的图片标签实体
if (Cesium.defined(pickedObject) &&
Cesium.defined(pickedObject.id) &&
pickedObject.id._isImageLabelEntity) {
// 调用对应实例的回调函数
if (pickedObject.id._imageLabelInstance.onClickCallback) {
pickedObject.id._imageLabelInstance.onClickCallback(
pickedObject.id,
movement.position
);
}
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 存储全局事件处理器引用,避免重复创建
this.viewer._imageLabelGlobalClickHandler = handler;
}
}
/**