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