initial
@@ -0,0 +1 @@
|
|||||||
|
/src/vendors/**
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
commonjs: true,
|
||||||
|
es2021: true,
|
||||||
|
node: true
|
||||||
|
},
|
||||||
|
extends: ['standard', 'plugin:vue/vue3-essential'],
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 12,
|
||||||
|
parser: '@typescript-eslint/parser'
|
||||||
|
},
|
||||||
|
plugins: ['vue', '@typescript-eslint'],
|
||||||
|
rules: {
|
||||||
|
'comma-dangle': 'off',
|
||||||
|
'import/no-absolute-path': 'off',
|
||||||
|
'no-unused-vars': 'off',
|
||||||
|
camelcase: 'off',
|
||||||
|
'no-redeclare': 'off',
|
||||||
|
'vue/no-unused-components': 'off'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
# .vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
|
||||||
|
.history
|
||||||
|
/coverage
|
||||||
|
/backup
|
||||||
|
node_modules
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
registry=https://registry.npm.taobao.org/
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# VUE3
|
||||||
|
全系统选用 script setup 模式
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
VITE_APP_ENVIRONMENT=DEV
|
||||||
|
VITE_APP_APIGATEWAY_BACKEND_HOST=''
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
VITE_APP_ENVIRONMENT=production
|
||||||
|
VITE_APP_APIGATEWAY_BACKEND_HOST=''
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
VITE_APP_ENVIRONMENT=STAG
|
||||||
|
VITE_APP_APIGATEWAY_BACKEND_HOST=''
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>demo-web</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="demo-app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"name": "demo-web",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vite",
|
||||||
|
"build:test": "vite build --mode stag",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"lint": "eslint --fix"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@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",
|
||||||
|
"ant-design-vue": "^2.2.8",
|
||||||
|
"axios": "^0.21.1",
|
||||||
|
"query-string": "^7.0.1",
|
||||||
|
"reconnecting-websocket": "^4.4.0",
|
||||||
|
"vconsole": "^3.8.1",
|
||||||
|
"vite-plugin-components": "^0.13.3",
|
||||||
|
"vite-plugin-importer": "^0.2.5",
|
||||||
|
"vite-plugin-optimize-persist": "^0.1.2",
|
||||||
|
"vite-plugin-package-config": "^0.1.1",
|
||||||
|
"vue": "^3.2.26",
|
||||||
|
"vue-cookies": "^1.7.4",
|
||||||
|
"vue-i18n": "^9.1.6",
|
||||||
|
"vue-router": "4",
|
||||||
|
"vuex": "^4.0.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^16.3.2",
|
||||||
|
"@types/urlencode": "^1.1.2",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
||||||
|
"@typescript-eslint/parser": "^5.8.1",
|
||||||
|
"@vitejs/plugin-vue": "^1.2.4",
|
||||||
|
"@vue/compiler-sfc": "^3.0.5",
|
||||||
|
"eslint": "^7.30.0",
|
||||||
|
"eslint-config-standard": "^16.0.3",
|
||||||
|
"eslint-plugin-import": "^2.23.4",
|
||||||
|
"eslint-plugin-node": "^11.1.0",
|
||||||
|
"eslint-plugin-promise": "^5.1.0",
|
||||||
|
"eslint-plugin-vue": "^7.13.0",
|
||||||
|
"rollup-plugin-external-globals": "^0.6.1",
|
||||||
|
"sass": "^1.35.1",
|
||||||
|
"typescript": "^4.5.4",
|
||||||
|
"vite": "^2.4.0",
|
||||||
|
"vite-plugin-eslint": "^1.3.0",
|
||||||
|
"vite-plugin-style-import": "^1.0.1",
|
||||||
|
"vite-plugin-svg-icons": "^1.0.5",
|
||||||
|
"vite-plugin-vconsole": "^1.1.0",
|
||||||
|
"vue-tsc": "^0.0.24"
|
||||||
|
},
|
||||||
|
"license": "ISC",
|
||||||
|
"vite": {
|
||||||
|
"optimizeDeps": {
|
||||||
|
"include": [
|
||||||
|
"@amap/amap-jsapi-loader",
|
||||||
|
"@ant-design/icons-vue",
|
||||||
|
"@vue/reactivity",
|
||||||
|
"agora-rtc-sdk-ng",
|
||||||
|
"ant-design-vue",
|
||||||
|
"ant-design-vue/es",
|
||||||
|
"ant-design-vue/es/button/style/css",
|
||||||
|
"ant-design-vue/es/divider/style/css",
|
||||||
|
"ant-design-vue/es/drawer/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/message/style/css",
|
||||||
|
"ant-design-vue/es/modal/style/css",
|
||||||
|
"ant-design-vue/es/radio/style/css",
|
||||||
|
"ant-design-vue/es/select/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",
|
||||||
|
"reconnecting-websocket",
|
||||||
|
"vconsole",
|
||||||
|
"vue",
|
||||||
|
"vue-router",
|
||||||
|
"vuex"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Depois Largura: | Altura: | Tamanho: 6.4 KiB |
@@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<div id="demo-app" class="demo-app">
|
||||||
|
<router-view />
|
||||||
|
<!-- <div class="map-wrapper">
|
||||||
|
<GMap/>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, ref } from 'vue'
|
||||||
|
import { useMyStore } from './store'
|
||||||
|
import GMap from '/@/components/GMap.vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'App',
|
||||||
|
components: { GMap },
|
||||||
|
|
||||||
|
setup () {
|
||||||
|
const store = useMyStore()
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.demo-app {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
.map-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// import Icon from '@ant-design/icons-vue'
|
||||||
|
import * as antDesign from 'ant-design-vue'
|
||||||
|
import 'ant-design-vue/dist/antd.css'
|
||||||
|
import { App } from 'vue'
|
||||||
|
import svgIcon from '/@/components/svgIcon.vue'
|
||||||
|
|
||||||
|
export const antComponents = {
|
||||||
|
install (app: App): void {
|
||||||
|
app.use(antDesign)
|
||||||
|
// app.component('Icon', Icon)
|
||||||
|
app.component('svg-icon', svgIcon)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* 职责声明:
|
||||||
|
* 1.提供一个 单一的 axios 实例(方面进行统一拦截)
|
||||||
|
* 2.允许调用方定制自己的配置(例如拦截器等),而不影响其他实例
|
||||||
|
*
|
||||||
|
* 暴露 API:
|
||||||
|
* 1.一个统一的 axios 实例: singleAxiosInstance(绑定了统一的拦截器)
|
||||||
|
* 2.创建 axios 实例的方法 createAxiosInstance,并在参数中允许配置是否绑定统一拦截器
|
||||||
|
* 3.对外暴露统一拦截器绑定方案,允许外界进行定制: bindCommonRequestInterceptors、bindCommonResponseInterceptors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
|
||||||
|
|
||||||
|
// 统一的 request 拦截器
|
||||||
|
export function bindCommonRequestInterceptors (instance: AxiosInstance): void {
|
||||||
|
instance.interceptors.request.use(config => {
|
||||||
|
return config
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unified response interceptor
|
||||||
|
export function bindCommonResponseInterceptors (instance: AxiosInstance): void {
|
||||||
|
instance.interceptors.response.use(config => {
|
||||||
|
return config
|
||||||
|
}, err => {
|
||||||
|
return Promise.reject(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAxiosInstance (config?: AxiosRequestConfig, commonInterceptorConf: { request?: boolean, response?: boolean } = {}): AxiosInstance {
|
||||||
|
const instance = Axios.create(config)
|
||||||
|
|
||||||
|
// Binding a unified interceptor, binding by default
|
||||||
|
commonInterceptorConf.request !== false && bindCommonRequestInterceptors(instance)
|
||||||
|
commonInterceptorConf.response !== false && bindCommonResponseInterceptors(instance)
|
||||||
|
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
const singleAxios = createAxiosInstance({}, { request: true, response: false })
|
||||||
|
|
||||||
|
export default singleAxios
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
export const CURRENT_CONFIG = {
|
||||||
|
|
||||||
|
baseURL: 'Please enter the backend access address prefix.', // This url must end with "/". Example: 'http://192.168.1.1:6789/cloud/'
|
||||||
|
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.',
|
||||||
|
agoraAPPID: 'Please enter the agora app id.',
|
||||||
|
agoraToken: 'Please enter the agora 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.
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import { uuidv4 } from '/@/utils/uuid'
|
||||||
|
import { CURRENT_CONFIG } from './config'
|
||||||
|
export * from './type'
|
||||||
|
const REQUEST_ID = 'X-Request-Id'
|
||||||
|
function getAuthToken () {
|
||||||
|
return localStorage.getItem('x-auth-token')
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = axios.create({
|
||||||
|
// withCredentials: true,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
// timeout: 12000,
|
||||||
|
})
|
||||||
|
|
||||||
|
instance.interceptors.request.use(
|
||||||
|
config => {
|
||||||
|
config.headers['X-Auth-Token'] = getAuthToken()
|
||||||
|
// config.headers[REQUEST_ID] = uuidv4()
|
||||||
|
config.baseURL = CURRENT_CONFIG.baseURL
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
return Promise.reject(error)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
instance.interceptors.response.use(
|
||||||
|
response => response,
|
||||||
|
err => {
|
||||||
|
const requestId = err?.config?.headers && err?.config?.headers[REQUEST_ID]
|
||||||
|
console.info('')
|
||||||
|
if (requestId) {
|
||||||
|
console.info(REQUEST_ID, ':', requestId)
|
||||||
|
}
|
||||||
|
console.info('url: ', err?.config?.url, `【${err?.config?.method}】 \n>>>> err: `, err)
|
||||||
|
|
||||||
|
let description = '-'
|
||||||
|
if (err.response?.data && err.response.data.message) {
|
||||||
|
description = err.response.data.message
|
||||||
|
}
|
||||||
|
if (err.response?.data && err.response.data.result) {
|
||||||
|
description = err.response.data.result.message
|
||||||
|
}
|
||||||
|
// @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}`)
|
||||||
|
}
|
||||||
|
if (err.response?.status === 403) {
|
||||||
|
// window.location.href = '/'
|
||||||
|
}
|
||||||
|
if (err.response?.status === 401) {
|
||||||
|
console.log(err.response)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(err)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
export default instance
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
export interface IResult {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPage {
|
||||||
|
page: number;
|
||||||
|
total: number;
|
||||||
|
page_size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IListWorkspaceResponse<T> {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
data: {
|
||||||
|
list: T[];
|
||||||
|
pagination: IPage;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Workspace
|
||||||
|
export interface IWorkspaceResponse<T> {
|
||||||
|
[x: string]: number;
|
||||||
|
code: number;
|
||||||
|
data: T;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
export type IStatus = 'WAITING' | 'DOING' | 'SUCCESS' | 'FAILED';
|
||||||
|
|
||||||
|
export interface CommonListResponse<T> extends IResult {
|
||||||
|
data: {
|
||||||
|
list: T[];
|
||||||
|
pagination: IPage;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CommonResponse<T> extends IResult {
|
||||||
|
data: T
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
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')
|
||||||
|
type UnknownResponse = Promise<IWorkspaceResponse<unknown>>
|
||||||
|
// get elements group
|
||||||
|
// export const getLayers = async (reqParams: elementGroupsReq): UnknownResponse => {
|
||||||
|
// const url = `${PREFIX}/workspaces/${workspace_id}/element_groups`
|
||||||
|
// const result = await request.get(url, {
|
||||||
|
// params: {
|
||||||
|
// group_id: reqParams.groupId,
|
||||||
|
// is_distributed: reqParams.isDistributed
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// return result.data
|
||||||
|
// }
|
||||||
|
export const getLayers = async (reqParams: elementGroupsReq): UnknownResponse => {
|
||||||
|
return mapLayers
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get elements groups request
|
||||||
|
export const getElementGroupsReq = async (body: elementGroupsReq): Promise<IWorkspaceResponse<any>> => {
|
||||||
|
const url = `${PREFIX}/workspaces/` + workspace_id + '/element-groups'
|
||||||
|
const result = await request.get(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
// add element
|
||||||
|
export const postElementsReq = async (pid: string, body: PostElementsBody): Promise<IWorkspaceResponse<{ id: string }>> => {
|
||||||
|
const url = `${PREFIX}/workspaces/` + workspace_id + `/element-groups/${pid}/elements`
|
||||||
|
const result = await request.post(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
// Update map element request
|
||||||
|
export const updateElementsReq = async (id: string, body: PutElementsBody): Promise<IWorkspaceResponse<{ id: string }>> => {
|
||||||
|
const url = `${PREFIX}/workspaces/` + workspace_id + `/elements/${id}`
|
||||||
|
const result = await request.put(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
// Delete map element
|
||||||
|
export const deleteElementReq = async (id: string, body: {}): Promise<any> => {
|
||||||
|
const url = `${PREFIX}/workspaces/` + workspace_id + `/elements/${id}`
|
||||||
|
const result = await request.delete(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete layer elements
|
||||||
|
export const deleteLayerEleReq = async (id: string, body: {}): Promise<any> => {
|
||||||
|
const url = `${PREFIX}/workspaces/` + workspace_id + `/element-groups/${id}/elements`
|
||||||
|
const result = await request.delete(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import request, { IWorkspaceResponse } from '/@/api/http/request'
|
||||||
|
const HTTP_PREFIX = '/manage/api/v1'
|
||||||
|
|
||||||
|
// login
|
||||||
|
interface loginBody {
|
||||||
|
username: string,
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
export const login = async function (body: loginBody): Promise<IWorkspaceResponse<any>> {
|
||||||
|
const url = `${HTTP_PREFIX}/login`
|
||||||
|
const result = await request.post(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh Token
|
||||||
|
export const refreshToken = async function (body: {}): Promise<IWorkspaceResponse<any>> {
|
||||||
|
const url = `${HTTP_PREFIX}/token/refresh`
|
||||||
|
const result = await request.post(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Platform Info
|
||||||
|
export const getPlatformInfo = async function (body: {}): Promise<IWorkspaceResponse<any>> {
|
||||||
|
const url = `${HTTP_PREFIX}/workspaces/current`
|
||||||
|
const result = await request.get(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get User Info
|
||||||
|
export const getUserInfo = async function (body: {}): Promise<IWorkspaceResponse<any>> {
|
||||||
|
const url = `${HTTP_PREFIX}/users/current`
|
||||||
|
const result = await request.get(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Device Topo
|
||||||
|
export const getDeviceTopo = async function (body: {}): Promise<IWorkspaceResponse<any>> {
|
||||||
|
const url = `${HTTP_PREFIX}/devices/devices`
|
||||||
|
const result = await request.get(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Livestream Capacity
|
||||||
|
export const getLiveCapacity = async function (body: {}): Promise<IWorkspaceResponse<any>> {
|
||||||
|
const url = `${HTTP_PREFIX}/live/capacity`
|
||||||
|
const result = await request.get(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start Livestream
|
||||||
|
export const startLivestream = async function (body: {}): Promise<IWorkspaceResponse<any>> {
|
||||||
|
const url = `${HTTP_PREFIX}/live/streams/start`
|
||||||
|
const result = await request.post(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop Livestream
|
||||||
|
export const stopLivestream = async function (body: {}): Promise<IWorkspaceResponse<any>> {
|
||||||
|
const url = `${HTTP_PREFIX}/live/streams/stop`
|
||||||
|
const result = await request.post(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '/@/api/http/request'
|
||||||
|
const HTTP_PREFIX = '/media/api/v1'
|
||||||
|
|
||||||
|
// Get Media Files
|
||||||
|
export const getMediaFiles = async function (wid: string, body: {}): Promise<any> {
|
||||||
|
const url = `${HTTP_PREFIX}/files/${wid}/files`
|
||||||
|
const result = await request.get(url, body)
|
||||||
|
return result.data
|
||||||
|
}
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
import { getRoot } from '/@/root'
|
||||||
|
|
||||||
|
const root = getRoot()
|
||||||
|
const components = new Map()
|
||||||
|
|
||||||
|
declare let window:any
|
||||||
|
|
||||||
|
interface JsResponse{
|
||||||
|
code:number,
|
||||||
|
message:string,
|
||||||
|
data:{}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init () {
|
||||||
|
components.set('thing', {
|
||||||
|
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', {
|
||||||
|
userName: '',
|
||||||
|
elementPreName: ''
|
||||||
|
})
|
||||||
|
components.set('ws', {
|
||||||
|
host: '',
|
||||||
|
token: '',
|
||||||
|
connectCallback: ''
|
||||||
|
})
|
||||||
|
components.set('api', {
|
||||||
|
host: '',
|
||||||
|
token: ''
|
||||||
|
})
|
||||||
|
components.set('tsa', {
|
||||||
|
})
|
||||||
|
components.set('media', {
|
||||||
|
autoUploadPhoto: true, // 是否自动上传图片, 非必需
|
||||||
|
autoUploadPhotoType: 1, // 自动上传的照片类型,0:原图, 1:缩略图, 非必需
|
||||||
|
autoUploadVideo: true // 是否自动上传视频, 非必需
|
||||||
|
})
|
||||||
|
components.set('mission', {
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getComponentParam (key:string) {
|
||||||
|
return components.get(key)
|
||||||
|
},
|
||||||
|
setComponentParam (key:string, value:any) {
|
||||||
|
components.set(key, value)
|
||||||
|
},
|
||||||
|
loadComponent (name:string, param:any):string {
|
||||||
|
return window.djiBridge.platformLoadComponent(name, JSON.stringify(param))
|
||||||
|
},
|
||||||
|
unloadComponent (name:string) :string {
|
||||||
|
return window.djiBridge.platformUnloadComponent(name)
|
||||||
|
},
|
||||||
|
isComponentLoaded (module:string):string {
|
||||||
|
return window.djiBridge.platformIsComponentLoaded(module)
|
||||||
|
},
|
||||||
|
setWorkspaceId (uuid:string):string {
|
||||||
|
return window.djiBridge.platformSetWorkspaceId(uuid)
|
||||||
|
},
|
||||||
|
setPlatformMessage (platformName:string, title:string, desc:string):string {
|
||||||
|
return window.djiBridge.platformSetInformation(platformName, title, desc)
|
||||||
|
},
|
||||||
|
getRemoteControllerSN () :string {
|
||||||
|
return window.djiBridge.platformGetRemoteControllerSN()
|
||||||
|
},
|
||||||
|
getAircraftSN ():string {
|
||||||
|
return 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)
|
||||||
|
},
|
||||||
|
setLogEncryptKey (key:string):string {
|
||||||
|
return window.djiBridge.platformSetLogEncryptKey(key)
|
||||||
|
},
|
||||||
|
clearLogEncryptKey ():string {
|
||||||
|
return window.djiBridge.platformClearLogEncryptKey()
|
||||||
|
},
|
||||||
|
getLogPath ():string {
|
||||||
|
return window.djiBridge.platformGetLogPath()
|
||||||
|
},
|
||||||
|
platformVerifyLicense (appId:string, appKey:string, appLicense:string):string {
|
||||||
|
return window.djiBridge.platformVerifyLicense(appId, appKey, appLicense)
|
||||||
|
},
|
||||||
|
isPlatformVerifySuccess ():string {
|
||||||
|
return window.djiBridge.platformIsVerified()
|
||||||
|
},
|
||||||
|
// liveshare
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* video-on-demand: 服务器点播,依赖于thing模块,具体的点播命令参见设备物模型的直播服务
|
||||||
|
* video-by-manual:手动点播,配置好直播类型参数之后,在图传页面可修改直播参数,停止直播
|
||||||
|
* video-demand-aux-manual: 混合模式,支持服务器点播,以及图传页面修改直播参数,停止直播
|
||||||
|
*/
|
||||||
|
setVideoPublishType (type:string):string {
|
||||||
|
return window.djiBridge.liveshareSetVideoPublishType(type)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* type: liveshare type, 0:unknown, 1:agora, 2:rtmp, 3:rtsp, 4:gb28181
|
||||||
|
*/
|
||||||
|
getLiveshareConfig () {
|
||||||
|
return window.djiBridge.liveshareGetConfig()
|
||||||
|
},
|
||||||
|
|
||||||
|
setLiveshareConfig (type:number, params:string):string {
|
||||||
|
return window.djiBridge.liveshareSetConfig(type, params)
|
||||||
|
},
|
||||||
|
|
||||||
|
setLiveshareStatusCallback (callbackFunc:string) :string {
|
||||||
|
return window.djiBridge.liveshareSetStatusCallback(callbackFunc)
|
||||||
|
},
|
||||||
|
getLiveshareStatus () {
|
||||||
|
return window.djiBridge.liveshareGetStatus()
|
||||||
|
},
|
||||||
|
startLiveshare ():string {
|
||||||
|
return window.djiBridge.liveshareStartLive()
|
||||||
|
},
|
||||||
|
stopLiveshare ():string {
|
||||||
|
return window.djiBridge.liveshareStopLive()
|
||||||
|
},
|
||||||
|
// media
|
||||||
|
setAutoUploadPhoto (auto:boolean):string {
|
||||||
|
return window.djiBridge.mediaSetAutoUploadPhoto(auto)
|
||||||
|
},
|
||||||
|
getAutoUploadPhoto () {
|
||||||
|
return window.djiBridge.mediaGetAutoUploadPhoto()
|
||||||
|
},
|
||||||
|
setUploadPhotoType (type:number):string {
|
||||||
|
return window.djiBridge.mediaSetUploadPhotoType(type)
|
||||||
|
},
|
||||||
|
getUploadPhotoType () {
|
||||||
|
return window.djiBridge.mediaGetUploadPhotoType()
|
||||||
|
},
|
||||||
|
setAutoUploadVideo (auto:boolean):string {
|
||||||
|
return window.djiBridge.mediaSetAutoUploadVideo(auto)
|
||||||
|
},
|
||||||
|
getAutoUploadVideo () {
|
||||||
|
return window.djiBridge.mediaGetAutoUploadVideo()
|
||||||
|
},
|
||||||
|
setDownloadOwner (rcIndex:number):string {
|
||||||
|
return window.djiBridge.mediaSetDownloadOwner(rcIndex)
|
||||||
|
},
|
||||||
|
getDownloadOwner () {
|
||||||
|
return window.djiBridge.mediaGetDownloadOwner()
|
||||||
|
},
|
||||||
|
onBackClickReg () {
|
||||||
|
window.djiBridge.onBackClick = () => {
|
||||||
|
if (root.$router.currentRoute.value.path === '/pilot-home') {
|
||||||
|
console.log(root.$router.currentRoute.value.path)
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
console.log(root.$router.currentRoute.value.path)
|
||||||
|
history.go(-1)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '/@/api/http/request'
|
||||||
|
const HTTP_PREFIX = '/wayline/api/v1'
|
||||||
|
|
||||||
|
// Get Wayline Files
|
||||||
|
export const getWaylineFiles = async function (wid: string, body: {}): Promise<any> {
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import ReconnectingWebSocket from 'reconnecting-websocket'
|
||||||
|
import { CURRENT_CONFIG as config } from '/@/api/http/config'
|
||||||
|
|
||||||
|
let socket = {}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init (getMsgFunc) {
|
||||||
|
const token = localStorage.getItem('x-auth-token')
|
||||||
|
const wspath =
|
||||||
|
config.websocketURL + '?x-auth-token=' + escape(token)
|
||||||
|
socket = new ReconnectingWebSocket(wspath)
|
||||||
|
socket.onopen = this.onOpen
|
||||||
|
socket.onerror = this.onError
|
||||||
|
socket.onmessage = getMsgFunc
|
||||||
|
socket.onclose = this.onClose
|
||||||
|
return socket
|
||||||
|
},
|
||||||
|
onOpen () {
|
||||||
|
console.log('ws opened')
|
||||||
|
},
|
||||||
|
onError (err) {
|
||||||
|
console.error(err)
|
||||||
|
},
|
||||||
|
onClose () {
|
||||||
|
console.log('ws closed')
|
||||||
|
},
|
||||||
|
sendMsg (data) {
|
||||||
|
this.socket.send(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
|
||||||
|
<title>ic/panel/checkbox_active</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<g id="ic/panel/checkbox_active" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="Group-3" fill="#FFFFFF">
|
||||||
|
<polygon id="Shape-Copy" points="11.2103387 4.23529412 6.47425817 8.97137463 4.50089127 6.99800776 2.82352941 8.65563591 4.79689632 10.6290028 6.37558979 12.2076964 6.47425817 12.286631 12.8877005 5.8929223"></polygon>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 731 B |
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="layer" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 652 652" style="enable-background:new 0 0 652 652;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#241F1F;}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M464.9,404.7l44.3-183.9h-95l-40.5,164.9c-5.9,32.2-40.4,47.2-64.9,47.6h-67.3l-22.9,66.3h141.5
|
||||||
|
C395,499.6,446.5,481.8,464.9,404.7"/>
|
||||||
|
<path class="st0" d="M265.5,339.9L310.1,153h97.8l-50.8,212.6c-9.8,41.1-40.3,50.9-68.5,50.9H63.2c-24.8,0-45.6-10.6-34.4-58
|
||||||
|
l20.3-84.8c10.3-43,42.3-52.9,65.4-52.9h157.3l-12.7,53h-80.3c-11.8,0-18.3,2.6-21.6,16.3l-13,54.1c-4.6,19.4,2.2,20.8,16.4,20.8
|
||||||
|
h73.6C247.8,365.2,259.6,364.3,265.5,339.9"/>
|
||||||
|
<polygon class="st0" points="530.7,220.9 484.6,416.5 579.7,416.5 625.7,220.9 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 952 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<defs><path d="m14.042 0 14.043 8.055-5.128 2.941 5.128 2.941-5.127 2.94 5.127 2.942-14.043 8.055L0 19.82l5.126-2.942L0 13.937l5.127-2.941L0 8.056 14.042 0zM7.638 18.318l-2.614 1.5 9.018 5.175 9.017-5.174-2.614-1.5-6.403 3.674-6.404-3.675zm0-5.882-2.615 1.5 9.02 5.175 9.017-5.173-2.615-1.501-6.403 3.674-6.404-3.675zm6.404-9.554L5.024 8.056l9.018 5.174 9.017-5.174-9.017-5.174z" id="layer_a"></path></defs><g transform="translate(2 2)" fill-rule="evenodd"><mask id="layer_b"><use xlink:href="#layer_a"></use></mask><use fill-rule="nonzero" xlink:href="#layer_a"></use><g mask="url(#layer_b)"><path d="M-19-20h68v68h-68z"></path></g></g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 830 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<defs><path d="M29.5 4v21.5h-4v2H3V8h3V4h23.5zM10.553 18.859 5.5 22.399V25H23v-6.088l-7.011 5.108-5.436-5.161zM27 6.5H8.499L8.5 8h17v15H27V6.5zm-4 4H5.5v8.847l5.293-3.707 5.406 5.133L23 15.819V10.5zm-6.362 1.956a2 2 0 1 1 0 4 2 2 0 0 1 0-4z" id="media_a"></path></defs><g fill-rule="evenodd"><mask id="media_b"><use xlink:href="#media_a"></use></mask><use fill-rule="nonzero" xlink:href="#media_a"></use><g mask="url(#media_b)"><path d="M-17-18h68v68h-68z"></path></g></g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 666 B |
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
|
||||||
|
<title>2图标/24px/pin</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs>
|
||||||
|
<path d="M6.56239716,0 L13.1247943,9.89949494 L6.56239716,19.7989899 L0,9.89949494 L6.56239716,0 Z M6.56239716,3.61897251 L2.39965953,9.89878783 L6.56239716,16.1786032 L10.7251348,9.89878783 L6.56239716,3.61897251 Z" id="path-1"></path>
|
||||||
|
</defs>
|
||||||
|
<g id="2图标//24px/pin" stroke="none" stroke-width="1" fill="#19BE6B" fill-rule="evenodd">
|
||||||
|
<g id="编组" transform="translate(5.000000, 2.000000)">
|
||||||
|
<mask id="mask-2" fill="white">
|
||||||
|
<use xlink:href="#path-1"></use>
|
||||||
|
</mask>
|
||||||
|
<use id="形状" fill="#19BE6B" fill-rule="nonzero" xlink:href="#path-1"></use>
|
||||||
|
<g id="1颜色/ic色/nor" mask="url(#mask-2)" fill="#19BE6B">
|
||||||
|
<g transform="translate(-26.000000, -26.000000)">
|
||||||
|
<rect x="0" y="0" width="68" height="68"></rect>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 1.2 KiB |
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
|
||||||
|
<title>2图标/24px/pin</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs>
|
||||||
|
<path d="M6.56239716,0 L13.1247943,9.89949494 L6.56239716,19.7989899 L0,9.89949494 L6.56239716,0 Z M6.56239716,3.61897251 L2.39965953,9.89878783 L6.56239716,16.1786032 L10.7251348,9.89878783 L6.56239716,3.61897251 Z" id="path-1"></path>
|
||||||
|
</defs>
|
||||||
|
<g id="2图标//24px/pin" stroke="none" stroke-width="1" fill="#212121" fill-rule="evenodd">
|
||||||
|
<g id="编组" transform="translate(5.000000, 2.000000)">
|
||||||
|
<mask id="mask-2" fill="white">
|
||||||
|
<use xlink:href="#path-1"></use>
|
||||||
|
</mask>
|
||||||
|
<use id="形状" fill="#212121" fill-rule="nonzero" xlink:href="#path-1"></use>
|
||||||
|
<g id="1颜色/ic色/nor" mask="url(#mask-2)" fill="#212121">
|
||||||
|
<g transform="translate(-26.000000, -26.000000)">
|
||||||
|
<rect x="0" y="0" width="68" height="68"></rect>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 1.2 KiB |
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
|
||||||
|
<title>2图标/24px/pin</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs>
|
||||||
|
<path d="M6.56239716,0 L13.1247943,9.89949494 L6.56239716,19.7989899 L0,9.89949494 L6.56239716,0 Z M6.56239716,3.61897251 L2.39965953,9.89878783 L6.56239716,16.1786032 L10.7251348,9.89878783 L6.56239716,3.61897251 Z" id="path-1"></path>
|
||||||
|
</defs>
|
||||||
|
<g id="2图标//24px/pin" stroke="none" stroke-width="1" fill="#2D8CF0" fill-rule="evenodd">
|
||||||
|
<g id="编组" transform="translate(5.000000, 2.000000)">
|
||||||
|
<mask id="mask-2" fill="white">
|
||||||
|
<use xlink:href="#path-1"></use>
|
||||||
|
</mask>
|
||||||
|
<use id="形状" fill="#2D8CF0" fill-rule="nonzero" xlink:href="#path-1"></use>
|
||||||
|
<g id="1颜色/ic色/nor" mask="url(#mask-2)" fill="#2D8CF0">
|
||||||
|
<g transform="translate(-26.000000, -26.000000)">
|
||||||
|
<rect x="0" y="0" width="68" height="68"></rect>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 1.2 KiB |
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
|
||||||
|
<title>2图标/24px/pin</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs>
|
||||||
|
<path d="M6.56239716,0 L13.1247943,9.89949494 L6.56239716,19.7989899 L0,9.89949494 L6.56239716,0 Z M6.56239716,3.61897251 L2.39965953,9.89878783 L6.56239716,16.1786032 L10.7251348,9.89878783 L6.56239716,3.61897251 Z" id="path-1"></path>
|
||||||
|
</defs>
|
||||||
|
<g id="2图标//24px/pin" stroke="none" stroke-width="1" fill="#b620e0" fill-rule="evenodd">
|
||||||
|
<g id="编组" transform="translate(5.000000, 2.000000)">
|
||||||
|
<mask id="mask-2" fill="white">
|
||||||
|
<use xlink:href="#path-1"></use>
|
||||||
|
</mask>
|
||||||
|
<use id="形状" fill="#b620e0" fill-rule="nonzero" xlink:href="#path-1"></use>
|
||||||
|
<g id="1颜色/ic色/nor" mask="url(#mask-2)" fill="#b620e0">
|
||||||
|
<g transform="translate(-26.000000, -26.000000)">
|
||||||
|
<rect x="0" y="0" width="68" height="68"></rect>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 1.2 KiB |
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
|
||||||
|
<title>2图标/24px/pin</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs>
|
||||||
|
<path d="M6.56239716,0 L13.1247943,9.89949494 L6.56239716,19.7989899 L0,9.89949494 L6.56239716,0 Z M6.56239716,3.61897251 L2.39965953,9.89878783 L6.56239716,16.1786032 L10.7251348,9.89878783 L6.56239716,3.61897251 Z" id="path-1"></path>
|
||||||
|
</defs>
|
||||||
|
<g id="2图标//24px/pin" stroke="none" stroke-width="1" fill="#e23c39" fill-rule="evenodd">
|
||||||
|
<g id="编组" transform="translate(5.000000, 2.000000)">
|
||||||
|
<mask id="mask-2" fill="white">
|
||||||
|
<use xlink:href="#path-1"></use>
|
||||||
|
</mask>
|
||||||
|
<use id="形状" fill="#e23c39" fill-rule="nonzero" xlink:href="#path-1"></use>
|
||||||
|
<g id="1颜色/ic色/nor" mask="url(#mask-2)" fill="#e23c39">
|
||||||
|
<g transform="translate(-26.000000, -26.000000)">
|
||||||
|
<rect x="0" y="0" width="68" height="68"></rect>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 1.2 KiB |
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
|
||||||
|
<title>2图标/24px/pin</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs>
|
||||||
|
<path d="M6.56239716,0 L13.1247943,9.89949494 L6.56239716,19.7989899 L0,9.89949494 L6.56239716,0 Z M6.56239716,3.61897251 L2.39965953,9.89878783 L6.56239716,16.1786032 L10.7251348,9.89878783 L6.56239716,3.61897251 Z" id="path-1"></path>
|
||||||
|
</defs>
|
||||||
|
<g id="2图标//24px/pin" stroke="none" stroke-width="1" fill="#FFBB00" fill-rule="evenodd">
|
||||||
|
<g id="编组" transform="translate(5.000000, 2.000000)">
|
||||||
|
<mask id="mask-2" fill="white">
|
||||||
|
<use xlink:href="#path-1"></use>
|
||||||
|
</mask>
|
||||||
|
<use id="形状" fill="#FFBB00" fill-rule="nonzero" xlink:href="#path-1"></use>
|
||||||
|
<g id="1颜色/ic色/nor" mask="url(#mask-2)" fill="#FFBB00">
|
||||||
|
<g transform="translate(-26.000000, -26.000000)">
|
||||||
|
<rect x="0" y="0" width="68" height="68"></rect>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 1.2 KiB |
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<defs>
|
||||||
|
<path d="m19.87 10.131-1.01 2.518-.86-.012v-.006l-7.045.002-.068.004a1.75 1.75 0 0 0-1.614 1.737l.006.144.656 8.388h4.804l-1.005 2.5h-6.11l-.168-2.137H.544l-.53-6.896a4.25 4.25 0 0 1 4.03-4.598l.206-.005h2.48a4.25 4.25 0 0 1 .873.09 4.238 4.238 0 0 1 3.089-1.716l.166-.01.166-.003h8.846zm1.106 1.7 5.476 13.566-5.454-1.781-5.497 1.78 5.475-13.565zm.008 4.028.011 6.18H21l2.854.931-2.87-7.111zm-14.21-1.588L4.25 14.27a1.75 1.75 0 0 0-1.75 1.75l.007.153.352 4.597 4.401-.001-.473-6.056a4.3 4.3 0 0 1-.012-.442zM6.193 3.748a3.25 3.25 0 1 1 0 6.5 3.25 3.25 0 0 1 0-6.5zM14.3 0a4.25 4.25 0 1 1 0 8.5 4.25 4.25 0 0 1 0-8.5zM6.192 5.748a1.25 1.25 0 1 0 0 2.5 1.25 1.25 0 0 0 0-2.5zM14.3 2a2.25 2.25 0 1 0 0 4.5 2.25 2.25 0 0 0 0-4.5z" id="team_a">
|
||||||
|
</path>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(3 3)" fill-rule="evenodd">
|
||||||
|
<mask id="team_b">
|
||||||
|
<use xlink:href="#team_a"></use>
|
||||||
|
</mask>
|
||||||
|
<use fill-rule="nonzero" xlink:href="#team_a"></use>
|
||||||
|
<g mask="url(#team_b)"><path d="M-20-21h68v68h-68z"></path>
|
||||||
|
</g></g>
|
||||||
|
</svg>
|
||||||
|
Depois Largura: | Altura: | Tamanho: 1.2 KiB |
@@ -0,0 +1,311 @@
|
|||||||
|
<template>
|
||||||
|
<div class="g-map-wrapper">
|
||||||
|
<div id="g-container" :style="{ width: '100%', height: '100%' }" />
|
||||||
|
<div
|
||||||
|
class="g-action-panle"
|
||||||
|
:style="{ right: drawVisible ? '316px' : '16px' }"
|
||||||
|
>
|
||||||
|
<div class="g-action-item" @click="draw('pin', true)">
|
||||||
|
<a-button type="primary">PIN</a-button>
|
||||||
|
</div>
|
||||||
|
<div class="g-action-item" @click="draw('polyline', true)">
|
||||||
|
<a-button type="primary">Line</a-button>
|
||||||
|
</div>
|
||||||
|
<div class="g-action-item" @click="draw('polygon', true)">
|
||||||
|
<a-button type="primary">Poly</a-button>
|
||||||
|
</div>
|
||||||
|
<div v-if="mouseMode" class="g-action-item" @click="draw('off', false)">
|
||||||
|
<a-button type="primary" danger>X</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, onMounted, reactive, ref, watch } from 'vue'
|
||||||
|
import {
|
||||||
|
generateLineContent,
|
||||||
|
generatePointContent,
|
||||||
|
generatePolyContent
|
||||||
|
} from '../utils/map-layer-utils'
|
||||||
|
import { postElementsReq } from '/@/api/layer'
|
||||||
|
import { MapDoodleType, MapElementEnum } from '/@/constants/map'
|
||||||
|
import { useGMapManage } from '/@/hooks/use-g-map'
|
||||||
|
import { useGMapCover } from '/@/hooks/use-g-map-cover'
|
||||||
|
import { useMouseTool } from '/@/hooks/use-mouse-tool'
|
||||||
|
import { getApp } from '/@/root'
|
||||||
|
import { useMyStore } from '/@/store'
|
||||||
|
import { GeojsonCoordinate } from '/@/types/map'
|
||||||
|
import { MapDoodleEnum } from '/@/types/map-enum'
|
||||||
|
import { PostElementsBody } from '/@/types/mapLayer'
|
||||||
|
import { uuidv4 } from '/@/utils/uuid'
|
||||||
|
import { gcj02towgs84, wgs84togcj02 } from '/@/vendors/coordtransform'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'GMap',
|
||||||
|
props: {},
|
||||||
|
setup () {
|
||||||
|
const useMouseToolHook = useMouseTool()
|
||||||
|
const useGMapManageHook = useGMapManage()
|
||||||
|
|
||||||
|
const mouseMode = ref(false)
|
||||||
|
const store = useMyStore()
|
||||||
|
const state = reactive({
|
||||||
|
currentType: '',
|
||||||
|
coverIndex: 0
|
||||||
|
})
|
||||||
|
const shareId = computed(() => {
|
||||||
|
return store.state.layerBaseInfo.share
|
||||||
|
})
|
||||||
|
const defaultId = computed(() => {
|
||||||
|
return store.state.layerBaseInfo.default
|
||||||
|
})
|
||||||
|
const drawVisible = computed(() => {
|
||||||
|
return store.state.drawVisible
|
||||||
|
})
|
||||||
|
watch(
|
||||||
|
() => store.state.wsEvent,
|
||||||
|
newData => {
|
||||||
|
const useGMapCoverHook = useGMapCover()
|
||||||
|
const event = newData
|
||||||
|
let exist = false
|
||||||
|
if (Object.keys(event.mapElementCreat).length !== 0) {
|
||||||
|
console.log(event.mapElementCreat)
|
||||||
|
const ele = event.mapElementCreat
|
||||||
|
store.state.Layers.forEach(layer => {
|
||||||
|
layer.elements.forEach(e => {
|
||||||
|
if (e.id === ele.id) {
|
||||||
|
exist = true
|
||||||
|
console.log('true')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (exist === false) {
|
||||||
|
setLayers({
|
||||||
|
id: ele.id,
|
||||||
|
name: ele.name,
|
||||||
|
resource: ele.resource
|
||||||
|
})
|
||||||
|
|
||||||
|
updateCoordinates('wgs84-gcj02', ele)
|
||||||
|
useGMapCoverHook.init2DPin(
|
||||||
|
ele.name,
|
||||||
|
ele.resource.content.geometry.coordinates,
|
||||||
|
ele.resource.content.properties.color,
|
||||||
|
{
|
||||||
|
id: ele.id,
|
||||||
|
name: ele.name
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
store.state.wsEvent.mapElementCreat = {}
|
||||||
|
}
|
||||||
|
if (Object.keys(event.mapElementUpdate).length !== 0) {
|
||||||
|
console.log(event.mapElementUpdate)
|
||||||
|
console.log('该功能还未实现,请开发商自己增加')
|
||||||
|
store.state.wsEvent.mapElementUpdate = {}
|
||||||
|
}
|
||||||
|
if (Object.keys(event.mapElementDelete).length !== 0) {
|
||||||
|
console.log(event.mapElementDelete)
|
||||||
|
console.log('该功能还未实现,请开发商自己增加')
|
||||||
|
store.state.wsEvent.mapElementDelete = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function draw (type: MapDoodleType, bool: boolean) {
|
||||||
|
state.currentType = type
|
||||||
|
useMouseToolHook.mouseTool(type, getDrawCallback)
|
||||||
|
mouseMode.value = bool
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
const app = getApp()
|
||||||
|
useGMapManageHook.globalPropertiesConfig(app)
|
||||||
|
})
|
||||||
|
function getDrawCallback ({ obj }) {
|
||||||
|
switch (state.currentType) {
|
||||||
|
case MapDoodleEnum.PIN:
|
||||||
|
postPinPositionResource(obj)
|
||||||
|
break
|
||||||
|
case MapDoodleEnum.POLYLINE:
|
||||||
|
postPolylineResource(obj)
|
||||||
|
break
|
||||||
|
case MapDoodleEnum.POLYGON:
|
||||||
|
postPolygonResource(obj)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function postPinPositionResource (obj) {
|
||||||
|
const req = getPinPositionResource(obj)
|
||||||
|
setLayers(req)
|
||||||
|
updateCoordinates('gcj02-wgs84', req)
|
||||||
|
const result = await postElementsReq(shareId.value, req)
|
||||||
|
obj.setExtData({ id: req.id, name: req.name })
|
||||||
|
store.state.coverList.push(obj)
|
||||||
|
// console.log(store.state.coverList)
|
||||||
|
}
|
||||||
|
async function postPolylineResource (obj) {
|
||||||
|
const req = getPolylineResource(obj)
|
||||||
|
setLayers(req)
|
||||||
|
updateCoordinates('gcj02-wgs84', req)
|
||||||
|
const result = await postElementsReq(shareId.value, req)
|
||||||
|
obj.setExtData({ id: req.id, name: req.name })
|
||||||
|
store.state.coverList.push(obj)
|
||||||
|
// console.log(store.state.coverList)
|
||||||
|
}
|
||||||
|
async function postPolygonResource (obj) {
|
||||||
|
const req = getPoygonResource(obj)
|
||||||
|
setLayers(req)
|
||||||
|
updateCoordinates('gcj02-wgs84', req)
|
||||||
|
const result = await postElementsReq(shareId.value, req)
|
||||||
|
obj.setExtData({ id: req.id, name: req.name })
|
||||||
|
store.state.coverList.push(obj)
|
||||||
|
// console.log(store.state.coverList)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPinPositionResource (obj) {
|
||||||
|
const position = obj.getPosition()
|
||||||
|
const resource = generatePointContent(position)
|
||||||
|
const name = obj._originOpts.title
|
||||||
|
const id = uuidv4()
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
resource
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getPolylineResource (obj) {
|
||||||
|
const path = obj.getPath()
|
||||||
|
const resource = generateLineContent(path)
|
||||||
|
const { name, id } = getBaseInfo(obj._opts)
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
resource
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getPoygonResource (obj) {
|
||||||
|
const path = obj.getPath()
|
||||||
|
const resource = generatePolyContent(path)
|
||||||
|
const { name, id } = getBaseInfo(obj._opts)
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
resource
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getBaseInfo (obj) {
|
||||||
|
const name = obj.title
|
||||||
|
const id = uuidv4()
|
||||||
|
return { name, id }
|
||||||
|
}
|
||||||
|
function setLayers (resource: PostElementsBody) {
|
||||||
|
const layers = store.state.Layers
|
||||||
|
const layer = layers.find(item => item.id.includes(shareId.value))
|
||||||
|
// layer.id = 'private_layer' + uuidv4()
|
||||||
|
// layer?.elements.push(resource)
|
||||||
|
if (layer?.elements) {
|
||||||
|
;(layer?.elements as any[]).push(resource)
|
||||||
|
}
|
||||||
|
console.log('layers', layers)
|
||||||
|
store.commit('SET_LAYER_INFO', layers)
|
||||||
|
}
|
||||||
|
function updateCoordinates (transformType: string, element: any) {
|
||||||
|
const geoType = element.resource?.content.geometry.type
|
||||||
|
const type = element.resource?.type as number
|
||||||
|
if (element.resource) {
|
||||||
|
if (MapElementEnum.PIN === type) {
|
||||||
|
const coordinates = element.resource?.content.geometry
|
||||||
|
.coordinates as GeojsonCoordinate
|
||||||
|
if (transformType === 'wgs84-gcj02') {
|
||||||
|
const transResult = wgs84togcj02(
|
||||||
|
coordinates[0],
|
||||||
|
coordinates[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
element.resource.content.geometry.coordinates = transResult
|
||||||
|
} else if (transformType === 'gcj02-wgs84') {
|
||||||
|
const transResult = gcj02towgs84(
|
||||||
|
coordinates[0],
|
||||||
|
coordinates[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
element.resource.content.geometry.coordinates = transResult
|
||||||
|
}
|
||||||
|
} else if (MapElementEnum.LINE === type && geoType === 'LineString') {
|
||||||
|
const coordinates = element.resource?.content.geometry
|
||||||
|
.coordinates as GeojsonCoordinate[]
|
||||||
|
if (transformType === 'wgs84-gcj02') {
|
||||||
|
coordinates.forEach(coordinate => {
|
||||||
|
coordinate = wgs84togcj02(
|
||||||
|
coordinate[0],
|
||||||
|
coordinate[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
})
|
||||||
|
} else if (transformType === 'gcj02-wgs84') {
|
||||||
|
coordinates.forEach(coordinate => {
|
||||||
|
coordinate = gcj02towgs84(
|
||||||
|
coordinate[0],
|
||||||
|
coordinate[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
})
|
||||||
|
}
|
||||||
|
element.resource.content.geometry.coordinates = coordinates
|
||||||
|
} else if (MapElementEnum.LINE === type && geoType === 'Polygon') {
|
||||||
|
const coordinates = element.resource?.content.geometry
|
||||||
|
.coordinates[0] as GeojsonCoordinate[]
|
||||||
|
|
||||||
|
if (transformType === 'wgs84-gcj02') {
|
||||||
|
coordinates.forEach(coordinate => {
|
||||||
|
coordinate = wgs84togcj02(
|
||||||
|
coordinate[0],
|
||||||
|
coordinate[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
})
|
||||||
|
} else if (transformType === 'gcj02-wgs84') {
|
||||||
|
coordinates.forEach(coordinate => {
|
||||||
|
coordinate = gcj02towgs84(
|
||||||
|
coordinate[0],
|
||||||
|
coordinate[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
})
|
||||||
|
}
|
||||||
|
element.resource.content.geometry.coordinates = [coordinates]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
draw,
|
||||||
|
mouseMode,
|
||||||
|
drawVisible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.g-map-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
.g-action-panle {
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
right: 16px;
|
||||||
|
.g-action-item {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss">
|
||||||
|
.amap-logo {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.amap-copyright {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<a-tree
|
||||||
|
draggable
|
||||||
|
:defaultExpandAll="true"
|
||||||
|
class="device-map-layers"
|
||||||
|
@drop="onDrop"
|
||||||
|
v-bind="$attrs"
|
||||||
|
>
|
||||||
|
<a-tree-node
|
||||||
|
:title="layer.name"
|
||||||
|
:id="layer.id"
|
||||||
|
v-for="layer in getTreeData"
|
||||||
|
:key="layer.id"
|
||||||
|
>
|
||||||
|
<!-- <template #title>
|
||||||
|
{{layer.name}}
|
||||||
|
</template> -->
|
||||||
|
<template v-if="layer.elements">
|
||||||
|
<a-tree-node
|
||||||
|
v-for="resource in layer.elements"
|
||||||
|
:id="getLayerTreeKey('resource', resource.id)"
|
||||||
|
:key="getLayerTreeKey('resource', resource.id)"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
{{ resource.name }}
|
||||||
|
</template>
|
||||||
|
</a-tree-node>
|
||||||
|
</template>
|
||||||
|
</a-tree-node>
|
||||||
|
</a-tree>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, defineProps, PropType, reactive } from 'vue'
|
||||||
|
import { useMyStore } from '/@/store'
|
||||||
|
import { DropEvent, mapLayer } from '/@/types/mapLayer'
|
||||||
|
import { getLayerTreeKey } from '/@/utils/layer-tree'
|
||||||
|
const store = useMyStore()
|
||||||
|
const props = defineProps({
|
||||||
|
layerData: Array as PropType<mapLayer[]>
|
||||||
|
})
|
||||||
|
const state = reactive({
|
||||||
|
checkedKeys: [] as string[],
|
||||||
|
expandedKeys: [] as string[]
|
||||||
|
})
|
||||||
|
const getTreeData = computed(() => {
|
||||||
|
// console.log('props.treeData', JSON.parse(JSON.stringify(props.layerData)))
|
||||||
|
return JSON.parse(JSON.stringify(props.layerData))
|
||||||
|
})
|
||||||
|
const shareId = computed(() => {
|
||||||
|
return store.state.layerBaseInfo.share
|
||||||
|
})
|
||||||
|
const defaultId = computed(() => {
|
||||||
|
return store.state.layerBaseInfo.default
|
||||||
|
})
|
||||||
|
async function onDrop ({ node, dragNode, dropPosition, dropToGap }: DropEvent) {
|
||||||
|
let _treeData = props.layerData || []
|
||||||
|
let dragKey = dragNode.eventKey
|
||||||
|
dragKey = dragKey.replaceAll('resource__', '')
|
||||||
|
const dropPos = node.pos.split('-')
|
||||||
|
let dropKey =
|
||||||
|
node.eventKey.includes(shareId.value) ||
|
||||||
|
node.eventKey.includes(defaultId.value)
|
||||||
|
? node.eventKey
|
||||||
|
: node.$parent.eventKey
|
||||||
|
if (!dragKey || !dropKey) return
|
||||||
|
dropKey = dropKey.replaceAll('resource__', '')
|
||||||
|
const loop = (data: mapLayer[], key: string, callback: Function) => {
|
||||||
|
data.forEach((item, index, arr) => {
|
||||||
|
if (item.id === key) {
|
||||||
|
return callback(item, index, arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.elements) {
|
||||||
|
return loop(item.elements, key, callback)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const data = [..._treeData] as mapLayer[]
|
||||||
|
// Find dragObject
|
||||||
|
let dragObj = {} as mapLayer
|
||||||
|
loop(data, dragKey, (item: mapLayer, index: number, arr: mapLayer[]) => {
|
||||||
|
arr.splice(index, 1)
|
||||||
|
dragObj = item
|
||||||
|
})
|
||||||
|
if (!dropToGap) {
|
||||||
|
// Drop on the content
|
||||||
|
loop(data, dropKey, (item: mapLayer) => {
|
||||||
|
item.elements = item.elements || []
|
||||||
|
// where to insert 示例添加到尾部,可以是随意位置
|
||||||
|
item.elements.push(dragObj)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_treeData = data
|
||||||
|
// console.log('_treeData', _treeData)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
$antPrefix: 'ant';
|
||||||
|
.device-map-layers.#{$antPrefix}-tree {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
.#{$antPrefix}-tree-checkbox:not(.#{$antPrefix}-tree-checkbox-checked)
|
||||||
|
.#{$antPrefix}-tree-checkbox-inner {
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.anticon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一个层级的 li,有左边距 16px
|
||||||
|
> li {
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.#{$antPrefix}-tree-treenode-disabled
|
||||||
|
> .#{$antPrefix}-tree-node-content-wrapper {
|
||||||
|
height: 20px;
|
||||||
|
span {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> ul {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$antPrefix}-tree-switcher {
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$antPrefix}-tree-checkbox {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.#{$antPrefix}-tree-checkbox:hover::after,
|
||||||
|
.#{$antPrefix}-tree-checkbox-wrapper:hover
|
||||||
|
.#{$antPrefix}-tree-checkbox::after {
|
||||||
|
visibility: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$antPrefix}-tree-title {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$antPrefix}-tree-node-content-wrapper {
|
||||||
|
color: #fff;
|
||||||
|
width: calc(100% - 46px);
|
||||||
|
flex: 1;
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 20px;
|
||||||
|
min-width: 0; // 解决文字溢出不会省略的问题
|
||||||
|
padding-right: 0;
|
||||||
|
|
||||||
|
&:not([draggable='true']) {
|
||||||
|
border-top: 2px transparent solid;
|
||||||
|
border-bottom: 2px transparent solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
&::before {
|
||||||
|
// position: absolute;
|
||||||
|
// right: 0;
|
||||||
|
// left: 0;
|
||||||
|
height: 28px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 进度条组件需要相对最外层定位,进度条组件的position不能设置为relative
|
||||||
|
> *:not(.progress-wrapper) {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.#{$antPrefix}-tree-node-selected {
|
||||||
|
background-color: transparent;
|
||||||
|
color: #2d8cf0;
|
||||||
|
> span {
|
||||||
|
&::before {
|
||||||
|
background-color: #4f4f4f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span.#{$antPrefix}-tree-switcher.#{$antPrefix}-tree-switcher_open
|
||||||
|
.#{$antPrefix}-tree-switcher-icon {
|
||||||
|
transform: rotate(0deg) !important;
|
||||||
|
}
|
||||||
|
span.#{$antPrefix}-tree-switcher.#{$antPrefix}-tree-switcher_close
|
||||||
|
.#{$antPrefix}-tree-switcher-icon {
|
||||||
|
transform: rotate(0deg) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<div class="media-panel-wrapper">
|
||||||
|
<div class="header">Media</div>
|
||||||
|
<a-button type="primary" style="margin-top:20px" @click="onRefresh"
|
||||||
|
>Refresh</a-button
|
||||||
|
>
|
||||||
|
<a-table class="media-table" :columns="columns" :data-source="data">
|
||||||
|
<template #name="{ text, record }">
|
||||||
|
<a :href="record.preview_url">{{ text }}</a>
|
||||||
|
</template>
|
||||||
|
<template #action>
|
||||||
|
<span class="action-area">
|
||||||
|
action
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from '@vue/reactivity'
|
||||||
|
import { getMediaFiles } from '/@/api/media'
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'FileName',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
slots: { customRender: 'name' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'FileSize',
|
||||||
|
dataIndex: 'size',
|
||||||
|
key: 'size'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'PayloadType',
|
||||||
|
dataIndex: 'payload_type',
|
||||||
|
key: 'payload_type',
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
key: 'action',
|
||||||
|
slots: { customRender: 'action' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const data = ref([
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
name: 'name1',
|
||||||
|
size: 32,
|
||||||
|
payload_type: 'PM320_DUAL',
|
||||||
|
preview_url: ''
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const onRefresh = async () => {
|
||||||
|
const wid = localStorage.getItem('workspace-id')
|
||||||
|
data.value = []
|
||||||
|
const index = 1
|
||||||
|
const res = await getMediaFiles(wid, {})
|
||||||
|
res.data.forEach(ele => {
|
||||||
|
data.value.push({
|
||||||
|
key: index.toString(),
|
||||||
|
name: ele.file_name
|
||||||
|
})
|
||||||
|
})
|
||||||
|
console.log(res)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.media-panel-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
.media-table {
|
||||||
|
background: #fff;
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
background: #fff;
|
||||||
|
padding: 16px 24px;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: start;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.action-area {
|
||||||
|
color: $primary;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<svg :class="svgClass" :aria-hidden="true" :style="{color: color, width:computedWidth, height:computedWidth}">
|
||||||
|
<use :xlink:href="iconName" :fill="color"/>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { defineProps, computed } from 'vue'
|
||||||
|
const props = defineProps({
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const iconName = computed(() => `#icon-${props.name}`)
|
||||||
|
const svgClass = computed(() => {
|
||||||
|
console.log(props.name, 'props.name')
|
||||||
|
if (props.name) {
|
||||||
|
return `svg-icon icon-${props.name}`
|
||||||
|
}
|
||||||
|
return 'svg-icon'
|
||||||
|
})
|
||||||
|
const computedWidth = computed(() => {
|
||||||
|
const result = props.width || props.size
|
||||||
|
return result ? result + 'px' : '1em'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang='scss'>
|
||||||
|
.svg-icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
fill: currentColor;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-wrapper">
|
||||||
|
<div class="header">Wayline Library</div>
|
||||||
|
<a-button type="primary" style="margin-top:20px" @click="onRefresh"
|
||||||
|
>Refresh</a-button
|
||||||
|
>
|
||||||
|
<a-table class="table" :columns="columns" :data-source="data">
|
||||||
|
<template #name="{ text, record }">
|
||||||
|
<a :href="record.preview_url">{{ text }}</a>
|
||||||
|
</template>
|
||||||
|
<template #action>
|
||||||
|
<span class="action-area">
|
||||||
|
action
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from '@vue/reactivity'
|
||||||
|
import { onMounted } from 'vue'
|
||||||
|
import { getWaylineFiles } from '/@/api/wayline'
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'FileName',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
slots: { customRender: 'name' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'TemplateType',
|
||||||
|
dataIndex: 'template_type',
|
||||||
|
key: 'template_type'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Favorited',
|
||||||
|
dataIndex: 'favorite',
|
||||||
|
key: 'favorite'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'DroneType',
|
||||||
|
dataIndex: 'drone_type',
|
||||||
|
key: 'drone_type'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'PayloadType',
|
||||||
|
dataIndex: 'payload_type',
|
||||||
|
key: 'payload_type'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'User',
|
||||||
|
dataIndex: 'user',
|
||||||
|
key: 'user'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
key: 'action',
|
||||||
|
slots: { customRender: 'action' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const data = ref([
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
name: 'name1',
|
||||||
|
template_type: '0',
|
||||||
|
drone_type: '0-60-0',
|
||||||
|
payload_type: 'PM320_DUAL',
|
||||||
|
user: 'pilot',
|
||||||
|
favorited: 'true'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
onMounted(() => {
|
||||||
|
onRefresh()
|
||||||
|
})
|
||||||
|
const onRefresh = async () => {
|
||||||
|
const wid: string = localStorage.getItem('workspace-id')
|
||||||
|
data.value = []
|
||||||
|
const index = 1
|
||||||
|
const res = await getWaylineFiles(wid, {
|
||||||
|
page: 1, // 页数
|
||||||
|
page_size: 9, // 每页大小
|
||||||
|
order_by: 'update_time desc' // 排序, xxx_column_desc, xxx_column_asc, xxx_column(default asc)
|
||||||
|
})
|
||||||
|
console.log(res)
|
||||||
|
res.data.list.forEach(ele => {
|
||||||
|
data.value.push({
|
||||||
|
key: index.toString(),
|
||||||
|
name: ele.name,
|
||||||
|
template_type: ele.template_types[0],
|
||||||
|
drone_type: ele.drone_model_key,
|
||||||
|
payload_type: ele.payload_model_keys[0],
|
||||||
|
user: ele.user_name,
|
||||||
|
favorite: ele.favorited.toString()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
console.log('wayline files:', data.value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.panel-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
.table {
|
||||||
|
background: #fff;
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
background: #fff;
|
||||||
|
padding: 16px 24px;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: start;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.action-area {
|
||||||
|
color: $primary;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export const AMapConfig = {
|
||||||
|
key: '26d54da6733de88435c68d1a2e88b682',
|
||||||
|
version: '2.0',
|
||||||
|
plugins: [
|
||||||
|
'AMap.Scale',
|
||||||
|
'AMap.ToolBar',
|
||||||
|
'AMap.ControlBar',
|
||||||
|
'AMap.ElasticMarker',
|
||||||
|
'AMap.MapType',
|
||||||
|
'AMap.Geocoder',
|
||||||
|
'AMap.CircleEditor',
|
||||||
|
'AMap.PolygonEditor',
|
||||||
|
'AMap.PolylineEditor',
|
||||||
|
'AMap.PolyEditor',
|
||||||
|
'AMap.RangingTool',
|
||||||
|
'AMap.Weather',
|
||||||
|
'AMap.MouseTool'
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
export enum MapElementColor {
|
||||||
|
Blue = '#2D8CF0',
|
||||||
|
Green = '#19BE6B',
|
||||||
|
Yellow = '#FFBB00',
|
||||||
|
Red = '#E23C39',
|
||||||
|
Orange = '#B620E0',
|
||||||
|
Default = '#212121'
|
||||||
|
}
|
||||||
|
export const MapElementDefaultColor = MapElementColor.Default
|
||||||
|
|
||||||
|
export enum MapDoodleColor {
|
||||||
|
PinColor = '#2D8CF0',
|
||||||
|
PolylineColor = '#3366FF',
|
||||||
|
PolygonColor = '#FF33FF'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum MapElementEnum {
|
||||||
|
PIN = 0,
|
||||||
|
LINE = 1,
|
||||||
|
POLY = 2
|
||||||
|
}
|
||||||
|
export type MapDoodleType = 'pin' | 'polyline' | 'polygon' | 'off'
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
export const mapLayers = {
|
||||||
|
code: 0,
|
||||||
|
message: 'success',
|
||||||
|
data: {
|
||||||
|
list: [{
|
||||||
|
id: 'private_layer',
|
||||||
|
name: 'Private Layer',
|
||||||
|
order: 0,
|
||||||
|
is_distributed: false,
|
||||||
|
type: 1,
|
||||||
|
is_lock: false,
|
||||||
|
create_time: 1634268707424,
|
||||||
|
elements: [{
|
||||||
|
id: 'b2370d29-be65-42b0-9224-4d816e86dc64',
|
||||||
|
name: 'xuejia n. 1',
|
||||||
|
order: 0,
|
||||||
|
status: 1,
|
||||||
|
display: 1,
|
||||||
|
resource: {
|
||||||
|
content: {
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {
|
||||||
|
color: '#2D8CF0'
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [
|
||||||
|
[
|
||||||
|
[114.156671, 38.468249],
|
||||||
|
[114.139517, 37.372177],
|
||||||
|
[115.52899, 37.712212]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
type: 4,
|
||||||
|
user_name: 'xuejia n.',
|
||||||
|
user_id: '1402914943455727616'
|
||||||
|
},
|
||||||
|
update_time: 1636966336566,
|
||||||
|
create_time: 1636966325700,
|
||||||
|
elevation_load_status: 0,
|
||||||
|
icon: 'area'
|
||||||
|
}, {
|
||||||
|
id: '768e9fcd-121f-47a6-96b9-f1aee27d32f0',
|
||||||
|
name: 'xuejia n. 1',
|
||||||
|
order: 0,
|
||||||
|
status: 1,
|
||||||
|
display: 1,
|
||||||
|
resource: {
|
||||||
|
content: {
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {
|
||||||
|
color: '#2D8CF0'
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: 'LineString',
|
||||||
|
coordinates: [
|
||||||
|
[116.263962, 40.234929],
|
||||||
|
[116.503006, 40.237026],
|
||||||
|
[116.335465, 40.155206],
|
||||||
|
[116.541458, 40.12371]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
type: 4,
|
||||||
|
user_name: 'xuejia n.',
|
||||||
|
user_id: '1402914943455727616'
|
||||||
|
},
|
||||||
|
update_time: 1636966322636,
|
||||||
|
create_time: 1636966316803,
|
||||||
|
elevation_load_status: 0,
|
||||||
|
icon: 'line'
|
||||||
|
}, {
|
||||||
|
id: '4e741a76-3600-4af5-ace8-d805e7cd31fa',
|
||||||
|
name: 'xuejia n. 2',
|
||||||
|
order: 0,
|
||||||
|
status: 1,
|
||||||
|
display: 1,
|
||||||
|
resource: {
|
||||||
|
content: {
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {
|
||||||
|
color: '#2D8CF0',
|
||||||
|
clampToGround: true
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [116.098223, 39.976538, 104]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
type: 6,
|
||||||
|
user_name: 'xuejia n.',
|
||||||
|
user_id: '1402914943455727616'
|
||||||
|
},
|
||||||
|
update_time: 1636966305229,
|
||||||
|
create_time: 1636966305229,
|
||||||
|
elevation_load_status: 0,
|
||||||
|
icon: 'pin'
|
||||||
|
}, {
|
||||||
|
id: 'efff2b5d-de22-4d48-8d92-4f53170668f6',
|
||||||
|
name: 'xuejia n. 1',
|
||||||
|
order: 0,
|
||||||
|
status: 1,
|
||||||
|
display: 1,
|
||||||
|
resource: {
|
||||||
|
content: {
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {
|
||||||
|
color: '#19BE6B',
|
||||||
|
clampToGround: true
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [113.35367028239645, 23.755194000519843, 22]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
type: 6,
|
||||||
|
user_name: 'xuejia n.',
|
||||||
|
user_id: '1402914943455727616'
|
||||||
|
},
|
||||||
|
update_time: 1636966304432,
|
||||||
|
create_time: 1636966299455,
|
||||||
|
elevation_load_status: 0,
|
||||||
|
icon: 'pin'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
id: 'share_layer',
|
||||||
|
name: 'Share Layer',
|
||||||
|
order: 0,
|
||||||
|
is_distributed: true,
|
||||||
|
type: 2,
|
||||||
|
is_lock: false,
|
||||||
|
create_time: 1634268707414,
|
||||||
|
elements: []
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// Environment variable definition
|
||||||
|
// https://cn.vitejs.dev/guide/env-and-mode.html#env-files
|
||||||
|
|
||||||
|
interface ImportMetaEnv {
|
||||||
|
VITE_APP_ENVIRONMENT: 'DEV' | 'STAG' | 'UAT' | 'PROD',
|
||||||
|
// api gateway
|
||||||
|
VITE_APP_APIGATEWAY_BACKEND_HOST: string
|
||||||
|
// More environment variables...
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
import pin19be6b from '/@/assets/icons/pin-19be6b.svg'
|
||||||
|
import pin212121 from '/@/assets/icons/pin-212121.svg'
|
||||||
|
import pin2d8cf0 from '/@/assets/icons/pin-2d8cf0.svg'
|
||||||
|
import pinb620e0 from '/@/assets/icons/pin-b620e0.svg'
|
||||||
|
import pine23c39 from '/@/assets/icons/pin-e23c39.svg'
|
||||||
|
import pineffbb00 from '/@/assets/icons/pin-ffbb00.svg'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
import rootStore from '/@/store'
|
||||||
|
import { GeojsonCoordinate } from '/@/types/map'
|
||||||
|
|
||||||
|
export function useGMapCover () {
|
||||||
|
const root = getRoot()
|
||||||
|
const AMap = root.$aMapObj
|
||||||
|
const normalColor = '#2D8CF0'
|
||||||
|
const store = rootStore
|
||||||
|
const coverList = store.state.coverList
|
||||||
|
|
||||||
|
function AddCoverToMap (cover :any) {
|
||||||
|
root.$aMap.add(cover)
|
||||||
|
coverList.push(cover)
|
||||||
|
// console.log('coverList:', store.state.coverList)
|
||||||
|
}
|
||||||
|
function getPinIcon (color?:string) {
|
||||||
|
// console.log('color', color)
|
||||||
|
const colorObj: {
|
||||||
|
[key: number| string]: any
|
||||||
|
} = {
|
||||||
|
'2d8cf0': pin2d8cf0,
|
||||||
|
'19be6b': pin19be6b,
|
||||||
|
212121: pin212121,
|
||||||
|
b620e0: pinb620e0,
|
||||||
|
e23c39: pine23c39,
|
||||||
|
ffbb00: pineffbb00,
|
||||||
|
|
||||||
|
}
|
||||||
|
const iconName = (color?.replaceAll('#', '') || '').toLocaleLowerCase()
|
||||||
|
return new AMap.Icon({
|
||||||
|
// size: new AMap.Size(40, 50),
|
||||||
|
image: colorObj[iconName],
|
||||||
|
// imageOffset: new AMap.Pixel(0, -60),
|
||||||
|
// imageSize: new AMap.Size(40, 50)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function init2DPin (name: string, coordinates:GeojsonCoordinate, color?:string, data?:{}) {
|
||||||
|
console.log(name, coordinates[0], coordinates[1], color, data)
|
||||||
|
const pin = new AMap.Marker({
|
||||||
|
position: new AMap.LngLat(coordinates[0], coordinates[1]),
|
||||||
|
title: name,
|
||||||
|
icon: getPinIcon(color),
|
||||||
|
// strokeColor: color || normalColor,
|
||||||
|
// fillColor: color || normalColor,
|
||||||
|
extData: data
|
||||||
|
})
|
||||||
|
// console.log('coordinates pin', pin)
|
||||||
|
AddCoverToMap(pin)
|
||||||
|
}
|
||||||
|
function AddOverlayGroup (overlayGroup) {
|
||||||
|
root.$aMap.add(overlayGroup)
|
||||||
|
coverList.push(overlayGroup)
|
||||||
|
}
|
||||||
|
function initPolyline (name: string, coordinates:GeojsonCoordinate[], color?:string, data?:{}) {
|
||||||
|
const path = [] as GeojsonCoordinate[]
|
||||||
|
coordinates.forEach(coordinate => {
|
||||||
|
path.push(new AMap.LngLat(coordinate[0], coordinate[1]))
|
||||||
|
})
|
||||||
|
const polyline = new AMap.Polyline({
|
||||||
|
path: path,
|
||||||
|
strokeColor: color || normalColor,
|
||||||
|
strokeOpacity: 1,
|
||||||
|
strokeWeight: 2,
|
||||||
|
strokeStyle: 'solid',
|
||||||
|
extData: data
|
||||||
|
// draggable: true,
|
||||||
|
})
|
||||||
|
AddOverlayGroup(polyline)
|
||||||
|
}
|
||||||
|
function initPolygon (name: string, coordinates:GeojsonCoordinate[], color?:string, data?:{}) {
|
||||||
|
const path = [] as GeojsonCoordinate[]
|
||||||
|
coordinates.forEach(coordinate => {
|
||||||
|
path.push(new AMap.LngLat(coordinate[0], coordinate[1]))
|
||||||
|
})
|
||||||
|
// console.log('Polygon', path)
|
||||||
|
const Polygon = new AMap.Polygon({
|
||||||
|
path: path,
|
||||||
|
strokeOpacity: 1,
|
||||||
|
strokeWeight: 2,
|
||||||
|
fillColor: color || normalColor,
|
||||||
|
fillOpacity: 0.4,
|
||||||
|
// draggable: true,
|
||||||
|
strokeColor: color || normalColor,
|
||||||
|
extData: data
|
||||||
|
})
|
||||||
|
AddOverlayGroup(Polygon)
|
||||||
|
}
|
||||||
|
function removeCoverFromMap (id:string) {
|
||||||
|
for (let i = 0; i < coverList.length; i++) {
|
||||||
|
const ele = coverList[i]
|
||||||
|
// console.log(ele)
|
||||||
|
const extdata = ele?.getExtData()
|
||||||
|
if (extdata?.id === id) {
|
||||||
|
console.log(extdata)
|
||||||
|
root.$aMap.remove(ele)
|
||||||
|
coverList.slice(i, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getElementFromMap (id:string) {
|
||||||
|
// console.log('start', new Date().getTime())
|
||||||
|
const ele = coverList.find(ele => ele?.getExtData().id === id)
|
||||||
|
// console.log('end', new Date().getTime())
|
||||||
|
return ele
|
||||||
|
// coverList.forEach((ele:any) => {
|
||||||
|
// const extdata = ele?.getExtData()
|
||||||
|
// // console.log(extdata)
|
||||||
|
// if (extdata?.id === id) {
|
||||||
|
// return ele
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
function updatePinElement (id:string, name: string, coordinates:GeojsonCoordinate, color?:string) {
|
||||||
|
const element = getElementFromMap(id) as any
|
||||||
|
if (element) {
|
||||||
|
const icon = getPinIcon(color)
|
||||||
|
element.setPosition(new AMap.LngLat(coordinates[0], coordinates[1]))
|
||||||
|
element.setIcon(icon)
|
||||||
|
element.setTitle(name)
|
||||||
|
} else {
|
||||||
|
// console.log('into init PIN')
|
||||||
|
init2DPin(name, coordinates, color, {
|
||||||
|
id: id,
|
||||||
|
name: name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
init2DPin,
|
||||||
|
initPolyline,
|
||||||
|
initPolygon,
|
||||||
|
removeCoverFromMap,
|
||||||
|
getElementFromMap,
|
||||||
|
updatePinElement
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import AMapLoader from '@amap/amap-jsapi-loader'
|
||||||
|
import { App, reactive } from 'vue'
|
||||||
|
import { AMapConfig } from '/@/constants/index'
|
||||||
|
|
||||||
|
export function useGMapManage () {
|
||||||
|
const state = reactive({
|
||||||
|
mapEntity: null,
|
||||||
|
mapObj: null,
|
||||||
|
mouseTool: null,
|
||||||
|
})
|
||||||
|
async function initMap (container: string, app:App) {
|
||||||
|
AMapLoader.load({
|
||||||
|
...AMapConfig
|
||||||
|
}).then((AMap) => {
|
||||||
|
state.mapObj = AMap
|
||||||
|
state.mapEntity = new AMap.Map(container, {
|
||||||
|
center: [113.935913, 22.525335],
|
||||||
|
zoom: 15
|
||||||
|
})
|
||||||
|
state.mouseTool = new AMap.MouseTool(state.mapEntity)
|
||||||
|
app.config.globalProperties.$aMap = state.mapEntity
|
||||||
|
app.config.globalProperties.$aMapObj = state.mapObj
|
||||||
|
app.config.globalProperties.$mouseTool = state.mouseTool
|
||||||
|
}).catch(e => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function globalPropertiesConfig (app:App) {
|
||||||
|
initMap('g-container', app)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
globalPropertiesConfig,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { reactive } from 'vue'
|
||||||
|
import pin2d8cf0 from '/@/assets/icons/pin-2d8cf0.svg'
|
||||||
|
import { MapDoodleType } from '/@/constants/map'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
import { MapDoodleEnum } from '/@/types/map-enum'
|
||||||
|
|
||||||
|
export function useMouseTool () {
|
||||||
|
const root = getRoot()
|
||||||
|
const AMap = root.$aMapObj
|
||||||
|
const state = reactive({
|
||||||
|
pinNum: 0,
|
||||||
|
polylineNum: 0,
|
||||||
|
PolygonNum: 0,
|
||||||
|
currentType: '',
|
||||||
|
})
|
||||||
|
function drawPin (type:MapDoodleType, getDrawCallback:Function) {
|
||||||
|
root?.$mouseTool.marker({
|
||||||
|
title: type + state.pinNum,
|
||||||
|
icon: pin2d8cf0,
|
||||||
|
})
|
||||||
|
state.pinNum++
|
||||||
|
root?.$mouseTool.on('draw', getDrawCallback)
|
||||||
|
}
|
||||||
|
function drawPolyline (type:MapDoodleType, getDrawCallback:Function) {
|
||||||
|
root?.$mouseTool.polyline({
|
||||||
|
strokeColor: '#2d8cf0',
|
||||||
|
strokeOpacity: 1,
|
||||||
|
strokeWeight: 2,
|
||||||
|
strokeStyle: 'solid',
|
||||||
|
draggable: true,
|
||||||
|
title: type + state.polylineNum++
|
||||||
|
})
|
||||||
|
root?.$mouseTool.on('draw', getDrawCallback)
|
||||||
|
}
|
||||||
|
function drawPolygon (type:MapDoodleType, getDrawCallback:Function) {
|
||||||
|
root?.$mouseTool.polygon({
|
||||||
|
strokeColor: '#2d8cf0',
|
||||||
|
strokeOpacity: 1,
|
||||||
|
strokeWeight: 2,
|
||||||
|
fillColor: '#1791fc',
|
||||||
|
fillOpacity: 0.4,
|
||||||
|
draggable: true,
|
||||||
|
title: type + state.PolygonNum++
|
||||||
|
})
|
||||||
|
root?.$mouseTool.on('draw', getDrawCallback)
|
||||||
|
}
|
||||||
|
function drawOff (type:MapDoodleType) {
|
||||||
|
root?.$mouseTool.close()
|
||||||
|
root?.$mouseTool.off('draw')
|
||||||
|
}
|
||||||
|
function mouseTool (type: MapDoodleType, getDrawCallback: Function) {
|
||||||
|
state.currentType = type
|
||||||
|
switch (type) {
|
||||||
|
case MapDoodleEnum.PIN:
|
||||||
|
drawPin(type, getDrawCallback)
|
||||||
|
break
|
||||||
|
case MapDoodleEnum.POLYLINE:
|
||||||
|
drawPolyline(type, getDrawCallback)
|
||||||
|
break
|
||||||
|
case MapDoodleEnum.POLYGON:
|
||||||
|
drawPolygon(type, getDrawCallback)
|
||||||
|
break
|
||||||
|
case MapDoodleEnum.Close:
|
||||||
|
drawOff(type)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
mouseTool
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import App from './App.vue'
|
||||||
|
import router from './router'
|
||||||
|
import { antComponents } from './antd'
|
||||||
|
import { CommonComponents } from './use-common-components'
|
||||||
|
import 'virtual:svg-icons-register'
|
||||||
|
import store, { storeKey } from './store'
|
||||||
|
import { createInstance } from '/@/root'
|
||||||
|
import '/@/styles/index.scss'
|
||||||
|
const app = createInstance(App)
|
||||||
|
app.use(store, storeKey)
|
||||||
|
app.use(router)
|
||||||
|
app.use(CommonComponents)
|
||||||
|
app.use(antComponents)
|
||||||
|
app.mount('#demo-app')
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div class="element-map-wrapper">
|
||||||
|
<GMap/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, onMounted } from 'vue'
|
||||||
|
import GMap from '/@/components/GMap.vue'
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Elements',
|
||||||
|
components: { GMap },
|
||||||
|
setup () {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<div class="left flex-column flex-justify-start flex-align-center">
|
||||||
|
<p class="fz26 mb0 mt10" style="color: #727272">
|
||||||
|
{{ platformName }}
|
||||||
|
</p>
|
||||||
|
<p class="fz16 ml10 mb0 mt10" style="color: #2d8cf0">
|
||||||
|
status:{{ connect }}
|
||||||
|
</p>
|
||||||
|
<p class="fz32 mb0 mt50" style="color: #000000">{{ workspaceName }}</p>
|
||||||
|
<a-button
|
||||||
|
class="fz20 mt20 flex-column flex-justify-center flex-align-center"
|
||||||
|
style="width: 30vw; height: 12vh;"
|
||||||
|
type="default"
|
||||||
|
@click="onOpen3rdApp"
|
||||||
|
>Open 3rd Party APP</a-button
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
class="fz20"
|
||||||
|
style="width: 15vw; height: 12vh; position: fixed; bottom: 7vh"
|
||||||
|
type="primary"
|
||||||
|
@click="onExit"
|
||||||
|
>Quit</a-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="right flex-column flex-justify-start flex-align-center">
|
||||||
|
<p class="fz24 mb0 mt10 ">Setting</p>
|
||||||
|
<a-button class="mt10 fz16" style="width:90%" @click="onMediaSetting"
|
||||||
|
>Media File Upload Setting</a-button
|
||||||
|
>
|
||||||
|
<a-button class="mt10 fz16" style="width:90%" @click="onLiveshareSetting"
|
||||||
|
>Manual Live Share Setting</a-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { CURRENT_CONFIG } from '/@/api/http/config'
|
||||||
|
import { getPlatformInfo, getUserInfo } from '/@/api/manage'
|
||||||
|
import apiPilot from '/@/api/pilot-bridge'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
|
||||||
|
const root = getRoot()
|
||||||
|
const connect = ref('Disconnect')
|
||||||
|
const platformName = ref('Unknown')
|
||||||
|
const workspaceName = ref('Unknown')
|
||||||
|
const workspaceDesc = ref('Unknown')
|
||||||
|
const wsId = ref()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
apiPilot.init()
|
||||||
|
const token = apiPilot.getToken()
|
||||||
|
if (token) {
|
||||||
|
getPlatformInfo({}).then(res => {
|
||||||
|
console.log(res)
|
||||||
|
platformName.value = res.data.platform_name
|
||||||
|
workspaceName.value = res.data.workspace_name
|
||||||
|
workspaceDesc.value = res.data.workspace_desc
|
||||||
|
wsId.value = res.data.workspace_id
|
||||||
|
apiPilot.setPlatformMessage(
|
||||||
|
platformName.value,
|
||||||
|
workspaceName.value,
|
||||||
|
workspaceDesc.value
|
||||||
|
)
|
||||||
|
apiPilot.setWorkspaceId(wsId.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (JSON.parse(apiPilot.isComponentLoaded('thing')).data === false || token) {
|
||||||
|
getUserInfo({}).then(res => {
|
||||||
|
const param = {
|
||||||
|
host: res.data.mqtt_addr,
|
||||||
|
username: res.data.mqtt_username,
|
||||||
|
password: res.data.mqtt_password,
|
||||||
|
connectCallback: 'connectCallback'
|
||||||
|
}
|
||||||
|
apiPilot.setComponentParam('thing', param)
|
||||||
|
apiPilot.loadComponent('thing', apiPilot.getComponentParam('thing'))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const connectState = JSON.parse(window.djiBridge.thingGetConnectState())
|
||||||
|
if (connectState.code === 0 && connectState.data) {
|
||||||
|
connect.value = 'Connected'
|
||||||
|
} else {
|
||||||
|
connect.value = 'Disconnect'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apiPilot.loadComponent('liveshare', apiPilot.getComponentParam('liveshare'))
|
||||||
|
console.log('ws token:', token)
|
||||||
|
apiPilot.setComponentParam('ws', {
|
||||||
|
host: CURRENT_CONFIG.websocketURL,
|
||||||
|
token: token
|
||||||
|
})
|
||||||
|
apiPilot.loadComponent('ws', apiPilot.getComponentParam('ws'))
|
||||||
|
apiPilot.setComponentParam('map', {
|
||||||
|
userName: 'pilot1',
|
||||||
|
elementPreName: 'PILOT'
|
||||||
|
})
|
||||||
|
apiPilot.loadComponent('map', apiPilot.getComponentParam('map'))
|
||||||
|
apiPilot.loadComponent('tsa', apiPilot.getComponentParam('tsa'))
|
||||||
|
apiPilot.loadComponent('media', apiPilot.getComponentParam('media'))
|
||||||
|
apiPilot.loadComponent('mission', {})
|
||||||
|
window.connectCallback = arg => {
|
||||||
|
connectCallback(arg)
|
||||||
|
}
|
||||||
|
apiPilot.onBackClickReg()
|
||||||
|
})
|
||||||
|
const connectCallback = (arg: any) => {
|
||||||
|
console.info('into callback', arg)
|
||||||
|
if (arg) {
|
||||||
|
connect.value = 'Connected'
|
||||||
|
window.djiBridge.mediaSetDownloadOwner(0)
|
||||||
|
window.djiBridge.mediaSetUploadPhotoType(1)
|
||||||
|
} else {
|
||||||
|
connect.value = 'Disconnect'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onExit = async (e: any) => {
|
||||||
|
apiPilot.stopwebview()
|
||||||
|
}
|
||||||
|
const onMediaSetting = async (e: any) => {
|
||||||
|
root.$router.push('/pilot-media')
|
||||||
|
}
|
||||||
|
const onLiveshareSetting = async (e: any) => {
|
||||||
|
root.$router.push('/pilot-liveshare')
|
||||||
|
}
|
||||||
|
const onOpen3rdApp = () => {
|
||||||
|
window.open('mydjischeme://www.dji.com')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '/@/styles/index.scss';
|
||||||
|
.page {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
transition: width 0.2s ease;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
.left {
|
||||||
|
width: 50%;
|
||||||
|
border-right: red solid 2px;
|
||||||
|
}
|
||||||
|
.right {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
<template>
|
||||||
|
<div class="login flex-column flex-justify-center flex-align-center m0 b0">
|
||||||
|
<a-image
|
||||||
|
style="width: 17vw; height: 10vw; margin-bottom: 50px"
|
||||||
|
src="http://lofrev.net/wp-content/photos/2016/09/dji_logo_png.png"
|
||||||
|
/>
|
||||||
|
<p class="logo fz35 pb50">Pilot Cloud API Demo</p>
|
||||||
|
<a-form
|
||||||
|
layout="inline"
|
||||||
|
:model="formState"
|
||||||
|
class="flex-row flex-justify-center flex-align-center"
|
||||||
|
>
|
||||||
|
<a-form-item>
|
||||||
|
<a-input v-model:value="formState.user" placeholder="Username">
|
||||||
|
<template #prefix
|
||||||
|
><UserOutlined style="color: rgba(0, 0, 0, 0.25)"
|
||||||
|
/></template>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<a-input
|
||||||
|
v-model:value="formState.password"
|
||||||
|
type="password"
|
||||||
|
placeholder="Password"
|
||||||
|
>
|
||||||
|
<template #prefix
|
||||||
|
><LockOutlined style="color: rgba(0, 0, 0, 0.25)"
|
||||||
|
/></template>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<a-button
|
||||||
|
class="m0"
|
||||||
|
type="primary"
|
||||||
|
html-type="submit"
|
||||||
|
:disabled="formState.user === '' || formState.password === ''"
|
||||||
|
@click="onSubmit"
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { LockOutlined, UserOutlined } from '@ant-design/icons-vue'
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import { onMounted, reactive, UnwrapRef } from 'vue'
|
||||||
|
import { CURRENT_CONFIG } from '/@/api/http/config'
|
||||||
|
import { login, refreshToken } from '/@/api/manage'
|
||||||
|
import apiPilot from '/@/api/pilot-bridge'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
|
||||||
|
interface FormState {
|
||||||
|
user: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
const root = getRoot()
|
||||||
|
|
||||||
|
const formState: UnwrapRef<FormState> = reactive({
|
||||||
|
user: 'pilot',
|
||||||
|
password: 'pilot123'
|
||||||
|
})
|
||||||
|
let isVerified:any
|
||||||
|
onMounted(async () => {
|
||||||
|
const verifyLicense = JSON.parse(apiPilot.platformVerifyLicense(CURRENT_CONFIG.appId,
|
||||||
|
CURRENT_CONFIG.appKey, CURRENT_CONFIG.appLicense))
|
||||||
|
const platformVerify = JSON.parse(apiPilot.isPlatformVerifySuccess())
|
||||||
|
isVerified = platformVerify.data
|
||||||
|
if (platformVerify.data === true) {
|
||||||
|
message.success('The license verification is successful.')
|
||||||
|
} else {
|
||||||
|
message.error('Filed to verify the license. message is ' + verifyLicense.data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const token = apiPilot.getToken()
|
||||||
|
console.log('api token:', token)
|
||||||
|
apiPilot.setPlatformMessage('Cloud Api Platform', '', '')
|
||||||
|
if (token && token !== undefined) {
|
||||||
|
await refreshToken({})
|
||||||
|
.then(res => {
|
||||||
|
apiPilot.setComponentParam('api', {
|
||||||
|
host: CURRENT_CONFIG.baseURL,
|
||||||
|
token: res.data.access_token
|
||||||
|
})
|
||||||
|
const jsres = JSON.parse(
|
||||||
|
apiPilot.loadComponent('api', apiPilot.getComponentParam('api'))
|
||||||
|
)
|
||||||
|
console.log('load api module status:', jsres)
|
||||||
|
apiPilot.setToken(res.data.access_token)
|
||||||
|
localStorage.setItem('x-auth-token', res.data.access_token)
|
||||||
|
message.success('Login Success')
|
||||||
|
root.$router.push('/pilot-home')
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const onSubmit = async (e: any) => {
|
||||||
|
await login({
|
||||||
|
username: formState.user,
|
||||||
|
password: formState.password
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (!isVerified) {
|
||||||
|
message.error('Please verify the license firstly.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log('login res:', res)
|
||||||
|
if (res.code === 0) {
|
||||||
|
apiPilot.setComponentParam('api', {
|
||||||
|
host: CURRENT_CONFIG.baseURL,
|
||||||
|
token: res.data.access_token
|
||||||
|
})
|
||||||
|
const jsres = apiPilot.loadComponent(
|
||||||
|
'api',
|
||||||
|
apiPilot.getComponentParam('api')
|
||||||
|
)
|
||||||
|
console.log('load api module res:', jsres)
|
||||||
|
apiPilot.setToken(res.data.access_token)
|
||||||
|
localStorage.setItem('x-auth-token', res.data.access_token)
|
||||||
|
localStorage.setItem('workspace-id', res.data.workspace_id)
|
||||||
|
localStorage.setItem('username', res.data.username)
|
||||||
|
message.success('Login Success')
|
||||||
|
root.$router.push('/pilot-home')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '/@/styles/index.scss';
|
||||||
|
.login {
|
||||||
|
// background-color: $dark-highlight;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
color: $primary;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="width-100vw height-100vh flex-column flex-justify-start flex-align-start"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mt20 flex-row flex-align-center flex-justify-between"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<p class="ml10 mb0 fz16" style="color: black">
|
||||||
|
Select Video Publish Mode:
|
||||||
|
</p>
|
||||||
|
<a-select
|
||||||
|
style="width: 200px"
|
||||||
|
placeholder="Select Mode"
|
||||||
|
@select="onPublishModeSelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in publishModeList"
|
||||||
|
:key="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-divider dashed class="mt10 mb0"></a-divider>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex-row flex-align-center flex-justify-between mt10"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<p class="ml10 mb0 fz16" style="color: black">Select Live Share Type:</p>
|
||||||
|
<a-select
|
||||||
|
style="width: 200px"
|
||||||
|
placeholder="Select Live Type"
|
||||||
|
@select="onLiveTypeSelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in liveTypeList"
|
||||||
|
:key="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
<a-divider dashed class="mt10 mb0"></a-divider>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex-row flex-align-center flex-justify-center mt20"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<p>Live Share State: {{ liveState }}</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex-row flex-align-center flex-justify-center mt20"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<a-button type="primary" @click="onPlay">Play</a-button>
|
||||||
|
<a-button class="ml20" type="primary" @click="onGetConfig"
|
||||||
|
>Get Config</a-button
|
||||||
|
>
|
||||||
|
<a-button class="ml20" type="primary" @click="onGetStatus"
|
||||||
|
>Get Status</a-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { CURRENT_CONFIG as config } from '/@/api/http/config'
|
||||||
|
import apiPilot from '/@/api/pilot-bridge'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
|
||||||
|
const root = getRoot()
|
||||||
|
|
||||||
|
const publishModeList = [
|
||||||
|
{
|
||||||
|
value: 'video-on-demand',
|
||||||
|
label: 'video-on-demand'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'video-by-manual',
|
||||||
|
label: 'video-by-manual'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'video-demand-aux-manual',
|
||||||
|
label: 'video-demand-aux-manual'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const liveTypeList = [
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
label: 'AGORA'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 2,
|
||||||
|
label: 'RTMP'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 3,
|
||||||
|
label: 'RTSP'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 4,
|
||||||
|
label: 'GB28181'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const agoraParam = {
|
||||||
|
uid: config.agoraAPPID,
|
||||||
|
token: config.agoraToken,
|
||||||
|
channelId: config.agoraChannel
|
||||||
|
}
|
||||||
|
const rtmpParam = {
|
||||||
|
url: config.rtmpURL + '12345'
|
||||||
|
}
|
||||||
|
const rtspParam = {
|
||||||
|
userName: 'dji-live-share',
|
||||||
|
password: '12345678',
|
||||||
|
port: '8554'
|
||||||
|
}
|
||||||
|
const gb28181Param = {
|
||||||
|
serverIp: '114.55.103.238',
|
||||||
|
serverPort: '5060',
|
||||||
|
serverId: '34020000002000000001',
|
||||||
|
agentId: '34020000001310000004',
|
||||||
|
password: '12345678',
|
||||||
|
agentPort: '7060',
|
||||||
|
agentChannel: '34020000001310000004'
|
||||||
|
}
|
||||||
|
const liveState = ref<string>('STOP')
|
||||||
|
const livetypeSelected = ref<number>(1)
|
||||||
|
const publishModeSelected = ref<string>('video-demand-aux-manual')
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const status: any = apiPilot.getLiveshareStatus()
|
||||||
|
console.log(status)
|
||||||
|
// liveState.value =
|
||||||
|
// status.status === 0
|
||||||
|
// ? 'Cannot connect to server'
|
||||||
|
// : status.status === 1
|
||||||
|
// ? 'Connect to server'
|
||||||
|
// : 'Playing'
|
||||||
|
|
||||||
|
// console.log(liveState.value)
|
||||||
|
})
|
||||||
|
const onLiveTypeSelect = (val: any) => {
|
||||||
|
livetypeSelected.value = val
|
||||||
|
message.info('set livetype:' + livetypeSelected.value, 5)
|
||||||
|
}
|
||||||
|
const onPublishModeSelect = (val: string) => {
|
||||||
|
publishModeSelected.value = val
|
||||||
|
message.info(
|
||||||
|
'set publish mode res:' +
|
||||||
|
apiPilot.setVideoPublishType(publishModeSelected.value),
|
||||||
|
5
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const onPlay = () => {
|
||||||
|
switch (livetypeSelected.value) {
|
||||||
|
case 1: {
|
||||||
|
message.info('agoraParam:' + JSON.stringify(agoraParam))
|
||||||
|
apiPilot.setLiveshareConfig(1, JSON.stringify(agoraParam))
|
||||||
|
apiPilot.startLiveshare()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
message.info('rtmpParam:' + JSON.stringify(rtmpParam))
|
||||||
|
apiPilot.setLiveshareConfig(2, JSON.stringify(rtmpParam))
|
||||||
|
message.info(apiPilot.startLiveshare())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
message.info('rtspParam:' + JSON.stringify(rtspParam))
|
||||||
|
apiPilot.setLiveshareConfig(3, JSON.stringify(rtspParam))
|
||||||
|
apiPilot.startLiveshare()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
message.info('gb28181Param:' + JSON.stringify(gb28181Param))
|
||||||
|
apiPilot.setLiveshareConfig(4, JSON.stringify(gb28181Param))
|
||||||
|
apiPilot.startLiveshare()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onGetStatus = () => {
|
||||||
|
const status = apiPilot.getLiveshareStatus()
|
||||||
|
message.info(status, 5)
|
||||||
|
}
|
||||||
|
const onGetConfig = () => {
|
||||||
|
const status = apiPilot.getLiveshareConfig()
|
||||||
|
message.info(status, 5)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
// @import '/@/styles/index.scss';
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="width-100vw height-100vh flex-column flex-justify-start flex-align-start"
|
||||||
|
>
|
||||||
|
<p class="fz16 ml10 mt10 mb10 color-text-title color-font-bold">
|
||||||
|
If Enabled, Pilot will upload photos or videos to the server
|
||||||
|
automatically.
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
class="flex-row flex-align-center flex-justify-between"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<p class="ml10 mb0 fz16" style="color: black">Auto Upload Photos</p>
|
||||||
|
<a-switch
|
||||||
|
class="mt0 mb0"
|
||||||
|
v-model:checked="enablePhotoUpload"
|
||||||
|
@change="onPhotoUpload"
|
||||||
|
></a-switch>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex-row flex-align-center flex-justify-between"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<a-radio-group
|
||||||
|
class="mt10 ml20"
|
||||||
|
v-if="enablePhotoUpload == true"
|
||||||
|
v-model:value="photoType"
|
||||||
|
defaultChecked="0"
|
||||||
|
@change="onPhototype"
|
||||||
|
>
|
||||||
|
<a-radio :value="0">Original Photo</a-radio>
|
||||||
|
<a-radio class="ml20" :value="1">Preview Photo</a-radio>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
<a-divider dashed class="mt10 mb0"></a-divider>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex-row flex-align-center flex-justify-between mt10"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<p class="ml10 mb0 fz16" style="color: black">Auto Upload Video</p>
|
||||||
|
<a-switch
|
||||||
|
@change="onVideoUpload"
|
||||||
|
v-model:checked="enableVideoUpload"
|
||||||
|
></a-switch>
|
||||||
|
</div>
|
||||||
|
<a-divider dashed class="mt10 mb0"></a-divider>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex-row flex-align-center flex-justify-between mt20"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<p class="ml10 mb0 fz16 color-font-bold" style="color: black">
|
||||||
|
Path for uploading media resources in dual-controller mode
|
||||||
|
</p>
|
||||||
|
<a-radio-group
|
||||||
|
class="mt0 mb0"
|
||||||
|
v-model:value="uploadPath"
|
||||||
|
button-style="solid"
|
||||||
|
@change="onUploadPath"
|
||||||
|
>
|
||||||
|
<a-radio-button :value="0">Mine</a-radio-button>
|
||||||
|
<a-radio-button :value="1">Another</a-radio-button>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import apiPilot from '/@/api/pilot-bridge'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
|
||||||
|
const root = getRoot()
|
||||||
|
|
||||||
|
const enablePhotoUpload = ref<boolean>(true)
|
||||||
|
const enableVideoUpload = ref<boolean>(false)
|
||||||
|
const photoType = ref<number>(1)
|
||||||
|
const uploadPath = ref<number>(0)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
message.info('After setting, please use the physical button of the remote control to return, otherwise the setting is invalid.')
|
||||||
|
|
||||||
|
enablePhotoUpload.value =
|
||||||
|
apiPilot.getAutoUploadPhoto() === undefined
|
||||||
|
? true
|
||||||
|
: apiPilot.getAutoUploadPhoto()
|
||||||
|
enableVideoUpload.value =
|
||||||
|
apiPilot.getAutoUploadVideo() === undefined
|
||||||
|
? false
|
||||||
|
: apiPilot.getAutoUploadVideo()
|
||||||
|
photoType.value =
|
||||||
|
apiPilot.getUploadPhotoType() === undefined
|
||||||
|
? 1
|
||||||
|
: apiPilot.getUploadPhotoType()
|
||||||
|
uploadPath.value =
|
||||||
|
apiPilot.getDownloadOwner() === undefined ? 0 : apiPilot.getDownloadOwner()
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
enablePhotoUpload.value,
|
||||||
|
enableVideoUpload.value,
|
||||||
|
photoType.value,
|
||||||
|
uploadPath.value
|
||||||
|
)
|
||||||
|
apiPilot.setComponentParam('media', {
|
||||||
|
autoUploadPhoto: enablePhotoUpload.value,
|
||||||
|
autoUploadPhotoType: photoType.value,
|
||||||
|
autoUploadVideo: enableVideoUpload.value
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const onPhotoUpload = () => {
|
||||||
|
apiPilot.setAutoUploadPhoto(enablePhotoUpload.value)
|
||||||
|
}
|
||||||
|
const onVideoUpload = () => {
|
||||||
|
console.log(enableVideoUpload.value)
|
||||||
|
apiPilot.setAutoUploadVideo(enableVideoUpload.value)
|
||||||
|
}
|
||||||
|
const onPhototype = () => {
|
||||||
|
console.log(photoType.value)
|
||||||
|
apiPilot.setUploadPhotoType(photoType.value)
|
||||||
|
}
|
||||||
|
const onUploadPath = (e: any) => {
|
||||||
|
apiPilot.setDownloadOwner(uploadPath.value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
// @import '/@/styles/index.scss';
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="showLogin"
|
||||||
|
class="login flex-column flex-justify-center flex-align-center m0 b0"
|
||||||
|
>
|
||||||
|
<a-image
|
||||||
|
style="width: 17vw; height: 10vw; margin-bottom: 50px"
|
||||||
|
src="http://lofrev.net/wp-content/photos/2016/09/dji_logo_png.png"
|
||||||
|
/>
|
||||||
|
<p class="logo fz35 pb50">Cloud API Demo</p>
|
||||||
|
<a-form
|
||||||
|
layout="inline"
|
||||||
|
:model="formState"
|
||||||
|
class="flex-row flex-justify-center flex-align-center"
|
||||||
|
>
|
||||||
|
<a-form-item>
|
||||||
|
<a-input v-model:value="formState.user" placeholder="Username">
|
||||||
|
<template #prefix
|
||||||
|
><UserOutlined style="color: rgba(0, 0, 0, 0.25)"
|
||||||
|
/></template>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<a-input
|
||||||
|
v-model:value="formState.password"
|
||||||
|
type="password"
|
||||||
|
placeholder="Password"
|
||||||
|
>
|
||||||
|
<template #prefix
|
||||||
|
><LockOutlined style="color: rgba(0, 0, 0, 0.25)"
|
||||||
|
/></template>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<a-button
|
||||||
|
class="m0"
|
||||||
|
type="primary"
|
||||||
|
html-type="submit"
|
||||||
|
:disabled="formState.user === '' || formState.password === ''"
|
||||||
|
@click="onSubmit"
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
<div v-else class="project-app-wrapper">
|
||||||
|
<div class="left">
|
||||||
|
<Sidebar />
|
||||||
|
<div class="main-content uranus-scrollbar dark">
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="map-wrapper">
|
||||||
|
<GMap />
|
||||||
|
</div>
|
||||||
|
<div class="media-wrapper" v-if="getMediaRoute()">
|
||||||
|
<MediaPanel />
|
||||||
|
</div>
|
||||||
|
<div class="wayline-wrapper" v-if="getWaylineRoute()">
|
||||||
|
<WaylinePanel />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { LockOutlined, UserOutlined } from '@ant-design/icons-vue'
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import { reactive, ref, UnwrapRef } from 'vue'
|
||||||
|
import Sidebar from './sidebar.vue'
|
||||||
|
import { login } from '/@/api/manage'
|
||||||
|
import websocket from '/@/api/websocket'
|
||||||
|
import GMap from '/@/components/GMap.vue'
|
||||||
|
import MediaPanel from '/@/components/MediaPanel.vue'
|
||||||
|
import WaylinePanel from '/@/components/wayline-panel.vue'
|
||||||
|
import { useGMapCover } from '/@/hooks/use-g-map-cover'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
import { useMyStore } from '/@/store'
|
||||||
|
|
||||||
|
interface FormState {
|
||||||
|
user: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = getRoot()
|
||||||
|
const showLogin = ref(true)
|
||||||
|
const store = useMyStore()
|
||||||
|
const formState: UnwrapRef<FormState> = reactive({
|
||||||
|
user: 'adminPC',
|
||||||
|
password: 'adminPC'
|
||||||
|
})
|
||||||
|
let socket = {} as any
|
||||||
|
const gMapCoverHook = useGMapCover()
|
||||||
|
|
||||||
|
const onSubmit = async (e: any) => {
|
||||||
|
const result = await login({
|
||||||
|
username: formState.user,
|
||||||
|
password: formState.password
|
||||||
|
})
|
||||||
|
if (result.code === 0) {
|
||||||
|
console.log(result)
|
||||||
|
localStorage.setItem('x-auth-token', result.data.access_token)
|
||||||
|
localStorage.setItem('workspace-id', result.data.workspace_id)
|
||||||
|
localStorage.setItem('username', result.data.username)
|
||||||
|
showLogin.value = false
|
||||||
|
message.info('login success')
|
||||||
|
socket = websocket.init(wsGetMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function wsInfo (data) {
|
||||||
|
// store.commit('SET_DEVICE_INFO', data)
|
||||||
|
// }
|
||||||
|
// function getDeviceInfo () {
|
||||||
|
// const info = store.state.DeviceInfo
|
||||||
|
// console.log(info)
|
||||||
|
const wsGetMsg = async (res: any) => {
|
||||||
|
const payload = JSON.parse(res.data)
|
||||||
|
// console.log(payload)
|
||||||
|
switch (payload.biz_code) {
|
||||||
|
case 'gateway_osd': {
|
||||||
|
store.commit('SET_GATEWAY_INFO', payload.data)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'device_osd': {
|
||||||
|
store.commit('SET_DEVICE_INFO', payload.data)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'map_element_create': {
|
||||||
|
store.commit('SET_MAP_ELEMENT_CREATE', payload.data)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'map_element_update': {
|
||||||
|
store.commit('SET_MAP_ELEMENT_UPDATE', payload.data)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'map_element_delete': {
|
||||||
|
store.commit('SET_MAP_ELEMENT_DELETE', payload.data)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMediaRoute () {
|
||||||
|
return root.$route.name === 'media'
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWaylineRoute () {
|
||||||
|
return root.$route.name === 'wayline'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '/@/styles/index.scss';
|
||||||
|
.login {
|
||||||
|
background-color: $dark-highlight;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
color: $primary;
|
||||||
|
}
|
||||||
|
.project-app-wrapper {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
transition: width 0.2s ease;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
.left {
|
||||||
|
width: 450px;
|
||||||
|
display: flex;
|
||||||
|
background-color: #232323;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.right {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
.map-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
color: $text-white-basic;
|
||||||
|
}
|
||||||
|
.media-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background: #f6f8fa;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.wayline-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background: #f6f8fa;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,438 @@
|
|||||||
|
<template>
|
||||||
|
<div class="project-layer-wrapper">
|
||||||
|
<LayersTree
|
||||||
|
:layer-data="mapLayers"
|
||||||
|
class="project-layer-content"
|
||||||
|
@check="checkLayer"
|
||||||
|
@select="selectLayer"
|
||||||
|
v-model:selectedKeys="selectedKeys"
|
||||||
|
v-model:checkedKeys="checkedKeys"
|
||||||
|
/>
|
||||||
|
<a-drawer
|
||||||
|
title="Map Element"
|
||||||
|
placement="right"
|
||||||
|
:closable="true"
|
||||||
|
v-model:visible="visible"
|
||||||
|
:mask="false"
|
||||||
|
wrapClassName="drawer-element-wrapper"
|
||||||
|
@close="closeDrawer"
|
||||||
|
width="300"
|
||||||
|
>
|
||||||
|
<div class="drawer-element-content">
|
||||||
|
<div class="name element-item">
|
||||||
|
<span class="title">Name:</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="layerState.layerName"
|
||||||
|
style="width:120px"
|
||||||
|
placeholder="element name"
|
||||||
|
@change="changeLayer"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="longitude element-item"
|
||||||
|
v-if="layerState.currentType === geoType.Point"
|
||||||
|
>
|
||||||
|
<span class="title">Longitude:</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="layerState.longitude"
|
||||||
|
style="width:120px"
|
||||||
|
placeholder="longitude"
|
||||||
|
@change="changeLayer"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="latitude element-item"
|
||||||
|
v-if="layerState.currentType === geoType.Point"
|
||||||
|
>
|
||||||
|
<span class="title">Latitude:</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="layerState.latitude"
|
||||||
|
style="width:120px"
|
||||||
|
placeholder="latitude"
|
||||||
|
@change="changeLayer"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="color-content">
|
||||||
|
<span class="mr30">Color: </span>
|
||||||
|
<div
|
||||||
|
v-for="item in colors"
|
||||||
|
:key="item.id"
|
||||||
|
class="color-item"
|
||||||
|
:style="'background:' + item.color"
|
||||||
|
@click="changeColor(item)"
|
||||||
|
>
|
||||||
|
<svg-icon
|
||||||
|
v-if="item.color === layerState.color"
|
||||||
|
:size="18"
|
||||||
|
name="check"
|
||||||
|
></svg-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-row flex-justify-around flex-align-center mt20">
|
||||||
|
<a-button type="primary" @click="deleteElement">Delete</a-button>
|
||||||
|
</div>
|
||||||
|
</a-drawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, reactive, ref, watch } from 'vue'
|
||||||
|
import {
|
||||||
|
deleteElementReq,
|
||||||
|
getElementGroupsReq,
|
||||||
|
updateElementsReq
|
||||||
|
} from '/@/api/layer'
|
||||||
|
import LayersTree from '/@/components/LayersTree.vue'
|
||||||
|
import { MapDoodleColor, MapElementEnum } from '/@/constants/map'
|
||||||
|
import { useGMapCover } from '/@/hooks/use-g-map-cover'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
import { useMyStore } from '/@/store'
|
||||||
|
import { GeojsonCoordinate, LayerResource } from '/@/types/map'
|
||||||
|
import { Color, GeoType } from '/@/types/mapLayer'
|
||||||
|
import { generatePoint } from '/@/utils/genjson'
|
||||||
|
import { gcj02towgs84, wgs84togcj02 } from '/@/vendors/coordtransform'
|
||||||
|
|
||||||
|
const root = getRoot()
|
||||||
|
const store = useMyStore()
|
||||||
|
let useGMapCoverHook = useGMapCover(store)
|
||||||
|
console.log('store', store)
|
||||||
|
const mapLayers = ref(store.state.Layers)
|
||||||
|
const checkedKeys = ref<string[]>([])
|
||||||
|
const selectedKeys = ref<string[]>([])
|
||||||
|
const selectedKey = ref<string>('')
|
||||||
|
const selectedLayer = ref<any>(null)
|
||||||
|
const visible = ref<boolean>(false)
|
||||||
|
store.commit('SET_DRAW_VISIBLE_INFO', visible.value)
|
||||||
|
const geoType = GeoType
|
||||||
|
const layerState = reactive({
|
||||||
|
layerName: '',
|
||||||
|
layerId: '',
|
||||||
|
longitude: 0,
|
||||||
|
latitude: 0,
|
||||||
|
currentType: '', // “LineString”,"Polygon","Point"
|
||||||
|
color: '#212121'
|
||||||
|
})
|
||||||
|
const colors = ref<Color[]>([
|
||||||
|
{ id: 1, name: 'BLUE', color: '#2D8CF0', selected: true },
|
||||||
|
{ id: 2, name: 'GREEN', color: '#19BE6B', selected: false },
|
||||||
|
{ id: 3, name: 'YELLOW', color: '#FFBB00', selected: false },
|
||||||
|
{ id: 4, name: 'ORANGE', color: '#B620E0', selected: false },
|
||||||
|
{ id: 5, name: 'RED', color: '#E23C39', selected: false },
|
||||||
|
{ id: 6, name: 'NAME_DEFAULT', color: '#212121', selected: false }
|
||||||
|
])
|
||||||
|
|
||||||
|
async function getAllElement () {
|
||||||
|
getElementGroups('init')
|
||||||
|
setTimeout(() => {
|
||||||
|
useGMapCoverHook = useGMapCover()
|
||||||
|
initMapCover()
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
function initMapCover () {
|
||||||
|
mapLayers.value.forEach(item => {
|
||||||
|
if (item.elements) {
|
||||||
|
setMapCoverByElement(item.elements)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => store.state.Layers,
|
||||||
|
newData => {
|
||||||
|
mapLayers.value = newData
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
function setMapCoverByElement (elements: LayerResource[]) {
|
||||||
|
elements.forEach(element => {
|
||||||
|
const name = element.name
|
||||||
|
const color = element.resource?.content.properties.color
|
||||||
|
const type = element.resource?.type as number
|
||||||
|
updateMapElement(element, name, color)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function updateMapElement (
|
||||||
|
element: LayerResource,
|
||||||
|
name: string,
|
||||||
|
color: string | undefined
|
||||||
|
) {
|
||||||
|
const geoType = element.resource?.content.geometry.type
|
||||||
|
const id = element.id
|
||||||
|
const type = element.resource?.type as number
|
||||||
|
|
||||||
|
if (MapElementEnum.PIN === type) {
|
||||||
|
const coordinates = element.resource?.content.geometry
|
||||||
|
.coordinates as GeojsonCoordinate
|
||||||
|
useGMapCoverHook.updatePinElement(id, name, coordinates, color)
|
||||||
|
} else if (MapElementEnum.LINE === type && geoType === 'LineString') {
|
||||||
|
const coordinates = element.resource?.content.geometry
|
||||||
|
.coordinates as GeojsonCoordinate[]
|
||||||
|
useGMapCoverHook.initPolyline(name, coordinates, color, {
|
||||||
|
id: id,
|
||||||
|
name: name
|
||||||
|
})
|
||||||
|
} else if (MapElementEnum.LINE === type && geoType === 'Polygon') {
|
||||||
|
const coordinates = element.resource?.content.geometry
|
||||||
|
.coordinates[0] as GeojsonCoordinate[]
|
||||||
|
useGMapCoverHook.initPolygon(name, coordinates, color, {
|
||||||
|
id: id,
|
||||||
|
name: name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function checkLayer (keys: string[]) {
|
||||||
|
console.log('checkLayer', keys, selectedKeys.value, checkedKeys.value)
|
||||||
|
}
|
||||||
|
function selectLayer (keys: string[], e) {
|
||||||
|
// console.log('selectLayer', e.node.eventKey, e.selected)
|
||||||
|
if (e.selected) {
|
||||||
|
selectedKey.value = e.node.eventKey
|
||||||
|
selectedLayer.value = getCurrentLayer(selectedKey.value)
|
||||||
|
setBaseInfo()
|
||||||
|
}
|
||||||
|
visible.value = e.selected
|
||||||
|
store.commit('SET_DRAW_VISIBLE_INFO', visible.value)
|
||||||
|
// store.dispatch('updateElement', { type: 'is_select', id: e.node.eventKey, bool: e.selected })
|
||||||
|
}
|
||||||
|
function getCurrentLayer (id: string) {
|
||||||
|
const Layers = store.state.Layers
|
||||||
|
const key = id.replaceAll('resource__', '')
|
||||||
|
// console.log('selectedKey.value', selectedKey.value)
|
||||||
|
let layer = null
|
||||||
|
const findCan = function (V) {
|
||||||
|
V.forEach(item => {
|
||||||
|
if (item.id === key) {
|
||||||
|
layer = item
|
||||||
|
}
|
||||||
|
if (item.elements) {
|
||||||
|
findCan(item.elements)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
findCan(Layers)
|
||||||
|
// const layer = Layers.find(item => item.elements.find(el => el.id === key))
|
||||||
|
console.log('layer', layer)
|
||||||
|
return layer
|
||||||
|
}
|
||||||
|
function setBaseInfo () {
|
||||||
|
const layer = selectedLayer.value
|
||||||
|
if (layer) {
|
||||||
|
const geoType = layer.resource?.content.geometry.type
|
||||||
|
// “LineString”,"Polygon","Point"
|
||||||
|
layerState.currentType = geoType
|
||||||
|
layerState.layerName = layer.name
|
||||||
|
layerState.layerId = layer.id
|
||||||
|
layerState.color = layer.resource?.content.properties.color
|
||||||
|
switch (geoType) {
|
||||||
|
case GeoType.Point:
|
||||||
|
layerState.longitude = layer.resource?.content.geometry.coordinates[0]
|
||||||
|
layerState.latitude = layer.resource?.content.geometry.coordinates[1]
|
||||||
|
break
|
||||||
|
case GeoType.LineString:
|
||||||
|
break
|
||||||
|
case GeoType.Polygon:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
getAllElement()
|
||||||
|
})
|
||||||
|
function closeDrawer () {
|
||||||
|
store.commit('SET_DRAW_VISIBLE_INFO', false)
|
||||||
|
selectedKeys.value = []
|
||||||
|
}
|
||||||
|
function changeColor (color: Color) {
|
||||||
|
layerState.color = color.color
|
||||||
|
|
||||||
|
updateElements()
|
||||||
|
}
|
||||||
|
function changeLayer (val: string) {
|
||||||
|
updateElements()
|
||||||
|
}
|
||||||
|
async function deleteElement () {
|
||||||
|
const elementid = selectedLayer.value.id
|
||||||
|
|
||||||
|
await deleteElementReq(elementid, {}).then(async (res: any) => {
|
||||||
|
// console.log('delete element res:', res)
|
||||||
|
if (res.code !== 0) {
|
||||||
|
console.warn(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
visible.value = false
|
||||||
|
store.commit('SET_DRAW_VISIBLE_INFO', visible.value)
|
||||||
|
useGMapCoverHook.removeCoverFromMap(elementid)
|
||||||
|
getElementGroups()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
async function getElementGroups (type?: string) {
|
||||||
|
const result = await getElementGroupsReq({
|
||||||
|
groupId: '',
|
||||||
|
isDistributed: true
|
||||||
|
})
|
||||||
|
mapLayers.value = result.data
|
||||||
|
mapLayers.value = updateWgs84togcj02()
|
||||||
|
if (type && type === 'init') {
|
||||||
|
store.dispatch('setLayerInfo', mapLayers.value)
|
||||||
|
}
|
||||||
|
store.commit('SET_LAYER_INFO', mapLayers.value)
|
||||||
|
}
|
||||||
|
async function updateElements () {
|
||||||
|
let content = null
|
||||||
|
if (layerState.currentType === GeoType.Point) {
|
||||||
|
const position = {
|
||||||
|
height: 0,
|
||||||
|
latitude: Number(layerState.latitude || 0),
|
||||||
|
longitude: Number(layerState.longitude || 0)
|
||||||
|
}
|
||||||
|
const cxt = generatePoint(position, {
|
||||||
|
color: layerState.color || MapDoodleColor.PinColor,
|
||||||
|
clampToGround: true
|
||||||
|
})
|
||||||
|
content = {
|
||||||
|
type: MapElementEnum.PIN,
|
||||||
|
geometry: cxt.geometry,
|
||||||
|
properties: cxt.properties
|
||||||
|
}
|
||||||
|
const currentLayer = selectedLayer.value
|
||||||
|
currentLayer.resource.content = content
|
||||||
|
selectedLayer.value = currentLayer
|
||||||
|
} else {
|
||||||
|
const currentLayer = selectedLayer.value
|
||||||
|
content = currentLayer.resource.content
|
||||||
|
content.properties.color = layerState.color
|
||||||
|
}
|
||||||
|
updateMapElement(selectedLayer.value, layerState.layerName, layerState.color)
|
||||||
|
const result = await updateElementsReq(layerState.layerId, {
|
||||||
|
name: layerState.layerName,
|
||||||
|
content: content
|
||||||
|
})
|
||||||
|
getElementGroups()
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateWgs84togcj02 () {
|
||||||
|
const layers = mapLayers.value
|
||||||
|
layers.forEach(item => {
|
||||||
|
if (item.elements) {
|
||||||
|
item.elements.forEach(ele => {
|
||||||
|
updateCoordinates('wgs84-gcj02', ele)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return layers
|
||||||
|
}
|
||||||
|
function updateCoordinates (transformType: string, element: LayerResource) {
|
||||||
|
const geoType = element.resource?.content.geometry.type
|
||||||
|
const type = element.resource?.type as number
|
||||||
|
if (element.resource) {
|
||||||
|
if (MapElementEnum.PIN === type) {
|
||||||
|
const coordinates = element.resource?.content.geometry
|
||||||
|
.coordinates as GeojsonCoordinate
|
||||||
|
if (transformType === 'wgs84-gcj02') {
|
||||||
|
const transResult = wgs84togcj02(
|
||||||
|
coordinates[0],
|
||||||
|
coordinates[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
element.resource.content.geometry.coordinates = transResult
|
||||||
|
} else if (transformType === 'gcj02-wgs84') {
|
||||||
|
const transResult = gcj02towgs84(
|
||||||
|
coordinates[0],
|
||||||
|
coordinates[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
element.resource.content.geometry.coordinates = transResult
|
||||||
|
}
|
||||||
|
} else if (MapElementEnum.LINE === type && geoType === 'LineString') {
|
||||||
|
const coordinates = element.resource?.content.geometry
|
||||||
|
.coordinates as GeojsonCoordinate[]
|
||||||
|
if (transformType === 'wgs84-gcj02') {
|
||||||
|
coordinates.forEach(coordinate => {
|
||||||
|
coordinate = wgs84togcj02(
|
||||||
|
coordinate[0],
|
||||||
|
coordinate[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
})
|
||||||
|
} else if (transformType === 'gcj02-wgs84') {
|
||||||
|
coordinates.forEach(coordinate => {
|
||||||
|
coordinate = gcj02towgs84(
|
||||||
|
coordinate[0],
|
||||||
|
coordinate[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
})
|
||||||
|
}
|
||||||
|
element.resource.content.geometry.coordinates = coordinates
|
||||||
|
} else if (MapElementEnum.LINE === type && geoType === 'Polygon') {
|
||||||
|
const coordinates = element.resource?.content.geometry
|
||||||
|
.coordinates[0] as GeojsonCoordinate[]
|
||||||
|
|
||||||
|
if (transformType === 'wgs84-gcj02') {
|
||||||
|
coordinates.forEach(coordinate => {
|
||||||
|
coordinate = wgs84togcj02(
|
||||||
|
coordinate[0],
|
||||||
|
coordinate[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
})
|
||||||
|
} else if (transformType === 'gcj02-wgs84') {
|
||||||
|
coordinates.forEach(coordinate => {
|
||||||
|
coordinate = gcj02towgs84(
|
||||||
|
coordinate[0],
|
||||||
|
coordinate[1]
|
||||||
|
) as GeojsonCoordinate
|
||||||
|
})
|
||||||
|
}
|
||||||
|
element.resource.content.geometry.coordinates = [coordinates]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '/@/styles/index.scss';
|
||||||
|
.project-layer-wrapper {
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss">
|
||||||
|
.drawer-element-wrapper {
|
||||||
|
.ant-drawer-content {
|
||||||
|
background-color: $dark-highlight;
|
||||||
|
color: $text-white-basic;
|
||||||
|
.ant-drawer-header {
|
||||||
|
background-color: $dark-highlight;
|
||||||
|
.ant-drawer-title {
|
||||||
|
color: $text-white-basic;
|
||||||
|
}
|
||||||
|
.ant-drawer-close {
|
||||||
|
color: $text-white-basic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-input {
|
||||||
|
background-color: #101010;
|
||||||
|
border-color: $dark-border;
|
||||||
|
color: $text-white-basic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.color-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 8px;
|
||||||
|
.color-item {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
display: inline-flex;
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
.element-item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,327 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex-column flex-justify-start flex-align-center">
|
||||||
|
<p class="fz24">Live streaming source selection</p>
|
||||||
|
<div class="flex-row flex-justify-center flex-align-center mt10">
|
||||||
|
<a-select
|
||||||
|
style="width:150px"
|
||||||
|
placeholder="Select Drone"
|
||||||
|
@select="onDroneSelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in dronePara.droneList"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>{{ item.label }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
<a-select
|
||||||
|
class="ml10"
|
||||||
|
style="width:150px"
|
||||||
|
placeholder="Select Camera"
|
||||||
|
@select="onCameraSelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in dronePara.cameraList"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>{{ item.label }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
<a-select
|
||||||
|
class="ml10"
|
||||||
|
style="width:150px"
|
||||||
|
placeholder="Select Lens"
|
||||||
|
@select="onVideoSelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
class="ml10"
|
||||||
|
v-for="item in dronePara.videoList"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>{{ item.label }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
<a-select
|
||||||
|
class="ml10"
|
||||||
|
style="width:150px"
|
||||||
|
placeholder="Select Clarity"
|
||||||
|
@select="onClaritySelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in clarityList"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>{{ item.label }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
<p class="fz24 mt10">Agora Parameter</p>
|
||||||
|
<p class="fz16">
|
||||||
|
Note: Obtain The Following Parameters From https://console.agora.io
|
||||||
|
</p>
|
||||||
|
<div class="flex-row flex-justify-center flex-align-center">
|
||||||
|
<a-input v-model:value="agoraPara.appid" placeholder="APP ID"></a-input>
|
||||||
|
<a-input
|
||||||
|
class="ml10"
|
||||||
|
v-model:value="agoraPara.token"
|
||||||
|
placeholder="Token"
|
||||||
|
></a-input>
|
||||||
|
<a-input
|
||||||
|
class="ml10"
|
||||||
|
v-model:value="agoraPara.channel"
|
||||||
|
placeholder="Channel"
|
||||||
|
></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="mt20">
|
||||||
|
<p class="fz20">
|
||||||
|
Livestate:{{ livePara.liveState == false ? 'Stop' : 'Playing' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="mt10 flex-row flex-justify-center flex-align-center">
|
||||||
|
<a-button type="primary" large @click="onStart">Play</a-button>
|
||||||
|
<a-button class="ml20" type="primary" large @click="onStop"
|
||||||
|
>Stop</a-button
|
||||||
|
>
|
||||||
|
<a-button class="ml20" type="primary" large @click="onRefresh"
|
||||||
|
>Refresh Live Capacity</a-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div id="player"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import AgoraRTC from 'agora-rtc-sdk-ng'
|
||||||
|
import { onMounted, reactive } from 'vue'
|
||||||
|
import { CURRENT_CONFIG as config } from '/@/api/http/config'
|
||||||
|
import { getLiveCapacity, startLivestream, stopLivestream } from '/@/api/manage'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
|
||||||
|
const root = getRoot()
|
||||||
|
|
||||||
|
const clarityList = [
|
||||||
|
{
|
||||||
|
value: 0,
|
||||||
|
label: 'Adaptive'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
label: 'Smooth'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 2,
|
||||||
|
label: 'Standard'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 3,
|
||||||
|
label: 'HD'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 4,
|
||||||
|
label: 'Super Clear'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
let agoraClient = {} as any
|
||||||
|
const agoraPara = reactive({
|
||||||
|
appid: config.agoraAPPID,
|
||||||
|
token: config.agoraToken,
|
||||||
|
channel: config.agoraChannel,
|
||||||
|
uid: null,
|
||||||
|
stream: {}
|
||||||
|
})
|
||||||
|
const dronePara = reactive({
|
||||||
|
livestreamSource: [],
|
||||||
|
droneList: [],
|
||||||
|
cameraList: [],
|
||||||
|
videoList: [],
|
||||||
|
droneSelected: '',
|
||||||
|
cameraSelected: '',
|
||||||
|
videoSelected: '',
|
||||||
|
claritySelected: ''
|
||||||
|
})
|
||||||
|
const livePara = reactive({
|
||||||
|
url: '',
|
||||||
|
webrtc: {} as any,
|
||||||
|
videoId: '',
|
||||||
|
liveState: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const onRefresh = async () => {
|
||||||
|
await getLiveCapacity({})
|
||||||
|
.then(res => {
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 0) {
|
||||||
|
if (res.data === null) {
|
||||||
|
console.warn('warning: get live capacity is null!!!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dronePara.livestreamSource = res.data
|
||||||
|
dronePara.droneList = []
|
||||||
|
|
||||||
|
console.log('live_capacity:', dronePara.livestreamSource)
|
||||||
|
|
||||||
|
if (dronePara.livestreamSource) {
|
||||||
|
dronePara.livestreamSource.forEach((ele: any) => {
|
||||||
|
dronePara.droneList.push({ label: ele.sn, value: ele.sn })
|
||||||
|
})
|
||||||
|
console.log(dronePara.droneList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
onRefresh()
|
||||||
|
agoraClient = AgoraRTC.createClient({ mode: 'live', codec: 'h264' })
|
||||||
|
agoraClient.setClientRole('audience')
|
||||||
|
|
||||||
|
// Subscribe when a remote user publishes a stream
|
||||||
|
agoraClient.on('user-published', async (user: any, mediaType: string) => {
|
||||||
|
await agoraClient.subscribe(user, mediaType)
|
||||||
|
if (mediaType === 'video') {
|
||||||
|
console.log('subscribe success')
|
||||||
|
// Get `RemoteVideoTrack` in the `user` object.
|
||||||
|
const remoteVideoTrack = user.videoTrack
|
||||||
|
// Dynamically create a container in the form of a DIV element for playing the remote video track.
|
||||||
|
const remotePlayerContainer: any = document.getElementById('player')
|
||||||
|
// Specify the ID of the DIV container. You can use the `uid` of the remote user.
|
||||||
|
remotePlayerContainer.id = agoraPara.uid
|
||||||
|
remotePlayerContainer.textContent = 'uid: ' + agoraPara.uid
|
||||||
|
remotePlayerContainer.style.width = '640px'
|
||||||
|
remotePlayerContainer.style.height = '480px'
|
||||||
|
remoteVideoTrack.play(remotePlayerContainer)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
agoraClient.on('user-unpublished', async (user: any) => {
|
||||||
|
console.log('unpublish live:', user)
|
||||||
|
await agoraClient.leave()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleError = (err: any) => {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
const handleJoinChannel = (uid: any) => {
|
||||||
|
agoraPara.uid = uid
|
||||||
|
}
|
||||||
|
|
||||||
|
const onStart = async () => {
|
||||||
|
const that = this
|
||||||
|
console.log(
|
||||||
|
'drone parameter:',
|
||||||
|
dronePara.droneSelected,
|
||||||
|
dronePara.cameraSelected,
|
||||||
|
dronePara.videoSelected,
|
||||||
|
dronePara.claritySelected
|
||||||
|
)
|
||||||
|
const timestamp = new Date().getTime().toString()
|
||||||
|
const liveTimestamp = timestamp
|
||||||
|
if (
|
||||||
|
dronePara.droneSelected == null ||
|
||||||
|
dronePara.cameraSelected == null ||
|
||||||
|
dronePara.videoSelected == null ||
|
||||||
|
dronePara.claritySelected == null
|
||||||
|
) {
|
||||||
|
console.warn('waring: not select live para!!!')
|
||||||
|
}
|
||||||
|
livePara.videoId =
|
||||||
|
dronePara.droneSelected +
|
||||||
|
'/' +
|
||||||
|
dronePara.cameraSelected +
|
||||||
|
'/' +
|
||||||
|
dronePara.videoSelected
|
||||||
|
console.log(agoraPara)
|
||||||
|
await agoraClient
|
||||||
|
.join(agoraPara.appid, agoraPara.channel, agoraPara.token, null)
|
||||||
|
.then((res: any) => {
|
||||||
|
console.log('agora uid:', res)
|
||||||
|
agoraPara.uid = res
|
||||||
|
})
|
||||||
|
console.log(agoraPara.token)
|
||||||
|
agoraPara.token = encodeURIComponent(agoraPara.token)
|
||||||
|
console.log('agoraToken:', agoraPara.token)
|
||||||
|
livePara.url =
|
||||||
|
'channel=' +
|
||||||
|
agoraPara.channel +
|
||||||
|
'&sn=' +
|
||||||
|
dronePara.droneSelected +
|
||||||
|
'&token=' +
|
||||||
|
agoraPara.token +
|
||||||
|
'&uid=' +
|
||||||
|
agoraPara.uid
|
||||||
|
|
||||||
|
await startLivestream({
|
||||||
|
url: livePara.url,
|
||||||
|
video_id: livePara.videoId,
|
||||||
|
url_type: 0,
|
||||||
|
video_quality: dronePara.claritySelected
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
livePara.liveState = true
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onStop = async () => {
|
||||||
|
stopLivestream({
|
||||||
|
video_id: livePara.videoId
|
||||||
|
}).then(res => {
|
||||||
|
livePara.liveState = false
|
||||||
|
console.log('stop play livestream')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onDroneSelect = (val: any) => {
|
||||||
|
dronePara.droneSelected = val
|
||||||
|
if (dronePara.droneSelected) {
|
||||||
|
const droneTemp = dronePara.livestreamSource
|
||||||
|
droneTemp.forEach(ele => {
|
||||||
|
const drone = ele
|
||||||
|
if (drone.sn === dronePara.droneSelected) {
|
||||||
|
const cameraListTemp = drone.cameras_list
|
||||||
|
dronePara.cameraList = []
|
||||||
|
cameraListTemp.forEach((ele: any) => {
|
||||||
|
dronePara.cameraList.push({ label: ele.name, value: ele.index })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onCameraSelect = (val: any) => {
|
||||||
|
dronePara.cameraSelected = val
|
||||||
|
|
||||||
|
if (dronePara.cameraSelected) {
|
||||||
|
const droneTemp = dronePara.livestreamSource
|
||||||
|
droneTemp.forEach(ele => {
|
||||||
|
const drone = ele
|
||||||
|
if (drone.sn === dronePara.droneSelected) {
|
||||||
|
const cameraListTemp = drone.cameras_list
|
||||||
|
cameraListTemp.forEach((ele: any) => {
|
||||||
|
const camera = ele
|
||||||
|
if (camera.index === dronePara.cameraSelected) {
|
||||||
|
const videoListTemp = camera.videos_list
|
||||||
|
dronePara.videoList = []
|
||||||
|
videoListTemp.forEach((ele: any) => {
|
||||||
|
dronePara.videoList.push({ label: ele.type, value: ele.index })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onVideoSelect = (val: any) => {
|
||||||
|
dronePara.videoSelected = val
|
||||||
|
}
|
||||||
|
const onClaritySelect = (val: any) => {
|
||||||
|
dronePara.claritySelected = val
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '/@/styles/index.scss';
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,351 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex-column flex-justify-start flex-align-center">
|
||||||
|
<video
|
||||||
|
:style="{ width: '720px', height: '480px' }"
|
||||||
|
id="video-webrtc"
|
||||||
|
ref="videowebrtc"
|
||||||
|
controls
|
||||||
|
class="mt20"
|
||||||
|
></video>
|
||||||
|
<p class="fz24">Live streaming source selection</p>
|
||||||
|
<div class="flex-row flex-justify-center flex-align-center mt10">
|
||||||
|
<a-select
|
||||||
|
style="width: 150px"
|
||||||
|
placeholder="Select Live Type"
|
||||||
|
@select="onLiveTypeSelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in liveTypeList"
|
||||||
|
:key="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<a-select
|
||||||
|
class="ml10"
|
||||||
|
style="width:150px"
|
||||||
|
placeholder="Select Drone"
|
||||||
|
@select="onDroneSelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in droneList"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>{{ item.label }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
<a-select
|
||||||
|
class="ml10"
|
||||||
|
style="width:150px"
|
||||||
|
placeholder="Select Camera"
|
||||||
|
@select="onCameraSelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in cameraList"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>{{ item.label }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
<a-select
|
||||||
|
class="ml10"
|
||||||
|
style="width:150px"
|
||||||
|
placeholder="Select Lens"
|
||||||
|
@select="onVideoSelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
class="ml10"
|
||||||
|
v-for="item in videoList"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>{{ item.label }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
<a-select
|
||||||
|
class="ml10"
|
||||||
|
style="width:150px"
|
||||||
|
placeholder="Select Clarity"
|
||||||
|
@select="onClaritySelect"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in clarityList"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>{{ item.label }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
<div class="mt20">
|
||||||
|
<p class="fz20">Livestate:{{ liveState == 0 ? 'Stop' : 'Playing' }}</p>
|
||||||
|
<p class="fz10" v-if="livetypeSelected == 2">
|
||||||
|
Please use VLC media player to play the RTSP livestream !!!
|
||||||
|
</p>
|
||||||
|
<p class="fz10" v-if="livetypeSelected == 2">
|
||||||
|
RTSP Parameter:{{ rtspData }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="mt10 flex-row flex-justify-center flex-align-center">
|
||||||
|
<a-button type="primary" large @click="onStart">Play</a-button>
|
||||||
|
<a-button class="ml20" type="primary" large @click="onStop"
|
||||||
|
>Stop</a-button
|
||||||
|
>
|
||||||
|
<a-button class="ml20" type="primary" large @click="onRefresh"
|
||||||
|
>Refresh Live Capacity</a-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { CURRENT_CONFIG as config } from '/@/api/http/config'
|
||||||
|
import { getLiveCapacity, startLivestream, stopLivestream } from '/@/api/manage'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
import jswebrtc from '/@/vendors/jswebrtc.min.js'
|
||||||
|
const root = getRoot()
|
||||||
|
|
||||||
|
const liveTypeList = [
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
label: 'RTMP'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 2,
|
||||||
|
label: 'RTSP'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 3,
|
||||||
|
label: 'GB28181'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const clarityList = [
|
||||||
|
{
|
||||||
|
value: 0,
|
||||||
|
label: 'Adaptive'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
label: 'Smooth'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 2,
|
||||||
|
label: 'Standard'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 3,
|
||||||
|
label: 'HD'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 4,
|
||||||
|
label: 'Super Clear'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const videowebrtc = ref(null)
|
||||||
|
const livestreamSource = ref()
|
||||||
|
const droneList = ref()
|
||||||
|
const cameraList = ref()
|
||||||
|
const videoList = ref()
|
||||||
|
const droneSelected = ref()
|
||||||
|
const cameraSelected = ref()
|
||||||
|
const videoSeleted = ref()
|
||||||
|
const claritySeleted = ref()
|
||||||
|
const videoId = ref()
|
||||||
|
const liveState = ref(0)
|
||||||
|
const livetypeSelected = ref()
|
||||||
|
const rtspData = ref()
|
||||||
|
|
||||||
|
const onRefresh = async () => {
|
||||||
|
await getLiveCapacity({})
|
||||||
|
.then(res => {
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 0) {
|
||||||
|
if (res.data === null) {
|
||||||
|
console.warn('warning: get live capacity is null!!!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const resData: Array<[]> = res.data
|
||||||
|
console.log('live_capacity:', resData)
|
||||||
|
livestreamSource.value = resData
|
||||||
|
console.log(livestreamSource)
|
||||||
|
|
||||||
|
const temp: Array<{}> = []
|
||||||
|
if (livestreamSource.value) {
|
||||||
|
livestreamSource.value.forEach(ele => {
|
||||||
|
temp.push({ label: ele.sn, value: ele.sn })
|
||||||
|
})
|
||||||
|
console.log(temp)
|
||||||
|
droneList.value = temp
|
||||||
|
console.log(droneList.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
onRefresh()
|
||||||
|
})
|
||||||
|
const onStart = async () => {
|
||||||
|
const that = this
|
||||||
|
console.log(
|
||||||
|
'直播参数:',
|
||||||
|
livetypeSelected.value,
|
||||||
|
droneSelected.value,
|
||||||
|
cameraSelected.value,
|
||||||
|
videoSeleted.value,
|
||||||
|
claritySeleted.value
|
||||||
|
)
|
||||||
|
const timestamp = new Date().getTime().toString()
|
||||||
|
const liveTimestamp = timestamp
|
||||||
|
if (
|
||||||
|
livetypeSelected.value == null ||
|
||||||
|
droneSelected.value == null ||
|
||||||
|
cameraSelected.value == null ||
|
||||||
|
videoSeleted.value == null ||
|
||||||
|
claritySeleted.value == null
|
||||||
|
) {
|
||||||
|
console.warn('waring: not select live para!!!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
videoId.value =
|
||||||
|
droneSelected.value + '/' + cameraSelected.value + '/' + videoSeleted.value
|
||||||
|
let liveURL = ''
|
||||||
|
switch (livetypeSelected.value) {
|
||||||
|
case 1: {
|
||||||
|
// RTMP
|
||||||
|
liveURL = config.rtmpURL + timestamp
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
// RTSP
|
||||||
|
liveURL = config.rtspPara
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
// GB28181
|
||||||
|
liveURL = config.gb28181Para
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
console.warn('warning: live type is not correct!!!')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
await startLivestream({
|
||||||
|
url: liveURL,
|
||||||
|
video_id: videoId.value,
|
||||||
|
url_type: livetypeSelected.value,
|
||||||
|
video_quality: claritySeleted.value
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (livetypeSelected.value === 3) {
|
||||||
|
const url = res.data.url
|
||||||
|
const videoElement = videowebrtc.value
|
||||||
|
// gb28181,it will fail if not wait.
|
||||||
|
message.loading({
|
||||||
|
content: '直播等待中。。。',
|
||||||
|
duration: 4,
|
||||||
|
onClose () {
|
||||||
|
const player = new jswebrtc.Player(url, {
|
||||||
|
video: videoElement,
|
||||||
|
autoplay: true,
|
||||||
|
onPlay: obj => {
|
||||||
|
console.log('start play livestream')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
liveState.value = 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (livetypeSelected.value === 2) {
|
||||||
|
console.log(res)
|
||||||
|
rtspData.value =
|
||||||
|
'url:' +
|
||||||
|
res.data.url +
|
||||||
|
'&username:' +
|
||||||
|
res.data.username +
|
||||||
|
'&password:' +
|
||||||
|
res.data.password
|
||||||
|
} else if (livetypeSelected.value === 1) {
|
||||||
|
const url = res.data.url
|
||||||
|
const videoElement = videowebrtc.value
|
||||||
|
console.log('start live:', url)
|
||||||
|
const player = new jswebrtc.Player(url, {
|
||||||
|
video: videoElement,
|
||||||
|
autoplay: true,
|
||||||
|
onPlay: obj => {
|
||||||
|
console.log('start play livestream')
|
||||||
|
liveState.value = 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onStop = () => {
|
||||||
|
stopLivestream({
|
||||||
|
video_id: videoId.value
|
||||||
|
}).then(res => {
|
||||||
|
liveState.value = 0
|
||||||
|
console.log('stop play livestream')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onLiveTypeSelect = (val: any) => {
|
||||||
|
livetypeSelected.value = val
|
||||||
|
}
|
||||||
|
const onDroneSelect = (val: any) => {
|
||||||
|
droneSelected.value = val
|
||||||
|
const temp: Array<{}> = []
|
||||||
|
if (droneSelected.value) {
|
||||||
|
const droneTemp = livestreamSource.value
|
||||||
|
droneTemp.forEach(ele => {
|
||||||
|
const drone = ele
|
||||||
|
if (drone.sn === droneSelected.value) {
|
||||||
|
const cameraListTemp = drone.cameras_list
|
||||||
|
cameraListTemp.forEach(ele => {
|
||||||
|
temp.push({ label: ele.name, value: ele.index })
|
||||||
|
})
|
||||||
|
cameraList.value = temp
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onCameraSelect = (val: any) => {
|
||||||
|
cameraSelected.value = val
|
||||||
|
const result: Array<{}> = []
|
||||||
|
if (cameraSelected.value) {
|
||||||
|
const droneTemp = livestreamSource.value
|
||||||
|
droneTemp.forEach(ele => {
|
||||||
|
const drone = ele
|
||||||
|
if (drone.sn === droneSelected.value) {
|
||||||
|
const cameraListTemp = drone.cameras_list
|
||||||
|
cameraListTemp.forEach(ele => {
|
||||||
|
const camera = ele
|
||||||
|
if (camera.index === cameraSelected.value) {
|
||||||
|
const videoListTemp = camera.videos_list
|
||||||
|
videoListTemp.forEach(ele => {
|
||||||
|
result.push({ label: ele.type, value: ele.index })
|
||||||
|
})
|
||||||
|
videoList.value = result
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onVideoSelect = (val: any) => {
|
||||||
|
videoSeleted.value = val
|
||||||
|
}
|
||||||
|
const onClaritySelect = (val: any) => {
|
||||||
|
claritySeleted.value = val
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '/@/styles/index.scss';
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex-column flex-justify-start flex-align-center">
|
||||||
|
<a-button
|
||||||
|
class="mt10 "
|
||||||
|
style="width:90%"
|
||||||
|
type="primary"
|
||||||
|
@click="onAgoraLiveStream"
|
||||||
|
>Agora Live</a-button
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
class="mt10"
|
||||||
|
style="width:90%"
|
||||||
|
type="primary"
|
||||||
|
@click="onOthersLive"
|
||||||
|
>RTMP/GB28181 Live</a-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div v-if="enableAgoraLive">
|
||||||
|
<a-modal
|
||||||
|
style="top:0"
|
||||||
|
v-model:visible="enableAgoraLive"
|
||||||
|
title="Agora Live"
|
||||||
|
width="100%"
|
||||||
|
:maskClosable="false"
|
||||||
|
wrapClassName="full-modal"
|
||||||
|
:footer="null"
|
||||||
|
>
|
||||||
|
<LiveAgora />
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
<div v-if="enableOthersLive">
|
||||||
|
<a-modal
|
||||||
|
style="top:0"
|
||||||
|
v-model:visible="enableOthersLive"
|
||||||
|
title="RTMP/GB28181/RTSP Live"
|
||||||
|
width="100%"
|
||||||
|
:maskClosable="false"
|
||||||
|
wrapClassName="full-modal"
|
||||||
|
:footer="null"
|
||||||
|
>
|
||||||
|
<LiveOthers />
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import LiveAgora from './livestream-agora.vue'
|
||||||
|
import LiveOthers from './livestream-others.vue'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
const root = getRoot()
|
||||||
|
|
||||||
|
const enableAgoraLive = ref(false)
|
||||||
|
const enableOthersLive = ref(false)
|
||||||
|
const onAgoraLiveStream = () => {
|
||||||
|
console.log('agora')
|
||||||
|
enableAgoraLive.value = true
|
||||||
|
}
|
||||||
|
const onOthersLive = () => {
|
||||||
|
console.log('liveview')
|
||||||
|
enableOthersLive.value = true
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.full-modal {
|
||||||
|
.ant-modal {
|
||||||
|
max-width: 100%;
|
||||||
|
top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.ant-modal-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: calc(100vh);
|
||||||
|
}
|
||||||
|
.ant-modal-body {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<div class="project-media-wrapper">
|
||||||
|
Media
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<div class="project-tsa-wrapper">
|
||||||
|
TSA
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="project-wayline-wrapper">
|
||||||
|
wayline
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup></script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-project-sidebar-wrapper">
|
||||||
|
<router-link
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.key"
|
||||||
|
:to="item.path"
|
||||||
|
:class="{
|
||||||
|
'menu-item': true,
|
||||||
|
selected: selectedRoute(item),
|
||||||
|
disabled: item.key > 6
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<a-tooltip :title="item.label" placement="right">
|
||||||
|
<span>{{ item.label }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { getRoot } from '/@/root'
|
||||||
|
interface IOptions {
|
||||||
|
key: number
|
||||||
|
label: string
|
||||||
|
path:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
path: string
|
||||||
|
query?: any
|
||||||
|
}
|
||||||
|
icon: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Sidebar',
|
||||||
|
setup () {
|
||||||
|
const root = getRoot()
|
||||||
|
const options = [
|
||||||
|
{ key: 0, label: 'livestream', path: '/livestream', icon: 'livestream' },
|
||||||
|
{ key: 1, label: 'tsa', path: '/tsa', icon: 'tsa' },
|
||||||
|
{ key: 2, label: 'layer', path: '/layer', icon: 'layer' },
|
||||||
|
{ key: 3, label: 'media', path: '/media', icon: 'media' },
|
||||||
|
{ key: 4, label: 'wayline', path: '/wayline', icon: 'wayline' }
|
||||||
|
]
|
||||||
|
|
||||||
|
function selectedRoute (item: IOptions) {
|
||||||
|
const path = typeof item.path === 'string' ? item.path : item.path.path
|
||||||
|
return root.$route.path?.indexOf(path) === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
options,
|
||||||
|
selectedRoute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.demo-project-sidebar-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 80px;
|
||||||
|
border-right: 1px solid #4f4f4f;
|
||||||
|
color: $text-white-basic;
|
||||||
|
// flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
.menu-item {
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px 0px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: $text-white-basic;
|
||||||
|
cursor: pointer;
|
||||||
|
&.selected {
|
||||||
|
background-color: $dark-highlight;
|
||||||
|
color: $primary;
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filling {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
color: $text-white-basic;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
.ant-tooltip-open {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { readFileSync, readdirSync } from 'fs'
|
||||||
|
|
||||||
|
let idPerfix = ''
|
||||||
|
const svgTitle = /<svg([^>+].*?)>/
|
||||||
|
const clearHeightWidth = /(width|height)="([^>+].*?)"/g
|
||||||
|
const hasViewBox = /(viewBox="[^>+].*?")/g
|
||||||
|
const clearReturn = /(\r)|(\n)/g
|
||||||
|
|
||||||
|
// Find the svg file
|
||||||
|
function svgFind(e) {
|
||||||
|
const arr = []
|
||||||
|
const dirents = readdirSync(e, { withFileTypes: true })
|
||||||
|
for (const dirent of dirents) {
|
||||||
|
if (dirent.isDirectory()) arr.push(...svgFind(e + dirent.name + '/'))
|
||||||
|
else {
|
||||||
|
const svg = readFileSync(e + dirent.name)
|
||||||
|
.toString()
|
||||||
|
.replace(clearReturn, '')
|
||||||
|
.replace(svgTitle, ($1, $2) => {
|
||||||
|
let width = 0
|
||||||
|
let height = 0
|
||||||
|
let content = $2.replace(clearHeightWidth, (s1, s2, s3) => {
|
||||||
|
if (s2 === 'width') width = s3
|
||||||
|
else if (s2 === 'height') height = s3
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
if (!hasViewBox.test($2)) content += `viewBox="0 0 ${width} ${height}"`
|
||||||
|
return `<symbol id="${idPerfix}-${dirent.name.replace('.svg', '')}" ${content}>`
|
||||||
|
}).replace('</svg>', '</symbol>')
|
||||||
|
arr.push(svg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
export const svgBuilder = (path: any, perfix = 'icon') => {
|
||||||
|
if (path === '') return
|
||||||
|
idPerfix = perfix
|
||||||
|
const res = svgFind(path)
|
||||||
|
console.log(res)
|
||||||
|
return {
|
||||||
|
name: 'svg-transform',
|
||||||
|
transformIndexHtml (dom: String) {
|
||||||
|
return dom.replace(
|
||||||
|
'<body>',
|
||||||
|
`<body><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0" version="1.1">${res.join('')}</svg>`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { createApp, ComponentCustomProperties, App as VueApp } from 'vue'
|
||||||
|
declare module '@vue/runtime-core' {
|
||||||
|
interface ComponentCustomProperties {
|
||||||
|
$aMap: any
|
||||||
|
$aMapObj: any
|
||||||
|
$mouseTool: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let root: ComponentCustomProperties
|
||||||
|
let app = null as any
|
||||||
|
|
||||||
|
export function createInstance (App: any): VueApp {
|
||||||
|
app = createApp(App)
|
||||||
|
root = app.config.globalProperties as ComponentCustomProperties
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRoot (): ComponentCustomProperties {
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getApp (): VueApp {
|
||||||
|
return app
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
|
||||||
|
import { ERouterName } from '/@/types/index'
|
||||||
|
|
||||||
|
const routes: Array<RouteRecordRaw> = [
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.Project,
|
||||||
|
name: ERouterName.Project,
|
||||||
|
// redirect: {
|
||||||
|
// name: ERouterName.Project
|
||||||
|
// },
|
||||||
|
component: () => import('/@/pages/project-app/index.vue'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.Livestream,
|
||||||
|
component: () => import('/@/pages/project-app/projects/livestream.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.Tsa,
|
||||||
|
component: () => import('/@/pages/project-app/projects/tsa.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.Layer,
|
||||||
|
name: ERouterName.Layer,
|
||||||
|
component: () => import('/@/pages/project-app/projects/layer.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.Media,
|
||||||
|
name: ERouterName.Media,
|
||||||
|
component: () => import('/@/pages/project-app/projects/media.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.Wayline,
|
||||||
|
name: ERouterName.Wayline,
|
||||||
|
component: () => import('/@/pages/project-app/projects/wayline.vue')
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.Pilot,
|
||||||
|
name: ERouterName.Pilot,
|
||||||
|
component: () => import('/@/pages/page-pilot/pilot-index.vue'),
|
||||||
|
children: [
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.PilotHome,
|
||||||
|
component: () => import('/@/pages/page-pilot/pilot-home.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.PilotMedia,
|
||||||
|
component: () => import('/@/pages/page-pilot/pilot-media.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.PilotLiveshare,
|
||||||
|
component: () => import('/@/pages/page-pilot/pilot-liveshare.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/' + ERouterName.Element,
|
||||||
|
name: ERouterName.Element,
|
||||||
|
component: () => import('/@/pages/elements/elements.vue')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
routes
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
declare module '*.vue' {
|
||||||
|
import { DefineComponent } from 'vue'
|
||||||
|
const component: DefineComponent<{}, {}, any>
|
||||||
|
export default component
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
import { InjectionKey } from 'vue'
|
||||||
|
import { ActionTree, createStore, GetterTree, MutationTree, Store, StoreOptions, useStore } from 'vuex'
|
||||||
|
import { getLayers } from '/@/api/layer'
|
||||||
|
import { LayerType } from '/@/types/mapLayer'
|
||||||
|
const initStateFunc = () => ({
|
||||||
|
Layers: [
|
||||||
|
{
|
||||||
|
name: 'default',
|
||||||
|
id: '',
|
||||||
|
is_distributed: true,
|
||||||
|
elements: [],
|
||||||
|
is_check: false,
|
||||||
|
is_select: false,
|
||||||
|
type: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'share',
|
||||||
|
id: '',
|
||||||
|
is_distributed: true,
|
||||||
|
elements: [],
|
||||||
|
is_check: false,
|
||||||
|
is_select: false,
|
||||||
|
type: 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
GatewayInfo: { // remote controller, dock
|
||||||
|
|
||||||
|
},
|
||||||
|
DeviceInfo: { // drone
|
||||||
|
|
||||||
|
},
|
||||||
|
layerBaseInfo: {} as {
|
||||||
|
[key:string]:string
|
||||||
|
},
|
||||||
|
drawVisible: false,
|
||||||
|
coverList: [
|
||||||
|
|
||||||
|
] as any,
|
||||||
|
wsEvent: {
|
||||||
|
mapElementCreat: {},
|
||||||
|
mapElementUpdate: {},
|
||||||
|
mapElementDelete: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export type RootStateType = ReturnType<typeof initStateFunc>
|
||||||
|
|
||||||
|
const getters: GetterTree<RootStateType, RootStateType> = {
|
||||||
|
}
|
||||||
|
const mutations: MutationTree<RootStateType> = {
|
||||||
|
SET_LAYER_INFO (state, info) {
|
||||||
|
state.Layers = info
|
||||||
|
},
|
||||||
|
SET_DEVICE_INFO (state, info) {
|
||||||
|
state.DeviceInfo = info
|
||||||
|
// console.log(state.DeviceInfo)
|
||||||
|
},
|
||||||
|
SET_GATEWAY_INFO (state, info) {
|
||||||
|
state.GatewayInfo = info
|
||||||
|
// console.log(state.GatewayInfo)
|
||||||
|
},
|
||||||
|
SET_DRAW_VISIBLE_INFO (state, bool) {
|
||||||
|
state.drawVisible = bool
|
||||||
|
},
|
||||||
|
SET_MAP_ELEMENT_CREATE (state, info) {
|
||||||
|
state.wsEvent.mapElementCreat = info
|
||||||
|
},
|
||||||
|
SET_MAP_ELEMENT_UPDATE (state, info) {
|
||||||
|
state.wsEvent.mapElementUpdate = info
|
||||||
|
},
|
||||||
|
SET_MAP_ELEMENT_DELETE (state, info) {
|
||||||
|
state.wsEvent.mapElementDelete = info
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const actions: ActionTree<RootStateType, RootStateType> = {
|
||||||
|
async getAllElement ({ commit }) {
|
||||||
|
const result = await getLayers({
|
||||||
|
groupId: '',
|
||||||
|
isDistributed: true
|
||||||
|
})
|
||||||
|
commit('SET_LAYER_INFO', result.data?.list)
|
||||||
|
console.log(result)
|
||||||
|
},
|
||||||
|
updateElement ({ state }, content: {type: 'is_check' | 'is_select', id: string, bool:boolean}) {
|
||||||
|
const key = content.id.replaceAll('resource__', '')
|
||||||
|
const type = content.type
|
||||||
|
const layers = state.Layers
|
||||||
|
const layer = layers.find(item => item.id === key)
|
||||||
|
if (layer) {
|
||||||
|
layer[type] = content.bool
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setLayerInfo ({ state }, layers) {
|
||||||
|
// const layers = state.Layers
|
||||||
|
const obj:{
|
||||||
|
[key:string]:string
|
||||||
|
} = {}
|
||||||
|
layers.forEach(layer => {
|
||||||
|
if (layer.type === LayerType.Default) {
|
||||||
|
obj.default = layer.id
|
||||||
|
} else {
|
||||||
|
if (layer.type === LayerType.Share) {
|
||||||
|
obj.share = layer.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
state.layerBaseInfo = obj
|
||||||
|
console.log('state.layerBaseInfo', state.layerBaseInfo)
|
||||||
|
},
|
||||||
|
getLayerInfo ({ state }, id:string) {
|
||||||
|
return state.layerBaseInfo[id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const storeOptions: StoreOptions<RootStateType> = {
|
||||||
|
state: initStateFunc,
|
||||||
|
getters,
|
||||||
|
mutations,
|
||||||
|
actions
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootStore = createStore(storeOptions)
|
||||||
|
|
||||||
|
export default rootStore
|
||||||
|
|
||||||
|
export const storeKey: InjectionKey<Store<RootStateType>> = Symbol('')
|
||||||
|
|
||||||
|
type AllStateStoreTypes = RootStateType & {
|
||||||
|
// moduleName: moduleType
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMyStore<T = AllStateStoreTypes> () {
|
||||||
|
return useStore<T>(storeKey)
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
html, body, #app, #my-app {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #f7f9fa;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
// Prevent font enlargement in horizontal screen
|
||||||
|
text-size-adjust: 100%;
|
||||||
|
|
||||||
|
font-family: Roboto, sans-serif-medium, Arial, sans-serif;
|
||||||
|
color: $main-text-color;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
.flex-display {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-column {
|
||||||
|
@extend .flex-display;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row {
|
||||||
|
@extend .flex-display;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-align-start {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.flex-align-end {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
.flex-align-baseline {
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
.flex-align-stretch {
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
.flex-align-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-justify-start {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
.flex-justify-end {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
.flex-justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.flex-justify-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.flex-justify-around {
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
//width
|
||||||
|
.width-100vw {
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
.width-100 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
//height
|
||||||
|
.height-100vh {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
.height-100 {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
//margin
|
||||||
|
m-5 {
|
||||||
|
margin: -5px !important;
|
||||||
|
}
|
||||||
|
.mt-5 {
|
||||||
|
margin-top: -5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt100 {
|
||||||
|
margin-top: 100px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt110 {
|
||||||
|
margin-top: 110px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-5 {
|
||||||
|
margin-bottom: -5px !important;
|
||||||
|
}
|
||||||
|
.ml-5 {
|
||||||
|
margin-left: -5px !important;
|
||||||
|
}
|
||||||
|
.mr-5 {
|
||||||
|
margin-right: -5px !important;
|
||||||
|
}
|
||||||
|
.m0 {
|
||||||
|
margin: 0px !important;
|
||||||
|
}
|
||||||
|
.mt0 {
|
||||||
|
margin-top: 0px !important;
|
||||||
|
}
|
||||||
|
.mb0 {
|
||||||
|
margin-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
.ml0 {
|
||||||
|
margin-left: 0px !important;
|
||||||
|
}
|
||||||
|
.mr0 {
|
||||||
|
margin-right: 0px !important;
|
||||||
|
}
|
||||||
|
.m5 {
|
||||||
|
margin: 5px !important;
|
||||||
|
}
|
||||||
|
.mt5 {
|
||||||
|
margin-top: 5px !important;
|
||||||
|
}
|
||||||
|
.mb5 {
|
||||||
|
margin-bottom: 5px !important;
|
||||||
|
}
|
||||||
|
.ml5 {
|
||||||
|
margin-left: 5px !important;
|
||||||
|
}
|
||||||
|
.mr5 {
|
||||||
|
margin-right: 5px !important;
|
||||||
|
}
|
||||||
|
.m10 {
|
||||||
|
margin: 10px !important;
|
||||||
|
}
|
||||||
|
.mt10 {
|
||||||
|
margin-top: 10px !important;
|
||||||
|
}
|
||||||
|
.mb10 {
|
||||||
|
margin-bottom: 10px !important;
|
||||||
|
}
|
||||||
|
.ml10 {
|
||||||
|
margin-left: 10px !important;
|
||||||
|
}
|
||||||
|
.mr10 {
|
||||||
|
margin-right: 10px !important;
|
||||||
|
}
|
||||||
|
.m15 {
|
||||||
|
margin: 15px !important;
|
||||||
|
}
|
||||||
|
.mt15 {
|
||||||
|
margin-top: 15px !important;
|
||||||
|
}
|
||||||
|
.mb15 {
|
||||||
|
margin-bottom: 15px !important;
|
||||||
|
}
|
||||||
|
.ml15 {
|
||||||
|
margin-left: 15px !important;
|
||||||
|
}
|
||||||
|
.mr15 {
|
||||||
|
margin-right: 15px !important;
|
||||||
|
}
|
||||||
|
.m20 {
|
||||||
|
margin: 20px !important;
|
||||||
|
}
|
||||||
|
.mt20 {
|
||||||
|
margin-top: 20px !important;
|
||||||
|
}
|
||||||
|
.mb20 {
|
||||||
|
margin-bottom: 20px !important;
|
||||||
|
}
|
||||||
|
.ml20 {
|
||||||
|
margin-left: 20px !important;
|
||||||
|
}
|
||||||
|
.mr20 {
|
||||||
|
margin-right: 20px !important;
|
||||||
|
}
|
||||||
|
.m25 {
|
||||||
|
margin: 25px !important;
|
||||||
|
}
|
||||||
|
.mt25 {
|
||||||
|
margin-top: 25px !important;
|
||||||
|
}
|
||||||
|
.mb25 {
|
||||||
|
margin-bottom: 25px !important;
|
||||||
|
}
|
||||||
|
.ml25 {
|
||||||
|
margin-left: 25px !important;
|
||||||
|
}
|
||||||
|
.mr25 {
|
||||||
|
margin-right: 25px !important;
|
||||||
|
}
|
||||||
|
.m30 {
|
||||||
|
margin: 30px !important;
|
||||||
|
}
|
||||||
|
.mt30 {
|
||||||
|
margin-top: 30px !important;
|
||||||
|
}
|
||||||
|
.mb30 {
|
||||||
|
margin-bottom: 30px !important;
|
||||||
|
}
|
||||||
|
.ml30 {
|
||||||
|
margin-left: 30px !important;
|
||||||
|
}
|
||||||
|
.ml40 {
|
||||||
|
margin-left: 40px !important;
|
||||||
|
}
|
||||||
|
.mr30 {
|
||||||
|
margin-right: 30px !important;
|
||||||
|
}
|
||||||
|
.m50 {
|
||||||
|
margin: 50px !important;
|
||||||
|
}
|
||||||
|
.mt50 {
|
||||||
|
margin-top: 50px !important;
|
||||||
|
}
|
||||||
|
.mb50 {
|
||||||
|
margin-bottom: 50px !important;
|
||||||
|
}
|
||||||
|
.ml50 {
|
||||||
|
margin-left: 50px !important;
|
||||||
|
}
|
||||||
|
.mr50 {
|
||||||
|
margin-right: 50px !important;
|
||||||
|
}
|
||||||
|
// padding值
|
||||||
|
.p0 {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.pt0 {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
.pr0 {
|
||||||
|
padding-right: 0 !important;
|
||||||
|
}
|
||||||
|
.pb0 {
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
.pl0 {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
.p5 {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
.pt5 {
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
.pr5 {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
.pb5 {
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
.pl5 {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
.p10 {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.pt10 {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
.pr10 {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
.pb10 {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
.pl10 {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
.p15 {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
.pt15 {
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
.pr15 {
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
.pb15 {
|
||||||
|
padding-bottom: 15px;
|
||||||
|
}
|
||||||
|
.pl15 {
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
.p20 {
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.pt20 {
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
.pr20 {
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
.pb20 {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
.pl20 {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
.p30 {
|
||||||
|
padding: 30px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.pt30 {
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
.pr30 {
|
||||||
|
padding-right: 30px;
|
||||||
|
}
|
||||||
|
.pb30 {
|
||||||
|
padding-bottom: 30px;
|
||||||
|
}
|
||||||
|
.pl30 {
|
||||||
|
padding-left: 30px;
|
||||||
|
}
|
||||||
|
.pb50 {
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
|
.pl50 {
|
||||||
|
padding-left: 50px;
|
||||||
|
}
|
||||||
|
.pl120 {
|
||||||
|
padding-left: 120px;
|
||||||
|
}
|
||||||
|
.pl150 {
|
||||||
|
padding-left: 150px;
|
||||||
|
}
|
||||||
|
.pt50 {
|
||||||
|
padding-top: 50px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
$font-family-sans-serif: 'Open Sans', BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||||
|
'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
|
||||||
|
'Microsoft YaHei', SimSun, sans-serif;
|
||||||
|
|
||||||
|
$line-heights: (
|
||||||
|
12: 20px,
|
||||||
|
14: 22px,
|
||||||
|
16: 24px,
|
||||||
|
18: 26px
|
||||||
|
);
|
||||||
|
|
||||||
|
// 用法: @include text(12)
|
||||||
|
@mixin text($size) {
|
||||||
|
font-size: #{$size}px;
|
||||||
|
line-height: map-get($line-heights, $size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 常规体
|
||||||
|
@mixin text-regular {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 中粗体
|
||||||
|
@mixin text-semibold {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin ellipsis {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fz10 {
|
||||||
|
font-size: 10;
|
||||||
|
}
|
||||||
|
.fz12 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.fz14 {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.fz16 {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.fz18 {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.fz20 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
.fz22 {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
.fz24 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.fz26 {
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
|
.fz28 {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
.fz30 {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
.fz32 {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
.fz35 {
|
||||||
|
font-size: 35px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
@import './common.scss';
|
||||||
|
@import 'flex.style.scss';
|
||||||
|
@import 'fonts.scss';
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
html,
|
||||||
|
body,
|
||||||
|
div,
|
||||||
|
span,
|
||||||
|
applet,
|
||||||
|
object,
|
||||||
|
iframe,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
p,
|
||||||
|
blockquote,
|
||||||
|
pre,
|
||||||
|
a,
|
||||||
|
abbr,
|
||||||
|
acronym,
|
||||||
|
address,
|
||||||
|
big,
|
||||||
|
cite,
|
||||||
|
code,
|
||||||
|
del,
|
||||||
|
dfn,
|
||||||
|
em,
|
||||||
|
img,
|
||||||
|
ins,
|
||||||
|
kbd,
|
||||||
|
q,
|
||||||
|
s,
|
||||||
|
samp,
|
||||||
|
small,
|
||||||
|
strike,
|
||||||
|
strong,
|
||||||
|
sub,
|
||||||
|
sup,
|
||||||
|
tt,
|
||||||
|
var,
|
||||||
|
b,
|
||||||
|
u,
|
||||||
|
i,
|
||||||
|
center,
|
||||||
|
dl,
|
||||||
|
dt,
|
||||||
|
dd,
|
||||||
|
ol,
|
||||||
|
ul,
|
||||||
|
li,
|
||||||
|
fieldset,
|
||||||
|
form,
|
||||||
|
label,
|
||||||
|
legend,
|
||||||
|
table,
|
||||||
|
caption,
|
||||||
|
tbody,
|
||||||
|
tfoot,
|
||||||
|
thead,
|
||||||
|
tr,
|
||||||
|
th,
|
||||||
|
td,
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
canvas,
|
||||||
|
details,
|
||||||
|
embed,
|
||||||
|
figure,
|
||||||
|
figcaption,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
hgroup,
|
||||||
|
menu,
|
||||||
|
nav,
|
||||||
|
output,
|
||||||
|
ruby,
|
||||||
|
section,
|
||||||
|
summary,
|
||||||
|
time,
|
||||||
|
mark,
|
||||||
|
audio,
|
||||||
|
video {
|
||||||
|
margin : 0;
|
||||||
|
padding : 0;
|
||||||
|
border : 0;
|
||||||
|
font : inherit;
|
||||||
|
font-size : 100%;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
line-height : 1;
|
||||||
|
// -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ol,
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
caption,
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
font-weight : normal;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
q,
|
||||||
|
blockquote {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
q::before,
|
||||||
|
q::after,
|
||||||
|
blockquote::before,
|
||||||
|
blockquote::after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a img {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
details,
|
||||||
|
figcaption,
|
||||||
|
figure,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
hgroup,
|
||||||
|
menu,
|
||||||
|
nav,
|
||||||
|
section,
|
||||||
|
summary {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
background : transparent;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input[type='number'],
|
||||||
|
input[type='text'],
|
||||||
|
input[type='password'],
|
||||||
|
input[type='email'],
|
||||||
|
input[type='search'],
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family : inherit;
|
||||||
|
margin : 0;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
$main-text-color: #000;
|
||||||
|
$header-height: 52px;
|
||||||
|
// Auxiliary color
|
||||||
|
$info: #1fa3f6;
|
||||||
|
$success: #28d445;
|
||||||
|
$danger: #e70102;
|
||||||
|
$alarm: #ffcc00;
|
||||||
|
$warning: #ffcc00;
|
||||||
|
$error: #e70102;
|
||||||
|
|
||||||
|
// 品牌色
|
||||||
|
$primary: #2d8cf0;
|
||||||
|
$primary-click: #2b85e4;
|
||||||
|
$primary-hover: #5cadff;
|
||||||
|
$primary-hover-dropdown: rgba($primary-hover, 0.2);
|
||||||
|
$primary-disabled: #274d75;
|
||||||
|
// 辅助色拓展
|
||||||
|
$danger-hover: #ff4d4e;
|
||||||
|
$danger-active: #d40001;
|
||||||
|
$menu-primary: #464c5b; // tab菜单主题色
|
||||||
|
// 图标颜色
|
||||||
|
$ic-white-normal: #fff;
|
||||||
|
$ic-black-normal: #4e4e4e;
|
||||||
|
$ic-hover: #a7a7a7;
|
||||||
|
$ic-disabled: #5f5f5f;
|
||||||
|
$ic-selected: #1088f2;
|
||||||
|
// 中性色-黑
|
||||||
|
$dark-bg-light: #868688; // 背景色浅色
|
||||||
|
$dark-btn-hover: #5d5f61; // 按钮 hover 色
|
||||||
|
$dark-border: #4f4f4f; // 边框色
|
||||||
|
$dark-btn-disabled: #3c3c3c; // 按钮主色禁用
|
||||||
|
$dark-border-secondary: #393939; // 第二边框色
|
||||||
|
$dark-basic-primary: #232323; // 第一基础底色
|
||||||
|
$dark-basic-secondary: #282828; // 第二基础底色
|
||||||
|
$dark-highlight: #232323; // 高亮色
|
||||||
|
$dark-disable: #444444; // 置灰底色
|
||||||
|
$dark-project-disabled: #292929;
|
||||||
|
// 中性色-白
|
||||||
|
$light-bg-primary: #fff; // 1 背景
|
||||||
|
$light-bg-secondary: #f7f9fa; // 2 背景
|
||||||
|
$light-divider: #e8eaec; // 3 分割线
|
||||||
|
$light-border: #dcdee2; // 4 边框
|
||||||
|
$light-disabled: #c5c8ce; // 5 失效
|
||||||
|
$light-auxiliary: #808695; // 6 辅助图标
|
||||||
|
$light-main-text: #515a6e; // 7 正文 ?用处
|
||||||
|
$light-title: #17233d; // 8 标题 ?用处
|
||||||
|
$light-bg-menu: #3b3e40; // 9 菜单栏背景色 ?用处
|
||||||
|
$light-border-secondary: #e8e8e8; // 第二边框色
|
||||||
|
|
||||||
|
// 字体
|
||||||
|
// 白色
|
||||||
|
$text-white-basic: #fff; // 基础色
|
||||||
|
$text-white-main: rgba($text-white-basic, 1); // 正文
|
||||||
|
$text-white-secondary: rgba($text-white-basic, 0.45); // 次级
|
||||||
|
$text-white-disabled: rgba($text-white-basic, 0.25); // 置灰
|
||||||
|
// 黑色
|
||||||
|
$text-black-basic: #000000; // 基础色
|
||||||
|
$text-black-emphasize: rgba($text-black-basic, 0.85); // 强调
|
||||||
|
$text-black-main: rgba($text-black-basic, 0.65); // 正文
|
||||||
|
$text-black-secondary: rgba($text-black-basic, 0.45); // 次要
|
||||||
|
$text-black-disabled: rgba($text-black-basic, 0.25); // 置灰
|
||||||
|
$text-link: $primary;
|
||||||
|
$text-danger: $danger;
|
||||||
|
// 标签
|
||||||
|
$tag-green: #19be6b;
|
||||||
|
// 滚动条等颜色
|
||||||
|
$scroll-bar: #c5c8ce;
|
||||||
|
$scroll-bar-dark: #5f5f5f;
|
||||||
|
|
||||||
|
// 选择框
|
||||||
|
|
||||||
|
$select-disabled: #d8d8d8;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export enum ERouterName {
|
||||||
|
Element = 'element',
|
||||||
|
Project = 'project',
|
||||||
|
Tsa = 'tsa',
|
||||||
|
Layer = 'layer',
|
||||||
|
Media = 'media',
|
||||||
|
Wayline = 'wayline',
|
||||||
|
Livestream = 'livestream',
|
||||||
|
Pilot = 'pilot-login',
|
||||||
|
PilotHome = 'pilot-home',
|
||||||
|
PilotMedia = 'pilot-media',
|
||||||
|
PilotLiveshare = 'pilot-liveshare'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum EStorageKey {
|
||||||
|
LANG_CODE = 'DJI_CREATE_VITE_H5_APP:lang_code',
|
||||||
|
TEST_TOOLS_POSITION_STORAGE_KEY = 'DJI_CREATE_VITE_H5_APP:test_tools_position',
|
||||||
|
SESSION_ID = 'DJI_CREATE_VITE_H5_APP:sess'
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './enums'
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export enum MapDoodleEnum {
|
||||||
|
PIN = 'pin',
|
||||||
|
POLYLINE = 'polyline',
|
||||||
|
POLYGON = 'polygon',
|
||||||
|
Close = 'off'
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
export interface MapGeographicPosition {
|
||||||
|
longitude: number;
|
||||||
|
latitude: number;
|
||||||
|
height?: number;
|
||||||
|
}
|
||||||
|
export enum LayerType {
|
||||||
|
Normal,
|
||||||
|
Default,
|
||||||
|
Share
|
||||||
|
}
|
||||||
|
export interface pinAMapPosition {
|
||||||
|
KL: number
|
||||||
|
className: string
|
||||||
|
kT: number
|
||||||
|
lng: number
|
||||||
|
lat: number
|
||||||
|
}
|
||||||
|
export enum ResourceStatus {
|
||||||
|
NotShow,
|
||||||
|
Show
|
||||||
|
}
|
||||||
|
export type GeojsonCoordinate = [number, number, number?]
|
||||||
|
|
||||||
|
export interface GeojsonLine {
|
||||||
|
type: 'Feature'
|
||||||
|
properties: {
|
||||||
|
color: string
|
||||||
|
directConnected?: boolean
|
||||||
|
}
|
||||||
|
geometry: {
|
||||||
|
type: 'LineString'
|
||||||
|
coordinates: GeojsonCoordinate[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeojsonPolygon {
|
||||||
|
type: 'Feature'
|
||||||
|
properties: {
|
||||||
|
color: string
|
||||||
|
}
|
||||||
|
geometry: {
|
||||||
|
type: 'Polygon'
|
||||||
|
coordinates: GeojsonCoordinate[][]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeojsonPoint {
|
||||||
|
type: 'Feature'
|
||||||
|
properties: {
|
||||||
|
color: string
|
||||||
|
clampToGround?: boolean
|
||||||
|
}
|
||||||
|
geometry: {
|
||||||
|
type: 'Point'
|
||||||
|
coordinates: GeojsonCoordinate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export type GeojsonFeature = GeojsonLine | GeojsonPolygon | GeojsonPoint
|
||||||
|
|
||||||
|
interface ResourceObjectBasic {
|
||||||
|
user_name: string
|
||||||
|
user_id?: string
|
||||||
|
type:0| 1 | 2
|
||||||
|
content: unknown
|
||||||
|
}
|
||||||
|
export interface PinResource extends ResourceObjectBasic {
|
||||||
|
type: 0
|
||||||
|
content: GeojsonFeature
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ResourceObject = PinResource
|
||||||
|
export enum LayerElevationLoadStatus {
|
||||||
|
Unload,
|
||||||
|
Load
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LayerResource {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
order: number
|
||||||
|
status: ResourceStatus
|
||||||
|
resource: ResourceObject | null
|
||||||
|
display: number
|
||||||
|
create_time: number
|
||||||
|
elevation_load_status?: LayerElevationLoadStatus //
|
||||||
|
}
|
||||||
|
export interface Layer {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
order: number
|
||||||
|
create_time: number
|
||||||
|
type: LayerType
|
||||||
|
is_distributed: boolean
|
||||||
|
is_lock: boolean
|
||||||
|
elements: null | LayerResource[],
|
||||||
|
is_check?: boolean
|
||||||
|
is_select?: boolean
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import { MapElementEnum } from '/@/constants/map'
|
||||||
|
|
||||||
|
export interface mapLayerStyle {
|
||||||
|
background: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface mapLayerChildren {
|
||||||
|
key: string
|
||||||
|
style: mapLayerStyle
|
||||||
|
title: string
|
||||||
|
obj: any
|
||||||
|
}
|
||||||
|
export interface mapLayerChildrenObj {
|
||||||
|
className: string
|
||||||
|
key: string
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽事件
|
||||||
|
export interface DropEvent {
|
||||||
|
node: {
|
||||||
|
eventKey: string
|
||||||
|
pos: string
|
||||||
|
$parent: any
|
||||||
|
}
|
||||||
|
dragNode: {
|
||||||
|
eventKey: string
|
||||||
|
}
|
||||||
|
dropPosition: number
|
||||||
|
dropToGap: boolean
|
||||||
|
}
|
||||||
|
export interface mapLayer {
|
||||||
|
key?: string
|
||||||
|
title: string
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
style: mapLayerStyle
|
||||||
|
elements: any
|
||||||
|
}
|
||||||
|
export interface elementGroupsReq{
|
||||||
|
groupId: string
|
||||||
|
isDistributed: boolean
|
||||||
|
}
|
||||||
|
export interface PostElementsBody {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
resource: {
|
||||||
|
type: MapElementEnum,
|
||||||
|
user_name?: string,
|
||||||
|
content: {
|
||||||
|
type:string,
|
||||||
|
properties:{
|
||||||
|
color:string,
|
||||||
|
clampToGround:boolean
|
||||||
|
},
|
||||||
|
geometry:{
|
||||||
|
type:string,
|
||||||
|
coordinates:unknown
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Color {
|
||||||
|
id: number
|
||||||
|
color: string
|
||||||
|
selected: boolean,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum GeoType {
|
||||||
|
LineString = 'LineString',
|
||||||
|
Polygon = 'Polygon',
|
||||||
|
Point = 'Point'
|
||||||
|
}
|
||||||
|
export enum ResourceStatus {
|
||||||
|
NotShow,
|
||||||
|
Show
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum LayerElevationLoadStatus {
|
||||||
|
Unload,
|
||||||
|
Load
|
||||||
|
}
|
||||||
|
export interface PutElementsBody {
|
||||||
|
name?: string
|
||||||
|
status?: ResourceStatus
|
||||||
|
content?: unknown
|
||||||
|
display?: number
|
||||||
|
elevation_load_status?: LayerElevationLoadStatus
|
||||||
|
}
|
||||||
|
export enum LayerType {
|
||||||
|
Normal,
|
||||||
|
Default,
|
||||||
|
Share,
|
||||||
|
Reconstruction
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { App, DefineComponent } from 'vue'
|
||||||
|
|
||||||
|
const components: Record<string, DefineComponent<{}, {}, any>> = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CommonComponents = {
|
||||||
|
install (app: App): void {
|
||||||
|
Object.keys(components).forEach(name => {
|
||||||
|
app.component(name, components[name])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export function formatPhoneNum (phoneNum: string | number) {
|
||||||
|
const str = String(phoneNum)
|
||||||
|
return str.substring(0, 3) + '****' + str.slice(-4)
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import {
|
||||||
|
MapGeographicPosition,
|
||||||
|
} from '/@/types/map'
|
||||||
|
|
||||||
|
export type GeojsonCoordinate = [number, number, number?]
|
||||||
|
|
||||||
|
export interface GeojsonLine {
|
||||||
|
type: 'Feature'
|
||||||
|
properties: {
|
||||||
|
color: string
|
||||||
|
directConnected?: boolean
|
||||||
|
}
|
||||||
|
geometry: {
|
||||||
|
type: 'LineString'
|
||||||
|
coordinates: GeojsonCoordinate[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeojsonPolygon {
|
||||||
|
type: 'Feature'
|
||||||
|
properties: {
|
||||||
|
color: string
|
||||||
|
}
|
||||||
|
geometry: {
|
||||||
|
type: 'Polygon'
|
||||||
|
coordinates: GeojsonCoordinate[][]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeojsonPoint {
|
||||||
|
type: 'Feature'
|
||||||
|
properties: {
|
||||||
|
color: string
|
||||||
|
clampToGround?: boolean
|
||||||
|
}
|
||||||
|
geometry: {
|
||||||
|
type: 'Point'
|
||||||
|
coordinates: GeojsonCoordinate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GeojsonFeature = GeojsonLine | GeojsonPolygon | GeojsonPoint
|
||||||
|
|
||||||
|
export function geographic2Coordinate (position: MapGeographicPosition): GeojsonCoordinate {
|
||||||
|
const coordinates: GeojsonCoordinate = [position.longitude, position.latitude]
|
||||||
|
if (position.height !== undefined) coordinates.push(position.height)
|
||||||
|
return coordinates
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateLine (coordinates: MapGeographicPosition[], properties: GeojsonLine['properties']): GeojsonFeature {
|
||||||
|
return {
|
||||||
|
type: 'Feature',
|
||||||
|
properties,
|
||||||
|
geometry: {
|
||||||
|
type: 'LineString',
|
||||||
|
coordinates: coordinates.map(geographic2Coordinate),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generatePolygon (coordinates: MapGeographicPosition[], properties: GeojsonPolygon['properties']): GeojsonFeature {
|
||||||
|
return {
|
||||||
|
type: 'Feature',
|
||||||
|
properties,
|
||||||
|
geometry: {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [coordinates.map(geographic2Coordinate)],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generatePoint (position: MapGeographicPosition, properties: GeojsonPoint['properties']): GeojsonFeature {
|
||||||
|
return {
|
||||||
|
type: 'Feature',
|
||||||
|
properties,
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: geographic2Coordinate(position),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const layerTreeTypes = ['layer', 'resource'] as const
|
||||||
|
type LayerTreeType = (typeof layerTreeTypes)[number]
|
||||||
|
const Spliter = '__'
|
||||||
|
|
||||||
|
export function getLayerTreeKey (type: LayerTreeType, id: number | string) {
|
||||||
|
return `${type}${Spliter}${id}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isLayerTreeKey (key: string, type?: LayerTreeType) {
|
||||||
|
if (type) {
|
||||||
|
return key.startsWith(`${type}${Spliter}`)
|
||||||
|
} else {
|
||||||
|
return layerTreeTypes.some(t => key.startsWith(`${t}${Spliter}`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIdFromLayerTreeKey (key: string) {
|
||||||
|
return key.split(Spliter)[1]
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Used for log printing in a non-production environment
|
||||||
|
* @param args
|
||||||
|
*/
|
||||||
|
export function consoleLog (...args: Parameters<typeof console.log>) {
|
||||||
|
if (import.meta.env.VITE_APP_ENVIRONMENT !== 'PROD') {
|
||||||
|
window.console.log.apply(null, args) // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function consoleWarn (...args: Parameters<typeof console.warn>) {
|
||||||
|
if (import.meta.env.VITE_APP_ENVIRONMENT !== 'PROD') {
|
||||||
|
console.warn.apply(null, args) // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function consoleError (...args: Parameters<typeof console.error>) {
|
||||||
|
if (import.meta.env.VITE_APP_ENVIRONMENT !== 'PROD') {
|
||||||
|
console.error.apply(null, args) // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function testEnvLog (...args: Parameters<typeof console.log>) {
|
||||||
|
if (import.meta.env.VITE_APP_ENVIRONMENT !== 'PROD') {
|
||||||
|
console.log.apply(null, args) // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { pinAMapPosition, MapGeographicPosition, Layer, LayerType, LayerElevationLoadStatus } from '/@/types/map'
|
||||||
|
import { generatePoint, generateLine, generatePolygon } from '/@/utils/genjson'
|
||||||
|
import { MapDoodleColor, MapElementEnum } from '/@/constants/map'
|
||||||
|
function getPinPosition (pinAMapPosition: pinAMapPosition):MapGeographicPosition {
|
||||||
|
return { height: 0, latitude: pinAMapPosition.lat, longitude: pinAMapPosition.lng }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generatePointContent (pinAMapPosition: pinAMapPosition) {
|
||||||
|
const position = getPinPosition(pinAMapPosition)
|
||||||
|
return {
|
||||||
|
type: MapElementEnum.PIN,
|
||||||
|
content: generatePoint(position, {
|
||||||
|
color: MapDoodleColor.PinColor,
|
||||||
|
clampToGround: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getLieOrPolyPosition (mapPosition: pinAMapPosition[]):MapGeographicPosition[] {
|
||||||
|
const position = [] as MapGeographicPosition[]
|
||||||
|
mapPosition.forEach(item => {
|
||||||
|
position.push({ height: 0, latitude: item.lat, longitude: item.lng })
|
||||||
|
})
|
||||||
|
return position
|
||||||
|
}
|
||||||
|
export function generateLineContent (mapPosition: pinAMapPosition[]) {
|
||||||
|
const position = getLieOrPolyPosition(mapPosition)
|
||||||
|
return {
|
||||||
|
type: MapElementEnum.LINE,
|
||||||
|
content: generateLine(position, {
|
||||||
|
color: MapDoodleColor.PolylineColor,
|
||||||
|
directConnected: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generatePolyContent (mapPosition: pinAMapPosition[]) {
|
||||||
|
const position = getLieOrPolyPosition(mapPosition)
|
||||||
|
return {
|
||||||
|
type: MapElementEnum.POLY,
|
||||||
|
content: generatePolygon(position, {
|
||||||
|
color: MapDoodleColor.PolygonColor,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { EStorageKey } from '/@/types/enums'
|
||||||
|
import { consoleWarn } from './logger'
|
||||||
|
|
||||||
|
function getStorageData (key: EStorageKey, parse?: boolean): string | null
|
||||||
|
function getStorageData<T> (key: EStorageKey, parse?: boolean): T | null
|
||||||
|
function getStorageData (key: EStorageKey, parse?: boolean): any {
|
||||||
|
const value = window.localStorage.getItem(key)
|
||||||
|
if (parse && value) {
|
||||||
|
try {
|
||||||
|
const result = JSON.parse(value)
|
||||||
|
return result
|
||||||
|
} catch (e) {
|
||||||
|
consoleWarn('appStorage.get failed, err:', e)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearStorageData (key: EStorageKey | EStorageKey[]) {
|
||||||
|
let keyList: EStorageKey[] = []
|
||||||
|
if (Array.isArray(key)) {
|
||||||
|
keyList = key
|
||||||
|
} else {
|
||||||
|
keyList = [key]
|
||||||
|
}
|
||||||
|
keyList.forEach(item => {
|
||||||
|
window.localStorage.removeItem(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const appStorage = {
|
||||||
|
save (key: EStorageKey, value: string) {
|
||||||
|
window.localStorage.setItem(key, value)
|
||||||
|
},
|
||||||
|
get: getStorageData,
|
||||||
|
|
||||||
|
clear: clearStorageData,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default appStorage
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export function uuidv4 () {
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||||
|
const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8)
|
||||||
|
return v.toString(16)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* Conversion between the coordinates of the National Bureau of Survey and Measurement (Mars coordinates, GCJ02) and the WGS84 coordinate system
|
||||||
|
*/
|
||||||
|
const x_PI = 3.14159265358979324 * 3000.0 / 180.0;
|
||||||
|
const PI = 3.1415926535897932384626;
|
||||||
|
const a = 6378245.0;
|
||||||
|
const ee = 0.00669342162296594323;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WGS84 to Mars coordinate system GCj02
|
||||||
|
* @param lng
|
||||||
|
* @param lat
|
||||||
|
* @returns {*[]}
|
||||||
|
*/
|
||||||
|
export function wgs84togcj02(lng, lat) {
|
||||||
|
if (out_of_china(lng, lat)) {
|
||||||
|
return [lng, lat]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var dlat = transformlat(lng - 105.0, lat - 35.0);
|
||||||
|
var dlng = transformlng(lng - 105.0, lat - 35.0);
|
||||||
|
var radlat = lat / 180.0 * PI;
|
||||||
|
var magic = Math.sin(radlat);
|
||||||
|
magic = 1 - ee * magic * magic;
|
||||||
|
var sqrtmagic = Math.sqrt(magic);
|
||||||
|
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
|
||||||
|
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
|
||||||
|
var mglat = lat + dlat;
|
||||||
|
var mglng = lng + dlng;
|
||||||
|
return [mglng, mglat]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GCJ02 transform WGS84
|
||||||
|
* @param lng
|
||||||
|
* @param lat
|
||||||
|
* @returns {*[]}
|
||||||
|
*/
|
||||||
|
export function gcj02towgs84(lng, lat) {
|
||||||
|
var lat = +lat;
|
||||||
|
var lng = +lng;
|
||||||
|
if (out_of_china(lng, lat)) {
|
||||||
|
return [lng, lat]
|
||||||
|
} else {
|
||||||
|
var dlat = transformlat(lng - 105.0, lat - 35.0);
|
||||||
|
var dlng = transformlng(lng - 105.0, lat - 35.0);
|
||||||
|
var radlat = lat / 180.0 * PI;
|
||||||
|
var magic = Math.sin(radlat);
|
||||||
|
magic = 1 - ee * magic * magic;
|
||||||
|
var sqrtmagic = Math.sqrt(magic);
|
||||||
|
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
|
||||||
|
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
|
||||||
|
var mglat = lat + dlat;
|
||||||
|
var mglng = lng + dlng;
|
||||||
|
return [lng * 2 - mglng, lat * 2 - mglat]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformlat(lng, lat) {
|
||||||
|
var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
|
||||||
|
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
|
||||||
|
ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
|
||||||
|
ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformlng(lng, lat) {
|
||||||
|
var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
|
||||||
|
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
|
||||||
|
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
|
||||||
|
ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Judge whether you are in the country or not if you are not in the country
|
||||||
|
* @param lng
|
||||||
|
* @param lat
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function out_of_china(lng, lat) {
|
||||||
|
return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"sourceMap": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"types": ["vite/client"],
|
||||||
|
"lib": [
|
||||||
|
"esnext",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"/@/*": [
|
||||||
|
"src/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue"
|
||||||
|
, "src/vendors/coordtransform.js" ]
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
// config alias
|
||||||
|
import path from 'path'
|
||||||
|
import { ConfigEnv, defineConfig, UserConfigExport } from 'vite'
|
||||||
|
import ViteComponents, { AntDesignVueResolver } from 'vite-plugin-components'
|
||||||
|
// Introduce eslint plugin
|
||||||
|
import eslintPlugin from 'vite-plugin-eslint'
|
||||||
|
import OptimizationPersist from 'vite-plugin-optimize-persist'
|
||||||
|
import PkgConfig from 'vite-plugin-package-config'
|
||||||
|
import viteSvgIcons from 'vite-plugin-svg-icons'
|
||||||
|
import { viteVConsole } from 'vite-plugin-vconsole'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default ({ command, mode }: ConfigEnv): UserConfigExport => defineConfig({
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
eslintPlugin({
|
||||||
|
fix: true
|
||||||
|
}),
|
||||||
|
ViteComponents({
|
||||||
|
customComponentResolvers: [AntDesignVueResolver()],
|
||||||
|
}),
|
||||||
|
viteSvgIcons({
|
||||||
|
// 指定需要缓存的图标文件夹
|
||||||
|
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
|
||||||
|
// 指定symbolId格式
|
||||||
|
symbolId: 'icon-[dir]-[name]',
|
||||||
|
}),
|
||||||
|
viteVConsole({
|
||||||
|
entry: path.resolve(__dirname, './src/main.ts'), // 入口文件
|
||||||
|
// localEnabled: command === 'serve', // serve开发环境下
|
||||||
|
// enabled: command !== 'serve' || mode === 'test', // 打包环境下/发布测试包,
|
||||||
|
config: { // vconsole 配置项
|
||||||
|
maxLogNumber: 1000,
|
||||||
|
theme: 'light'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
PkgConfig(),
|
||||||
|
OptimizationPersist()
|
||||||
|
// [svgBuilder('./src/assets/icons/')] // All svg under src/icons/svg/ have been imported here, no need to import separately
|
||||||
|
],
|
||||||
|
server: {
|
||||||
|
open: true,
|
||||||
|
host: '0.0.0.0',
|
||||||
|
port: 8080
|
||||||
|
},
|
||||||
|
envDir: './env',
|
||||||
|
resolve: {
|
||||||
|
alias: [{
|
||||||
|
// https://github.com/vitejs/vite/issues/279#issuecomment-635646269
|
||||||
|
find: '/@',
|
||||||
|
replacement: path.resolve(__dirname, './src'),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
preprocessorOptions: {
|
||||||
|
scss: {
|
||||||
|
// example : additionalData: `@import "./src/design/styles/variables";`
|
||||||
|
// dont need include file extend .scss
|
||||||
|
additionalData: '@import "./src/styles/variables";'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
base: '/',
|
||||||
|
build: {
|
||||||
|
target: ['es2015'], // 最低支持 es2015
|
||||||
|
sourcemap: true
|
||||||
|
}
|
||||||
|
})
|
||||||