Merge branch 'main' of http://123.132.248.154:10000/gitY/DiKongGanZhiPingTai
commit
17f4dfced7
|
|
@ -0,0 +1,14 @@
|
|||
import { defHttp } from '@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
VerifyToken = '/api/DroneDock/VerifyToken',
|
||||
GetDroneDockflightInfos = '/api/DroneDock/GetDroneDockflightInfos',
|
||||
}
|
||||
|
||||
export function getVerifyToken(token) {
|
||||
return defHttp.get({ url: Api.VerifyToken + '?token=' + token });
|
||||
}
|
||||
|
||||
export function getDroneDockflightInfos(id) {
|
||||
return defHttp.get({ url: Api.GetDroneDockflightInfos + '?taskid=' + id });
|
||||
}
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
import { createConnection, client, servicesTopic, destroyConnection } from './src/mqtt';
|
||||
import { airport, uav, liveInfo, buildGUID } from './src/config';
|
||||
import { GetUavPageByDocksn } from '@/api/demo/projecthome';
|
||||
import { getVerifyToken, getDroneDockflightInfos } from '@/api/workmanagement/droneDock';
|
||||
import TCPlayer from 'tcplayer.js';
|
||||
|
||||
const bid = buildGUID();
|
||||
let video_id;
|
||||
let sn;
|
||||
let live_url;
|
||||
|
||||
class LiveStreamPlugin {
|
||||
constructor() {
|
||||
console.log('LiveStreamPlugin constructor');
|
||||
}
|
||||
initSDK(token: String) {
|
||||
/**
|
||||
* 初始化SDK。token:用国土调查云ak/sk生成的token,
|
||||
* 分中心进行校验通过才能使用直播插件
|
||||
*/
|
||||
return getVerifyToken(token).then((res) => {
|
||||
return res;
|
||||
});
|
||||
}
|
||||
setLiveStreamControl(divContainor: HTMLElement, deviceType: number) {
|
||||
/**
|
||||
* 设置视频直播画面控件,用于展示视频直播。
|
||||
* divContainor:div元素
|
||||
* deviceType: 0无人机 1 机场监控
|
||||
*/
|
||||
console.log('LiveStreamPlugin setLiveStreamControl', divContainor, deviceType);
|
||||
divContainor.innerHTML =
|
||||
' <video id="player-container-id" preload="auto" playsinline webkit-playsinline > </video>';
|
||||
setTimeout(() => {
|
||||
const player = TCPlayer('player-container-id', {
|
||||
sources: [
|
||||
{
|
||||
src: live_url + '.flv', // 播放地址
|
||||
},
|
||||
],
|
||||
licenseUrl: live_url + '.flv', // license 地址,必传。参考准备工作部分,在视立方控制台申请 license 后可获得 licenseUrl
|
||||
autoplay: true, // 是否自动播放
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
async startLiveStreamCall(serialNum: String, deviceType: number) {
|
||||
/**
|
||||
* 开始视频直播
|
||||
* serialNum:无人机机场序列号
|
||||
* deviceType: 0无人机 1 机场监控
|
||||
*/
|
||||
console.log('LiveStreamPlugin startLiveStreamCall', serialNum, deviceType);
|
||||
sn = serialNum;
|
||||
createConnection('mqtt_' + serialNum);
|
||||
video_id =
|
||||
deviceType == 1
|
||||
? serialNum + '/' + airport.camera_index + '/' + airport.video_index
|
||||
: serialNum + '/' + uav.camera_index + '/' + uav.video_index;
|
||||
// const liveUrl = liveInfo.rtmp + serialNum;
|
||||
let querys;
|
||||
if (deviceType == 1) {
|
||||
querys = {
|
||||
bid: bid,
|
||||
method: 'live_start_push',
|
||||
tid: buildGUID(),
|
||||
timestamp: new Date().getTime(),
|
||||
data: {
|
||||
url_type: 1,
|
||||
url: liveInfo.rtmp + '5',
|
||||
video_id: video_id,
|
||||
video_quality: 3,
|
||||
},
|
||||
};
|
||||
live_url = liveInfo.url + '5';
|
||||
} else {
|
||||
// 根据机场sn获取无人机sn
|
||||
const params = {
|
||||
sn: sn,
|
||||
page: 1,
|
||||
limit: 99,
|
||||
};
|
||||
await GetUavPageByDocksn(params).then((res) => {
|
||||
console.log('GetUavPageByDocksn', res);
|
||||
if (res.items.length > 0) {
|
||||
querys = {
|
||||
bid: bid,
|
||||
method: 'live_start_push',
|
||||
tid: buildGUID(),
|
||||
timestamp: new Date().getTime(),
|
||||
data: {
|
||||
url_type: 1,
|
||||
url: liveInfo.rtmp + '6',
|
||||
video_id: video_id,
|
||||
video_quality: 3,
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
live_url = liveInfo.url + '5';
|
||||
}
|
||||
// 发送消息
|
||||
servicesTopic(serialNum, querys);
|
||||
// 订阅回执
|
||||
client.subscribe('thing/product/' + serialNum + '/services_reply', { qos: 0 }, () => {});
|
||||
// 接收消息
|
||||
client.on('message', (topic, message) => {
|
||||
const rs = JSON.parse(message);
|
||||
if (rs.bid == bid) {
|
||||
console.log(rs);
|
||||
console.log('LiveStreamPlugin liveStartPush', rs);
|
||||
}
|
||||
});
|
||||
}
|
||||
endLiveStreamCall(deviceType: number) {
|
||||
/**
|
||||
* 结束视频直播
|
||||
* deviceType: 0无人机 1 机场监控
|
||||
*/
|
||||
console.log('LiveStreamPlugin endLiveStreamCall', deviceType);
|
||||
const querys = {
|
||||
bid: bid,
|
||||
method: 'live_stop_push',
|
||||
tid: buildGUID(),
|
||||
timestamp: new Date().getTime(),
|
||||
data: {
|
||||
video_id: video_id,
|
||||
},
|
||||
};
|
||||
servicesTopic(sn, querys);
|
||||
}
|
||||
takePicture(callback) {
|
||||
/**
|
||||
* 拍照
|
||||
* callback:拍照完成回调方法,
|
||||
* 参数如下: issuccess:状态
|
||||
* true/false;
|
||||
* imgBlob:照片文件Blob;
|
||||
* zpkzxx:照片扩展信息
|
||||
*/
|
||||
console.log('LiveStreamPlugin takePicture', callback);
|
||||
servicesTopic(sn, {
|
||||
bid: bid,
|
||||
method: 'camera_photo_take',
|
||||
tid: buildGUID(),
|
||||
timestamp: new Date().getTime(),
|
||||
data: {
|
||||
payload_index: uav.camera_index,
|
||||
},
|
||||
});
|
||||
const data = {};
|
||||
callback(data);
|
||||
}
|
||||
startVideoRecording() {
|
||||
/**
|
||||
* 开始录像
|
||||
*/
|
||||
console.log('LiveStreamPlugin startVideoRecording');
|
||||
servicesTopic(sn, {
|
||||
bid: bid,
|
||||
method: 'payload_authority_grab',
|
||||
tid: buildGUID(),
|
||||
timestamp: new Date().getTime(),
|
||||
data: {
|
||||
payload_index: uav.camera_index,
|
||||
},
|
||||
});
|
||||
servicesTopic(sn, {
|
||||
bid: bid,
|
||||
method: 'camera_recording_start',
|
||||
tid: buildGUID(),
|
||||
timestamp: new Date().getTime(),
|
||||
data: {
|
||||
payload_index: uav.camera_index,
|
||||
},
|
||||
});
|
||||
}
|
||||
endVideoRecording(callback: Function) {
|
||||
/**
|
||||
* 结束录像
|
||||
* callback:录像完成回调方法,
|
||||
* 参数如下: issuccess:状态
|
||||
* true/false;
|
||||
*/
|
||||
console.log('LiveStreamPlugin endVideoRecording', callback);
|
||||
servicesTopic(sn, {
|
||||
bid: bid,
|
||||
method: 'camera_recording_stop',
|
||||
tid: buildGUID(),
|
||||
timestamp: new Date().getTime(),
|
||||
data: {
|
||||
payload_index: uav.camera_index,
|
||||
},
|
||||
});
|
||||
const data = {};
|
||||
callback(data);
|
||||
}
|
||||
disposeSDK() {
|
||||
/**
|
||||
* 销毁SDK
|
||||
*/
|
||||
console.log('LiveStreamPlugin disposeSDK');
|
||||
destroyConnection();
|
||||
}
|
||||
async getFlightTaskInfo(serialNum: String) {
|
||||
/**
|
||||
* 获取无人机任务信息
|
||||
* 参数:serialNum无人机机场序列号
|
||||
* 返回结果:FlightTaskInfo
|
||||
*/
|
||||
console.log('LiveStreamPlugin getFlightTaskInfo', serialNum);
|
||||
|
||||
client.subscribe('thing/product/' + serialNum + '/events', { qos: 2 }, () => {});
|
||||
// 接收消息
|
||||
let id = '';
|
||||
client.on('message', async (topic, message) => {
|
||||
const rs = JSON.parse(message);
|
||||
if (
|
||||
rs.method == 'flighttask_progress' &&
|
||||
rs.data.output.status == 'in_progress' &&
|
||||
id == ''
|
||||
) {
|
||||
console.log(rs);
|
||||
id = rs.data.output.ext.flight_id;
|
||||
return new Promise((resolve, reject) => {
|
||||
getDroneDockflightInfos(id).then((res) => {
|
||||
console.log(res);
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
return await getDroneDockflightInfos(id).then((res) => {
|
||||
return res;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default LiveStreamPlugin;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
export const airport = {
|
||||
camera_index: '165-0-7',
|
||||
video_index: 'normal-0',
|
||||
};
|
||||
export const uav = {
|
||||
camera_index: '99-0-0',
|
||||
video_index: 'normal-0',
|
||||
};
|
||||
export const liveInfo = {
|
||||
rtmp: 'rtmp://box.wisestcity.com:1935/live/',
|
||||
url: 'http://box.wisestcity.com:8081/live/',
|
||||
};
|
||||
const hexList: string[] = [];
|
||||
for (let i = 0; i <= 15; i++) {
|
||||
hexList[i] = i.toString(16);
|
||||
}
|
||||
export function buildGUID(): string {
|
||||
let guid = '';
|
||||
for (let i = 1; i <= 36; i++) {
|
||||
if (i === 9 || i === 14 || i === 19 || i === 24) {
|
||||
guid += '-';
|
||||
} else if (i === 15) {
|
||||
guid += 4;
|
||||
} else if (i === 20) {
|
||||
guid += hexList[(Math.random() * 4) | 8];
|
||||
} else {
|
||||
guid += hexList[(Math.random() * 16) | 0];
|
||||
}
|
||||
}
|
||||
return guid;
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import mqtt from 'mqtt';
|
||||
|
||||
const connection = {
|
||||
protocol: 'ws',
|
||||
host: '175.27.168.120',
|
||||
port: 6010,
|
||||
endpoint: '/mqtt',
|
||||
clean: true,
|
||||
connectTimeout: 30 * 1000, // ms
|
||||
reconnectPeriod: 4000, // ms
|
||||
clientId: '',
|
||||
username: 'sdhc',
|
||||
password: '',
|
||||
};
|
||||
|
||||
let client: any = {
|
||||
connected: false,
|
||||
};
|
||||
// 创建连接函数
|
||||
const createConnection = (id, callback?) => {
|
||||
try {
|
||||
connection.clientId = id;
|
||||
const { protocol, host, port, endpoint, ...options } = connection;
|
||||
const connectUrl = `${protocol}://${host}:${port}${endpoint}`;
|
||||
client = mqtt.connect(connectUrl, options);
|
||||
client.on('connect', () => {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('mqtt.connect error', error);
|
||||
}
|
||||
};
|
||||
// 断开连接
|
||||
const destroyConnection = () => {
|
||||
if (client.connected) {
|
||||
try {
|
||||
client.end(false, () => {
|
||||
client = {
|
||||
connected: false,
|
||||
};
|
||||
console.log('Successfully disconnected!');
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('Disconnect failed', error.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
// 订阅事件
|
||||
const clientSubscribe = (topic: string) => {
|
||||
client.subscribe(topic, { qos: 0 }, () => {});
|
||||
};
|
||||
// 发送消息
|
||||
// 定义一个函数clientPublish,用于发布消息
|
||||
const clientPublish = (topic: string, querys: any) => {
|
||||
client.publish(topic, JSON.stringify(querys), { qos: 0 }, (err) => {
|
||||
if (err) {
|
||||
console.error('Publish error:', err);
|
||||
}
|
||||
});
|
||||
};
|
||||
// 发送消息
|
||||
export const servicesTopic = (id, data) => {
|
||||
console.log(id, data);
|
||||
// 发送消息
|
||||
clientPublish('thing/product/' + id + '/services', data);
|
||||
};
|
||||
|
||||
export { createConnection, client, destroyConnection };
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<div>
|
||||
<a-button @click="starAirpot">开启机场直播</a-button>
|
||||
<a-button @click="startUAV">开启无人机直播</a-button>
|
||||
<a-button @click="startRecording">开始录像</a-button>
|
||||
<a-button @click="endRecording">结束录像</a-button>
|
||||
<a-button @click="liveStreamPlugin.disposeSDK">释放资源</a-button>
|
||||
<a-button @click="getTask">获取航线任务</a-button>
|
||||
<a-button @click="viewLive">展示视频直播</a-button>
|
||||
<div id="live-div"> </div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import LiveStreamPlugin from '@/plugin/video/index';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
const liveStreamPlugin = new LiveStreamPlugin();
|
||||
const starAirpot = () => {
|
||||
liveStreamPlugin.startLiveStreamCall('8UUXN5400A079H', 1);
|
||||
};
|
||||
const startUAV = () => {
|
||||
liveStreamPlugin.startLiveStreamCall('1581F8HGX254V00A0BUY', 0);
|
||||
};
|
||||
const startRecording = () => {
|
||||
liveStreamPlugin.startVideoRecording();
|
||||
};
|
||||
const endRecording = () => {
|
||||
liveStreamPlugin.endVideoRecording((res) => {
|
||||
console.log(res);
|
||||
});
|
||||
};
|
||||
const getTask = async () => {
|
||||
await liveStreamPlugin.getFlightTaskInfo('8UUXN5400A079H').then((res) => {
|
||||
console.log(res);
|
||||
});
|
||||
};
|
||||
const viewLive = () => {
|
||||
console.log(document.getElementById('live-div'));
|
||||
liveStreamPlugin.setLiveStreamControl(document.getElementById('live-div'), '1');
|
||||
};
|
||||
onMounted(async () => {
|
||||
const token =
|
||||
'API32_HENJOZMPBYKEXNVLFMY3Y5W5SQ.1751622229582.fmCjIucQYyq4YZe4CnSStN/rHcwjZTxUsDuXeXJfrYn0bwoaV1/IW8mcFwtLw8JHjowvMJrmPyy/QZAhssxQCQ==';
|
||||
const status = await liveStreamPlugin.initSDK(token);
|
||||
console.log(status);
|
||||
if (!status) {
|
||||
console.log('初始化失败');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="home-page">
|
||||
<div style="width: 100%;height: calc(100vh - 80px);">
|
||||
<Map :airRoute="airRoute" @mapOnLoad="mapOnLoad" :homeAirport="airPort" @clickAirPort="clickAirPort"/>
|
||||
<Map :airRoute="airRoute" @mapOnLoad="mapOnLoad" :homeAirport="airPort" @clickAirPort="clickAirPort" @changeAirportLive="changeAirportLive" @changeUAVLive="changeUAVLive"/>
|
||||
</div>
|
||||
<div ref="leftComponentRef" style="position: absolute;top: 0px;left: 0px;">
|
||||
<!-- 项目列表 -->
|
||||
|
|
@ -15,6 +15,17 @@
|
|||
<!-- 成果动态 -->
|
||||
<Result />
|
||||
</div>
|
||||
<AirportLive
|
||||
:msgData="msgData"
|
||||
v-if="airportLiveVisible"
|
||||
@changeAirportLive="airportLiveVisible = false"
|
||||
/>
|
||||
<LivePreview
|
||||
v-if="livePreviewVisible"
|
||||
:msgData="msgData"
|
||||
:airportLiveVisible="airportLiveVisible"
|
||||
@loadLiveStreaming="livePreviewVisible = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -28,6 +39,7 @@ import Result from './Result/index.vue'
|
|||
import { ref, onMounted, onBeforeUnmount, } from "vue"
|
||||
import { getClient, createConnection, clientSubscribe, destroyConnection } from '@/utils/mqtt';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { AirportLive, LivePreview } from '@/views/demo/workmanagement/flightoperation/index'
|
||||
|
||||
const router = useRouter();
|
||||
const airRoute = ref({
|
||||
|
|
@ -48,6 +60,9 @@ const leftComponentRef = ref<HTMLElement | null>(null)
|
|||
const rightComponentRef = ref<HTMLElement | null>(null)
|
||||
const map = ref()
|
||||
const connect = ref(false)
|
||||
const msgData = ref({});
|
||||
const airportLiveVisible = ref(false);
|
||||
const livePreviewVisible = ref(false);
|
||||
|
||||
const clickAirPort = () => {
|
||||
sessionStorage.setItem('homeToFlightId', activeProject.value);
|
||||
|
|
@ -94,6 +109,12 @@ onBeforeUnmount(() => {
|
|||
const mapOnLoad = (value) => {
|
||||
map.value = value
|
||||
}
|
||||
const changeAirportLive = (type) => {
|
||||
airportLiveVisible.value = type
|
||||
}
|
||||
const changeUAVLive = (type) => {
|
||||
livePreviewVisible.value = type
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ const generatePreviewPoint = (placemark)=>{
|
|||
}
|
||||
};
|
||||
|
||||
const emits = defineEmits(['exitDraw', 'flyToThere', 'mapOnLoad', 'clickAirPort']);
|
||||
const emits = defineEmits(['exitDraw', 'flyToThere', 'mapOnLoad', 'clickAirPort', 'changeAirportLive', 'changeUAVLive']);
|
||||
|
||||
const airPoints = ref([]);
|
||||
const currentAirPoint = ref({});
|
||||
|
|
@ -1947,6 +1947,12 @@ const homeSetAirportPosition = () => {
|
|||
homeStartGraphic.on(mars3d.EventType.click, function (event) {
|
||||
emits('clickAirPort')
|
||||
});
|
||||
homeStartGraphicLive.on(mars3d.EventType.click, function (event) {
|
||||
emits('changeAirportLive', true)
|
||||
if(props.homeAirport.mode_code == 4){
|
||||
emits('changeUAVLive', true)
|
||||
}
|
||||
});
|
||||
graphicLayer.addGraphic(homeStartGraphic);
|
||||
graphicLayer.addGraphic(homeStartGraphicLive);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue