| | |
| | | <!-- |
| | | * @Author: husq 931347610@qq.com |
| | | * @Date: 2023-08-22 09:55:39 |
| | | * @LastEditors: husq 931347610@qq.com |
| | | * @LastEditTime: 2023-09-13 18:33:22 |
| | | * @FilePath: \Cloud-API-Demo-Web\index.html |
| | | * @Description: |
| | | * |
| | | * Copyright (c) 2023 by ${git_name_email}, All Rights Reserved. |
| | | --> |
| | | <!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> |
| | | <title>无人机操作系统</title> |
| | | </head> |
| | | <body> |
| | | <div id="demo-app"></div> |
| | |
| | | * @Author: 胡思旗 931347610@qq.com |
| | | * @Date: 2023-08-22 09:55:39 |
| | | * @LastEditors: husq 931347610@qq.com |
| | | * @LastEditTime: 2023-09-11 12:04:07 |
| | | * @LastEditTime: 2023-09-13 19:01:16 |
| | | * @FilePath: \Cloud-API-Demo-Web\src\api\http\config.ts |
| | | * @Description: |
| | | * |
| | |
| | | |
| | | // http |
| | | // http://172.16.13.64:8100 |
| | | baseURL: 'http://172.16.13.129:8100', // This url must end with "/". Example: 'http://192.168.1.1:6789/' |
| | | baseURL: 'http://192.168.1.198:6789', // This url must end with "/". Example: 'http://192.168.1.1:6789/' |
| | | // ws://172.16.13.129:6789/api/v1/ws |
| | | // ws://192.168.1.198:1883/ |
| | | websocketURL: 'ws://192.168.1.198:8600/drone/api/v1/ws', // Example: 'ws://192.168.1.198:6789/api/v1/ws' |
| | |
| | | |
| | | instance.interceptors.request.use( |
| | | config => { |
| | | config.headers[ELocalStorageKey.Token] = getAuthToken() |
| | | config.headers[ELocalStorageKey.Token] = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2OTQ2MDMwOTQsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE3ODEwMDMwOTQsImlhdCI6MTY5NDYwMzA5NCwidXNlcm5hbWUiOiJhZG1pblBDIn0.EuYY3zwbTVdJuE1_3x_ZbrBT83JcbaC_dLaIIwm795k' |
| | | config.baseURL = CURRENT_CONFIG.baseURL |
| | | // config.headers[REQUEST_ID] = uuidv4() |
| | | // config.baseURL = CURRENT_CONFIG.baseURL |
| | | return config |
| | |
| | | |
| | | instance.interceptors.response.use( |
| | | response => { |
| | | |
| | | |
| | | // console.info('URL: ' + response.config.baseURL + response.config.url, '\nData: ', response.data, '\nResponse:', response) |
| | | |
| | | //处理消息返回 |
| | | // if (response.data.code && !response.data.success) { |
| | | // 处理消息返回 |
| | | // if (response.data.code && !response.data.success) { |
| | | // message.error(response.data.message) |
| | | // } |
| | | if (response.data.code != 5000) { |
| | | message.error(response.data.message) |
| | | } |
| | | if (response.data.code && response.data.code !== 0) { |
| | | message.error(response.data.message) |
| | | } |
| | | return response |
| | | }, |
| | | err => { |
| | | message.error(`ERROR_INFO: ${err}`) |
| | | // const requestId = err?.config?.headers && err?.config?.headers[REQUEST_ID] |
| | | // if (requestId) { |
| | | // console.info(REQUEST_ID, ':', requestId) |
| | | // } |
| | | // console.info('url: ', err?.config?.url, `【${err?.config?.method}】 \n>>>> err: `, err) |
| | | const requestId = err?.config?.headers && err?.config?.headers[REQUEST_ID] |
| | | 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 |
| | | 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) { |
| | | message.error('The network is abnormal, please check the backend service and try again') |
| | | return |
| | | } |
| | | if (err.response?.status !== 200) { |
| | | message.error(`ERROR_CODE: ${err.response?.status}`) |
| | | } |
| | | // if (err.response?.status === 403) { |
| | | // // window.location.href = '/' |
| | | // } |
| | | // 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) { |
| | | // message.error('The network is abnormal, please check the backend service and try again') |
| | | // return |
| | | // } |
| | | // if (err.response?.status !== 200) { |
| | | // message.error(`ERROR_CODE: ${err.response?.status}`) |
| | | // } |
| | | // // if (err.response?.status === 403) { |
| | | // // // window.location.href = '/' |
| | | // // } |
| | | // if (err.response?.status === 401) { |
| | | // console.error(err.response) |
| | | // const flag: number = Number(localStorage.getItem(ELocalStorageKey.Flag)) |
| | | // switch (flag) { |
| | | // case EUserType.Web: |
| | | // router.push(ERouterName.LOGIN) |
| | | // break |
| | | // case EUserType.Pilot: |
| | | // router.push(ERouterName.PILOT) |
| | | // break |
| | | // } |
| | | // } |
| | | if (err.response?.status === 401) { |
| | | console.error(err.response) |
| | | const flag: number = Number(localStorage.getItem(ELocalStorageKey.Flag)) |
| | | switch (flag) { |
| | | case EUserType.Web: |
| | | router.push(ERouterName.PROJECT) |
| | | break |
| | | case EUserType.Pilot: |
| | | router.push(ERouterName.PILOT) |
| | | break |
| | | } |
| | | } |
| | | return Promise.reject(err) |
| | | }, |
| | | ) |
| | |
| | | pagination: IPage; |
| | | }; |
| | | } |
| | | // 接口返回参数字段 |
| | | interface Field<T> { |
| | | code: number |
| | | data: T, |
| | | message: string |
| | | success: boolean |
| | | } |
| | | // Workspace |
| | | export interface IWorkspaceResponse<T> { |
| | | code: number; |
| | | data: Field<T>; |
| | | message: string; |
| | | success:boolean; |
| | | code: number; |
| | | data: T; |
| | | message: string; |
| | | } |
| | | |
| | | export type IStatus = 'WAITING' | 'DOING' | 'SUCCESS' | 'FAILED'; |
| | |
| | | import request, { CommonListResponse, IListWorkspaceResponse, IPage, IWorkspaceResponse } from '/@/api/http/request' |
| | | import { Device } from '/@/types/device' |
| | | |
| | | const HTTP_PREFIX = 'api/system' |
| | | const HTTP_PREFIX_MANAGE='api/drone' |
| | | const HTTP_PREFIX = '/manage/api/v1' |
| | | const HTTP_PREFIX_MANAGE = 'api/drone' |
| | | |
| | | // login |
| | | export interface LoginBody { |
| | | username: string, |
| | | password: string, |
| | | username: string, |
| | | password: string, |
| | | flag: number |
| | | } |
| | | export interface BindBody { |
| | | device_sn: string, |
| | |
| | | } |
| | | |
| | | export const login = async function (body: LoginBody): Promise<IWorkspaceResponse<any>> { |
| | | const url = 'api/system/auth/login/password' |
| | | const url = `${HTTP_PREFIX}/login` |
| | | const result = await request.post(url, body) |
| | | return result.data |
| | | } |
| | |
| | | return result.data |
| | | } |
| | | |
| | | // edit Platform info |
| | | export const editPlatformInfo = async function (params:any): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX}/workspaces/update` |
| | | const result = await request.post(url, params) |
| | | return result.data |
| | | } |
| | | |
| | | // add Platform info |
| | | export const addPlatformInfo = async function (params:any): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX}/workspaces/add` |
| | | const result = await request.post(url, params) |
| | | return result.data |
| | | } |
| | | |
| | | // delete Platform info |
| | | export const delPlatformInfo = async function (id:any): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX}/workspaces/delete?id=${id}` |
| | | const result = await request.post(url, { id }) |
| | | return result.data |
| | | } |
| | | |
| | | // Get Platform |
| | | export const getPlatform = async function (params:any, page:number, pageSize:number): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX}/workspaces/list` |
| | | const result = await request.get(url, { params: { ...params, page, pageSize } }) |
| | | return result.data |
| | | } |
| | | |
| | | // Get User Info |
| | | export const getUserInfo = async function (): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX}/users/current` |
| | |
| | | // 获取在线设备信息 |
| | | export const getDeviceTopo = async function (params:any): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX_MANAGE}/manage/device` |
| | | const result = await request.get(url,{params}) |
| | | const result = await request.get(url, { params }) |
| | | return result.data |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | export const getUserPage = async function (params: any, body: IPage): Promise<CommonListResponse<any>> { |
| | | |
| | | console.log(params,"++++++++++++++") |
| | | console.log(params, '++++++++++++++') |
| | | |
| | | const url = `${HTTP_PREFIX}/user/page` |
| | | const result = await request.get(url,{params:{...params,pageNum:body.current,pageSize:body.size}}) |
| | | const result = await request.get(url, { params: { ...params, pageNum: body.current, pageSize: body.size } }) |
| | | return result.data |
| | | } |
| | | |
| | | |
| | | |
| | | export const updateUserInfo = async function (wid: string, user_id: string, body: {}): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX}/users/${wid}/users/${user_id}` |
| | |
| | | */ |
| | | export const getDeviceList = async function (params:any): Promise<IListWorkspaceResponse<Device>> { |
| | | const url = `${HTTP_PREFIX}/manage/device/getPage` |
| | | const result = await request.get(url,{params}) |
| | | const result = await request.get(url, { params }) |
| | | return result.data |
| | | } |
| | | |
| | | |
| | | |
| | | export const updateDevice = async function (body: {}, workspace_id: string, device_sn: string): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX}/devices/${workspace_id}/devices/${device_sn}` |
| | |
| | | // Get Wayline Files |
| | | export const getWaylineFiles = async function (params:any): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX}/waylineFile/getList` |
| | | const result = await request.get(url,{ params }) |
| | | const result = await request.get(url, { params }) |
| | | return result.data |
| | | } |
| | | |
| | |
| | | breakContinue: number |
| | | } |
| | | |
| | | |
| | | |
| | | // 新增计划 |
| | | export const createPlan = async function (plan:any): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX}/waylineJob/add` |
| | |
| | | // 获取计划列表(分页) |
| | | export const getWaylineJobs = async function (workspaceId: string, page: IPage): Promise<IListWorkspaceResponse<Task>> { |
| | | const url = `${HTTP_PREFIX}/waylineJob/getPage` |
| | | const result = await request.get(url,{params:{workspaceId}}) |
| | | const result = await request.get(url, { params: { workspaceId } }) |
| | | return result.data |
| | | } |
| | | |
| | |
| | | export const importKmzFile = async function (workspaceId: string, file: {}): Promise<IWorkspaceResponse<any>> { |
| | | const url = `${HTTP_PREFIX}/waylineFile/upload` |
| | | const result = await request.post(url, file, { |
| | | params:{ |
| | | params: { |
| | | projectId: workspaceId |
| | | }, |
| | | headers: { |
| | |
| | | import { DEFAULT_PLACEHOLDER } from '/@/utils/constants' |
| | | import {Task, waylineJob} from '/@/api/wayline' |
| | | import { Task, waylineJob } from '/@/api/wayline' |
| | | import { TaskStatusColor, TaskStatusMap, TaskTypeMap, OutOfControlActionMap, MediaStatusMap, MediaStatusColorMap, MediaStatus } from '/@/types/task' |
| | | import { isNil } from 'lodash' |
| | | |
| | |
| | | import { onMounted, onUnmounted } from 'vue' |
| | | import ReconnectingWebSocket from 'reconnecting-websocket' |
| | | import ConnectWebSocket, { MessageHandler } from '/@/websocket' |
| | | import { getWebsocketUrl, getMyWebSocketUrl } from '/@/websocket/util/config' |
| | | import { getWebsocketUrl } from '/@/websocket/util/config' |
| | | |
| | | /** |
| | | * 接收一个message函数 |
| | | * @param messageHandler |
| | | */ |
| | | export function useConnectWebSocket (messageHandler: MessageHandler) { |
| | | const webSocket = new ConnectWebSocket(getMyWebSocketUrl()) |
| | | const webSocket = new ConnectWebSocket(getWebsocketUrl()) |
| | | |
| | | onMounted(() => { |
| | | webSocket?.registerMessageHandler(messageHandler) |
| | |
| | | } |
| | | } |
| | | // 监听ws 消息 |
| | | // useConnectWebSocket(messageHandler) |
| | | useConnectWebSocket(messageHandler) |
| | | |
| | | onMounted(() => { |
| | | const token = localStorage.getItem(ELocalStorageKey.Token) |
| | |
| | | const root = getRoot() |
| | | |
| | | const formState: UnwrapRef<LoginBody> = reactive({ |
| | | username: 'admin', |
| | | password: 'Yes@!#$20230523', |
| | | // flag: EUserType.Web, |
| | | username: 'adminPC', |
| | | password: 'adminPC', |
| | | flag: EUserType.Web, |
| | | }) |
| | | |
| | | const loginBtnDisabled = computed(() => { |
| | | return !formState.username || !formState.password |
| | | }) |
| | | |
| | | const onSubmit = async (e: any) => { |
| | | const password = encrypt(formState.password) |
| | | const result = await login({ ...formState, password }) |
| | | if (result.success) { |
| | | localStorage.setItem(ELocalStorageKey.Token, result.data.token) |
| | | localStorage.setItem(ELocalStorageKey.Username, result.data.user.username) |
| | | localStorage.setItem(ELocalStorageKey.UserInfo, JSON.stringify(result.data.user)) |
| | | root.$router.push(ERouterName.PROJECT_LIST) |
| | | const onSubmit = async () => { |
| | | // const password = encrypt(formState.password) |
| | | const result = await login(formState) |
| | | if (result.code === 0) { |
| | | localStorage.setItem(ELocalStorageKey.Token, result.data.access_token) |
| | | localStorage.setItem(ELocalStorageKey.WorkspaceId, result.data.workspace_id) |
| | | localStorage.setItem(ELocalStorageKey.Username, result.data.username) |
| | | localStorage.setItem(ELocalStorageKey.UserId, result.data.user_id) |
| | | localStorage.setItem(ELocalStorageKey.Flag, EUserType.Web.toString()) |
| | | root.$router.push(ERouterName.MEMBERS) |
| | | } else { |
| | | message.error(result.message) |
| | | } |
| | | } |
| | | |
| | | onMounted(() => { |
| | | // onSubmit() |
| | | }) |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | 机场 |
| | | </a-menu-item> |
| | | </a-menu> |
| | | |
| | | <div class="device-table-wrap table flex-display flex-column"> |
| | | <a-table :columns="columns" :data-source="data.device" :pagination="paginationProp" @change="refreshData" row-key="device_sn" :expandedRowKeys="expandRows" |
| | | :row-selection="rowSelection" :rowClassName="rowClassName" :scroll="{ x: '100%', y: 600 }" |
| | |
| | | </template> |
| | | </div> |
| | | </template> |
| | | |
| | | <template v-for="col in ['sn', 'workspace']" #[col]="{ text }" :key="col"> |
| | | <a-tooltip :title="text"> |
| | | <span>{{ text }}</span> |
| | |
| | | <template #status="{ text }"> |
| | | <span v-if="text" class="flex-row flex-align-center"> |
| | | <span class="mr5" style="width: 12px; height: 12px; border-radius: 50%; background-color: green;" /> |
| | | <span>Online</span> |
| | | <span>在线</span> |
| | | </span> |
| | | <span class="flex-row flex-align-center" v-else> |
| | | <span class="mr5" style="width: 12px; height: 12px; border-radius: 50%; background-color: red;" /> |
| | | <span>Offline</span> |
| | | <span>离线</span> |
| | | </span> |
| | | </template> |
| | | <!-- 操作 --> |
| | |
| | | <div class="editable-row-operations"> |
| | | <!-- 编辑态操作 --> |
| | | <div v-if="editableData[record.device_sn]"> |
| | | <a-tooltip title="Confirm changes"> |
| | | <a-tooltip title="保存"> |
| | | <span @click="save(record)" style="color: #28d445;"><CheckOutlined /></span> |
| | | </a-tooltip> |
| | | <a-tooltip title="Modification canceled"> |
| | | <a-tooltip title="取消"> |
| | | <span @click="() => delete editableData[record.device_sn]" style="color: #e70102;"><CloseOutlined /></span> |
| | | </a-tooltip> |
| | | </div> |
| | |
| | | <a-tooltip v-if="current.indexOf(EDeviceTypeName.Dock) !== -1" title="设备日志"> |
| | | <CloudServerOutlined @click="showDeviceLogUploadRecord(record)"/> |
| | | </a-tooltip> |
| | | <a-tooltip v-if="current.indexOf(EDeviceTypeName.Dock) !== -1" title="Hms Info"> |
| | | <a-tooltip v-if="current.indexOf(EDeviceTypeName.Dock) !== -1" title="Hms信息"> |
| | | <FileSearchOutlined @click="showHms(record)"/> |
| | | </a-tooltip> |
| | | <a-tooltip title="Edit"> |
| | | <a-tooltip title="编辑"> |
| | | <EditOutlined @click="edit(record)"/> |
| | | </a-tooltip> |
| | | <a-tooltip title="Delete"> |
| | | <a-tooltip title="删除"> |
| | | <DeleteOutlined @click="() => { deleteTip = true, deleteSn = record.device_sn }"/> |
| | | </a-tooltip> |
| | | </div> |
| | |
| | | |
| | | </a-table> |
| | | <a-modal v-model:visible="deleteTip" width="450px" :closable="false" centered :okButtonProps="{ danger: true }" @ok="unbind"> |
| | | <p class="pt10 pl20" style="height: 50px;">Delete device from workspace?</p> |
| | | <p class="pt10 pl20" style="height: 50px;">确定从项目中删除该设备吗?</p> |
| | | <template #title> |
| | | <div class="flex-row flex-justify-center"> |
| | | <span>Delete devices</span> |
| | | <span>确定</span> |
| | | </div> |
| | | </template> |
| | | </a-modal> |
| | |
| | | :device="currentDevice"> |
| | | </DeviceHmsDrawer> |
| | | </div> |
| | | |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import { ColumnProps, TableState } from 'ant-design-vue/lib/table/interface' |
| | | import { h, onMounted, reactive, ref, UnwrapRef } from 'vue' |
| | | import { IPage } from '/@/api/http/type' |
| | | import { BindBody, bindDevice, getBindingDevices, getDeviceList, unbindDevice, updateDevice } from '/@/api/manage' |
| | | import { BindBody, bindDevice, getBindingDevices, unbindDevice, updateDevice } from '/@/api/manage' |
| | | import { EDeviceTypeName, ELocalStorageKey } from '/@/types' |
| | | import { EditOutlined, CheckOutlined, CloseOutlined, DeleteOutlined, FileSearchOutlined, CloudServerOutlined } from '@ant-design/icons-vue' |
| | | import { Device, DeviceFirmwareStatusEnum } from '/@/types/device' |
| | |
| | | device: Device[] |
| | | } |
| | | |
| | | const loading = ref(true) |
| | | const loading = ref(false) |
| | | const deleteTip = ref<boolean>(false) |
| | | const deleteSn = ref<string>() |
| | | const columns: ColumnProps[] = [ |
| | | { title: '设备型号', dataIndex: 'deviceName', width: 100, className: 'titleStyle' }, |
| | | { title: '设备SN', dataIndex: 'deviceSn', width: 100, className: 'titleStyle', ellipsis: true, slots: { customRender: 'sn' } }, |
| | | { title: '设备型号', dataIndex: 'device_name', width: 100, className: 'titleStyle' }, |
| | | { title: '设备SN', dataIndex: 'device_sn', width: 100, className: 'titleStyle', ellipsis: true, slots: { customRender: 'sn' } }, |
| | | { |
| | | title: '设备组织名称', |
| | | dataIndex: 'nickname', |
| | |
| | | ellipsis: true, |
| | | slots: { customRender: 'nickname' } |
| | | }, |
| | | { title: '固件版本', dataIndex: 'firmwareVersion', width: 150, className: 'titleStyle', slots: { customRender: 'firmware_version' } }, |
| | | { title: '固件版本', dataIndex: 'firmware_version', width: 150, className: 'titleStyle', slots: { customRender: 'firmware_version' } }, |
| | | { title: '在线状态', dataIndex: 'status', width: 100, className: 'titleStyle', slots: { customRender: 'status' } }, |
| | | { |
| | | title: '所属项目', |
| | | dataIndex: 'workspaceName', |
| | | dataIndex: 'workspace_name', |
| | | width: 100, |
| | | className: 'titleStyle', |
| | | ellipsis: true, |
| | |
| | | return obj |
| | | } |
| | | }, |
| | | { title: '加入组织时间', dataIndex: 'boundTime', width: 150, sorter: (a: Device, b: Device) => a.bound_time.localeCompare(b.bound_time), className: 'titleStyle' }, |
| | | { title: '在线时间', dataIndex: 'loginTime', width: 150, sorter: (a: Device, b: Device) => a.login_time.localeCompare(b.login_time), className: 'titleStyle' }, |
| | | { title: '加入组织时间', dataIndex: 'bound_time', width: 150, sorter: (a: Device, b: Device) => a.bound_time.localeCompare(b.bound_time), className: 'titleStyle' }, |
| | | { title: '在线时间', dataIndex: 'login_time', width: 150, sorter: (a: Device, b: Device) => a.login_time.localeCompare(b.login_time), className: 'titleStyle' }, |
| | | { |
| | | title: '操作', |
| | | dataIndex: 'actions', |
| | |
| | | // 获取分页信息 |
| | | function getPaginationBody () { |
| | | return { |
| | | current: paginationProp.current, |
| | | size: paginationProp.pageSize |
| | | page: paginationProp.current, |
| | | page_size: paginationProp.pageSize |
| | | } as IPage |
| | | } |
| | | |
| | |
| | | useDeviceUpgradeEvent(onDeviceUpgradeWs) |
| | | |
| | | // 获取设备列表信息 |
| | | function getDevices (params:any) { |
| | | loading.value = true |
| | | const paginationBody = getPaginationBody() |
| | | |
| | | getDeviceList(Object.assign(params, paginationBody)).then(res => { |
| | | if (res.code !== 5000) { |
| | | function getDevices (domain: number, closeLoading?: boolean) { |
| | | if (!closeLoading) { |
| | | loading.value = true |
| | | } |
| | | getBindingDevices(workspaceId, getPaginationBody(), domain).then(res => { |
| | | if (res.code !== 0) { |
| | | loading.value = false |
| | | return |
| | | } |
| | | |
| | | console.log(res, '++++++++++') |
| | | const list = res.data.records |
| | | data.device = list |
| | | |
| | | const resData: Device[] = res.data.list |
| | | expandRows.value = [] |
| | | resData.forEach((val: any) => { |
| | | if (val.children) { |
| | | val.children = [val.children] |
| | | } |
| | | if (judgeCurrentType(EDeviceTypeName.Dock)) { |
| | | expandRows.value.push(val.device_sn) |
| | | } |
| | | }) |
| | | data.device = resData |
| | | paginationProp.total = res.data.pagination.total |
| | | paginationProp.current = res.data.pagination.page |
| | | paginationProp.pageSize = res.data.pagination.page_size |
| | | loading.value = false |
| | | }).catch(err => { |
| | | console.log('错误:', err) |
| | | }).catch(e => { |
| | | loading.value = false |
| | | }) |
| | | } |
| | |
| | | } |
| | | |
| | | onMounted(() => { |
| | | // getDevices(current.value[0]) |
| | | getDevices(current.value[0]) |
| | | }) |
| | | </script> |
| | | |
| | |
| | | user_id: string |
| | | username: string |
| | | organization_name: string |
| | | workspace_name: string |
| | | project: string |
| | | create_time: string |
| | | user_role: string |
| | |
| | | } |
| | | const workspaceId: string = localStorage.getItem(ELocalStorageKey.WorkspaceId)! |
| | | const store = useMyStore() |
| | | const projectId:string = store.state.common.projectId |
| | | |
| | | onMounted(() => { |
| | | getAllUsers({ projectId }, body) |
| | | getAllUsers(workspaceId, body) |
| | | }) |
| | | |
| | | function refreshData (page: Pagination) { |
| | | body.page = page?.current! |
| | | body.page_size = page?.pageSize! |
| | | getAllUsers({ projectId }, body) |
| | | getAllUsers(workspaceId, body) |
| | | } |
| | | |
| | | function getAllUsers (params:any, page: IPage) { |
| | | getUserPage(params, page).then(res => { |
| | | const resData = res.data |
| | | data.member = resData.list |
| | | |
| | | paginationProp.total = resData.total |
| | | paginationProp.current = resData.pageNum |
| | | }).catch(err => { |
| | | console.log(err) |
| | | function getAllUsers (workspaceId: string, page: IPage) { |
| | | getAllUsersInfo(workspaceId, page).then(res => { |
| | | const userList: Member[] = res.data.list |
| | | data.member = userList |
| | | paginationProp.total = res.data.pagination.total |
| | | paginationProp.current = res.data.pagination.page |
| | | }) |
| | | } |
| | | |
| | |
| | | <a-form-item label="项目名称" :name="FormProject.PROJECT_NAME"> |
| | | <a-input v-model:value="formState[FormProject.PROJECT_NAME]" placeholder="项目名称" /> |
| | | </a-form-item> |
| | | <a-form-item label="平台名称" :name="FormProject.PLATFORMNAME"> |
| | | <a-input v-model:value="formState[FormProject.PLATFORMNAME]" placeholder="平台名称" /> |
| | | </a-form-item> |
| | | <a-form-item label="绑定编码" :name="FormProject.BINDCODE"> |
| | | <a-input v-model:value="formState[FormProject.BINDCODE]" placeholder="绑定编码" /> |
| | | </a-form-item> |
| | | <a-form-item label="项目简介" :name="FormProject.PROJCECT_INTRO"> |
| | | <a-textarea :auto-size="{ minRows: 4, maxRows: 8 }" type="textarea" |
| | | v-model:value="formState[FormProject.PROJCECT_INTRO]" placeholder="项目简介" /> |
| | | </a-form-item> |
| | | <a-form-item> |
| | | <!-- <a-form-item> |
| | | <div class="application flex-display flex-align-center flex-justify-between"> |
| | | <p>申请码加入项目</p> |
| | | <div class="btn dis_opticy"> |
| | |
| | | </div> |
| | | <div class="latitude" v-if="latitude && latitude != 0"> |
| | | 经纬度:{{ latitude }}°N {{ longitude }}°E</div> |
| | | </a-form-item> |
| | | </a-form-item> --> |
| | | </a-form> |
| | | <WeatherDrawer v-model:show="drawerConfig.weatherDrawer" title="以下设置仅在当前项目中生效"> |
| | | <!-- <WeatherDrawer v-model:show="drawerConfig.weatherDrawer" title="以下设置仅在当前项目中生效"> |
| | | <ComWeather v-model="formState" /> |
| | | </WeatherDrawer> |
| | | <WeatherDrawer v-model:show="drawerConfig.userDrawer" title="添加成员"> |
| | | <ComUser v-model="formState" /> |
| | | </WeatherDrawer> |
| | | </WeatherDrawer> --> |
| | | </div> |
| | | <div class="fix-button"> |
| | | <a-button @click="submit" style="width: 100%;height: 36px;justify-content: center;" |
| | |
| | | import { Form, message } from 'ant-design-vue' |
| | | import { cloneDeep } from 'lodash' |
| | | import { add, detail, edit as projectEdit } from '/@/api/project-page/index' |
| | | import { getPlatformInfo, editPlatformInfo, addPlatformInfo } from '/@/api/manage' |
| | | import { addPoint } from '/@/hooks/use-center-point' |
| | | import { useMyStore } from '/@/store/index' |
| | | const { appContext } = getCurrentInstance() |
| | |
| | | }) |
| | | const formState = ref<FormState>({ |
| | | [FormProject.PROJECT_NAME]: '', |
| | | [FormProject.PROJECT_STATUS]: '', |
| | | // [FormProject.PROJECT_STATUS]: '', |
| | | [FormProject.BINDCODE]: '', |
| | | [FormProject.PROJCECT_INTRO]: '', |
| | | [FormProject.LONGITUDE]: null, |
| | | [FormProject.LATITUDE]: null, |
| | | [FormProject.USERLIST]: [], |
| | | [FormProject.PROJECT_BLOCKING]: { |
| | | [blocking.CLOUDBLOCKINGCONFIGENABLE]: '1', |
| | | [blocking.WEATHERREPORTENABLE]: '1', |
| | | [blocking.WINDSPEED]: 12, |
| | | [blocking.WINDSPEEDREPORT]: 15, |
| | | [blocking.RAIN]: 3 |
| | | } |
| | | [FormProject.PLATFORMNAME]: '', |
| | | }) |
| | | const drawerConfig = ref({ |
| | | userDrawer: false, |
| | |
| | | // 获取项目详情 |
| | | const getDetail = async () => { |
| | | if (!route.query.id) return |
| | | const id = route.query.id |
| | | const res = await detail(id) |
| | | if (res.code !== 5000) return |
| | | const res = await getPlatformInfo() |
| | | console.log(res, '项目详情') |
| | | if (res.code !== 0) return |
| | | formState.value = res.data |
| | | addPoint(global.$viewer, res.data.id, res.data.latitude, res.data.latitude) |
| | | store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: formState.value.latitude, longitude: formState.value.longitude }) |
| | | // addPoint(global.$viewer, res.data.id, res.data.latitude, res.data.latitude) |
| | | // store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: formState.value.latitude, longitude: formState.value.longitude }) |
| | | } |
| | | // 编辑项目 |
| | | const editProject = async () => { |
| | | const res = await projectEdit(formState.value) |
| | | if (res.code !== 5000) return |
| | | const res = await editPlatformInfo(formState.value) |
| | | if (res.code !== 0) return |
| | | message.success('修改成功') |
| | | router.go(-1) |
| | | store.commit('SET_CENTER_CONFIG_TYPE', false) |
| | | store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: null, longitude: null }) |
| | | // store.commit('SET_CENTER_CONFIG_TYPE', false) |
| | | // store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: null, longitude: null }) |
| | | } |
| | | // 新增项目 |
| | | const addProject = async () => { |
| | | const res = await add(formState.value) |
| | | if (res.code !== 5000) return |
| | | const res = await addPlatformInfo(formState.value) |
| | | if (res.code !== 0) return |
| | | message.success('保存成功') |
| | | router.go(-1) |
| | | store.commit('SET_CENTER_CONFIG_TYPE', false) |
| | | store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: null, longitude: null }) |
| | | // store.commit('SET_CENTER_CONFIG_TYPE', false) |
| | | // store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: null, longitude: null }) |
| | | } |
| | | const goBack = () => { |
| | | router.go(-1) |
| | | store.commit('SET_CENTER_CONFIG_TYPE', false) |
| | | store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: null, longitude: null }) |
| | | // store.commit('SET_CENTER_CONFIG_TYPE', false) |
| | | // store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: null, longitude: null }) |
| | | } |
| | | // 天气组飞侧边栏 |
| | | const openDrawer = (name: string) => { |
| | |
| | | } |
| | | // 表单验证提交 |
| | | const submit = () => { |
| | | formState.value[FormProject.LATITUDE] = latitude.value |
| | | formState.value[FormProject.LONGITUDE] = longitude.value |
| | | projectForm.value.validate().then(async () => { |
| | | if (route.query.id) { |
| | | editProject() |
| | |
| | | export enum FormProject { |
| | | PROJECT_NAME = 'projectName', |
| | | PROJECT_STATUS = 'projectStatus', |
| | | PROJCECT_INTRO = 'projectIntro', |
| | | LONGITUDE = 'longitude', |
| | | LATITUDE = 'latitude', |
| | | DEVICELIST = 'deviceList', |
| | | USERLIST = 'userList', |
| | | PROJECT_BLOCKING = 'projectBlocking', |
| | | PROJECT_NAME = 'workspace_name', |
| | | // PROJECT_STATUS = 'projectStatus', |
| | | PROJCECT_INTRO = 'workspace_desc', |
| | | PLATFORMNAME = 'platform_name', |
| | | BINDCODE = 'bind_code', |
| | | // LONGITUDE = 'longitude', |
| | | // LATITUDE = 'latitude', |
| | | // DEVICELIST = 'deviceList', |
| | | // USERLIST = 'userList', |
| | | // PROJECT_BLOCKING = 'projectBlocking', |
| | | } |
| | | export enum blocking { |
| | | WINDSPEED = 'windDevice', |
| | |
| | | } |
| | | export interface FormState { |
| | | [FormProject.PROJECT_NAME]: string |
| | | [FormProject.PROJECT_STATUS]: string |
| | | [FormProject.BINDCODE]: string |
| | | [FormProject.PROJCECT_INTRO]: string |
| | | [FormProject.LONGITUDE]?: number | null |
| | | [FormProject.LATITUDE]?: number | null |
| | | [FormProject.DEVICELIST]?: deviceList[] |
| | | [FormProject.USERLIST]: number[] |
| | | [FormProject.PROJECT_BLOCKING]: projectBlocking |
| | | [FormProject.PLATFORMNAME]: string |
| | | // [FormProject.PROJECT_STATUS]: string |
| | | // [FormProject.PROJCECT_INTRO]: string |
| | | // [FormProject.LONGITUDE]?: number | null |
| | | // [FormProject.LATITUDE]?: number | null |
| | | // [FormProject.DEVICELIST]?: deviceList[] |
| | | // [FormProject.USERLIST]: number[] |
| | | // [FormProject.PROJECT_BLOCKING]: projectBlocking |
| | | } |
| | | |
| | | /* |
| | |
| | | <div class="project-left" @click="goCenter(item, index)"> |
| | | <div class="head mb10 flex-display flex-align-center flex-justify-between"> |
| | | <div class="head-left flex-display flex-align-center"> |
| | | <a-tag color="#87d068">{{ status[item.projectStatus] }}</a-tag> |
| | | <span class="head-text">{{ item.projectName }}</span> |
| | | <a-tag color="#87d068">{{ status[item.projectStatus] || '进行中' }}</a-tag> |
| | | <span class="head-text">{{ item.workspace_name }}</span> |
| | | </div> |
| | | <div class="head-right"> |
| | | <a-dropdown> |
| | |
| | | </div> |
| | | </div> |
| | | <div class="wrapper"> |
| | | <div class="introduction mb10">{{ item.projectIntro || '暂无简介' }}</div> |
| | | <div class="introduction mb10">{{ item.workspace_desc || '暂无简介' }}</div> |
| | | <div class="time mb5">创建时间: {{ item.createTime }}</div> |
| | | <div class="manager mb5 flex-display flex-align-center"> |
| | | <user-outlined /> |
| | |
| | | import { ERouterName } from '/@/types/index' |
| | | import { status, projectCard } from './data' |
| | | import { del, edit } from '/@/api/project-page' |
| | | import { delPlatformInfo } from '/@/api/manage' |
| | | import { Modal, message } from 'ant-design-vue' |
| | | import { useMyStore } from '/@/store' |
| | | import { flyTo, isEntityExist } from '/@/hooks/use-center-point' |
| | |
| | | okType: 'danger', |
| | | cancelText: () => '取消', |
| | | onOk () { |
| | | del(item.id).then(res => { |
| | | if (res.code === 5000) { |
| | | delPlatformInfo(item.id).then(res => { |
| | | if (res.code === 0) { |
| | | message.success('删除成功') |
| | | emit('refreshList') |
| | | } |
| | |
| | | } |
| | | |
| | | const goDetail = (item: any) => { |
| | | console.log(item, 'item') |
| | | store.commit('SET_PROJECT_ID', item.id) |
| | | store.commit('SET_POINT_LIST', []) |
| | | router.push({ |
| | |
| | | export type projectCard={ |
| | | id:string |
| | | projectStatus:number |
| | | projectName:string |
| | | projectIntro:string |
| | | workspace_name:string |
| | | workspace_desc:string |
| | | createTime:string |
| | | memberList: Array<Menber> |
| | | [key:string]:any |
| | |
| | | <!-- |
| | | * @Author: husq 931347610@qq.com |
| | | * @Date: 2023-09-13 18:21:08 |
| | | * @LastEditors: husq 931347610@qq.com |
| | | * @LastEditTime: 2023-09-13 19:24:39 |
| | | * @FilePath: \Cloud-API-Demo-Web\src\pages\page-web\projects\project_list\list_page\list.vue |
| | | * @Description: |
| | | * |
| | | * Copyright (c) 2023 by ${git_name_email}, All Rights Reserved. |
| | | --> |
| | | <template> |
| | | <div class="project"> |
| | | <div class="side-header"> |
| | |
| | | </div> |
| | | <div class="border-bottom"></div> |
| | | </div> |
| | | <div class="side-filter-warp"> |
| | | <!-- <div class="side-filter-warp"> |
| | | <div class="side-filter flex-display flex-align-center flex-justify-between"> |
| | | <Select :bordered="false" :options="statusOption" v-model="params.projectStatus" @handleChange="handleChange" /> |
| | | <Select :bordered="false" :options="projectOption" v-model="params.project" @handleChange="handleChange" /> |
| | |
| | | </template> |
| | | </a-input> |
| | | </div> |
| | | </div> |
| | | </div> --> |
| | | <div class="wrap_card"> |
| | | <List @refreshList="init" v-model="spinning" :cardList="cardList"></List> |
| | | </div> |
| | |
| | | import { ERouterName } from '/@/types/enums' |
| | | import { statusOption, sortOption, projectOption, map, sortEnum } from './data' |
| | | import { getPage as getProjectPage } from '/@/api/project-page' |
| | | import { getPlatform } from '/@/api/manage' |
| | | import { PlusCircleOutlined, MonitorOutlined } from '@ant-design/icons-vue' |
| | | import { projectCard } from './components/data' |
| | | import { useMyStore } from '/@/store' |
| | |
| | | // 页面初始化 |
| | | const init = async () => { |
| | | spinning.value = true |
| | | const res = await getProjectPage(params.value).catch(e => { |
| | | const res = await getPlatform(params.value, 1, 20).catch(e => { |
| | | spinning.value = false |
| | | }) |
| | | cardList.value = res.data.records |
| | | const longitudeList = res.data.records.map((item: { id: string, longitude: any; latitude: any, projectName: string }) => { |
| | | console.log(res, '=====res=====') |
| | | cardList.value = res.data.list |
| | | const longitudeList = res.data.list.map((item: { id: string, longitude: any; latitude: any, projectName: string }) => { |
| | | return { |
| | | longitude: item.longitude, |
| | | latitude: item.latitude, |
| | |
| | | id: item.id |
| | | } |
| | | }) |
| | | store.commit('SET_POINT_LIST', longitudeList) |
| | | // store.commit('SET_POINT_LIST', longitudeList) |
| | | spinning.value = false |
| | | } |
| | | onMounted(() => { |
| | | init() |
| | | console.log(global, '+++++') |
| | | }) |
| | | </script> |
| | | |
| | |
| | | const routes: Array<RouteRecordRaw> = [ |
| | | { |
| | | path: '/', |
| | | redirect: '/' + ERouterName.LOGIN |
| | | redirect: '/' + ERouterName.MEMBERS |
| | | }, |
| | | // 首页 登陆页面 |
| | | { |
| | | path: '/' + ERouterName.LOGIN, |
| | | name: ERouterName.LOGIN, |
| | | component: () => import('/@/pages/page-web/index.vue') |
| | | }, |
| | | // // 首页 登陆页面 |
| | | // { |
| | | // path: '/' + ERouterName.LOGIN, |
| | | // name: ERouterName.LOGIN, |
| | | // component: () => import('/@/pages/page-web/index.vue') |
| | | // }, |
| | | // members, devices |
| | | { |
| | | path: '/' + ERouterName.HOME, |
| | |
| | | export enum ELocalStorageKey { |
| | | Username = 'username', |
| | | WorkspaceId = 'workspace_id', |
| | | Token = 'Authorization', |
| | | Token = 'x-auth-token', |
| | | PlatformName = 'platform_name', |
| | | WorkspaceName = 'workspace_name', |
| | | WorkspaceDesc = 'workspace_desc', |
| | |
| | | Immediate = 1, // 立即执行 |
| | | Timed = 2, // 单次定时任务 |
| | | RepeatTimed = 3, // 重复定时任务 |
| | | Continuous//连续执行 |
| | | Continuous// 连续执行 |
| | | } |
| | | |
| | | export const TaskTypeMap = { |
| | |
| | | { value: TaskType.Continuous, label: TaskTypeMap[TaskType.Continuous] }, |
| | | ] |
| | | |
| | | //频率类型 |
| | | // 频率类型 |
| | | export enum FrequencyType { |
| | | day = 1, // 日 |
| | | week = 2, // 周 |
| | |
| | | [FrequencyType.month]: '月', |
| | | } |
| | | |
| | | |
| | | export const FrequencyTypeOptions = [ |
| | | { value: FrequencyType.month, label: FrequencyTypeMap[FrequencyType.month]}, |
| | | { value: FrequencyType.month, label: FrequencyTypeMap[FrequencyType.month] }, |
| | | { value: FrequencyType.week, label: FrequencyTypeMap[FrequencyType.week] }, |
| | | { value: FrequencyType.day, label: FrequencyTypeMap[FrequencyType.day] }, |
| | | ] |
| | |
| | | [RepeatRuleType.week]: '按星期', |
| | | } |
| | | |
| | | export const RepeatRuleTypeOptions=[ |
| | | export const RepeatRuleTypeOptions = [ |
| | | { value: RepeatRuleType.day, label: RepeatRuleTypeMap[RepeatRuleType.day] }, |
| | | { value: RepeatRuleType.week, label: RepeatRuleTypeMap[RepeatRuleType.week] }, |
| | | ] |
| | | |
| | | export const WhichWeekOptions = [ |
| | | {value: 1, label: '第一个'}, |
| | | {value: 2, label: '第二个'}, |
| | | {value: 3, label: '第三个'}, |
| | | {value: 4, label: '第四个'}, |
| | | { value: 1, label: '第一个' }, |
| | | { value: 2, label: '第二个' }, |
| | | { value: 3, label: '第三个' }, |
| | | { value: 4, label: '第四个' }, |
| | | ] |
| | | export const WhichDayOptions = [ |
| | | {value: 7, label: '周日'}, |
| | | {value: 1, label: '周一'}, |
| | | {value: 2, label: '周二'}, |
| | | {value: 3, label: '周三'}, |
| | | {value: 4, label: '周四'}, |
| | | {value: 5, label: '周五'}, |
| | | {value: 6, label: '周六'}, |
| | | { value: 7, label: '周日' }, |
| | | { value: 1, label: '周一' }, |
| | | { value: 2, label: '周二' }, |
| | | { value: 3, label: '周三' }, |
| | | { value: 4, label: '周四' }, |
| | | { value: 5, label: '周五' }, |
| | | { value: 6, label: '周六' }, |
| | | ] |
| | | |
| | | |
| | | // 失控动作 |
| | | export enum OutOfControlAction { |
| | | ReturnToHome = 0, //返航 |
| | | Hover = 1, //盘旋 |
| | | Land = 2, //降落 |
| | | Continue//继续执行 |
| | | ReturnToHome = 0, // 返航 |
| | | Hover = 1, // 盘旋 |
| | | Land = 2, // 降落 |
| | | Continue// 继续执行 |
| | | } |
| | | |
| | | export const OutOfControlActionMap = { |
| | |
| | | ] |
| | | |
| | | export const FinishActionOptions = [ |
| | | {value:1,label:"自动返航"} |
| | | { value: 1, label: '自动返航' } |
| | | ] |
| | | |
| | | // 任务状态 |
| | |
| | | return url |
| | | } |
| | | |
| | | // 我们自己的webSocket逻辑 |
| | | export function getMyWebSocketUrl () { |
| | | const obj = JSON.parse(user) |
| | | const url = CURRENT_CONFIG.websocketURL + '/' + obj.id |
| | | return url |
| | | } |
| | | // // 我们自己的webSocket逻辑 |
| | | // export function getMyWebSocketUrl () { |
| | | // const obj = JSON.parse(user) |
| | | // const url = CURRENT_CONFIG.websocketURL + '/' + obj.id |
| | | // return url |
| | | // } |
| | |
| | | open: true, |
| | | host: '0.0.0.0', |
| | | port: 8080, |
| | | proxy: { |
| | | '/api': { |
| | | // 代理请求之后的请求地址(你的真实接口地址) |
| | | target: CURRENT_CONFIG.baseURL, |
| | | rewrite: path => path.replace(/^\/api/, ''), |
| | | // 跨域 |
| | | changeOrigin: true |
| | | } |
| | | } |
| | | // proxy: { |
| | | // '/api': { |
| | | // // 代理请求之后的请求地址(你的真实接口地址) |
| | | // target: CURRENT_CONFIG.baseURL, |
| | | // rewrite: path => path.replace(/^\/api/, ''), |
| | | // // 跨域 |
| | | // changeOrigin: true |
| | | // } |
| | | // } |
| | | }, |
| | | envDir: './env', |
| | | resolve: { |