From 942e784e3127a2234a3a66c761d9876a01dd7dcc Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Wed, 16 Apr 2025 20:23:10 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'
---
src/views/TaskManage/TaskTop/TaskTime.vue | 1
src/views/Home/EventOverviewDetail/EventOverviewDetailRight.vue | 182 +++
src/api/home/machineNest.js | 83
src/views/Home/RSide.vue | 6
src/assets/images/newEndPointicon.png | 0
src/assets/images/home/useEventOperate/expand.png | 0
src/assets/images/task/publish.png | 0
src/hooks/components/DevicePopUpBox.vue | 0
src/hooks/useMapAggregation/useMapAggregation.js | 11
src/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventOverviewDetailLeft.vue | 44
src/views/Home/SearchBox.vue | 25
src/assets/images/home/useEventOperate/point.png | 0
src/hooks/useSingleDroneMap/useSingleDroneMap.js | 236 ++++
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceEvent.vue | 94 -
vite.config.mjs.timestamp-1744707003737-1868137d88f2d.mjs | 187 +++
src/store/modules/common.js | 4
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/MachineTableDetails.vue | 8
src/components/CommonDateTime.vue | 3
src/assets/images/aiNowFly/photo.png | 0
src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue | 15
src/views/Home/Footer.vue | 7
src/views/TaskManage/TaskIntermediateContent/TaskTable.vue | 337 +++---
src/layout/Header.vue | 5
src/assets/images/home/useEventOperate/close.png | 0
src/views/Home/HomeLeft/MachineNestList.vue | 10
src/hooks/components/EventPopUpBox.vue | 0
src/api/home/common.js | 8
src/assets/images/home/useEventOperate/offline.png | 0
src/views/SignMachineNest/SignMachineNest.vue | 169 +-
src/views/Home/AINowFly.vue | 188 ++-
.env.development | 2
src/assets/images/home/useEventOperate/point-active.png | 0
src/views/Home/HomeLeft/OverviewNext.vue | 23
src/assets/images/aiNowFly/stop.png | 0
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue | 22
src/views/TaskManage/TaskIntermediateContent/TaskMap.vue | 725 +++++++-------
src/assets/images/newStartPoint.png | 0
src/assets/images/task/cancel.png | 0
src/store/modules/home.js | 7
.env.production | 2
src/views/TaskManage/TaskIntermediateContent/AddTask.vue | 413 ++++---
src/api/home/event.js | 8
src/assets/images/newarrow-right.png | 0
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJob.vue | 16
44 files changed, 1,801 insertions(+), 1,040 deletions(-)
diff --git a/.env.development b/.env.development
index 029d374..4792921 100644
--- a/.env.development
+++ b/.env.development
@@ -11,3 +11,5 @@
# 航线文件地址
VITE_APP_AIRLINE_URL = https://wrj.shuixiongit.com/minio/cloud-bucket
+#系统运维
+VITE_APP_ADMIN_URL = 'https://wrj.shuixiongit.com/manage'
\ No newline at end of file
diff --git a/.env.production b/.env.production
index 4a0e953..d4914e6 100644
--- a/.env.production
+++ b/.env.production
@@ -5,3 +5,5 @@
VITE_BUILD_COMPRESS = gzip
# ws地址
VITE_APP_WS_API_URL = wss://wrj.shuixiongit.com/drone-wss/api/v1/ws
+# 管理后台地址
+VITE_APP_ADMIN_URL = ' https://aisky.org.cn/manage'
diff --git a/src/api/home/common.js b/src/api/home/common.js
index d1b21fe..2916599 100644
--- a/src/api/home/common.js
+++ b/src/api/home/common.js
@@ -25,18 +25,18 @@
params,
})
}
-// 机巢搜索
+// 地址搜索
export const searchByKeyword = params => {
return request({
url: `/drone-device-core/map/amap/searchByKeyword?keyword=${params}`,
method: 'get',
})
}
-// 地址搜索
-export const selectDeviceList = params => {
+// 机巢搜索
+export const selectDeviceList = data => {
return request({
url: `/drone-device-core/manage/api/v1/devices/selectDeviceList`,
method: 'post',
- params,
+ data: data,
})
}
diff --git a/src/api/home/event.js b/src/api/home/event.js
index 5f83f06..3d92f53 100644
--- a/src/api/home/event.js
+++ b/src/api/home/event.js
@@ -55,3 +55,11 @@
data,
})
}
+// 点击图片关联的事件历史图片列表
+export const findImgHistory = id => {
+ return request({
+ url: '/drone-device-core/jobEvent/findImgHistory?eventId='+id,
+ method: 'get',
+ })
+}
+
diff --git a/src/api/home/machineNest.js b/src/api/home/machineNest.js
index cc2c476..7c7cf8a 100644
--- a/src/api/home/machineNest.js
+++ b/src/api/home/machineNest.js
@@ -2,60 +2,69 @@
// 机巢统计
export const getDeviceInfoNum = params => {
- return request({
- url: '/drone-device-core/manage/api/v1/devices/getDeviceInfoNum',
- method: 'get',
- params,
- })
+ return request({
+ url: '/drone-device-core/manage/api/v1/devices/getDeviceInfoNum',
+ method: 'get',
+ params,
+ })
}
// 机巢列表
export const selectDevicePage = ({ nickname, ...params }) => {
- return request({
- url: `/drone-device-core/manage/api/v1/devices/selectDevicePage?type=${params.type}¤t=${params.current}&size=${params.size}`,
- method: 'post',
- data: {
- nickname,
- },
- })
+ return request({
+ url: `/drone-device-core/manage/api/v1/devices/selectDevicePage?type=${params.type}¤t=${params.current}&size=${params.size}`,
+ method: 'post',
+ data: {
+ nickname,
+ },
+ })
}
// 机巢数据
export const getFlightStatistics = dockSn => {
- return request({
- url: `/drone-device-core/manage/api/v1/devices/getFlightStatistics?dockSn=${dockSn}`,
- method: 'get',
- params: {},
- })
+ return request({
+ url: `/drone-device-core/manage/api/v1/devices/getFlightStatistics?dockSn=${dockSn}`,
+ method: 'get',
+ params: {},
+ })
}
// 机巢直播/无人机直播 均可使用
export const liveStart = (deviceSn, quality) => {
- return request({
- url: `/drone-device-core/manage/api/v1/live/streams/liveStart?deviceSn=${deviceSn}&quality=${quality}`,
- method: 'post',
- data: {},
- headers: {
- areaCode: '',
- },
- })
+ return request({
+ url: `/drone-device-core/manage/api/v1/live/streams/liveStart?deviceSn=${deviceSn}&quality=${quality}`,
+ method: 'post',
+ data: {},
+ headers: {
+ areaCode: '',
+ },
+ })
}
// 单个机巢获取机巢详情
export const getDeviceDetail = deviceSn => {
- return request({
- url: `/drone-device-core/manage/api/v1/devices/getDeviceDetail?deviceSn=${deviceSn}`,
- method: 'get',
- params: {},
- })
+ return request({
+ url: `/drone-device-core/manage/api/v1/devices/getDeviceDetail?deviceSn=${deviceSn}`,
+ method: 'get',
+ params: {},
+ })
}
// 设备-事件列表
-export const getDeviceEventList = (data,params) => {
- return request({
- url: `/drone-device-core/jobEvent/eventPage`,
- method: 'post',
- data,
- params
- })
+export const getDeviceEventList = (data, params) => {
+ return request({
+ url: `/drone-device-core/jobEvent/eventPage`,
+ method: 'post',
+ data,
+ params
+ })
}
+// 事件列表---点位上图
+export const getEventList = (data, params) => {
+ return request({
+ url: '/drone-device-core/jobEvent/eventList',
+ method: 'post',
+ data,
+ params
+ })
+}
diff --git a/src/assets/images/aiNowFly/photo.png b/src/assets/images/aiNowFly/photo.png
new file mode 100644
index 0000000..6139d5c
--- /dev/null
+++ b/src/assets/images/aiNowFly/photo.png
Binary files differ
diff --git a/src/assets/images/aiNowFly/stop.png b/src/assets/images/aiNowFly/stop.png
new file mode 100644
index 0000000..3213cee
--- /dev/null
+++ b/src/assets/images/aiNowFly/stop.png
Binary files differ
diff --git a/src/assets/images/home/useEventOperate/close.png b/src/assets/images/home/useEventOperate/close.png
new file mode 100644
index 0000000..d1b20a1
--- /dev/null
+++ b/src/assets/images/home/useEventOperate/close.png
Binary files differ
diff --git a/src/assets/images/home/useEventOperate/expand.png b/src/assets/images/home/useEventOperate/expand.png
new file mode 100644
index 0000000..4c19122
--- /dev/null
+++ b/src/assets/images/home/useEventOperate/expand.png
Binary files differ
diff --git a/src/assets/images/home/useEventOperate/offline.png b/src/assets/images/home/useEventOperate/offline.png
new file mode 100644
index 0000000..f80ee01
--- /dev/null
+++ b/src/assets/images/home/useEventOperate/offline.png
Binary files differ
diff --git a/src/assets/images/home/useEventOperate/point-active.png b/src/assets/images/home/useEventOperate/point-active.png
new file mode 100644
index 0000000..3f5c556
--- /dev/null
+++ b/src/assets/images/home/useEventOperate/point-active.png
Binary files differ
diff --git a/src/assets/images/home/useEventOperate/point.png b/src/assets/images/home/useEventOperate/point.png
new file mode 100644
index 0000000..b574793
--- /dev/null
+++ b/src/assets/images/home/useEventOperate/point.png
Binary files differ
diff --git a/src/assets/images/newEndPointicon.png b/src/assets/images/newEndPointicon.png
new file mode 100644
index 0000000..4856313
--- /dev/null
+++ b/src/assets/images/newEndPointicon.png
Binary files differ
diff --git a/src/assets/images/newStartPoint.png b/src/assets/images/newStartPoint.png
new file mode 100644
index 0000000..4845f58
--- /dev/null
+++ b/src/assets/images/newStartPoint.png
Binary files differ
diff --git a/src/assets/images/newarrow-right.png b/src/assets/images/newarrow-right.png
new file mode 100644
index 0000000..fd860a3
--- /dev/null
+++ b/src/assets/images/newarrow-right.png
Binary files differ
diff --git a/src/assets/images/task/cancel.png b/src/assets/images/task/cancel.png
new file mode 100644
index 0000000..8067a0a
--- /dev/null
+++ b/src/assets/images/task/cancel.png
Binary files differ
diff --git a/src/assets/images/task/publish.png b/src/assets/images/task/publish.png
new file mode 100644
index 0000000..5bbf106
--- /dev/null
+++ b/src/assets/images/task/publish.png
Binary files differ
diff --git a/src/components/CommonDateTime.vue b/src/components/CommonDateTime.vue
index 393e9b7..3876c6c 100644
--- a/src/components/CommonDateTime.vue
+++ b/src/components/CommonDateTime.vue
@@ -60,9 +60,8 @@
let timeClick = (item,index) => {
checked.value = item;
const newDateRange = dateRanges[item];
- store.commit('setEventTimeType', [checked.value, timeListEnum[index]]);
model.value = newDateRange;
- emit('change', newDateRange, timeListEnum[index]);
+ emit('change', newDateRange, timeListEnum[index],checked.value);
};
onMounted(() => {
// 如果父组件传入了值,就使用父组件的值 by cpz
diff --git a/src/hooks/useMapAggregation/DevicePopUpBox.vue b/src/hooks/components/DevicePopUpBox.vue
similarity index 100%
rename from src/hooks/useMapAggregation/DevicePopUpBox.vue
rename to src/hooks/components/DevicePopUpBox.vue
diff --git a/src/hooks/useMapAggregation/EventPopUpBox.vue b/src/hooks/components/EventPopUpBox.vue
similarity index 100%
rename from src/hooks/useMapAggregation/EventPopUpBox.vue
rename to src/hooks/components/EventPopUpBox.vue
diff --git a/src/hooks/useMapAggregation/useMapAggregation.js b/src/hooks/useMapAggregation/useMapAggregation.js
index 41d33ee..c3b229b 100644
--- a/src/hooks/useMapAggregation/useMapAggregation.js
+++ b/src/hooks/useMapAggregation/useMapAggregation.js
@@ -4,8 +4,8 @@
import uavImg from '@/assets/images/home/useUavHome/uavImg.png'
import eventSingle from '@/assets/images/home/useEventOperate/eventSingle.png'
-import DevicePopUpBox from '@/hooks/useMapAggregation/DevicePopUpBox.vue'
-import EventPopUpBox from '@/hooks/useMapAggregation/EventPopUpBox.vue'
+import DevicePopUpBox from '@/hooks/components/DevicePopUpBox.vue'
+import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue'
import { render } from 'vue'
import { useStore } from 'vuex'
@@ -137,14 +137,12 @@
if (arr.length !== 0) {
returnObj.childrens = arr
}
- console.log(returnObj, '111111')
return returnObj
})
}
// 获取事件聚合
function getMapEventCount (params) {
- console.log(5555555)
return getMapEvents(params).then(res => {
const resData = res?.data?.data
if (resData?.data) {
@@ -185,7 +183,6 @@
eventList = []
if (!areaCode) return
saveParams.area_code = areaCode
- console.log(type, '444')
const list = type === 'device' ? await getDeviceCount(areaCode) : await getMapEventCount(saveParams)
const splashedList = type === 'device'
? await getDeviceList(areaCode)
@@ -248,8 +245,6 @@
return
}
- handlerInit()
-
if (newValue.eventTimeType) {
saveParams = { area_code: newValue.selectedAreaCode, date_enum: store.state.home.eventTimeParams }
}
@@ -260,6 +255,8 @@
needFly = true
if (!viewer) return
+ handlerInit()
+
viewer.scene.postRender.removeEventListener(determineScaling)
initMapData(newValue.selectedAreaCode).then(() => {
diff --git a/src/hooks/useSingleDroneMap/useSingleDroneMap.js b/src/hooks/useSingleDroneMap/useSingleDroneMap.js
new file mode 100644
index 0000000..86c46b0
--- /dev/null
+++ b/src/hooks/useSingleDroneMap/useSingleDroneMap.js
@@ -0,0 +1,236 @@
+/*
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2025-04-15 22:41:40
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2025-04-16 18:38:00
+ * @FilePath: \command-center-dashboard\src\hooks\useSingleDroneMap\useSingleDroneMap.js
+ * @Description:
+ *
+ * Copyright (c) 2025 by shuishen, All Rights Reserved.
+ */
+import * as Cesium from 'cesium'
+import endingImg from '@/assets/images/aiNowFly/ending.png'
+import endingHighImg from '@/assets/images/aiNowFly/ending-high.png'
+
+/**
+ *
+ * @param {Object} options - 配置选项
+ */
+export function useSingleDroneMap (options = {
+ eventPositions: [],
+ eventApi: null,
+ eventApiParams: {}
+}) {
+ const { eventPositions, eventApi, eventApiParams } = options
+
+ let viewer = null
+ let handler = null
+ let currentEntity = null
+
+ // 初始化机场位置
+ const initDroneEntity = (dronePosition) => {
+ const { lng, lat, status } = dronePosition
+
+ if (!lng || !lat) return
+
+ const markerImg = status ? endingHighImg : endingImg
+ const position = Cesium.Cartesian3.fromDegrees(+lng, +lat, 0)
+
+ const droneEntity = viewer?.entities.add({
+ id: `single-drone-position`,
+ position: position,
+
+ billboard: {
+ image: new Cesium.ConstantProperty(markerImg),
+ width: 35,
+ height: 35,
+ },
+
+ ellipse: {
+ semiMinorAxis: 5000,
+ semiMajorAxis: 5000,
+ outline: true,
+ material: Cesium.Color.CORNFLOWERBLUE.withAlpha(0.3),
+ },
+
+ properties: {
+ customData: {
+ data: {
+ type: 'single-drone-event'
+ }
+ }
+ }
+ })
+
+ viewer?.flyTo(droneEntity, {
+ offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0),
+ duration: 0.5,
+ })
+ }
+
+ // 机巢事件地图撒点
+ const initDroneEventEntity = (eventPositions = eventPositions) => {
+ // 遍历特征并添加实体
+ eventPositions.length && eventPositions.forEach((item, index) => {
+ const { longitude, latitude, status, id } = item
+
+ const position = Cesium.Cartesian3.fromDegrees(+longitude, +latitude, 0)
+
+ viewer?.entities.add({
+ id: `single-drone-event-${index}`,
+ position: position,
+ billboard: {
+ image: new Cesium.ConstantProperty(endingHighImg),
+ width: 35,
+ height: 35,
+ },
+ properties: {
+ customData: {
+ data: {
+ type: 'single-drone-sign'
+ }
+ }
+ },
+ })
+ })
+ }
+
+ // 调用传入api
+ const initEventApiEntity = () => {
+ removeEventLayer()
+
+ eventApi(
+ {
+ ...eventApiParams,
+ }
+ ).then(res => {
+ const result = res.data.data.records
+
+ initDroneEventEntity(result)
+ })
+ }
+
+ // 事件地图撒点加载方式
+ const initEventLayer = () => {
+ eventApi ? initEventApiEntity() : initDroneEventEntity()
+ }
+
+ const removeEventLayer = () => {
+ // entities移除
+ const entitiesIDs = viewer?.entities.values.map(i => i.id)
+ entitiesIDs && entitiesIDs.forEach(item => {
+ item.includes('single-drone-event') && viewer?.entities.removeById(item)
+ })
+ }
+
+ // 移除当前地图所有entity
+ const removeLayer = () => {
+ // entities移除
+ const entitiesIDs = viewer?.entities.values.map(i => i.id)
+ entitiesIDs.forEach(item => {
+ item.includes('single-drone-') && viewer?.entities.removeById(item)
+ })
+ }
+
+ // 查找特定类型的实体
+ const findEntityByType = (entities, type) => {
+ return entities.find(entity =>
+ entity?.properties?.customData?._value?.data?.type === type
+ )
+ }
+
+ // 左键单机事件
+ const singleMachineEvent = async click => {
+ let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id)
+ if (!clickedEntities.length) return
+
+ const currentEntity = findEntityByType(clickedEntities, 'single-drone-event')
+
+ removeLabel()
+
+ if (currentEntity) {
+ viewer?.scene.postRender.addEventListener(labelBoxRender)
+ }
+ }
+
+ // 事件初始化
+ const handlerInit = () => {
+ if (handler) return
+
+ handler = new Cesium.ScreenSpaceEventHandler(viewer?.scene.canvas)
+ handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK)
+ }
+
+ // 事件移除
+ const removeHandler = () => {
+ handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
+ handler?.destroy()
+ handler = null
+ }
+
+ // 获取弹框box
+ const getLabelDom = data => {
+ const vNode = h(EventPopUpBox, { data, removeLabel })
+ const tooltipContainer = document.createElement('div')
+ tooltipContainer.id = 'mapPopUpBox'
+ tooltipContainer.style.position = 'absolute'
+ tooltipContainer.style.transform = styleTransform
+ tooltipContainer.style.pointerEvents = 'none'
+ document.querySelector('.page-index').append(tooltipContainer)
+ render(vNode, tooltipContainer)
+ return tooltipContainer
+ }
+
+ // 弹框位置刷新
+ const labelBoxRender = () => {
+ if (!currentEntity) return
+ let dom = document.querySelector('#mapPopUpBox')
+ if (!dom) {
+ dom = getLabelDom(currentEntity.properties.customData._value.data)
+ }
+ const screenPosition = viewer?.scene.cartesianToCanvasCoordinates(currentEntity?.position?._value)
+ if (screenPosition) {
+ dom.style.left = `${screenPosition.x}px`
+ dom.style.top = `${screenPosition.y}px`
+ dom.style.display = 'block'
+ }
+ }
+
+ const removeDom = () => {
+ const dom = document.querySelector('#mapPopUpBox')
+ if (dom && dom.parentNode) {
+ dom.parentNode.removeChild(dom)
+ }
+ }
+
+ // 移除弹框标签
+ const removeLabel = () => {
+ viewer?.scene.postRender.removeEventListener(labelBoxRender)
+ removeDom()
+ }
+
+
+ const init = () => {
+ viewer = window.$viewer
+
+ handlerInit()
+ }
+
+ const removeAll = () => {
+ removeLayer()
+ removeHandler()
+ removeLabel()
+ }
+
+ // 自动清理
+ onUnmounted(() => {
+ removeAll()
+ })
+
+ return {
+ init,
+ removeAll,
+ initEventLayer,
+ initDroneEntity,
+ }
+}
\ No newline at end of file
diff --git a/src/layout/Header.vue b/src/layout/Header.vue
index 17a4f57..3e67c19 100644
--- a/src/layout/Header.vue
+++ b/src/layout/Header.vue
@@ -31,6 +31,7 @@
import { useRouter, useRoute } from 'vue-router';
import { Message } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
+import { ELocalStorageKey } from '@/utils/http/enums';
const router = useRouter();
const route = useRoute();
@@ -50,6 +51,10 @@
]);
const handleClick = ({ path, name }) => {
+ if (['系统运维'].includes(name)) {
+ window.open(import.meta.env.VITE_APP_ADMIN_URL + '?token=' + localStorage.getItem(ELocalStorageKey.Token), '_blank');
+ return;
+ }
if (!['首页', '任务管理'].includes(name)) return ElMessage.warning('正在加急开发中...');
// 更新 leftList 的 active 状态
leftList.value.forEach(item => {
diff --git a/src/store/modules/common.js b/src/store/modules/common.js
index 4a97c4a..54b519d 100644
--- a/src/store/modules/common.js
+++ b/src/store/modules/common.js
@@ -36,8 +36,12 @@
visual: '3D',
isDark: false,
},
+ isHideBottomIcon: true,
},
mutations: {
+ setHideBottomIcon (state, data) {
+ state.isHideBottomIcon = data
+ },
setMapSetting: (state, data) => {
state.mapSetting = data
loadLAYER()
diff --git a/src/store/modules/home.js b/src/store/modules/home.js
index 73618a3..f4b0ca8 100644
--- a/src/store/modules/home.js
+++ b/src/store/modules/home.js
@@ -117,10 +117,9 @@
dock.work_osd = info.host
}
},
- setEventTimeType : (state, data) => {
- console.log('33333')
- state.eventTimeType = data[0]
- state.eventTimeParams = data[1]
+ setEventTimeType: (state, [timeType, timeParams]) => {
+ state.eventTimeType = timeType
+ state.eventTimeParams = timeParams
},
setEventTimeRang : (state, time) => {
state.eventTimeRang = time
diff --git a/src/views/Home/AINowFly.vue b/src/views/Home/AINowFly.vue
index 45eff86..2cbe190 100644
--- a/src/views/Home/AINowFly.vue
+++ b/src/views/Home/AINowFly.vue
@@ -14,21 +14,46 @@
<el-input disabled type="text" v-model="di" placeholder="地名&经纬度"/>
</el-form-item>
<!-- todo-->
- <el-form-item label="事件">
+ <el-form-item label="飞行事件">
<div class="event">
<img src="@/assets/images/aiNowFly/picture-recording.png" alt="">
+ <div class="img-close" v-show="isPhoto">
+ <img @click="isPhoto=false" class="close" src="@/assets/images/aiNowFly/close.png" alt="">
+ <img src="@/assets/images/aiNowFly/photo.png" alt="">
+ </div>
+ <div class="img-close" v-show="isStop">
+ <img @click="isStop=false" class="close" src="@/assets/images/aiNowFly/close.png" alt="">
+ <img src="@/assets/images/aiNowFly/stop.png" alt="">
+ </div>
+ <div class="add-event" @click="isShowEvent = !isShowEvent">+
+ <div class="event-select" v-show="isShowEvent">
+ <div class="photo" @click="isPhoto=true">拍照</div>
+ <div class="stop" @click="isStop=true">悬停</div>
+ </div>
+ </div>
</div>
</el-form-item>
</el-form>
<div class="title-list">可飞行机巢列表:</div>
- <el-table :data="list" height="120" @selection-change="handleSelectionChange">
- <el-table-column type="selection" />
- <!-- <el-table-column type="index" label="序号" /> -->
- <el-table-column prop="nickname" label="机巢名称" />
- <el-table-column prop="minute" label="可飞行时间" />
- <el-table-column prop="exe_distance" label="可飞行距离" />
- </el-table>
+ <div class="tabledata">
+ <div class="table-content">
+ <div class="tabler-item">
+ <el-checkbox v-model="isCheckAll" @change="checkedAll"/>
+ </div>
+ <div class="table-item">机巢名称</div>
+ <div class="table-item">可飞行时间</div>
+ <div class="table-item">可飞行距离</div>
+ </div>
+ <div class="table-content" v-for="item in list">
+ <div class="tabler-item">
+ <el-checkbox v-model="item.checked" @change="handleItemCheck"/>
+ </div>
+ <div class="table-item">{{ item.nickname }}</div>
+ <div class="table-item">{{ item.minute }}</div>
+ <div class="table-item">{{ item.exe_distance }}</div>
+ </div>
+ </div>
<div class="btn-submit" @click="nowFly"><img src="@/assets/images/aiNowFly/fly.png" alt=""></div>
</div>
</template>
@@ -61,9 +86,17 @@
type: 1,
begin_time: nowTime,
end_time: nowTime,
+ action_modes: [{action_actuator_func: 'startRecord'}],
}
const params = ref(_.cloneDeep(paramsInit))
const di = computed(() => params.value.longitude + ',' + params.value.latitude)
+
+// 事件默认隐藏
+const isShowEvent = ref(false);
+
+// 添加事件
+const isPhoto = ref(false)
+const isStop = ref(false)
const rules = ref({
name: [
@@ -89,6 +122,12 @@
await ruleFormRef.value.validate()
if (!params.value.dock_sns.length) return ElMessage.warning('请选择将要飞行的机巢')
if (!params.value.longitude) return ElMessage.warning('请选择飞行的点')
+ if (isPhoto.value) {
+ params.value.action_modes.push({action_actuator_func:'takePhoto'})
+ }
+ if (isStop.value) {
+ params.value.action_modes.push({action_actuator_func:'hover'})
+ }
createTask(params.value).then(res => {
ElMessage.success('起飞成功')
if (params.value.dock_sns.length === 1) {
@@ -205,6 +244,7 @@
size: 10
});
+const isCheckAll = ref(false);
// 获取飞机列表
const getFJList = async () => {
let pageParams = ref({
@@ -215,10 +255,27 @@
const res = await getFlyingNestBy(pageParams.value, pagingParams.value)
list.value = (res.data?.data || []).map(item => ({
...item,
+ checked: false,
minute: _.round(item.estimated_arrival_time / 60, 0),
}))
if (!list.value.length) ElMessage.warning('附近暂无可用无人机')
renderingLine()
+}
+
+// 单个选择框变化
+const handleItemCheck = () => {
+ const allChecked = list.value.every(item => item.checked)
+ const someChecked = list.value.some(item => item.checked)
+ isCheckAll.value = allChecked
+ params.value.dock_sns = list.value.filter(item => item.checked).map(item => item.device_sn)
+}
+
+// 全选
+const checkedAll = () => {
+ list.value.forEach(item => {
+ item.checked = isCheckAll.value
+ })
+ params.value.dock_sns = isCheckAll.value ? list.value.map(item => item.device_sn) : []
}
const initMap = () => {
@@ -240,6 +297,8 @@
list.value = []
eventPoint = {}
store.commit('setFootActiveIndex', 0)
+ // 显示相关的按钮
+ store.commit('setHideBottomIcon', true)
}
onBeforeUnmount(() => {
@@ -304,79 +363,82 @@
box-shadow: 0 0 0 1px #026AD6;
}
.event {
+ display: flex;
img {
width: 40px;
height: 34px;
+ margin-right: 10px;
+ }
+ .img-close {
+ position: relative;
+ .close {
+ cursor: pointer;
+ width: 8px;
+ height: 8px;
+ position: absolute;
+ top: -8px;
+ right: 1px;
+ }
+ }
+ .add-event {
+ width: 38px;
+ height: 38px;
+ background: rgba(83,179,255,0.16);
+ border-radius: 8px 8px 8px 8px;
+ border: 1px dashed;
+ text-align: center;
+ line-height: 38px;
+ color: #11C4FF;
+ position: relative;
+ cursor: pointer;
+ // border-image: linear-gradient(180deg, rgba(17, 196, 255, 1), rgba(255, 255, 255, 1)) 1 1;
+ .event-select {
+ z-index: 10;
+ position: absolute;
+ top: 40px;
+ width: 72px;
+ height: 70px;
+ background: #0F1929;
+ box-shadow: inset 0px -50px 50px 0px rgba(27,148,255,0.13);
+ border-radius: 8px 8px 8px 8px;
+ border: 1px solid #51A8FF;
+ text-align: center;
+ color: #D3E9FF;
+ .photo {
+ height: 36px;
+ border-bottom: 1px solid #51A8FF;
+ }
+ }
}
}
}
.title-list {
padding: 0 0 14px 11px;
}
- .el-table {
- width: 300px;
+ .tabledata {
height: 120px;
- margin: 0 0 0 11px;
- overflow: hidden;
- :deep(.el-scrollbar__wrap) {
- overflow-x: hidden !important;
+ border: 1px dashed #fff;
+ margin: 0px 10px;
+ .table-content {
+ padding: 0 8px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px dashed #fff;
}
-
- :deep(.el-table__body-wrapper) {
- overflow-x: hidden !important;
- }
- :deep(.el-table__header-wrapper) {
- th {
- font-size: 12px;
- color: #D3E9FF;
- background-color: #122348;
- font-weight: normal;
- border-bottom: none;
- }
- }
- :deep(.el-table__empty-block) {
- background-color: #0A1734;
- height: auto !important; // 移除固定高度
- min-height: 60px; // 设置最小高度
- .el-table__empty-text {
- color: #FFFFFF;
- }
- }
- :deep(.el-table__body) {
- background-color: #0A1734;
- tr {
- background-color: #0A1734 !important;
- color: #FFFFFF;
-
- &:hover > td {
- background-color: #0A1734 !important;
- }
- }
- }
- :deep(.el-scrollbar) {
- background-color: #0A1734;
+ .table-item {
+ width: 100px;
+ text-align: center;
+ height: 32px;
+ line-height: 32px;
}
}
+
.btn-submit {
cursor: pointer;
margin-left: 88px;
margin-top: 12px;
img { width: 138px; height: 38px; }
}
- :deep(.el-table__inner-wrapper) {
- border: 1px dashed #2F497D;
-
- &::before {
- display: none;
- }
- }
-
- :deep(.el-table__cell) {
- border: none;
- }
-
- :deep(.el-table__border) {
- display: none;
- }
}
</style>
diff --git a/src/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventOverviewDetailLeft.vue b/src/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventOverviewDetailLeft.vue
index 276130c..90f553c 100644
--- a/src/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventOverviewDetailLeft.vue
+++ b/src/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventOverviewDetailLeft.vue
@@ -1,12 +1,12 @@
<template>
<!--时间 天气-->
<common-weather></common-weather>
- <div class="event-overview-detail-left">
- <!--返回-->
- <div class="do-return" @click="goBack">
- <img src="@/assets/images/return.png" alt="" />
- </div>
- <common-title title="事件数据分析" />
+ <!--返回-->
+ <div class="do-return" :style="{left:isHideBottomIcon?pxToRem(430):pxToRem(46)}" @click="goBack">
+ <img src="@/assets/images/return.png" alt="" />
+ </div>
+ <common-title v-show="isHideBottomIcon" :style="{left:pxToRem(14)}" title="事件数据分析" />
+ <div v-show="isHideBottomIcon" class="event-overview-detail-left">
<CommonDateTime class="dateTime" v-model="timeArr" @change="timeChange" />
<EventDataAnalysis />
<EventTrendAnalysis />
@@ -22,6 +22,7 @@
import { useStore } from 'vuex'
import EventTrendAnalysis from '@/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventTrendAnalysis.vue'
import EventTop5 from '@/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventTop5.vue'
+import { pxToRem } from '@/utils/rem'
// 选中机巢默认日
// const today = dayjs().format('YYYY-MM-DD')
@@ -30,6 +31,8 @@
const startOfWeek = dayjs().startOf('week').add(1, 'day').format('YYYY-MM-DD')
const endOfWeek = dayjs().endOf('week').add(1, 'day').format('YYYY-MM-DD')
const timeArr = ref([startOfWeek, endOfWeek])
+
+const isHideBottomIcon = computed(() => store.state.common.isHideBottomIcon)
const store = useStore()
@@ -41,13 +44,15 @@
provide('eventOverviewParams', params)
// 时间变化
-const timeChange = (value, date_enum) => {
+const timeChange = (value, date_enum, type) => {
params.value = {
...params.value,
date_enum,
}
+ store.commit('setEventTimeType', [type, date_enum]);
}
const goBack = () => {
+ store.commit('setHideBottomIcon', true)
store.commit('setIsEventOverviewDetail', false)
}
</script>
@@ -55,8 +60,8 @@
.event-overview-detail-left {
position: absolute;
width: 390px;
- height: 920px;
- top: 120px;
+ height: 870px;
+ top: 166px;
margin-left: 29px;
background: linear-gradient(
270deg,
@@ -71,20 +76,19 @@
align-items: center;
.dateTime {
- width: 400px;
+ width: 356px;
margin: 0 0 8px 0;
}
+}
+.do-return {
+ position: absolute;
+ top: 136px;
+ left: 430px;
+ cursor: pointer;
- .do-return {
- position: absolute;
-
- right: -50px;
- cursor: pointer;
-
- img {
- width: 60px;
- height: 33px;
- }
+ img {
+ width: 60px;
+ height: 33px;
}
}
</style>
diff --git a/src/views/Home/EventOverviewDetail/EventOverviewDetailRight.vue b/src/views/Home/EventOverviewDetail/EventOverviewDetailRight.vue
index edfc854..16d7179 100644
--- a/src/views/Home/EventOverviewDetail/EventOverviewDetailRight.vue
+++ b/src/views/Home/EventOverviewDetail/EventOverviewDetailRight.vue
@@ -1,9 +1,9 @@
<template>
<div class="event-overviewdetail-right" :class="{ isMore }">
- <CommonTitle title="工单列表" />
+ <CommonTitle title="事件概况" :style="{right: isMore?pxToRem(410):pxToRem(0)}" />
<div class="content">
- <img class="leftArrow" :src="isMore ? rightArrowImg : leftArrowImg" @click="leftArrowFun" alt="" />
+ <img class="leftArrow" :class="isMore?'rightArrow':''" :src="isMore ? rightArrowImg : leftArrowImg" @click="leftArrowFun" alt="" />
<el-date-picker
class="ztzf-date-picker"
@@ -50,12 +50,12 @@
<img class="statusItemImg" :src="item.img" alt="" />
<div class="statusItemInfo">
<div class="statusItemName">{{ item.name }}</div>
- <div class="statusItemNum">{{ item.num || 0 }}</div>
+ <div class="statusItemNum" :style="{ color:item.color }">{{ item.num || 0 }}</div>
</div>
</div>
</div>
- <el-checkbox-group v-model="params.event_keys" @change="getList">
+ <el-checkbox-group v-show="isMore" v-model="params.event_keys" @change="getList">
<el-checkbox v-for="item in eventList" :value="item.status" :key="item.dictKey">
<template #default>
<span class="eventListItemCheckboxName">{{ item.name }}</span>
@@ -70,6 +70,7 @@
class="eventListItemImg"
:src="getSmallImg(item.photo_url)"
alt=""
+ @click="getFindImgHistory(item.id)"
/>
<div class="eventListItemPosition" :title="item.address" @click="positioning(item)">
<img :src="positioningImg" alt="" title="点击定位" />
@@ -95,6 +96,25 @@
</div>
</div>
</div>
+ <div class="image-list" v-if="isShowBigImg">
+ <div class="title">
+ <img @click="isShowBigImg=false" src="@/assets/images/home/useEventOperate/close.png" alt="">
+ </div>
+ <div class="content">
+ <img :src="clickImgSrc" alt="">
+ </div>
+ <div class="card">
+ <div v-for="(item,index) in imageList">
+ <div class="time-top" :class="index===selectedImgIndex?'active':''" @click="clickWeekTime(item,index)">{{ item.create_time_str }}</div>
+ <div class="time-point">
+ <img v-if="index===selectedImgIndex" src="@/assets/images/home/useEventOperate/point-active.png" alt="">
+ <img v-else src="@/assets/images/home/useEventOperate/point.png" alt="">
+ </div>
+ <div class="time-bottom">{{ item.create_time }}</div>
+ </div>
+ <div class="time-line"></div>
+ </div>
+ </div>
</template>
<script setup>
import status0Img from '@/assets/images/home/eventOverviewDetail/status0.png'
@@ -110,7 +130,7 @@
import dayjs from 'dayjs'
import { selectDevicePage } from '@/api/home/machineNest'
import { getMultipleDictionary } from '@/api/system/dictbiz'
-import { getEvenNum, getEventPage, getEventStatusNum } from '@/api/home/event'
+import { getEvenNum, getEventPage, getEventStatusNum, findImgHistory } from '@/api/home/event'
import cesiumOperation from '@/utils/cesium-tsa'
import CommonTitle from '@/components/CommonTitle.vue'
import { pxToRem } from '@/utils/rem'
@@ -148,6 +168,8 @@
isMore.value = !isMore.value
params.value.size = isMore.value ? 16 : 8
params.value.current = 1
+ // 下半部分隐藏 右侧隐藏
+ store.commit('setHideBottomIcon', !isMore.value)
getList()
}
@@ -181,12 +203,12 @@
// 事件状态+数量
const statusList = ref([
- { name: '全部状态', img: status0Img, id: undefined,few: true },
- { name: '待审核', img: status1Img, id: 2 },
- { name: '待处理', img: status2Img, id: 0, few: true },
- { name: '处理中', img: status3Img, id: 3, few: true },
- { name: '已完成', img: status4Img, id: 4, few: true },
- { name: '待分拨', img: status5Img, id: 1 },
+ { name: '全部状态', img: status0Img, id: undefined,few: true, color: '#FFD509' },
+ { name: '待审核', img: status1Img, id: 2, color: '#8CFEA7' },
+ { name: '待处理', img: status2Img, id: 0, few: true, color: '#FF7411' },
+ { name: '处理中', img: status3Img, id: 3, few: true, color: '#FFC398' },
+ { name: '已完成', img: status4Img, id: 4, few: true, color: '#AFD9FB' },
+ { name: '待分拨', img: status5Img, id: 1, color: '#11C4FF' },
])
const getEventStatusNumFun = () => {
@@ -244,6 +266,24 @@
total.value = resData.total
})
}
+const isShowBigImg = ref(false)
+const imageList = ref([]);
+const clickImgSrc = ref('');
+const selectedImgIndex = ref(0);
+// 点击图片放大 显示详细信息
+const getFindImgHistory = (id) => {
+ findImgHistory(id).then((res) => {
+ if (res.data.code !== 0) return
+ imageList.value = res.data.data
+ clickImgSrc.value = res.data.data[0]?.url;
+ isShowBigImg.value = true
+ })
+}
+// 点击周期
+const clickWeekTime = (item,index) => {
+ clickImgSrc.value = item.url
+ selectedImgIndex.value = index
+}
const getDateRange = unit => {
if (unit === 'today') {
@@ -282,25 +322,31 @@
height: 922px;
width: 405px;
font-size: 18px;
+ z-index: 10;
&.isMore {
- width: 807px;
+ width: 808px;
.content {
width: 792px;
+ padding-left: 44px;
}
}
.content {
width: 390px;
height: 877px;
- background: linear-gradient(270deg, #1f3e7a 0%, rgba(31, 62, 122, 0.35) 79%, rgba(31, 62, 122, 0) 100%);
+ background: linear-gradient(
+ 270deg,
+ rgba(31, 62, 122, 0) 0%,
+ rgba(31, 62, 122, 0.35) 21%,
+ #1f3e7a 100%);
display: flex;
justify-content: space-between;
align-content: start;
flex-wrap: wrap;
- padding: 7px 15px 0 11px;
- gap: 10px;
+ padding: 7px 13px 0 11px;
+ gap: 16px;
.leftArrow {
position: absolute;
@@ -310,38 +356,42 @@
cursor: pointer;
}
+ .rightArrow {
+ position: absolute;
+ top: 50%;
+ left: 30px;
+ transform: translateY(-50%);
+ cursor: pointer;
+ }
+
.statusList {
width: 100%;
display: flex;
+ justify-content: space-between;
.statusItem {
- width: 95px;
+ // width: 95px;
height: 44px;
display: flex;
flex: 1;
justify-content: center;
position: relative;
cursor: pointer;
+ // margin-right: 4px;
&.active {
- background: linear-gradient(
- 180deg,
- rgba(19, 80, 141, 0) 0%,
- rgba(22, 56, 91, 0.48) 48%,
- #053462 91%,
- #259dff 91%,
- #259dff 98%
- );
+ background: linear-gradient( 180deg, rgba(19,80,141,0) 0%, rgba(22,56,91,0.48) 48%, #053462 98%, #259DFF 98%, #259DFF 98%);
}
.statusItemImg {
- width: 35px;
- height: 35px;
+ width: 34px;
+ height: 34px;
+ margin-right: 1px;
}
.statusItemInfo {
.statusItemName {
- width: 59px;
+ // width: 59px;
height: 17px;
font-family: Segoe UI, Segoe UI;
font-weight: 400;
@@ -351,6 +401,7 @@
text-align: left;
font-style: normal;
text-transform: none;
+ margin-bottom: 4px;
}
.statusItemNum {
@@ -401,13 +452,14 @@
width: 100%;
display: flex;
flex-wrap: wrap;
- justify-content: space-between;
- gap: 20px 0;
+ // justify-content: space-between;
+ gap: 20px 10px;
.eventListItem {
width: 175px;
height: 140px;
position: relative;
+ cursor: pointer;
.eventListItemImg {
width: 174px;
@@ -475,4 +527,76 @@
display: flex;
justify-content: center;
}
+.image-list {
+ position: absolute;
+ left: 40%;
+ transform: translate(-40%);
+ bottom: 218px;
+ width: 524px;
+ height: 382px;
+ background: #0F1929;
+ box-shadow: inset 0px -50px 50px 0px rgba(27,148,255,0.13);
+ border-radius: 0px 0px 0px 0px;
+ border: 2px solid;
+ border-image: linear-gradient(180deg, rgba(81, 168, 255, 0), rgba(48, 111, 202, 1), rgba(255, 255, 255, 1), rgba(27, 148, 255, 1)) 2 2;
+ .title {
+ position: relative;
+ text-align: right;
+ right: 12px;
+ top: 12px;
+ img {
+ width: 10px;
+ height: 10px;
+ cursor: pointer;
+ }
+ }
+ .content {
+ width: 475px;
+ height: 231px;
+ box-shadow: 1px 3px 6px 0px rgba(81,168,255,0.58);
+ border-radius: 20px 20px 20px 20px;
+ border-image: linear-gradient(180deg, rgba(81, 168, 255, 1), rgba(189, 228, 255, 1)) 2 2;
+ margin: 28px 28px;
+ img {
+ width: 100%;
+ height: 230px;
+ }
+ }
+ .card {
+ margin: 26px 26px;
+ color: #BECBEA;
+ display: flex;
+ justify-content: space-between;
+ position: relative;
+ .time-top {
+ width: 50px;
+ height: 30px;
+ line-height: 30px;
+ text-align: center;
+ color: #ffffff;
+ background: linear-gradient( 180deg, rgba(13,30,70,0.72) 0%, #142E6B 100%);
+ border: 1px solid #0054D3;
+ cursor: pointer;
+ }
+ .active {
+ background: linear-gradient( 180deg, rgba(13,48,131,0.72) 0%, #023DC8 100%);
+ border: 1px solid;
+ border-image: linear-gradient(180deg, rgba(0, 84, 211, 1), rgba(146, 186, 245, 1)) 1 1;
+ }
+ .time-point {
+ text-align: center;
+ img {
+ width: 8px;
+ height: 12px;
+ }
+ }
+ .time-line {
+ position: absolute;
+ background: linear-gradient( 82deg, rgba(23,40,79,0) 0%, #576D9F 17%, #576D9F 86%, rgba(23,40,79,0) 100%);
+ height: 2px;
+ top: 38px;
+ width: 100%;
+ }
+ }
+}
</style>
diff --git a/src/views/Home/Footer.vue b/src/views/Home/Footer.vue
index 68a916d..b87f522 100644
--- a/src/views/Home/Footer.vue
+++ b/src/views/Home/Footer.vue
@@ -1,5 +1,5 @@
<template>
- <div class="footer">
+ <div class="footer" v-show="isHideBottomIcon">
<img
v-for="(item,index) in list.filter(i => !i.show)"
:class="item.className"
@@ -37,6 +37,7 @@
const store = useStore()
const footActiveIndex = computed(() => store.state.home.footActiveIndex)
+const isHideBottomIcon = computed(() => store.state.common.isHideBottomIcon)
// 机巢聚合
const { init, removeAll } = useMapAggregation('device')
@@ -76,6 +77,10 @@
fromItem?.removeAll?.()
nextTick(() => toItem?.init?.())
list.value = list.value.map(item => ({ ...item, active: item.name === toItem?.name }))
+ if (index === 5) {
+ // 相关图标不显示
+ store.commit('setHideBottomIcon', false)
+ }
}
watch(
diff --git a/src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue b/src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue
index 777af0c..b5e7ed4 100644
--- a/src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue
+++ b/src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue
@@ -3,7 +3,7 @@
<el-dialog
class="inspection-rask-details-dialog ztzf-dialog"
v-model="isShowDetailsDialog"
- :width="pxToRem(1000)"
+ :width="pxToRem(1500)"
:close-on-click-modal="false"
:destroy-on-close="true"
>
@@ -64,7 +64,7 @@
<el-table
:data="taskDetailData"
:row-class-name="tableRowClassName"
- :row-style="{ height: '54px', fontSize: '14px', 'text-align': 'center' }"
+ :row-style="{ height: '45px', fontSize: '14px', 'text-align': 'center' }"
:header-cell-style="{ 'text-align': 'center', height: '36px', fontSize: '14px' }"
>
<el-table-column label="序号" type="index" width="60">
@@ -115,7 +115,7 @@
</el-table>
</div>
<!-- 分页 -->
- <div style="display: flex; justify-content: center">
+ <div style="display: flex; justify-content: center;margin:15px 0;">
<el-pagination
class="ztzf-pagination"
v-model:current-page="pageParams.current"
@@ -322,7 +322,7 @@
.tabledata {
padding: 0 16px;
overflow: hidden;
- height: 640px;
+ // height: 640px;
overflow-y: scroll !important;
}
@@ -343,9 +343,4 @@
color: #8cfea7;
}
</style>
-<style lang="scss">
-.inspection-rask-details-dialog {
- width: 1270px;
- height: 856px;
-}
-</style>
+
diff --git a/src/views/Home/HomeLeft/MachineNestList.vue b/src/views/Home/HomeLeft/MachineNestList.vue
index 016fb64..8b4ccf8 100644
--- a/src/views/Home/HomeLeft/MachineNestList.vue
+++ b/src/views/Home/HomeLeft/MachineNestList.vue
@@ -5,13 +5,17 @@
<div class="machine-nest-list">
<MachineNestTotal @searchNickName="handleSearch" />
<div class="content-wrapper">
- <div
+ <!-- <div
class="table-list"
v-if="tableList.length > 0"
infinite-scroll-distance="6"
v-infinite-scroll="loadMore"
:infinite-scroll-disabled="busy"
infinite-scroll-immediate="true"
+ > -->
+ <div
+ class="table-list"
+ v-if="tableList.length > 0"
>
<div
:class="[index % 2 === 1 ? 'table-itemeven' : 'table-item']"
@@ -73,7 +77,7 @@
// 分页参数
const pageParams = ref({
current: 1,
- size: 8,
+ size: 99,
total: 0,
})
@@ -90,7 +94,7 @@
if (res.data.code !== 0) return
if (res.data.data.records.length === 0) return (isMore.value = false)
// pageParams.value.current += 1
- pageParams.value.size += 8
+ // pageParams.value.size += 8
tableList.value = res.data.data.records;// [...tableList.value, ...res.data.data.records]
busy.value = false
})
diff --git a/src/views/Home/HomeLeft/OverviewNext.vue b/src/views/Home/HomeLeft/OverviewNext.vue
index 4d1116a..a1e4e07 100644
--- a/src/views/Home/HomeLeft/OverviewNext.vue
+++ b/src/views/Home/HomeLeft/OverviewNext.vue
@@ -8,14 +8,17 @@
<div class="name">机巢名称</div>
<div class="status">机巢状态</div>
</div>
- <div
+ <!-- <div
class="table-body"
v-if="tableList.length > 0"
infinite-scroll-distance="6"
v-infinite-scroll="loadMore"
:infinite-scroll-disabled="busy"
infinite-scroll-immediate="true"
- >
+ > -->
+ <div
+ class="table-body"
+ v-if="tableList.length > 0">
<div
class="table-item"
:class="[index % 2 === 1 ? '' : 'table-item-odd']"
@@ -66,7 +69,7 @@
// 分页参数
const pageParams = ref({
current: 1,
- size: 5,
+ size: 99,
total: 0,
})
// 机巢列表
@@ -82,24 +85,24 @@
if (res.data.code !== 0) return
if (res.data.data.records.length === 0) return (isMore.value = false)
// pageParams.value.current += 1
- pageParams.value.size += 5;
+ // pageParams.value.size += 5;
tableList.value = res.data.data.records;// [...tableList.value, ...res.data.data.records]
busy.value = false
})
}
// 加载更多数据
-const loadMore = async () => {
- busy.value = true
- if (!isMore.value) return
- getTableList()
-}
+// const loadMore = async () => {
+ // busy.value = true
+ // if (!isMore.value) return
+ // getTableList()
+// }
// 搜索数据
const handleSearch = name => {
searchText.value = name
pageParams.value.current = 1
- pageParams.value.size = 5;
+ // pageParams.value.size = 5;
tableList.value = []
isMore.value = true
getTableList()
diff --git a/src/views/Home/RSide.vue b/src/views/Home/RSide.vue
index be82d71..7e41a56 100644
--- a/src/views/Home/RSide.vue
+++ b/src/views/Home/RSide.vue
@@ -1,5 +1,5 @@
<template>
- <div class="ai-chat">
+ <div class="ai-chat" v-show="isHideBottomIcon">
<el-popover placement="bottom" :visible="visible" :width="200" trigger="click">
<template #reference>
<div class="chat" id="chatID" v-drag:chatID @mousedown="handleMouseDown" @mouseup="handleMouseUp" />
@@ -11,7 +11,7 @@
</el-popover>
<img class="chat-bottom" src="../../assets/images/chat-bottom.png" alt="" />
</div>
- <div class="r-side">
+ <div class="r-side" v-show="isHideBottomIcon">
<img
v-for="(item, index) in images"
:key="index"
@@ -49,6 +49,8 @@
const store = useStore()
const currentAreaPosition = computed(() => store.state.home.currentAreaPosition)
+// 事件概况 展开隐藏
+const isHideBottomIcon = computed(() => store.state.common.isHideBottomIcon)
let activeIndex = ref(null)
const activeChange = value => {
diff --git a/src/views/Home/SearchBox.vue b/src/views/Home/SearchBox.vue
index e27cf63..46d23e7 100644
--- a/src/views/Home/SearchBox.vue
+++ b/src/views/Home/SearchBox.vue
@@ -21,7 +21,7 @@
:load="load"
:props="props"
style="width: 240px"
- @change="treeChange"
+ @node-click="handleNodeClick"
/>
</div>
</div>
@@ -47,9 +47,9 @@
const searchBoxRef = ref(null);
const selectDownRef = ref(null);
-function treeChange(value, node) {
- areaValue.value = node.label;
- store.commit('setSelectedAreaCode', value);
+function handleNodeClick(data) {
+ areaValue.value = data.name;
+ store.commit('setSelectedAreaCode', data.code);
}
const props = {
@@ -93,9 +93,7 @@
// 获取机巢搜索结果
const getDeviceList = async () => {
- const res = await selectDeviceList({
- keyword: searchKey.value,
- });
+ const res = await selectDeviceList({nickname: searchKey.value});
if (res.data.code !== 0) return;
machineNestList.value = res?.data?.data || [];
downList.value = res?.data?.data || [];
@@ -144,11 +142,12 @@
watch(searchKey, async (newVal) => {
if (optionsValue.value === '2') {
await getAddressList();
+ } else {
+ await getDeviceList();
}
}, { immediate: false });
onMounted(() => {
- getDeviceList();
document.addEventListener('click', handleClickOutside);
});
@@ -166,8 +165,8 @@
.select-down-list {
position: absolute;
top: 188px;
- left: 45%;
- transform: translateX(-45%);
+ left: 44%;
+ transform: translateX(-40%);
width: 220px;
height: 256px;
overflow-y: auto;
@@ -175,6 +174,7 @@
border-radius: 0px 0px 8px 8px;
border: 1px solid;
border-image: linear-gradient(180deg, rgba(255, 255, 255, 0), rgba(115, 192, 255, 1)) 1 1;
+ opacity: 0.8;
&::-webkit-scrollbar {
width: 0;
display: none;
@@ -187,6 +187,11 @@
line-height: 32px;
text-align: center;
cursor: pointer;
+ &:hover {
+ background: linear-gradient( 90deg, rgba(0,122,255,0) 0%, rgba(0,98,204,0.6) 50%, rgba(0,73,153,0) 100%);
+ border: 1px solid;
+ border-image: linear-gradient(90deg, rgba(0, 199, 190, 0), rgba(48, 176, 199, 1), rgba(0, 199, 190, 0)) 1 1;
+ }
}
}
.searchBox {
diff --git a/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceEvent.vue b/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceEvent.vue
index 587af5b..0edf424 100644
--- a/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceEvent.vue
+++ b/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceEvent.vue
@@ -2,45 +2,48 @@
<div class="deviceevent-container">
<div class="machineTableDetailsTitle">
<p>
- 相关事件<span>{{ total }}</span
- >件
+ 相关事件
+ <span>{{ total }}</span>
+ 件
</p>
</div>
- <div class="deviceevent-table ztzf-table" >
- <el-table :data="list" :row-class-name="tableRowClassName"
- style="width: 100%;"
- :row-style="{ height: '38px', fontSize: '14px', 'text-align': 'center' }"
- :header-cell-style="{ 'text-align': 'center', height: '36px', fontSize: '14px' }">
- <el-table-column label="序号" type="index" width="60">
+ <div class="deviceevent-table ztzf-table">
+ <el-table
+ :data="list"
+ :row-class-name="tableRowClassName"
+ style="width: 100%"
+ :row-style="{ height: '35px', fontSize: '14px', 'text-align': 'center' }"
+ :header-cell-style="{ 'text-align': 'center', height: '30px', fontSize: '14px' }"
+ >
+ <el-table-column label="序号" type="index" width="60">
<template #default="{ $index }">
{{ ($index + 1).toString().padStart(2, '0') }}
</template>
</el-table-column>
- <el-table-column prop="id" label="事件编号" />
- <el-table-column prop="event_name" label="事件名称" />
- <el-table-column prop="create_user" label="所属单位 " />
- <el-table-column show-overflow-tooltip prop="remark" label="事件内容" />
- <el-table-column show-overflow-tooltip prop="ai_types" label="关联算法" />
- <el-table-column prop="status" label="事件状态">
- <template #default="scope">
- <div class="pending" v-if="scope.row.status === 0">待处理</div>
- <div class="reviewed" v-if="scope.row.status === 2">待审核</div>
- <div class="processing" v-if="scope.row.status === 3">处理中</div>
- <div class="done" v-if="scope.row.status === 4">已完成</div>
- <div class="ended" v-if="scope.row.status === 5">已完结</div>
- </template>
- </el-table-column>
- <el-table-column label="操作" width="80">
- <template #default="scope">
- <div class="ztzf-view" @click="distribution(scope.row)">查看</div>
- </template>
- </el-table-column>
- </el-table>
+ <el-table-column prop="id" label="事件编号" />
+ <el-table-column prop="event_name" label="事件名称" />
+ <el-table-column prop="create_user" label="所属单位 " />
+ <el-table-column show-overflow-tooltip prop="remark" label="事件内容" />
+ <el-table-column show-overflow-tooltip prop="ai_types" label="关联算法" />
+ <el-table-column prop="status" label="事件状态">
+ <template #default="scope">
+ <div class="pending" v-if="scope.row.status === 0">待处理</div>
+ <div class="reviewed" v-if="scope.row.status === 2">待审核</div>
+ <div class="processing" v-if="scope.row.status === 3">处理中</div>
+ <div class="done" v-if="scope.row.status === 4">已完成</div>
+ <div class="ended" v-if="scope.row.status === 5">已完结</div>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" width="80">
+ <template #default="scope">
+ <div class="ztzf-view" @click="distribution(scope.row)">查看</div>
+ </template>
+ </el-table-column>
+ </el-table>
</div>
<el-pagination
- class="ztzf-pagination"
+ class="ztzf-pagination"
background
-
v-model:current-page="sizeParams.current"
v-model:page-size="sizeParams.size"
layout="prev, pager, next, jumper"
@@ -79,11 +82,7 @@
const resData = res?.data?.data || {}
list.value = resData.records
total.value = resData.total
-
})
-
-
-
}
const pageChange = val => {
sizeParams.value.current = val
@@ -103,11 +102,10 @@
</script>
<style scoped lang="scss">
-
// 标题
.machineTableDetailsTitle {
margin: 0 24px;
- margin-bottom: 16px;
+ margin-bottom: 10px;
background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
background-size: 100% 100%;
p {
@@ -127,38 +125,36 @@
}
// 表格
.deviceevent-table {
-padding: 0 17px;
-
+ padding: 0 17px;
}
// 分页
:deep(.el-pagination) {
display: flex;
justify-content: center;
-
}
:deep(.el-pagination button) {
background: center center no-repeat none !important;
color: #8eb8ea !important;
}
// 待处理
-.pending{
-color: #FF7411;
+.pending {
+ color: #ff7411;
}
// 待审核
-.reviewed{
-color: #8CFEA7;
+.reviewed {
+ color: #8cfea7;
}
// 处理中
-.processing{
-color: #FFC398;
+.processing {
+ color: #ffc398;
}
// 已完成
-.done{
-color: #AFD9FB;
+.done {
+ color: #afd9fb;
}
// 已完结
-.ended{
-color: #11C4FF;
+.ended {
+ color: #11c4ff;
}
</style>
diff --git a/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJob.vue b/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJob.vue
index 4999956..4d904db 100644
--- a/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJob.vue
+++ b/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJob.vue
@@ -12,8 +12,8 @@
:data="list"
:row-class-name="tableRowClassName"
style="width: 100%"
- :row-style="{ height: '38px', fontSize: '14px', 'text-align': 'center' }"
- :header-cell-style="{ 'text-align': 'center', height: '36px', fontSize: '14px' }"
+ :row-style="{ height: '35px', fontSize: '14px', 'text-align': 'center' }"
+ :header-cell-style="{ 'text-align': 'center', height: '30px', fontSize: '14px' }"
>
<el-table-column label="序号" type="index" width="60">
<template #default="{ $index }">
@@ -100,7 +100,7 @@
// 标题
.machineTableDetailsTitle {
margin: 0 24px;
- margin-bottom: 16px;
+ margin-bottom: 10px;
background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
background-size: 100% 100%;
p {
@@ -121,15 +121,9 @@
// 表格
.devicelob-table {
padding: 0 17px;
- // height: 280px;
- // overflow: hidden;
- // overflow-y: scroll !important;
+
}
-// :deep(::-webkit-scrollbar) {
-// width: 0;
-// display: none;
-// background: none !important;
-// }
+
// 分页
:deep(.el-pagination) {
diff --git a/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue b/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue
index e40f4c2..d4cc8c7 100644
--- a/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue
+++ b/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue
@@ -1,4 +1,4 @@
-<!-- 任务详情 -->
+<!-- 历史任务详情 -->
<template>
<el-dialog
class="ztzf-dialog"
@@ -24,7 +24,7 @@
</div>
<div class="itemBoxRight">
<div class="itemTitle">关联算法:</div>
- <div class="itemValue">{{ flystatus }}</div>
+ <div class="itemValue">{{ flystatus ? flystatus :'' }}</div>
</div>
</div>
<JobRelatedEvents v-if="isShow" />
@@ -123,7 +123,7 @@
if (item.name === '任务时间') {
item.value = detailsData.value.begin_time.slice(0, 10) + '-' + detailsData.value.end_time.slice(0, 10)
} else if (item.name === '任务频次') {
- item.value = detailsData.value.rep_rule_type + ' -- ' + detailsData.value.rep_rule_val
+ item.value ===undefined ? '' : detailsData.value.rep_rule_type + ' -- ' + detailsData.value.rep_rule_val
} else {
item.value = detailsData.value?.[item.field] || ''
}
@@ -240,14 +240,16 @@
}
.imgListBox {
- display: flex;
- flex-wrap: wrap;
+ // display: flex;
+ // flex-wrap: wrap;
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
gap: 10px;
-
- .imgItem {
- width: 200px;
- height: 200px;
- }
+ margin-bottom: 49px;
+ // .imgItem {
+ // width: 200px;
+ // height: 200px;
+ // }
}
}
diff --git a/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/MachineTableDetails.vue b/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/MachineTableDetails.vue
index f4f104f..e44d230 100644
--- a/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/MachineTableDetails.vue
+++ b/src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/MachineTableDetails.vue
@@ -70,12 +70,10 @@
<style lang="scss">
.machineTableDetails {
- width: 1270px;
- height: 856px;
.el-pagination {
text-align: left;
- padding: 20px 20px 0 20px;
+ padding: 10px 20px 5px 10px;
}
.my-header {
display: inline-block;
@@ -90,7 +88,7 @@
display: flex;
justify-content: space-between;
align-items: center;
- margin-bottom: 14px;
+ margin-bottom: 10px;
font-size: 14px;
color: #ffffff;
.itemBox {
@@ -115,7 +113,7 @@
margin: 0 24px;
}
.machineTableDetailsTitle {
- margin-bottom: 16px;
+ margin-bottom: 10px;
background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
background-size: 100% 100%;
span {
diff --git a/src/views/SignMachineNest/SignMachineNest.vue b/src/views/SignMachineNest/SignMachineNest.vue
index bfec7ce..453e73c 100644
--- a/src/views/SignMachineNest/SignMachineNest.vue
+++ b/src/views/SignMachineNest/SignMachineNest.vue
@@ -1,98 +1,119 @@
<template>
- <MachineLeft></MachineLeft>
- <MachineRight></MachineRight>
+ <MachineLeft></MachineLeft>
+ <MachineRight></MachineRight>
</template>
<script setup>
import MachineLeft from '@/views/SignMachineNest/MachineLeft/MachineLeft.vue'
-import MachineRight from '@/views/SignMachineNest/MachineRight/MachineRight.vue';
-import { useConnectWebSocket } from '@/utils/websocket/connect-websocket';
-import { getWebsocketUrl } from '@/websocket/util/config';
-import { EBizCode } from '@/utils/staticData/enums.js';
-import { EModeCode } from '@/utils/staticData/device.js';
-import { useStore } from 'vuex';
-import { getDeviceDetail, getFlightStatistics } from '@/api/home/machineNest';
+import MachineRight from '@/views/SignMachineNest/MachineRight/MachineRight.vue'
+import { useConnectWebSocket } from '@/utils/websocket/connect-websocket'
+import { getWebsocketUrl } from '@/websocket/util/config'
+import { EBizCode } from '@/utils/staticData/enums.js'
+import { EModeCode } from '@/utils/staticData/device.js'
+import { useStore } from 'vuex'
+import { getDeviceDetail, getFlightStatistics, getEventList } from '@/api/home/machineNest'
+import { useSingleDroneMap } from '@/hooks/useSingleDroneMap/useSingleDroneMap'
-const store = useStore();
-let connectWs = ref(null);
+const store = useStore()
+let connectWs = ref(null)
// 单个机巢信息
-const singleUavHome = computed(() => store.state.home.singleUavHome);
+const singleUavHome = computed(() => store.state.home.singleUavHome)
+const selectedAreaCode = computed(() => store.state.user.selectedAreaCode)
-let osdVisible = ref({});
+let osdVisible = ref({})
-let workspaceId = ref('');
+let workspaceId = ref('')
// 进入单个机巢开始连接ws
const createWsConntect = () => {
- let webSorketUrl = getWebsocketUrl() + '&workspace-id=' + workspaceId.value;
- // 监听ws 消息
- connectWs.value = useConnectWebSocket(messageHandler, webSorketUrl);
-};
+ let webSorketUrl = getWebsocketUrl() + '&workspace-id=' + workspaceId.value
+ // 监听ws 消息
+ connectWs.value = useConnectWebSocket(messageHandler, webSorketUrl)
+}
-const messageHandler = (result) => {
- let payload = JSON.parse(result) // 为了兼容聊天消息
- if (!payload) return
- switch (payload.biz_code) {
- case EBizCode.GatewayOsd: {
- store.commit('setGatewayInfo', payload.data)
- break
- }
- case EBizCode.DeviceOsd: {
- // console.log(payload, 'DeviceOsd')
- store.commit('setDeviceInfo', payload)
- store.commit('setWsMessage', payload)
- break
- }
- case EBizCode.DockOsd: {
- store.commit('setDockOnfo', payload.data)
- break
- }
- default:
- break
- }
-};
+const messageHandler = result => {
+ let payload = JSON.parse(result) // 为了兼容聊天消息
+ if (!payload) return
+ switch (payload.biz_code) {
+ case EBizCode.GatewayOsd: {
+ store.commit('setGatewayInfo', payload.data)
+ break
+ }
+ case EBizCode.DeviceOsd: {
+ // console.log(payload, 'DeviceOsd')
+ store.commit('setDeviceInfo', payload)
+ store.commit('setWsMessage', payload)
+ break
+ }
+ case EBizCode.DockOsd: {
+ store.commit('setDockOnfo', payload.data)
+ break
+ }
+ default:
+ break
+ }
+}
+
+// 单机巢初始化及事件撒点
+const { init, initEventLayer, initDroneEntity } = useSingleDroneMap({
+ eventApi: getEventList,
+ eventApiParams: {
+ device_sn: singleUavHome.value.device_sn,
+ },
+})
// 获取单个机巢信息
const getSingleDetails = () => {
- getDeviceDetail(singleUavHome.value.device_sn).then((res) => {
- if (res.data.code !== 0) return;
- const result = res.data.data;
- const child = result.children;
- // 对应store 里面数据结构
- osdVisible.value.sn = child?.device_sn || ''
- osdVisible.value.callsign = child?.nickname || '--'
- osdVisible.value.model = EModeCode.Disconnected || ''
- osdVisible.value.visible = true
- osdVisible.value.gateway_sn = result?.device_sn || ''
- osdVisible.value.is_dock = true
- osdVisible.value.gateway_callsign = result?.callsign || '--'
- osdVisible.value.payloads = child?.payloads_list || []
- osdVisible.value.device_domain = child.domain || 0
- osdVisible.value.device_sub_type = child.sub_type || 1
- osdVisible.value.device_type = child.type || 0
- // osdVisible.value.latest_wayline_job = result?.latest_wayline_job || {}
- store.commit('setOsdVisibleInfo', osdVisible.value);
- store.commit('setSelectedWorkSpaceId', result.workspace_id);
- workspaceId.value = result.workspace_id;
- createWsConntect();
- });
-};
+ getDeviceDetail(singleUavHome.value.device_sn).then(res => {
+ if (res.data.code !== 0) return
+ const result = res.data.data
+
+ initDroneEntity({
+ lng: result.longitude,
+ lat: result.latitude,
+ status: result.status,
+ })
+
+ const child = result.children
+ // 对应store 里面数据结构
+ osdVisible.value.sn = child?.device_sn || ''
+ osdVisible.value.callsign = child?.nickname || '--'
+ osdVisible.value.model = EModeCode.Disconnected || ''
+ osdVisible.value.visible = true
+ osdVisible.value.gateway_sn = result?.device_sn || ''
+ osdVisible.value.is_dock = true
+ osdVisible.value.gateway_callsign = result?.callsign || '--'
+ osdVisible.value.payloads = child?.payloads_list || []
+ osdVisible.value.device_domain = child.domain || 0
+ osdVisible.value.device_sub_type = child.sub_type || 1
+ osdVisible.value.device_type = child.type || 0
+ // osdVisible.value.latest_wayline_job = result?.latest_wayline_job || {}
+ store.commit('setOsdVisibleInfo', osdVisible.value)
+ store.commit('setSelectedWorkSpaceId', result.workspace_id)
+ workspaceId.value = result.workspace_id
+ createWsConntect()
+ })
+}
// 获取机巢统计数据 提供给左右侧组件使用
const getMachineData = () => {
- getFlightStatistics(singleUavHome.value.device_sn).then(res => {
- if (res.data.code !== 0) return;
- const result = res.data.data;
- store.commit('setSingleTotal', result);
- })
-};
+ getFlightStatistics(singleUavHome.value.device_sn).then(res => {
+ if (res.data.code !== 0) return
+ const result = res.data.data
+ store.commit('setSingleTotal', result)
+ })
+}
onMounted(() => {
- getSingleDetails();
- getMachineData();
-});
+ nextTick(() => {
+ init()
+ })
+ initEventLayer()
+ getSingleDetails()
+ getMachineData()
+})
onUnmounted(() => {
- connectWs?.value?.close();
-});
+ connectWs?.value?.close()
+})
</script>
diff --git a/src/views/TaskManage/TaskIntermediateContent/AddTask.vue b/src/views/TaskManage/TaskIntermediateContent/AddTask.vue
index 6846ab1..5fc9f15 100644
--- a/src/views/TaskManage/TaskIntermediateContent/AddTask.vue
+++ b/src/views/TaskManage/TaskIntermediateContent/AddTask.vue
@@ -1,49 +1,71 @@
-<!-- 机巢列表详情 -->
+<!-- 新建任务 -->
<template>
<el-dialog
+ class="ztzf-dialog"
modal-class="add-task"
v-model="isShowAddTask"
title="新建任务"
:width="pxToRem(1500)"
:close-on-click-modal="false"
- :destroy-on-close="true">
+ :destroy-on-close="true"
+ >
<!-- <el-divider content-position="left">新建任务</el-divider> -->
<div class="task-contain">
<div class="left">
<div class="search">
- <div class="item"><span class="required">*</span>任务名称:<el-input v-model="searchForm.name" placeholder="请输入任务名称"></el-input></div>
- <div class="item"><span class="required">*</span>任务日期:
+ <div class="item">
+ <el-input class="ztzf-input" v-model="searchForm.name" placeholder="请输入任务/机巢名称"></el-input>
+ </div>
+ <div class="item">
<el-date-picker
+ class="ztzf-date-picker"
v-model="taskData"
- format="YYYY-MM-DD"
+ type="daterange"
+ range-separator="至"
+ start-placeholder="开始日期"
+ end-placeholder="结束日期"
value-format="YYYY-MM-DD"
- :disabled-date="disabledDate"
+ @change="changeselect"
/>
</div>
- <div class="item">任务时间:
+ <div class="item">
+ <div class="itemchild">任务时间:</div>
<el-time-picker
+ class="ztzf-date-picker tasktimer"
v-model="timeSlot"
- placeholder="选择时间"
+ placeholder="请选择"
format="HH:mm"
- value-format="HH:mm"/>
+ value-format="HH:mm"
+ />
</div>
- <div class="item">选择航线:
+ <div class="item">
+ <div class="itemchild">选择航线:</div>
+
<el-select
+ class="ztzf-select"
v-model="searchForm.file_id"
@change="getWayLineFile"
placeholder="请选择航线"
- clearable>
+ clearable
+ >
<el-option
v-for="item in routeOptions"
:key="item.wayline_id"
:label="item.name"
- :value="item.wayline_id"/>
- </el-select>
- </div>
- <div class="item">关联算法:
- <TaskAlgorithmBusiness :showAlgorithm="true" @algorithmChange="algorithmChange"/>
- </div>
- <div class="item">任务描述:<el-input v-model="searchForm.remark" placeholder="请输入任务名称"></el-input></div>
+ :value="item.wayline_id"
+ />
+ </el-select>
+ </div>
+ <div class="item">
+
+ <div class="itemchild">关联算法:</div>
+ <TaskAlgorithmBusiness :setWidth="200" :showAlgorithm="true" @algorithmChange="algorithmChange" />
+ </div>
+ <div class="item">
+
+ <div class="itemchild">任务描述:</div>
+ <el-input class="ztzf-input" v-model="searchForm.remark" placeholder="请输入任务名称"></el-input>
+ </div>
</div>
<div class="lines">
<div class="wayline-type">
@@ -52,26 +74,29 @@
<el-radio :value="2" label="智能规划选区"></el-radio>
</el-radio-group>
</div>
- <TaskMap class="wayline-map"
+ <TaskMap
+ class="wayline-map"
:wayLineFile="wayLineFile"
:checkedTableData="checkedTableData"
- :waylineTypeTest="waylineType"
+ :waylineTypeTest="waylineType"
@clickPosition="clickSignPosition"
@saveWayline="savePlanerWayline"
/>
</div>
</div>
- <div class="right">
- <TaskTable ref="taskTableRef"
- :waylineId="waylineId"
- :waylineType="waylineType"
+ <div class="right ">
+ <TaskTable
+ ref="taskTableRef"
+ :waylineId="waylineId"
+ :waylineType="waylineType"
:singlePoint="singlePoint"
:planarPoints="planarPoints"
- @update:selected="handleSelected"
+ @update:selected="handleSelected"
/>
<div class="btn">
- <el-button type="primary" @click="cancel">取消</el-button>
- <el-button type="primary" @click="submitClick">发布</el-button>
+ <img @click="cancel" style="margin-right:23px" src="@/assets/images/task/cancel.png" alt="">
+ <img @click="submitClick" src="@/assets/images/task/publish.png" alt="">
+
</div>
</div>
</div>
@@ -79,26 +104,26 @@
</template>
<script setup>
-import { ElMessage } from 'element-plus';
-import { pxToRem } from '@/utils/rem';
-import { getWaylineList, createTask } from '@/api/home/task';
-import TaskAlgorithmBusiness from '../components/TaskAlgorithmBusiness.vue';
-import TaskMap from './TaskMap.vue';
-import TaskTable from './TaskTable.vue';
+import { ElMessage } from 'element-plus'
+import { pxToRem } from '@/utils/rem'
+import { getWaylineList, createTask } from '@/api/home/task'
+import TaskAlgorithmBusiness from '../components/TaskAlgorithmBusiness.vue'
+import TaskMap from './TaskMap.vue'
+import TaskTable from './TaskTable.vue'
-const emit = defineEmits(['refresh']);
+const emit = defineEmits(['refresh'])
-const rangDate = ref([]);
+const rangDate = ref([])
// 航线ID
-const waylineId = ref('');
+const waylineId = ref('')
// 航线文件
-const wayLineFile = ref('');
+const wayLineFile = ref('')
// 航线类型
-const waylineType = ref(3);
+const waylineType = ref(3)
// 添加子组件引用
-const taskTableRef = ref(null);
-const taskData = ref('');
-const timeSlot = ref('');
+const taskTableRef = ref(null)
+const taskData = ref('')
+const timeSlot = ref('')
const searchForm = reactive({
name: '',
ai_types: [],
@@ -112,157 +137,157 @@
longitude: '',
latitude: '',
polygon: [],
-});
-const isShowAddTask = defineModel('show');
+})
+const isShowAddTask = defineModel('show')
// 禁用当天之前的日期
-const disabledDate = (time) => {
- return time.getTime() < Date.now() - 8.64e7; // 86400000 = 24 * 60 * 60 * 1000
-};
+const disabledDate = time => {
+ return time.getTime() < Date.now() - 8.64e7 // 86400000 = 24 * 60 * 60 * 1000
+}
// 获取航线列表数据
-const routeOptions = ref([]);
+const routeOptions = ref([])
const getRouteList = async () => {
- const res = await getWaylineList();
- if (res.data.code === 0) {
- routeOptions.value = res.data.data;
- }
-};
+ const res = await getWaylineList()
+ if (res.data.code === 0) {
+ routeOptions.value = res.data.data
+ }
+}
// 关联算法
-const algorithmChange = (val) => {
- searchForm.ai_types = val;
-};
+const algorithmChange = val => {
+ searchForm.ai_types = val
+}
// 切换航线类型
-const radioChange = (val) => {
+const radioChange = val => {
// 清空选中航线值
- searchForm.file_id = '';
+ searchForm.file_id = ''
// 航线ID也清空
- waylineId.value = '';
- wayLineFile.value = '';
- waylineType.value = val;
- searchForm.type = val;
+ waylineId.value = ''
+ wayLineFile.value = ''
+ waylineType.value = val
+ searchForm.type = val
// 清空列表数据
nextTick(() => {
- if (taskTableRef.value) {
- taskTableRef.value.clearTableData();
- }
- });
-};
+ if (taskTableRef.value) {
+ taskTableRef.value.clearTableData()
+ }
+ })
+}
// 获取航线文件
-const getWayLineFile = async (val) => {
- searchForm.type = 0;
- waylineType.value = 0;
- waylineId.value = val;
- const currentRoute = routeOptions.value.find(item => item.wayline_id === val);
- wayLineFile.value = currentRoute.object_key;
-};
+const getWayLineFile = async val => {
+ searchForm.type = 0
+ waylineType.value = 0
+ waylineId.value = val
+ const currentRoute = routeOptions.value.find(item => item.wayline_id === val)
+ wayLineFile.value = currentRoute.object_key
+}
// 获取选中机场列表数据,并且发布
-let checkedTableData = ref([]);
-const handleSelected = (val) => {
- searchForm.dock_sns = val.map(item => item.device_sn);
- checkedTableData.value = val;
-};
+let checkedTableData = ref([])
+const handleSelected = val => {
+ searchForm.dock_sns = val.map(item => item.device_sn)
+ checkedTableData.value = val
+}
// 地图点击事件 表格重新刷新数据
-let singlePoint = ref({});
-const clickSignPosition = (val) => {
- singlePoint.value = val;
- searchForm.longitude = val.longitude;
- searchForm.latitude = val.latitude;
-};
+let singlePoint = ref({})
+const clickSignPosition = val => {
+ singlePoint.value = val
+ searchForm.longitude = val.longitude
+ searchForm.latitude = val.latitude
+}
// 保存面状航线
-let planarPoints = ref([]);
-const savePlanerWayline = (val) => {
- planarPoints.value = val;
- const polygonArray = val.map(point => [point.longitude, point.latitude]);
- searchForm.polygon = polygonArray;
-};
+let planarPoints = ref([])
+const savePlanerWayline = val => {
+ planarPoints.value = val
+ const polygonArray = val.map(point => [point.longitude, point.latitude])
+ searchForm.polygon = polygonArray
+}
// 提交
const submitClick = () => {
if (!taskData.value) {
- ElMessage({
- message: '请选择任务日期',
- type: 'warning'
- });
- return;
- }
+ ElMessage({
+ message: '请选择任务日期',
+ type: 'warning',
+ })
+ return
+ }
if (!searchForm.name) {
- ElMessage({
- message: '请输入任务名称',
- type: 'warning'
- });
- return;
- }
+ ElMessage({
+ message: '请输入任务名称',
+ type: 'warning',
+ })
+ return
+ }
// 检查任务时间
- if (timeSlot.value) {
- const now = new Date();
- const today = now.toDateString();
- const selectedDate = new Date(taskData.value).toDateString();
-
- if (today === selectedDate) {
- const [hours, minutes] = timeSlot.value.split(':');
- const selectedTime = new Date();
- selectedTime.setHours(parseInt(hours), parseInt(minutes));
-
- if (selectedTime < now) {
- ElMessage({
- message: '任务时间不能小于当前时间',
- type: 'warning'
- });
- return;
- }
- }
- }
+ if (timeSlot.value) {
+ const now = new Date()
+ const today = now.toDateString()
+ const selectedDate = new Date(taskData.value).toDateString()
+
+ if (today === selectedDate) {
+ const [hours, minutes] = timeSlot.value.split(':')
+ const selectedTime = new Date()
+ selectedTime.setHours(parseInt(hours), parseInt(minutes))
+
+ if (selectedTime < now) {
+ ElMessage({
+ message: '任务时间不能小于当前时间',
+ type: 'warning',
+ })
+ return
+ }
+ }
+ }
if (searchForm.dock_sns.length === 0) {
ElMessage({
message: '请选择机场',
- type: 'warning'
- });
- return;
+ type: 'warning',
+ })
+ return
}
- searchForm.begin_time = `${taskData.value} 00:00:00`;
- searchForm.end_time = `${taskData.value} 23:59:59`;
- searchForm.execute_time_arr = timeSlot.value ? [timeSlot.value] : [];
- createTask(searchForm).then((res) => {
+ searchForm.begin_time = `${taskData.value} 00:00:00`
+ searchForm.end_time = `${taskData.value} 23:59:59`
+ searchForm.execute_time_arr = timeSlot.value ? [timeSlot.value] : []
+ createTask(searchForm).then(res => {
if (res.data.code === 0) {
- ElMessage.success('任务创建成功');
+ ElMessage.success('任务创建成功')
// 关闭当前窗口,刷新任务管理列表
- isShowAddTask.value = false;
+ isShowAddTask.value = false
// 清除数据
- cancel();
- emit('refresh');
+ cancel()
+ emit('refresh')
}
- });
-};
+ })
+}
const cancel = () => {
- isShowAddTask.value = false;
+ isShowAddTask.value = false
// 清除搜索数据
- searchForm.name = '';
- searchForm.ai_types = [];
- searchForm.file_id = '';
- searchForm.begin_time = '';
- searchForm.end_time = '';
- timeSlot.value = '';
- searchForm.remark = '';
- searchForm.dock_sns = [];
- rangDate.value = [];
- waylineId.value = '';
- wayLineFile.value = '';
- taskData.value = '';
-};
+ searchForm.name = ''
+ searchForm.ai_types = []
+ searchForm.file_id = ''
+ searchForm.begin_time = ''
+ searchForm.end_time = ''
+ timeSlot.value = ''
+ searchForm.remark = ''
+ searchForm.dock_sns = []
+ rangDate.value = []
+ waylineId.value = ''
+ wayLineFile.value = ''
+ taskData.value = ''
+}
onMounted(() => {
- getRouteList();
+ getRouteList()
})
</script>
<style lang="scss">
-.add-task{
+.add-task {
.el-pagination {
text-align: left;
padding: 20px;
@@ -273,52 +298,72 @@
<style lang="scss" scoped>
.task-contain {
display: flex;
+ padding: 20px 32px 32px 27px;
.left {
width: 68%;
+ margin-right: 35px;
.search {
display: grid;
- grid-template-columns: repeat(3, 1fr);
- grid-template-rows: repeat(2, 1fr);
- gap: 30px; // 增加间距使布局更合理
- margin-bottom: 8px; // 添加底部间距
+ grid-template-columns: repeat(3, 1fr);
+ grid-template-rows: repeat(2, 1fr);
+ gap: 30px; // 增加间距使布局更合理
+ margin-bottom: 8px; // 添加底部间距
.item {
position: relative;
- display: flex;
- align-items: center;
- :deep(.el-input),
- :deep(.el-select),
- :deep(.el-date-picker),
- :deep(.el-time-picker) {
- width: 240px;
- // margin-left: 10px;
- }
- :deep(.el-date-editor.el-input__wrapper) {
- width: 200px; // 调整日期选择器宽度
- }
- .required {
- color: #f56c6c;
- margin-left: 4px;
- position: absolute;
- left: -10px;
- top: 8px;
+ display: flex;
+ align-items: center;
+ font-size: 16px;
+ color: #ffffff;
+ .itemchild {
+ width: 68px;
+ white-space: nowrap;
+ margin-right: 5px;
}
- }
+ :deep(.el-date-editor.el-input__wrapper) {
+ width: 200px; // 调整日期选择器宽度
+ }
+
+ }
}
}
.right {
width: 32%;
display: flex;
- flex-direction: column;
- justify-content: space-between;
-
- .btn {
- margin-top: 20px;
- text-align: center;
-
- .el-button {
- margin: 0 10px;
- }
- }
+ flex-direction: column;
+ justify-content: space-between;
+
+ .btn {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ img {
+ width: 137px;
+ height: 32px;
+ cursor: pointer;
+ }
+
+ }
+ }
+ :deep(.tasktimer .el-input__wrapper) {
+ background: none !important;
+ color: #8ac3fd !important;
+
+ }
+ :deep(.el-input__inner) {
+ color: #8ac3fd !important;
+ &::placeholder {
+ color: #8ac3fd !important;
+ }
+ }
+ :deep(.el-radio__inner){
+ background: none !important;
+ border: 1px solid #1B5D9A !important;
+ }
+ :deep(.el-radio__label){
+ color: #fff !important;
+ }
+ :deep(.el-radio__inner:after ){
+ background: #65B5FF !important;
}
}
</style>
diff --git a/src/views/TaskManage/TaskIntermediateContent/TaskMap.vue b/src/views/TaskManage/TaskIntermediateContent/TaskMap.vue
index b360db9..a8787a7 100644
--- a/src/views/TaskManage/TaskIntermediateContent/TaskMap.vue
+++ b/src/views/TaskManage/TaskIntermediateContent/TaskMap.vue
@@ -7,33 +7,37 @@
import AmapMercatorTilingScheme from '@/utils/cesium/AmapMercatorTilingScheme'
import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz'
import ImageTrailMaterial from '@/utils/cesium/ImageTrailMaterial'
-import lineImg from '@/assets/images/arrow-right-blue.png';
-import Startingpointicon from '@/assets/images/Startingpointicon.png';
-import EndPointicon from '@/assets/images/EndPointicon.png';
+import lineImg from '@/assets/images/arrow-right-blue.png'
+import Startingpointicon from '@/assets/images/Startingpointicon.png'
+import EndPointicon from '@/assets/images/EndPointicon.png'
import uavImg from '@/assets/images/home/useUavHome/uavImg.png'
import { getCenterPoint } from '@/utils/cesium/mapUtil'
-import { getWaylineByArea } from '@/api/home/task';
-import { useStore } from 'vuex';
-
-const store = useStore();
-const userAreaPosition = computed(() => store.state.home.userAreaPosition);
+import { getWaylineByArea } from '@/api/home/task'
+import { useStore } from 'vuex'
+import { addBlueFilter } from '@/utils/cesium/common'
+// 新图片
+import newStartPoint from '@/assets/images/newStartPoint.png'
+import newEndPointImg from '@/assets/images/newEndPointicon.png'
+import newlineImg from '@/assets/images/newarrow-right.png'
+const store = useStore()
+const userAreaPosition = computed(() => store.state.home.userAreaPosition)
// 声明事件
-const emit = defineEmits(['clickPosition', 'saveWayline']);
+const emit = defineEmits(['clickPosition', 'saveWayline'])
const props = defineProps({
wayLineFile: {
- type: String,
- default: ''
- },
- checkedTableData: {
- type: Array,
- default: () => []
- },
+ type: String,
+ default: '',
+ },
+ checkedTableData: {
+ type: Array,
+ default: () => [],
+ },
waylineTypeTest: {
- type: Number,
- default: 3
- }
+ type: Number,
+ default: 3,
+ },
})
const imageryProvider_ammapSL = new Cesium.UrlTemplateImageryProvider({
@@ -46,17 +50,16 @@
maximumLevel: 18,
tilingScheme: new AmapMercatorTilingScheme(),
credit: 'amap_SL',
-});
+})
-let viewer = null;
-let currentEntity = null;
-let connectLines = []; // 存储连接线实体
-let polygonPoints = []; // 存储多边形的点
-let polygonEntity = null; // 存储多边形实体
-let existingEntity = null; // 后端返回数据生成得面状线
+let viewer = null
+let currentEntity = null
+let connectLines = [] // 存储连接线实体
+let polygonPoints = [] // 存储多边形的点
+let polygonEntity = null // 存储多边形实体
+let existingEntity = null // 后端返回数据生成得面状线
// 添加变量跟踪当前菜单
-let currentMenu = null;
-
+let currentMenu = null
const init = () => {
viewer = new Viewer('taskMap', {
@@ -74,80 +77,81 @@
fullscreenButton: false,
// sceneMode: Cesium.SceneMode.COLUMBUS_VIEW,
})
- viewer.imageryLayers.addImageryProvider(imageryProvider_ammapSL)
- viewer.scene.morphTo2D(0);
+ const gdLayer = viewer.imageryLayers.addImageryProvider(imageryProvider_ammapSL)
+ const options = {
+ bInvertColor: true,
+ bFilterColor: true,
+ filterColor: '#4e70a6',
+ }
+ // 添加蓝色滤镜
+ addBlueFilter(options, viewer, gdLayer)
+ viewer.scene.morphTo2D(0)
//设置默认点
- const { longitude = 115.763819, latitude = 28.787374, height = 10 } = userAreaPosition.value || {};
+ const { longitude = 115.763819, latitude = 28.787374, height = 10 } = userAreaPosition.value || {}
viewer.camera.setView({
destination: Cartesian3.fromDegrees(longitude, latitude, height),
- });
+ })
}
// 单点左键点击事件
const singlePointLeftClick = () => {
- viewer.screenSpaceEventHandler.setInputAction((click) => {
+ viewer.screenSpaceEventHandler.setInputAction(click => {
if (props.waylineTypeTest !== 1) return
- const cartesian = viewer.camera.pickEllipsoid(
- click.position,
- viewer.scene.globe.ellipsoid
- );
- if (cartesian) {
- // 清除之前的实体
- viewer.entities.removeAll();
-
- // 添加新点
- const point = viewer.entities.add({
- position: cartesian,
- point: {
- pixelSize: 10,
- color: Cesium.Color.WHITE
- }
- });
-
- // 转换坐标
- const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
- const longitude = Cesium.Math.toDegrees(cartographic.longitude);
- const latitude = Cesium.Math.toDegrees(cartographic.latitude);
-
- // 更新当前实体引用
- currentEntity = point;
-
- // 发送坐标
- emit('clickPosition', { longitude, latitude });
- }
- }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
-};
+ const cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid)
+ if (cartesian) {
+ // 清除之前的实体
+ viewer.entities.removeAll()
+
+ // 添加新点
+ const point = viewer.entities.add({
+ position: cartesian,
+ point: {
+ pixelSize: 10,
+ color: Cesium.Color.fromCssColorString('#1FFF69'),
+ },
+ })
+
+ // 转换坐标
+ const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
+ const longitude = Cesium.Math.toDegrees(cartographic.longitude)
+ const latitude = Cesium.Math.toDegrees(cartographic.latitude)
+
+ // 更新当前实体引用
+ currentEntity = point
+
+ // 发送坐标
+ emit('clickPosition', { longitude, latitude })
+ }
+ }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
+}
// 智能规划航线
const intelligentPlanning = () => {
// 添加点击事件监听
- viewer.screenSpaceEventHandler.setInputAction((click) => {
+ viewer.screenSpaceEventHandler.setInputAction(click => {
if (props.waylineTypeTest !== 2) return
- const cartesian = viewer.camera.pickEllipsoid(
- click.position,
- viewer.scene.globe.ellipsoid
- );
-
+ const cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid)
+
if (cartesian) {
// 添加新点
const point = viewer.entities.add({
position: cartesian,
point: {
pixelSize: 10,
- color: Cesium.Color.WHITE
- }
- });
-
+ color: Cesium.Color.fromCssColorString('#1FFF69'),
+ },
+ })
+
// 存储点位
- polygonPoints.push(cartesian);
-
+ polygonPoints.push(cartesian)
+
// 当点击超过2个点时绘制多边形
if (polygonPoints.length > 2) {
// 移除旧的多边形
if (polygonEntity) {
- viewer.entities.remove(polygonEntity);
+ viewer.entities.remove(polygonEntity)
}
-
+
// 创建新的多边形
polygonEntity = viewer.entities.add({
polygon: {
@@ -159,110 +163,109 @@
outlineColor: new Cesium.Color(0, 0.5, 1, 1), // 蓝
outlineWidth: 2,
height: 0, // Set explicit height
- heightReference: Cesium.HeightReference.NONE // Disable terrain clamping
- }
- });
+ heightReference: Cesium.HeightReference.NONE, // Disable terrain clamping
+ },
+ })
}
// 转换坐标并发送
- const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
- const longitude = Cesium.Math.toDegrees(cartographic.longitude);
- const latitude = Cesium.Math.toDegrees(cartographic.latitude);
+ const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
+ const longitude = Cesium.Math.toDegrees(cartographic.longitude)
+ const latitude = Cesium.Math.toDegrees(cartographic.latitude)
// emit('clickPosition', cartographic);
-
}
- }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+ }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 修改右键点击事件,添加菜单
- viewer.screenSpaceEventHandler.setInputAction((movement) => {
+ viewer.screenSpaceEventHandler.setInputAction(movement => {
if (props.waylineTypeTest !== 2) return
if (polygonPoints.length > 2) {
// 清除之前的菜单
if (currentMenu) {
- document.body.querySelectorAll('.context-menu').forEach(menu => menu.remove());
+ document.body.querySelectorAll('.context-menu').forEach(menu => menu.remove())
}
- const menuContainer = document.createElement('div');
- menuContainer.className = 'context-menu';
+ const menuContainer = document.createElement('div')
+ menuContainer.className = 'context-menu'
// 获取地图容器
- const mapContainer = document.getElementById('taskMap');
+ const mapContainer = document.getElementById('taskMap')
// 使用鼠标右键点击的实际位置
- menuContainer.style.position = 'absolute';
- menuContainer.style.left = `${movement.position.x}px`;
- menuContainer.style.top = `${movement.position.y}px`;
- menuContainer.style.zIndex = '1000';
+ menuContainer.style.position = 'absolute'
+ menuContainer.style.left = `${movement.position.x}px`
+ menuContainer.style.top = `${movement.position.y}px`
+ menuContainer.style.zIndex = '1000'
menuContainer.innerHTML = `
<div class="menu-item" id="saveWayline">保存航线</div>
<div class="menu-item" id="cancelDraw">取消绘制</div>
- `;
-
- mapContainer.appendChild(menuContainer);
- currentMenu = menuContainer;
+ `
+
+ mapContainer.appendChild(menuContainer)
+ currentMenu = menuContainer
// 添加全局点击事件监听
- const handleClickOutside = (e) => {
- if (!menuContainer) return;
- const isClickInside = menuContainer.contains(e.target);
+ const handleClickOutside = e => {
+ if (!menuContainer) return
+ const isClickInside = menuContainer.contains(e.target)
if (!isClickInside) {
- menuContainer.remove();
- document.removeEventListener('mousedown', handleClickOutside);
+ menuContainer.remove()
+ document.removeEventListener('mousedown', handleClickOutside)
}
- };
+ }
// 延迟添加事件监听,避免右键点击立即触发
setTimeout(() => {
- document.addEventListener('mousedown', handleClickOutside);
- }, 100);
+ document.addEventListener('mousedown', handleClickOutside)
+ }, 100)
// 菜单按钮点击事件
document.getElementById('saveWayline').onclick = () => {
const coordinates = polygonPoints.map(point => {
- const cartographic = Cesium.Cartographic.fromCartesian(point);
+ const cartographic = Cesium.Cartographic.fromCartesian(point)
return {
longitude: Cesium.Math.toDegrees(cartographic.longitude),
- latitude: Cesium.Math.toDegrees(cartographic.latitude)
- };
- });
- emit('saveWayline', coordinates);
- saveWaylineByArea(coordinates);
- mapContainer.removeChild(menuContainer);
- };
-
+ latitude: Cesium.Math.toDegrees(cartographic.latitude),
+ }
+ })
+ emit('saveWayline', coordinates)
+ saveWaylineByArea(coordinates)
+ mapContainer.removeChild(menuContainer)
+ }
+
document.getElementById('cancelDraw').onclick = () => {
- polygonPoints = [];
- viewer.entities.removeAll();
- mapContainer.removeChild(menuContainer);
- };
+ polygonPoints = []
+ viewer.entities.removeAll()
+ mapContainer.removeChild(menuContainer)
+ }
}
- }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
-};
+ }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
+}
// 保存航线并且获取线
-const saveWaylineByArea = (dataValue) => {
- const polygonArray = dataValue.map(point => [point.longitude, point.latitude]);
+const saveWaylineByArea = dataValue => {
+ const polygonArray = dataValue.map(point => [point.longitude, point.latitude])
getWaylineByArea({ type: 2, polygon: polygonArray }).then(res => {
- if (res.data.code !== 0) retrun;
- drawResultWayline(res.data.data);
- });
+ if (res.data.code !== 0) retrun
+ drawResultWayline(res.data.data)
+ })
}
// 绘制后端生成得面状线
-const drawResultWayline = (dataValue) => {
+const drawResultWayline = dataValue => {
// 先检查并删除已存在的航线
- existingEntity = viewer.entities.getById('result_wayline');
- if (existingEntity) {
- viewer.entities.remove(existingEntity);
- }
- const cartesian3List = ref([]);
- dataValue.forEach((lnglat) => {
+ existingEntity = viewer.entities.getById('result_wayline')
+ if (existingEntity) {
+ viewer.entities.remove(existingEntity)
+ }
+ const cartesian3List = ref([])
+ dataValue.forEach(lnglat => {
const cartesian3 = Cesium.Cartesian3.fromDegrees(
Number(lnglat.x),
Number(lnglat.y),
- Number(100), // 默认100
+ Number(100) // 默认100
)
cartesian3List.value.push(cartesian3)
- });
+ })
const setting = {
id: 'result_wayline',
polyline: {
@@ -275,7 +278,7 @@
polyline: setting.polyline,
id: setting.id,
})
-};
+}
// 选中航线时调用 渲染线和点 type = 0
const renderingLine = lineObj => {
@@ -283,83 +286,90 @@
const [lon, lat] = item.Point.coordinates.split(',')
return Cartesian3.fromDegrees(Number(lon), Number(lat))
})
-
+
viewer.entities.add({
polyline: {
- width: 4,
+ width: 5,
positions: positions,
- material: new ImageTrailMaterial({
- color: { alpha: 1, blue: 1, green: 1, red: 1 },
- speed: 20,
- image: lineImg,
- repeat: { x: Math.floor(40), y: 1 },
+ // material: new ImageTrailMaterial({
+ // color: { alpha: 1, blue: 1, green: 1, red: 1 },
+ // speed: 20,
+ // image: newlineImg,
+ // repeat: { x: Math.floor(40), y: 1 },
+ // }),
+ material: new Cesium.PolylineGlowMaterialProperty({
+ // color: Cesium.Color.GREEN,
+ image: newlineImg,
}),
clampToGround: false,
},
})
-
- positions.forEach((point, index) => {
- let setting = {};
- // if (index === 0) {
- // //TODO
- // }
+
+ positions.forEach((point, index) => {
+ let setting = {}
+ // if (index === 0) {
+ // //TODO
+ // }
// else if (index === 1) {
- // setting = {
- // position: point,
- // id: `point_${index}`,
- // billboard: {
- // image: Startingpointicon,
- // outlineWidth: 0,
- // width: 20,
- // height: 20,
- // scale: 1.0,
- // },
- // }
- // } else
+ // setting = {
+ // position: point,
+ // id: `point_${index}`,
+ // billboard: {
+ // image: Startingpointicon,
+ // outlineWidth: 0,
+ // width: 20,
+ // height: 20,
+ // scale: 1.0,
+ // },
+ // }
+ // } else
if (index === positions.length - 1) {
- setting = {
- position: point,
- id: `point_${index}`,
- billboard: {
- image: EndPointicon,
- outlineWidth: 0,
- width: 20,
- height: 20,
- scale: 1.0,
- },
- }
- } else {
- setting = {
- position: point,
- id: `point_${index}`,
- label: {
- text: `${index+1}`,
- font: 'bold 14px serif',
- style: Cesium.LabelStyle.FILL,
- verticalOrigin: Cesium.VerticalOrigin.CENTER, // 垂直居中
- horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平居中
- pixelOffset: new Cesium.Cartesian2(0, 0), // 根据需要调整偏移量
- eyeOffset: new Cesium.Cartesian3(0, 0, -10) // 使标签在点的上方
- },
+ setting = {
+ position: point,
+ id: `point_${index}`,
+ billboard: {
+ image: newEndPointImg,
+ outlineWidth: 0,
+ width: 20,
+ height: 20,
+ scale: 1.0,
+ },
+ }
+ } else {
+ setting = {
+ position: point,
+ id: `point_${index}`,
+ label: {
+ text: `${index + 1}`,
+ font: 'bold 14px serif',
+ fillColor: Cesium.Color.WHITE,
+ // style: Cesium.LabelStyle.FILL,
+ // verticalOrigin: Cesium.VerticalOrigin.CENTER, // 垂直居中
+ // horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平居中
+ pixelOffset: new Cesium.Cartesian2(2, 0), // 根据需要调整偏移量
+ eyeOffset: new Cesium.Cartesian3(0, 0, -10), // 使标签在点的上方
+ },
+ billboard: {
+ image: new Cesium.ConstantProperty(newStartPoint),
+ width: 70,
+ height: 70,
+ },
+ // point: {
+ // pixelSize: 24,
+ // color: new Cesium.Color.fromBytes(255, 186, 0, 255),
+ // },
- point: {
- pixelSize: 24,
- color: new Cesium.Color.fromBytes(255, 186, 0, 255),
- },
-
- offset: new Cesium.Cartesian2(10, 30),
- }
- }
- viewer.entities.add(setting)
- });
+ offset: new Cesium.Cartesian2(10, 30),
+ }
+ }
+ viewer.entities.add(setting)
+ })
}
// 飞到中心点
function flyToPoints(lngLatArr) {
if (!Array.isArray(lngLatArr) || lngLatArr.length === 0) return
- const positions = lngLatArr.map(([lon, lat]) =>
- Cesium.Cartesian3.fromDegrees(Number(lon), Number(lat))
- )
+ const positions = lngLatArr.map(([lon, lat]) => Cesium.Cartesian3.fromDegrees(Number(lon), Number(lat)))
// 计算包围盒 BoundingSphere(所有点的外接球)
const boundingSphere = Cesium.BoundingSphere.fromPoints(positions)
viewer.camera.flyToBoundingSphere(boundingSphere, {
@@ -368,11 +378,10 @@
})
}
-
// 异步解析kmz文件
const analysis = async url => {
return new Promise(async resolve => {
- const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`);
+ const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`)
const templateXML = await res.fileInfoObj['wpmz/template.kml']
const templateXMLJSON = XMLToJSON(templateXML)?.['Document']
const templateXMLObj = removeTextKey(templateXMLJSON.Folder)
@@ -382,16 +391,16 @@
// 绘制线和飞行
const drawLine = async () => {
- let prexUrl = ref(import.meta.env.VITE_APP_AIRLINE_URL+ props.wayLineFile);
- const res = await analysis(prexUrl.value);
+ let prexUrl = ref(import.meta.env.VITE_APP_AIRLINE_URL + props.wayLineFile)
+ const res = await analysis(prexUrl.value)
if (!res.Placemark.length) return
- renderingLine(res);
+ renderingLine(res)
const points = res.Placemark.map(item => item.Point.coordinates.split(','))
flyToPoints(points)
}
// 选择航线时,根据选择机巢连线
-const selectLineFile = (newVal) => {
+const selectLineFile = newVal => {
// 清除之前的实体
// viewer.entities.removeAll();
// 重新绘制航线
@@ -400,7 +409,7 @@
// }
// 添加选中点和连接线
const positions = newVal.map(item => {
- const position = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude));
+ const position = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude))
// 添加机巢点
viewer.entities.add({
position: position,
@@ -409,9 +418,9 @@
width: 24,
height: 24,
},
- });
- return position;
- });
+ })
+ return position
+ })
// 添加连接线
if (positions.length > 1) {
@@ -421,33 +430,30 @@
width: 2,
material: new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.RED,
- dashLength: 8.0
- })
- }
- });
+ dashLength: 8.0,
+ }),
+ },
+ })
}
// 飞到中心点
- const lngLatArr = newVal.map(item => [item.longitude, item.latitude]);
- flyToPoints(lngLatArr);
-};
+ const lngLatArr = newVal.map(item => [item.longitude, item.latitude])
+ flyToPoints(lngLatArr)
+}
// 单个点生成选择多个机巢生成航线
-const singlePointLines = (newVal) => {
+const singlePointLines = newVal => {
// 清除之前的连接线
- connectLines.forEach(line => viewer.entities.remove(line));
- connectLines = [];
+ connectLines.forEach(line => viewer.entities.remove(line))
+ connectLines = []
if (currentEntity) {
// 获取当前点的位置
- const currentPosition = currentEntity.position.getValue();
-
+ const currentPosition = currentEntity.position.getValue()
+
// 为每个选中的机巢创建点和连接线
newVal.forEach(item => {
// 创建机巢点
- const nestPosition = Cartesian3.fromDegrees(
- Number(item.longitude),
- Number(item.latitude)
- );
+ const nestPosition = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude))
viewer.entities.add({
position: nestPosition,
billboard: {
@@ -455,7 +461,7 @@
width: 24,
height: 24,
},
- });
+ })
// 创建连接线
const line = viewer.entities.add({
@@ -464,155 +470,163 @@
width: 2,
material: new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.RED,
- dashLength: 8.0
- })
- }
- });
- connectLines.push(line);
- });
+ dashLength: 8.0,
+ }),
+ },
+ })
+ connectLines.push(line)
+ })
// 飞到所有点的中心位置
- const lngLatArr = newVal.map(item => [item.longitude, item.latitude]);
- flyToPoints(lngLatArr);
+ const lngLatArr = newVal.map(item => [item.longitude, item.latitude])
+ flyToPoints(lngLatArr)
}
-};
+}
// 智慧规划航线-面状航线
-const planarPointsLines = (newVal) => {
- // 如果存在面状航线
- if (existingEntity) {
- const waylinePositions = existingEntity.polyline.positions.getValue();
-
- newVal.forEach(item => {
- // 创建机巢点
- const nestPosition = Cartesian3.fromDegrees(
- Number(item.longitude),
- Number(item.latitude)
- );
-
- // 添加机巢图标
- viewer.entities.add({
- position: nestPosition,
- billboard: {
- image: new Cesium.ConstantProperty(uavImg),
- width: 24,
- height: 24,
- },
- });
+const planarPointsLines = newVal => {
+ // 如果存在面状航线
+ if (existingEntity) {
+ const waylinePositions = existingEntity.polyline.positions.getValue()
- // 找到最近的航线点并连线
- let minDistance = Number.MAX_VALUE;
- let closestPosition = null;
-
- waylinePositions.forEach(waylinePos => {
- const distance = Cartesian3.distance(nestPosition, waylinePos);
- if (distance < minDistance) {
- minDistance = distance;
- closestPosition = waylinePos;
- }
- });
+ newVal.forEach(item => {
+ // 创建机巢点
+ const nestPosition = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude))
- // 创建连接线
- if (closestPosition) {
- const line = viewer.entities.add({
- polyline: {
- positions: [nestPosition, closestPosition],
- width: 2,
- material: new Cesium.PolylineDashMaterialProperty({
- color: Cesium.Color.CHARTREUSE,
- dashLength: 8.0
- })
- }
- });
- connectLines.push(line);
- }
- });
+ // 添加机巢图标
+ viewer.entities.add({
+ position: nestPosition,
+ billboard: {
+ image: new Cesium.ConstantProperty(uavImg),
+ width: 24,
+ height: 24,
+ },
+ })
- // 飞到所有点的中心位置
- const lngLatArr = newVal.map(item => [item.longitude, item.latitude]);
- flyToPoints(lngLatArr);
- }
-};
+ // 找到最近的航线点并连线
+ let minDistance = Number.MAX_VALUE
+ let closestPosition = null
+
+ waylinePositions.forEach(waylinePos => {
+ const distance = Cartesian3.distance(nestPosition, waylinePos)
+ if (distance < minDistance) {
+ minDistance = distance
+ closestPosition = waylinePos
+ }
+ })
+
+ // 创建连接线
+ if (closestPosition) {
+ const line = viewer.entities.add({
+ polyline: {
+ positions: [nestPosition, closestPosition],
+ width: 2,
+ material: new Cesium.PolylineDashMaterialProperty({
+ color: Cesium.Color.CHARTREUSE,
+ dashLength: 8.0,
+ }),
+ },
+ })
+ connectLines.push(line)
+ }
+ })
+
+ // 飞到所有点的中心位置
+ const lngLatArr = newVal.map(item => [item.longitude, item.latitude])
+ flyToPoints(lngLatArr)
+ }
+}
// 监听选择航线文件事件
-watch(() => props.wayLineFile, async (newVal, oldValue) => {
- await removeMap();
- if(newVal){
- await drawLine();
- }
-}, { deep: true });
+watch(
+ () => props.wayLineFile,
+ async (newVal, oldValue) => {
+ await removeMap()
+ if (newVal) {
+ await drawLine()
+ }
+ },
+ { deep: true }
+)
// 监听表格选中数据变化
-watch(() => props.checkedTableData, (newVal) => {
- if (newVal.length > 0 && props.waylineTypeTest === 0) {
- selectLineFile(newVal);
- } else if (newVal.length > 0 && props.waylineTypeTest === 1) {
- singlePointLines(newVal);
- } else if (newVal.length > 0 && props.waylineTypeTest === 2) {
- planarPointsLines(newVal);
- }
-}, { deep: true });
+watch(
+ () => props.checkedTableData,
+ newVal => {
+ if (newVal.length > 0 && props.waylineTypeTest === 0) {
+ selectLineFile(newVal)
+ } else if (newVal.length > 0 && props.waylineTypeTest === 1) {
+ singlePointLines(newVal)
+ } else if (newVal.length > 0 && props.waylineTypeTest === 2) {
+ planarPointsLines(newVal)
+ }
+ },
+ { deep: true }
+)
// 监听航线类型
-watch(() => props.waylineTypeTest, async (newVal) => {
- await removeMap();
- if (newVal === 1) {
- await singlePointLeftClick();
- } else if (newVal === 2) {
- await intelligentPlanning();
- }
-}, { deep: true });
+watch(
+ () => props.waylineTypeTest,
+ async newVal => {
+ await removeMap()
+ if (newVal === 1) {
+ await singlePointLeftClick()
+ } else if (newVal === 2) {
+ await intelligentPlanning()
+ }
+ },
+ { deep: true }
+)
const removeEvent = () => {
// 清除事件监听器
- viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
- viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
-};
-
-const removeMap = () => {
- // 清除所有实体
- if (viewer) {
- // 清除连接线
- connectLines.forEach(line => viewer.entities.remove(line));
- connectLines = [];
-
- // 清除多边形点和实体
- polygonPoints = [];
- if (polygonEntity) {
- viewer.entities.remove(polygonEntity);
- }
-
- // 清除当前实体和面状航线
- if (currentEntity) {
- viewer.entities.remove(currentEntity);
- }
- if (existingEntity) {
- viewer.entities.remove(existingEntity);
- }
-
- viewer.entities.removeAll();
-
- // 重置所有变量
- currentEntity = null;
- polygonEntity = null;
- existingEntity = null;
- }
+ viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
+ viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
+const removeMap = () => {
+ // 清除所有实体
+ if (viewer) {
+ // 清除连接线
+ connectLines.forEach(line => viewer.entities.remove(line))
+ connectLines = []
+
+ // 清除多边形点和实体
+ polygonPoints = []
+ if (polygonEntity) {
+ viewer.entities.remove(polygonEntity)
+ }
+
+ // 清除当前实体和面状航线
+ if (currentEntity) {
+ viewer.entities.remove(currentEntity)
+ }
+ if (existingEntity) {
+ viewer.entities.remove(existingEntity)
+ }
+
+ viewer.entities.removeAll()
+
+ // 重置所有变量
+ currentEntity = null
+ polygonEntity = null
+ existingEntity = null
+ }
+}
onBeforeUnmount(() => {
- removeMap();
- removeEvent();
+ removeMap()
+ removeEvent()
// 移除所有实体并销毁viewer
- viewer.destroy();
- viewer = null;
+ viewer.destroy()
+ viewer = null
})
onMounted(() => {
nextTick(() => {
init()
})
-});
+})
</script>
<style scoped lang="scss">
#taskMap {
@@ -644,14 +658,14 @@
display: none;
}
}
-
-:deep(.context-menu) {
- position: absolute;
- background: rgba(0, 21, 41, 0.9);;
- border-radius: 4px;
- padding: 8px 0;
- min-width: 120px;
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
+
+ :deep(.context-menu) {
+ position: absolute;
+ background: rgba(0, 21, 41, 0.9);
+ border-radius: 4px;
+ padding: 8px 0;
+ min-width: 120px;
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
.menu-item {
padding: 8px 16px;
@@ -659,12 +673,11 @@
cursor: pointer;
transition: all 0.3s;
font-size: 14px;
-
+
&:hover {
background: rgba(255, 255, 255, 0.1);
}
}
}
}
-
</style>
diff --git a/src/views/TaskManage/TaskIntermediateContent/TaskTable.vue b/src/views/TaskManage/TaskIntermediateContent/TaskTable.vue
index 6d1b608..b8ff51b 100644
--- a/src/views/TaskManage/TaskIntermediateContent/TaskTable.vue
+++ b/src/views/TaskManage/TaskIntermediateContent/TaskTable.vue
@@ -1,189 +1,230 @@
<template>
- <div class="table-container">
- <el-table :data="tableData" style="width: 100%" height="400"
- @selection-change="handleSelectionChange"
- @select="handleSelect">
- <el-table-column type="selection" width="55" :selectable="checkSelectable" />
- <el-table-column type="index" label="序号" width="60" />
- <el-table-column prop="nickname" label="机巢名称" />
- <el-table-column prop="estimated_arrival_time" label="预计到达时间" />
- <el-table-column prop="exe_distance" label="执行里程" />
- </el-table>
- <div class="pagination">
- <el-pagination
- v-model:current-page="pagingParams.page"
- v-model:page-size="pagingParams.size"
- :page-sizes="[10, 20, 30]"
- layout="total, sizes, prev, pager, next"
- :total="total"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- />
- </div>
- </div>
+ <div class="table-container ztzf-table">
+ <div class="taskTableTitle"><span>可飞行机巢列表</span></div>
+ <el-table
+ :data="tableData"
+ style="width: 100%"
+ height="400"
+ :row-style="{ height: '38px', fontSize: '14px', 'text-align': 'center' }"
+ :header-cell-style="{ 'text-align': 'center', height: '36px', fontSize: '14px' }"
+ @selection-change="handleSelectionChange"
+ @select="handleSelect"
+ >
+ <el-table-column type="selection" width="55" :selectable="checkSelectable" />
+ <el-table-column type="index" label="序号" width="60" >
+ <template #default="{ $index }">
+ {{ ($index + 1).toString().padStart(2, '0') }}
+ </template>
+ </el-table-column>
+ <el-table-column show-overflow-tooltip prop="nickname" label="机巢名称" />
+ <el-table-column show-overflow-tooltip width="120" prop="estimated_arrival_time" label="预计到达时间" />
+ <el-table-column show-overflow-tooltip prop="exe_distance" label="执行里程" />
+ </el-table>
+ <div class="pagination">
+ <el-pagination
+ class="ztzf-pagination"
+ v-model:current-page="pagingParams.page"
+ v-model:page-size="pagingParams.size"
+ :page-sizes="[10, 20, 30]"
+ layout=" prev, pager, next"
+ :total="total"
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ />
+ </div>
+ </div>
</template>
<script setup>
-import { getFlyingNestBy } from '@/api/home/task';
+import { getFlyingNestBy } from '@/api/home/task'
const props = defineProps({
- waylineId: {
- type: String,
- default: ''
- },
- waylineType: {
- type: Number,
- default: 3
- },
- singlePoint: {
- type: Object,
- default: () => ({})
- },
- planarPoints: {
- type: Array,
- default: () => ([])
- }
-});
+ waylineId: {
+ type: String,
+ default: '',
+ },
+ waylineType: {
+ type: Number,
+ default: 3,
+ },
+ singlePoint: {
+ type: Object,
+ default: () => ({}),
+ },
+ planarPoints: {
+ type: Array,
+ default: () => [],
+ },
+})
// 选中的数据
-const selectedRows = ref([]);
+const selectedRows = ref([])
// 分页参数
let pageParams = ref({
- wayline_id: props.waylineId,
- type: props.waylineType,
- longitude: props.singlePoint.longitude,
- latitude: props.singlePoint.latitude,
- polygon: [],
-});
+ wayline_id: props.waylineId,
+ type: props.waylineType,
+ longitude: props.singlePoint.longitude,
+ latitude: props.singlePoint.latitude,
+ polygon: [],
+})
let pagingParams = ref({
- current: 1,
- size: 10
-});
+ current: 1,
+ size: 10,
+})
// 获取可用机巢列表数据
-const total = ref(0);
-const tableData = ref([]);
+const total = ref(0)
+const tableData = ref([])
const getNestList = async () => {
- tableData.value = [];
- const res = await getFlyingNestBy(pageParams.value, pagingParams.value);
- if (res.data.code === 0) {
- tableData.value = res.data.data;
- }
-};
+ tableData.value = []
+ const res = await getFlyingNestBy(pageParams.value, pagingParams.value)
+ if (res.data.code === 0) {
+ tableData.value = res.data.data
+ }
+}
// 分页大小改变
-const handleSizeChange = (val) => {
- pagingParams.value.size = val;
- getNestList();
-};
+const handleSizeChange = val => {
+ pagingParams.value.size = val
+ getNestList()
+}
// 页码改变
-const handleCurrentChange = (val) => {
- pagingParams.value.current = val;
- getNestList();
-};
+const handleCurrentChange = val => {
+ pagingParams.value.current = val
+ getNestList()
+}
// 刷新数据
const refreshData = () => {
- tableData.value = [];
- pagingParams.value.current = 1;
- getNestList();
-};
+ tableData.value = []
+ pagingParams.value.current = 1
+ getNestList()
+}
-const emit = defineEmits(['update:selected']);
-const handleSelectionChange = (val) => {
- // 如果不是智能规划选区模式,才更新所有选中数据
- if (props.waylineType !== 2) {
- selectedRows.value = val;
- emit('update:selected', val);
- }
-};
+const emit = defineEmits(['update:selected'])
+const handleSelectionChange = val => {
+ // 如果不是智能规划选区模式,才更新所有选中数据
+ if (props.waylineType !== 2) {
+ selectedRows.value = val
+ emit('update:selected', val)
+ }
+}
// 控制表格行是否可选
-const checkSelectable = (row) => {
- if (props.waylineType === 2) {
- // 如果已经有选中的行,且当前行未被选中,则不允许选择
- return selectedRows.value.length === 0 || selectedRows.value.some(selected => selected.device_sn === row.device_sn);
- }
- return true;
-};
+const checkSelectable = row => {
+ if (props.waylineType === 2) {
+ // 如果已经有选中的行,且当前行未被选中,则不允许选择
+ return selectedRows.value.length === 0 || selectedRows.value.some(selected => selected.device_sn === row.device_sn)
+ }
+ return true
+}
// 处理单行选择
const handleSelect = (selection, row) => {
- if (props.waylineType === 2) {
- // 如果是智能规划选区模式,确保只能选中一行
- if (selection.length > 1) {
- // 保留最后选中的那一行
- const lastSelected = selection[selection.length - 1];
- selectedRows.value = [lastSelected];
- // 触发更新事件
- emit('update:selected', selectedRows.value);
- }
- }
-};
+ if (props.waylineType === 2) {
+ // 如果是智能规划选区模式,确保只能选中一行
+ if (selection.length > 1) {
+ // 保留最后选中的那一行
+ const lastSelected = selection[selection.length - 1]
+ selectedRows.value = [lastSelected]
+ // 触发更新事件
+ emit('update:selected', selectedRows.value)
+ }
+ }
+}
// 监听航线ID变化
-watch(() => props.waylineId, (newVal) => {
- pageParams.value.type = 0;
- if (newVal) {
- pageParams.value.wayline_id = newVal;
- refreshData();
- } else {
- // 数据为空时,清除列表数据
- tableData.value = [];
- }
-}, { deep: true });
+watch(
+ () => props.waylineId,
+ newVal => {
+ pageParams.value.type = 0
+ if (newVal) {
+ pageParams.value.wayline_id = newVal
+ refreshData()
+ } else {
+ // 数据为空时,清除列表数据
+ tableData.value = []
+ }
+ },
+ { deep: true }
+)
// 监听单点返回的数据
-watch(() => props.singlePoint, (newVal) => {
- pageParams.value.wayline_id = '';
- pageParams.value.type = 1;
- if (newVal && newVal.latitude && newVal.longitude) {
- pageParams.value.latitude = newVal.latitude;
- pageParams.value.longitude = newVal.longitude;
- refreshData();
- }
-}, { deep: true });
+watch(
+ () => props.singlePoint,
+ newVal => {
+ pageParams.value.wayline_id = ''
+ pageParams.value.type = 1
+ if (newVal && newVal.latitude && newVal.longitude) {
+ pageParams.value.latitude = newVal.latitude
+ pageParams.value.longitude = newVal.longitude
+ refreshData()
+ }
+ },
+ { deep: true }
+)
// 监听面状航线返回的数据
-watch(() => props.planarPoints, (newVal) => {
- pageParams.value.wayline_id = '';
- pageParams.value.type = 2;
- if (newVal && newVal.length > 0) {
- const polygonArray = newVal.map(point => [point.longitude, point.latitude]);
- pageParams.value.polygon = polygonArray;
- refreshData();
- }
-}, { deep: true });
+watch(
+ () => props.planarPoints,
+ newVal => {
+ pageParams.value.wayline_id = ''
+ pageParams.value.type = 2
+ if (newVal && newVal.length > 0) {
+ const polygonArray = newVal.map(point => [point.longitude, point.latitude])
+ pageParams.value.polygon = polygonArray
+ refreshData()
+ }
+ },
+ { deep: true }
+)
// 暴露给父组件的方法
const clearTableData = () => {
- tableData.value = [];
-};
+ tableData.value = []
+}
defineExpose({
- clearTableData
-});
-
-
-onMounted(() => {});
-
+ clearTableData,
+})
+// 表格隔行变色
+const tableRowClassName = ({ row, rowIndex }) => {
+ if (rowIndex % 2 === 1) {
+ return 'warning-row'
+ } else {
+ return 'success-row'
+ }
+}
+onMounted(() => {})
</script>
<style lang="scss" scoped>
.table-container {
- height: 500px;
- // display: flex;
- // flex-direction: column;
-
- .pagination {
- margin-top: 10px;
- }
-
- // :deep(.el-table) {
- // flex: 1;
- // background-color: transparent;
- // --el-table-border-color: rgba(255, 255, 255, 0.1);
- // --el-table-header-bg-color: rgba(31, 62, 122, 0.5);
- // --el-table-header-text-color: #fff;
- // --el-table-text-color: #fff;
- // }
+ height: 500px;
+ .pagination {
+ margin-top: 10px;
+ }
+
+ // 分页
+ :deep(.el-pagination) {
+ display: flex;
+ justify-content: center;
+ }
+ .taskTableTitle {
+ margin-bottom: 16px;
+ background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
+ background-size: 100% 100%;
+ span {
+ display: inline-block;
+ margin-left: 10px;
+ font-size: 16px;
+ color: #ddf0ff;
+ line-height: 20px;
+ text-align: left;
+ margin-bottom: 8px;
+ }
+ }
+ :deep(.el-checkbox__inner){
+ background: none !important;
+ border: 1px solid #3194EF !important;
+ }
}
</style>
\ No newline at end of file
diff --git a/src/views/TaskManage/TaskTop/TaskTime.vue b/src/views/TaskManage/TaskTop/TaskTime.vue
index d4a7c31..c9cb869 100644
--- a/src/views/TaskManage/TaskTop/TaskTime.vue
+++ b/src/views/TaskManage/TaskTop/TaskTime.vue
@@ -107,7 +107,6 @@
// 添加监听
watch(() => store.state.task.taskSearchParams, (newVal) => {
- console.log(newVal, '33333');
if (newVal) {
getJobNumBar(newVal);
(newVal);
diff --git a/vite.config.mjs.timestamp-1744707003737-1868137d88f2d.mjs b/vite.config.mjs.timestamp-1744707003737-1868137d88f2d.mjs
new file mode 100644
index 0000000..9ccffb4
--- /dev/null
+++ b/vite.config.mjs.timestamp-1744707003737-1868137d88f2d.mjs
@@ -0,0 +1,187 @@
+// vite.config.mjs
+import {
+ defineConfig,
+ loadEnv
+} from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/vite/dist/node/index.js";
+import { resolve } from "path";
+
+// vite/plugins/index.js
+import vue from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/@vitejs/plugin-vue/dist/index.mjs";
+
+// vite/plugins/auto-import.js
+import autoImport from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/unplugin-auto-import/dist/vite.js";
+function createAutoImport() {
+ return autoImport({
+ imports: ["vue", "vue-router", "vuex"],
+ dts: false
+ });
+}
+
+// vite/plugins/compression.js
+import compression from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/vite-plugin-compression/dist/index.mjs";
+function createCompression(env) {
+ const { VITE_BUILD_COMPRESS } = env;
+ const plugin = [];
+ if (VITE_BUILD_COMPRESS) {
+ const compressList = VITE_BUILD_COMPRESS.split(",");
+ if (compressList.includes("gzip")) {
+ plugin.push(
+ compression({
+ ext: ".gz",
+ deleteOriginFile: false
+ })
+ );
+ }
+ if (compressList.includes("brotli")) {
+ plugin.push(
+ compression({
+ ext: ".br",
+ algorithm: "brotliCompress",
+ deleteOriginFile: false
+ })
+ );
+ }
+ }
+ return plugin;
+}
+
+// vite/plugins/setup-extend.js
+import setupExtend from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/vite-plugin-vue-setup-extend/dist/index.mjs";
+function createSetupExtend() {
+ return setupExtend();
+}
+
+// vite/plugins/svg-plugin.js
+import { createSvgIconsPlugin } from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/vite-plugin-svg-icons/dist/index.mjs";
+import path from "path";
+function createSvgPlugin() {
+ return createSvgIconsPlugin({
+ iconDirs: [path.resolve(process.cwd(), "src/assets/svg")],
+ //svg图片存放的目录
+ symbolId: "icon-[name]",
+ // symbol的id
+ inject: "body-last",
+ // 插入的位置
+ customDomId: "__svg__icons__dom__"
+ // svg的id
+ });
+}
+
+// vite/plugins/index.js
+function createVitePlugins(viteEnv, isBuild = false) {
+ const vitePlugins = [vue()];
+ vitePlugins.push(createAutoImport());
+ vitePlugins.push(createSetupExtend());
+ vitePlugins.push(createSvgPlugin());
+ isBuild && vitePlugins.push(...createCompression(viteEnv));
+ return vitePlugins;
+}
+
+// vite.config.mjs
+import postCssPxToRem from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/postcss-pxtorem/index.js";
+var __vite_injected_original_dirname = "E:\\\u9648\u7476\\\u4E2D\u56FE\u667A\u98DE\\command-center-dashboard";
+var vite_config_default = ({
+ mode,
+ command
+}) => {
+ const env = loadEnv(mode, process.cwd());
+ const {
+ VITE_APP_ENV,
+ VITE_APP_BASE,
+ VITE_APP_API_URL
+ } = env;
+ const isProd = VITE_APP_ENV === "production";
+ const buildConfig = {
+ target: "esnext",
+ minify: isProd ? "terser" : "esbuild"
+ // 根据环境选择压缩工具
+ };
+ if (isProd) {
+ buildConfig.terserOptions = {
+ compress: {
+ drop_console: true,
+ // 删除 console
+ drop_debugger: true
+ // 删除 debugger
+ },
+ format: {
+ comments: false
+ // 删除所有注释
+ }
+ };
+ buildConfig.rollupOptions = {
+ output: {
+ manualChunks: {
+ "element-plus": ["element-plus"],
+ "@smallwei/avue": ["@smallwei/avue"]
+ }
+ }
+ };
+ }
+ return defineConfig({
+ base: VITE_APP_BASE,
+ define: {
+ __VUE_I18N_FULL_INSTALL__: true,
+ __VUE_I18N_LEGACY_API__: true,
+ __INTLIFY_PROD_DEVTOOLS__: false
+ },
+ server: {
+ // port: 2888,
+ proxy: {
+ "/api": {
+ target: VITE_APP_API_URL,
+ changeOrigin: true,
+ rewrite: (path2) => path2.replace(/^\/api/, "")
+ }
+ }
+ },
+ resolve: {
+ alias: {
+ "~": resolve(__vite_injected_original_dirname, "./"),
+ "@": resolve(__vite_injected_original_dirname, "./src"),
+ components: resolve(__vite_injected_original_dirname, "./src/components"),
+ styles: resolve(__vite_injected_original_dirname, "./src/styles"),
+ utils: resolve(__vite_injected_original_dirname, "./src/utils")
+ }
+ },
+ css: {
+ preprocessorOptions: {
+ scss: {
+ api: "modern-compiler",
+ additionalData: `@use "@/styles/variables.scss" as *;`
+ }
+ },
+ postcss: {
+ plugins: [
+ postCssPxToRem({
+ rootValue: 10,
+ // 指定转换基准值,通常是设计稿宽度的1/10
+ propList: ["*"],
+ // 可以从px转换为rem的属性,这里是所有属性
+ unitPrecision: 5,
+ // 允许REM单位增长到的十进制数
+ selectorBlackList: [],
+ // 选择器黑名单,忽略转换的选择器
+ replace: true,
+ // 替换包含rem的规则,而不是添加回退
+ mediaQuery: false,
+ // 允许在媒体查询中转换px
+ minPixelValue: 0
+ // 设置要替换的最小像素值
+ })
+ ]
+ }
+ },
+ plugins: createVitePlugins(env, command === "build"),
+ build: buildConfig,
+ optimizeDeps: {
+ esbuildOptions: {
+ target: "esnext"
+ }
+ }
+ });
+};
+export {
+ vite_config_default as default
+};
+//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcubWpzIiwgInZpdGUvcGx1Z2lucy9pbmRleC5qcyIsICJ2aXRlL3BsdWdpbnMvYXV0by1pbXBvcnQuanMiLCAidml0ZS9wbHVnaW5zL2NvbXByZXNzaW9uLmpzIiwgInZpdGUvcGx1Z2lucy9zZXR1cC1leHRlbmQuanMiLCAidml0ZS9wbHVnaW5zL3N2Zy1wbHVnaW4uanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJFOlxcXFxcdTk2NDhcdTc0NzZcXFxcXHU0RTJEXHU1NkZFXHU2NjdBXHU5OERFXFxcXGNvbW1hbmQtY2VudGVyLWRhc2hib2FyZFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRTpcXFxcXHU5NjQ4XHU3NDc2XFxcXFx1NEUyRFx1NTZGRVx1NjY3QVx1OThERVxcXFxjb21tYW5kLWNlbnRlci1kYXNoYm9hcmRcXFxcdml0ZS5jb25maWcubWpzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9FOi8lRTklOTklODglRTclOTElQjYvJUU0JUI4JUFEJUU1JTlCJUJFJUU2JTk5JUJBJUU5JUEzJTlFL2NvbW1hbmQtY2VudGVyLWRhc2hib2FyZC92aXRlLmNvbmZpZy5tanNcIjtpbXBvcnQge1xyXG4gIGRlZmluZUNvbmZpZyxcclxuICBsb2FkRW52XHJcbn0gZnJvbSAndml0ZSc7XHJcbmltcG9ydCB7IHJlc29sdmUgfSBmcm9tICdwYXRoJ1xyXG5pbXBvcnQgY3JlYXRlVml0ZVBsdWdpbnMgZnJvbSAnLi92aXRlL3BsdWdpbnMnO1xyXG5pbXBvcnQgcG9zdENzc1B4VG9SZW0gZnJvbSAncG9zdGNzcy1weHRvcmVtJ1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgKHtcclxuICBtb2RlLFxyXG4gIGNvbW1hbmRcclxufSkgPT4ge1xyXG4gIGNvbnN0IGVudiA9IGxvYWRFbnYobW9kZSwgcHJvY2Vzcy5jd2QoKSlcclxuICBjb25zdCB7XHJcbiAgICBWSVRFX0FQUF9FTlYsXHJcbiAgICBWSVRFX0FQUF9CQVNFLFxyXG4gICAgVklURV9BUFBfQVBJX1VSTFxyXG4gIH0gPSBlbnZcclxuICAvLyBcdTUyMjRcdTY1QURcdTY2MkZcdTYyNTNcdTc1MUZcdTRFQTdcdTczQUZcdTU4ODNcdTUzMDVcclxuICBjb25zdCBpc1Byb2QgPSBWSVRFX0FQUF9FTlYgPT09ICdwcm9kdWN0aW9uJ1xyXG5cclxuICAvLyBcdTY4MzlcdTYzNkVcdTY2MkZcdTU0MjZcdTc1MUZcdTRFQTdcdTczQUZcdTU4ODNcdUZGMENcdTUyQThcdTYwMDFcdThCQkVcdTdGNkVcdTUzOEJcdTdGMjlcdTkxNERcdTdGNkVcclxuICBjb25zdCBidWlsZENvbmZpZyA9IHtcclxuICAgIHRhcmdldDogJ2VzbmV4dCcsXHJcbiAgICBtaW5pZnk6IGlzUHJvZCA/ICd0ZXJzZXInIDogJ2VzYnVpbGQnLCAvLyBcdTY4MzlcdTYzNkVcdTczQUZcdTU4ODNcdTkwMDlcdTYyRTlcdTUzOEJcdTdGMjlcdTVERTVcdTUxNzdcclxuICB9O1xyXG5cclxuICAvLyBcdTU5ODJcdTY3OUNcdTY2MkZcdTc1MUZcdTRFQTdcdTczQUZcdTU4ODNcdUZGMENcdTZERkJcdTUyQTBUZXJzZXJcdTc2ODRcdTkxNERcdTdGNkVcclxuICBpZiAoaXNQcm9kKSB7XHJcbiAgICBidWlsZENvbmZpZy50ZXJzZXJPcHRpb25zID0ge1xyXG4gICAgICBjb21wcmVzczoge1xyXG4gICAgICAgIGRyb3BfY29uc29sZTogdHJ1ZSwgLy8gXHU1MjIwXHU5NjY0IGNvbnNvbGVcclxuICAgICAgICBkcm9wX2RlYnVnZ2VyOiB0cnVlLCAvLyBcdTUyMjBcdTk2NjQgZGVidWdnZXJcclxuICAgICAgfSxcclxuICAgICAgZm9ybWF0OiB7XHJcbiAgICAgICAgY29tbWVudHM6IGZhbHNlIC8vIFx1NTIyMFx1OTY2NFx1NjI0MFx1NjcwOVx1NkNFOFx1OTFDQVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG4gICAgYnVpbGRDb25maWcucm9sbHVwT3B0aW9ucyA9IHtcclxuICAgICAgb3V0cHV0OiB7XHJcbiAgICAgICAgbWFudWFsQ2h1bmtzOiB7XHJcbiAgICAgICAgICAnZWxlbWVudC1wbHVzJzogWydlbGVtZW50LXBsdXMnXSxcclxuICAgICAgICAgICdAc21hbGx3ZWkvYXZ1ZSc6IFsnQHNtYWxsd2VpL2F2dWUnXVxyXG4gICAgICAgIH0sXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbiAgcmV0dXJuIGRlZmluZUNvbmZpZyh7XHJcbiAgICBiYXNlOiBWSVRFX0FQUF9CQVNFLFxyXG4gICAgZGVmaW5lOiB7XHJcbiAgICAgIF9fVlVFX0kxOE5fRlVMTF9JTlNUQUxMX186IHRydWUsXHJcbiAgICAgIF9fVlVFX0kxOE5fTEVHQUNZX0FQSV9fOiB0cnVlLFxyXG4gICAgICBfX0lOVExJRllfUFJPRF9ERVZUT09MU19fOiBmYWxzZVxyXG4gICAgfSxcclxuICAgIHNlcnZlcjoge1xyXG4gICAgICAvLyBwb3J0OiAyODg4LFxyXG4gICAgICBwcm94eToge1xyXG4gICAgICAgICcvYXBpJzoge1xyXG4gICAgICAgICAgdGFyZ2V0OiBWSVRFX0FQUF9BUElfVVJMLFxyXG4gICAgICAgICAgY2hhbmdlT3JpZ2luOiB0cnVlLFxyXG4gICAgICAgICAgcmV3cml0ZTogcGF0aCA9PiBwYXRoLnJlcGxhY2UoL15cXC9hcGkvLCAnJyksXHJcbiAgICAgICAgfSxcclxuICAgICAgfSxcclxuICAgIH0sXHJcbiAgICByZXNvbHZlOiB7XHJcbiAgICAgIGFsaWFzOiB7XHJcbiAgICAgICAgJ34nOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vJyksXHJcbiAgICAgICAgJ0AnOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjJyksXHJcbiAgICAgICAgY29tcG9uZW50czogcmVzb2x2ZShfX2Rpcm5hbWUsICcuL3NyYy9jb21wb25lbnRzJyksXHJcbiAgICAgICAgc3R5bGVzOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjL3N0eWxlcycpLFxyXG4gICAgICAgIHV0aWxzOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjL3V0aWxzJyksXHJcbiAgICAgIH0sXHJcbiAgICB9LFxyXG4gICAgY3NzOiB7XHJcbiAgICAgIHByZXByb2Nlc3Nvck9wdGlvbnM6IHtcclxuICAgICAgICBzY3NzOiB7XHJcbiAgICAgICAgICBhcGk6ICdtb2Rlcm4tY29tcGlsZXInLFxyXG4gICAgICAgICAgYWRkaXRpb25hbERhdGE6IGBAdXNlIFwiQC9zdHlsZXMvdmFyaWFibGVzLnNjc3NcIiBhcyAqO2AsXHJcbiAgICAgICAgfSxcclxuICAgICAgfSxcclxuICAgICAgcG9zdGNzczoge1xyXG4gICAgICAgIHBsdWdpbnM6IFtcclxuICAgICAgICAgIHBvc3RDc3NQeFRvUmVtKHtcclxuICAgICAgICAgICAgcm9vdFZhbHVlOiAxMCwgLy8gXHU2MzA3XHU1QjlBXHU4RjZDXHU2MzYyXHU1N0ZBXHU1MUM2XHU1MDNDXHVGRjBDXHU5MDFBXHU1RTM4XHU2NjJGXHU4QkJFXHU4QkExXHU3QTNGXHU1QkJEXHU1RUE2XHU3Njg0MS8xMFxyXG4gICAgICAgICAgICBwcm9wTGlzdDogWycqJ10sIC8vIFx1NTNFRlx1NEVFNVx1NEVDRXB4XHU4RjZDXHU2MzYyXHU0RTNBcmVtXHU3Njg0XHU1QzVFXHU2MDI3XHVGRjBDXHU4RkQ5XHU5MUNDXHU2NjJGXHU2MjQwXHU2NzA5XHU1QzVFXHU2MDI3XHJcbiAgICAgICAgICAgIHVuaXRQcmVjaXNpb246IDUsIC8vIFx1NTE0MVx1OEJCOFJFTVx1NTM1NVx1NEY0RFx1NTg5RVx1OTU3Rlx1NTIzMFx1NzY4NFx1NTM0MVx1OEZEQlx1NTIzNlx1NjU3MFxyXG4gICAgICAgICAgICBzZWxlY3RvckJsYWNrTGlzdDogW10sIC8vIFx1OTAwOVx1NjJFOVx1NTY2OFx1OUVEMVx1NTQwRFx1NTM1NVx1RkYwQ1x1NUZGRFx1NzU2NVx1OEY2Q1x1NjM2Mlx1NzY4NFx1OTAwOVx1NjJFOVx1NTY2OFxyXG4gICAgICAgICAgICByZXBsYWNlOiB0cnVlLCAvLyBcdTY2RkZcdTYzNjJcdTUzMDVcdTU0MkJyZW1cdTc2ODRcdTg5QzRcdTUyMTlcdUZGMENcdTgwMENcdTRFMERcdTY2MkZcdTZERkJcdTUyQTBcdTU2REVcdTkwMDBcclxuICAgICAgICAgICAgbWVkaWFRdWVyeTogZmFsc2UsIC8vIFx1NTE0MVx1OEJCOFx1NTcyOFx1NUE5Mlx1NEY1M1x1NjdFNVx1OEJFMlx1NEUyRFx1OEY2Q1x1NjM2MnB4XHJcbiAgICAgICAgICAgIG1pblBpeGVsVmFsdWU6IDAgLy8gXHU4QkJFXHU3RjZFXHU4OTgxXHU2NkZGXHU2MzYyXHU3Njg0XHU2NzAwXHU1QzBGXHU1MENGXHU3RDIwXHU1MDNDXHJcbiAgICAgICAgICB9KSxcclxuICAgICAgICBdXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwbHVnaW5zOiBjcmVhdGVWaXRlUGx1Z2lucyhlbnYsIGNvbW1hbmQgPT09ICdidWlsZCcpLFxyXG4gICAgYnVpbGQ6IGJ1aWxkQ29uZmlnLFxyXG4gICAgb3B0aW1pemVEZXBzOiB7XHJcbiAgICAgIGVzYnVpbGRPcHRpb25zOiB7XHJcbiAgICAgICAgdGFyZ2V0OiAnZXNuZXh0JyxcclxuICAgICAgfSxcclxuICAgIH0sXHJcbiAgfSk7XHJcbn07XHJcbiIsICJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiRTpcXFxcXHU5NjQ4XHU3NDc2XFxcXFx1NEUyRFx1NTZGRVx1NjY3QVx1OThERVxcXFxjb21tYW5kLWNlbnRlci1kYXNoYm9hcmRcXFxcdml0ZVxcXFxwbHVnaW5zXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCJFOlxcXFxcdTk2NDhcdTc0NzZcXFxcXHU0RTJEXHU1NkZFXHU2NjdBXHU5OERFXFxcXGNvbW1hbmQtY2VudGVyLWRhc2hib2FyZFxcXFx2aXRlXFxcXHBsdWdpbnNcXFxcaW5kZXguanNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0U6LyVFOSU5OSU4OCVFNyU5MSVCNi8lRTQlQjglQUQlRTUlOUIlQkUlRTYlOTklQkElRTklQTMlOUUvY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkL3ZpdGUvcGx1Z2lucy9pbmRleC5qc1wiO2ltcG9ydCB2dWUgZnJvbSAnQHZpdGVqcy9wbHVnaW4tdnVlJztcclxuXHJcbmltcG9ydCBjcmVhdGVBdXRvSW1wb3J0IGZyb20gJy4vYXV0by1pbXBvcnQnO1xyXG5pbXBvcnQgY3JlYXRlQ29tcHJlc3Npb24gZnJvbSAnLi9jb21wcmVzc2lvbic7XHJcbmltcG9ydCBjcmVhdGVTZXR1cEV4dGVuZCBmcm9tICcuL3NldHVwLWV4dGVuZCc7XHJcbmltcG9ydCBjcmVhdGVTdmdQbHVnaW4gZnJvbSAnLi9zdmctcGx1Z2luJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGNyZWF0ZVZpdGVQbHVnaW5zKHZpdGVFbnYsIGlzQnVpbGQgPSBmYWxzZSkge1xyXG4gIGNvbnN0IHZpdGVQbHVnaW5zID0gW3Z1ZSgpXTtcclxuICB2aXRlUGx1Z2lucy5wdXNoKGNyZWF0ZUF1dG9JbXBvcnQoKSk7XHJcbiAgdml0ZVBsdWdpbnMucHVzaChjcmVhdGVTZXR1cEV4dGVuZCgpKTtcclxuICB2aXRlUGx1Z2lucy5wdXNoKGNyZWF0ZVN2Z1BsdWdpbigpKTtcclxuICBpc0J1aWxkICYmIHZpdGVQbHVnaW5zLnB1c2goLi4uY3JlYXRlQ29tcHJlc3Npb24odml0ZUVudikpO1xyXG4gIHJldHVybiB2aXRlUGx1Z2lucztcclxufVxyXG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIkU6XFxcXFx1OTY0OFx1NzQ3NlxcXFxcdTRFMkRcdTU2RkVcdTY2N0FcdTk4REVcXFxcY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkXFxcXHZpdGVcXFxccGx1Z2luc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRTpcXFxcXHU5NjQ4XHU3NDc2XFxcXFx1NEUyRFx1NTZGRVx1NjY3QVx1OThERVxcXFxjb21tYW5kLWNlbnRlci1kYXNoYm9hcmRcXFxcdml0ZVxcXFxwbHVnaW5zXFxcXGF1dG8taW1wb3J0LmpzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9FOi8lRTklOTklODglRTclOTElQjYvJUU0JUI4JUFEJUU1JTlCJUJFJUU2JTk5JUJBJUU5JUEzJTlFL2NvbW1hbmQtY2VudGVyLWRhc2hib2FyZC92aXRlL3BsdWdpbnMvYXV0by1pbXBvcnQuanNcIjtpbXBvcnQgYXV0b0ltcG9ydCBmcm9tICd1bnBsdWdpbi1hdXRvLWltcG9ydC92aXRlJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGNyZWF0ZUF1dG9JbXBvcnQoKSB7XHJcbiAgcmV0dXJuIGF1dG9JbXBvcnQoe1xyXG4gICAgaW1wb3J0czogWyd2dWUnLCAndnVlLXJvdXRlcicsICd2dWV4J10sXHJcbiAgICBkdHM6IGZhbHNlLFxyXG4gIH0pO1xyXG59XHJcbiIsICJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiRTpcXFxcXHU5NjQ4XHU3NDc2XFxcXFx1NEUyRFx1NTZGRVx1NjY3QVx1OThERVxcXFxjb21tYW5kLWNlbnRlci1kYXNoYm9hcmRcXFxcdml0ZVxcXFxwbHVnaW5zXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCJFOlxcXFxcdTk2NDhcdTc0NzZcXFxcXHU0RTJEXHU1NkZFXHU2NjdBXHU5OERFXFxcXGNvbW1hbmQtY2VudGVyLWRhc2hib2FyZFxcXFx2aXRlXFxcXHBsdWdpbnNcXFxcY29tcHJlc3Npb24uanNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0U6LyVFOSU5OSU4OCVFNyU5MSVCNi8lRTQlQjglQUQlRTUlOUIlQkUlRTYlOTklQkElRTklQTMlOUUvY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkL3ZpdGUvcGx1Z2lucy9jb21wcmVzc2lvbi5qc1wiO2ltcG9ydCBjb21wcmVzc2lvbiBmcm9tICd2aXRlLXBsdWdpbi1jb21wcmVzc2lvbic7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBjcmVhdGVDb21wcmVzc2lvbihlbnYpIHtcclxuICBjb25zdCB7IFZJVEVfQlVJTERfQ09NUFJFU1MgfSA9IGVudjtcclxuICBjb25zdCBwbHVnaW4gPSBbXTtcclxuICBpZiAoVklURV9CVUlMRF9DT01QUkVTUykge1xyXG4gICAgY29uc3QgY29tcHJlc3NMaXN0ID0gVklURV9CVUlMRF9DT01QUkVTUy5zcGxpdCgnLCcpO1xyXG4gICAgaWYgKGNvbXByZXNzTGlzdC5pbmNsdWRlcygnZ3ppcCcpKSB7XHJcbiAgICAgIHBsdWdpbi5wdXNoKFxyXG4gICAgICAgIGNvbXByZXNzaW9uKHtcclxuICAgICAgICAgIGV4dDogJy5neicsXHJcbiAgICAgICAgICBkZWxldGVPcmlnaW5GaWxlOiBmYWxzZSxcclxuICAgICAgICB9KVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgaWYgKGNvbXByZXNzTGlzdC5pbmNsdWRlcygnYnJvdGxpJykpIHtcclxuICAgICAgcGx1Z2luLnB1c2goXHJcbiAgICAgICAgY29tcHJlc3Npb24oe1xyXG4gICAgICAgICAgZXh0OiAnLmJyJyxcclxuICAgICAgICAgIGFsZ29yaXRobTogJ2Jyb3RsaUNvbXByZXNzJyxcclxuICAgICAgICAgIGRlbGV0ZU9yaWdpbkZpbGU6IGZhbHNlLFxyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiBwbHVnaW47XHJcbn1cclxuIiwgImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJFOlxcXFxcdTk2NDhcdTc0NzZcXFxcXHU0RTJEXHU1NkZFXHU2NjdBXHU5OERFXFxcXGNvbW1hbmQtY2VudGVyLWRhc2hib2FyZFxcXFx2aXRlXFxcXHBsdWdpbnNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkU6XFxcXFx1OTY0OFx1NzQ3NlxcXFxcdTRFMkRcdTU2RkVcdTY2N0FcdTk4REVcXFxcY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkXFxcXHZpdGVcXFxccGx1Z2luc1xcXFxzZXR1cC1leHRlbmQuanNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0U6LyVFOSU5OSU4OCVFNyU5MSVCNi8lRTQlQjglQUQlRTUlOUIlQkUlRTYlOTklQkElRTklQTMlOUUvY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkL3ZpdGUvcGx1Z2lucy9zZXR1cC1leHRlbmQuanNcIjtpbXBvcnQgc2V0dXBFeHRlbmQgZnJvbSAndml0ZS1wbHVnaW4tdnVlLXNldHVwLWV4dGVuZCc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBjcmVhdGVTZXR1cEV4dGVuZCgpIHtcclxuICByZXR1cm4gc2V0dXBFeHRlbmQoKTtcclxufVxyXG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIkU6XFxcXFx1OTY0OFx1NzQ3NlxcXFxcdTRFMkRcdTU2RkVcdTY2N0FcdTk4REVcXFxcY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkXFxcXHZpdGVcXFxccGx1Z2luc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRTpcXFxcXHU5NjQ4XHU3NDc2XFxcXFx1NEUyRFx1NTZGRVx1NjY3QVx1OThERVxcXFxjb21tYW5kLWNlbnRlci1kYXNoYm9hcmRcXFxcdml0ZVxcXFxwbHVnaW5zXFxcXHN2Zy1wbHVnaW4uanNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0U6LyVFOSU5OSU4OCVFNyU5MSVCNi8lRTQlQjglQUQlRTUlOUIlQkUlRTYlOTklQkElRTklQTMlOUUvY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkL3ZpdGUvcGx1Z2lucy9zdmctcGx1Z2luLmpzXCI7aW1wb3J0IHsgY3JlYXRlU3ZnSWNvbnNQbHVnaW4gfSBmcm9tICd2aXRlLXBsdWdpbi1zdmctaWNvbnMnXHJcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gY3JlYXRlU3ZnUGx1Z2luKCkge1xyXG4gIHJldHVybiAgY3JlYXRlU3ZnSWNvbnNQbHVnaW4oe1xyXG4gICAgaWNvbkRpcnM6IFtwYXRoLnJlc29sdmUocHJvY2Vzcy5jd2QoKSwgXCJzcmMvYXNzZXRzL3N2Z1wiKV0sIC8vc3ZnXHU1NkZFXHU3MjQ3XHU1QjU4XHU2NTNFXHU3Njg0XHU3NkVFXHU1RjU1XHJcbiAgICBzeW1ib2xJZDogXCJpY29uLVtuYW1lXVwiLCAvLyBzeW1ib2xcdTc2ODRpZFxyXG4gICAgaW5qZWN0OiBcImJvZHktbGFzdFwiLCAvLyBcdTYzRDJcdTUxNjVcdTc2ODRcdTRGNERcdTdGNkVcclxuICAgIGN1c3RvbURvbUlkOiBcIl9fc3ZnX19pY29uc19fZG9tX19cIiAvLyBzdmdcdTc2ODRpZFxyXG4gIH0pO1xyXG59XHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBcVY7QUFBQSxFQUNuVjtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsU0FBUyxlQUFlOzs7QUNKMFYsT0FBTyxTQUFTOzs7QUNBSixPQUFPLGdCQUFnQjtBQUV0WSxTQUFSLG1CQUFvQztBQUN6QyxTQUFPLFdBQVc7QUFBQSxJQUNoQixTQUFTLENBQUMsT0FBTyxjQUFjLE1BQU07QUFBQSxJQUNyQyxLQUFLO0FBQUEsRUFDUCxDQUFDO0FBQ0g7OztBQ1A4WCxPQUFPLGlCQUFpQjtBQUV2WSxTQUFSLGtCQUFtQyxLQUFLO0FBQzdDLFFBQU0sRUFBRSxvQkFBb0IsSUFBSTtBQUNoQyxRQUFNLFNBQVMsQ0FBQztBQUNoQixNQUFJLHFCQUFxQjtBQUN2QixVQUFNLGVBQWUsb0JBQW9CLE1BQU0sR0FBRztBQUNsRCxRQUFJLGFBQWEsU0FBUyxNQUFNLEdBQUc7QUFDakMsYUFBTztBQUFBLFFBQ0wsWUFBWTtBQUFBLFVBQ1YsS0FBSztBQUFBLFVBQ0wsa0JBQWtCO0FBQUEsUUFDcEIsQ0FBQztBQUFBLE1BQ0g7QUFBQSxJQUNGO0FBQ0EsUUFBSSxhQUFhLFNBQVMsUUFBUSxHQUFHO0FBQ25DLGFBQU87QUFBQSxRQUNMLFlBQVk7QUFBQSxVQUNWLEtBQUs7QUFBQSxVQUNMLFdBQVc7QUFBQSxVQUNYLGtCQUFrQjtBQUFBLFFBQ3BCLENBQUM7QUFBQSxNQUNIO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFDQSxTQUFPO0FBQ1Q7OztBQzFCZ1ksT0FBTyxpQkFBaUI7QUFFelksU0FBUixvQkFBcUM7QUFDMUMsU0FBTyxZQUFZO0FBQ3JCOzs7QUNKNFgsU0FBUyw0QkFBNEI7QUFDamEsT0FBTyxVQUFVO0FBRUYsU0FBUixrQkFBbUM7QUFDeEMsU0FBUSxxQkFBcUI7QUFBQSxJQUMzQixVQUFVLENBQUMsS0FBSyxRQUFRLFFBQVEsSUFBSSxHQUFHLGdCQUFnQixDQUFDO0FBQUE7QUFBQSxJQUN4RCxVQUFVO0FBQUE7QUFBQSxJQUNWLFFBQVE7QUFBQTtBQUFBLElBQ1IsYUFBYTtBQUFBO0FBQUEsRUFDZixDQUFDO0FBQ0g7OztBSkhlLFNBQVIsa0JBQW1DLFNBQVMsVUFBVSxPQUFPO0FBQ2xFLFFBQU0sY0FBYyxDQUFDLElBQUksQ0FBQztBQUMxQixjQUFZLEtBQUssaUJBQWlCLENBQUM7QUFDbkMsY0FBWSxLQUFLLGtCQUFrQixDQUFDO0FBQ3BDLGNBQVksS0FBSyxnQkFBZ0IsQ0FBQztBQUNsQyxhQUFXLFlBQVksS0FBSyxHQUFHLGtCQUFrQixPQUFPLENBQUM7QUFDekQsU0FBTztBQUNUOzs7QURSQSxPQUFPLG9CQUFvQjtBQU4zQixJQUFNLG1DQUFtQztBQVN6QyxJQUFPLHNCQUFRLENBQUM7QUFBQSxFQUNkO0FBQUEsRUFDQTtBQUNGLE1BQU07QUFDSixRQUFNLE1BQU0sUUFBUSxNQUFNLFFBQVEsSUFBSSxDQUFDO0FBQ3ZDLFFBQU07QUFBQSxJQUNKO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxFQUNGLElBQUk7QUFFSixRQUFNLFNBQVMsaUJBQWlCO0FBR2hDLFFBQU0sY0FBYztBQUFBLElBQ2xCLFFBQVE7QUFBQSxJQUNSLFFBQVEsU0FBUyxXQUFXO0FBQUE7QUFBQSxFQUM5QjtBQUdBLE1BQUksUUFBUTtBQUNWLGdCQUFZLGdCQUFnQjtBQUFBLE1BQzFCLFVBQVU7QUFBQSxRQUNSLGNBQWM7QUFBQTtBQUFBLFFBQ2QsZUFBZTtBQUFBO0FBQUEsTUFDakI7QUFBQSxNQUNBLFFBQVE7QUFBQSxRQUNOLFVBQVU7QUFBQTtBQUFBLE1BQ1o7QUFBQSxJQUNGO0FBQ0EsZ0JBQVksZ0JBQWdCO0FBQUEsTUFDMUIsUUFBUTtBQUFBLFFBQ04sY0FBYztBQUFBLFVBQ1osZ0JBQWdCLENBQUMsY0FBYztBQUFBLFVBQy9CLGtCQUFrQixDQUFDLGdCQUFnQjtBQUFBLFFBQ3JDO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBQ0EsU0FBTyxhQUFhO0FBQUEsSUFDbEIsTUFBTTtBQUFBLElBQ04sUUFBUTtBQUFBLE1BQ04sMkJBQTJCO0FBQUEsTUFDM0IseUJBQXlCO0FBQUEsTUFDekIsMkJBQTJCO0FBQUEsSUFDN0I7QUFBQSxJQUNBLFFBQVE7QUFBQTtBQUFBLE1BRU4sT0FBTztBQUFBLFFBQ0wsUUFBUTtBQUFBLFVBQ04sUUFBUTtBQUFBLFVBQ1IsY0FBYztBQUFBLFVBQ2QsU0FBUyxDQUFBQSxVQUFRQSxNQUFLLFFBQVEsVUFBVSxFQUFFO0FBQUEsUUFDNUM7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUFBLElBQ0EsU0FBUztBQUFBLE1BQ1AsT0FBTztBQUFBLFFBQ0wsS0FBSyxRQUFRLGtDQUFXLElBQUk7QUFBQSxRQUM1QixLQUFLLFFBQVEsa0NBQVcsT0FBTztBQUFBLFFBQy9CLFlBQVksUUFBUSxrQ0FBVyxrQkFBa0I7QUFBQSxRQUNqRCxRQUFRLFFBQVEsa0NBQVcsY0FBYztBQUFBLFFBQ3pDLE9BQU8sUUFBUSxrQ0FBVyxhQUFhO0FBQUEsTUFDekM7QUFBQSxJQUNGO0FBQUEsSUFDQSxLQUFLO0FBQUEsTUFDSCxxQkFBcUI7QUFBQSxRQUNuQixNQUFNO0FBQUEsVUFDSixLQUFLO0FBQUEsVUFDTCxnQkFBZ0I7QUFBQSxRQUNsQjtBQUFBLE1BQ0Y7QUFBQSxNQUNBLFNBQVM7QUFBQSxRQUNQLFNBQVM7QUFBQSxVQUNQLGVBQWU7QUFBQSxZQUNiLFdBQVc7QUFBQTtBQUFBLFlBQ1gsVUFBVSxDQUFDLEdBQUc7QUFBQTtBQUFBLFlBQ2QsZUFBZTtBQUFBO0FBQUEsWUFDZixtQkFBbUIsQ0FBQztBQUFBO0FBQUEsWUFDcEIsU0FBUztBQUFBO0FBQUEsWUFDVCxZQUFZO0FBQUE7QUFBQSxZQUNaLGVBQWU7QUFBQTtBQUFBLFVBQ2pCLENBQUM7QUFBQSxRQUNIO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxJQUNBLFNBQVMsa0JBQWtCLEtBQUssWUFBWSxPQUFPO0FBQUEsSUFDbkQsT0FBTztBQUFBLElBQ1AsY0FBYztBQUFBLE1BQ1osZ0JBQWdCO0FBQUEsUUFDZCxRQUFRO0FBQUEsTUFDVjtBQUFBLElBQ0Y7QUFBQSxFQUNGLENBQUM7QUFDSDsiLAogICJuYW1lcyI6IFsicGF0aCJdCn0K
--
Gitblit v1.9.3