diff --git a/src/api/workmanagement/droneDock.ts b/src/api/workmanagement/droneDock.ts
new file mode 100644
index 0000000..91e179f
--- /dev/null
+++ b/src/api/workmanagement/droneDock.ts
@@ -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 });
+}
diff --git a/src/plugin/video/index.ts b/src/plugin/video/index.ts
new file mode 100644
index 0000000..c5db646
--- /dev/null
+++ b/src/plugin/video/index.ts
@@ -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 =
+ ' ';
+ 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;
diff --git a/src/plugin/video/src/config.ts b/src/plugin/video/src/config.ts
new file mode 100644
index 0000000..3722a60
--- /dev/null
+++ b/src/plugin/video/src/config.ts
@@ -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;
+}
diff --git a/src/plugin/video/src/mqtt.ts b/src/plugin/video/src/mqtt.ts
new file mode 100644
index 0000000..f630817
--- /dev/null
+++ b/src/plugin/video/src/mqtt.ts
@@ -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 };
diff --git a/src/views/demo/workmanagement/ceshi/index.vue b/src/views/demo/workmanagement/ceshi/index.vue
new file mode 100644
index 0000000..031bf64
--- /dev/null
+++ b/src/views/demo/workmanagement/ceshi/index.vue
@@ -0,0 +1,50 @@
+
+
+
开启机场直播
+
开启无人机直播
+
开始录像
+
结束录像
+
释放资源
+
获取航线任务
+
展示视频直播
+
+
+
+
diff --git a/src/views/demo/workmanagement/projecthome/index.vue b/src/views/demo/workmanagement/projecthome/index.vue
index d913fb3..25d2717 100644
--- a/src/views/demo/workmanagement/projecthome/index.vue
+++ b/src/views/demo/workmanagement/projecthome/index.vue
@@ -1,7 +1,7 @@
-
+
@@ -15,6 +15,17 @@
+
+
@@ -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(null)
const rightComponentRef = ref(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
+}