diff --git a/src/api/wayline.ts b/src/api/wayline.ts index a917804..474e413 100644 --- a/src/api/wayline.ts +++ b/src/api/wayline.ts @@ -135,3 +135,9 @@ export const uploadMediaFileNow = async function (workspaceId: string, jobId: st const result = await request.post(url) return result.data } +// 获取指定航线 +export const getNevigationLine = async function (workspaceId: string, id: any): Promise<IWorkspaceResponse<{}>> { + const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/waylines/get/${id}` + const result = await request.get(url) + return result.data +} diff --git a/src/assets/icons/line.svg b/src/assets/icons/line.svg new file mode 100644 index 0000000..c06947d --- /dev/null +++ b/src/assets/icons/line.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1693968072497" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4876" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M796.444444 557.511111c-22.755556-45.511111-68.266667-73.955556-113.777777-73.955555H358.4c-39.822222 0-68.266667-28.444444-68.266667-68.266667v-28.444445c0-5.688889 0-17.066667 5.688889-28.444444 5.688889-28.444444 34.133333-51.2 68.266667-51.2h56.888889c17.066667 0 34.133333-17.066667 34.133333-34.133333s-22.755556-28.444444-39.822222-28.444445h-56.888889C295.822222 244.622222 244.622222 284.444444 227.555556 341.333333c0 17.066667-5.688889 28.444444-5.688889 45.511111v28.444445c0 73.955556 56.888889 130.844444 130.844444 130.844444H682.666667c22.755556 0 51.2 17.066667 62.577777 39.822223 5.688889 17.066667 11.377778 39.822222 11.377778 62.577777s-5.688889 39.822222-11.377778 56.888889c-11.377778 22.755556-34.133333 39.822222-62.577777 39.822222H312.888889c-5.688889-68.266667-62.577778-125.155556-130.844445-125.155555-73.955556 0-130.844444 56.888889-130.844444 130.844444s56.888889 130.844444 130.844444 130.844445c51.2 0 96.711111-28.444444 119.466667-73.955556H682.666667c51.2 0 96.711111-28.444444 119.466666-73.955555 11.377778-22.755556 17.066667-51.2 17.066667-85.333334s-5.688889-62.577778-22.755556-91.022222z m-551.822222 210.488889v5.688889c-5.688889 22.755556-34.133333 45.511111-62.577778 45.511111-39.822222 0-68.266667-34.133333-68.266666-68.266667 0-39.822222 28.444444-68.266667 68.266666-68.266666s68.266667 34.133333 68.266667 68.266666c0 5.688889 0 5.688889-5.688889 17.066667zM830.577778 142.222222c-73.955556 0-130.844444 56.888889-130.844445 130.844445 0 73.955556 56.888889 130.844444 130.844445 130.844444 73.955556 0 130.844444-56.888889 130.844444-130.844444 0-73.955556-56.888889-130.844444-130.844444-130.844445z m0 199.111111c-34.133333 0-68.266667-28.444444-68.266667-68.266666s28.444444-68.266667 68.266667-68.266667 68.266667 34.133333 68.266666 68.266667c0 39.822222-34.133333 68.266667-68.266666 68.266666z" fill="#cdcdcd" p-id="4877"></path><path d="M477.866667 273.066667c0 17.066667 11.377778 34.133333 34.133333 34.133333h130.844444c17.066667 0 34.133333-17.066667 34.133334-34.133333s-17.066667-34.133333-34.133334-34.133334H512c-17.066667 5.688889-34.133333 17.066667-34.133333 34.133334z" fill="#cdcdcd" p-id="4878"></path></svg> \ No newline at end of file diff --git a/src/components/GMap.vue b/src/components/GMap.vue index 762993f..03f5be0 100644 --- a/src/components/GMap.vue +++ b/src/components/GMap.vue @@ -20,6 +20,15 @@ <a style="color: red;"><CloseOutlined /></a> </div> </div> + <!-- 航线信息 --> + <div class="g-nevigation" v-if="nevigationVisible"> + <div class="nevigation-content"> + <div><div>航线长度</div><div>{{(nevigationInformation.line_length/1).toFixed(0)}}m</div></div> + <div><div>预计执行时间</div><div>{{getTime(nevigationInformation.scheduled_time)}}</div></div> + <div><div>航点</div><div>{{nevigationInformation.geometry_point_size}}</div></div> + <!-- <div><div>照片</div><div>4</div></div> --> + </div> + </div> <!-- 飞机OSD --> <div v-if="osdVisible.visible && !osdVisible.is_dock" class="osd-panel fz12"> <div style="opacity: 0.8;background: #000;"> @@ -556,7 +565,12 @@ export default defineComponent({ const osdVisible = computed(() => { return store.state.osdVisible }) - + const nevigationVisible = computed(() => { + return store.state.nevigationVisible + }) + const nevigationInformation = computed(() => { + return store.state.nevigationInformation + }) watch(() => store.state.deviceStatusEvent, data => { if (Object.keys(data.deviceOnline).length !== 0) { @@ -663,9 +677,9 @@ export default defineComponent({ function play () { // routeName.value = 'LiveOthers' showLive.value = !showLive.value - nextTick(() => { - showLive.value ? liveStreamRef.value.onStart() : liveStreamRef.value.onStop() - }) + if (!showLive.value) { + liveStreamRef.value.onStop() + } } // dock 控制面板 @@ -721,6 +735,7 @@ export default defineComponent({ // console.log(store.state.coverList) } async function postPolygonResource (obj) { + console.log(obj, 'hafhhaf') const req = getPoygonResource(obj) setLayers(req) updateCoordinates('gcj02-wgs84', req) @@ -839,7 +854,13 @@ export default defineComponent({ } } } - + function getTime (data:any) { + if (data >= 60) { + return `${(data / 60).toFixed()}m${(data % 60).toFixed()}s` + } else { + return `${data.toFixed()}s` + } + } return { draw, play, @@ -848,7 +869,10 @@ export default defineComponent({ // routeName, mouseMode, drawVisible, + nevigationInformation, + nevigationVisible, osdVisible, + getTime, pin, state, M30, @@ -874,7 +898,21 @@ export default defineComponent({ .g-map-wrapper { height: 100%; width: 100%; - + .g-nevigation{ + position: absolute; + bottom: 60px; + width: 100%; + .nevigation-content{ + display:flex; + justify-content: center; + color:#666; + font-weight: 500; + font-size:26px; + &>div{ + padding-right: 20px; + } + } + } .g-action-panel { position: absolute; top: 16px; @@ -911,10 +949,10 @@ export default defineComponent({ left: 10px; top: 10px; width: 480px; - /* background: #000; */ + background: #000; color: #fff; border-radius: 2px; - /* opacity: 0.8; */ + // opacity: 0.8; .content-padding{ padding:16px; .video-btn{ diff --git a/src/components/MediaPanel.vue b/src/components/MediaPanel.vue index 7a575f1..4496bdd 100644 --- a/src/components/MediaPanel.vue +++ b/src/components/MediaPanel.vue @@ -1,5 +1,5 @@ <template> - <div class="header"> + <div class="header" ref="headerRef"> <a-button type="primary" large class="btn-primary" @click='openFileDialog'>创建文件夹</a-button> <div v-show="state.selectedRowIds.length" class="other-btn"> <a-button large class="btn-primary">压缩并下载</a-button> @@ -56,7 +56,7 @@ <div class="bread-content"> <span v-for="(item,index) in breadList" :key="item" @click="jumpToPath(index)" :class="[index!=breadList.length-1?'tab-click':'']">{{ item }}<span v-if="index!=breadList.length-1" >/</span></span> </div> - <a-table :columns="columns" ref='tableRef' :data-source="mediaData.data" :scroll="{ x: '100%', y: 400 }" :row-selection="rowSelection"> + <a-table :columns="columns" ref='tableRef' :data-source="mediaData.data" :scroll="{ x: '100%', y:`calc(100vh - ${otherHeight}px)` }" :row-selection="rowSelection" :pagination="false"> <template v-for="col in ['file_name','payload','drone','create_time']" #[col]="{ text,index }" :key="col"> <div @click="goDetail(mediaData.data[index],index)" v-if="col=='file_name'"> <img src="../assets/icons/folder.svg" v-if='mediaData.data[index].file_type==0'> @@ -76,10 +76,16 @@ <div v-else>{{ text||'--' }}</div> </template> <template #action="{ record, index }"> - <a-tooltip title="download"> + <a-tooltip title="下载"> <a class="fz18 space" @click="downloadMedia(record)"><DownloadOutlined /></a> + </a-tooltip> + <a-tooltip title="编辑"> <a class="fz18 space" @click="editName(index)"><EditOutlined /></a> + </a-tooltip> + <a-tooltip title="删除"> <a class="fz18 space" @click="deleteRow(index)"><DeleteOutlined /></a> + </a-tooltip> + <a-tooltip title="移入"> <a class="fz18 space" @click="move(mediaData.data[index].id)"><LoginOutlined /></a> </a-tooltip> </template> @@ -145,6 +151,7 @@ const loading = ref(false) const searchParam = reactive({ timestamp: [], type: [], name: '' }) const state = reactive({ rowid: '', selectedRowIds: [], folderOpen: false, fileName: '新建文件夹', fatherId: 0, changeName: '', index: '', folderTree: false }) const tableRef = ref() +const headerRef = ref() // 面包屑对应的文件名 const breadList = ref(['全部文件']) // 面包屑对应的父级id @@ -195,6 +202,7 @@ const paginationProp = reactive({ total: 0 }) const treeList = ref([]) +const otherHeight = ref(0) const fieldNames = reactive({ children: 'children', title: 'file_name', @@ -229,6 +237,7 @@ onMounted(() => { const tableContainer = tableRef.value.$el.querySelector('.ant-table-body') tableContainer.addEventListener('scroll', handleScroll) } + getHeight() }) getFiles(workspaceId, paginationProp) }) @@ -362,7 +371,6 @@ const move = (id?:any) => { floderTreeData(workspaceId).then(res => { if (res.code === 0) { treeList.value = res.data - console.log(treeList.value, res.data, '1212') state.folderTree = true } }) @@ -370,7 +378,10 @@ const move = (id?:any) => { const selectTree = (seid:any, e:any) => { selectedKeys.value = e.node.dataRef.id } - +const getHeight = () => { + // 32表格padding值,60误差值 + otherHeight.value = document.querySelector('.header').offsetHeight + 32 + 60 + document.querySelector('.bread-content').offsetHeight +} </script> <style lang="scss" scoped> diff --git a/src/components/common/sidebar.vue b/src/components/common/sidebar.vue index 41f6bb7..2374249 100644 --- a/src/components/common/sidebar.vue +++ b/src/components/common/sidebar.vue @@ -53,12 +53,12 @@ export default defineComponent({ setup () { const root = getRoot() const options = [ - { key: 0, label: 'Tsa', path: '/' + ERouterName.TSA, icon: 'TeamOutlined' }, - { key: 1, label: 'Livestream', path: '/' + ERouterName.LIVESTREAM, icon: 'VideoCameraOutlined' }, - { key: 2, label: 'Annotations', path: '/' + ERouterName.LAYER, icon: 'EnvironmentOutlined' }, - { key: 3, label: 'Media Files', path: '/' + ERouterName.MEDIA, icon: 'PictureOutlined' }, - { key: 4, label: 'Flight Route Library', path: '/' + ERouterName.WAYLINE, icon: 'NodeIndexOutlined' }, - { key: 5, label: 'Task Plan Library', path: '/' + ERouterName.TASK, icon: 'CalendarOutlined' } + { key: 0, label: '团队', path: '/' + ERouterName.TSA, icon: 'TeamOutlined' }, + { key: 1, label: '直播', path: '/' + ERouterName.LIVESTREAM, icon: 'VideoCameraOutlined' }, + { key: 2, label: '标注', path: '/' + ERouterName.LAYER, icon: 'EnvironmentOutlined' }, + { key: 3, label: '媒体库', path: '/' + ERouterName.MEDIA, icon: 'PictureOutlined' }, + { key: 4, label: '航线库', path: '/' + ERouterName.WAYLINE, icon: 'NodeIndexOutlined' }, + { key: 5, label: '计划库', path: '/' + ERouterName.TASK, icon: 'CalendarOutlined' } ] function selectedRoute (item: IOptions) { diff --git a/src/components/common/topbar.vue b/src/components/common/topbar.vue index 4f0bff3..69e4462 100644 --- a/src/components/common/topbar.vue +++ b/src/components/common/topbar.vue @@ -27,7 +27,7 @@ <a-menu theme="dark" class="flex-column flex-justify-between flex-align-center"> <a-menu-item> <span class="mr10" style="font-size: 16px;"><ExportOutlined /></span> - <span @click="logout">Log Out</span> + <span @click="logout">退出登录</span> </a-menu-item> </a-menu> </template> diff --git a/src/components/livestream-newOthers.vue b/src/components/livestream-newOthers.vue index 307913e..e4c595d 100644 --- a/src/components/livestream-newOthers.vue +++ b/src/components/livestream-newOthers.vue @@ -195,7 +195,6 @@ const onRefresh = async () => { videoSelected.value = null await getLiveSnCapacity(osdVisible.value.sn) .then(res => { - console.log(res) if (res.code === 0) { if (res.data === null) { console.warn('warning: get live capacity is null!!!') @@ -210,8 +209,9 @@ const onRefresh = async () => { livestreamSource.value.forEach((ele: any) => { temp.push({ label: ele.name + '-' + ele.sn, value: ele.sn, more: ele.cameras_list }) }) - droneSelected.value = temp[0].value + // droneSelected.value = temp[0].value } + onStart() } }) .catch(error => { diff --git a/src/components/task/CreatePlan.vue b/src/components/task/CreatePlan.vue index 21006d8..d4c69c0 100644 --- a/src/components/task/CreatePlan.vue +++ b/src/components/task/CreatePlan.vue @@ -1,20 +1,20 @@ <template> <div class="create-plan-wrapper"> <div class="header"> - Create Plan + 新建计划 </div> <div class="content"> <a-form ref="valueRef" layout="horizontal" :hideRequiredMark="true" :rules="rules" :model="planBody" labelAlign="left"> - <a-form-item label="Plan Name" name="name" :labelCol="{span: 23}"> - <a-input style="background: black;" placeholder="Please enter plan name" v-model:value="planBody.name"/> + <a-form-item label="计划名称" name="name" :labelCol="{span: 23}"> + <a-input style="background: black;" placeholder="请输入名称" v-model:value="planBody.name"/> </a-form-item> <!-- 航线 --> - <a-form-item label="Flight Route" :wrapperCol="{offset: 7}" name="file_id"> + <a-form-item label="航线" :wrapperCol="{offset: 15}" name="file_id"> <router-link :to="{name: 'select-plan'}" @click="selectRoute" > - Select Route + 选择航线 </router-link> </a-form-item> <a-form-item v-if="planBody.file_id" style="margin-top: -15px;"> @@ -37,16 +37,16 @@ </span> </div> <div class="mt5 ml10" style="color: hsla(0,0%,100%,0.35);"> - <span class="mr10">Update at {{ new Date(wayline.update_time).toLocaleString() }}</span> + <span class="mr10">更新时间 {{ new Date(wayline.update_time).toLocaleString() }}</span> </div> </div> </a-form-item> <!-- 设备 --> - <a-form-item label="Device" :wrapperCol="{offset: 10}" v-model:value="planBody.dock_sn" name="dock_sn"> + <a-form-item label="设备" :wrapperCol="{offset: 15}" v-model:value="planBody.dock_sn" name="dock_sn"> <router-link :to="{name: 'select-plan'}" @click="selectDevice" - >Select Device</router-link> + >选择设备</router-link> </a-form-item> <a-form-item v-if="planBody.dock_sn" style="margin-top: -15px;"> <div class="panel" style="padding-top: 5px;" @click="selectDock(dock)"> @@ -62,7 +62,7 @@ </div> </a-form-item> <!-- 任务类型 --> - <a-form-item label="Plan Timer" class="plan-timer-form-item" :labelCol="{span: 23}"> + <a-form-item label="计划时间" class="plan-timer-form-item" :labelCol="{span: 23}"> <div style="white-space: nowrap;"> <a-radio-group v-model:value="planBody.task_type" button-style="solid"> <a-radio-button v-for="type in TaskTypeOptions" :value="type.value" :key="type.value">{{ type.label }}</a-radio-button> @@ -70,21 +70,21 @@ </div> </a-form-item> <!-- 执行时间 --> - <a-form-item label="Start Time" v-if="planBody.task_type === TaskType.Timed" name="select_execute_time" :labelCol="{span: 23}"> + <a-form-item label="开始时间" v-if="planBody.task_type === TaskType.Timed" name="select_execute_time" :labelCol="{span: 12}"> <a-date-picker v-model:value="planBody.select_execute_time" format="YYYY-MM-DD HH:mm:ss" show-time - placeholder="Select Time" + placeholder="选择时间" /> </a-form-item> <!-- RTH Altitude Relative to Dock --> - <a-form-item label="RTH Altitude Relative to Dock (m)" :labelCol="{span: 23}" name="rth_altitude"> + <a-form-item label="返航高度 (m)" :labelCol="{span: 23}" name="rth_altitude"> <a-input-number v-model:value="planBody.rth_altitude" :min="20" :max="1500" class="width-100" required> </a-input-number> </a-form-item> <!-- Lost Action --> - <a-form-item label="Lost Action" :labelCol="{span: 23}" name="out_of_control_action"> + <a-form-item label="失联动作" :labelCol="{span: 23}" name="out_of_control_action"> <div style="white-space: nowrap;"> <a-radio-group v-model:value="planBody.out_of_control_action" button-style="solid"> <a-radio-button v-for="action in OutOfControlActionOptions" :value="action.value" :key="action.value"> @@ -95,9 +95,9 @@ </a-form-item> <a-form-item class="width-100" style="margin-bottom: 40px;"> <div class="footer"> - <a-button class="mr10" style="background: #3c3c3c;" @click="closePlan">Cancel + <a-button class="mr10" style="background: #3c3c3c;" @click="closePlan">取消 </a-button> - <a-button type="primary" @click="onSubmit" :disabled="disabled">OK + <a-button type="primary" @click="onSubmit" :disabled="disabled">确认 </a-button> </div> </a-form-item> @@ -145,8 +145,8 @@ const disabled = ref(false) const routeName = ref('') const planBody = reactive({ name: '', - file_id: computed(() => store.state.waylineInfo.id), - dock_sn: computed(() => store.state.dockInfo.device_sn), + file_id: computed(() => store.state?.waylineInfo?.id), + dock_sn: computed(() => store.state?.dockInfo?.device_sn), task_type: TaskType.Immediate, select_execute_time: undefined as Moment| undefined, rth_altitude: '', @@ -157,17 +157,21 @@ const drawerVisible = ref(false) const valueRef = ref() const rules = { name: [ - { required: true, message: 'Please enter plan name.' }, - { max: 20, message: 'Length should be 1 to 20', trigger: 'blur' } + { required: true, message: '请输入计划名称' }, + { max: 20, message: '长度为1~20', trigger: 'blur' } ], - file_id: [{ required: true, message: 'Select Route' }], - dock_sn: [{ required: true, message: 'Select Device' }], - select_execute_time: [{ required: true, message: 'Select start time' }], + file_id: [{ required: true, message: '请选择航线' }], + dock_sn: [{ required: true, message: '请选择设备' }], + select_execute_time: [{ required: true, message: '请选择开始时间' }], rth_altitude: [ { validator: async (rule: RuleObject, value: string) => { - if (!/^[0-9]{1,}$/.test(value)) { - throw new Error('RTH Altitude Relative Require number') + if (!value) { + throw new Error('请输入返航导读') + } else { + if (!/^[0-9]{1,}$/.test(value)) { + throw new Error('请输入整数') + } } }, } @@ -266,7 +270,7 @@ function selectDevice () { .ant-radio-button-wrapper{ background-color: #232323; color: #fff; - width: 80%; + width: 70%; text-align: center; &.ant-radio-button-wrapper-checked{ background-color: #1890ff; diff --git a/src/components/task/TaskPanel.vue b/src/components/task/TaskPanel.vue index fd6a204..4060b6e 100644 --- a/src/components/task/TaskPanel.vue +++ b/src/components/task/TaskPanel.vue @@ -1,8 +1,8 @@ <template> - <div class="header">Task Plan Library</div> + <div class="header">计划库</div> <div class="plan-panel-wrapper"> <a-table class="plan-table" :columns="columns" :data-source="plansData.data" row-key="job_id" - :pagination="paginationProp" :scroll="{ x: '100%', y: 600 }" @change="refreshData"> + :pagination="paginationProp" :scroll="{ x: true, y: `calc(100vh - 196px)`}" @change="refreshData"> <!-- 执行时间 --> <template #duration="{ record }"> <div class="flex-row" style="white-space: pre-wrap"> @@ -53,7 +53,7 @@ {{ formatMediaTaskStatus(record).number }} <a-tooltip v-if="formatMediaTaskStatus(record).status === MediaStatus.ToUpload" placement="bottom" arrow-point-at-center > <template #title> - <div>Upload now</div> + <div>立即下载</div> </template> <UploadOutlined class="ml5" :style="{color: commonColor.BLUE, fontSize: '16px' }" @click="onUploadMediaFileNow(record.job_id)"/> </a-tooltip> @@ -70,7 +70,7 @@ cancel-text="No" @confirm="onDeleteTask(record.job_id)" > - <a-button type="primary" size="small">Delete</a-button> + <a-button type="primary" size="small">删除</a-button> </a-popconfirm> <a-popconfirm v-if="record.status === TaskStatus.Carrying" @@ -79,7 +79,7 @@ cancel-text="No" @confirm="onSuspendTask(record.job_id)" > - <a-button type="primary" size="small">Suspend</a-button> + <a-button type="primary" size="small">暂停</a-button> </a-popconfirm> <a-popconfirm v-if="record.status === TaskStatus.Paused" @@ -88,7 +88,7 @@ cancel-text="No" @confirm="onResumeTask(record.job_id)" > - <a-button type="primary" size="small">Resume</a-button> + <a-button type="primary" size="small">开始</a-button> </a-popconfirm> </div> </template> @@ -131,63 +131,63 @@ const paginationProp = reactive({ const columns = [ { - title: 'Planned/Actual Time', + title: '计划|实际时间', dataIndex: 'duration', width: 200, slots: { customRender: 'duration' }, }, { - title: 'Status', + title: '执行状态', key: 'status', width: 150, slots: { customRender: 'status' } }, { - title: 'Plan Name', + title: '计划名称', dataIndex: 'job_name', width: 100, }, { - title: 'Type', + title: '类型', dataIndex: 'taskType', width: 100, slots: { customRender: 'taskType' }, }, { - title: 'Flight Route Name', + title: '航线名称', dataIndex: 'file_name', width: 100, }, { - title: 'Dock Name', + title: '机场名称', dataIndex: 'dock_name', width: 100, ellipsis: true }, { - title: 'RTH Altitude Relative to Dock (m)', + title: '返航高度(m)', dataIndex: 'rth_altitude', width: 120, }, { - title: 'Lost Action', + title: '失联动作', dataIndex: 'out_of_control_action', width: 120, slots: { customRender: 'lostAction' }, }, { - title: 'Creator', + title: '创建者', dataIndex: 'username', width: 120, }, { - title: 'Media File Upload', + title: '媒体文件下载', key: 'media_upload', width: 160, slots: { customRender: 'media_upload' } }, { - title: 'Action', + title: '操作', width: 120, slots: { customRender: 'action' } } @@ -331,6 +331,7 @@ async function onUploadMediaFileNow (jobId: string) { .plan-table { background: #fff; margin-top: 10px; + width:100%; } .action-area { diff --git a/src/pages/page-web/index.vue b/src/pages/page-web/index.vue index 8616925..7b7b290 100644 --- a/src/pages/page-web/index.vue +++ b/src/pages/page-web/index.vue @@ -37,7 +37,7 @@ :disabled="loginBtnDisabled" @click="onSubmit" > - Login + 登录 </a-button> </a-form-item> </a-form> diff --git a/src/pages/page-web/projects/layer.vue b/src/pages/page-web/projects/layer.vue index c494a05..76fa96d 100644 --- a/src/pages/page-web/projects/layer.vue +++ b/src/pages/page-web/projects/layer.vue @@ -3,7 +3,7 @@ <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #4f4f4f; font-weight: 450;"> <a-row> <a-col :span="1"></a-col> - <a-col :span="22">Annotations</a-col> + <a-col :span="22">标注</a-col> <a-col :span="1"></a-col> </a-row> </div> @@ -18,7 +18,7 @@ /> </div> <a-drawer - title="Map Element" + title="标注信息" placement="right" :closable="true" v-model:visible="visible" @@ -29,7 +29,7 @@ > <div class="drawer-element-content"> <div class="name element-item"> - <span class="title">Name:</span> + <span class="title">名称:</span> <a-input v-model:value="layerState.layerName" style="width:120px" @@ -82,7 +82,7 @@ /> </div> <div class="color-content"> - <span class="mr30">Color: </span> + <span class="mr30">颜色: </span> <div v-for="item in colors" :key="item.id" @@ -99,7 +99,7 @@ </div> </div> <div class="flex-row flex-justify-around flex-align-center mt20"> - <a-button type="primary" @click="deleteElement">Delete</a-button> + <a-button type="primary" @click="deleteElement">删除</a-button> </div> </a-drawer> </div> diff --git a/src/pages/page-web/projects/task.vue b/src/pages/page-web/projects/task.vue index 3e83954..7f8a33e 100644 --- a/src/pages/page-web/projects/task.vue +++ b/src/pages/page-web/projects/task.vue @@ -3,7 +3,7 @@ <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #4f4f4f; font-weight: 450;"> <a-row> <a-col :span="1"></a-col> - <a-col :span="20">Task Plan Library</a-col> + <a-col :span="20">计划库</a-col> <a-col :span="2"> <span v-if="taskRoute"> <router-link :to="{ name: ERouterName.CREATE_PLAN}"> diff --git a/src/pages/page-web/projects/tsa.vue b/src/pages/page-web/projects/tsa.vue index 73690c5..11eb013 100644 --- a/src/pages/page-web/projects/tsa.vue +++ b/src/pages/page-web/projects/tsa.vue @@ -3,18 +3,18 @@ <div> <a-row> <a-col :span="1"></a-col> - <a-col :span="11">My Username</a-col> + <a-col :span="11">用户名</a-col> <a-col :span="11" align="right" style="font-weight: 700">{{ username }}</a-col> <a-col :span="1"></a-col> </a-row> </div> <div class="scrollbar" :style="{ height: scorllHeight + 'px'}"> <a-collapse :bordered="false" expandIconPosition="right" accordion style="background: #232323;"> - <a-collapse-panel :key="EDeviceTypeName.Dock" header="Dock" style="border-bottom: 1px solid #4f4f4f;"> + <a-collapse-panel :key="EDeviceTypeName.Dock" header="机场" style="border-bottom: 1px solid #4f4f4f;"> <div v-if="onlineDocks.data.length === 0" style="height: 150px; color: white;"> <a-empty :image="noData" :image-style="{ height: '60px' }" /> </div> - <div v-else class="fz12" style="color: white;"> + <div v-else class="fz12" style="color: white;"> <div v-for="dock in onlineDocks.data" :key="dock.sn" style="background: #3c3c3c; height: 90px; width: 250px; margin-bottom: 10px;"> <div style="border-radius: 2px; height: 100%; width: 100%;" class="flex-row flex-justify-between flex-align-center"> <div style="float: left; padding: 0px 5px 8px 8px; width: 88%"> @@ -137,11 +137,11 @@ </a-collapse-panel> </a-collapse> <a-collapse :bordered="false" expandIconPosition="right" accordion style="background: #232323;"> - <a-collapse-panel v-if='!onlineDevices.data.length' :key="EDeviceTypeName.Aircraft" header="Online Devices" style="border-bottom: 1px solid #4f4f4f;"> - <div style="height: 150px; color: white;"> + <a-collapse-panel :key="EDeviceTypeName.Aircraft" header="在线设备" style="border-bottom: 1px solid #4f4f4f;"> + <div style="height: 150px; color: white;" v-if='!onlineDevices.data.length' > <a-empty :image="noData" :image-style="{ height: '60px' }" /> </div> - <div class="fz12" style="color: white;" v-else> + <div v-else class="fz12" style="color: white;" > <div v-for="device in onlineDevices.data" :key="device.sn" style="background: #3c3c3c; height: 90px; width: 250px; margin-bottom: 10px;"> <div class="battery-slide" v-if="deviceInfo[device.sn]"> <div style="background: #535759; width: 100%;"></div> @@ -155,7 +155,7 @@ <div style="width: 100%; height: 100%;"> <a-tooltip> <template #title>{{ device.model ? `${device.model} - ${device.callsign}` : 'No Drone'}}</template> - <span class="text-hidden" style="max-width: 200px; display: block; height: 20px;">{{ device.model ? `${device.model} - ${device.callsign}` : 'No Drone'}}</span> + <span class="text-hidden" style="max-width: 200px; display: block; height: 20px;">{{ device.model ? `${device.model} - ${device.callsign}` : '暂无'}}</span> </a-tooltip> </div> <div class="mt5" style="background: #595959;"> diff --git a/src/pages/page-web/projects/wayline.vue b/src/pages/page-web/projects/wayline.vue index a9a7bc5..26e1fa4 100644 --- a/src/pages/page-web/projects/wayline.vue +++ b/src/pages/page-web/projects/wayline.vue @@ -4,7 +4,7 @@ <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #4f4f4f; font-weight: 450;"> <a-row> <a-col :span="1"></a-col> - <a-col :span="15">Flight Route Library</a-col> + <a-col :span="15">航线库</a-col> <a-col :span="8" v-if="importVisible" class="flex-row flex-justify-end flex-align-center"> <a-upload name="file" @@ -22,8 +22,8 @@ </div> <div :style="{ height : height + 'px'}" class="scrollbar"> <div id="data" class="height-100 uranus-scrollbar" v-if="waylinesData.data.length !== 0" @scroll="onScroll"> - <div v-for="wayline in waylinesData.data" :key="wayline.id"> - <div class="wayline-panel" style="padding-top: 5px;" @click="selectRoute(wayline)"> + <div v-for="(wayline,index) in waylinesData.data" :key="wayline.id"> + <div style="padding-top: 5px;" @click="selectRoute(wayline,index)" :class="[chooseIndex === index ? 'wayline-panel wayline-border':'wayline-panel']"> <div class="title"> <a-tooltip :title="wayline.name"> <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{ wayline.name }}</div> @@ -40,10 +40,10 @@ <template #overlay> <a-menu theme="dark" class="more" style="background: #3c3c3c;"> <a-menu-item @click="downloadWayline(wayline.id, wayline.name)"> - <span>Download</span> + <span>下载</span> </a-menu-item> <a-menu-item @click="showWaylineTip(wayline.id)"> - <span>Delete</span> + <span>删除</span> </a-menu-item> </a-menu> </template> @@ -58,8 +58,12 @@ {{ Object.keys(EDeviceType)[Object.values(EDeviceType).indexOf(payload)] }} </span> </div> - <div class="mt5 ml10" style="color: hsla(0,0%,100%,0.35);"> - <span class="mr10">Update at {{ new Date(wayline.update_time).toLocaleString() }}</span> + <div class="mt5 ml10 line-position" style="color: hsla(0,0%,100%,0.35);"> + <span class="mr10">更新时间 {{ new Date(wayline.update_time).toLocaleString() }}</span> + <a-tooltip> + <template #title>{{lineType[wayline.template_types[0]]}}</template> + <img class='line-img' :src="line" /> + </a-tooltip> </div> </div> </div> @@ -84,7 +88,8 @@ import { reactive } from '@vue/reactivity' import { message } from 'ant-design-vue' import { onMounted, onUpdated, ref } from 'vue' -import { deleteWaylineFile, downloadWaylineFile, getWaylineFiles, importKmzFile } from '/@/api/wayline' +import { onBeforeRouteLeave } from 'vue-router' +import { deleteWaylineFile, downloadWaylineFile, getWaylineFiles, importKmzFile, getNevigationLine } from '/@/api/wayline' import { ELocalStorageKey, ERouterName } from '/@/types' import { EllipsisOutlined, RocketOutlined, CameraFilled, UserOutlined, SelectOutlined } from '@ant-design/icons-vue' import { EDeviceType } from '/@/types/device' @@ -95,7 +100,10 @@ import { IPage } from '/@/api/http/type' import { CURRENT_CONFIG } from '/@/api/http/config' import { load } from '@amap/amap-jsapi-loader' import { getRoot } from '/@/root' - +import { wgs84togcj02 } from '/@/vendors/coordtransform' +import line from '/@/assets/icons/line.svg' +const lineType = ref(['航点飞行', '航点飞行', '建图航拍', '倾斜摄影', '带状航线']) +const polyline = ref() const loading = ref(false) const store = useMyStore() const pagination :IPage = { @@ -107,7 +115,7 @@ const pagination :IPage = { const waylinesData = reactive({ data: [] as WaylineFile[] }) - +const chooseIndex = ref() const root = getRoot() const workspaceId = localStorage.getItem(ELocalStorageKey.WorkspaceId)! const deleteTip = ref(false) @@ -184,9 +192,39 @@ function downloadWayline (waylineId: string, fileName: string) { loading.value = false }) } - -function selectRoute (wayline: WaylineFile) { +// 定位地图上对应的航线 +function selectRoute (wayline: WaylineFile, index:any) { + chooseIndex.value = index store.commit('SET_SELECT_WAYLINE_INFO', wayline) + const map = root.$map + if (polyline.value) { + map.remove(polyline.value) + } + getNevigationLine(workspaceId, wayline.id).then(res => { + if (res.code === 0) { + const path = res.data?.geometry.coordinates + path.forEach((item:any, index:any) => { + item = wgs84togcj02( + item[0], + item[1] + ) + }) + polyline.value = new root.$aMap.Polyline({ + path: path, + strokeWeight: 10, // 线条宽度,默认为 1 + strokeColor: '#3366bb', // 线条颜色 + lineJoin: 'round', + lineCap: 'round', + showDir: true // 折线拐点连接处样式 + }) + map.add(polyline.value) + map.setCenter(path[0]) + map.setZoom(12) + store.commit('SET_NEVIGATION_VISIBLE', true) + const { scheduled_time, line_length, geometry_point_size } = res.data + store.commit('SET_NEVIGATION_INFO', { scheduled_time, line_length, geometry_point_size }) + } + }) } function onScroll (e: any) { @@ -235,10 +273,19 @@ const uploadFile = async () => { }) }) } - +// 离开该组件清除航线相关信息 +onBeforeRouteLeave(() => { + if (polyline.value) { + root.$map.remove(polyline.value) + } + store.commit('SET_NEVIGATION_VISIBLE', false) +}) </script> <style lang="scss" scoped> +.wayline-border{ + border:1px solid #2b85e4; +} .wayline-panel { background: #3c3c3c; margin-left: auto; @@ -249,6 +296,9 @@ const uploadFile = async () => { font-size: 13px; border-radius: 2px; cursor: pointer; + &:hover{ + background: #666363; + } .title { display: flex; flex-direction: row; @@ -262,5 +312,15 @@ const uploadFile = async () => { overflow: auto; scrollbar-width: thin; scrollbar-color: #c5c8cc transparent; + .line-position{ + display: flex; + justify-content: space-between; + align-items: center; + .line-img{ + width:20px; + margin-right: 10px; + } + } + } </style> diff --git a/src/store/index.ts b/src/store/index.ts index d618c0f..dd06fda 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -32,6 +32,8 @@ const initStateFunc = () => ({ layerBaseInfo: {} as { [key:string]:string }, + nevigationVisible: false, + nevigationInformation: {}, // 航线信息 drawVisible: false, coverList: [ @@ -140,6 +142,13 @@ const mutations: MutationTree<RootStateType> = { SET_DRAW_VISIBLE_INFO (state, bool) { state.drawVisible = bool }, + SET_NEVIGATION_INFO (state, bool) { + console.log(bool, 'bool') + Object.assign(state.nevigationInformation, bool) + }, + SET_NEVIGATION_VISIBLE (state, bool) { + state.nevigationVisible = bool + }, SET_MAP_ELEMENT_CREATE (state, info) { state.wsEvent.mapElementCreat = info }, diff --git a/src/types/task.ts b/src/types/task.ts index b0cf295..caec0d1 100644 --- a/src/types/task.ts +++ b/src/types/task.ts @@ -7,8 +7,8 @@ export enum TaskType { } export const TaskTypeMap = { - [TaskType.Immediate]: 'Immediate', - [TaskType.Timed]: 'Timed', + [TaskType.Immediate]: '立即执行', + [TaskType.Timed]: '执行时间', } export const TaskTypeOptions = [ @@ -24,9 +24,9 @@ export enum OutOfControlAction { } export const OutOfControlActionMap = { - [OutOfControlAction.ReturnToHome]: 'Return to Home', - [OutOfControlAction.Hover]: 'Hover', - [OutOfControlAction.Land]: 'Land', + [OutOfControlAction.ReturnToHome]: '返航', + [OutOfControlAction.Hover]: '悬停', + [OutOfControlAction.Land]: '降落', } export const OutOfControlActionOptions = [