diff --git a/README.md b/README.md index 2071047..faf73ce 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,15 @@ The launch of the Cloud API mainly solves the problem of developers reinventing ## Docker -If you don't want to install the development environment, you can try deploying with docker. [Click the link to download.](https://terra-sz-hc1pro-cloudapi.oss-cn-shenzhen.aliyuncs.com/c0af9fe0d7eb4f35a8fe5b695e4d0b96/docker/cloud_api_sample_docker_1.0.0.zip) +If you don't want to install the development environment, you can try deploying with docker. [Click the link to download.](https://terra-sz-hc1pro-cloudapi.oss-cn-shenzhen.aliyuncs.com/c0af9fe0d7eb4f35a8fe5b695e4d0b96/docker/cloud_api_sample_docker.zip) ## Usage -For more documentation, please visit the [DJI Developer Documentation](https://developer.dji.com/cn/document/209883f1-f2ad-406e-b99c-be7498df7f10). +For more documentation, please visit the [DJI Developer Documentation](https://developer.dji.com/doc/cloud-api-tutorial/cn/). ## Latest Release -Cloud API 1.0.0 was released on 21 March 2022. For more information, please visit the [Release Note](https://developer.dji.com/cn/document/87026f9b-e906-4809-9aba-870f569061b5). +Cloud API 1.1.0 was released on 22 July 2022. For more information, please visit the [Release Note](https://developer.dji.com/doc/cloud-api-tutorial/cn/). ## License diff --git a/package-lock.json b/package-lock.json index 5ae7c05..ccce315 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@amap/amap-jsapi-loader": "^1.0.1", "@ant-design/icons-vue": "^6.0.1", "@vitejs/plugin-legacy": "^1.6.2", - "agora-rtc-sdk-ng": "latest", + "agora-rtc-sdk-ng": "^4.12.1", "ant-design-vue": "^2.2.8", "axios": "^0.21.1", "query-string": "^7.0.1", @@ -1226,9 +1226,17 @@ } }, "node_modules/agora-rtc-sdk-ng": { - "version": "4.9.1", - "resolved": "https://registry.npmmirror.com/agora-rtc-sdk-ng/-/agora-rtc-sdk-ng-4.9.1.tgz", - "integrity": "sha512-Jogn3TQC7VdA7uZjGYmaAs0XzgYBgGs6nGA67/dQVjqC7kiwAfkQsAuvbevE/qxrVJmLfqtDTNxP40IFvnTlgQ==" + "version": "4.12.1", + "resolved": "https://registry.npmmirror.com/agora-rtc-sdk-ng/-/agora-rtc-sdk-ng-4.12.1.tgz", + "integrity": "sha512-kmc+ZyKDdnY/BN3iAwBs+MSgTX8Zkc6THFSIAXN9WebjZ/F+N/JXItoNEcgQe3MdTABUli6w3pZ+iObnDqVkBw==", + "dependencies": { + "agora-rte-extension": "^1.0.22" + } + }, + "node_modules/agora-rte-extension": { + "version": "1.0.23", + "resolved": "https://registry.npmmirror.com/agora-rte-extension/-/agora-rte-extension-1.0.23.tgz", + "integrity": "sha512-X2cGBg+L5ZJIFU91qvMASvRsBfg1HXTktVG3YROw9wxHsILSI7jgF9R9XraLc3fNX/UjovaYAlUW+hiJe0v6Xw==" }, "node_modules/ajv": { "version": "6.12.6", @@ -8774,9 +8782,17 @@ "requires": {} }, "agora-rtc-sdk-ng": { - "version": "4.9.1", - "resolved": "https://registry.npmmirror.com/agora-rtc-sdk-ng/-/agora-rtc-sdk-ng-4.9.1.tgz", - "integrity": "sha512-Jogn3TQC7VdA7uZjGYmaAs0XzgYBgGs6nGA67/dQVjqC7kiwAfkQsAuvbevE/qxrVJmLfqtDTNxP40IFvnTlgQ==" + "version": "4.12.1", + "resolved": "https://registry.npmmirror.com/agora-rtc-sdk-ng/-/agora-rtc-sdk-ng-4.12.1.tgz", + "integrity": "sha512-kmc+ZyKDdnY/BN3iAwBs+MSgTX8Zkc6THFSIAXN9WebjZ/F+N/JXItoNEcgQe3MdTABUli6w3pZ+iObnDqVkBw==", + "requires": { + "agora-rte-extension": "^1.0.22" + } + }, + "agora-rte-extension": { + "version": "1.0.23", + "resolved": "https://registry.npmmirror.com/agora-rte-extension/-/agora-rte-extension-1.0.23.tgz", + "integrity": "sha512-X2cGBg+L5ZJIFU91qvMASvRsBfg1HXTktVG3YROw9wxHsILSI7jgF9R9XraLc3fNX/UjovaYAlUW+hiJe0v6Xw==" }, "ajv": { "version": "6.12.6", diff --git a/package.json b/package.json index 85f213a..89acf7c 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@amap/amap-jsapi-loader": "^1.0.1", "@ant-design/icons-vue": "^6.0.1", "@vitejs/plugin-legacy": "^1.6.2", - "agora-rtc-sdk-ng": "latest", + "agora-rtc-sdk-ng": "^4.12.1", "ant-design-vue": "^2.2.8", "axios": "^0.21.1", "query-string": "^7.0.1", @@ -61,21 +61,39 @@ "agora-rtc-sdk-ng", "ant-design-vue", "ant-design-vue/es", + "ant-design-vue/es/avatar/style/css", + "ant-design-vue/es/breadcrumb/style/css", "ant-design-vue/es/button/style/css", + "ant-design-vue/es/checkbox/style/css", + "ant-design-vue/es/col/style/css", + "ant-design-vue/es/collapse/style/css", + "ant-design-vue/es/date-picker/style/css", "ant-design-vue/es/divider/style/css", "ant-design-vue/es/drawer/style/css", + "ant-design-vue/es/dropdown/style/css", + "ant-design-vue/es/empty/style/css", "ant-design-vue/es/form/style/css", "ant-design-vue/es/image/style/css", "ant-design-vue/es/input/style/css", + "ant-design-vue/es/layout/style/css", + "ant-design-vue/es/menu/style/css", "ant-design-vue/es/message/style/css", "ant-design-vue/es/modal/style/css", + "ant-design-vue/es/pagination/style/css", + "ant-design-vue/es/popconfirm/style/css", + "ant-design-vue/es/popover/style/css", + "ant-design-vue/es/progress/style/css", "ant-design-vue/es/radio/style/css", + "ant-design-vue/es/row/style/css", "ant-design-vue/es/select/style/css", + "ant-design-vue/es/space/style/css", + "ant-design-vue/es/spin/style/css", "ant-design-vue/es/switch/style/css", "ant-design-vue/es/table/style/css", "ant-design-vue/es/tooltip/style/css", "ant-design-vue/es/tree/style/css", "axios", + "moment", "reconnecting-websocket", "vconsole", "vue", diff --git a/src/api/http/config.ts b/src/api/http/config.ts index 6b12882..fafe023 100644 --- a/src/api/http/config.ts +++ b/src/api/http/config.ts @@ -1,20 +1,36 @@ export const CURRENT_CONFIG = { + // license + appId: 'Please enter the app id.', // You need to go to the development website to apply. + appKey: 'Please enter the app key.', // You need to go to the development website to apply. + appLicense: 'Please enter the app license.' // You need to go to the development website to apply. + + // http baseURL: 'Please enter the backend access address prefix.', // This url must end with "/". Example: 'http://192.168.1.1:6789/' websocketURL: 'Please enter the WebSocket access address.', // Example: 'ws://192.168.1.1:6789/api/v1/ws' - rtmpURL: 'Please enter the rtmp access address.', // Example: 'rtmp://192.168.1.1/live/' - gb28181Para: - 'serverIP=Please enter the server ip.&serverPort=Please enter the server port.&serverID=Please enter the server id.' + - '&agentID=Please enter the agent id.&agentPassword=Please enter the agent password' + - '&localPort=Please enter the local port.&channel=Please enter the channel.', - rtspPara: 'userName=Please enter the username.&password=Please enter the password&port=Please enter the port.', - amapKey: 'Please enter the amap key.', + // livestreaming + // RTMP Note: This IP is the address of the streaming server. If you want to see livestream on web page, you need to convert the RTMP stream to WebRTC stream. + rtmpURL: 'Please enter the rtmp access address.', // Example: 'rtmp://192.168.1.1/live/' + // GB28181 Note:If you don't know what these parameters mean, you can go to Pilot2 and select the GB28181 page in the cloud platform. Where the parameters same as these parameters. + gbServerIp: 'Please enter the server ip.', + gbServerPort: 'Please enter the server port.', + gbServerId: 'Please enter the server id.', + gbAgentId: 'Please enter the agent id', + gbPassword: 'Please enter the agent password', + gbAgentPort: 'Please enter the local port.', + gbAgentChannel: 'Please enter the channel.', + // RTSP + rtspUserName: 'Please enter the username.', + rtspPassword: 'Please enter the password.', + rtspPort: '8554', + // Agora agoraAPPID: 'Please enter the agora app id.', - agoraToken: 'Please enter the agora token.', + agoraToken: 'Please enter the agora temporary token.', agoraChannel: 'Please enter the agora channel.', - appId: 'Please enter the app id.', // You need to go to the development website to apply. - appKey: 'Please enter the app key.', // You need to go to the development website to apply. - appLicense: 'Please enter the app license.' // You need to go to the development website to apply. + // map + // You can apply on the AMap website. + amapKey: 'Please enter the amap key.', + } diff --git a/src/api/http/request.ts b/src/api/http/request.ts index d1a0d6f..d668b89 100644 --- a/src/api/http/request.ts +++ b/src/api/http/request.ts @@ -1,10 +1,14 @@ import axios from 'axios' import { uuidv4 } from '/@/utils/uuid' import { CURRENT_CONFIG } from './config' +import { message } from 'ant-design-vue' +import router from '/@/router' +import { ELocalStorageKey, ERouterName, EUserType } from '/@/types/enums' export * from './type' + const REQUEST_ID = 'X-Request-Id' function getAuthToken () { - return localStorage.getItem('x-auth-token') + return localStorage.getItem(ELocalStorageKey.Token) } const instance = axios.create({ @@ -17,7 +21,7 @@ const instance = axios.create({ instance.interceptors.request.use( config => { - config.headers['X-Auth-Token'] = getAuthToken() + config.headers[ELocalStorageKey.Token] = getAuthToken() // config.headers[REQUEST_ID] = uuidv4() config.baseURL = CURRENT_CONFIG.baseURL return config @@ -28,10 +32,15 @@ instance.interceptors.request.use( ) instance.interceptors.response.use( - response => response, + response => { + console.info('URL: ' + response.config.baseURL + response.config.url, '\nData: ', response.data, '\nResponse:', response) + if (response.data.code && response.data.code !== 0) { + message.error(response.data.message) + } + return response + }, err => { const requestId = err?.config?.headers && err?.config?.headers[REQUEST_ID] - console.info('') if (requestId) { console.info(REQUEST_ID, ':', requestId) } @@ -46,15 +55,26 @@ instance.interceptors.response.use( } // @See: https://github.com/axios/axios/issues/383 if (!err.response || !err.response.status) { - console.log('The network is abnormal, please check the network and try again') - } else if (err.response?.status !== 200) { - console.log(`ERROR_CODE: ${err.response?.status}`) + message.error('The network is abnormal, please check the backend service and try again') + return } - if (err.response?.status === 403) { - // window.location.href = '/' + if (err.response?.status !== 200) { + message.error(`ERROR_CODE: ${err.response?.status}`) } + // if (err.response?.status === 403) { + // // window.location.href = '/' + // } if (err.response?.status === 401) { - console.log(err.response) + console.error(err.response) + const flag: number = Number(localStorage.getItem(ELocalStorageKey.Flag)) + switch (flag) { + case EUserType.Web: + router.push(ERouterName.PROJECT) + break + case EUserType.Pilot: + router.push(ERouterName.PILOT) + break + } } return Promise.reject(err) diff --git a/src/api/layer.ts b/src/api/layer.ts index 1c97320..9501201 100644 --- a/src/api/layer.ts +++ b/src/api/layer.ts @@ -1,8 +1,9 @@ +import { ELocalStorageKey } from '../types/enums' import request, { IWorkspaceResponse } from '/@/api/http/request' import { mapLayers } from '/@/constants/mock-layers' import { elementGroupsReq, PostElementsBody, PutElementsBody } from '/@/types/mapLayer' const PREFIX = '/map/api/v1' -const workspace_id = localStorage.getItem('workspace-id') +const workspace_id = localStorage.getItem(ELocalStorageKey.WorkspaceId) type UnknownResponse = Promise> // get elements group // export const getLayers = async (reqParams: elementGroupsReq): UnknownResponse => { diff --git a/src/api/manage.ts b/src/api/manage.ts index 305fcb0..1fe6b06 100644 --- a/src/api/manage.ts +++ b/src/api/manage.ts @@ -1,12 +1,31 @@ -import request, { IWorkspaceResponse } from '/@/api/http/request' +import request, { CommonListResponse, IListWorkspaceResponse, IPage, IWorkspaceResponse } from '/@/api/http/request' const HTTP_PREFIX = '/manage/api/v1' // login -interface loginBody { +export interface LoginBody { username: string, - password: string + password: string, + flag: number, } -export const login = async function (body: loginBody): Promise> { +export interface BindBody { + device_sn: string, + user_id: string, + workspace_id: string, + domain?: string +} +export interface HmsQueryBody { + sns: string[], + children_sn: string, + device_sn: string, + language: string, + level: number | string, + begin_time: number, + end_time: number, + message: string, + domain: string, +} + +export const login = async function (body: LoginBody): Promise> { const url = `${HTTP_PREFIX}/login` const result = await request.post(url, body) return result.data @@ -20,23 +39,23 @@ export const refreshToken = async function (body: {}): Promise> { +export const getPlatformInfo = async function (): Promise> { const url = `${HTTP_PREFIX}/workspaces/current` - const result = await request.get(url, body) + const result = await request.get(url) return result.data } // Get User Info -export const getUserInfo = async function (body: {}): Promise> { +export const getUserInfo = async function (): Promise> { const url = `${HTTP_PREFIX}/users/current` - const result = await request.get(url, body) + const result = await request.get(url) return result.data } // Get Device Topo -export const getDeviceTopo = async function (body: {}): Promise> { - const url = `${HTTP_PREFIX}/devices/devices` - const result = await request.get(url, body) +export const getDeviceTopo = async function (workspace_id: string): Promise> { + const url = `${HTTP_PREFIX}/devices/${workspace_id}/devices` + const result = await request.get(url) return result.data } @@ -60,3 +79,75 @@ export const stopLivestream = async function (body: {}): Promise> { + const url = `${HTTP_PREFIX}/live/streams/update` + const result = await request.post(url, body) + return result.data +} + +export const getAllUsersInfo = async function (wid: string, body: IPage): Promise> { + const url = `${HTTP_PREFIX}/users/${wid}/users?&page=${body.page}&page_size=${body.page_size}` + const result = await request.get(url) + return result.data +} + +export const updateUserInfo = async function (wid: string, user_id: string, body: {}): Promise> { + const url = `${HTTP_PREFIX}/users/${wid}/users/${user_id}` + const result = await request.put(url, body) + return result.data +} + +export const bindDevice = async function (body: BindBody): Promise> { + const url = `${HTTP_PREFIX}/devices/${body.device_sn}/binding` + const result = await request.post(url, body) + return result.data +} + +export const unbindDevice = async function (device_sn: string): Promise> { + const url = `${HTTP_PREFIX}/devices/${device_sn}/unbinding` + const result = await request.delete(url) + return result.data +} + +export const getDeviceBySn = async function (workspace_id: string, device_sn: string): Promise> { + const url = `${HTTP_PREFIX}/devices/${workspace_id}/devices/${device_sn}` + const result = await request.get(url) + return result.data +} + +export const getBindingDevices = async function (workspace_id: string, body: IPage, domain: string): Promise> { + const url = `${HTTP_PREFIX}/devices/${workspace_id}/devices/bound?&page=${body.page}&page_size=${body.page_size}&domain=${domain}` + const result = await request.get(url) + return result.data +} + +export const updateDevice = async function (body: {}, workspace_id: string, device_sn: string): Promise> { + const url = `${HTTP_PREFIX}/devices/${workspace_id}/devices/${device_sn}` + const result = await request.put(url, body) + return result.data +} + +export const getUnreadDeviceHms = async function (workspace_id: string, device_sn: string): Promise> { + const url = `${HTTP_PREFIX}/devices/${workspace_id}/devices/hms/${device_sn}` + const result = await request.get(url) + return result.data +} + +export const updateDeviceHms = async function (workspace_id: string, device_sn: string): Promise> { + const url = `${HTTP_PREFIX}/devices/${workspace_id}/devices/hms/${device_sn}` + const result = await request.put(url) + return result.data +} + +export const getDeviceHms = async function (body: HmsQueryBody, workspace_id: string, pagination: IPage): Promise> { + let url = `${HTTP_PREFIX}/devices/${workspace_id}/devices/hms?page=${pagination.page}&pageSize=${pagination.page_size}` + + `&level=${body.level ?? ''}&beginTime=${body.begin_time ?? ''}&endTime=${body.end_time ?? ''}&message=${body.message ?? ''}&language=${body.language}` + body.sns.forEach((sn: string) => { + if (sn !== '') { + url = url.concat(`&deviceSn=${sn}`) + } + }) + const result = await request.get(url) + return result.data +} \ No newline at end of file diff --git a/src/api/media.ts b/src/api/media.ts index 8cdec5c..9cf48d9 100644 --- a/src/api/media.ts +++ b/src/api/media.ts @@ -1,9 +1,18 @@ -import request from '/@/api/http/request' +import request, { IPage, IWorkspaceResponse } from '/@/api/http/request' const HTTP_PREFIX = '/media/api/v1' // Get Media Files -export const getMediaFiles = async function (wid: string, body: {}): Promise { - const url = `${HTTP_PREFIX}/files/${wid}/files` - const result = await request.get(url, body) +export const getMediaFiles = async function (wid: string, pagination: IPage): Promise> { + const url = `${HTTP_PREFIX}/files/${wid}/files?page=${pagination.page}&page_size=${pagination.page_size}` + const result = await request.get(url) return result.data } +// Download Media File +export const downloadMediaFile = async function (workspaceId: string, fingerprint: string): Promise { + const url = `${HTTP_PREFIX}/files/${workspaceId}/file/${fingerprint}/url` + const result = await request.get(url, { responseType: 'blob' }) + if (result.data.code) { + return result.data + } + return result +} diff --git a/src/api/pilot-bridge.ts b/src/api/pilot-bridge.ts index a126522..61bdf4e 100644 --- a/src/api/pilot-bridge.ts +++ b/src/api/pilot-bridge.ts @@ -1,95 +1,151 @@ +import { message } from 'ant-design-vue' +import { EComponentName, EPhotoType, ERouterName } from '../types' +import { CURRENT_CONFIG } from './http/config' +import { EVideoPublishType, LiveStreamStatus } from '../types/live-stream' import { getRoot } from '/@/root' const root = getRoot() -const components = new Map() - +export const components = new Map() declare let window:any - interface JsResponse{ code:number, message:string, - data:{} + data:any +} + +export interface ThingParam { + host: string, + username: string, + password: string, + connectCallback: string +} + +export interface LiveshareParam { + videoPublishType: string, // video-on-demand、video-by-manual、video-demand-aux-manual + statusCallback: string +} + +export interface MapParam { + userName: string, + elementPreName: string +} + +export interface WsParam { + host: string, + token: string, + connectCallback: string +} + +export interface ApiParam { + host: string, + token: string +} + +export interface MediaParam { + autoUploadPhoto: boolean, // 是否自动上传图片, 非必需 + autoUploadPhotoType: number, // 自动上传的照片类型,0:原图, 1:缩略图, 非必需 + autoUploadVideo: boolean // 是否自动上传视频, 非必需 +} + +function returnBool (response: string): boolean { + const res: JsResponse = JSON.parse(response) + const isError = errorHint(res) + if (JSON.stringify(res.data) !== '{}') { + return isError && res.data + } + return isError +} + +function returnString (response: string): string { + const res: JsResponse = JSON.parse(response) + return errorHint(res) ? res.data : '' +} + +function returnNumber (response: string): number { + const res: JsResponse = JSON.parse(response) + return errorHint(res) ? res.data : -1 +} + +function errorHint (response: JsResponse): boolean { + if (response.code !== 0) { + message.error(response.message) + console.error(response.message) + return false + } + return true } export default { - init () { - components.set('thing', { + init (): Map { + const thingParam: ThingParam = { host: '', connectCallback: '', username: '', password: '' - }) - components.set('liveshare', { - videoPublishType: 'video-demand-aux-manual', // video-on-demand、video-by-manual、video-demand-aux-manual - statusCallback: '' - }) - components.set('map', { + } + components.set(EComponentName.Thing, thingParam) + const liveshareParam: LiveshareParam = { + videoPublishType: EVideoPublishType.VideoDemandAuxManual, + statusCallback: 'liveStatusCallback' + } + components.set(EComponentName.Liveshare, liveshareParam) + const mapParam: MapParam = { userName: '', - elementPreName: '' - }) - components.set('ws', { - host: '', + elementPreName: 'PILOT' + } + components.set(EComponentName.Map, mapParam) + const wsParam: WsParam = { + host: CURRENT_CONFIG.websocketURL, token: '', - connectCallback: '' - }) - components.set('api', { + connectCallback: 'wsConnectCallback' + } + components.set(EComponentName.Ws, wsParam) + const apiParam: ApiParam = { host: '', token: '' - }) - components.set('tsa', { - }) - components.set('media', { - autoUploadPhoto: true, // 是否自动上传图片, 非必需 - autoUploadPhotoType: 1, // 自动上传的照片类型,0:原图, 1:缩略图, 非必需 - autoUploadVideo: true // 是否自动上传视频, 非必需 - }) - components.set('mission', { - }) - }, - getComponentParam (key:string) { + } + components.set(EComponentName.Api, apiParam) + components.set(EComponentName.Tsa, {}) + const mediaParam: MediaParam = { + autoUploadPhoto: true, + autoUploadPhotoType: EPhotoType.Preview, + autoUploadVideo: true + } + components.set(EComponentName.Media, mediaParam) + components.set(EComponentName.Mission, {}) + + return components + }, + + getComponentParam (key:EComponentName): any { return components.get(key) }, - setComponentParam (key:string, value:any) { + setComponentParam (key:EComponentName, value:any) { components.set(key, value) }, loadComponent (name:string, param:any):string { - return window.djiBridge.platformLoadComponent(name, JSON.stringify(param)) + return returnString(window.djiBridge.platformLoadComponent(name, JSON.stringify(param))) }, unloadComponent (name:string) :string { - return window.djiBridge.platformUnloadComponent(name) + return returnString(window.djiBridge.platformUnloadComponent(name)) }, - isComponentLoaded (module:string):string { - return window.djiBridge.platformIsComponentLoaded(module) + isComponentLoaded (module:string): boolean { + return returnBool(window.djiBridge.platformIsComponentLoaded(module)) }, setWorkspaceId (uuid:string):string { - return window.djiBridge.platformSetWorkspaceId(uuid) + return returnString(window.djiBridge.platformSetWorkspaceId(uuid)) }, - setPlatformMessage (platformName:string, title:string, desc:string):string { - return window.djiBridge.platformSetInformation(platformName, title, desc) + setPlatformMessage (platformName:string, title:string, desc:string): boolean { + return returnBool(window.djiBridge.platformSetInformation(platformName, title, desc)) }, getRemoteControllerSN () :string { - return window.djiBridge.platformGetRemoteControllerSN() + return returnString(window.djiBridge.platformGetRemoteControllerSN()) }, getAircraftSN ():string { - return window.djiBridge.platformGetAircraftSN() + return returnString(window.djiBridge.platformGetAircraftSN()) }, stopwebview ():string { - return window.djiBridge.platformStopSelf() - }, - getToken () :string { - const res:string = this.isComponentLoaded('api') - const resObj = JSON.parse(res) - console.log('api load status:', resObj) - if (resObj.data === true) { - const tokenRes = JSON.parse(window.djiBridge.apiGetToken()) - return tokenRes.data - } else { - console.warn('warning: not api component loaded!!') - return '' - } - }, - setToken (token:string):string { - return window.djiBridge.apiSetToken(token) + return returnString(window.djiBridge.platformStopSelf()) }, setLogEncryptKey (key:string):string { return window.djiBridge.platformSetLogEncryptKey(key) @@ -98,14 +154,42 @@ export default { return window.djiBridge.platformClearLogEncryptKey() }, getLogPath ():string { - return window.djiBridge.platformGetLogPath() + return returnString(window.djiBridge.platformGetLogPath()) + }, + platformVerifyLicense (appId:string, appKey:string, appLicense:string): boolean { + return returnBool(window.djiBridge.platformVerifyLicense(appId, appKey, appLicense)) + }, + isPlatformVerifySuccess (): boolean { + return returnBool(window.djiBridge.platformIsVerified()) }, - platformVerifyLicense (appId:string, appKey:string, appLicense:string):string { - return window.djiBridge.platformVerifyLicense(appId, appKey, appLicense) + isAppInstalled (pkgName: string): boolean { + return returnBool(window.djiBridge.platformIsAppInstalled(pkgName)) }, - isPlatformVerifySuccess ():string { - return window.djiBridge.platformIsVerified() + getVersion (): string { + return window.djiBridge.platformGetVersion() }, + + // thing + thingGetConnectState (): boolean { + return returnBool(window.djiBridge.thingGetConnectState()) + }, + + thingGetConfigs (): ThingParam { + const thingParam = JSON.parse(window.djiBridge.thingGetConfigs()) + return thingParam.code === 0 ? JSON.parse(thingParam.data) : {} + }, + + // api + getToken () : string { + return returnString(window.djiBridge.apiGetToken()) + }, + setToken (token:string):string { + return returnString(window.djiBridge.apiSetToken(token)) + }, + getHost (): string { + return returnString(window.djiBridge.apiGetHost()) + }, + // liveshare /** * @@ -114,8 +198,8 @@ export default { * video-by-manual:手动点播,配置好直播类型参数之后,在图传页面可修改直播参数,停止直播 * video-demand-aux-manual: 混合模式,支持服务器点播,以及图传页面修改直播参数,停止直播 */ - setVideoPublishType (type:string):string { - return window.djiBridge.liveshareSetVideoPublishType(type) + setVideoPublishType (type:string): boolean { + return returnBool(window.djiBridge.liveshareSetVideoPublishType(type)) }, /** @@ -123,8 +207,8 @@ export default { * @returns * type: liveshare type, 0:unknown, 1:agora, 2:rtmp, 3:rtsp, 4:gb28181 */ - getLiveshareConfig () { - return window.djiBridge.liveshareGetConfig() + getLiveshareConfig (): string { + return returnString(window.djiBridge.liveshareGetConfig()) }, setLiveshareConfig (type:number, params:string):string { @@ -134,50 +218,66 @@ export default { setLiveshareStatusCallback (callbackFunc:string) :string { return window.djiBridge.liveshareSetStatusCallback(callbackFunc) }, - getLiveshareStatus () { - return window.djiBridge.liveshareGetStatus() + getLiveshareStatus (): LiveStreamStatus { + return JSON.parse(JSON.parse(window.djiBridge.liveshareGetStatus()).data) }, - startLiveshare ():string { - return window.djiBridge.liveshareStartLive() + startLiveshare (): boolean { + return returnBool(window.djiBridge.liveshareStartLive()) }, - stopLiveshare ():string { - return window.djiBridge.liveshareStopLive() + stopLiveshare (): boolean { + return returnBool(window.djiBridge.liveshareStopLive()) + }, + // WebSocket + wsGetConnectState (): boolean { + return returnBool(window.djiBridge.wsGetConnectState()) + }, + wsConnect (host: string, token: string, callback: string): string { + return window.djiBridge.wsConnect(host, token, callback) + }, + wsDisconnect (): string { + return window.djiBridge.wsConnect() + }, + wsSend (message: string): string { + return window.djiBridge.wsSend(message) }, // media setAutoUploadPhoto (auto:boolean):string { return window.djiBridge.mediaSetAutoUploadPhoto(auto) }, - getAutoUploadPhoto () { - return window.djiBridge.mediaGetAutoUploadPhoto() + getAutoUploadPhoto (): boolean { + return returnBool(window.djiBridge.mediaGetAutoUploadPhoto()) }, setUploadPhotoType (type:number):string { return window.djiBridge.mediaSetUploadPhotoType(type) }, - getUploadPhotoType () { - return window.djiBridge.mediaGetUploadPhotoType() + getUploadPhotoType (): number { + return returnNumber(window.djiBridge.mediaGetUploadPhotoType()) }, setAutoUploadVideo (auto:boolean):string { return window.djiBridge.mediaSetAutoUploadVideo(auto) }, - getAutoUploadVideo () { - return window.djiBridge.mediaGetAutoUploadVideo() + getAutoUploadVideo (): boolean { + return returnBool(window.djiBridge.mediaGetAutoUploadVideo()) }, setDownloadOwner (rcIndex:number):string { return window.djiBridge.mediaSetDownloadOwner(rcIndex) }, - getDownloadOwner () { - return window.djiBridge.mediaGetDownloadOwner() + getDownloadOwner (): number { + return returnNumber(window.djiBridge.mediaGetDownloadOwner()) }, onBackClickReg () { window.djiBridge.onBackClick = () => { - if (root.$router.currentRoute.value.path === '/pilot-home') { - console.log(root.$router.currentRoute.value.path) + if (root.$router.currentRoute.value.path === '/' + ERouterName.PILOT_HOME) { return false } else { - console.log(root.$router.currentRoute.value.path) history.go(-1) return true } } + }, + onStopPlatform () { + window.djiBridge.onStopPlatform = () => { + localStorage.clear() + } } } diff --git a/src/api/wayline.ts b/src/api/wayline.ts index 2963b6c..87c9c31 100644 --- a/src/api/wayline.ts +++ b/src/api/wayline.ts @@ -1,9 +1,55 @@ -import request from '/@/api/http/request' +import request, { IPage, IWorkspaceResponse } from '/@/api/http/request' const HTTP_PREFIX = '/wayline/api/v1' +export interface CreatePlan { + name: string, + file_id: string, + dock_sn: string, + immediate: boolean, + type: string, +} + // Get Wayline Files -export const getWaylineFiles = async function (wid: string, body: {}): Promise { - const url = `${HTTP_PREFIX}/workspaces/${wid}/waylines?` + 'order_by=' + body.order_by + '&page=' + body.page + '&page_size=' + body.page_size +export const getWaylineFiles = async function (wid: string, body: {}): Promise> { + const url = `${HTTP_PREFIX}/workspaces/${wid}/waylines?order_by=${body.order_by}&page=${body.page}&page_size=${body.page_size}` const result = await request.get(url) return result.data } + +// Download Wayline File +export const downloadWaylineFile = async function (workspaceId: string, waylineId: string): Promise { + const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/waylines/${waylineId}/url` + const result = await request.get(url, { responseType: 'blob' }) + if (result.data.code) { + return result.data + } + return result +} + +// Delete Wayline File +export const deleteWaylineFile = async function (workspaceId: string, waylineId: string): Promise> { + const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/waylines/${waylineId}` + const result = await request.delete(url) + return result.data +} + +// Create Wayline Job +export const createPlan = async function (workspaceId: string, plan: CreatePlan): Promise> { + const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/flight-tasks` + const result = await request.post(url, plan) + return result.data +} + +// Get Wayline Jobs +export const getWaylineJobs = async function (workspaceId: string, page: IPage): Promise> { + const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/jobs?page=${page.page}&page_size=${page.page_size}` + const result = await request.get(url) + return result.data +} + +// Execute Wayline Job +export const executeWaylineJobs = async function (workspaceId: string, plan_id: string): Promise> { + const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/jobs/${plan_id}` + const result = await request.post(url) + return result.data +} diff --git a/src/api/websocket.ts b/src/api/websocket.ts index 4613457..0d5a08f 100644 --- a/src/api/websocket.ts +++ b/src/api/websocket.ts @@ -1,14 +1,14 @@ import ReconnectingWebSocket from 'reconnecting-websocket' +import { ELocalStorageKey } from '../types/enums' import { CURRENT_CONFIG as config } from '/@/api/http/config' -let socket = {} +let socket: ReconnectingWebSocket export default { - init (getMsgFunc) { - const token = localStorage.getItem('x-auth-token') - const wspath = - config.websocketURL + '?x-auth-token=' + escape(token) - socket = new ReconnectingWebSocket(wspath) + init (getMsgFunc: any) { + const token: string = localStorage.getItem(ELocalStorageKey.Token)! + const wspath = config.websocketURL + '?x-auth-token=' + encodeURI(token) + socket = new ReconnectingWebSocket(wspath, '', { maxRetries: 5 }) socket.onopen = this.onOpen socket.onerror = this.onError socket.onmessage = getMsgFunc @@ -18,13 +18,16 @@ export default { onOpen () { console.log('ws opened') }, - onError (err) { + onError (err: any) { console.error(err) }, onClose () { console.log('ws closed') }, - sendMsg (data) { - this.socket.send(data) + sendMsg (data: any) { + socket.send(data) + }, + close () { + socket.close() } } diff --git a/src/assets/icons/cloudapi.png b/src/assets/icons/cloudapi.png new file mode 100644 index 0000000..c4e398b Binary files /dev/null and b/src/assets/icons/cloudapi.png differ diff --git a/src/assets/icons/dji_logo.png b/src/assets/icons/dji_logo.png new file mode 100644 index 0000000..c6d0e22 Binary files /dev/null and b/src/assets/icons/dji_logo.png differ diff --git a/src/assets/icons/dock.png b/src/assets/icons/dock.png new file mode 100644 index 0000000..7c0958b Binary files /dev/null and b/src/assets/icons/dock.png differ diff --git a/src/assets/icons/drone.png b/src/assets/icons/drone.png new file mode 100644 index 0000000..cf5f3b2 Binary files /dev/null and b/src/assets/icons/drone.png differ diff --git a/src/assets/icons/m30.png b/src/assets/icons/m30.png new file mode 100644 index 0000000..a5932c7 Binary files /dev/null and b/src/assets/icons/m30.png differ diff --git a/src/assets/icons/no-data.png b/src/assets/icons/no-data.png new file mode 100644 index 0000000..36a8fd8 Binary files /dev/null and b/src/assets/icons/no-data.png differ diff --git a/src/assets/icons/rc.png b/src/assets/icons/rc.png new file mode 100644 index 0000000..a4ca3c5 Binary files /dev/null and b/src/assets/icons/rc.png differ diff --git a/src/components/GMap.vue b/src/components/GMap.vue index 8121e47..80d540b 100644 --- a/src/components/GMap.vue +++ b/src/components/GMap.vue @@ -5,19 +5,378 @@ class="g-action-panle" :style="{ right: drawVisible ? '316px' : '16px' }" > -
- PIN +
+
-
- Line +
+
-
- Poly +
+
- X +
+
+
+ {{ osdVisible.callsign }} + +
+
+
+ +
+ + {{ osdVisible.model }} +
+
+
+
+ + {{ EModeCode[deviceInfo.device.mode_code] }} + + + + + HD + {{ deviceInfo.gateway?.transmission_signal_quality }} + + + + + + {{ deviceInfo.gateway && deviceInfo.gateway.capacity_percent !== str ? deviceInfo.gateway.capacity_percent + ' %' : deviceInfo.gateway.capacity_percent }} + + + + + + + {{ deviceInfo.device.battery.capacity_percent !== str ? deviceInfo.device.battery.capacity_percent + ' %' : deviceInfo.device.battery.capacity_percent }} + + + + + + + Fixed + + + + + + GPS + {{ deviceInfo.device.position_state.gps_number }} + + + + + + {{ deviceInfo.device.position_state.rtk_number }} + + + + + + + + {{ EGear[deviceInfo.device.gear] }} + + + + + ASL + {{ deviceInfo.device.height === str ? str : deviceInfo.device.height.toFixed(2) + ' m'}} + + + + + ALT + {{ deviceInfo.device.elevation === str ? str : deviceInfo.device.elevation.toFixed(2) + ' m' }} + + + + + H + {{ deviceInfo.device.home_distance === str ? str : deviceInfo.device.home_distance.toFixed(2) + ' m' }} + + + + + + + H.S + {{ deviceInfo.device.horizontal_speed === str ? str : deviceInfo.device.horizontal_speed.toFixed(2) + ' m/s'}} + + + + + V.S + {{ deviceInfo.device.vertical_speed === str ? str : deviceInfo.device.vertical_speed.toFixed(2) + ' m/s'}} + + + + + W.S + {{ deviceInfo.device.wind_speed === str ? str : (deviceInfo.device.wind_speed / 10).toFixed(2) + ' m/s'}} + + + +
+
+
+
+
+
+
+
+
+ {{ Math.floor(deviceInfo.device.battery.remain_flight_time / 60) }}: + {{ 10 > (deviceInfo.device.battery.remain_flight_time % 60) ? '0' : ''}}{{deviceInfo.device.battery.remain_flight_time % 60 }} +
+
+
+
+
+ {{ osdVisible.gateway_callsign }} + +
+
+
+ +
+ + Dock +
+
+
+
+ + + {{ EDockModeCode[deviceInfo.dock.mode_code] }} + + + + + + + {{ Math.floor(deviceInfo.dock.acc_time / 2592000) }}m + {{ Math.floor((deviceInfo.dock.acc_time % 2592000) / 86400) }}d + {{ Math.floor((deviceInfo.dock.acc_time % 2592000 % 86400) / 3600) }}h + {{ Math.floor((deviceInfo.dock.acc_time % 2592000 % 86400 % 3600) / 60) }}min + {{ Math.floor(deviceInfo.dock.acc_time % 2592000 % 86400 % 3600 % 60) }} s + + + + + + + {{ new Date(deviceInfo.dock.first_power_on).toLocaleString() }} + + + + + + + + + + + + {{ deviceInfo.dock.network_state.rate }} KB/S + + + + + + {{ deviceInfo.dock.media_file_detail?.remain_upload }} + + + + + + + + + + + + + + + + W.S + {{ deviceInfo.dock.wind_speed === str ? str : (deviceInfo.dock.wind_speed / 10).toFixed(2) + ' m/s'}} + + + + + 🌧 + {{ deviceInfo.dock.rainfall === str ? str : deviceInfo.dock.rainfall + ' mm/h' }} + + + + + °C + {{ deviceInfo.dock.environment_temperature }} + + + + + 💦 + {{ deviceInfo.dock.environment_humidity === str ? str : deviceInfo.dock.environment_humidity }} + + + + + + + °C + {{ deviceInfo.dock.temperature }} + + + + + 💦 + {{ deviceInfo.dock.humidity === str ? str : deviceInfo.dock.humidity }} + + + + + V + {{ deviceInfo.dock.working_voltage === str ? str : deviceInfo.dock.working_voltage + ' mV' }} + + + + + A + {{ deviceInfo.dock.working_current === str ? str : deviceInfo.dock.working_current + ' mA' }} + + + +
+
+
+
+ +
+ + M30 +
+
+
+
+ + + {{ !deviceInfo.device ? EModeCode[EModeCode.Disconnected] : EModeCode[deviceInfo.device?.mode_code] }} + + + + + + {{ deviceInfo.dock.sdr?.up_quality }} + + + + + + {{ deviceInfo.dock.sdr?.down_quality }} + + + + + + {{ deviceInfo.device && deviceInfo.device.battery.capacity_percent !== str ? deviceInfo.device?.battery.capacity_percent + ' %' : str }} + + + + + + + Fixed + + + + + + GPS + {{ deviceInfo.device ? deviceInfo.device.position_state.gps_number : str }} + + + + + + {{ deviceInfo.device ? deviceInfo.device.position_state.rtk_number : str }} + + + + + + + + {{ deviceInfo.device ? EGear[deviceInfo.device?.gear] : str }} + + + + + ASL + {{ !deviceInfo.device || deviceInfo.device.height === str ? str : deviceInfo.device?.height.toFixed(2) + ' m'}} + + + + + ALT + {{ !deviceInfo.device || deviceInfo.device.elevation === str ? str : deviceInfo.device?.elevation.toFixed(2) + ' m' }} + + + + + H + {{ !deviceInfo.device || deviceInfo.device.home_distance === str ? str : deviceInfo.device?.home_distance.toFixed(2) + ' m' }} + + + + + + + H.S + {{ !deviceInfo.device || deviceInfo.device?.horizontal_speed === str ? str : deviceInfo.device?.horizontal_speed.toFixed(2) + ' m/s'}} + + + + + V.S + {{ !deviceInfo.device || deviceInfo.device.vertical_speed === str ? str : deviceInfo.device?.vertical_speed.toFixed(2) + ' m/s'}} + + + + + W.S + {{ !deviceInfo.device || deviceInfo.device.wind_speed === str ? str : (deviceInfo.device?.wind_speed / 10).toFixed(2) + ' m/s'}} + + + +
+
+
+
+
+
+
+
+
+ {{ Math.floor(deviceInfo.device.battery.remain_flight_time / 60) }}: + {{ 10 > (deviceInfo.device.battery.remain_flight_time % 60) ? '0' : ''}}{{deviceInfo.device.battery.remain_flight_time % 60 }} +
+
+ +
@@ -40,13 +399,43 @@ import { MapDoodleEnum } from '/@/types/map-enum' import { PostElementsBody } from '/@/types/mapLayer' import { uuidv4 } from '/@/utils/uuid' import { gcj02towgs84, wgs84togcj02 } from '/@/vendors/coordtransform' +import { deviceTsaUpdate } from '/@/hooks/use-g-map-tsa' +import { DeviceOsd, DeviceStatus, DockOsd, EGear, EModeCode, GatewayOsd, EDockModeCode } from '/@/types/device' +import pin from '/@/assets/icons/pin-2d8cf0.svg' +import M30 from '/@/assets/icons/m30.png' +import { + BorderOutlined, LineOutlined, CloseOutlined, ControlOutlined, TrademarkOutlined, ArrowDownOutlined, + ThunderboltOutlined, SignalFilled, GlobalOutlined, HistoryOutlined, CloudUploadOutlined, + FieldTimeOutlined, CloudOutlined, CloudFilled, FolderOpenOutlined, RobotFilled, ArrowUpOutlined +} from '@ant-design/icons-vue' +import { EDeviceTypeName } from '../types' export default defineComponent({ + components: { + BorderOutlined, + LineOutlined, + CloseOutlined, + ControlOutlined, + TrademarkOutlined, + ThunderboltOutlined, + SignalFilled, + GlobalOutlined, + HistoryOutlined, + CloudUploadOutlined, + FieldTimeOutlined, + CloudOutlined, + CloudFilled, + FolderOpenOutlined, + RobotFilled, + ArrowUpOutlined, + ArrowDownOutlined + }, name: 'GMap', props: {}, setup () { const useMouseToolHook = useMouseTool() const useGMapManageHook = useGMapManage() + const deviceTsaUpdateHook = ref() const mouseMode = ref(false) const store = useMyStore() @@ -54,6 +443,86 @@ export default defineComponent({ currentType: '', coverIndex: 0 }) + const str: string = '--' + const deviceInfo = reactive({ + gateway: { + capacity_percent: str, + transmission_signal_quality: str, + } as GatewayOsd, + dock: { + media_file_detail: { + remain_upload: 0 + }, + sdr: { + up_quality: str, + down_quality: str, + frequency_band: -1, + }, + network_state: { + type: 0, + quality: 0, + rate: 0, + }, + drone_in_dock: 0, + drone_charge_state: { + state: 0, + capacity_percent: str, + }, + rainfall: str, + wind_speed: str, + environment_temperature: str, + environment_humidity: str, + temperature: str, + humidity: str, + job_number: 0, + acc_time: 0, + first_power_on: 0, + positionState: { + gps_number: str, + is_fixed: 0, + rtk_number: str, + is_calibration: 0, + quality: 0, + }, + storage: { + total: 0, + used: 0, + }, + electric_supply_voltage: 0, + working_voltage: str, + working_current: str, + backup_battery_voltage: 0, + mode_code: -1, + cover_state: -1, + supplement_light_state: -1, + putter_state: -1, + + } as DockOsd, + device: { + gear: -1, + mode_code: EModeCode.Disconnected, + height: str, + home_distance: str, + horizontal_speed: str, + vertical_speed: str, + wind_speed: str, + wind_direction: str, + elevation: str, + position_state: { + gps_number: str, + is_fixed: 0, + rtk_number: str + }, + battery: { + capacity_percent: str, + landing_power: str, + remain_flight_time: 0, + return_home_power: str, + }, + latitude: 0, + longitude: 0, + } as DeviceOsd + }) const shareId = computed(() => { return store.state.layerBaseInfo.share }) @@ -63,6 +532,57 @@ export default defineComponent({ const drawVisible = computed(() => { return store.state.drawVisible }) + const osdVisible = computed(() => { + return store.state.osdVisible + }) + + watch(() => store.state.deviceStatusEvent, + data => { + deviceTsaUpdateHook.value = deviceTsaUpdate() + if (Object.keys(data.deviceOnline).length !== 0) { + deviceTsaUpdateHook.value.initMarker(data.deviceOnline.domain, data.deviceOnline.device_callsign, data.deviceOnline.sn) + store.state.deviceStatusEvent.deviceOnline = {} as DeviceStatus + } + if (Object.keys(data.deviceOffline).length !== 0) { + deviceTsaUpdateHook.value.removeMarker(data.deviceOffline.sn) + if ((data.deviceOffline.sn === osdVisible.value.sn) || (osdVisible.value.is_dock && data.deviceOffline.sn === osdVisible.value.gateway_sn)) { + osdVisible.value.visible = false + store.commit('SET_OSD_VISIBLE_INFO', osdVisible) + } + store.state.deviceStatusEvent.deviceOffline = {} + } + }, + { + deep: true + } + ) + + watch(() => store.state.deviceState, data => { + if (!deviceTsaUpdateHook.value) { + deviceTsaUpdateHook.value = deviceTsaUpdate() + } + if (data.currentType === EDeviceTypeName.Gateway && data.gatewayInfo[data.currentSn]) { + deviceTsaUpdateHook.value.moveTo(data.currentSn, data.gatewayInfo[data.currentSn].longitude, data.gatewayInfo[data.currentSn].latitude) + if (osdVisible.value.visible && osdVisible.value.gateway_sn !== '') { + deviceInfo.gateway = data.gatewayInfo[osdVisible.value.gateway_sn] + } + } + if (data.currentType === EDeviceTypeName.Aircraft && data.deviceInfo[data.currentSn]) { + deviceTsaUpdateHook.value.moveTo(data.currentSn, data.deviceInfo[data.currentSn].longitude, data.deviceInfo[data.currentSn].latitude) + if (osdVisible.value.visible && osdVisible.value.sn !== '') { + deviceInfo.device = data.deviceInfo[osdVisible.value.sn] + } + } + if (data.currentType === EDeviceTypeName.Dock && data.dockInfo[data.currentSn]) { + if (osdVisible.value.visible && osdVisible.value.is_dock && osdVisible.value.gateway_sn !== '') { + deviceInfo.dock = data.dockInfo[osdVisible.value.gateway_sn] + deviceInfo.device = data.deviceInfo[deviceInfo.dock.sub_device?.device_sn] + } + } + }, { + deep: true + }) + watch( () => store.state.wsEvent, newData => { @@ -144,7 +664,9 @@ export default defineComponent({ async function postPinPositionResource (obj) { const req = getPinPositionResource(obj) setLayers(req) - updateCoordinates('gcj02-wgs84', req) + const coordinates = req.resource.content.geometry.coordinates + updateCoordinates('gcj02-wgs84', req); + (req.resource.content.geometry.coordinates as GeojsonCoordinate).push((coordinates as GeojsonCoordinate)[2]) const result = await postElementsReq(shareId.value, req) obj.setExtData({ id: req.id, name: req.name }) store.state.coverList.push(obj) @@ -281,7 +803,16 @@ export default defineComponent({ return { draw, mouseMode, - drawVisible + drawVisible, + osdVisible, + pin, + state, + M30, + deviceInfo, + EGear, + EModeCode, + str, + EDockModeCode, } } }) @@ -296,16 +827,77 @@ export default defineComponent({ top: 16px; right: 16px; .g-action-item { - padding-top: 8px; + width: 28px; + height: 28px; + background: white; + color: $primary; + border-radius: 2px; + line-height: 28px; + text-align: center; + margin-bottom: 2px; + } + .g-action-item:hover { + border: 1px solid $primary; + border-radius: 2px; } } + .selection { + border: 1px solid $primary; + border-radius: 2px; + } } - - diff --git a/src/components/MediaPanel.vue b/src/components/MediaPanel.vue index 969342a..32b7714 100644 --- a/src/components/MediaPanel.vue +++ b/src/components/MediaPanel.vue @@ -1,92 +1,168 @@ diff --git a/src/components/TaskPanel.vue b/src/components/TaskPanel.vue new file mode 100644 index 0000000..ce880e0 --- /dev/null +++ b/src/components/TaskPanel.vue @@ -0,0 +1,182 @@ + + + + + diff --git a/src/components/livestream-agora.vue b/src/components/livestream-agora.vue new file mode 100644 index 0000000..41463f3 --- /dev/null +++ b/src/components/livestream-agora.vue @@ -0,0 +1,350 @@ + + + + + diff --git a/src/components/livestream-others.vue b/src/components/livestream-others.vue new file mode 100644 index 0000000..a77bcc0 --- /dev/null +++ b/src/components/livestream-others.vue @@ -0,0 +1,378 @@ + + + + + diff --git a/src/components/wayline-panel.vue b/src/components/wayline-panel.vue index 784fa3c..aad0a49 100644 --- a/src/components/wayline-panel.vue +++ b/src/components/wayline-panel.vue @@ -1,5 +1,5 @@ diff --git a/src/pages/project-app/index.vue b/src/pages/project-app/index.vue index d8359da..b5a855d 100644 --- a/src/pages/project-app/index.vue +++ b/src/pages/project-app/index.vue @@ -1,20 +1,18 @@ diff --git a/src/pages/project-app/projects/create-plan.vue b/src/pages/project-app/projects/create-plan.vue new file mode 100644 index 0000000..3891f2a --- /dev/null +++ b/src/pages/project-app/projects/create-plan.vue @@ -0,0 +1,251 @@ + + + + + diff --git a/src/pages/project-app/projects/devices.vue b/src/pages/project-app/projects/devices.vue new file mode 100644 index 0000000..71201ec --- /dev/null +++ b/src/pages/project-app/projects/devices.vue @@ -0,0 +1,518 @@ + + + + diff --git a/src/pages/project-app/projects/dock.vue b/src/pages/project-app/projects/dock.vue new file mode 100644 index 0000000..72fd32f --- /dev/null +++ b/src/pages/project-app/projects/dock.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/src/pages/project-app/projects/layer.vue b/src/pages/project-app/projects/layer.vue index 89b4020..325fd86 100644 --- a/src/pages/project-app/projects/layer.vue +++ b/src/pages/project-app/projects/layer.vue @@ -1,5 +1,12 @@