From 75cdd3cdcec1fc22bddebd6352e5e87e0a8d5d33 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Fri, 18 Apr 2025 10:57:41 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'
---
src/assets/images/home/useUavHome/eventAggregationImg1.png | 0
src/layout/Header.vue | 8
src/page/login/index.vue | 4
src/utils/stateToImageMap/event.js | 23
src/hooks/components/useMapHandlerClick.js | 89 ++
src/hooks/components/EventPopUpBox.vue | 16
src/views/SignMachineNest/MachineRight/MachineMonitor.vue | 135 ++--
src/styles/login.scss | 19
.env.test | 3
src/views/SignMachineNest/SignMachineNest.vue | 1
src/hooks/useMapAggregation/useMapAggregation.js | 139 +----
src/views/Home/AINowFly.vue | 2
src/views/Home/SearchBox.vue | 442 ++++++++--------
src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue | 404 +++++++-------
src/hooks/useSingleDroneMap/useSingleDroneMap.js | 135 ----
.env.development | 2
src/assets/images/home/useUavHome/eventAggregationImg.png | 0
src/utils/stateToImageMap/drone.js | 32 +
.env.production | 2
src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue | 46 +
20 files changed, 750 insertions(+), 752 deletions(-)
diff --git a/.env.development b/.env.development
index 4792921..c1b7c39 100644
--- a/.env.development
+++ b/.env.development
@@ -12,4 +12,4 @@
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
+VITE_APP_ADMIN_URL = 'https://wrj.shuixiongit.com/manage'
diff --git a/.env.production b/.env.production
index d4914e6..4e96c25 100644
--- a/.env.production
+++ b/.env.production
@@ -6,4 +6,4 @@
# ws地址
VITE_APP_WS_API_URL = wss://wrj.shuixiongit.com/drone-wss/api/v1/ws
# 管理后台地址
-VITE_APP_ADMIN_URL = ' https://aisky.org.cn/manage'
+VITE_APP_ADMIN_URL = 'https://aisky.org.cn/manage'
diff --git a/.env.test b/.env.test
index 3ed2c36..1518c99 100644
--- a/.env.test
+++ b/.env.test
@@ -5,3 +5,6 @@
VITE_APP_WS_API_URL = wss://wrj.shuixiongit.com/drone-wss/api/v1/ws
# 航线文件地址
VITE_APP_AIRLINE_URL = https://wrj.shuixiongit.com/minio/cloud-bucket
+
+#系统运维
+VITE_APP_ADMIN_URL = 'https://wrj.shuixiongit.com/manage'
diff --git a/src/assets/images/home/useUavHome/eventAggregationImg.png b/src/assets/images/home/useUavHome/eventAggregationImg.png
index da95764..da133c4 100644
--- a/src/assets/images/home/useUavHome/eventAggregationImg.png
+++ b/src/assets/images/home/useUavHome/eventAggregationImg.png
Binary files differ
diff --git a/src/assets/images/home/useUavHome/eventAggregationImg1.png b/src/assets/images/home/useUavHome/eventAggregationImg1.png
new file mode 100644
index 0000000..da95764
--- /dev/null
+++ b/src/assets/images/home/useUavHome/eventAggregationImg1.png
Binary files differ
diff --git a/src/hooks/components/EventPopUpBox.vue b/src/hooks/components/EventPopUpBox.vue
index 5a50e29..ddee5be 100644
--- a/src/hooks/components/EventPopUpBox.vue
+++ b/src/hooks/components/EventPopUpBox.vue
@@ -31,7 +31,7 @@
</div>
</template>
<script setup>
-import { ElImage } from 'element-plus'
+import { ElImage, ElIcon } from 'element-plus'
// src="@/assets/images/home/useEventOperate/eventErr.png"
import { Close } from '@element-plus/icons-vue'
@@ -54,10 +54,20 @@
loading.value = true
const res = await getEventDetails({ id: props.data.eventId })
info.value = res.data.data
-
- info.value.url = import.meta.env.VITE_APP_AIRLINE_URL + info.value.url
+ info.value.url = disposeUrl(info.value)
loading.value = false
})
+
+const disposeUrl = ({ url, media_type }) => {
+ if (media_type == 'PHOTO_TYPE') {
+ const parts = url.split('.')
+ parts[parts.length - 2] += '_small' // 在最后一个点前插入 _small
+
+ return import.meta.env.VITE_APP_AIRLINE_URL + parts.join('.')
+ }
+
+ return import.meta.env.VITE_APP_AIRLINE_URL + url
+}
</script>
<style scoped lang="scss">
diff --git a/src/hooks/components/useMapHandlerClick.js b/src/hooks/components/useMapHandlerClick.js
index a4854ce..82d59c5 100644
--- a/src/hooks/components/useMapHandlerClick.js
+++ b/src/hooks/components/useMapHandlerClick.js
@@ -2,33 +2,72 @@
* @Author: shuishen 1109946754@qq.com
* @Date: 2025-04-15 22:41:40
* @LastEditors: shuishen 1109946754@qq.com
- * @LastEditTime: 2025-04-16 19:02:39
+ * @LastEditTime: 2025-04-17 19:43:36
* @FilePath: \command-center-dashboard\src\hooks\components\useMapHandlerClick.js
* @Description:
*
* Copyright (c) 2025 by shuishen, All Rights Reserved.
*/
import * as Cesium from 'cesium'
+import { render } from 'vue'
+import { useStore } from 'vuex'
+
+import DevicePopUpBox from '@/hooks/components/DevicePopUpBox.vue'
import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue'
/**
*
* @param {Object} options - 配置选项
*/
-export function useMapHandlerClick (viewer, options = {
- type: 'single-drone-event',
- customDom: EventPopUpBox
-}) {
- const { type } = options
+export function useMapHandlerClick (options = {}) {
+ const {
+ popupType = 'event-popup',
+ eventType = 'single-drone-event',
+ styleTransform = 'translate(-50%,-110%)',
+ getViewer
+ } = options
- const currentClickEntity = ref(null)
+ const store = useStore()
+
+ const popupData = {
+ 'event-popup': EventPopUpBox,
+ 'device-popup': DevicePopUpBox
+ }
+
+ const MapPopUpBox = popupData[popupType]
+
+ let viewer = null
let handler = null
+ let currentClickEntity = null
// 查找特定类型的实体
const findEntityByType = (entities, type) => {
- return entities.find(entity =>
- entity?.properties?.customData?._value?.data?.type === type
- )
+ let types = []
+
+ Array.isArray(type) ? types = type : types = [type]
+
+ return types.reduce((pre, curType) => {
+ let entity = entities.find(entity => entity?.properties?.customData?._value?.data?.type === curType)
+
+ return entity ? (pre.push({
+ type: curType,
+ entity
+ }), pre) : pre
+ }, [])
+ }
+
+ const publicEvent = (entity) => {
+ viewer.scene.postRender.addEventListener(labelBoxRender)
+ }
+
+ const typeEvent = {
+ 'deviceAggregation': publicEvent,
+ 'single-drone-event': publicEvent,
+ 'event': publicEvent,
+ 'device': (entity) => {
+ const device = entity.properties.customData._value.data
+ store.commit('setSingleUavHome', device)
+ }
}
// 左键单机事件
@@ -36,17 +75,21 @@
let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id)
if (!clickedEntities.length) return
- currentClickEntity.value = findEntityByType(clickedEntities, type)
+ let curClick = findEntityByType(clickedEntities, eventType)
removeLabel()
- if (currentClickEntity.value) {
- viewer?.scene.postRender.addEventListener(labelBoxRender)
+ if (curClick.length > 0 && typeEvent[curClick[0].type]) {
+ currentClickEntity = curClick[0].entity
+
+ typeEvent[curClick[0].type](currentClickEntity)
}
}
// 事件初始化
const handlerInit = () => {
+ !viewer && (viewer = getViewer())
+
if (handler) return
handler = new Cesium.ScreenSpaceEventHandler(viewer?.scene.canvas)
@@ -62,7 +105,7 @@
// 获取弹框box
const getLabelDom = data => {
- const vNode = h(customDom, { data, removeLabel })
+ const vNode = h(MapPopUpBox, { data, removeLabel })
const tooltipContainer = document.createElement('div')
tooltipContainer.id = 'mapPopUpBox'
tooltipContainer.style.position = 'absolute'
@@ -75,12 +118,12 @@
// 弹框位置刷新
const labelBoxRender = () => {
- if (!currentEntity) return
+ if (!currentClickEntity) return
let dom = document.querySelector('#mapPopUpBox')
if (!dom) {
- dom = getLabelDom(currentEntity.properties.customData._value.data)
+ dom = getLabelDom(currentClickEntity.properties.customData._value.data)
}
- const screenPosition = viewer?.scene.cartesianToCanvasCoordinates(currentEntity?.position?._value)
+ const screenPosition = viewer?.scene.cartesianToCanvasCoordinates(currentClickEntity?.position?._value)
if (screenPosition) {
dom.style.left = `${screenPosition.x}px`
dom.style.top = `${screenPosition.y}px`
@@ -101,15 +144,19 @@
removeDom()
}
- // 自动清理
- onUnmounted(() => {
+ const removeAll = () => {
removeHandler()
removeLabel()
+ }
+
+ // 自动清理
+ onUnmounted(() => {
+ removeAll()
})
return {
- currentClickEntity,
handlerInit,
- removeHandler
+ removeAll,
+ removeLabel
}
}
\ No newline at end of file
diff --git a/src/hooks/useMapAggregation/useMapAggregation.js b/src/hooks/useMapAggregation/useMapAggregation.js
index 5557967..d46d74a 100644
--- a/src/hooks/useMapAggregation/useMapAggregation.js
+++ b/src/hooks/useMapAggregation/useMapAggregation.js
@@ -3,30 +3,19 @@
import eventAggregationImg from '@/assets/images/home/useUavHome/eventAggregationImg.png'
import uavImg from '@/assets/images/home/useUavHome/uavImg.png'
-// 事件图标
-import eventSingle from '@/assets/images/home/useEventOperate/eventSingle.png'
+import { getEventImage } from '@/utils/stateToImageMap/event'
+import { getDroneStatusImage } from '@/utils/stateToImageMap/drone'
-import eventPending from '@/assets/images/home/useEventOperate/eventPending.png' // 待处理 0
-import eventWaitAudit from '@/assets/images/home/useEventOperate/eventWaitAudit.png' // 待审核 2
-import eventProcessing from '@/assets/images/home/useEventOperate/eventProcessing.png' // 处理中 3
-import eventCompleted from '@/assets/images/home/useEventOperate/eventCompleted.png' // 已完成 4
-import eventClosed from '@/assets/images/home/useEventOperate/eventClosed.png' // 已完结 5
-
-import DevicePopUpBox from '@/hooks/components/DevicePopUpBox.vue'
-import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue'
-
-
-// 机巢图标
-import endingImg from '@/assets/images/aiNowFly/ending.png'
-import endingHighImg from '@/assets/images/aiNowFly/ending-high.png'
-
-import { render } from 'vue'
import { useStore } from 'vuex'
import { getCenterPoint } from '@/utils/cesium/mapUtil'
import cesiumOperation from '@/utils/cesium-tsa'
import { getDeviceRegion, getDeviceRegionCount, getEventDetails, getMapEvents } from '@/api/home/aggregation'
import { PolyGradientMaterial } from '@/utils/cesium/Material'
import { start } from 'nprogress'
+
+// hook
+import { useMapHandlerClick } from '@/hooks/components/useMapHandlerClick'
+
/**
* 机巢聚合功能
*/
@@ -51,8 +40,21 @@
const { flyTo } = cesiumOperation()
const mergeImg = type === 'device' ? aggregationImg : eventAggregationImg
- const MapPopUpBox = type === 'device' ? DevicePopUpBox : EventPopUpBox
const styleTransform = type === 'device' ? 'translateY(-50%)' : 'translate(-50%,-110%)'
+ const eventType = type === 'device' ? ['deviceAggregation', 'device'] : 'event'
+
+ const {
+ handlerInit: mapHandlerInit,
+ removeAll: removeMapHandlerAll,
+ removeLabel: removeMapLabel
+ } = useMapHandlerClick({
+ popupType: `${type}-popup`,
+ eventType: eventType,
+ styleTransform,
+ getViewer () {
+ return viewer
+ }
+ })
let scalingJudgment = [
{ name: '县', splashedList: [], gJson: null, show: false, outline: {}, value: [0, 48651], height: 31753 },
@@ -69,8 +71,6 @@
]
let viewer = null
let active = null
- let handler = null
- let currentEntity = null
const store = useStore()
const userAreaCode = computed(() => store.state.user.userInfo.detail.areaCode)
@@ -104,7 +104,7 @@
if (active === item.name) return
active = item.name
removeEntities()
- removeLabel()
+ removeMapLabel()
renderOutline(item)
if (!item.gJson && !item.splashedList?.length) return
item.gJson ? aggregation(item) : splashed(item)
@@ -288,7 +288,7 @@
needFly = true
if (!viewer) return
- handlerInit()
+ mapHandlerInit()
viewer.scene.postRender.removeEventListener(determineScaling)
@@ -302,15 +302,7 @@
//散点机巢
function splashed (row) {
row.splashedList.forEach((item, index) => {
- const eventImage = {
- 0: eventPending,
- 2: eventWaitAudit,
- 3: eventProcessing,
- 4: eventCompleted,
- 5: eventClosed
- }
-
- const image = type === 'device' ? (item.status === "OFFLINE" ? endingHighImg : endingImg) : eventImage[item.status] || eventSingle
+ const image = type === 'device' ? getDroneStatusImage(item.status) : getEventImage(item.status)
viewer.entities.add({
id: `aggregation-splashed-${index}`,
@@ -470,33 +462,6 @@
})
}
- // 获取弹框box
- const getLabelDom = data => {
- const vNode = h(MapPopUpBox, { 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'
- }
- }
/**
* 根据条件获取项
@@ -506,41 +471,6 @@
*/
const findTypeItem = (arr, condition) => {
return arr.find(item => condition(item))
- }
-
- // 左键单机事件
- const singleMachineEvent = async click => {
- let clickTargets = viewer.scene.drillPick(click.position).map(item => item.id)
- if (!clickTargets.length) return
-
- let deviceAggregationFind = findTypeItem(
- clickTargets,
- item => item?.properties?.customData?._value?.data?.type === 'deviceAggregation'
- )
- let deviceFind = findTypeItem(clickTargets, item => item?.properties?.customData?._value?.data?.type === 'device')
- // "event"
- let eventFind = findTypeItem(clickTargets, item => item?.properties?.customData?._value?.data?.type === 'event')
- // let eventFind = findTypeItem(clickTargets, (item) => item?.properties?.customData?._value?.data?.type === 'eventAggregation')
- currentEntity = deviceAggregationFind || deviceFind || eventFind
-
- if (!currentEntity) return
- if (!currentEntity?.position?._value) return
- // 一定要移除
- removeLabel()
- if (deviceAggregationFind || eventFind) {
- viewer.scene.postRender.addEventListener(labelBoxRender)
- }
- if (deviceFind) {
- const device = deviceFind.properties.customData._value.data
- store.commit('setSingleUavHome', device)
- }
- }
-
- const removeDom = () => {
- const dom = document.querySelector('#mapPopUpBox')
- if (dom && dom.parentNode) {
- dom.parentNode.removeChild(dom)
- }
}
// 移除 点 和 gjson 实体
@@ -556,11 +486,7 @@
item.includes('aggregation-') && viewer.entities.removeById(item)
})
}
- // 移除弹框标签
- const removeLabel = () => {
- viewer?.scene.postRender.removeEventListener(labelBoxRender)
- removeDom()
- }
+
// 移除所有监听事件,变量置空
const removeAll = () => {
@@ -571,14 +497,12 @@
const clearMapEntity = () => {
if (!viewer) return
removeEntities()
- removeLabel()
+ removeMapHandlerAll()
+
// viewer.camera.moveEnd.removeEventListener(determineScaling);
viewer.scene.postRender.removeEventListener(determineScaling)
- handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
- handler?.destroy()
+
active = null
- handler = null
- currentEntity = null
}
const init = () => {
@@ -588,14 +512,7 @@
viewer.scene.postRender.addEventListener(determineScaling)
})
- handlerInit()
- }
-
- const handlerInit = () => {
- if (handler) return
-
- handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
- handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK)
+ mapHandlerInit()
}
onBeforeUnmount(() => { })
diff --git a/src/hooks/useSingleDroneMap/useSingleDroneMap.js b/src/hooks/useSingleDroneMap/useSingleDroneMap.js
index ff7f0c3..b8b7aa7 100644
--- a/src/hooks/useSingleDroneMap/useSingleDroneMap.js
+++ b/src/hooks/useSingleDroneMap/useSingleDroneMap.js
@@ -2,25 +2,18 @@
* @Author: shuishen 1109946754@qq.com
* @Date: 2025-04-15 22:41:40
* @LastEditors: shuishen 1109946754@qq.com
- * @LastEditTime: 2025-04-17 15:05:32
+ * @LastEditTime: 2025-04-17 20:24:19
* @FilePath: \command-center-dashboard\src\hooks\useSingleDroneMap\useSingleDroneMap.js
* @Description:
*
* Copyright (c) 2025 by shuishen, All Rights Reserved.
*/
import * as Cesium from 'cesium'
-import { render } from 'vue'
-import endingImg from '@/assets/images/aiNowFly/ending.png'
-import endingHighImg from '@/assets/images/aiNowFly/ending-high.png'
-import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue'
-import eventSingle from '@/assets/images/home/useEventOperate/eventSingle.png'
+import { getEventImage } from '@/utils/stateToImageMap/event'
+import { getDroneFlagImage } from '@/utils/stateToImageMap/drone'
-import eventPending from '@/assets/images/home/useEventOperate/eventPending.png' // 待处理 0
-import eventWaitAudit from '@/assets/images/home/useEventOperate/eventWaitAudit.png' // 待审核 2
-import eventProcessing from '@/assets/images/home/useEventOperate/eventProcessing.png' // 处理中 3
-import eventCompleted from '@/assets/images/home/useEventOperate/eventCompleted.png' // 已完成 4
-import eventClosed from '@/assets/images/home/useEventOperate/eventClosed.png' // 已完结 5
+import { useMapHandlerClick } from '@/hooks/components/useMapHandlerClick'
/**
*
@@ -31,20 +24,18 @@
eventApi: null,
eventApiParams: {}
}) {
- const styleTransform = 'translate(-50%,-110%)'
-
const { eventPositions, eventApi, eventApiParams } = options
- const eventImage = {
- 0: eventPending,
- 2: eventWaitAudit,
- 3: eventProcessing,
- 4: eventCompleted,
- 5: eventClosed
- }
let viewer = null
- let handler = null
- let currentEntity = null
+
+ const {
+ handlerInit: mapHandlerInit,
+ removeAll: removeMapHandlerAll
+ } = useMapHandlerClick({
+ getViewer () {
+ return viewer
+ }
+ })
// 初始化机场位置
const initDroneEntity = (dronePosition) => {
@@ -52,7 +43,7 @@
if (!lng || !lat) return
- const markerImg = status ? endingHighImg : endingImg
+ const markerImg = getDroneFlagImage(status)
const position = Cesium.Cartesian3.fromDegrees(+lng, +lat, 0)
const droneEntity = viewer?.entities.add({
@@ -93,7 +84,7 @@
eventData.length && eventData.forEach((item, index) => {
const { longitude, latitude, status, id } = item
- const curImg = eventImage[status] || eventSingle
+ const curImg = getEventImage(status)
const position = Cesium.Cartesian3.fromDegrees(+longitude, +latitude, 0)
@@ -109,7 +100,7 @@
customData: {
data: {
...item,
- eventId: item.id,
+ eventId: id,
type: 'single-drone-event'
}
}
@@ -155,104 +146,20 @@
})
}
- // 查找特定类型的实体
- const findEntityByType = (entities, type) => {
- return entities.find(entity =>
- entity?.properties?.customData?._value?.data?.type === type
- )
- }
-
- // 左键单机事件
- const singleMachineEvent = async click => {
- currentEntity = null
-
- let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id)
-
- if (!clickedEntities?.length) return
-
- 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()
+ mapHandlerInit()
}
const removeAll = () => {
removeLayer()
- removeHandler()
- removeLabel()
+ removeMapHandlerAll()
}
- onMounted(() => {
- nextTick(() => {
- init()
- })
+ onMounted(async () => {
+ await nextTick()
+ init()
})
// 自动清理
diff --git a/src/layout/Header.vue b/src/layout/Header.vue
index 3e67c19..8bdf2ca 100644
--- a/src/layout/Header.vue
+++ b/src/layout/Header.vue
@@ -128,14 +128,16 @@
font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
font-weight: 400;
font-size: 45px;
- color: #ffffff;
line-height: 53px;
letter-spacing: 11px;
- text-shadow: 0px 4px 1px rgba(19, 80, 143, 0.66), 0px 0px 18px rgba(130, 165, 255, 0.4),
- inset 0px 0px 2px rgba(255, 255, 255, 0.8);
+ text-shadow: 0px 4px 1px rgba(19,80,143,0.66), 0px 0px 18px rgba(130,165,255,0.4), inset 0px 0px 2px rgba(255,255,255,0.8);
text-align: center;
font-style: normal;
text-transform: none;
+ background: linear-gradient(180deg, #FFFFFF 23%, #E9F8FF 46%, #77BAFF 76%);
+ -webkit-background-clip: text;
+ color: transparent;
+ background-clip: text;
}
.h-right {
diff --git a/src/page/login/index.vue b/src/page/login/index.vue
index 7e0f0a8..1049488 100644
--- a/src/page/login/index.vue
+++ b/src/page/login/index.vue
@@ -3,7 +3,7 @@
<div class="login-header">
<div class="title">中图智飞低空智能感知网平台</div>
</div>
- <div class="login-left-title">中国图强 智领飞跃</div>
+ <!-- <div class="login-left-title">中国图强 智领飞跃</div> -->
<div class="login-left"></div>
<userLogin v-if="activeName === 'user'"></userLogin>
</div>
@@ -31,7 +31,7 @@
data() {
return {
login:{
- info: '中图智绘低空无人机监测网平台'
+ info: '中图智飞低空智能感知网平台'
},
website: website,
time: '',
diff --git a/src/styles/login.scss b/src/styles/login.scss
index f46ceeb..07131c3 100644
--- a/src/styles/login.scss
+++ b/src/styles/login.scss
@@ -23,15 +23,17 @@
text-align: center;
font-style: normal;
text-transform: none;
- color: #fff;
- // background: linear-gradient(90deg, #FFFFFF 0%, #B2D5FF 100%);
+ background: linear-gradient(180deg, #FFFFFF 0%, #B2D5FF 100%);
+ -webkit-background-clip: text;
+ color: transparent;
+ background-clip: text;
}
}
-.login-left-title-new {
+.login-left-title {
position: absolute;
- border: 1px solid greenyellow;
- left: 147px;
- top: 263px;
+ // border: 1px solid greenyellow;
+ left: 160px;
+ top: 240px;
width: 926px;
height: 42px;
font-family: Source Han Sans CN, Source Han Sans CN;
@@ -44,7 +46,10 @@
text-align: center;
font-style: normal;
text-transform: none;
- // background: linear-gradient(90.00000000000004deg, #FFFFFF 0%, #E3FEFF 63%, #88BAFF 100%);
+ background: linear-gradient(90.00000000000004deg, #FFFFFF 0%, #E3FEFF 63%, #88BAFF 100%);
+ -webkit-background-clip: text;
+ color: transparent;
+ background-clip: text;
}
.login-left-new {
position: absolute;
diff --git a/src/utils/stateToImageMap/drone.js b/src/utils/stateToImageMap/drone.js
new file mode 100644
index 0000000..192e78b
--- /dev/null
+++ b/src/utils/stateToImageMap/drone.js
@@ -0,0 +1,32 @@
+/*
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2025-04-17 20:17:12
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2025-04-17 20:28:08
+ * @FilePath: \command-center-dashboard\src\utils\stateToImageMap\drone.js
+ * @Description:
+ *
+ * Copyright (c) 2025 by shuishen, All Rights Reserved.
+ */
+import endingImg from '@/assets/images/aiNowFly/ending.png'
+import endingHighImg from '@/assets/images/aiNowFly/ending-high.png'
+
+const droneImage = {
+ 'OFFLINE': endingImg,
+ 'WORKING': endingHighImg,
+ 'LEISURE': endingHighImg
+}
+
+/**
+ * 根据机巢状态获取图片
+ * @param {string} status 状态
+ * @returns
+ */
+export const getDroneStatusImage = (status) => droneImage[status] || endingHighImg
+
+/**
+ * 根据机巢状态获取图片
+ * @param {boolean} isOnline 状态
+ * @returns
+ */
+export const getDroneFlagImage = (isOnline) => isOnline ? endingHighImg : endingImg
\ No newline at end of file
diff --git a/src/utils/stateToImageMap/event.js b/src/utils/stateToImageMap/event.js
new file mode 100644
index 0000000..fe6ca7e
--- /dev/null
+++ b/src/utils/stateToImageMap/event.js
@@ -0,0 +1,23 @@
+import eventSingle from '@/assets/images/home/useEventOperate/eventSingle.png'
+
+import eventPending from '@/assets/images/home/useEventOperate/eventPending.png' // 待处理 0
+import eventWaitAudit from '@/assets/images/home/useEventOperate/eventWaitAudit.png' // 待审核 2
+import eventProcessing from '@/assets/images/home/useEventOperate/eventProcessing.png' // 处理中 3
+import eventCompleted from '@/assets/images/home/useEventOperate/eventCompleted.png' // 已完成 4
+import eventClosed from '@/assets/images/home/useEventOperate/eventClosed.png' // 已完结 5
+
+
+const eventImage = {
+ 0: eventPending,
+ 2: eventWaitAudit,
+ 3: eventProcessing,
+ 4: eventCompleted,
+ 5: eventClosed
+}
+
+/**
+ * 根据事件状态获取图片资源
+ * @param {*} status 状态
+ * @returns
+ */
+export const getEventImage = (status) => eventImage[status] || eventSingle
\ No newline at end of file
diff --git a/src/views/Home/AINowFly.vue b/src/views/Home/AINowFly.vue
index 05a4f78..dbad17b 100644
--- a/src/views/Home/AINowFly.vue
+++ b/src/views/Home/AINowFly.vue
@@ -122,6 +122,8 @@
await ruleFormRef.value.validate()
if (!params.value.dock_sns.length) return ElMessage.warning('请选择将要飞行的机巢')
if (!params.value.longitude) return ElMessage.warning('请选择飞行的点')
+ // 先清除,再push
+ params.value.action_modes = [{action_actuator_func:'startRecord'}]
if (isPhoto.value) {
params.value.action_modes.push({action_actuator_func:'takePhoto'})
}
diff --git a/src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue b/src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue
index c74eacf..62c42e2 100644
--- a/src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue
+++ b/src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue
@@ -88,7 +88,9 @@
? 'finish '
: scope.row.status === 5
? 'fail '
- : ' '">
+ : ' '
+ "
+ >
{{
scope.row.status === 1
? '待执行'
@@ -110,7 +112,11 @@
<span>{{ scope.row.event_number ? scope.row.event_number : '/' }}</span>
</template>
</el-table-column>
- <el-table-column label="操作" width="80"><div class="ztzf-view">查看</div></el-table-column>
+ <el-table-column label="操作" width="80">
+ <template #default="scope">
+ <div class="ztzf-view" @click="viewDetail(scope.row)">查看</div>
+ </template>
+ </el-table-column>
</el-table>
</div>
<!-- 分页 -->
@@ -128,6 +134,18 @@
/>
</div>
</el-dialog>
+ <!-- 当前任务详情 -->
+ <CurrentTaskDetails
+ v-if="isShowCurrentTaskDetails"
+ v-model:show="isShowCurrentTaskDetails"
+ :id="currentTaskDetailsId"
+ />
+ <!-- 历史任务详情 -->
+ <DeviceJobDetails
+ v-if="deviceJobDetailsShow"
+ v-model:show="deviceJobDetailsShow"
+ :wayLineJodInfoId="wayLineJodInfoId"
+ />
</template>
<script setup>
import { pxToRem } from '@/utils/rem'
@@ -135,6 +153,8 @@
import { getDictionary } from '@/api/system/dict'
import { selectDevicePage } from '@/api/home/machineNest'
import { getMultipleDictionary } from '@/api/system/dictbiz'
+import CurrentTaskDetails from '@/components/CurrentTaskDetails/CurrentTaskDetails.vue'
+import DeviceJobDetails from '@/components/DeviceJobDetails/DeviceJobDetails.vue'
const isShowDetailsDialog = defineModel('show')
const dateRange = ref('')
const searchForm = reactive({
@@ -148,7 +168,7 @@
const statusOptions = [
{ label: '待执行', value: 1 },
{ label: '执行中', value: 2 },
- { label: '已完成', value: 3 },
+ { label: '已执行', value: 3 },
{ label: '执行失败', value: 5 },
]
@@ -215,7 +235,6 @@
}
// 获取任务列表
const getJobList = () => {
- // 事件状态:0 =待处理,1=待分拨,2=待处理,3=处理中,4=已完成 5=已完结
jobList(taskDetailParams).then(res => {
if (res.data.code !== 0) return
taskDetailData.value = res.data.data.records
@@ -249,6 +268,23 @@
return 'warning-row'
} else {
return 'success-row'
+ }
+}
+// 查看
+ // 当前任务详情 1:待执行 2:执行中
+ // 历史任务详情 3:已执行 5:执行失败
+const isShowCurrentTaskDetails = ref(false)
+const currentTaskDetailsId = ref(null)
+const deviceJobDetailsShow = ref(false)
+const wayLineJodInfoId = ref(null)
+const viewDetail = row => {
+ if (row.status === 1 || row.status === 2) {
+ currentTaskDetailsId.value = row.id
+ isShowCurrentTaskDetails.value = true
+ }
+ if (row.status === 3 || row.status === 5) {
+ wayLineJodInfoId.value = row.id
+ deviceJobDetailsShow.value = true
}
}
onMounted(() => {
@@ -331,7 +367,7 @@
}
// 执行中
.distributed {
- color: #FFA768;
+ color: #ffa768;
}
// 已执行
.finish {
diff --git a/src/views/Home/SearchBox.vue b/src/views/Home/SearchBox.vue
index 46d23e7..fb3b28c 100644
--- a/src/views/Home/SearchBox.vue
+++ b/src/views/Home/SearchBox.vue
@@ -1,277 +1,281 @@
<template>
- <div class="searchBox" ref="searchBoxRef">
- <div class="searchInput">
- <el-select v-model="optionsValue" @change="optionChange" placeholder="请选择查询">
- <el-option
- v-for="item in options"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
+ <div class="searchBox" ref="searchBoxRef">
+ <div class="searchInput">
+ <el-select v-model="optionsValue" @change="optionChange" placeholder="请选择查询">
+ <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
+ </el-select>
- <el-input v-model="searchKey" @focus="handleFocus" placeholder="请输入搜索关键字"></el-input>
- </div>
- <div class="searchBtn" @click="searchClick"></div>
- <div class="region">
- <el-tree-select
- v-model="treeValue"
- check-strictly
- lazy
- :load="load"
- :props="props"
- style="width: 240px"
- @node-click="handleNodeClick"
- />
- </div>
- </div>
- <div class="select-down-list" ref="selectDownRef" v-show="isSelectDown">
- <div class="item" v-for="item in downList" @click="selectedValue(item)">{{ item.nickname || item.name }}</div>
- </div>
+ <el-input
+ v-model="searchKey"
+ @input="handlerInput"
+ @focus="handleFocus"
+ placeholder="请输入搜索关键字"
+ ></el-input>
+ </div>
+ <div class="searchBtn" @click="searchClick"></div>
+ <div class="region">
+ <el-tree-select
+ v-model="treeValue"
+ check-strictly
+ lazy
+ :load="load"
+ :props="props"
+ style="width: 240px"
+ @node-click="handleNodeClick"
+ />
+ </div>
+ </div>
+ <div class="select-down-list" ref="selectDownRef" v-show="isSelectDown">
+ <div class="item" v-for="item in downList" @click="selectedValue(item)">{{ item.nickname || item.name }}</div>
+ </div>
</template>
<script setup>
-import { getRegion } from '@/api/home';
-import { searchByKeyword, selectDeviceList } from '@/api/home/common';
-import { useStore } from 'vuex';
+import _ from 'lodash'
+import { getRegion } from '@/api/home'
+import { searchByKeyword, selectDeviceList } from '@/api/home/common'
+import { useStore } from 'vuex'
import cesiumOperation from '@/utils/cesium-tsa'
const { flyTo } = cesiumOperation()
-const store = useStore();
-const searchKey = ref('');
-const userAreaCode = computed(() => store.state.user.userInfo.detail.areaCode);
-const selectedAreaCode = computed(() => store.state.user.selectedAreaCode);
-const areaValue = ref('江西省');
-const treeValue = ref(userAreaCode.value);
-let first = true;
-const searchBoxRef = ref(null);
-const selectDownRef = ref(null);
+const store = useStore()
+const searchKey = ref('')
+const userAreaCode = computed(() => store.state.user.userInfo.detail.areaCode)
+const selectedAreaCode = computed(() => store.state.user.selectedAreaCode)
+const areaValue = ref('江西省')
+const treeValue = ref(userAreaCode.value)
+let first = true
+const searchBoxRef = ref(null)
+const selectDownRef = ref(null)
function handleNodeClick(data) {
- areaValue.value = data.name;
- store.commit('setSelectedAreaCode', data.code);
+ areaValue.value = data.name
+ store.commit('setSelectedAreaCode', data.code)
}
const props = {
- label: 'name',
- value: 'code',
- children: 'children',
-};
+ label: 'name',
+ value: 'code',
+ children: 'children',
+}
const load = async (node, resolve) => {
- if (first) {
- first = false;
- const res = await getRegion(userAreaCode.value);
- const { provinceCode, provinceName } = res?.data?.data?.[0] || {};
- resolve([{ code: provinceCode, name: provinceName }]);
- return;
- }
- const code = node?.data?.code || userAreaCode.value;
- if ((node?.data?.regionLevel || 0) > 2) return resolve([]);
- getRegion(code).then(res => {
- resolve(res?.data?.data || []);
- });
-};
+ if (first) {
+ first = false
+ const res = await getRegion(userAreaCode.value)
+ const { provinceCode, provinceName } = res?.data?.data?.[0] || {}
+ resolve([{ code: provinceCode, name: provinceName }])
+ return
+ }
+ const code = node?.data?.code || userAreaCode.value
+ if ((node?.data?.regionLevel || 0) > 2) return resolve([])
+ getRegion(code).then(res => {
+ resolve(res?.data?.data || [])
+ })
+}
-const optionsValue = ref('1');
+const optionsValue = ref('1')
const options = [
- {
- value: '1',
- label: '机巢',
- },
- {
- value: '2',
- label: '地址',
- },
-];
+ {
+ value: '1',
+ label: '机巢',
+ },
+ {
+ value: '2',
+ label: '地址',
+ },
+]
-const isSelectDown = ref(false);
-// 下拉数据列表
-const machineNestList = ref([]);
+const isSelectDown = ref(false)
+
// 地址搜索结果
-const downList = ref([]);
-const position = ref({});
+const downList = ref([])
+const position = ref({})
// 获取机巢搜索结果
const getDeviceList = async () => {
- const res = await selectDeviceList({nickname: searchKey.value});
- if (res.data.code !== 0) return;
- machineNestList.value = res?.data?.data || [];
- downList.value = res?.data?.data || [];
-};
+ const res = await selectDeviceList({ nickname: searchKey.value })
+ if (res.data.code !== 0) return
+ downList.value = res?.data?.data || []
+}
// 获取地址搜索结果
const getAddressList = async () => {
- const res = await searchByKeyword(encodeURIComponent(`${areaValue.value}+${searchKey.value}`));
- if (res.data.code !== 0) return;
- downList.value = res?.data?.data.tips || [];
- if (downList.value.length > 0) {
- isSelectDown.value = true;
- }
-};
+ const res = await searchByKeyword(encodeURIComponent(`${areaValue.value}+${searchKey.value}`))
+ if (res.data.code !== 0) return
+ downList.value = res?.data?.data.tips || []
+ if (downList.value.length > 0) {
+ isSelectDown.value = true
+ }
+}
// 搜索结果
const searchClick = () => {
const longitude = Number(position.value.longitude)
const latitude = Number(position.value.latitude)
flyTo({ longitude, latitude }, 1, 1000)
-};
+}
// 地址和机巢的切换
const optionChange = () => {
- searchKey.value = '';
- downList.value = [];
-};
+ searchKey.value = ''
+ downList.value = []
+
+ inputSelect()
+}
+
+// input对应下拉数据初始化
+const inputSelect = () => {
+ if (optionsValue.value === '2') {
+ getAddressList()
+ } else {
+ getDeviceList()
+ }
+}
+
+inputSelect()
+
+// 输入框input事件
+const handlerInput = _.debounce(inputSelect, 1000)
+
// 输入框获取焦点
const handleFocus = () => {
- if (optionsValue.value === '1') {
- isSelectDown.value = true;
- downList.value = machineNestList.value;
- }
-};
+ isSelectDown.value = true
+}
// 机巢下拉获取值
const selectedValue = item => {
- searchKey.value = item.nickname || item.name;
- if (optionsValue.value === '1') {
- position.value = item;
- } else {
- position.value = { longitude: item.location.split(',')[0], latitude: item.location.split(',')[1] };
- }
-
- isSelectDown.value = false;
-};
+ searchKey.value = item.nickname || item.name
+ if (optionsValue.value === '1') {
+ position.value = item
+ } else {
+ position.value = { longitude: item.location.split(',')[0], latitude: item.location.split(',')[1] }
+ }
-// 监听搜索关键字变化
-watch(searchKey, async (newVal) => {
- if (optionsValue.value === '2') {
- await getAddressList();
- } else {
- await getDeviceList();
- }
-}, { immediate: false });
+ isSelectDown.value = false
+}
onMounted(() => {
- document.addEventListener('click', handleClickOutside);
-});
+ document.addEventListener('click', handleClickOutside)
+})
onUnmounted(() => {
- document.removeEventListener('click', handleClickOutside);
-});
+ document.removeEventListener('click', handleClickOutside)
+})
-const handleClickOutside = (event) => {
- if (!searchBoxRef.value?.contains(event.target) && !selectDownRef.value?.contains(event.target)) {
- isSelectDown.value = false;
- }
-};
+const handleClickOutside = event => {
+ if (!searchBoxRef.value?.contains(event.target) && !selectDownRef.value?.contains(event.target)) {
+ isSelectDown.value = false
+ }
+}
</script>
<style scoped lang="scss">
.select-down-list {
- position: absolute;
- top: 188px;
- left: 44%;
- transform: translateX(-40%);
- width: 220px;
- height: 256px;
- overflow-y: auto;
- background: linear-gradient( 180deg, #0D3556 0%, #012350 100%);
- 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;
- }
- -ms-overflow-style: none; /* IE and Edge */
- scrollbar-width: none; /* Firefox */
- .item {
- color: #FFFFFF;
- height: 32px;
- 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;
- }
- }
+ position: absolute;
+ top: 188px;
+ left: 44%;
+ transform: translateX(-40%);
+ width: 220px;
+ height: 256px;
+ overflow-y: auto;
+ background: linear-gradient(180deg, #0d3556 0%, #012350 100%);
+ 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;
+ }
+ -ms-overflow-style: none; /* IE and Edge */
+ scrollbar-width: none; /* Firefox */
+ .item {
+ color: #ffffff;
+ height: 32px;
+ 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 {
- width: 420px;
- height: 43px;
- position: absolute;
- top: 145px;
- left: 50%;
- transform: translateX(-50%);
- display: flex;
+ width: 420px;
+ height: 43px;
+ position: absolute;
+ top: 145px;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
- .el-select {
- width: 130px;
- height: 100%;
+ .el-select {
+ width: 130px;
+ height: 100%;
- :deep() {
- .el-select__wrapper {
- background: transparent;
- border: none;
- box-shadow: none;
- height: 100%;
- padding-left: 20px;
- }
+ :deep() {
+ .el-select__wrapper {
+ background: transparent;
+ border: none;
+ box-shadow: none;
+ height: 100%;
+ padding-left: 20px;
+ }
- .el-select__selected-item {
- font-family: Source Han Sans CN, Source Han Sans CN, serif;
- font-weight: 400;
- font-size: 14px;
- color: #ffffff;
- line-height: 18px;
- }
- }
- }
+ .el-select__selected-item {
+ font-family: Source Han Sans CN, Source Han Sans CN, serif;
+ font-weight: 400;
+ font-size: 14px;
+ color: #ffffff;
+ line-height: 18px;
+ }
+ }
+ }
- .searchInput {
- width: 243px;
- height: 100%;
- background: url('@/assets/images/home/searchBox/searchBg1.png') no-repeat center / 100% 100%;
- display: flex;
+ .searchInput {
+ width: 243px;
+ height: 100%;
+ background: url('@/assets/images/home/searchBox/searchBg1.png') no-repeat center / 100% 100%;
+ display: flex;
- .el-input {
- height: 100%;
+ .el-input {
+ height: 100%;
- :deep() {
- .el-input__wrapper {
- background: transparent;
- border: none;
- box-shadow: none;
- height: 100%;
- }
+ :deep() {
+ .el-input__wrapper {
+ background: transparent;
+ border: none;
+ box-shadow: none;
+ height: 100%;
+ }
- .el-input__inner {
- font-family: Source Han Sans CN, Source Han Sans CN, serif;
- font-weight: 400;
- font-size: 14px;
- color: #ffffff;
- line-height: 18px;
- }
- }
- }
- }
+ .el-input__inner {
+ font-family: Source Han Sans CN, Source Han Sans CN, serif;
+ font-weight: 400;
+ font-size: 14px;
+ color: #ffffff;
+ line-height: 18px;
+ }
+ }
+ }
+ }
- .searchBtn {
- width: 67px;
- height: 100%;
- background: url('@/assets/images/home/searchBox/searchBg2.png') no-repeat center / 100% 100%;
- cursor: pointer;
- }
+ .searchBtn {
+ width: 67px;
+ height: 100%;
+ background: url('@/assets/images/home/searchBox/searchBg2.png') no-repeat center / 100% 100%;
+ cursor: pointer;
+ }
- .region {
- width: 0;
- flex-grow: 1;
- background: url('@/assets/images/home/searchBox/searchBg3.png') no-repeat center / 100% 100%;
+ .region {
+ width: 0;
+ flex-grow: 1;
+ background: url('@/assets/images/home/searchBox/searchBg3.png') no-repeat center / 100% 100%;
- :deep() {
- .el-select__wrapper {
- width: 100px;
- padding-left: 20px;
- }
- }
- }
+ :deep() {
+ .el-select__wrapper {
+ width: 100px;
+ padding-left: 20px;
+ }
+ }
+ }
}
</style>
diff --git a/src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue b/src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue
index 98c6ac5..2c24401 100644
--- a/src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue
+++ b/src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue
@@ -1,228 +1,230 @@
<!-- 任务事件概况 -->
<template>
- <common-title title="任务事件概况" :style="{ marginLeft: pxToRem(14) }"></common-title>
- <div class="inspection-rask-details">
- <CommonDateTime :style="{ top: pxToRem(14),marginLeft: pxToRem(10) }" v-model="newTime" @change="getData"></CommonDateTime>
- <div class="chart-container" ref="chartRef"></div>
- <div class="pie-container" ref="pieRef"></div>
- </div>
+ <common-title title="任务事件概况" :style="{ marginLeft: pxToRem(14) }"></common-title>
+ <div class="inspection-rask-details">
+ <CommonDateTime
+ :style="{ top: pxToRem(14), marginLeft: pxToRem(10) }"
+ v-model="newTime"
+ @change="getData"
+ ></CommonDateTime>
+ <div class="chart-container" ref="chartRef"></div>
+ <div class="pie-container" ref="pieRef"></div>
+ </div>
</template>
<script setup>
-import * as echarts from 'echarts';
-import dayjs from 'dayjs';
-import { pxToRem } from '@/utils/rem';
-import CommonTitle from '@/components/CommonTitle.vue';
-import CommonDateTime from '@/components/CommonDateTime.vue';
+import * as echarts from 'echarts'
+import dayjs from 'dayjs'
+import { pxToRem } from '@/utils/rem'
+import CommonTitle from '@/components/CommonTitle.vue'
+import CommonDateTime from '@/components/CommonDateTime.vue'
import { jobNumBar, eventNumPie } from '@/api/home'
import useEchartsResize from '@/hooks/useEchartsResize'
+import { useStore } from 'vuex'
+const store = useStore()
+// 单个机巢信息
+const singleUavHome = computed(() => store.state.home.singleUavHome)
// 日期
-const currenDate = dayjs().format('YYYY-MM-DD');
-const newTime = ref([currenDate, currenDate]);
+const currenDate = dayjs().format('YYYY-MM-DD')
+const newTime = ref([currenDate, currenDate])
// 统计图
-const chartRef = ref(null);
+const chartRef = ref(null)
let { chart } = useEchartsResize(chartRef)
-const pieRef = ref(null);
+const pieRef = ref(null)
let { chart: pieChart } = useEchartsResize(pieRef)
-
const option = {
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- }
- },
- grid: {
- top: '15%',
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- legend: {
- data: ['任务', '事件'],
- textStyle: {
- color: '#fff'
- }
- },
- xAxis: {
- type: 'category',
- // data: ['1月', '2月', '3月', '4月', '5月', '6月'],
- axisLine: {
- lineStyle: {
- color: '#fff'
- }
- },
- axisLabel: {
- color: '#fff'
- }
- },
- yAxis: {
- type: 'value',
- axisLine: {
- lineStyle: {
- color: '#fff'
- }
- },
- splitLine: {
- lineStyle: {
- color: 'rgba(255, 255, 255, 0.1)'
- }
- },
- axisLabel: {
- color: '#fff'
- }
- },
- series: [
- {
- name: '任务',
- type: 'bar',
- barWidth: '20%',
- // data: [10, 15, 20, 25, 30, 35],
- itemStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: '#1EE7E7' },
- { offset: 1, color: 'rgba(30, 231, 231, 0.1)' }
- ])
- }
- },
- {
- name: '事件',
- type: 'bar',
- barWidth: '20%',
- // data: [15, 20, 25, 30, 35, 40],
- itemStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: '#0070FF' },
- { offset: 1, color: 'rgba(0, 112, 255, 0.1)' }
- ])
- }
- }
- ]
-};
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'shadow',
+ },
+ },
+ grid: {
+ top: '15%',
+ left: '3%',
+ right: '4%',
+ bottom: '3%',
+ containLabel: true,
+ },
+ legend: {
+ data: ['任务', '事件'],
+ textStyle: {
+ color: '#fff',
+ },
+ },
+ xAxis: {
+ type: 'category',
+ // data: ['1月', '2月', '3月', '4月', '5月', '6月'],
+ axisLine: {
+ lineStyle: {
+ color: '#fff',
+ },
+ },
+ axisLabel: {
+ color: '#fff',
+ },
+ },
+ yAxis: {
+ type: 'value',
+ axisLine: {
+ lineStyle: {
+ color: '#fff',
+ },
+ },
+ splitLine: {
+ lineStyle: {
+ color: 'rgba(255, 255, 255, 0.1)',
+ },
+ },
+ axisLabel: {
+ color: '#fff',
+ },
+ },
+ series: [
+ {
+ name: '任务',
+ type: 'bar',
+ barWidth: '20%',
+ // data: [10, 15, 20, 25, 30, 35],
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: '#1EE7E7' },
+ { offset: 1, color: 'rgba(30, 231, 231, 0.1)' },
+ ]),
+ },
+ },
+ {
+ name: '事件',
+ type: 'bar',
+ barWidth: '20%',
+ // data: [15, 20, 25, 30, 35, 40],
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: '#0070FF' },
+ { offset: 1, color: 'rgba(0, 112, 255, 0.1)' },
+ ]),
+ },
+ },
+ ],
+}
// chart.setOption(option);
const pieOption = {
- tooltip: {
- trigger: 'item',
- formatter: '{b}: {c} ({d}%)'
- },
- legend: {
- orient: 'vertical',
- right: '5%',
- top: 'middle',
- textStyle: {
- color: '#fff',
- fontSize: 12
- },
- itemWidth: 10,
- itemHeight: 10,
- itemGap: 10,
- formatter: function(name) {
- let data = pieOption.series[0].data;
- let total = 0;
- let tarValue = 0;
- for (let i = 0; i < data.length; i++) {
- total += data[i].value;
- if (data[i].name === name) {
- tarValue = data[i].value;
- }
- }
- let percentage = ((tarValue / total) * 100).toFixed(1);
- return `${name} ${percentage}%`;
- }
- },
- series: [
- {
- name: '任务状态',
- type: 'pie',
- radius: ['10%', '90%'],
- center: ['35%', '50%'], // 将图表向左偏移
- roseType: 'radius',
- itemStyle: {
- borderRadius: 4
- },
- label: {
- show: true,
- position: 'inside',
- formatter: '{c}%',
- fontSize: 12,
- color: '#fff'
- },
- data: [
- { value: 0, name: '待审核', itemStyle: { color: '#1860EC' } },
- { value: 0, name: '待处理', itemStyle: { color: '#47D107' } },
- { value: 0, name: '已完成', itemStyle: { color: '#F29509' } },
- // { value: 0, name: '待分拨', itemStyle: { color: '#E9C81A' } },
- { value: 0, name: '处理中', itemStyle: { color: '#0FC1E8' } },
- { value: 0, name: '已完结', itemStyle: { color: '#FE577F' } }
- ]
- }
- ]
-};
+ tooltip: {
+ trigger: 'item',
+ formatter: '{b}: {c} ({d}%)',
+ },
+ legend: {
+ orient: 'vertical',
+ right: '5%',
+ top: 'middle',
+ textStyle: {
+ color: '#fff',
+ fontSize: 12,
+ },
+ itemWidth: 10,
+ itemHeight: 10,
+ itemGap: 10,
+ formatter: function (name) {
+ let data = pieOption.series[0].data
+ let total = 0
+ let tarValue = 0
+ for (let i = 0; i < data.length; i++) {
+ total += data[i].value
+ if (data[i].name === name) {
+ tarValue = data[i].value
+ }
+ }
+ let percentage = ((tarValue / total) * 100).toFixed(1)
+ return `${name} ${percentage}%`
+ },
+ },
+ series: [
+ {
+ name: '任务状态',
+ type: 'pie',
+ radius: ['10%', '90%'],
+ center: ['35%', '50%'], // 将图表向左偏移
+ roseType: 'radius',
+ itemStyle: {
+ borderRadius: 4,
+ },
+ label: {
+ show: true,
+ position: 'inside',
+ formatter: '{c}%',
+ fontSize: 12,
+ color: '#fff',
+ },
+ data: [
+ { value: 0, name: '待审核', itemStyle: { color: '#1860EC' } },
+ { value: 0, name: '待处理', itemStyle: { color: '#47D107' } },
+ { value: 0, name: '已完成', itemStyle: { color: '#F29509' } },
+ // { value: 0, name: '待分拨', itemStyle: { color: '#E9C81A' } },
+ { value: 0, name: '处理中', itemStyle: { color: '#0FC1E8' } },
+ { value: 0, name: '已完结', itemStyle: { color: '#FE577F' } },
+ ],
+ },
+ ],
+}
// TODAY,CURRENT_WEEK,CURRENT_MONTH,CURRENT_YEAR
-const getData = (value,date_enum) => {
- const params = {
- device_sn: '',
- date_enum,
- // start_date: newTime.value[0],
- // end_date: newTime.value[1]
- };
- // 获取柱状图
- jobNumBar(params).then(res => {
- if (res.data.code !== 0) return;
- option.xAxis.data = res.data?.data.map(item => item.name);
- option.series[0].data = res.data?.data.map(item => item.data[0].value);
- option.series[1].data = res.data?.data.map(item => item.data[1].value);
- chart.value.setOption(option);
- })
- // 获取饼状图
- eventNumPie(params).then(res => {
- if (res.data.code!== 0) return;
- // 更新饼图数据
- const updatedPieData = pieOption.series[0].data.map(item => {
- const matchedData = res.data?.data.find(dataItem => dataItem.name === item.name);
- return {
- ...item,
- value: matchedData ? matchedData.value : item.value
- };
- });
- pieOption.series[0].data = updatedPieData;
- pieChart.value.setOption(pieOption);
- })
-};
+const getData = (value, date_enum) => {
+ const params = {
+ device_sn: singleUavHome.value.device_sn,
+ date_enum,
+ // start_date: newTime.value[0],
+ // end_date: newTime.value[1]
+ }
+ // 获取柱状图
+ jobNumBar(params).then(res => {
+ if (res.data.code !== 0) return
+ option.xAxis.data = res.data?.data.map(item => item.name)
+ option.series[0].data = res.data?.data.map(item => item.data[0].value)
+ option.series[1].data = res.data?.data.map(item => item.data[1].value)
+ chart.value.setOption(option)
+ })
+ // 获取饼状图
+ eventNumPie(params).then(res => {
+ if (res.data.code !== 0) return
+ // 更新饼图数据
+ const updatedPieData = pieOption.series[0].data.map(item => {
+ const matchedData = res.data?.data.find(dataItem => dataItem.name === item.name)
+ return {
+ ...item,
+ value: matchedData ? matchedData.value : item.value,
+ }
+ })
+ pieOption.series[0].data = updatedPieData
+ pieChart.value.setOption(pieOption)
+ })
+}
onMounted(() => {
- getData(newTime.value, 'TODAY');
-});
+ getData(newTime.value, 'TODAY')
+})
</script>
<style lang="scss" scoped>
.inspection-rask-details {
- margin-left: 29px;
- // padding: 16px 16px;
- width: 390px;
- height: 526px;
- background: linear-gradient(
- 270deg,
- rgba(31, 62, 122, 0) 0%,
- rgba(31, 62, 122, 0.35) 21%,
- #1f3e7a 100%
- );
- border-radius: 0px 0px 0px 0px;
- opacity: 0.85;
- .chart-container {
- width: 100%;
- height: 220px;
- margin-top: 20px;
- }
- .pie-container {
- width: 100%;
- height: 212px;
- margin-top: 10px;
- }
+ margin-left: 29px;
+ // padding: 16px 16px;
+ width: 390px;
+ height: 526px;
+ background: linear-gradient(270deg, rgba(31, 62, 122, 0) 0%, rgba(31, 62, 122, 0.35) 21%, #1f3e7a 100%);
+ border-radius: 0px 0px 0px 0px;
+ opacity: 0.85;
+ .chart-container {
+ width: 100%;
+ height: 220px;
+ margin-top: 20px;
+ }
+ .pie-container {
+ width: 100%;
+ height: 212px;
+ margin-top: 10px;
+ }
}
</style>
diff --git a/src/views/SignMachineNest/MachineRight/MachineMonitor.vue b/src/views/SignMachineNest/MachineRight/MachineMonitor.vue
index a0b30b8..8f44c2f 100644
--- a/src/views/SignMachineNest/MachineRight/MachineMonitor.vue
+++ b/src/views/SignMachineNest/MachineRight/MachineMonitor.vue
@@ -1,81 +1,90 @@
+<!--
+ * @Author: shuishen 1109946754@qq.com
+ * @Date: 2025-04-15 17:19:35
+ * @LastEditors: shuishen 1109946754@qq.com
+ * @LastEditTime: 2025-04-17 21:16:50
+ * @FilePath: \command-center-dashboard\src\views\SignMachineNest\MachineRight\MachineMonitor.vue
+ * @Description:
+ *
+ * Copyright (c) 2025 by shuishen, All Rights Reserved.
+-->
<!-- 机巢监控 -->
<template>
- <CommonTitle title="直播监控" />
- <div :style="{ marginLeft: pxToRem(14) }">
- <div class="machine-monitor">
- <LiveVideo :videoUrl="airPortUrl" />
- </div>
- </div>
+ <CommonTitle title="直播监控" />
+ <div :style="{ marginLeft: pxToRem(14) }">
+ <div class="machine-monitor">
+ <LiveVideo :videoUrl="airPortUrl" />
+ </div>
+ </div>
</template>
<script setup>
-import CommonTitle from '@/components/CommonTitle.vue';
-import LiveVideo from '@/components/LiveVideo.vue';
-import { liveStart } from '@/api/home/machineNest';
+import CommonTitle from '@/components/CommonTitle.vue'
+import LiveVideo from '@/components/LiveVideo.vue'
+import { liveStart } from '@/api/home/machineNest'
// import { CURRENT_CONFIG as config } from '@/utils/http/config'
-import { useStore } from 'vuex';
+import { useStore } from 'vuex'
-
-const store = useStore();
+const store = useStore()
// 单个机巢信息
-const singleUavHome = computed(() => store.state.home.singleUavHome);
+const singleUavHome = computed(() => store.state.home.singleUavHome)
// 直播地址
-let airPortUrl = ref('');
+let airPortUrl = ref('')
// 获取直播地址
-const getVideoUrl = (sn,quality) => {
- liveStart(sn, quality).then(res => {
- if (res.data.code !== 0) return;
- airPortUrl.value = res.data.data.rtcs_url;
- });
-};
-let isCurrentSn = ref(false);
-let CurrentSn = ref('');
+const getVideoUrl = (sn, quality) => {
+ liveStart(sn, quality).then(res => {
+ if (res.data.code !== 0) return
+ airPortUrl.value = res.data.data.rtcs_url
+ })
+}
+let isCurrentSn = ref(false)
+let CurrentSn = ref('')
// 监听ws消息
watch(
- () => store.state.home.deviceState.deviceInfo,
- (newValue) => {
- CurrentSn.value = Object.keys(newValue)[0];
- const currentDevice = newValue[CurrentSn.value];
- if (currentDevice && currentDevice?.mode_code > 0) {
- isCurrentSn.value = true;
- } else if (currentDevice && currentDevice?.mode_code === 14) {
- isCurrentSn.value = false;
- } else {
- isCurrentSn.value = false;
- }
- },
- {
- immediate: true,
- deep: true,
- }
-);
+ () => store.state.home.deviceState.deviceInfo,
+ newValue => {
+ CurrentSn.value = Object.keys(newValue)[0]
+ const currentDevice = newValue[CurrentSn.value]
+ if (currentDevice && currentDevice?.mode_code > 0) {
+ isCurrentSn.value = true
+ } else if (currentDevice && currentDevice?.mode_code === 14) {
+ isCurrentSn.value = false
+ } else {
+ isCurrentSn.value = false
+ }
+ },
+ {
+ immediate: true,
+ deep: true,
+ }
+)
// 监听 isCurrentSn
-watch(isCurrentSn, (newVal) => {
- if (newVal) {
- getVideoUrl(CurrentSn.value, 2);
- } else {
- getVideoUrl(singleUavHome.value.device_sn,1);
- }
-}, { immediate: true,deep: true });
+watch(
+ isCurrentSn,
+ newVal => {
+ if (newVal) {
+ getVideoUrl(CurrentSn.value, 2)
+ } else {
+ getVideoUrl(singleUavHome.value.device_sn, 1)
+ }
+ },
+ { immediate: true, deep: true }
+)
+
onMounted(() => {
- getVideoUrl(singleUavHome.value.device_sn,1);
-});
+ // getVideoUrl(singleUavHome.value.device_sn,1);
+})
</script>
<style lang="scss" scoped>
- .machine-monitor {
- width: 390px;
- height: 228px;
- background: linear-gradient(
- 270deg,
- #1f3e7a 0%,
- rgba(31, 62, 122, 0.35) 79%,
- rgba(31, 62, 122, 0) 100%
- );
- opacity: 0.85;
- margin: 2px 0 13 0;
- display: flex;
- justify-content: space-between;
- padding: 12px 10px 0;
- }
+.machine-monitor {
+ width: 390px;
+ height: 228px;
+ background: linear-gradient(270deg, #1f3e7a 0%, rgba(31, 62, 122, 0.35) 79%, rgba(31, 62, 122, 0) 100%);
+ opacity: 0.85;
+ // margin: 2px 0 13 0;
+ display: flex;
+ justify-content: space-between;
+ padding: 10px 10px;
+}
</style>
diff --git a/src/views/SignMachineNest/SignMachineNest.vue b/src/views/SignMachineNest/SignMachineNest.vue
index 2c73acd..33c48e8 100644
--- a/src/views/SignMachineNest/SignMachineNest.vue
+++ b/src/views/SignMachineNest/SignMachineNest.vue
@@ -19,7 +19,6 @@
let connectWs = ref(null)
// 单个机巢信息
const singleUavHome = computed(() => store.state.home.singleUavHome)
-const selectedAreaCode = computed(() => store.state.user.selectedAreaCode)
let osdVisible = ref({})
--
Gitblit v1.9.3