From 0be723f121c68eefafb93aba726edb7866edd0d1 Mon Sep 17 00:00:00 2001
From: chenyao <1219716595@qq.com>
Date: Fri, 23 Jan 2026 09:55:56 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'
---
applications/drone-command/src/views/permissionManage/operationLog/index.vue | 5
applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue | 6
applications/task-work-order/src/axios.js | 446 +++++++++----------
applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue | 137 +++--
applications/drone-command/src/views/recordManage/historyTracks/index.vue | 2
applications/task-work-order/src/views/orderView/orderManage/orderManage/RefuseOrderDialog.vue | 12
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue | 13
applications/task-work-order/env/.env | 3
applications/drone-command/src/components/map-container/device-map-container.vue | 580 +++++++++++++++++++-----
applications/task-work-order/src/api/zkxt/index.js | 9
applications/task-work-order/vite.config.mjs | 10
applications/task-work-order/src/App.vue | 14
applications/task-work-order/src/axiosXT.js | 73 +++
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue | 23
applications/drone-command/src/views/dataCockpit/components/HistoryWarning.vue | 6
applications/task-work-order/env/.env.development | 8
16 files changed, 893 insertions(+), 454 deletions(-)
diff --git a/applications/drone-command/src/components/map-container/device-map-container.vue b/applications/drone-command/src/components/map-container/device-map-container.vue
index d34c53a..6e584a0 100644
--- a/applications/drone-command/src/components/map-container/device-map-container.vue
+++ b/applications/drone-command/src/components/map-container/device-map-container.vue
@@ -1,4 +1,4 @@
-<template>
+<template>
<div class="map-shell">
<CommonCesiumMap ref="mapRef" class="command-cesium map-container" :dom-id="props.containerId" :active="true"
:flat-mode="false" :terrain="true" :layer-mode="4" :contour="false" :boundary="false"
@@ -93,6 +93,7 @@
import { cockpitAggregationApi } from '@/api/dataCockpit'
import layerControlIcon from '@/assets/images/dataCockpit/layerControl.png'
import equipmentIcon from '@/assets/images/dataCockpit/map/equipment.png'
+import droneIcon from '@/assets/images/dataCockpit/map/drone.png'
import aggregationIcon from '@/assets/images/dataCockpit/map/aggregation.png'
import commandPostIcon from '@/assets/images/dataCockpit/map/command-post.png'
import popupClose from '@/assets/images/dataCockpit/map/popup-close.png'
@@ -121,19 +122,29 @@
const mapRef = ref(null)
let viewer = null
-const deviceEntityIds = new Set()
-const deviceEntityMap = new Map()
-let defenseZoneSource = null
-let partitionSource = null
+let cockpitPrimitiveLayer = null
+const devicePickMap = new Map()
+let deviceBillboardCollection = null
+let deviceRingOutlinePrimitives = []
+let deviceRingFillPrimitives = []
+let defenseZonePrimitive = null
+let defenseZoneOutlinePrimitive = null
+let partitionPrimitive = null
+let partitionOutlinePrimitive = null
let aggregationSource = null
-let commandPostSource = null
+let commandPostBillboardCollection = null
+let droneTrackBillboardCollection = null
+let droneTrackPolylineCollection = null
+let droneTrackTickHandler = null
+let droneTrackStartTime = null
+let droneTrackRuntime = []
const detailVisible = ref(true)
const clusterVisible = ref(false)
const countyCenterMap = new Map()
const showLayerPanel = ref(false)
const layerWrapRef = ref(null)
const selectedDevice = ref(null)
-let selectedDeviceEntity = null
+let selectedDeviceBillboard = null
let deviceClickHandler = null
let popupRenderHandler = null
const layerTreeProps = {
@@ -180,23 +191,101 @@
return { longitude, latitude }
}
+const ensureCockpitPrimitiveLayer = () => {
+ if (!viewer) return
+ if (!cockpitPrimitiveLayer) {
+ cockpitPrimitiveLayer = new Cesium.PrimitiveCollection({ destroyPrimitives: false })
+ viewer.scene.primitives.add(cockpitPrimitiveLayer)
+ }
+}
+
+const addCockpitPrimitive = primitive => {
+ if (!primitive) return
+ if (cockpitPrimitiveLayer) {
+ cockpitPrimitiveLayer.add(primitive)
+ return
+ }
+ viewer?.scene?.primitives?.add(primitive)
+}
+
+const removeCockpitPrimitive = (primitive, destroy = true) => {
+ if (!primitive) return
+ if (cockpitPrimitiveLayer) {
+ cockpitPrimitiveLayer.remove(primitive, destroy)
+ return
+ }
+ viewer?.scene?.primitives?.remove(primitive)
+}
+
+const reorderCockpitPrimitives = () => {
+ if (!viewer) return
+ ensureCockpitPrimitiveLayer()
+ cockpitPrimitiveLayer.removeAll(false)
+ if (defenseZonePrimitive) cockpitPrimitiveLayer.add(defenseZonePrimitive)
+ if (defenseZoneOutlinePrimitive) cockpitPrimitiveLayer.add(defenseZoneOutlinePrimitive)
+ if (partitionPrimitive) cockpitPrimitiveLayer.add(partitionPrimitive)
+ if (partitionOutlinePrimitive) cockpitPrimitiveLayer.add(partitionOutlinePrimitive)
+ if (deviceRingFillPrimitives.length) {
+ deviceRingFillPrimitives.forEach(primitive => cockpitPrimitiveLayer.add(primitive))
+ }
+ if (deviceRingOutlinePrimitives.length) {
+ deviceRingOutlinePrimitives.forEach(primitive => cockpitPrimitiveLayer.add(primitive))
+ }
+ if (droneTrackPolylineCollection) cockpitPrimitiveLayer.add(droneTrackPolylineCollection)
+ if (droneTrackBillboardCollection) cockpitPrimitiveLayer.add(droneTrackBillboardCollection)
+ if (deviceBillboardCollection) cockpitPrimitiveLayer.add(deviceBillboardCollection)
+ if (commandPostBillboardCollection) cockpitPrimitiveLayer.add(commandPostBillboardCollection)
+}
+
const clearDeviceEntities = () => {
if (!viewer) return
- deviceEntityIds.forEach(id => {
- viewer.entities.removeById(id)
- })
- deviceEntityIds.clear()
- deviceEntityMap.clear()
+ if (deviceBillboardCollection) {
+ deviceBillboardCollection.removeAll()
+ removeCockpitPrimitive(deviceBillboardCollection)
+ deviceBillboardCollection = null
+ }
+ if (deviceRingFillPrimitives.length) {
+ deviceRingFillPrimitives.forEach(primitive => removeCockpitPrimitive(primitive))
+ deviceRingFillPrimitives = []
+ }
+ if (deviceRingOutlinePrimitives.length) {
+ deviceRingOutlinePrimitives.forEach(primitive => removeCockpitPrimitive(primitive))
+ deviceRingOutlinePrimitives = []
+ }
+ devicePickMap.clear()
+}
+
+const ensureDeviceCollections = () => {
+ if (!viewer) return
+ ensureCockpitPrimitiveLayer()
+ if (!deviceBillboardCollection) {
+ deviceBillboardCollection = new Cesium.BillboardCollection()
+ addCockpitPrimitive(deviceBillboardCollection)
+ }
}
const clearDefenseZoneEntities = () => {
- if (!defenseZoneSource) return
- defenseZoneSource.entities.removeAll()
+ if (!viewer) return
+ if (defenseZonePrimitive) {
+ removeCockpitPrimitive(defenseZonePrimitive)
+ defenseZonePrimitive = null
+ }
+ if (defenseZoneOutlinePrimitive) {
+ removeCockpitPrimitive(defenseZoneOutlinePrimitive)
+ defenseZoneOutlinePrimitive = null
+ }
}
const clearPartitionEntities = () => {
- if (!partitionSource) return
- partitionSource.entities.removeAll()
+ if (!viewer) return
+ if (partitionPrimitive) {
+ removeCockpitPrimitive(partitionPrimitive)
+ partitionPrimitive = null
+ }
+ if (partitionOutlinePrimitive) {
+ removeCockpitPrimitive(partitionOutlinePrimitive)
+ partitionOutlinePrimitive = null
+ }
}
const clearAggregationEntities = () => {
@@ -205,20 +294,42 @@
}
const clearCommandPostEntities = () => {
- if (!commandPostSource) return
- commandPostSource.entities.removeAll()
+ if (!viewer) return
+ if (commandPostBillboardCollection) {
+ commandPostBillboardCollection.removeAll()
+ removeCockpitPrimitive(commandPostBillboardCollection)
+ commandPostBillboardCollection = null
+ }
+}
+
+const ensureCommandPostCollection = () => {
+ if (!viewer) return
+ ensureCockpitPrimitiveLayer()
+ if (!commandPostBillboardCollection) {
+ commandPostBillboardCollection = new Cesium.BillboardCollection()
+ addCockpitPrimitive(commandPostBillboardCollection)
+ }
}
const setDetailVisibility = visible => {
detailVisible.value = visible
- if (defenseZoneSource) defenseZoneSource.show = visible
- if (partitionSource) partitionSource.show = visible
- if (commandPostSource) commandPostSource.show = visible
+ if (defenseZonePrimitive) defenseZonePrimitive.show = visible
+ if (defenseZoneOutlinePrimitive) defenseZoneOutlinePrimitive.show = visible
+ if (partitionPrimitive) partitionPrimitive.show = visible
+ if (partitionOutlinePrimitive) partitionOutlinePrimitive.show = visible
+ if (commandPostBillboardCollection) commandPostBillboardCollection.show = visible
+ if (deviceBillboardCollection) deviceBillboardCollection.show = visible
+ if (deviceRingFillPrimitives.length) {
+ deviceRingFillPrimitives.forEach(primitive => {
+ primitive.show = visible
+ })
+ }
+ if (deviceRingOutlinePrimitives.length) {
+ deviceRingOutlinePrimitives.forEach(primitive => {
+ primitive.show = visible
+ })
+ }
if (!visible) closePopup()
- deviceEntityIds.forEach(id => {
- const entity = viewer?.entities?.getById(id)
- if (entity) entity.show = visible
- })
}
const setClusterVisibility = visible => {
@@ -237,12 +348,139 @@
})
}
+const buildSimulatedTrackPoints = base => {
+ ensureCountyCenterMap()
+ const anchor = base || { longitude: 116.397, latitude: 39.908 }
+ const offsets = [
+ [0, 0, 120],
+ [0.02, 0.012, 150],
+ [0.04, 0.006, 180],
+ [0.06, -0.008, 200],
+ [0.03, -0.02, 160],
+ [0.0, -0.015, 140],
+ [-0.02, -0.005, 120],
+ [-0.01, 0.01, 130],
+ ]
+ return offsets.map(item => ({
+ longitude: anchor.longitude + item[0],
+ latitude: anchor.latitude + item[1],
+ height: item[2],
+ }))
+}
+
+
+const clearDroneTrackEntities = () => {
+ if (!viewer) return
+ if (droneTrackBillboardCollection) {
+ droneTrackBillboardCollection.removeAll()
+ removeCockpitPrimitive(droneTrackBillboardCollection)
+ droneTrackBillboardCollection = null
+ }
+ if (droneTrackPolylineCollection) {
+ droneTrackPolylineCollection.removeAll()
+ removeCockpitPrimitive(droneTrackPolylineCollection)
+ droneTrackPolylineCollection = null
+ }
+ droneTrackRuntime = []
+ stopDroneTrackAnimation()
+}
+
+
+const ensureDroneTrackCollections = () => {
+ if (!viewer) return
+ ensureCockpitPrimitiveLayer()
+ if (!droneTrackBillboardCollection) {
+ droneTrackBillboardCollection = new Cesium.BillboardCollection()
+ addCockpitPrimitive(droneTrackBillboardCollection)
+ }
+ if (!droneTrackPolylineCollection) {
+ droneTrackPolylineCollection = new Cesium.PolylineCollection()
+ addCockpitPrimitive(droneTrackPolylineCollection)
+ }
+}
+
+const startDroneTrackAnimation = () => {
+ if (!viewer) return
+ stopDroneTrackAnimation()
+ droneTrackStartTime = Cesium.JulianDate.now()
+ droneTrackTickHandler = clock => {
+ if (!droneTrackRuntime.length) return
+ const current = clock.currentTime
+ const elapsed = Cesium.JulianDate.secondsDifference(current, droneTrackStartTime)
+ droneTrackRuntime.forEach(track => {
+ const duration = track.duration
+ if (duration <= 0) return
+ const t = ((elapsed % duration) + duration) % duration
+ const seg = Math.min(track.positions.length - 2, Math.floor(t / track.segmentDuration))
+ const ratio = (t - seg * track.segmentDuration) / track.segmentDuration
+ const pos = Cesium.Cartesian3.lerp(
+ track.positions[seg],
+ track.positions[seg + 1],
+ ratio,
+ new Cesium.Cartesian3()
+ )
+ track.billboard.position = pos
+ })
+ }
+ viewer.clock.onTick.addEventListener(droneTrackTickHandler)
+ viewer.clock.shouldAnimate = true
+}
+
+const stopDroneTrackAnimation = () => {
+ if (!viewer || !droneTrackTickHandler) return
+ viewer.clock.onTick.removeEventListener(droneTrackTickHandler)
+ droneTrackTickHandler = null
+}
+
+const renderSimulatedDroneTrack = () => {
+ if (!viewer) return
+ ensureCountyCenterMap()
+ ensureDroneTrackCollections()
+ droneTrackBillboardCollection.removeAll()
+ droneTrackPolylineCollection.removeAll()
+ droneTrackRuntime = []
+ const centers = Array.from(countyCenterMap.values())
+ const baseCenters = centers.length ? centers.slice(0, 4) : [{ longitude: 116.397, latitude: 39.908 }]
+ const segmentDuration = 6
+ baseCenters.forEach((center, trackIndex) => {
+ const points = buildSimulatedTrackPoints(center)
+ if (points.length < 2) return
+ const positions = points.map(point =>
+ Cesium.Cartesian3.fromDegrees(point.longitude, point.latitude, point.height)
+ )
+ droneTrackPolylineCollection.add({
+ positions,
+ width: 2,
+ material: Cesium.Material.fromType('Color', {
+ color: Cesium.Color.fromCssColorString('#2AEDBF'),
+ }),
+ })
+ const billboard = droneTrackBillboardCollection.add({
+ position: positions[0],
+ image: droneIcon,
+ width: 36,
+ height: 36,
+ verticalOrigin: Cesium.VerticalOrigin.CENTER,
+ })
+ droneTrackRuntime.push({
+ positions,
+ billboard,
+ segmentDuration,
+ duration: (points.length - 1) * segmentDuration,
+ })
+ })
+ viewer.clock.multiplier = 1
+ startDroneTrackAnimation()
+ reorderCockpitPrimitives()
+}
const RING_STYLES = [
{ inner: 0, outer: 2000, gradient: ['#FF361C', '#360B00'] }
]
const MATERIAL_TYPE = 'RadialGradientMaterial'
+const TEXTURED_VERTEX_FORMAT =
+ Cesium.MaterialAppearance?.MaterialSupport?.TEXTURED?.vertexFormat || Cesium.VertexFormat.POSITION_AND_ST
let materialRegistered = false
const registerRadialGradientMaterial = () => {
@@ -287,27 +525,39 @@
return positions
}
-const addDeviceRings = (center, baseId, visible) => {
+const addDeviceRings = (center, ringFillInstancesByStyle, ringOutlineInstancesByStyle) => {
+ if (!ringFillInstancesByStyle) return
+ const centerPosition = Cesium.Cartesian3.fromDegrees(center.longitude, center.latitude, 0)
RING_STYLES.forEach((ring, index) => {
- const outerPositions = buildCirclePositions(center, ring.outer)
- const holes = ring.inner
- ? [new Cesium.PolygonHierarchy(buildCirclePositions(center, ring.inner))]
- : []
- const entityId = `${baseId}-ring-${index}`
- deviceEntityIds.add(entityId)
- registerRadialGradientMaterial()
- const [startColor, endColor] = ring.gradient
- const color1 = Cesium.Color.fromCssColorString(startColor).withAlpha(0.34)
- const color2 = Cesium.Color.fromCssColorString(endColor).withAlpha(0.34)
- const material = new RadialGradientMaterialProperty(color1, color2)
- viewer.entities.add({
- id: entityId,
- show: visible,
- polygon: {
- hierarchy: new Cesium.PolygonHierarchy(outerPositions, holes),
- material,
- },
- })
+ if (!ringFillInstancesByStyle[index]) return
+ ringFillInstancesByStyle[index].push(
+ new Cesium.GeometryInstance({
+ geometry: new Cesium.EllipseGeometry({
+ center: centerPosition,
+ semiMajorAxis: ring.outer,
+ semiMinorAxis: ring.outer,
+ vertexFormat: TEXTURED_VERTEX_FORMAT,
+ }),
+ })
+ )
+ })
+ if (!ringOutlineInstancesByStyle) return
+ RING_STYLES.forEach((ring, index) => {
+ if (!ringOutlineInstancesByStyle[index]) return
+ const positions = buildCirclePositions(center, ring.outer)
+ ringOutlineInstancesByStyle[index].push(
+ new Cesium.GeometryInstance({
+ geometry: new Cesium.GroundPolylineGeometry({
+ positions,
+ width: 2,
+ }),
+ attributes: {
+ color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+ Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(0.8)
+ ),
+ },
+ })
+ )
})
}
@@ -348,29 +598,69 @@
const renderDeviceEntities = devices => {
if (!viewer) return
- clearDeviceEntities()
+ ensureCockpitPrimitiveLayer()
+ ensureDeviceCollections()
+ deviceBillboardCollection.removeAll()
+ if (deviceRingFillPrimitives.length) {
+ deviceRingFillPrimitives.forEach(primitive => removeCockpitPrimitive(primitive))
+ deviceRingFillPrimitives = []
+ }
+ if (deviceRingOutlinePrimitives.length) {
+ deviceRingOutlinePrimitives.forEach(primitive => removeCockpitPrimitive(primitive))
+ deviceRingOutlinePrimitives = []
+ }
+ devicePickMap.clear()
+ deviceBillboardCollection.show = detailVisible.value
+ const ringFillInstancesByStyle = RING_STYLES.map(() => [])
+ const ringOutlineInstancesByStyle = RING_STYLES.map(() => [])
devices.forEach((item, index) => {
const position = getDevicePosition(item)
if (!position) return
const entityId = `online-device-${item.id ?? index}-${index}`
- deviceEntityIds.add(entityId)
- addDeviceRings(position, entityId, detailVisible.value)
- const entity = viewer.entities.add({
- id: entityId,
- show: detailVisible.value,
+ addDeviceRings(position, ringFillInstancesByStyle, ringOutlineInstancesByStyle)
+ const billboard = deviceBillboardCollection.add({
position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, 0),
- billboard: {
- image: equipmentIcon,
- width: 40,
- height: 56,
- verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
- },
+ image: equipmentIcon,
+ width: 40,
+ height: 56,
+ verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
})
- deviceEntityMap.set(entityId, { data: item, entity })
+ billboard.id = entityId
+ devicePickMap.set(entityId, { data: item, billboard })
})
- if (selectedDeviceEntity && !deviceEntityMap.has(selectedDeviceEntity.id)) {
+ if (selectedDeviceBillboard && !devicePickMap.has(selectedDeviceBillboard.id)) {
closePopup()
}
+ registerRadialGradientMaterial()
+ ringFillInstancesByStyle.forEach((instances, index) => {
+ if (!instances.length) return
+ const ring = RING_STYLES[index]
+ const material = Cesium.Material.fromType(MATERIAL_TYPE, {
+ color1: Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(0.64),
+ color2: Cesium.Color.fromCssColorString(ring.gradient[1]).withAlpha(0.64),
+ })
+ const primitive = new Cesium.GroundPrimitive({
+ geometryInstances: instances,
+ appearance: new Cesium.MaterialAppearance({
+ material,
+ translucent: true,
+ }),
+ })
+ primitive.show = detailVisible.value
+ addCockpitPrimitive(primitive)
+ deviceRingFillPrimitives.push(primitive)
+ })
+ ringOutlineInstancesByStyle.forEach(instances => {
+ if (!instances.length) return
+ const primitive = new Cesium.GroundPolylinePrimitive({
+ geometryInstances: instances,
+ appearance: new Cesium.PolylineColorAppearance(),
+ })
+ primitive.show = detailVisible.value
+ addCockpitPrimitive(primitive)
+ deviceRingOutlinePrimitives.push(primitive)
+ })
+ reorderCockpitPrimitives()
}
const getDefenseZonePositions = geom => {
@@ -385,70 +675,87 @@
return list.map(item => Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude))
}
-const renderZonePolygons = ({ zones, source, idPrefix, lineColor, fillGradient }) => {
- if (!viewer || !source) return
+const buildZonePrimitives = (zones, lineColor, fillColor1, fillColor2) => {
+ if (!viewer) return { primitive: null, outlinePrimitive: null }
+ const polygonInstances = []
+ const lineInstances = []
registerRadialGradientMaterial()
- const borderColor = Cesium.Color.fromCssColorString(lineColor)
- const fillColorStart = Cesium.Color.fromCssColorString(fillGradient[0]).withAlpha(0.34)
- const fillColorEnd = Cesium.Color.fromCssColorString(fillGradient[1]).withAlpha(0.34)
- const fillMaterial = new RadialGradientMaterialProperty(fillColorStart, fillColorEnd)
- zones.forEach((zone, index) => {
+ ; (zones || []).forEach((zone, index) => {
if (!zone?.geom) return
const positions = getDefenseZonePositions(zone.geom)
if (!positions.length) return
- const entityId = `${idPrefix}-${zone.id ?? index}`
- const linePositions = positions.length > 1 ? [...positions, positions[0]] : positions
- source.entities.add({
- id: entityId,
- polygon: {
- hierarchy: new Cesium.PolygonHierarchy(positions),
- material: fillMaterial,
- outline: true,
- outlineColor: borderColor,
- heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
- },
- polyline: {
- positions: linePositions,
- clampToGround: true,
- width: 2,
- material: borderColor,
- },
+ const polygon = new Cesium.PolygonGeometry({
+ polygonHierarchy: new Cesium.PolygonHierarchy(positions),
+ vertexFormat: TEXTURED_VERTEX_FORMAT,
})
+ polygonInstances.push(
+ new Cesium.GeometryInstance({
+ geometry: polygon,
+ })
+ )
+ const linePositions = positions.length > 1 ? [...positions, positions[0]] : positions
+ lineInstances.push(
+ new Cesium.GeometryInstance({
+ geometry: new Cesium.GroundPolylineGeometry({
+ positions: linePositions,
+ width: 2,
+ }),
+ attributes: {
+ color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+ Cesium.Color.fromCssColorString(lineColor)
+ ),
+ },
+ })
+ )
})
+ let primitive = null
+ if (polygonInstances.length) {
+ const baseColor1 = Cesium.Color.fromCssColorString(fillColor1)
+ const baseColor2 = Cesium.Color.fromCssColorString(fillColor2)
+ const material = Cesium.Material.fromType(MATERIAL_TYPE, {
+ color1: baseColor1.withAlpha(0.64),
+ color2: baseColor2.withAlpha(0.64),
+ })
+ primitive = new Cesium.GroundPrimitive({
+ geometryInstances: polygonInstances,
+ appearance: new Cesium.MaterialAppearance({
+ material,
+ translucent: true,
+ }),
+ })
+ addCockpitPrimitive(primitive)
+ }
+ let outlinePrimitive = null
+ if (lineInstances.length) {
+ outlinePrimitive = new Cesium.GroundPolylinePrimitive({
+ geometryInstances: lineInstances,
+ appearance: new Cesium.PolylineColorAppearance(),
+ })
+ addCockpitPrimitive(outlinePrimitive)
+ }
+ return { primitive, outlinePrimitive }
}
const renderDefenseZones = zones => {
if (!viewer) return
- if (!defenseZoneSource) {
- defenseZoneSource = new Cesium.CustomDataSource('defenseZoneSource')
- viewer.dataSources.add(defenseZoneSource)
- }
clearDefenseZoneEntities()
- defenseZoneSource.show = detailVisible.value
- renderZonePolygons({
- zones,
- source: defenseZoneSource,
- idPrefix: 'defense-zone',
- lineColor: '#19D266',
- fillGradient: ['#2AEDBF', '#012B11'],
- })
+ const result = buildZonePrimitives(zones, '#19D266', '#2AEDBF', '#012B11')
+ defenseZonePrimitive = result.primitive
+ defenseZoneOutlinePrimitive = result.outlinePrimitive
+ if (defenseZonePrimitive) defenseZonePrimitive.show = detailVisible.value
+ if (defenseZoneOutlinePrimitive) defenseZoneOutlinePrimitive.show = detailVisible.value
+ reorderCockpitPrimitives()
}
const renderPartitions = zones => {
if (!viewer) return
- if (!partitionSource) {
- partitionSource = new Cesium.CustomDataSource('partitionSource')
- viewer.dataSources.add(partitionSource)
- }
clearPartitionEntities()
- partitionSource.show = detailVisible.value
- renderZonePolygons({
- zones,
- source: partitionSource,
- idPrefix: 'partition-zone',
- lineColor: '#FFCD2A',
- fillGradient: ['#FFC609', '#583300'],
- })
+ const result = buildZonePrimitives(zones, '#FFCD2A', '#FFC609', '#583300')
+ partitionPrimitive = result.primitive
+ partitionOutlinePrimitive = result.outlinePrimitive
+ if (partitionPrimitive) partitionPrimitive.show = detailVisible.value
+ if (partitionOutlinePrimitive) partitionOutlinePrimitive.show = detailVisible.value
+ reorderCockpitPrimitives()
}
const loadDefenseZones = async () => {
@@ -517,19 +824,18 @@
const getPickedDevice = picks => {
for (const pick of picks) {
- const entityId = typeof pick?.id === 'string' ? pick.id : pick?.id?.id
- if (entityId && deviceEntityMap.has(entityId)) {
- return deviceEntityMap.get(entityId)
+ const pickId = pick?.id
+ const resolvedId = typeof pickId === 'string' ? pickId : pickId?.id
+ if (resolvedId && devicePickMap.has(resolvedId)) {
+ return devicePickMap.get(resolvedId)
}
}
return null
}
const updatePopupPosition = () => {
- if (!viewer || !selectedDeviceEntity) return
- const cartesian =
- selectedDeviceEntity.position?.getValue?.(Cesium.JulianDate.now()) ||
- selectedDeviceEntity.position?._value
+ if (!viewer || !selectedDeviceBillboard) return
+ const cartesian = selectedDeviceBillboard.position
if (!cartesian) return
const screenPosition = viewer.scene.cartesianToCanvasCoordinates(cartesian)
if (!screenPosition) return
@@ -558,7 +864,7 @@
return
}
selectedDevice.value = pickedDevice.data
- selectedDeviceEntity = pickedDevice.entity
+ selectedDeviceBillboard = pickedDevice.billboard
startPopupRender()
}
@@ -576,7 +882,7 @@
function closePopup () {
selectedDevice.value = null
- selectedDeviceEntity = null
+ selectedDeviceBillboard = null
stopPopupRender()
}
@@ -654,27 +960,21 @@
const renderCommandPosts = list => {
if (!viewer) return
- if (!commandPostSource) {
- commandPostSource = new Cesium.CustomDataSource('commandPostSource')
- viewer.dataSources.add(commandPostSource)
- }
- clearCommandPostEntities()
- commandPostSource.show = detailVisible.value
- ; (list || []).forEach((item, index) => {
- const position = getDevicePosition(item)
- if (!position) return
- commandPostSource.entities.add({
- id: `command-post-${item.id ?? index}`,
- position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, 0),
- billboard: {
- image: commandPostIcon,
- width: 40,
- height: 56,
- verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
- heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
- },
- })
+ ensureCommandPostCollection()
+ commandPostBillboardCollection.removeAll()
+ commandPostBillboardCollection.show = detailVisible.value
+ ; (list || []).forEach((item, index) => {
+ const position = getDevicePosition(item)
+ if (!position) return
+ commandPostBillboardCollection.add({
+ position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, 0),
+ image: commandPostIcon,
+ width: 40,
+ height: 56,
+ verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
})
+ })
+ reorderCockpitPrimitives()
}
const loadAggregation = async () => {
@@ -724,6 +1024,7 @@
const handleMapReady = ({ viewer: mapViewer }) => {
viewer = mapViewer
+ ensureCockpitPrimitiveLayer()
const height = viewer?.camera?.positionCartographic?.height
const stage = height != null && height >= 100000 ? 'cluster' : 'detail'
updateStageDisplay(stage)
@@ -732,6 +1033,7 @@
loadPartitions()
loadAggregation()
loadCommandPosts()
+ renderSimulatedDroneTrack()
initDeviceClickHandler()
}
@@ -759,8 +1061,13 @@
clearPartitionEntities()
clearAggregationEntities()
clearCommandPostEntities()
+ clearDroneTrackEntities()
closePopup()
destroyDeviceClickHandler()
+ if (cockpitPrimitiveLayer && viewer?.scene?.primitives) {
+ viewer.scene.primitives.remove(cockpitPrimitiveLayer)
+ }
+ cockpitPrimitiveLayer = null
viewer = null
})
</script>
@@ -1092,3 +1399,4 @@
border-color: #a1a3d4;
}
</style>
+
diff --git a/applications/drone-command/src/views/dataCockpit/components/HistoryWarning.vue b/applications/drone-command/src/views/dataCockpit/components/HistoryWarning.vue
index a0d460a..9e5efd7 100644
--- a/applications/drone-command/src/views/dataCockpit/components/HistoryWarning.vue
+++ b/applications/drone-command/src/views/dataCockpit/components/HistoryWarning.vue
@@ -9,7 +9,7 @@
<div class="search-box">
<!-- 关键字 -->
<el-input v-model="query.keyword" class="command-input" placeholder="请输入数据名称" clearable
- @keyup.enter="onSearch">
+ @keyup.enter="onSearch" @clear="onSearch">
</el-input>
<!-- 日期范围 -->
@@ -38,6 +38,7 @@
</template>
<script setup>
+ import { dateRangeFormat } from '@ztzf/utils'
import { ref, computed, onMounted } from 'vue'
import HistoryTemplate from './templateComponents/HistoryTemplate.vue'
import { alarmLogApi } from '@/api/dataCockpit'
@@ -62,10 +63,11 @@
}
const fetchHistoryWarning = async () => {
+
const startAt = Date.now()
loading.value = true
try {
- const [startTime, endTime] = query.value.dateRange || []
+ const [startTime, endTime] = dateRangeFormat(query.value.dateRange) || []
const keyword = (query.value.keyword || '').trim()
const params = {
current: 1,
diff --git a/applications/drone-command/src/views/permissionManage/operationLog/index.vue b/applications/drone-command/src/views/permissionManage/operationLog/index.vue
index 69066d8..ecf3b32 100644
--- a/applications/drone-command/src/views/permissionManage/operationLog/index.vue
+++ b/applications/drone-command/src/views/permissionManage/operationLog/index.vue
@@ -40,7 +40,7 @@
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
- value-format="YYYY-MM-DD HH:mm:ss"
+ value-format="YYYY-MM-DD"
@change="handleSearch"
/>
</el-form-item>
@@ -107,10 +107,9 @@
]
async function getList() {
- const range = dateRangeFormat(dateRange.value)
loading.value = true
try {
- const params = { ...searchParams.value, startTime: range[0], endTime: range[1] }
+ const params = { ...searchParams.value, startTime: dateRange.value[0], endTime: dateRange.value[1] }
const res = await getOperationLogPage(params)
list.value = res?.data?.data?.records ?? []
total.value = res?.data?.data?.total ?? 0
diff --git a/applications/drone-command/src/views/recordManage/historyTracks/index.vue b/applications/drone-command/src/views/recordManage/historyTracks/index.vue
index 69b6ad5..cf12e44 100644
--- a/applications/drone-command/src/views/recordManage/historyTracks/index.vue
+++ b/applications/drone-command/src/views/recordManage/historyTracks/index.vue
@@ -162,7 +162,7 @@
...searchParams.value,
start_time: range?.[0],
end_time: range?.[1],
- id: ids.join(','),
+ ids: ids.join(','),
})
.then(res => {
blobDownload(res)
diff --git a/applications/task-work-order/env/.env b/applications/task-work-order/env/.env
index f541bd6..5204ccb 100644
--- a/applications/task-work-order/env/.env
+++ b/applications/task-work-order/env/.env
@@ -1,6 +1,9 @@
#接口地址
VITE_APP_API=/api
+#接口地址-xt
+VITE_APP_API_XT=/apiXT
+
#页面基础路径
VITE_APP_BASE=/task-work-order
diff --git a/applications/task-work-order/env/.env.development b/applications/task-work-order/env/.env.development
index 9155aea..40d319b 100644
--- a/applications/task-work-order/env/.env.development
+++ b/applications/task-work-order/env/.env.development
@@ -4,10 +4,10 @@
# @LastEditors : yuan
# @LastEditTime : 2026-01-16 11:02:24
# @FilePath : \applications\task-work-order\env\.env.development
- # @Description :
- # Copyright 2026 OBKoro1, All Rights Reserved.
+ # @Description :
+ # Copyright 2026 OBKoro1, All Rights Reserved.
# 2026-01-07 14:58:30
-###
+###
NODE_ENV = 'development'
#开发环境配置
@@ -17,6 +17,8 @@
# VITE_APP_URL = https://wrj.shuixiongit.com/api
VITE_APP_URL= http://192.168.1.204
+VITE_APP_URL_XT=http://218.202.104.82:8200
+
#新大屏地址
VITE_APP_DASHBOARD_URL = 'https://wrj.shuixiongit.com/command-center-dashboard/'
diff --git a/applications/task-work-order/src/App.vue b/applications/task-work-order/src/App.vue
index 87347b7..50a0be4 100644
--- a/applications/task-work-order/src/App.vue
+++ b/applications/task-work-order/src/App.vue
@@ -2,9 +2,19 @@
<router-view />
</template>
-
-
<script setup>
+import { loginWithMiniProgramApi } from '@/api/zkxt'
+
+
+function getToken() {
+ loginWithMiniProgramApi({username: 'admin'}).then(res => {
+ console.log(res)
+ })
+}
+getToken()
+setInterval(() => {
+ getToken()
+}, 600000)
</script>
<style>
diff --git a/applications/task-work-order/src/api/zkxt/index.js b/applications/task-work-order/src/api/zkxt/index.js
new file mode 100644
index 0000000..b8b1570
--- /dev/null
+++ b/applications/task-work-order/src/api/zkxt/index.js
@@ -0,0 +1,9 @@
+import request from '@/axiosXT'
+
+export const loginWithMiniProgramApi = (data) => {
+ return request({
+ url: `/auth/loginWithMiniProgram`,
+ method: 'post',
+ data,
+ })
+}
diff --git a/applications/task-work-order/src/axios.js b/applications/task-work-order/src/axios.js
index 215e958..eb97e97 100644
--- a/applications/task-work-order/src/axios.js
+++ b/applications/task-work-order/src/axios.js
@@ -6,240 +6,224 @@
* isToken是否需要token
*/
-import axios from 'axios';
-import store from '@/store/';
-import router from '@/router/';
-import { serialize } from '@/utils/util';
-import { getToken, removeToken, removeRefreshToken } from '@/utils/auth';
-import { isURL, validatenull } from '@/utils/validate';
-import { ElMessage } from 'element-plus';
-import website from '@/config/website';
-import { Base64 } from 'js-base64';
-import { baseUrl } from '@/config/env';
-import crypto from '@/utils/crypto';
-const adminUrl = import.meta.env.VITE_APP_DASHBOARD_URL;
+import axios from 'axios'
+import store from '@/store/'
+import router from '@/router/'
+import { serialize } from '@/utils/util'
+import { getToken, removeToken, removeRefreshToken } from '@/utils/auth'
+import { isURL, validatenull } from '@/utils/validate'
+import { ElMessage } from 'element-plus'
+import website from '@/config/website'
+import { Base64 } from 'js-base64'
+import { baseUrl } from '@/config/env'
+import crypto from '@/utils/crypto'
+const adminUrl = import.meta.env.VITE_APP_DASHBOARD_URL
// 全局未授权错误提示状态,只提示一次
-let isErrorShown = false;
+let isErrorShown = false
-let _retry = false;
-// 超时时间设置为10分钟,部分接口上传比较慢,如固件上传
-axios.defaults.timeout = 600000;
-//返回其他状态码
-axios.defaults.validateStatus = function (status) {
- return status >= 200 && status <= 500; // 默认的
-};
-//跨域请求,允许保存cookie
-axios.defaults.withCredentials = true;
+let _retry = false
+
+// 创建作用域的 axios 实例
+const service = axios.create({
+ // 超时时间设置为10分钟,部分接口上传比较慢,如固件上传
+ timeout: 600000,
+ //返回其他状态码
+ validateStatus: function (status) {
+ return status >= 200 && status <= 500 // 默认的
+ },
+ //跨域请求,允许保存cookie
+ withCredentials: true,
+})
//http request拦截
-axios.interceptors.request.use(
- config => {
- // 初始化错误提示状态
- isErrorShown = false;
- //地址为已经配置状态则不添加前缀
- if (!isURL(config.url) && !config.url.startsWith(baseUrl)) {
- config.url = baseUrl + config.url;
- }
- //安全请求header
- config.headers['areaCode'] = config?.params?.areaCode || store?.state?.user?.userInfo?.detail?.areaCode;
- config.headers['Blade-Requested-With'] = 'BladeHttpRequest';
- //headers判断是否需要
- const authorization = config.authorization === false;
- if (!authorization) {
- config.headers['Authorization'] = `Basic ${Base64.encode(
- `${website.clientId}:${website.clientSecret}`
- )}`;
- }
- // 后端的要求
- if (router.currentRoute.value.path === '/job/jobstatistics'){
- const userAreaCode = store?.state?.user?.userInfo?.detail?.areaCode
- const paramsKey = config.method === 'get' ? 'params' : 'data';
- const codeKey = config.method === 'get' ? 'areaCode' : 'area_code';
- const paramCode = config?.params?.areaCode || config?.data?.area_code
- try {
- if (paramCode){
- if (paramCode === userAreaCode) {
- config[paramsKey][codeKey] = config.method === 'get' ? '' : undefined;
- } else {
- if (!Array.isArray(config[paramsKey])){
- config[paramsKey] = {...config[paramsKey],[codeKey]: paramCode}
- }
- }
- }
- }catch (e) {}
- }
+service.interceptors.request.use(
+ config => {
+ // 初始化错误提示状态
+ isErrorShown = false
+ //地址为已经配置状态则不添加前缀
+ if (!isURL(config.url) && !config.url.startsWith(baseUrl)) {
+ config.url = baseUrl + config.url
+ }
+ //安全请求header
+ config.headers['areaCode'] = config?.params?.areaCode || store?.state?.user?.userInfo?.detail?.areaCode
+ config.headers['Blade-Requested-With'] = 'BladeHttpRequest'
+ //headers判断是否需要
+ const authorization = config.authorization === false
+ if (!authorization) {
+ config.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`
+ }
- //headers判断请求是否携带token
- const meta = config.meta || {};
- const isToken = meta.isToken === false;
- //headers传递token是否加密
- const cryptoToken = config.cryptoToken === true;
- //判断传递数据是否加密
- const cryptoData = config.cryptoData === true;
- const token = getToken();
- if (token && !isToken) {
- config.headers[website.tokenHeader] = cryptoToken
- ? 'crypto ' + crypto.encryptAES(token, crypto.cryptoKey)
- : 'bearer ' + token;
- }
- // 开启报文加密
- // if (cryptoData) {
- // if (config.params) {
- // const data = crypto.encryptAES(JSON.stringify(config.params), crypto.aesKey);
- // config.params = { data };
- // }
- // if (config.data) {
- // config.text = true;
- // config.data = crypto.encryptAES(JSON.stringify(config.data), crypto.aesKey);
- // }
- // }
- //headers中配置text请求
- if (config.text === true) {
- config.headers['Content-Type'] = 'text/plain';
- }
- //headers中配置serialize为true开启序列化
- if (config.method === 'post' && meta.isSerialize === true) {
- config.data = serialize(config.data);
- }
- return config;
- },
- error => {
- return Promise.reject(error);
- }
-);
+ //headers判断请求是否携带token
+ const meta = config.meta || {}
+ const isToken = meta.isToken === false
+ //headers传递token是否加密
+ const cryptoToken = config.cryptoToken === true
+ //判断传递数据是否加密
+ const cryptoData = config.cryptoData === true
+ const token = getToken()
+ if (token && !isToken) {
+ config.headers[website.tokenHeader] = cryptoToken
+ ? 'crypto ' + crypto.encryptAES(token, crypto.cryptoKey)
+ : 'bearer ' + token
+ }
+ // 开启报文加密
+ // if (cryptoData) {
+ // if (config.params) {
+ // const data = crypto.encryptAES(JSON.stringify(config.params), crypto.aesKey);
+ // config.params = { data };
+ // }
+ // if (config.data) {
+ // config.text = true;
+ // config.data = crypto.encryptAES(JSON.stringify(config.data), crypto.aesKey);
+ // }
+ // }
+ //headers中配置text请求
+ if (config.text === true) {
+ config.headers['Content-Type'] = 'text/plain'
+ }
+ //headers中配置serialize为true开启序列化
+ if (config.method === 'post' && meta.isSerialize === true) {
+ config.data = serialize(config.data)
+ }
+ return config
+ },
+ error => {
+ return Promise.reject(error)
+ }
+)
//http response拦截
-axios.interceptors.response.use(
- res => {
- const status = res.data.error_code || res.data.code || res.status;
- const statusWhiteList = website.statusWhiteList || [];
- const message = res.data.msg || res.data.error_description || res.data.message || '系统错误';
- const config = res.config;
- const cryptoData = config.cryptoData === true;
- if (status === 511) {
- ElMessage({
- message: '请联系运维人员上传密钥证书!',
- type: 'error',
- });
- // 获取当前路由名称
- const currentRouteName = router.currentRoute.value.name;
- // 如果当前路由不是登录页,则跳转到登录页
- if (currentRouteName !== '登录页') {
- store.dispatch('FedLogOut').then(() =>
- router.push({
- path: '/login',
- })
- );
- }
- return Promise.reject(new Error(message));
- }
- //如果在白名单里则自行catch逻辑处理
- if (statusWhiteList.includes(status)) return Promise.reject(res);
- // 如果是401并且没有重试过,尝试刷新token
- if (status === 401 && !_retry) {
- // 标记此请求已尝试刷新token
- _retry = true;
- // 调用RefreshToken action来刷新token
- return store
- .dispatch('RefreshToken')
- .then(() => {
- const meta = config.meta || {};
- const isToken = meta.isToken === false;
- const cryptoToken = config.cryptoToken === true;
- // 获取刷新后的token
- const token = getToken();
- if (token && !isToken) {
- config.headers[website.tokenHeader] = cryptoToken
- ? 'crypto ' + crypto.encryptAES(token, crypto.cryptoKey)
- : 'bearer ' + token;
- }
- // 重新发送原来的请求
- return axios(config);
- })
- .catch(() => {
- // 首次报错时提示
- if (!isErrorShown) {
- isErrorShown = true;
- ElMessage({
- message: message,
- type: 'error',
- });
- }
- // 清除token信息
- removeToken();
- removeRefreshToken();
- const env = import.meta.env.VITE_APP_ENV;
- // 重定向到登录页
- // store.dispatch('FedLogOut').then(() => router.push({
- // path: '/login'
- // }));
- env === 'development'
- ? store.dispatch('FedLogOut').then(() =>
- router.push({
- path: '/login',
- })
- )
- : store.dispatch('FedLogOut').then(() => window.location.replace(`${adminUrl}#/login`));
- return Promise.reject(new Error(message));
- });
- }
- // 如果是401并且已经重试过,直接跳转到登录页面
- if (status === 401 && _retry) {
- // 首次报错时提示
- if (!isErrorShown) {
- isErrorShown = true;
- ElMessage({
- message: '用户令牌过期,请重新登录',
- type: 'error',
- });
- }
- // 清除token信息
- removeToken();
- removeRefreshToken();
- // 重定向到登录页
- // store.dispatch('FedLogOut').then(() => router.push({
- // path: '/login'
- // }));
- const env = import.meta.env.VITE_APP_ENV;
- env === 'development'
- ? store.dispatch('FedLogOut').then(() =>
- router.push({
- path: '/login',
- })
- )
- : store.dispatch('FedLogOut').then(() => window.location.replace(`${adminUrl}#/login`));
- return Promise.reject(new Error(message));
- }
- // 如果请求为oauth2错误码则首次报错时提示
- if (status > 2000 && !validatenull(res.data.error_description)) {
- // 首次报错时提示
- if (!isErrorShown) {
- isErrorShown = true;
- ElMessage({
- message: message,
- type: 'error',
- });
- }
- return Promise.reject(new Error(message));
- }
- // 如果请求为非200默认统一处理
- if (status !== 200 && status !== 0) {
- if (!isErrorShown) {
- ElMessage({
- message: message,
- type: 'error',
- });
- }
- return Promise.reject(new Error(message));
- }
- // 解析加密报文
- if (cryptoData) {
- res.data = JSON.parse(crypto.decryptAES(res.data, crypto.aesKey));
- }
- return res;
- },
- error => {
- return Promise.reject(new Error(error));
- }
-);
-window._request = axios
-export default axios;
+service.interceptors.response.use(
+ res => {
+ const status = res.data.error_code || res.data.code || res.status
+ const statusWhiteList = website.statusWhiteList || []
+ const message = res.data.msg || res.data.error_description || res.data.message || '系统错误'
+ const config = res.config
+ const cryptoData = config.cryptoData === true
+ if (status === 511) {
+ ElMessage({
+ message: '请联系运维人员上传密钥证书!',
+ type: 'error',
+ })
+ // 获取当前路由名称
+ const currentRouteName = router.currentRoute.value.name
+ // 如果当前路由不是登录页,则跳转到登录页
+ if (currentRouteName !== '登录页') {
+ store.dispatch('FedLogOut').then(() =>
+ router.push({
+ path: '/login',
+ })
+ )
+ }
+ return Promise.reject(new Error(message))
+ }
+ //如果在白名单里则自行catch逻辑处理
+ if (statusWhiteList.includes(status)) return Promise.reject(res)
+ // 如果是401并且没有重试过,尝试刷新token
+ if (status === 401 && !_retry) {
+ // 标记此请求已尝试刷新token
+ _retry = true
+ // 调用RefreshToken action来刷新token
+ return store
+ .dispatch('RefreshToken')
+ .then(() => {
+ const meta = config.meta || {}
+ const isToken = meta.isToken === false
+ const cryptoToken = config.cryptoToken === true
+ // 获取刷新后的token
+ const token = getToken()
+ if (token && !isToken) {
+ config.headers[website.tokenHeader] = cryptoToken
+ ? 'crypto ' + crypto.encryptAES(token, crypto.cryptoKey)
+ : 'bearer ' + token
+ }
+ // 重新发送原来的请求
+ return service(config)
+ })
+ .catch(() => {
+ // 首次报错时提示
+ if (!isErrorShown) {
+ isErrorShown = true
+ ElMessage({
+ message: message,
+ type: 'error',
+ })
+ }
+ // 清除token信息
+ removeToken()
+ removeRefreshToken()
+ const env = import.meta.env.VITE_APP_ENV
+ // 重定向到登录页
+ // store.dispatch('FedLogOut').then(() => router.push({
+ // path: '/login'
+ // }));
+ env === 'development'
+ ? store.dispatch('FedLogOut').then(() =>
+ router.push({
+ path: '/login',
+ })
+ )
+ : store.dispatch('FedLogOut').then(() => window.location.replace(`${adminUrl}#/login`))
+ return Promise.reject(new Error(message))
+ })
+ }
+ // 如果是401并且已经重试过,直接跳转到登录页面
+ if (status === 401 && _retry) {
+ // 首次报错时提示
+ if (!isErrorShown) {
+ isErrorShown = true
+ ElMessage({
+ message: '用户令牌过期,请重新登录',
+ type: 'error',
+ })
+ }
+ // 清除token信息
+ removeToken()
+ removeRefreshToken()
+ // 重定向到登录页
+ // store.dispatch('FedLogOut').then(() => router.push({
+ // path: '/login'
+ // }));
+ const env = import.meta.env.VITE_APP_ENV
+ env === 'development'
+ ? store.dispatch('FedLogOut').then(() =>
+ router.push({
+ path: '/login',
+ })
+ )
+ : store.dispatch('FedLogOut').then(() => window.location.replace(`${adminUrl}#/login`))
+ return Promise.reject(new Error(message))
+ }
+ // 如果请求为oauth2错误码则首次报错时提示
+ if (status > 2000 && !validatenull(res.data.error_description)) {
+ // 首次报错时提示
+ if (!isErrorShown) {
+ isErrorShown = true
+ ElMessage({
+ message: message,
+ type: 'error',
+ })
+ }
+ return Promise.reject(new Error(message))
+ }
+ // 如果请求为非200默认统一处理
+ if (status !== 200 && status !== 0) {
+ if (!isErrorShown) {
+ ElMessage({
+ message: message,
+ type: 'error',
+ })
+ }
+ return Promise.reject(new Error(message))
+ }
+ // 解析加密报文
+ if (cryptoData) {
+ res.data = JSON.parse(crypto.decryptAES(res.data, crypto.aesKey))
+ }
+ return res
+ },
+ error => {
+ return Promise.reject(new Error(error))
+ }
+)
+window._request = service
+export default service
diff --git a/applications/task-work-order/src/axiosXT.js b/applications/task-work-order/src/axiosXT.js
new file mode 100644
index 0000000..edc95df
--- /dev/null
+++ b/applications/task-work-order/src/axiosXT.js
@@ -0,0 +1,73 @@
+import axios from 'axios'
+import store from '@/store/'
+import { serialize } from '@/utils/util'
+import { getToken, removeToken, removeRefreshToken } from '@/utils/auth'
+import { isURL, validatenull } from '@/utils/validate'
+import { ElMessage } from 'element-plus'
+import website from '@/config/website'
+import { Base64 } from 'js-base64'
+import { baseUrl } from '@/config/env'
+import crypto from '@/utils/crypto'
+// 全局未授权错误提示状态,只提示一次
+const { VITE_APP_API_XT } = import.meta.env
+
+// 创建作用域的 axios 实例
+const serviceXT = axios.create({
+ // 超时时间设置为10分钟,部分接口上传比较慢,如固件上传
+ timeout: 600000,
+ baseURL: VITE_APP_API_XT,
+ //返回其他状态码
+ validateStatus: function (status) {
+ return status >= 200 && status <= 500 // 默认的
+ },
+ //跨域请求,允许保存cookie
+ withCredentials: true,
+})
+
+//http request拦截
+serviceXT.interceptors.request.use(
+ config => {
+ //headers判断是否需要
+ const authorization = config.authorization === false
+ if (!authorization) {
+ config.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`
+ }
+ const meta = config.meta || {}
+
+ //headers中配置text请求
+ if (config.text === true) {
+ config.headers['Content-Type'] = 'text/plain'
+ }
+ //headers中配置serialize为true开启序列化
+ if (config.method === 'post' && meta.isSerialize === true) {
+ config.data = serialize(config.data)
+ }
+ return config
+ },
+ error => {
+ return Promise.reject(error)
+ }
+)
+//http response拦截
+serviceXT.interceptors.response.use(
+ res => {
+ const status = res.data.error_code || res.data.code || res.status
+ const statusWhiteList = website.statusWhiteList || []
+ const message = res?.data?.msg || res?.data?.message || '系统错误'
+ //如果在白名单里则自行catch逻辑处理
+ if (statusWhiteList.includes(status)) return Promise.reject(res)
+ // 如果请求为非200默认统一处理
+ if (status !== 200 && status !== 0) {
+ ElMessage({
+ message: message,
+ type: 'error',
+ })
+ return Promise.reject(new Error(message))
+ }
+ return res
+ },
+ error => {
+ return Promise.reject(new Error(error))
+ }
+)
+export default serviceXT
diff --git a/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue b/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue
index c8ed5a9..ce3fe74 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue
@@ -256,19 +256,26 @@
// 获取工单列表
async function getWorkOrderList() {
- const res = await gdWorkOrderPageApi({ size: 999 })
+ const res = await gdWorkOrderPageApi({ size: 999, })
workOrderList.value = res?.data?.data?.records ?? []
}
// 获取飞手列表
async function getFlyerList() {
- const res = await gdFlyerPageApi({ size: 999 })
+ const res = await gdFlyerPageApi({
+ size: 999,
+ // todo 需要传入前面的巡查类型
+ // patrolTaskType: '1',
+ })
flyerList.value = res?.data?.data?.records ?? []
}
// 获取设备列表
async function getDeviceList() {
- const res = await gdManageDeviceListApi()
+ const res = await gdManageDeviceListApi({
+ // TODO 需要传入ids设备
+ // ids:
+ })
deviceList.value = res?.data?.data ?? []
}
diff --git a/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue b/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue
index 3328dee..b3eaa32 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue
@@ -1,5 +1,9 @@
<template>
<basic-container>
+ <el-tabs class="gd-tabs" v-model="activeName" @tab-click="tabsClick">
+ <el-tab-pane label="全部 " name="all"></el-tab-pane>
+ <el-tab-pane label="我的任务工单" name="my"></el-tab-pane>
+ </el-tabs>
<el-form ref="queryParamsRef" :model="searchParams" class="gd-search-form">
<el-form-item label="任务名称" prop="patrolTaskName">
<el-input
@@ -68,9 +72,7 @@
</el-form>
<div class="gd-table-toolbar">
-<!-- <el-button color="#F2F3F5" @click="requester = !requester">我是{{ requester ? '需求方' : '服务方' }}</el-button>-->
- <el-button :icon="Plus" color="#4C34FF" type="primary" @click="openForm('add')">新增</el-button>
- <!-- <el-button :icon="Delete" color="#4C34FF" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>-->
+ <el-button v-if="requester" :icon="Plus" color="#4C34FF" type="primary" @click="openForm('add')">新增</el-button>
</div>
<div class="gd-table-container" v-loading="loading">
@@ -159,7 +161,7 @@
deviceLoadDemand: [], // 设备负载需求
taskStatus: [], // 巡查任务状态
})
-
+const activeName = ref('all')
provide('dictObj', dictObj)
provide('requester', requester)
@@ -168,7 +170,12 @@
const range = dateRangeFormat(dateRange.value)
loading.value = true
try {
- const res = await gdPatrolTaskPageApi({ ...searchParams.value, startTime: range[0], endTime: range[1] })
+ const res = await gdPatrolTaskPageApi({
+ ...searchParams.value,
+ startTime: range[0],
+ endTime: range[1],
+ createUser: activeName.value === 'my' ? store.state.user.userInfo.user_id : '',
+ })
list.value = res?.data?.data?.records ?? []
total.value = res?.data?.data?.total ?? 0
} finally {
@@ -176,6 +183,12 @@
}
}
+function tabsClick(tab, event) {
+ activeName.value = tab.props.name
+ resetForm()
+ handleSearch()
+}
+
// 查询
function handleSearch() {
searchParams.value.current = 1
diff --git a/applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue b/applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue
index 467f20a..0cafd2f 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue
@@ -179,48 +179,35 @@
</div>
<template #footer>
- <!-- <el-button color="#F2F3F5" @click="visible = false">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>-->
- <el-button
- class="save-btn"
- color="#4C34FF"
- v-if="(!dialogReadonly && !formData.id) || suddenlyEdit"
- :loading="submitting"
- :disabled="submitting"
- @click="handleSubmit"
- >
- 发布
- </el-button>
+ <template v-if="requester">
+ <el-button
+ v-if="['11', '31'].includes(gdStatus) || suddenlyEdit || (!dialogReadonly && !formData.id)"
+ :loading="submitting"
+ :disabled="submitting"
+ @click="handleSubmit"
+ >
+ {{ gdStatus === '11' ? '发布' : '提交修改' }}
+ 发布
+ </el-button>
+ <el-button v-if="['11', '21', '23', '24', '25', '31', '60'].includes(gdStatus)" @click="viewDescription">
+ {{ gdStatusObj[gdStatus].reason }}
+ </el-button>
+ <el-button @click="addDescription" v-if="['20', '24', '25', '50'].includes(gdStatus)">
+ {{ gdStatus === '50' ? '结算' : '申请取消' }}
+ </el-button>
+ <el-button @click="requestModification" v-if="['20', '25'].includes(gdStatus)">申请修改</el-button>
+ </template>
<template v-else>
- <template v-if="requester">
- <el-button
- class="save-btn"
- color="#4C34FF"
- v-if="editStatus.includes(gdStatus)"
- :loading="submitting"
- :disabled="submitting"
- @click="handleSubmit"
- >
- 发布
- </el-button>
- <el-button color="#F2F3F5" v-if="gdStatus === '11'" @click="addDescription(2, 'view')">拒单原因</el-button>
- <el-button color="#F2F3F5" @click="statusChange(3)" v-if="gdStatus === '20'">申请取消</el-button>
- <el-button color="#4C34FF" @click="requestModification" v-if="gdStatus === '20'" class="save-btn">
- 申请修改
- </el-button>
- </template>
- <template v-else>
- <el-button color="#F2F3F5" v-if="gdStatus === '10'" @click="addDescription(2)">拒绝接单</el-button>
- <el-button color="#4C34FF" v-if="gdStatus === '10'" @click="statusChange(1)" class="save-btn">接单</el-button>
- <el-button color="#F2F3F5" v-if="gdStatus === '22'" @click="statusChange(7)">同意修改</el-button>
- <el-button color="#4C34FF" v-if="gdStatus === '22'" @click="statusChange(8)" class="save-btn">
- 不同意修改
- </el-button>
- <el-button color="#F2F3F5" v-if="gdStatus === '21'" @click="statusChange(5)">同意取消</el-button>
- <el-button color="#4C34FF" v-if="gdStatus === '21'" @click="statusChange(6)" class="save-btn">
- 不同意取消
- </el-button>
- <el-button color="#F2F3F5" v-if="gdStatus === '30'" @click="addDescription(9)">协商修改</el-button>
- </template>
+ <el-button v-if="['21', '23'].includes(gdStatus)" @click="viewDescription">
+ {{ gdStatusObj[gdStatus].reason }}
+ </el-button>
+ <el-button v-if="gdStatus === '10'" @click="addDescription">拒绝接单</el-button>
+ <el-button v-if="gdStatus === '10'" @click="statusChange(1)">接单</el-button>
+ <el-button v-if="gdStatus === '22'" @click="statusChange(7)">同意修改</el-button>
+ <el-button v-if="gdStatus === '22'" @click="statusChange(8)">不同意修改</el-button>
+ <el-button v-if="gdStatus === '21'" @click="statusChange(5)">同意取消</el-button>
+ <el-button v-if="gdStatus === '21'" @click="statusChange(6)">不同意取消</el-button>
+ <el-button v-if="gdStatus === '30'" @click="addDescription">协商修改</el-button>
</template>
</template>
@@ -286,11 +273,27 @@
let drawPolygonExample
let pointList = ref([])
const requester = inject('requester')
-const editStatus = inject('editStatus')
const suddenlyEdit = ref(false)
const processList = ref([])
let viewPlane
const hasPatrolTaskList = computed(() => ['30', '40', '50', '60'].includes(String(formData.value.workOrderStatus)))
+
+const gdStatusObj = {
+ '0': { reason: '' },
+ '10': { reason: '拒绝原因', operationType: '2' },
+ '11': { reason: '拒绝原因' },
+ '20': { reason: '取消原因', operationType: '3' },
+ '21': { reason: '取消原因' },
+ '22': { reason: '驳回原因' },
+ '23': { reason: '取消原因' },
+ '24': { reason: '驳回原因', operationType: '3' },
+ '25': { reason: '驳回原因', operationType: '3' },
+ '30': { reason: '修改原因', operationType: '9' },
+ '31': { reason: '修改原因' },
+ '40': { reason: '' },
+ '50': { reason: '情况说明', operationType: '10' },
+ '60': { reason: '情况说明' },
+}
// 工单状态:0草稿、10发布中_接单中、11发布中_拒绝接单、20响应中_待拆分、21响应中_申请取消、22响应中_申请修改、23响应中_已取消、
// 24响应中_拒绝取消、25响应中_拒绝修改 30执行中_待全部完成、31执行中_协商修改、40完成待验_待全部验收、50验收通过_待结算、60结算完成_已结算
@@ -302,9 +305,13 @@
executeStartTime: fieldRules(true),
deviceLoadDemand: fieldRules(true),
}
+
// 操作类型:1接单,2拒接接单,3申请取消,4申请修改, 5同意取消 6不同意取消 7.同意修改 8.不同意修改 9.协商修改
function statusChange(operationType) {
- gdWorkOrderHandleStatusApi({ operationType: operationType, workOrderId: formData.value.id }).then(res => {
+ gdWorkOrderHandleStatusApi({
+ operationType: operationType,
+ workOrderId: formData.value.id,
+ }).then(res => {
visible.value = false
emit('success')
})
@@ -326,24 +333,24 @@
}
// 填写说明
-function addDescription(type, mode = 'add') {
- let formLabel = ''
- switch (type) {
- case 2:
- formLabel = '拒绝原因'
- break
- case 9:
- formLabel = '修改原因'
- break
- }
+function addDescription() {
rejectVisible.value = true
nextTick(() => {
refuseOrderDialogRef.value.open({
- mode,
+ mode: 'add',
row: formData.value,
- type,
- formLabel,
+ type: gdStatusObj[gdStatus.value].operationType,
+ formLabel: gdStatusObj[gdStatus.value].reason,
})
+ })
+}
+
+function viewDescription() {
+ rejectVisible.value = true
+ refuseOrderDialogRef.value.open({
+ mode: 'view',
+ row: formData.value,
+ formLabel: gdStatusObj[gdStatus.value].reason,
})
}
@@ -365,6 +372,7 @@
function loadDemandChange() {
formData.value.recommendDeviceIds = ''
+ selectedDevices.value = []
getDeviceList()
syncSelection()
}
@@ -380,8 +388,10 @@
const isValid = await formRef.value?.validate().catch(() => false)
if (!isValid) return
if (!pointList.value.length) {
- ElMessage.warning('请绘制范围')
- return
+ return ElMessage.warning('请绘制范围')
+ }
+ if (!formData.value.recommendDeviceIds) {
+ return ElMessage.warning('请选择设备')
}
submitting.value = true
try {
@@ -436,6 +446,8 @@
const val = cartesian3Convert(item, viewer)
return { ...val, lng: val.longitude, lat: val.latitude }
})
+ formData.value.recommendDeviceIds = ''
+ selectedDevices.value = []
await getDeviceList()
syncSelection()
}
@@ -502,10 +514,11 @@
}
import droneIcon from '@/assets/images/orderView/orderManage/drone.png'
+
function renderingDevice(list) {
- // 渲染红点
+ // 渲染红点
list.forEach(item => {
- const position = Cesium.Cartesian3.fromDegrees(item.longitude || 115.00, item.latitude || 27.11)
+ const position = Cesium.Cartesian3.fromDegrees(item.longitude || 115.0, item.latitude || 27.11)
viewer.entities.add({
position: position,
billboard: {
@@ -554,16 +567,19 @@
.content {
display: flex;
gap: 0 20px;
+
.leftBox {
width: 0;
flex: 1;
display: flex;
flex-direction: column;
+
.gd-cesium {
width: 100%;
height: 423px;
}
}
+
.rightBox {
.title {
font-weight: 500;
@@ -571,6 +587,7 @@
color: #272e37;
}
}
+
.processBox {
width: 312px;
}
diff --git a/applications/task-work-order/src/views/orderView/orderManage/orderManage/RefuseOrderDialog.vue b/applications/task-work-order/src/views/orderView/orderManage/orderManage/RefuseOrderDialog.vue
index 07f477c..03f2608 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/orderManage/RefuseOrderDialog.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/orderManage/RefuseOrderDialog.vue
@@ -100,11 +100,19 @@
}
let formLabelStr = ref('原因')
-// 打开弹框
+
+
+// 操作类型:1接单,2拒接接单,3申请取消,4申请修改, 5同意取消 6不同意取消 7.同意修改 8.不同意修改 9.协商修改
async function open({ mode = 'add', row, formLabel, type } = {}) {
dialogMode.value = mode
formLabelStr.value = formLabel
- formData.value = { workOrderId: row.id, operationType: type, rejectReason: row.rejectReason }
+ formData.value = {
+ workOrderId: row.id,
+ operationType: type,
+ }
+ if (dialogMode.value !== 'add'){
+ formData.value.rejectReason = row.rejectReason
+ }
}
defineExpose({ open })
diff --git a/applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue b/applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue
index 50f0e85..524292f 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue
@@ -107,8 +107,8 @@
{{ dayjs(row.executeEndTime).format('YYYY-MM-DD') }}
</template>
</el-table-column>
- <el-table-column prop="serviceParty" show-overflow-tooltip label="服务方名称" />
<el-table-column prop="createUserName" show-overflow-tooltip label="需求方名称" />
+ <el-table-column prop="serviceParty" show-overflow-tooltip label="服务方名称" />
<el-table-column prop="createTime" show-overflow-tooltip label="工单创建时间" />
<el-table-column label="操作" class-name="operation-btns">
<template v-slot="{ row }">
@@ -229,8 +229,6 @@
dialogRef.value?.open({ mode, row })
})
}
-const editStatus = ['0','11','24','25']
-provide('editStatus', editStatus)
// 工单状态:0草稿、10发布中_接单中、11发布中_拒绝接单、20响应中_待拆分、
// 21响应中_申请取消、22响应中_申请修改、23响应中_已取消、24响应中_拒绝取消、
// 25响应中_拒绝修改 30执行中_待全部完成、31执行中_协商修改、40完成待验_待全部验收、
@@ -238,7 +236,7 @@
function openFormChange(row) {
dialogVisible.value = true
nextTick(() => {
- const mode = editStatus.includes(row.workOrderStatus) && requester.value ? 'edit' : 'view'
+ const mode = ['11','25'].includes(row.workOrderStatus) && requester.value ? 'edit' : 'view'
dialogRef.value?.open({ mode, row })
})
}
diff --git a/applications/task-work-order/vite.config.mjs b/applications/task-work-order/vite.config.mjs
index f29b570..831ff6c 100644
--- a/applications/task-work-order/vite.config.mjs
+++ b/applications/task-work-order/vite.config.mjs
@@ -6,7 +6,7 @@
// https://vitejs.dev/config/
export default ({ mode, command }) => {
const env = loadEnv(mode, fileURLToPath(new URL("./env", import.meta.url)))
- const { VITE_APP_ENV, VITE_APP_BASE, VITE_APP_URL } = env
+ const { VITE_APP_ENV, VITE_APP_BASE, VITE_APP_URL,VITE_APP_API_XT,VITE_APP_URL_XT } = env
// 判断是打生产环境包
const isProd = VITE_APP_ENV === 'production'
@@ -41,11 +41,17 @@
port: 5178,
// host: '192.168.1.178',
proxy: {
+ '/apiXT': {
+ target: VITE_APP_URL_XT,
+ changeOrigin: true,
+ rewrite: path => path.replace(/^\/apiXT/, ''),
+ },
'/api': {
target: VITE_APP_URL,
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, ''),
- }
+ },
+
},
},
assetsInclude: ['**/*.gltf','**/*.docx','**/*.pdf'],
--
Gitblit v1.9.3