From 6e88705bd5b443a259b24c17c8a299765d059d96 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Thu, 23 Jul 2026 16:50:41 +0800
Subject: [PATCH] Merge branch 'master' of http://139.196.74.78:10010/r/jagzwxm/ja_web

---
 applications/drone-command/src/utils/cesium/shapeTools/edit/EditEllipseTool.js                    |    3 
 applications/drone-command/src/views/areaManage/precinctInfo/index.vue                            |    2 
 applications/task-work-order/src/views/orderView/flyingHand/index.vue                             |    2 
 applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/index.vue              |    2 
 applications/task-work-order/src/views/orderView/appConfiguration/inventory/index.vue             |    2 
 applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/index.vue            |    3 
 applications/drone-command/src/styles/common/cockpit.scss                                         |   14 
 applications/drone-command/src/views/areaManage/areaStatistics/index.vue                          |    2 
 applications/drone-command/src/views/system/user/index.vue                                        |    2 
 applications/task-work-order/src/views/orderView/orderDataManage/appInnovation/index.vue          |    2 
 applications/mobile-web-view/vite.config.mjs                                                      |   15 
 applications/drone-command/src/assets/images/dataCenter/positionicon.png                          |    0 
 applications/drone-command/src/utils/cesium/shapeTools/draw/DrawRectangleTool.js                  |    3 
 applications/drone-command/src/views/system/helpCenter.vue                                        |    2 
 pnpm-lock.yaml                                                                                    |   16 
 applications/mobile-web-view/src/api/map/address.js                                               |    5 
 applications/mobile-web-view/src/axios.js                                                         |   26 
 applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue                 |    2 
 applications/drone-command/src/views/basicManage/deviceScrap/index.vue                            |    2 
 applications/drone-command/src/views/recordManage/historyTracks/TrajectoryDiaLog.vue              |  131 +++++
 applications/drone-command/src/assets/images/common/point.png                                     |    0 
 applications/drone-command/src/utils/cesium/shapeTools/edit/EditPolygonTool.js                    |    3 
 applications/task-work-order/src/api/documentPreview/index.js                                     |    9 
 applications/task-work-order/src/views/orderView/appConfiguration/process/index.vue               |    2 
 applications/drone-command/src/utils/cesium/shapeTools/draw/DrawBufferCircleTool.js               |    3 
 applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/FormDiaLog.vue     |   16 
 applications/drone-command/src/views/basicManage/maintainRecord/index.vue                         |    4 
 applications/task-work-order/src/views/orderView/organizational/agenciesManagement/index.vue      |    2 
 applications/task-work-order/src/views/orderView/orderDataManage/evaluate/index.vue               |    2 
 applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue                |   79 +++
 applications/task-work-order/src/views/orderView/organizational/roleMange/index.vue               |    2 
 applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue           |   31 +
 applications/drone-command/src/views/recordManage/historyTracks/index.vue                         |    2 
 applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/FormDiaLog.vue |    6 
 applications/task-work-order/src/views/documentPreview/index.vue                                  |  103 ++++
 applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue                       |   39 +
 AGENTS.md                                                                                         |   38 -
 applications/task-work-order/src/router/views/index.js                                            |   12 
 uniapps/work-wx/uploadCloudFunction.sh                                                            |    1 
 applications/mobile-web-view/src/axiosKY.js                                                       |  190 ++++++++
 applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue          |    2 
 applications/drone-command/src/views/areaManage/precinctInfo/FormDiaLog.vue                       |    5 
 applications/drone-command/src/views/audioCall.vue                                                |    3 
 applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue             |    2 
 applications/task-work-order/src/views/orderView/orderManage/inspectionReport/index.vue           |   96 +++
 pnpm-workspace.yaml                                                                               |    1 
 applications/drone-command/src/views/areaManage/sceneConfig/index.vue                             |    2 
 applications/task-work-order/src/views/system/helpCenter.vue                                      |    2 
 applications/drone-command/src/utils/cesium/shapeTools/draw/DrawEllipseTool.js                    |    3 
 applications/task-work-order/src/views/orderView/orderManage/orderManage/outcomeData.vue          |    2 
 uniapps/work-app/src/hooks/useGlobalWS.js                                                         |    3 
 applications/drone-command/src/components/map-container/common-cesium-map.vue                     |  306 +++++++++++++
 applications/drone-command/src/views/areaManage/sceneManage/index.vue                             |    2 
 applications/task-work-order/src/views/orderView/deviceInvocation/equipmentResource/index.vue     |    7 
 applications/drone-command/src/views/permissionManage/permissionRole/index.vue                    |    2 
 applications/mobile-web-view/env/.env                                                             |    7 
 applications/task-work-order/src/views/orderView/organizational/zoningManagement/index.vue        |    2 
 applications/drone-command/src/views/permissionManage/permissionDept/index.vue                    |    2 
 applications/drone-command/src/utils/cesium/shapeTools/draw/DrawPolygonTool.js                    |    3 
 applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue                          |    2 
 applications/drone-command/src/utils/cesium/shapeTools/edit/EditRectangleTool.js                  |    3 
 applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue                               |    3 
 applications/task-work-order/src/views/basicManage/maintainRecord/index.vue                       |    2 
 applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue            |    2 
 applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/index.vue      |    2 
 applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue            |    2 
 applications/drone-command/src/views/areaManage/defenseZone/index.vue                             |    2 
 applications/drone-command/src/views/permissionManage/permissionUser/index.vue                    |    2 
 applications/task-work-order/src/views/orderView/orderManage/orderManage/orderManageApi.js        |    2 
 applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/index.vue          |    2 
 applications/task-work-order/src/views/orderView/organizational/userMange/index.vue               |    2 
 applications/task-work-order/package.json                                                         |    1 
 applications/drone-command/src/assets/images/common/point-active.png                              |    0 
 applications/task-work-order/src/permission.js                                                    |   18 
 applications/drone-command/index.html                                                             |    4 
 applications/task-work-order/src/views/system/user/index.vue                                      |    2 
 applications/drone-command/src/views/aICrudTemplate/index.vue                                     |    2 
 applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue     |    2 
 applications/drone-command/src/views/areaManage/partition/index.vue                               |    2 
 applications/task-work-order/env/.env                                                             |    5 
 applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue                        |    4 
 applications/drone-command/src/views/basicManage/deviceStock/index.vue                            |   22 
 package.json                                                                                      |    3 
 applications/drone-command/src/utils/cesium/shapeTools/edit/EditBufferCircleTool.js               |    3 
 applications/task-work-order/src/views/orderView/appConfiguration/materials/index.vue             |    2 
 85 files changed, 1,158 insertions(+), 170 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index 5b6b1b9..a7e11dc 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -12,45 +12,13 @@
   - `uniapps/work-wx/`:使用 UniApp 开发的微信小程序。
 - 资源文件通常放在各应用内,具体入口以各应用的 `README.md` 为准。
 
-## 构建、测试与开发命令
-在仓库根目录使用 `pnpm`:
-- `pnpm install`:安装工作区依赖。
-- `pnpm dev`:并行启动所有工作区的开发服务。
-- `pnpm dev:drone-command`:启动单个应用。
-- `pnpm dev:mobile-web-view`:启动单个应用。
-- `pnpm dev:task-work-order`:启动单个应用。
-- `pnpm dev:work-app`:启动 UniApp H5 开发服务。
-- `pnpm dev:work-wx`:启动 UniApp H5 开发服务。
-- `pnpm build:test:<app>` / `pnpm build:prod:<app>`:构建指定应用,例如 `pnpm build:prod:mobile-web-view`。
-
 ## 编码风格与命名规范
 - 使用 Prettier 统一格式化(`.prettierrc.json`)。
-- 使用 Tab 缩进(`tabWidth: 2`, `useTabs: true`),`semi: false`,`singleQuote: true`。
 - SCSS 使用 `tabWidth: 4` 且双引号。
 - 文件与目录保持 kebabCase,遵循现有应用与包的命名风格。
 
-## 测试指南
-- 无需任何测试
-
-## 提交与合并请求规范
-- 提交历史使用简短的约定式主题(如 `feat: ...`)。
-- 建议使用 `feat:`、`fix:`、`chore:`、`refactor:` 等前缀并保持简洁描述。
-- PR 需要包含:目的、影响的应用/包、UI 改动截图。
-- 可关联相关 issue 或工单。
-
-## 环境与配置
-- Node.js >= 20,pnpm >= 9。
-- 优先使用根目录工作区脚本,除非必要不要在子目录直接运行脚本。
-
 # AI Rules / AI行为规范
-- 对低风险修改,AI可自主执行,无需批准。
-  AI may proceed autonomously for low-risk changes.
-- 仅当修改可能影响架构、核心模块、公共接口、数据结构或安全性时,才需要请求批准。
-  Ask for approval only for high-impact changes.
-- 若问题不影响系统正确性,应自行做出合理决策,而不是提问。
-  DO NOT ask questions that do not affect correctness.
-- 优先最小化修改范围。
-  Prefer minimal changes.
-- 未被明确要求时,禁止大规模重构。
-  Avoid large refactors unless requested.
+- 优先最小化修改范围
+- 未被明确要求时,禁止大规模重构
+- 每个方法前面加一行简短中文注释
 - 修改完不需要走打包编译校验
diff --git a/applications/drone-command/index.html b/applications/drone-command/index.html
index f676e39..2b8b39e 100644
--- a/applications/drone-command/index.html
+++ b/applications/drone-command/index.html
@@ -23,11 +23,11 @@
 	<!-- 高德地图api更新必须配合安全密钥使用 -->
 	<script>
 		window._AMapSecurityConfig = {
-			securityJsCode: '1cd61831ddce188f3129b761f57024fc',
+			securityJsCode: 'xxx',
 		}
 	</script>
 	<script type="text/javascript"
-					src='https://webapi.amap.com/maps?v=2.0&key=eb0654440644f710110547d2132b2fbe&plugin=AMap.PlaceSearch,AMap.Geocoder'></script>
+					src='https://webapi.amap.com/maps?v=2.0&key=xxx&plugin=AMap.PlaceSearch,AMap.Geocoder'></script>
 	<script src="https://webapi.amap.com/ui/1.1/main.js?v=1.0.11"></script>
 	<title>吉安市低空经济服务一体化平台</title>
 </head>
diff --git a/applications/drone-command/src/assets/images/common/point-active.png b/applications/drone-command/src/assets/images/common/point-active.png
new file mode 100644
index 0000000..c5869c7
--- /dev/null
+++ b/applications/drone-command/src/assets/images/common/point-active.png
Binary files differ
diff --git a/applications/drone-command/src/assets/images/common/point.png b/applications/drone-command/src/assets/images/common/point.png
new file mode 100644
index 0000000..9caf3bd
--- /dev/null
+++ b/applications/drone-command/src/assets/images/common/point.png
Binary files differ
diff --git a/applications/drone-command/src/assets/images/dataCenter/positionicon.png b/applications/drone-command/src/assets/images/dataCenter/positionicon.png
index b47c293..91b6ca1 100644
--- a/applications/drone-command/src/assets/images/dataCenter/positionicon.png
+++ b/applications/drone-command/src/assets/images/dataCenter/positionicon.png
Binary files differ
diff --git a/applications/drone-command/src/components/map-container/common-cesium-map.vue b/applications/drone-command/src/components/map-container/common-cesium-map.vue
index 33b95c8..f1c9be7 100644
--- a/applications/drone-command/src/components/map-container/common-cesium-map.vue
+++ b/applications/drone-command/src/components/map-container/common-cesium-map.vue
@@ -1,5 +1,42 @@
 <template>
-	<div :id="mapId" class="common-cesium-map" @contextmenu.prevent></div>
+	<div :id="mapId" class="common-cesium-map" @contextmenu.prevent>
+		<template v-if="props.list && props.list.length">
+			<div class="card">
+				<div class="timeline-prefix">
+					<slot name="timeline-prefix"></slot>
+				</div>
+				<div
+					ref="timelineRef"
+					class="card-content"
+					:class="{ 'is-dragging': timelineDragging }"
+					@mousedown="handleTimelineMouseDown"
+					@mousemove="handleTimelineMouseMove"
+					@mouseup="stopTimelineDrag"
+					@mouseleave="stopTimelineDrag"
+				>
+					<div class="timeline-track">
+						<div class="time-line"></div>
+						<div
+							class="card-item"
+							v-for="(item, index) in props.list"
+							@click="handleTimelineItemClick(item, index)"
+						>
+							<div class="time-point">
+								<img
+									class="active"
+									v-if="index === selectedImgIndex"
+									src="@/assets/images/common/point-active.png"
+									alt=""
+								/>
+								<img v-else src="@/assets/images/common/point.png" alt="" />
+							</div>
+							<div class="time-bottom">{{ item.createTime.slice(11) }}</div>
+						</div>
+					</div>
+				</div>
+			</div>
+		</template>
+	</div>
 </template>
 
 <script setup>
@@ -8,6 +45,7 @@
 import { onBeforeUnmount, onMounted, watch } from 'vue'
 import { PublicCesium } from '@/utils/cesium/publicCesium'
 import { loadJaAdminBoundary, removeJaAdminBoundary } from '@/utils/cesium/adminBoundary'
+import positionIcon from '@/assets/images/dataCenter/positionicon.png'
 
 const props = defineProps({
 	active: {
@@ -58,10 +96,19 @@
 		type: Number,
 		default: 10000,
 	},
+	list: {
+		type: Array,
+		default: () => [],
+	},
 })
 
-const emit = defineEmits(['ready', 'height-change', 'stage-change'])
+const emit = defineEmits(['ready', 'height-change', 'stage-change', 'point-change'])
 const mapId = props.domId || `common-cesium-map-${Math.random().toString(36).slice(2, 10)}`
+const timelineRef = ref(null)
+const timelineDragging = ref(false)
+let timelineStartX = 0
+let timelineStartScrollLeft = 0
+let timelineDidDrag = false
 let viewInstance = null
 let viewer = null
 const ADMIN_BOUNDARY_NAMES = {
@@ -108,7 +155,142 @@
 		removeCameraListener = () => viewer?.camera?.changed?.removeEventListener(onCameraChanged)
 	}
 	emit('ready', { viewer, publicCesium: viewInstance })
+	// 地图就绪时,若列表已加载则默认标记选中项(首个)
+	showSelectedMarker()
 }
+
+const selectedImgIndex = ref(0)
+// 航线高度(与 TrajectoryDiaLog 里 MOCK_FLIGHT_HEIGHT 保持一致),让标记悬浮在轨迹线上
+const FLIGHT_HEIGHT = 120
+const POSITION_MOVE_DURATION = 1000
+// 当前经纬度位置标记
+let positionEntity = null
+let positionAnimationFrame = null
+
+// 停止位置图标移动动画
+const stopPositionAnimation = () => {
+	if (positionAnimationFrame !== null) {
+		cancelAnimationFrame(positionAnimationFrame)
+		positionAnimationFrame = null
+	}
+}
+
+// 平滑移动位置图标
+const animatePositionMarker = (targetPosition, duration) => {
+	const currentPosition = positionEntity?.position?.getValue(viewer.clock.currentTime, new Cesium.Cartesian3())
+	if (!currentPosition) {
+		positionEntity.position = targetPosition
+		return
+	}
+	stopPositionAnimation()
+	const startTime = performance.now()
+	const nextPosition = new Cesium.Cartesian3()
+
+	// 更新位置图标移动进度
+	const updatePosition = currentTime => {
+		const progress = Math.min((currentTime - startTime) / duration, 1)
+		Cesium.Cartesian3.lerp(currentPosition, targetPosition, progress, nextPosition)
+		positionEntity.position.setValue(nextPosition)
+		viewer.scene.requestRender()
+		if (progress < 1) {
+			positionAnimationFrame = requestAnimationFrame(updatePosition)
+		} else {
+			positionAnimationFrame = null
+		}
+	}
+	positionAnimationFrame = requestAnimationFrame(updatePosition)
+}
+
+// 点击周期
+const clickWeekTime = (item, index, options = {}) => {
+	// clickImgSrc.value = item.url
+	selectedImgIndex.value = index
+	showPositionMarker(item, options)
+	// 通知父组件当前选中的轨迹点,用于右侧表格同步高亮
+	emit('point-change', { item, index })
+}
+
+// 开始拖动时间轴
+const handleTimelineMouseDown = event => {
+	if (event.button !== 0) return
+	timelineDragging.value = true
+	timelineDidDrag = false
+	timelineStartX = event.clientX
+	timelineStartScrollLeft = timelineRef.value?.scrollLeft ?? 0
+}
+
+// 横向拖动时间轴
+const handleTimelineMouseMove = event => {
+	if (!timelineDragging.value || !timelineRef.value) return
+	const offsetX = event.clientX - timelineStartX
+	if (Math.abs(offsetX) > 3) timelineDidDrag = true
+	if (!timelineDidDrag) return
+	timelineRef.value.scrollLeft = timelineStartScrollLeft - offsetX
+	event.preventDefault()
+}
+
+// 停止拖动时间轴
+const stopTimelineDrag = () => {
+	timelineDragging.value = false
+	setTimeout(() => {
+		timelineDidDrag = false
+	}, 0)
+}
+
+// 点击时间轴节点
+const handleTimelineItemClick = (item, index) => {
+	if (timelineDidDrag) return
+	clickWeekTime(item, index)
+}
+
+// 在地图上通过经纬度显示位置图标
+const showPositionMarker = (item, { animate = false, duration = POSITION_MOVE_DURATION } = {}) => {
+	if (!viewer) return
+	const longitude = Number(item?.longitude)
+	const latitude = Number(item?.latitude)
+	if (Number.isNaN(longitude) || Number.isNaN(latitude)) return
+
+	// 与航线相同的高度,让标记悬浮在轨迹线上,而不是贴地
+	const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, FLIGHT_HEIGHT)
+	if (positionEntity) {
+		if (animate) {
+			animatePositionMarker(position, duration)
+		} else {
+			stopPositionAnimation()
+			positionEntity.position = position
+		}
+	} else {
+		positionEntity = viewer.entities.add({
+			position,
+			billboard: {
+				image: positionIcon,
+				width: 36,
+				height: 36,
+				verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+				disableDepthTestDistance: Number.POSITIVE_INFINITY,
+			},
+		})
+	}
+}
+
+// 显示当前选中项的标记(默认首个),地图就绪和列表加载后都会调用
+const showSelectedMarker = () => {
+	const item = props.list?.[selectedImgIndex.value]
+	if (item) showPositionMarker(item)
+}
+
+// 列表数据到位后,默认选中并标记首个点
+watch(
+	() => props.list,
+	list => {
+		if (list && list.length) {
+			selectedImgIndex.value = 0
+			showSelectedMarker()
+			// 默认选中首个,同步通知父组件高亮表格首行
+			emit('point-change', { item: list[0], index: 0 })
+		}
+	}
+)
 
 watch(
 	() => props.active,
@@ -122,9 +304,11 @@
 })
 
 onBeforeUnmount(() => {
+	stopPositionAnimation()
 	if (removeCameraListener) removeCameraListener()
 	removeJaAdminBoundary(viewer, adminBoundarySources)
 	adminBoundarySources = null
+	positionEntity = null
 	viewInstance?.viewerDestroy?.()
 })
 
@@ -216,12 +400,128 @@
 	})
 }
 
-defineExpose({ getMap, getViewer, getPublicCesium, flyToPoint, setAdminBoundaryVisible, zoomToAdminBoundary })
+defineExpose({ getMap, getViewer, getPublicCesium, flyToPoint, clickWeekTime, setAdminBoundaryVisible, zoomToAdminBoundary })
 </script>
 
 <style scoped lang="scss">
 .common-cesium-map {
 	width: 100%;
 	height: 100%;
+	position: relative;
+	.card {
+		position: absolute;
+		bottom: 0px;
+		width: 100%;
+		height: 67px;
+		box-sizing: border-box;
+		background: rgba(0, 0, 0, 0.42);
+		border-radius: 0;
+
+		color: #d5d5d5;
+		font-size: 14px;
+
+		.timeline-prefix {
+			position: absolute;
+			left: 7.5%;
+			top: 50%;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			z-index: 2;
+			transform: translate(-50%, -50%);
+		}
+
+		.card-content {
+			display: flex;
+			position: absolute;
+			left: 15%;
+			width: 70%;
+			height: 100%;
+			overflow-x: auto;
+			overflow-y: hidden;
+			white-space: nowrap;
+			cursor: grab;
+			scrollbar-width: none;
+
+			&::-webkit-scrollbar {
+				display: none;
+			}
+
+			&.is-dragging {
+				cursor: grabbing;
+				user-select: none;
+			}
+
+			.timeline-track {
+				position: relative;
+				display: flex;
+				flex: 0 0 auto;
+				height: 100%;
+				margin: 0 auto;
+			}
+
+			.card-item {
+				position: relative;
+				flex: 0 0 82px;
+				width: 82px;
+				text-align: center;
+				cursor: pointer;
+			}
+
+			&.is-dragging .card-item {
+				cursor: grabbing;
+			}
+
+			.time-top {
+				margin-top: 10px;
+				line-height: 1;
+				text-align: center;
+				cursor: pointer;
+			}
+
+			.active {
+				font-weight: 400;
+				color: #ffffff;
+			}
+
+			.time-point {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				position: absolute;
+				top: 22px;
+				left: 50%;
+				width: 18px;
+				height: 18px;
+				z-index: 1;
+				transform: translate(-50%, 0);
+
+				img {
+					width: 11.2px;
+					height: 11.2px;
+				}
+
+				img.active {
+					width: 16.89px;
+					height: 16.89px;
+				}
+			}
+
+			.time-bottom {
+				margin-top: 44px;
+			}
+
+			.time-line {
+				position: absolute;
+				left: 41px;
+				right: 41px;
+				bottom: 36px;
+				height: 1px;
+				background: rgba(237, 237, 237, 0.6);
+				z-index: 0;
+				pointer-events: none;
+			}
+		}
+	}
 }
 </style>
diff --git a/applications/drone-command/src/styles/common/cockpit.scss b/applications/drone-command/src/styles/common/cockpit.scss
index 561ae84..cd6119c 100644
--- a/applications/drone-command/src/styles/common/cockpit.scss
+++ b/applications/drone-command/src/styles/common/cockpit.scss
@@ -1139,8 +1139,10 @@
         }
     }
 
-    th.el-table__cell:not(.fixed-column),
-    td.el-table__cell:not(.fixed-column) {
+    // 注意:Element Plus 2.9.11 固定列类名为 el-table-fixed-column--left/right,
+    // 老的 .fixed-column 已不存在,这里需一并排除,否则固定列会被刷成透明
+    th.el-table__cell:not(.fixed-column):not(.el-table-fixed-column--left):not(.el-table-fixed-column--right),
+    td.el-table__cell:not(.fixed-column):not(.el-table-fixed-column--left):not(.el-table-fixed-column--right) {
         background: transparent !important;
     }
 
@@ -1182,7 +1184,9 @@
         }
     }
 
-    .fixed-column {
+    .fixed-column,
+    .el-table-fixed-column--left,
+    .el-table-fixed-column--right {
         background-color: #1A1A2A !important;
     }
 }
@@ -1781,7 +1785,7 @@
                             align-items: center;
 
                             .label {
-                                width: 96px;
+                                min-width: 96px;
                                 font-family: Source Han Sans CN, Source Han Sans CN;
                                 font-weight: 500;
                                 font-size: 14px;
@@ -1965,7 +1969,7 @@
                                 justify-content: flex-end;
 
                                 padding-right: 12px;
-                                width: 96px;
+                                min-width: 96px;
 
                                 font-family: Source Han Sans CN, Source Han Sans CN;
                                 font-weight: 500;
diff --git a/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawBufferCircleTool.js b/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawBufferCircleTool.js
index 0198cf6..2f309bd 100644
--- a/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawBufferCircleTool.js
+++ b/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawBufferCircleTool.js
@@ -242,7 +242,8 @@
 
 	getPositionFromScreen(screenPosition) {
 		const scene = this.viewer.scene
-		const cartesian = scene.pickPosition(screenPosition)
+		const ray = scene.camera.getPickRay(screenPosition)
+		const cartesian = ray ? scene.globe.pick(ray, scene) : null
 		if (cartesian) return cartesian
 		return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
 	}
diff --git a/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawEllipseTool.js b/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawEllipseTool.js
index 6811412..3babb9b 100644
--- a/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawEllipseTool.js
+++ b/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawEllipseTool.js
@@ -144,7 +144,8 @@
 
 	getPositionFromScreen(screenPosition) {
 		const scene = this.viewer.scene
-		const cartesian = scene.pickPosition(screenPosition)
+		const ray = scene.camera.getPickRay(screenPosition)
+		const cartesian = ray ? scene.globe.pick(ray, scene) : null
 		if (cartesian) return cartesian
 		return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
 	}
diff --git a/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawPolygonTool.js b/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawPolygonTool.js
index 207ad4e..1a9c489 100644
--- a/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawPolygonTool.js
+++ b/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawPolygonTool.js
@@ -313,7 +313,8 @@
 
 	getPositionFromScreen(screenPosition) {
 		const scene = this.viewer.scene
-		const cartesian = scene.pickPosition(screenPosition)
+		const ray = scene.camera.getPickRay(screenPosition)
+		const cartesian = ray ? scene.globe.pick(ray, scene) : null
 		if (cartesian) return cartesian
 		return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
 	}
diff --git a/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawRectangleTool.js b/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawRectangleTool.js
index 8d9d03c..a5686a9 100644
--- a/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawRectangleTool.js
+++ b/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawRectangleTool.js
@@ -117,7 +117,8 @@
 
 	getPositionFromScreen(screenPosition) {
 		const scene = this.viewer.scene
-		const cartesian = scene.pickPosition(screenPosition)
+		const ray = scene.camera.getPickRay(screenPosition)
+		const cartesian = ray ? scene.globe.pick(ray, scene) : null
 		if (cartesian) return cartesian
 		return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
 	}
diff --git a/applications/drone-command/src/utils/cesium/shapeTools/edit/EditBufferCircleTool.js b/applications/drone-command/src/utils/cesium/shapeTools/edit/EditBufferCircleTool.js
index 8f77483..450d6e4 100644
--- a/applications/drone-command/src/utils/cesium/shapeTools/edit/EditBufferCircleTool.js
+++ b/applications/drone-command/src/utils/cesium/shapeTools/edit/EditBufferCircleTool.js
@@ -334,7 +334,8 @@
 
 	getPositionFromScreen(screenPosition) {
 		const scene = this.viewer.scene
-		const cartesian = scene.pickPosition(screenPosition)
+		const ray = scene.camera.getPickRay(screenPosition)
+		const cartesian = ray ? scene.globe.pick(ray, scene) : null
 		if (cartesian) return cartesian
 		return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
 	}
diff --git a/applications/drone-command/src/utils/cesium/shapeTools/edit/EditEllipseTool.js b/applications/drone-command/src/utils/cesium/shapeTools/edit/EditEllipseTool.js
index e548b93..1a8ad67 100644
--- a/applications/drone-command/src/utils/cesium/shapeTools/edit/EditEllipseTool.js
+++ b/applications/drone-command/src/utils/cesium/shapeTools/edit/EditEllipseTool.js
@@ -255,7 +255,8 @@
 
 	getPositionFromScreen(screenPosition) {
 		const scene = this.viewer.scene
-		const cartesian = scene.pickPosition(screenPosition)
+		const ray = scene.camera.getPickRay(screenPosition)
+		const cartesian = ray ? scene.globe.pick(ray, scene) : null
 		if (cartesian) return cartesian
 		return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
 	}
diff --git a/applications/drone-command/src/utils/cesium/shapeTools/edit/EditPolygonTool.js b/applications/drone-command/src/utils/cesium/shapeTools/edit/EditPolygonTool.js
index 7d0bf60..46da9c5 100644
--- a/applications/drone-command/src/utils/cesium/shapeTools/edit/EditPolygonTool.js
+++ b/applications/drone-command/src/utils/cesium/shapeTools/edit/EditPolygonTool.js
@@ -284,7 +284,8 @@
 
 	getPositionFromScreen(screenPosition) {
 		const scene = this.viewer.scene
-		const cartesian = scene.pickPosition(screenPosition)
+		const ray = scene.camera.getPickRay(screenPosition)
+		const cartesian = ray ? scene.globe.pick(ray, scene) : null
 		if (cartesian) return cartesian
 		return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
 	}
diff --git a/applications/drone-command/src/utils/cesium/shapeTools/edit/EditRectangleTool.js b/applications/drone-command/src/utils/cesium/shapeTools/edit/EditRectangleTool.js
index d76693a..1593356 100644
--- a/applications/drone-command/src/utils/cesium/shapeTools/edit/EditRectangleTool.js
+++ b/applications/drone-command/src/utils/cesium/shapeTools/edit/EditRectangleTool.js
@@ -149,7 +149,8 @@
 
 	getPositionFromScreen(screenPosition) {
 		const scene = this.viewer.scene
-		const cartesian = scene.pickPosition(screenPosition)
+		const ray = scene.camera.getPickRay(screenPosition)
+		const cartesian = ray ? scene.globe.pick(ray, scene) : null
 		if (cartesian) return cartesian
 		return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
 	}
diff --git a/applications/drone-command/src/views/aICrudTemplate/index.vue b/applications/drone-command/src/views/aICrudTemplate/index.vue
index 8394999..3d5d640 100644
--- a/applications/drone-command/src/views/aICrudTemplate/index.vue
+++ b/applications/drone-command/src/views/aICrudTemplate/index.vue
@@ -52,7 +52,7 @@
 			</el-table-column>
 			<el-table-column prop="deviceModel" label="设备型号" />
 			<el-table-column prop="deviceSpecification" label="规格" />
-			<el-table-column label="操作">
+			<el-table-column label="操作" fixed="right">
 				<template v-slot="{ row }">
 					<el-link @click="openForm('view', row)" type="primary">查看</el-link>
 					<el-link @click="openForm('edit', row)" type="warning">编辑</el-link>
diff --git a/applications/drone-command/src/views/areaManage/areaStatistics/index.vue b/applications/drone-command/src/views/areaManage/areaStatistics/index.vue
index e493c7b..7b82b63 100644
--- a/applications/drone-command/src/views/areaManage/areaStatistics/index.vue
+++ b/applications/drone-command/src/views/areaManage/areaStatistics/index.vue
@@ -49,7 +49,7 @@
 					<el-table-column prop="counterCount" show-overflow-tooltip label="侦测反制次数" />
 					<el-table-column prop="counterSuccessCount" show-overflow-tooltip label="反制成功次数" />
 					<el-table-column prop="controlEffect" show-overflow-tooltip label="管控效果" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="openForm(row)">查看</el-link>
 						</template>
diff --git a/applications/drone-command/src/views/areaManage/defenseZone/index.vue b/applications/drone-command/src/views/areaManage/defenseZone/index.vue
index 242cb96..d10550a 100644
--- a/applications/drone-command/src/views/areaManage/defenseZone/index.vue
+++ b/applications/drone-command/src/views/areaManage/defenseZone/index.vue
@@ -27,7 +27,7 @@
 					<el-table-column prop="sceneCount" show-overflow-tooltip label="场景数量" />
 					<el-table-column prop="areaCount" show-overflow-tooltip label="区域数量" />
 					<el-table-column prop="deviceCount" show-overflow-tooltip label="设备数量" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="openForm('view', row)">查看</el-link>
 							<el-link @click="openForm('edit', row)">编辑</el-link>
diff --git a/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue b/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
index 98f279e..ec42046 100644
--- a/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
+++ b/applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
@@ -180,7 +180,7 @@
 									{{ drawTypeLabelMap[row.drawType] || '-' }}
 								</template>
 							</el-table-column>
-							<el-table-column label="操作" class-name="operation-btns" width="120">
+							<el-table-column label="操作" class-name="operation-btns" fixed="right" width="120">
 								<template v-slot="{ row }">
 									<el-link @click="handleShapeEdit(row)">编辑</el-link>
 									<el-link @click="handleShapeDelete(row)">删除</el-link>
diff --git a/applications/drone-command/src/views/areaManage/partition/index.vue b/applications/drone-command/src/views/areaManage/partition/index.vue
index 9f81fd7..25fd628 100644
--- a/applications/drone-command/src/views/areaManage/partition/index.vue
+++ b/applications/drone-command/src/views/areaManage/partition/index.vue
@@ -52,7 +52,7 @@
 							{{ formatFlyDate(row) }}
 						</template>
 					</el-table-column>
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="openForm('view', row)">查看</el-link>
 							<el-link @click="openForm('edit', row)">编辑</el-link>
diff --git a/applications/drone-command/src/views/areaManage/precinctInfo/FormDiaLog.vue b/applications/drone-command/src/views/areaManage/precinctInfo/FormDiaLog.vue
index 88f41ae..ca898ba 100644
--- a/applications/drone-command/src/views/areaManage/precinctInfo/FormDiaLog.vue
+++ b/applications/drone-command/src/views/areaManage/precinctInfo/FormDiaLog.vue
@@ -264,6 +264,11 @@
 		redPointEntity.position = Cesium.Cartesian3.fromDegrees(longitude, latitude)
 		redPointEntity.label.text = `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`
 	}
+	// 打开弹窗回显时,相机定位到该经纬度(2000m 视高,瞬间定位)
+	viewer.camera.flyTo({
+		destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, 30000),
+		duration: 0,
+	})
 }
 
 function formatCoord(value) {
diff --git a/applications/drone-command/src/views/areaManage/precinctInfo/index.vue b/applications/drone-command/src/views/areaManage/precinctInfo/index.vue
index 439956a..a76b9e9 100644
--- a/applications/drone-command/src/views/areaManage/precinctInfo/index.vue
+++ b/applications/drone-command/src/views/areaManage/precinctInfo/index.vue
@@ -28,7 +28,7 @@
 					<el-table-column prop="latitude" show-overflow-tooltip label="纬度" />
 					<el-table-column prop="contactPerson" show-overflow-tooltip label="联系人" />
 					<el-table-column prop="contactPhone" show-overflow-tooltip label="联系方式" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="openForm('edit', row)">编辑</el-link>
 							<el-link @click="handleDelete(row)">删除</el-link>
diff --git a/applications/drone-command/src/views/areaManage/sceneConfig/index.vue b/applications/drone-command/src/views/areaManage/sceneConfig/index.vue
index 0f874ae..0b407b4 100644
--- a/applications/drone-command/src/views/areaManage/sceneConfig/index.vue
+++ b/applications/drone-command/src/views/areaManage/sceneConfig/index.vue
@@ -55,7 +55,7 @@
 					<el-table-column prop="areaCount" show-overflow-tooltip label="区域数量" />
 					<el-table-column prop="counterDeviceCount" show-overflow-tooltip label="反制设备数量" />
 					<el-table-column prop="detectDeviceCount" show-overflow-tooltip label="侦测设备数量" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="openForm('view', row)">查看</el-link>
 							<el-link @click="openForm('edit', row)">编辑</el-link>
diff --git a/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue b/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue
index da93c62..67a6362 100644
--- a/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue
+++ b/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue
@@ -146,7 +146,7 @@
 import { ElMessage } from 'element-plus'
 import { fwDefenseSceneManageDetailApi, fwDefenseSceneManageSubmitApi } from './sceneManageApi'
 import { fwDefenseSceneListApi } from '../sceneConfig/sceneConfigApi'
-import { fieldRules } from '@ztzf/utils'
+import { fieldRules, contactPhoneRules } from '@ztzf/utils'
 import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue'
 import * as Cesium from 'cesium'
 import commandPost from '@/assets/images/dataCockpit/legend/command-post.png'
@@ -213,7 +213,7 @@
 const rules = {
 	sceneName: fieldRules(true, 50),
 	defenseLeader: fieldRules(true, 50),
-	leaderPhone: fieldRules(true, 50),
+	leaderPhone: contactPhoneRules(true, 50),
 	effectiveDateStart: fieldRules(true),
 	longitude: fieldRules(true),
 	defenseSceneId: fieldRules(true),
diff --git a/applications/drone-command/src/views/areaManage/sceneManage/index.vue b/applications/drone-command/src/views/areaManage/sceneManage/index.vue
index f9f4689..8bcf04d 100644
--- a/applications/drone-command/src/views/areaManage/sceneManage/index.vue
+++ b/applications/drone-command/src/views/areaManage/sceneManage/index.vue
@@ -42,7 +42,7 @@
 						</template>
 					</el-table-column>
 					<el-table-column prop="defenseSceneName" show-overflow-tooltip label="关联场景配置" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="openForm('view', row)">查看</el-link>
 							<el-link @click="openForm('edit', row)">编辑</el-link>
diff --git a/applications/drone-command/src/views/audioCall.vue b/applications/drone-command/src/views/audioCall.vue
index bedcfba..b86e777 100644
--- a/applications/drone-command/src/views/audioCall.vue
+++ b/applications/drone-command/src/views/audioCall.vue
@@ -36,7 +36,8 @@
 import { ref, computed, onBeforeUnmount } from 'vue'
 
 /** ✅ 你的 WS 地址前缀(后面拼 userId) */
-const WS_BASE = 'ws://218.202.104.82:38201/ws/chat'
+// const WS_BASE = 'ws://218.202.104.82:38201/ws/chat'
+const WS_BASE = 'ws://220.177.172.27:8100/webrtc/ws/chat'
 
 const uid = ref('2021474568497131521')
 const peerUid = ref('2021474815063486465')
diff --git a/applications/drone-command/src/views/basicManage/deviceScrap/index.vue b/applications/drone-command/src/views/basicManage/deviceScrap/index.vue
index cf1553e..d2ff2f9 100644
--- a/applications/drone-command/src/views/basicManage/deviceScrap/index.vue
+++ b/applications/drone-command/src/views/basicManage/deviceScrap/index.vue
@@ -76,7 +76,7 @@
 					</el-table-column>
 					<el-table-column prop="scrapReason" show-overflow-tooltip label="报废原因" />
 					<el-table-column prop="disposeWay" show-overflow-tooltip label="处置方式" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="handleView(row)">查看</el-link>
 						</template>
diff --git a/applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue b/applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue
index 2240b15..e835248 100644
--- a/applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue
+++ b/applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue
@@ -45,6 +45,14 @@
 					<div class="val">{{ formData.belongDeptName }}</div>
 				</el-col>
 				<el-col :span="12">
+					<div class="label">开始使用日期</div>
+					<div class="val">{{ formData.useDate }}</div>
+				</el-col>
+				<el-col :span="12">
+					<div class="label">使用年限</div>
+					<div class="val">{{ formData.serviceLife }}</div>
+				</el-col>
+				<el-col :span="12">
 					<div class="label">负责人</div>
 					<div class="val">{{ formData.charger }}</div>
 				</el-col>
@@ -80,7 +88,7 @@
 			</div>
 		</div>
 
-		<el-form class="dialog-form" v-else ref="formRef" :model="formData" :rules="rules" label-width="100px">
+		<el-form class="dialog-form" v-else ref="formRef" :model="formData" :rules="rules" label-width="120px">
 			<el-row>
 				<el-col :span="12">
 					<el-form-item label="设备名称" prop="deviceName">
@@ -147,6 +155,33 @@
 						<el-tree-select class="command-select" popper-class="command-tree-select-popper"
 							v-model="formData.belongDept" node-key="id" :data="deptTree" :props="treeProps"
 							check-strictly @change="belongDeptChange" clearable />
+					</el-form-item>
+				</el-col>
+				<el-col :span="12">
+					<el-form-item label="开始使用日期" prop="useDate">
+						<el-date-picker class="command-date-picker" popper-class="command-date-picker-popper"
+							v-model="formData.useDate"
+							type="date"
+							placeholder="选择日期"
+							value-format="YYYY-MM-DD"
+							clearable
+						/>
+					</el-form-item>
+				</el-col>
+				<el-col :span="12">
+					<el-form-item label="使用年限" prop="serviceLife">
+						 <el-input-number
+							class="command-input"
+							v-model="formData.serviceLife"
+							:min="0"
+							:max="100"
+							:precision="0"
+							:step="1"
+							step-strictly
+							:controls="false"
+							placeholder="请输入"
+							@keydown="e => ['.', 'e', 'E', '+', '-'].includes(e.key) && e.preventDefault()"
+						/>
 					</el-form-item>
 				</el-col>
 				<el-col :span="12">
@@ -246,6 +281,8 @@
 	belongDept: fieldRules(true),
 	contactPhone: contactPhoneRules(true, 50),
 	charger: fieldRules(true),
+	serviceLife: fieldRules(true),
+	useDate: fieldRules(true),
 }
 
 const userList = ref([])
diff --git a/applications/drone-command/src/views/basicManage/deviceStock/index.vue b/applications/drone-command/src/views/basicManage/deviceStock/index.vue
index 2b49523..8fd28ee 100644
--- a/applications/drone-command/src/views/basicManage/deviceStock/index.vue
+++ b/applications/drone-command/src/views/basicManage/deviceStock/index.vue
@@ -1,9 +1,9 @@
 <template>
 	<basic-container>
 		<div class="chart">
-			<DeviceChart1 :key="updateKey"/>
-			<DeviceChart2 :key="updateKey"/>
-			<DeviceChart3 :key="updateKey"/>
+			<DeviceChart1 :key="updateKey" />
+			<DeviceChart2 :key="updateKey" />
+			<DeviceChart3 :key="updateKey" />
 		</div>
 
 		<el-form ref="queryParamsRef" :model="searchParams" class="command-page-history-search">
@@ -91,7 +91,14 @@
 							{{ getDictLabel(row.trackStatus, trackStatusOptions) }}
 						</template>
 					</el-table-column>
-					<el-table-column label="操作" class-name="operation-btns" width="196">
+					<el-table-column prop="maintenanceStatus" show-overflow-tooltip width="96" label="报废预警">
+						<template v-slot="{ row }">
+							<span :style="{ color: row.maintenanceStatus === 0 ? 'inherit' : 'red' }">
+								{{ row.maintenanceStatus === 0 ? '正常' : '临近报废' }}
+							</span>
+						</template>
+					</el-table-column>
+					<el-table-column label="操作" class-name="operation-btns" width="196" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="handleView(row)">查看</el-link>
 							<el-link @click="handleEdit(row)">编辑</el-link>
@@ -172,7 +179,7 @@
 // 出库状态
 const trackStatusOptions = ref([
 	{ dictKey: 0, dictValue: '未出库' },
-	{ dictKey: 1, dictValue: '已出库' }
+	{ dictKey: 1, dictValue: '已出库' },
 ])
 
 const updateKey = ref(0)
@@ -232,7 +239,7 @@
 		cancelButtonClass: 'command-message-box-cancel',
 	})
 	const payload = {
-		deviceId: row.id
+		deviceId: row.id,
 	}
 	await fwDeviceUpdateTrackStatusApi(payload)
 	ElMessage.success('归还成功')
@@ -341,4 +348,7 @@
 		}
 	}
 }
+.danger-text {
+	color: red; /* 或者直接用 red */
+}
 </style>
diff --git a/applications/drone-command/src/views/basicManage/maintainRecord/index.vue b/applications/drone-command/src/views/basicManage/maintainRecord/index.vue
index 2d9c4eb..848b7ee 100644
--- a/applications/drone-command/src/views/basicManage/maintainRecord/index.vue
+++ b/applications/drone-command/src/views/basicManage/maintainRecord/index.vue
@@ -47,7 +47,7 @@
 					<el-table-column prop="charger" show-overflow-tooltip label="负责人" />
 					<el-table-column prop="maintainStatus" show-overflow-tooltip label="维护提醒">
 						<template v-slot="{ row }">
-							{{ row.maintainStatus === 1 ? '已维修' : '未维修' }}
+							{{ row.maintainStatus === 1 ? '已维护' : '未维护' }}
 						</template>
 					</el-table-column>
 					<el-table-column prop="planCycleType" show-overflow-tooltip label="维护计划">
@@ -55,7 +55,7 @@
 							{{ getPlanCycleLabel(row) }}
 						</template>
 					</el-table-column>
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="handleView(row)">查看</el-link>
 							<el-link @click="maintenance(row)">维护</el-link>
diff --git a/applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue b/applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue
index 34735d3..e049ae3 100644
--- a/applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue
+++ b/applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue
@@ -65,7 +65,7 @@
 							{{ formatDeviceCode(row) }}
 						</template>
 					</el-table-column>
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="handleView(row)">查看</el-link>
 							<el-link @click="handleEdit(row)">编辑</el-link>
diff --git a/applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/index.vue b/applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/index.vue
index c5635fb..72dce3d 100644
--- a/applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/index.vue
+++ b/applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/index.vue
@@ -78,7 +78,7 @@
 					<el-table-column prop="manufacturer" show-overflow-tooltip label="厂商" />
 					<el-table-column prop="contactPhone" show-overflow-tooltip width="112" label="联系方式" />
 					<el-table-column prop="sceneName" show-overflow-tooltip label="所属场景" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="openForm('edit', row)" type="warning">配置接口</el-link>
 						</template>
@@ -127,6 +127,7 @@
 	status: '', // 设备状态
 	current: 1, // 当前页
 	size: 10, // 每页大小
+	trackStatus: 1, // 轨迹状态
 })
 
 const searchParams = ref(initSearchParams()) // 查询参数
diff --git a/applications/drone-command/src/views/permissionManage/permissionDept/index.vue b/applications/drone-command/src/views/permissionManage/permissionDept/index.vue
index 8ece0a6..a7def46 100644
--- a/applications/drone-command/src/views/permissionManage/permissionDept/index.vue
+++ b/applications/drone-command/src/views/permissionManage/permissionDept/index.vue
@@ -64,7 +64,7 @@
 					<el-table-column prop="bingId" show-overflow-tooltip width="80" label="组织id" />
 					<el-table-column prop="areaName" show-overflow-tooltip label="行政区划" />
 
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="handleView(row)">查看</el-link>
 							<el-link v-if="permission.permissionDept_edit" @click="handleEdit(row)">编辑</el-link>
diff --git a/applications/drone-command/src/views/permissionManage/permissionRole/index.vue b/applications/drone-command/src/views/permissionManage/permissionRole/index.vue
index 935e95b..19e7a91 100644
--- a/applications/drone-command/src/views/permissionManage/permissionRole/index.vue
+++ b/applications/drone-command/src/views/permissionManage/permissionRole/index.vue
@@ -57,7 +57,7 @@
 					<el-table-column prop="roleName" show-overflow-tooltip label="角色名称" />
 					<el-table-column prop="roleAlias" show-overflow-tooltip label="角色别名" />
 					<el-table-column prop="sort" show-overflow-tooltip label="角色排序" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="handleView(row)">查看</el-link>
 							<el-link @click="handleEdit(row)">编辑</el-link>
diff --git a/applications/drone-command/src/views/permissionManage/permissionUser/index.vue b/applications/drone-command/src/views/permissionManage/permissionUser/index.vue
index 6ecdbb6..e364de9 100644
--- a/applications/drone-command/src/views/permissionManage/permissionUser/index.vue
+++ b/applications/drone-command/src/views/permissionManage/permissionUser/index.vue
@@ -67,7 +67,7 @@
 					<el-table-column prop="roleName" show-overflow-tooltip label="所属角色" />
 					<el-table-column prop="deptName" show-overflow-tooltip label="所属部门" />
 					<el-table-column prop="phone" show-overflow-tooltip width="120" label="手机号" />
-					<el-table-column label="操作" class-name="operation-btns" width="180">
+					<el-table-column label="操作" class-name="operation-btns" width="180" fixed="right">
 						<template v-slot="{ row }">
 							<el-link  @click="handleView(row)">查看</el-link>
 							<el-link v-if="permission.permissionUser_edit" @click="handleEdit(row)">编辑</el-link>
diff --git a/applications/drone-command/src/views/recordManage/historyTracks/TrajectoryDiaLog.vue b/applications/drone-command/src/views/recordManage/historyTracks/TrajectoryDiaLog.vue
index 146f0ab..c9a7ef1 100644
--- a/applications/drone-command/src/views/recordManage/historyTracks/TrajectoryDiaLog.vue
+++ b/applications/drone-command/src/views/recordManage/historyTracks/TrajectoryDiaLog.vue
@@ -17,7 +17,16 @@
 					:terrain="true"
 					:layer-mode="4"
 					:boundary="false"
-				/>
+					:list="list"
+					@point-change="handlePointChange"
+				>
+					<template #timeline-prefix>
+						<el-icon class="track-play-btn" :size="30" @click.stop="handlePlayClick">
+							<VideoPause v-if="isPlaying" />
+							<VideoPlay v-else />
+						</el-icon>
+					</template>
+				</CommonCesiumMap>
 			</div>
 			<div class="right-container">
 				<div class="header">
@@ -53,7 +62,7 @@
 					<div class="detail-title">轨迹点</div>
 					<div class="command-table-container">
 						<div class="command-table-content">
-							<el-table class="command-table" :data="list" :row-class-name="getRowClassName">
+							<el-table ref="pointTableRef" class="command-table" :data="list" :row-class-name="getRowClassName">
 								<el-table-column type="index" width="60" label="序号" />
 								<el-table-column label="经纬度">
 									<template #default="{ row }">{{ row.longitude }},{{ row.latitude }}</template>
@@ -64,7 +73,9 @@
 					</div>
 				</div>
 				<div class="footer">
-					<el-button v-if="dialogMode != 'view'" color="#2B2B4C" @click="handleCancel">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>
+					<el-button v-if="dialogMode != 'view'" color="#2B2B4C" @click="handleCancel">
+						{{ dialogReadonly ? '关闭' : '取消' }}
+					</el-button>
 				</div>
 			</div>
 		</div>
@@ -72,9 +83,9 @@
 </template>
 
 <script setup>
-import { Close } from '@element-plus/icons-vue'
+import { Close, VideoPause, VideoPlay } from '@element-plus/icons-vue'
 
-import { computed, nextTick, ref } from 'vue'
+import { computed, nextTick, onBeforeUnmount, ref } from 'vue'
 import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue'
 import { fwDroneFlightRecordDetailApi } from '@/views/recordManage/historyTracks/fwDroneFlightRecord'
 import { fwDroneFlightRecordDetailPageApi } from '@/views/recordManage/historyTracks/flyTrajectory'
@@ -163,18 +174,87 @@
 
 // 关闭后重置
 function handleClosed() {
+	stopTrackPlay()
 	formData.value = initForm()
 	list.value = []
+	selectedPointIndex.value = 0
 	viewer = null
 	geometricSource = null
 	droneLineEntity = null
 	startDroneEntity = null
 }
 
-function getRowClassName({ row }) {
-	console.log(row.isAlarm, 11111111111)
+// 当前选中的轨迹点索引(与地图时间轴联动)
+const selectedPointIndex = ref(0)
+const pointTableRef = ref(null)
+const isPlaying = ref(false)
+const PLAY_INTERVAL = 1000
+let playTimer = null
+let playIndex = 0
 
-	return row?.isAlarm === 1 ? 'alarm-row' : ''
+// 停止轨迹播放
+function stopTrackPlay() {
+	if (playTimer) {
+		clearTimeout(playTimer)
+		playTimer = null
+	}
+	isPlaying.value = false
+}
+
+// 播放下一个轨迹点
+function playNextPoint() {
+	if (!list.value.length || playIndex >= list.value.length) {
+		stopTrackPlay()
+		return
+	}
+	mapRef.value?.clickWeekTime?.(list.value[playIndex], playIndex, {
+		animate: true,
+		duration: PLAY_INTERVAL,
+	})
+	playIndex += 1
+	playTimer = setTimeout(() => {
+		playTimer = null
+		if (playIndex >= list.value.length) {
+			stopTrackPlay()
+			return
+		}
+		playNextPoint()
+	}, PLAY_INTERVAL)
+}
+
+// 切换轨迹播放状态
+function handlePlayClick() {
+	if (isPlaying.value) {
+		stopTrackPlay()
+		return
+	}
+	if (!list.value.length) return
+	mapRef.value?.clickWeekTime?.(list.value[0], 0)
+	if (list.value.length === 1) return
+	playIndex = 1
+	isPlaying.value = true
+	playNextPoint()
+}
+
+// 地图上点击轨迹点后,同步高亮表格对应行,并滚动到该行
+function handlePointChange({ index } = {}) {
+	if (typeof index !== 'number') return
+	selectedPointIndex.value = index
+	scrollToSelectedRow()
+}
+
+// 表格行较多时自动滚动到选中行
+async function scrollToSelectedRow() {
+	await nextTick()
+	const rowEl = pointTableRef.value?.$el?.querySelector('.selected-row')
+	rowEl?.scrollIntoView({ block: 'nearest', behavior: 'smooth' })
+}
+
+function getRowClassName({ row, rowIndex }) {
+	const classNames = []
+	if (row?.isAlarm === 1) classNames.push('alarm-row')
+	if (rowIndex === selectedPointIndex.value) classNames.push('selected-row')
+	return classNames.join(' ')
 }
 
 let viewer, geometricSource, droneLineEntity, startDroneEntity
@@ -189,6 +269,7 @@
 
 // 打开弹框
 async function open({ mode, row } = {}) {
+	stopTrackPlay()
 	dialogMode.value = mode || 'add'
 	visible.value = true
 	await nextTick()
@@ -202,14 +283,46 @@
 }
 
 defineExpose({ open })
+
+// 卸载时清理播放定时器
+onBeforeUnmount(() => {
+	stopTrackPlay()
+})
 </script>
 
 <style scoped lang="scss">
+.left-container {
+	min-width: 0;
+	overflow: hidden;
+}
+
+.right-container {
+	position: relative;
+	flex-shrink: 0;
+	z-index: 1;
+	background: #1a1a2a;
+}
+
 :deep(.alarm-row) {
-	background: #2B2B4C !important;
+	background: #2b2b4c !important;
 
 	td {
 		background-color: transparent !important;
 	}
 }
+
+// 与地图时间轴联动的选中行高亮
+:deep(.selected-row) {
+	background: #14335f !important;
+
+	td {
+		background-color: transparent !important;
+		color: #4faaff !important;
+	}
+}
+
+.track-play-btn {
+	color: #ffffff;
+	cursor: pointer;
+}
 </style>
diff --git a/applications/drone-command/src/views/recordManage/historyTracks/index.vue b/applications/drone-command/src/views/recordManage/historyTracks/index.vue
index 92d4abd..0a7fb1b 100644
--- a/applications/drone-command/src/views/recordManage/historyTracks/index.vue
+++ b/applications/drone-command/src/views/recordManage/historyTracks/index.vue
@@ -66,7 +66,7 @@
 							{{ formatStayDuration(row.stayDuration) }}
 						</template>
 					</el-table-column>
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="handleView(row)">历史轨迹</el-link>
 						</template>
diff --git a/applications/drone-command/src/views/system/helpCenter.vue b/applications/drone-command/src/views/system/helpCenter.vue
index 8860f3c..6ee1cec 100644
--- a/applications/drone-command/src/views/system/helpCenter.vue
+++ b/applications/drone-command/src/views/system/helpCenter.vue
@@ -17,7 +17,7 @@
         <el-table-column prop="levelTwoType" label="二级类别" />
         <el-table-column prop="uploadUser" label="上传者" />
         <el-table-column prop="createTime" label="上传时间" />
-     <el-table-column label="操作" width="200" align="center">
+     <el-table-column label="操作" width="200" align="center" fixed="right">
   <template #default="scope">
     <div class="actionBar" >
       <el-button 
diff --git a/applications/drone-command/src/views/system/user/index.vue b/applications/drone-command/src/views/system/user/index.vue
index fe36b3d..3a9003f 100644
--- a/applications/drone-command/src/views/system/user/index.vue
+++ b/applications/drone-command/src/views/system/user/index.vue
@@ -137,7 +137,7 @@
 						</template>
 					</el-table-column>
 					<el-table-column prop="phone" label="手机号码" />
-					<el-table-column label="操作" width="180">
+					<el-table-column label="操作" width="180" fixed="right">
 						<template v-slot="{ row }">
 							<el-link v-if="permission.user_view" @click="openForm('view', row)" type="primary">查看</el-link>
 							<el-link v-if="permission.user_edit && !auditMode" @click="openForm('edit', row)" type="warning">
diff --git a/applications/mobile-web-view/env/.env b/applications/mobile-web-view/env/.env
index 90aa6f2..1f302e8 100644
--- a/applications/mobile-web-view/env/.env
+++ b/applications/mobile-web-view/env/.env
@@ -2,12 +2,15 @@
 
 
 #代理用的
-VITE_APP_API = /api
+VITE_APP_API = /jals/yisuanzhijian
 
 VITE_APP_API_JALS = /jals/api
 
+#axiosKY 直连航空网关域名(各环境一致)
+VITE_APP_KY_URL = https://wrj.shuixiongit.com
+
 #线上用的
-VITE_APP_XT_URL=http://220.177.172.27:8100/yisuanzhijian
+VITE_APP_XT_URL = http://220.177.172.27:8100/jals/yisuanzhijian
 
 #调试参数
 VITE_APP_DEBUG_KEY = saber
diff --git a/applications/mobile-web-view/src/api/map/address.js b/applications/mobile-web-view/src/api/map/address.js
index 35dcd3d..23296f8 100644
--- a/applications/mobile-web-view/src/api/map/address.js
+++ b/applications/mobile-web-view/src/api/map/address.js
@@ -1,4 +1,5 @@
 import request from '@/axios'
+import requestKY from '@/axiosKY'
 
 /**
  * @description: 获取地址搜索结果
@@ -29,9 +30,9 @@
   })
 }
 
-// 我的空域查询
+// 我的空域查询(走 axiosKY 实例,直连航空网关)
 export const droneFlightTaskApi = data => {
-  return request({
+  return requestKY({
     url: `/webservice/droneFlightTask/pageInfoOfMy`,
     method: 'post',
     data,
diff --git a/applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue b/applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue
index a83bea4..07e8e20 100644
--- a/applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue
+++ b/applications/mobile-web-view/src/appPages/voiceCallDetail/index.vue
@@ -43,7 +43,8 @@
 const route = useRoute()
 /** ✅ 你的 WS 地址前缀(后面拼 userId) */
 // const WS_BASE = 'ws://218.202.104.82:38201/ws/chat?userId='
-const WS_BASE = 'ws://218.202.104.82:38201/ws/chat'
+// const WS_BASE = 'ws://218.202.104.82:38201/ws/chat'
+const WS_BASE = 'ws://220.177.172.27:8100/webrtc/ws/chat'
 const newUserInfo = ref(null)
 const uid = ref('')
 const peerUid = ref('')
diff --git a/applications/mobile-web-view/src/axios.js b/applications/mobile-web-view/src/axios.js
index 1a99af6..d3777b2 100644
--- a/applications/mobile-web-view/src/axios.js
+++ b/applications/mobile-web-view/src/axios.js
@@ -25,19 +25,23 @@
 // 全局锁机制相关变量
 window.isRefreshing = false // 标记当前是否正在刷新token
 
-axios.defaults.timeout = 60000
-//返回其他状态码
-axios.defaults.validateStatus = function (status) {
-	return status >= 200 && status <= 500 // 默认的
-}
-//跨域请求,允许保存cookie
-axios.defaults.withCredentials = false
+// 创建作用域的 axios 实例
+const service = axios.create({
+	// 超时时间设置为10分钟,部分接口上传比较慢,如固件上传
+	timeout: 600000,
+	//返回其他状态码
+	validateStatus: function (status) {
+		return status >= 200 && status <= 500 // 默认的
+	},
+	//跨域请求,允许保存cookie
+	withCredentials: true,
+})
 NProgress.configure({
 	showSpinner: false,
 })
 
 //http request拦截
-axios.interceptors.request.use(
+service.interceptors.request.use(
 	config => {
 		// 初始化错误提示状态
 		isErrorShown = false
@@ -112,7 +116,7 @@
 )
 
 //http response拦截
-axios.interceptors.response.use(
+service.interceptors.response.use(
 	res => {
 		// NProgress.done()
 		//获取配置信息
@@ -178,5 +182,5 @@
 		return Promise.reject(new Error(error))
 	}
 )
-window._request = axios
-export default axios
+window._request = service
+export default service
diff --git a/applications/mobile-web-view/src/axiosKY.js b/applications/mobile-web-view/src/axiosKY.js
new file mode 100644
index 0000000..6e88bef
--- /dev/null
+++ b/applications/mobile-web-view/src/axiosKY.js
@@ -0,0 +1,190 @@
+/**
+ * 全站http配置
+ *
+ * axios参数说明
+ * isSerialize是否开启form表单提交
+ * isToken是否需要token
+ */
+import axios from 'axios'
+import store from '@/store/'
+import router from '@/router/'
+import { serialize } from '@/utils/util'
+import { getToken, removeRefreshToken, removeToken } from '@/utils/auth'
+import { isURL, validatenull } from '@/utils/validate'
+import website from '@/config/website'
+import NProgress from 'nprogress' // progress bar
+import 'nprogress/nprogress.css' // progress bar style
+import crypto from '@/utils/crypto'
+import { getStore } from '@/utils/store'
+import { showToast } from 'vant'
+import { baseUrl, baseUrlJals } from '@/config/env'
+
+let { VITE_APP_ENV,VITE_APP_XT_URL,VITE_APP_API,VITE_APP_KY_URL } = import.meta.env
+// 全局未授权错误提示状态,只提示一次
+let isErrorShown = false
+// 全局锁机制相关变量
+window.isRefreshing = false // 标记当前是否正在刷新token
+
+// 创建作用域的 axios 实例
+const service = axios.create({
+    // 直连航空网关域名,请求最终为 baseURL + /jals/yisuanzhijian + /webservice/...
+    // VITE_APP_KY_URL 各环境一致 = https://wrj.shuixiongit.com
+    baseURL: VITE_APP_KY_URL,
+    // 超时时间设置为10分钟,部分接口上传比较慢,如固件上传
+    timeout: 600000,
+    //返回其他状态码
+    validateStatus: function (status) {
+        return status >= 200 && status <= 500 // 默认的
+    },
+    //跨域请求,允许保存cookie
+    withCredentials: true,
+})
+NProgress.configure({
+    showSpinner: false,
+})
+
+//http request拦截
+service.interceptors.request.use(
+    config => {
+        console.log(config,'9090')
+        // 初始化错误提示状态
+        isErrorShown = false
+        // if (VITE_APP_ENV === 'development') {
+        // 	config.url = VITE_APP_API + config.url
+        // } else {
+        // 	config.url = VITE_APP_XT_URL + config.url
+        // }
+
+        if (config.isUseJals) {
+            if (!isURL(config.url) && !config.url.startsWith(baseUrlJals)) {
+                config.url = baseUrlJals + config.url
+            }
+        }
+
+        //地址为已经配置状态则不添加前缀
+        if (!isURL(config.url) && !config.url.startsWith(baseUrl) && !config.isUseJals) {
+            config.url = baseUrl + config.url
+        }
+
+        config.headers['areaCode'] = store.state.user.selectedAreaCode
+        //安全请求header
+        config.headers['Blade-Requested-With'] = 'BladeHttpRequest'
+        //headers判断是否需要
+        // const authorization = config.authorization === false
+        // if (!authorization) {
+        // 	config.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`
+        // }
+
+        config.headers['Authorization'] = store.state.user.token
+        // 根据后端要求,post的data为空的话传{}
+        if (config.method === 'post') {
+            config.data = config.data || {}
+        }
+        //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() || getStore({ name: 'token' })
+        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拦截
+service.interceptors.response.use(
+    res => {
+        // NProgress.done()
+        //获取配置信息
+        const config = res.config
+        const cryptoData = config.cryptoData === true
+        //解析加密报文
+        if (cryptoData) {
+            res.data = JSON.parse(crypto.decryptAES(res.data, crypto.aesKey))
+        }
+        //获取状态信息
+        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 || '系统错误'
+        // 处理没有密钥证书,需登录重新联系运维人员上传证书
+        if (status === 511) {
+            // 获取当前路由名称
+            const currentRoutePath = router.currentRoute.value
+            if (currentRoutePath.path !== '/login') {
+                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) {
+            isErrorShown = true
+            showToast('用户令牌不可用,请重新登录');
+            const transmitData = { data: { type: 'tokenExpired' } }
+
+            wx.miniProgram.reLaunch({url: 'pages/login/index'})
+            wx.miniProgram.postMessage(transmitData)
+            uni.postMessage(transmitData)
+
+            removeToken()
+            removeRefreshToken()
+            // 重定向到登录页
+            store.dispatch('FedLogOut').then(() => router.push({ path: '/login' }))
+            return Promise.reject(new Error(message))
+        }
+
+        // 如果请求为oauth2错误码则首次报错时提示
+        if (status > 2000 && !validatenull(res.data.error_description)) {
+            if (!isErrorShown) {
+                isErrorShown = true
+                showToast(message);
+            }
+            return Promise.reject(new Error(message))
+        }
+        // 如果请求为非200则默认统一处理
+        if (status !== 200) {
+            // ElMessage({
+            // 	message: message,
+            // 	type: status === -2 ? 'warning' : 'error',
+            // })
+            showToast(message)
+            return Promise.reject(new Error(message))
+        }
+        return res
+    },
+    error => {
+        // NProgress.done()
+        return Promise.reject(new Error(error))
+    }
+)
+window._request = service
+export default service
diff --git a/applications/mobile-web-view/vite.config.mjs b/applications/mobile-web-view/vite.config.mjs
index 1c947ec..b96c233 100644
--- a/applications/mobile-web-view/vite.config.mjs
+++ b/applications/mobile-web-view/vite.config.mjs
@@ -108,11 +108,11 @@
           rewrite: path => path.replace(/^\/dji_in_rectangle/, ''),
         },
 
-        '/webservice': {
-          target: VITE_APP_XT_URL,
-          changeOrigin: true,
-          rewrite: path => path.replace(/^\/webservice/, '/webservice'),
-        },
+        // '/webservice': {
+        //   target: VITE_APP_XT_URL,
+        //   changeOrigin: true,
+        //   rewrite: path => path.replace(/^\/webservice/, '/webservice'),
+        // },
 
         '/jals/api/drone-gd': {
           target: VITE_APP_XT_URL_GD,
@@ -120,10 +120,9 @@
           rewrite: path => path.replace(/^\/drone-gd/, '/drone-gd'),
         },
 
-        '/api': {
-          target: VITE_APP_XT_URL,
+        '/jals/yisuanzhijian/webservice': {
+          target: 'https://wrj.shuixiongit.com',
           changeOrigin: true,
-          rewrite: path => path.replace(/^\/api/, ''),
         }
       },
     },
diff --git a/applications/task-work-order/env/.env b/applications/task-work-order/env/.env
index 6bfc119..e9c206e 100644
--- a/applications/task-work-order/env/.env
+++ b/applications/task-work-order/env/.env
@@ -24,6 +24,11 @@
 
 # 预览地址 previewURL
 VITE_APP_PREVIEW_URL=http://220.177.172.27:8100/kkfile
+
+# OnlyOffice 文档服务地址
+#VITE_APP_ONLYOFFICE_DOCUMENT_SERVER_URL=http://192.168.1.54:8089/
+VITE_APP_ONLYOFFICE_DOCUMENT_SERVER_URL=http://220.177.172.27:8100/onlyoffice
+
 #地形服务地址
 VITE_APP_TERRAIN_URL=http://220.177.172.27:8100/ztzf_terrain/
 
diff --git a/applications/task-work-order/package.json b/applications/task-work-order/package.json
index 223e12b..6e1256b 100644
--- a/applications/task-work-order/package.json
+++ b/applications/task-work-order/package.json
@@ -13,6 +13,7 @@
 		"@amap/amap-jsapi-loader": "catalog:",
 		"@dvgis/dc-sdk": "catalog:",
 		"@element-plus/icons-vue": "catalog:",
+		"@onlyoffice/document-editor-vue": "catalog:",
 		"@saber/nf-design-base-elp": "catalog:",
 		"@saber/nf-form-design-elp": "catalog:",
 		"@saber/nf-form-elp": "catalog:",
diff --git a/applications/task-work-order/src/api/documentPreview/index.js b/applications/task-work-order/src/api/documentPreview/index.js
new file mode 100644
index 0000000..5973997
--- /dev/null
+++ b/applications/task-work-order/src/api/documentPreview/index.js
@@ -0,0 +1,9 @@
+import request from '@/axios'
+
+export const getOnlyOfficeConfigApi = params => {
+	return request({
+		url: '/blade-resource/attach/getOnlyOfficeConfig',
+		method: 'get',
+		params,
+	})
+}
diff --git a/applications/task-work-order/src/permission.js b/applications/task-work-order/src/permission.js
index 18a27a0..3e0ebbd 100644
--- a/applications/task-work-order/src/permission.js
+++ b/applications/task-work-order/src/permission.js
@@ -67,14 +67,16 @@
           //   query: firstMenu.query || {},
           //   meta: firstMenu.meta || {},
           // })
-          store.commit('ADD_TAG', {
-            name: toMenu.name,
-            path: toMenu.path,
-            fullPath: toMenu.path,
-            params: toMenu.params || {},
-            query: toMenu.query || {},
-            meta: toMenu.meta || {},
-          })
+          if (toMenu && to.meta?.isTab !== false) {
+            store.commit('ADD_TAG', {
+              name: toMenu.name,
+              path: toMenu.path,
+              fullPath: toMenu.path,
+              params: toMenu.params || {},
+              query: toMenu.query || {},
+              meta: toMenu.meta || {},
+            })
+          }
 
           next(to.fullPath)
         }
diff --git a/applications/task-work-order/src/router/views/index.js b/applications/task-work-order/src/router/views/index.js
index c18c3c3..d4d4d9c 100644
--- a/applications/task-work-order/src/router/views/index.js
+++ b/applications/task-work-order/src/router/views/index.js
@@ -22,6 +22,18 @@
       }
     ],
   },
+	{
+		path: '/documentPreview/officeEdit',
+		name: '巡查报告在线编辑',
+		component: () =>
+			import(
+				/* webpackChunkName: "views" */ '@/views/documentPreview/index.vue'
+			),
+		meta: {
+			isTab: false,
+			menu: false,
+		},
+	},
   {
     path: '/test',
     component: Layout,
diff --git a/applications/task-work-order/src/views/basicManage/maintainRecord/index.vue b/applications/task-work-order/src/views/basicManage/maintainRecord/index.vue
index 55ba0d7..4f4b4cd 100644
--- a/applications/task-work-order/src/views/basicManage/maintainRecord/index.vue
+++ b/applications/task-work-order/src/views/basicManage/maintainRecord/index.vue
@@ -51,7 +51,7 @@
 							{{ getPlanCycleLabel(row) }}
 						</template>
 					</el-table-column>
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="openForm('view', row)">查看</el-link>
 							<el-link @click="openForm('edit', row)">编辑</el-link>
diff --git a/applications/task-work-order/src/views/documentPreview/index.vue b/applications/task-work-order/src/views/documentPreview/index.vue
new file mode 100644
index 0000000..3da59da
--- /dev/null
+++ b/applications/task-work-order/src/views/documentPreview/index.vue
@@ -0,0 +1,103 @@
+<template>
+	<div class="document-preview-page" v-loading="loading">
+		<DocumentEditor
+			v-if="config"
+			id="inspectionReportOfficeEditor"
+			:documentServerUrl="documentServerUrl"
+			:config="config"
+			height="100%"
+			width="100%"
+			:events_onAppReady="onAppReady"
+			:events_onDocumentReady="onDocumentReady"
+			:events_onDocumentStateChange="onDocumentStateChange"
+			:events_onWarning="onWarning"
+			:events_onError="onError"
+			:onLoadComponentError="onLoadComponentError"
+		/>
+		<el-empty v-else-if="!loading" :description="errorMessage || '缺少文档配置'" />
+	</div>
+</template>
+
+<script setup>
+import { computed, ref, watch } from 'vue'
+import { useRoute } from 'vue-router'
+import { ElMessage } from 'element-plus'
+import { DocumentEditor } from '@onlyoffice/document-editor-vue'
+import { getOnlyOfficeConfigApi } from '@/api/documentPreview'
+
+const route = useRoute()
+const documentServerUrl = import.meta.env.VITE_APP_ONLYOFFICE_DOCUMENT_SERVER_URL
+const attachId = computed(() => String(route.query.attachId || ''))
+const mode = computed(() => String(route.query.mode || ''))
+
+const config = ref(null)
+const loading = ref(false)
+const errorMessage = ref('')
+
+async function getOnlyOfficeConfig() {
+	if (!attachId.value) {
+		config.value = null
+		errorMessage.value = '缺少附件ID'
+		return
+	}
+
+	loading.value = true
+	errorMessage.value = ''
+
+	try {
+		const res = await getOnlyOfficeConfigApi({
+			attachId: attachId.value,
+			mode: mode.value,
+		})
+		const data = res?.data?.data || res?.data
+		if (!data?.document || !data?.editorConfig) {
+			throw new Error('OnlyOffice配置不完整')
+		}
+		config.value = data
+	} catch (error) {
+		console.error('获取OnlyOffice配置失败:', error)
+		config.value = null
+		errorMessage.value = '获取文档配置失败'
+		ElMessage.error(error?.message || '获取文档配置失败')
+	} finally {
+		loading.value = false
+	}
+}
+
+watch(attachId, getOnlyOfficeConfig, {
+	immediate: true,
+})
+
+function onAppReady(event) {
+	console.log('OnlyOffice app ready:', event)
+}
+
+function onDocumentReady(event) {
+	console.log('OnlyOffice document ready:', event)
+}
+
+function onDocumentStateChange(event) {
+	console.log('OnlyOffice document state change:', event)
+}
+
+function onWarning(event) {
+	console.warn('OnlyOffice warning:', event)
+}
+
+function onError(event) {
+	console.error('OnlyOffice error:', event)
+}
+
+function onLoadComponentError(errorCode, errorDescription) {
+	console.error('OnlyOffice load error:', errorCode, errorDescription)
+}
+</script>
+
+<style scoped lang="scss">
+.document-preview-page {
+	height: 100vh;
+	min-height: 0;
+	width: 100vw;
+	overflow: hidden;
+}
+</style>
diff --git a/applications/task-work-order/src/views/orderView/appConfiguration/inventory/index.vue b/applications/task-work-order/src/views/orderView/appConfiguration/inventory/index.vue
index a3dae3f..0bf64b4 100644
--- a/applications/task-work-order/src/views/orderView/appConfiguration/inventory/index.vue
+++ b/applications/task-work-order/src/views/orderView/appConfiguration/inventory/index.vue
@@ -62,7 +62,7 @@
 					<el-table-column prop="matterName" show-overflow-tooltip label="事项名称" />
 					<el-table-column prop="catalogCode" show-overflow-tooltip label="目录编码" />
 					<el-table-column prop="orgName" show-overflow-tooltip label="所属机构" />
-					<el-table-column label="操作" class-name="operation-btns" width="250">
+					<el-table-column label="操作" class-name="operation-btns" width="250" fixed="right">
 						<template v-slot="{ row }">
 							<el-link type="primary" @click="openForm('view', row)">查看</el-link>
 							<el-link type="primary" @click="openForm('edit', row)">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/appConfiguration/materials/index.vue b/applications/task-work-order/src/views/orderView/appConfiguration/materials/index.vue
index 68d6b1d..693e3af 100644
--- a/applications/task-work-order/src/views/orderView/appConfiguration/materials/index.vue
+++ b/applications/task-work-order/src/views/orderView/appConfiguration/materials/index.vue
@@ -41,7 +41,7 @@
 							{{ getDictLabel(String(row.isAllScenario), dictObj.isAllScenario) }}
 						</template>
 					</el-table-column>
-					<el-table-column label="操作" class-name="operation-btns" width="200">
+					<el-table-column label="操作" class-name="operation-btns" width="200" fixed="right">
 						<template v-slot="{ row }">
 							<el-link type="primary" @click="openForm('view', row)">查看</el-link>
 							<el-link type="primary" @click="openForm('edit', row)">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/appConfiguration/process/index.vue b/applications/task-work-order/src/views/orderView/appConfiguration/process/index.vue
index 301c472..51e11aa 100644
--- a/applications/task-work-order/src/views/orderView/appConfiguration/process/index.vue
+++ b/applications/task-work-order/src/views/orderView/appConfiguration/process/index.vue
@@ -59,7 +59,7 @@
 					</el-table-column>
 					<el-table-column prop="created" show-overflow-tooltip label="创建时间" />
 					<el-table-column prop="lastUpdated" show-overflow-tooltip label="更新时间" />
-					<el-table-column label="操作" class-name="operation-btns" width="200">
+					<el-table-column label="操作" class-name="operation-btns" width="200" fixed="right">
 						<template v-slot="{ row }">
 							<el-link type="primary"  @click="handleUpdate(row)">配置</el-link>
 							<el-link type="primary" @click="handleDeploy(row)">部署</el-link>
diff --git a/applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/FormDiaLog.vue b/applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/FormDiaLog.vue
index 97cec03..b3d1bfb 100644
--- a/applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/FormDiaLog.vue
+++ b/applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/FormDiaLog.vue
@@ -95,8 +95,7 @@
 	visible.value = false
 }
 
-async function loadDetail(id) {
-	formData.value.callId = id || formData.value.callId
+async function loadDetail() {
 	const res = await getDeviceCallRecordDetails(formData.value)
 	detailsList.value = res?.data?.data.records || []
 	total.value = res?.data?.data.total || 0
@@ -109,7 +108,8 @@
 async function open({ mode, row } = {}) {
 	dialogMode.value = mode || 'add'
 	visible.value = true
-	await loadDetail(row.id)
+	formData.value.callId = row.id || ''
+	await loadDetail()
 }
 
 onMounted(() => {
diff --git a/applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/index.vue b/applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/index.vue
index ef45996..20660fd 100644
--- a/applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/index.vue
+++ b/applications/task-work-order/src/views/orderView/deviceInvocation/deviceCallRecord/index.vue
@@ -84,7 +84,7 @@
 					<el-table-column prop="deviceName" show-overflow-tooltip label="执行设备" />
 					<el-table-column prop="planExecuteTime" show-overflow-tooltip label="计划执行时间" />
 					<el-table-column prop="actualExecuteTime" show-overflow-tooltip label="实际执行时间" />
-					<el-table-column label="操作" class-name="operation-btns" width="180">
+					<el-table-column label="操作" class-name="operation-btns" width="180" fixed="right">
 						<template v-slot="{ row }">
 							<el-link  @click="handleView(row)">查看</el-link>
 						</template>
diff --git a/applications/task-work-order/src/views/orderView/deviceInvocation/equipmentResource/index.vue b/applications/task-work-order/src/views/orderView/deviceInvocation/equipmentResource/index.vue
index 9063627..acfc428 100644
--- a/applications/task-work-order/src/views/orderView/deviceInvocation/equipmentResource/index.vue
+++ b/applications/task-work-order/src/views/orderView/deviceInvocation/equipmentResource/index.vue
@@ -75,6 +75,11 @@
 							{{ getDictLabel(row.modeCode, dictObj.modeCode) }}
 						</template>
 					</el-table-column>
+					<el-table-column prop="maintenanceState" show-overflow-tooltip label="保养状态">
+						<template v-slot="{ row }">
+							{{ row.maintenanceState === 0 ? '无需保养' : row.maintenanceState === 1 ? '待保养' : '正在保养' }}
+						</template>
+					</el-table-column>
 					<el-table-column prop="deviceSn" show-overflow-tooltip label="设备SN" />
 					<el-table-column show-overflow-tooltip label="设备位置" >
 						<template v-slot="{ row }">
@@ -83,7 +88,7 @@
 					</el-table-column>
 					<el-table-column prop="firmwareVersion" show-overflow-tooltip label="固件版本" />
 					<el-table-column prop="deviceDeptName" show-overflow-tooltip label="所属部门" />
-					<el-table-column label="操作" class-name="operation-btns" width="180">
+					<el-table-column label="操作" class-name="operation-btns" width="180" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="viewEquipment(row)">查看</el-link>
 							<!-- <el-link type="primary" @click="editEquipment(row)">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/flyingHand/index.vue b/applications/task-work-order/src/views/orderView/flyingHand/index.vue
index 3dddd19..36a1634 100644
--- a/applications/task-work-order/src/views/orderView/flyingHand/index.vue
+++ b/applications/task-work-order/src/views/orderView/flyingHand/index.vue
@@ -75,7 +75,7 @@
 							{{ getTaskTypeLabel(row.skilledTaskType, workOrderTypeXT) }}
 						</template>
 					</el-table-column>
-					<el-table-column label="操作" class-name="operation-btns" width="180">
+					<el-table-column label="操作" class-name="operation-btns" width="180" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="viewFlyingHand(row)">查看</el-link>
 							<el-link type="primary" @click="editFlyingHand(row)">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/orderDataManage/appInnovation/index.vue b/applications/task-work-order/src/views/orderView/orderDataManage/appInnovation/index.vue
index 82aa128..305e0fe 100644
--- a/applications/task-work-order/src/views/orderView/orderDataManage/appInnovation/index.vue
+++ b/applications/task-work-order/src/views/orderView/orderDataManage/appInnovation/index.vue
@@ -60,7 +60,7 @@
 					<el-table-column prop="resourceName" show-overflow-tooltip label="资源名称" />
 					<el-table-column prop="resourceCode" show-overflow-tooltip label="资源编码" />
 					<el-table-column prop="caseDesc" show-overflow-tooltip label="案例描述" />
-					<el-table-column label="操作" class-name="operation-btns" width="150">
+					<el-table-column label="操作" class-name="operation-btns" width="150" fixed="right">
 						<template v-slot="{ row }">
 							<el-link  type="primary"  @click="openForm('view', row)">查看</el-link>
 							<el-link  type="primary"  @click="openForm('edit', row)" v-if="!['0','1', '2'].includes(row.innovationStatus) && row.isTheSameDepartment">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/FormDiaLog.vue b/applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/FormDiaLog.vue
index 19ec03e..b8998d6 100644
--- a/applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/FormDiaLog.vue
+++ b/applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/FormDiaLog.vue
@@ -448,7 +448,7 @@
       objectionDesc: formData.value.objectionDesc,
       objectionBasis: formData.value.objectionBasis,
       areaCode: formData.value.areaCode || '',
-      handleUnit: formData.value.handleUnit || '',
+      handleUnit: applyFormData.value.applyTargetDeptId || formData.value.handleUnit || '',
       // 构建附件列表 - 使用当前已上传的文件(包括回显的)
 			...(uploadedFiles.value.length > 0 && {
 				attachmentList: uploadedFiles.value.map(file => ({
@@ -487,6 +487,17 @@
 	 showApplyDialog.value = true
 }
 
+// 根据部门 id 在部门树里递归查找对应的中文名称(title)
+function findDeptTitleById(tree, id) {
+	if (!Array.isArray(tree) || id === '' || id == null) return ''
+	for (const node of tree) {
+		if (node.id === id) return node[treeProps.label]
+		const found = findDeptTitleById(node[treeProps.children], id)
+		if (found) return found
+	}
+	return ''
+}
+
 // 申请提交
 async function handleApplySubmit() {
 	const isValid = await applyFormRef.value?.validate().catch(() => false)
@@ -512,7 +523,8 @@
 			objectionDesc: applyData.objectionDesc,
 			objectionBasis: applyData.objectionBasis,
 			areaCode: applyData.areaCode || '',
-			handleUnit: applyData.handleUnit || '',
+			// 处理单位存部门中文名称,而不是 id
+			handleUnit: findDeptTitleById(deptTree.value, applyFormData.value.applyTargetDeptId) || applyData.handleUnit || '',
 			// 构建附件列表 - 使用当前已上传的文件(包括回显的)
 			...(uploadedFiles.value.length > 0 && {
 				attachmentList: uploadedFiles.value.map(file => ({
diff --git a/applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/index.vue b/applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/index.vue
index c54b9c3..1447de2 100644
--- a/applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/index.vue
+++ b/applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/index.vue
@@ -69,7 +69,7 @@
 					<el-table-column prop="objectionBasis" show-overflow-tooltip label="异议依据" />
 					<el-table-column prop="attachNames" show-overflow-tooltip label="附件名称" />
 					<el-table-column prop="reviewOpinion" show-overflow-tooltip label="审核意见" />
-					<el-table-column label="操作" class-name="operation-btns" width="150">
+					<el-table-column label="操作" class-name="operation-btns" width="150" fixed="right">
 						<template v-slot="{ row }">
 							<el-link  type="primary"  @click="openForm('view', row)">查看</el-link>
 							<el-link  type="primary"  @click="openForm('edit', row)" v-if="!['1', '2'].includes(row.objectionStatus)">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/orderDataManage/evaluate/index.vue b/applications/task-work-order/src/views/orderView/orderDataManage/evaluate/index.vue
index 484bcdc..6da0f54 100644
--- a/applications/task-work-order/src/views/orderView/orderDataManage/evaluate/index.vue
+++ b/applications/task-work-order/src/views/orderView/orderDataManage/evaluate/index.vue
@@ -54,7 +54,7 @@
 						</template>
 					</el-table-column>
 					<el-table-column prop="evaluationContent" show-overflow-tooltip label="评价内容" />
-					<el-table-column label="操作" class-name="operation-btns" width="150">
+					<el-table-column label="操作" class-name="operation-btns" width="150" fixed="right">
 						<template v-slot="{ row }">
 							<el-link  type="primary"  @click="openForm('view', row)">查看</el-link>
 							<el-link  type="primary"  @click="openForm('edit', row)" v-if="row.isTheSameDepartment">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/index.vue b/applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/index.vue
index 2e49fae..3763e8c 100644
--- a/applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/index.vue
+++ b/applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/index.vue
@@ -76,7 +76,7 @@
 					<el-table-column prop="responsibleDeptName" show-overflow-tooltip label="责任部门" />
 					<el-table-column prop="dataSource" show-overflow-tooltip label="数据来源依据" />
 					<el-table-column prop="demandInfo" show-overflow-tooltip label="需求信息项" />
-					<el-table-column label="操作" class-name="operation-btns" width="150">
+					<el-table-column label="操作" class-name="operation-btns" width="150" fixed="right">
 						<template v-slot="{ row }">
 							<el-link  type="primary"  @click="openForm('view', row)">查看</el-link>
 							<el-link  type="primary"  @click="openForm('edit', row)" v-if="!['1', '2', '3'].includes(row.demandStatus) && permissionList.addBtn">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue b/applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue
index 4f34518..7e13fa1 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue
@@ -33,7 +33,7 @@
 				</el-table-column>
 				<el-table-column prop="distributeDeptName" show-overflow-tooltip label="分发部门" />
 				<el-table-column prop="distributeUserName" show-overflow-tooltip label="分发人员" />
-				<el-table-column label="操作" class-name="operation-btns" width="140">
+				<el-table-column label="操作" class-name="operation-btns" width="140" fixed="right">
 					<template v-slot="{ row }">
 						<el-link
 							type="primary"
diff --git a/applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue b/applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue
index c8a2196..1d83c34 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue
@@ -85,7 +85,7 @@
 					<el-table-column prop="resultCount" show-overflow-tooltip label="线索数量" />
 					<el-table-column prop="issueEventCount" show-overflow-tooltip label="转为问题" />
 					<el-table-column prop="taskDesc" show-overflow-tooltip label="巡查任务描述" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link type="primary" @click="viewDiaLogView(row)">查看线索</el-link>
 						</template>
diff --git a/applications/task-work-order/src/views/orderView/orderManage/inspectionReport/index.vue b/applications/task-work-order/src/views/orderView/orderManage/inspectionReport/index.vue
index 1b1d54a..4a1b61f 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/inspectionReport/index.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/inspectionReport/index.vue
@@ -41,7 +41,11 @@
 				<el-table class="gd-table" :data="list" @selection-change="handleSelectionChange">
 					<el-table-column type="selection" width="46" />
 					<el-table-column type="index" width="64" label="序号" />
-					<el-table-column prop="nickName" show-overflow-tooltip label="文档名称" />
+					<el-table-column prop="nickName" class-name="operation-btns" show-overflow-tooltip label="文档名称">
+						<template v-slot="{ row }">
+							<el-link  type="primary"  @click="openForm(row)">{{ row.nickName }}</el-link>
+						</template>
+					</el-table-column>
 					<el-table-column prop="attachSize" show-overflow-tooltip label="文档大小">
 						<template v-slot="{ row }">
 						{{ formatFileSize(row.attachSize) }}
@@ -54,10 +58,10 @@
 							{{ getTaskTypeLabel(row.resultType, workOrderTypeXT) }}
 						</template>
 					</el-table-column>
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link  type="primary"  @click="seeOnlineWord(row)">查看</el-link>
-							<el-link  type="primary"  @click="openForm(row)">在线编辑</el-link>
+							<el-link type="primary" :disabled="isZipRow(row)" @click="openOfficeEdit(row)">在线编辑</el-link>
 							<el-link  type="primary"  @click="handleDelete(row)">删除</el-link>
 						</template>
 					</el-table-column>
@@ -135,8 +139,8 @@
 <script setup>
 import { Search, RefreshRight, Download, Upload } from '@element-plus/icons-vue'
 import { fjPageApi, fjSubmitApi, fjRemoveApi, fjUploadApi, fjDownloadByByteApi } from './inspectionRequestApi'
-import { useStore } from 'vuex'
-import { ref, computed, onMounted } from 'vue'
+import { ref, onMounted, onBeforeUnmount } from 'vue'
+import { useRouter } from 'vue-router'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import PreviewFiles from '@/components/PreviewFiles/PreviewFiles.vue'
 import { Base64 } from 'js-base64'
@@ -147,8 +151,7 @@
 	taskTypeCascaderProps,
 } from '../taskTypeOptions'
 
-const store = useStore()
-const userInfo = computed(() => store.getters.userInfo)
+const router = useRouter()
 
 
 
@@ -269,17 +272,66 @@
 ];
 const { VITE_APP_PREVIEW_URL } = import.meta.env
 
+// kkfileView 中,word/pdf 默认转成只读 pdf 预览,excel 才是可编辑的 html 模式。
+// 对这些类型追加 officePreviewType=html,让其以可编辑的 html 方式打开
+const editableOfficeTypes = ['doc', 'docx', 'pdf']
+
 // 在线查看文档
 function seeOnlineWord(row) {
 	// 获取点之后的文件格式名
-	const fileType = row?.link?.split('.').pop() || ''
+	const fileType = (row?.link?.split('.').pop() || '').toLowerCase()
 	if (!row.link) {
 		ElMessage.warning('文件链接不存在')
 	} else if (allSupportedExtensions.includes(fileType)){
-		window.open(`${VITE_APP_PREVIEW_URL}/onlinePreview?url=`+encodeURIComponent(Base64.encode(row.link)));
+		// let url = `${VITE_APP_PREVIEW_URL}/onlinePreview?url=` + encodeURIComponent(Base64.encode(row.link))
+		// // word/pdf 以可编辑的 html 模式打开(与 excel 一致)
+		// if (editableOfficeTypes.includes(fileType)) {
+		// 	url += '&officePreviewType=html'
+		// }
+		// window.open(url)
+		const route = router.resolve({
+			path: '/documentPreview/officeEdit',
+			query: {
+				attachId: row.id,
+				mode: 'view',
+			},
+		})
+		window.open(route.href, '_blank')
 	} else {
 		ElMessage.warning(`${fileType}文件格式,可以下载再查看`)
 	}
+}
+
+// 取行的文件扩展名(列表数据没有 extension 字段,回退用 link 解析)
+function getRowExtension(row) {
+	return (row?.extension || row?.link?.split('.').pop() || '').toLowerCase()
+}
+
+// 是否为 zip 文件(zip 不支持在线编辑)
+function isZipRow(row) {
+	return getRowExtension(row) === 'zip'
+}
+
+function openOfficeEdit(row) {
+	if (!row?.id) {
+		ElMessage.warning('附件ID不存在')
+		return
+	}
+	if (isZipRow(row)) {
+		ElMessage.warning('zip文件格式,不能编辑')
+		return
+	}
+
+	const route = router.resolve({
+		path: '/documentPreview/officeEdit',
+		query: {
+			attachId: row.id,
+			mode: 'edit',
+		},
+	})
+	window.open(route.href, '_blank')
+	// 标记已跳转去编辑,切回本页时刷新列表
+	pendingEditRefresh = true
 }
 
 // 删除
@@ -423,9 +475,33 @@
 	}
 }
 
+// 在线编辑跳转标记:从编辑页切回本页时刷新列表
+let pendingEditRefresh = false
+function handleVisibilityChange() {
+	if (document.visibilityState === 'visible' && pendingEditRefresh) {
+		pendingEditRefresh = false
+		getList()
+	}
+}
+
 onMounted(() => {
 	getDictList()
 	getList()
+	document.addEventListener('visibilitychange', handleVisibilityChange)
+})
+
+onBeforeUnmount(() => {
+	document.removeEventListener('visibilitychange', handleVisibilityChange)
 })
 </script>
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+// 操作列里链接的文字(span)被主题强制刷成蓝色 #0075FF,
+// 禁用时需在这里把 span 一并置灰,否则「在线编辑」禁用了还是蓝的
+:deep(.operation-btns) {
+	.el-link.is-disabled,
+	.el-link.is-disabled span {
+		color: #c0c4cc !important;
+		cursor: not-allowed !important;
+	}
+}
+</style>
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 fa7115c..286905d 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
@@ -171,7 +171,7 @@
 									>
 										<template #default>
 										<!-- 匹配区域=1 显示红星号 -->
-										<span v-if="item.areaMatchFlag === 1" style="color: #f56c6c; margin-right: 4px;">*</span>
+										<span v-if="item.taskTypeMatchFlag === 1" style="color: #f56c6c; margin-right: 4px;">*</span>
 										<span>{{ item.flyerName }}</span>
 										</template>
 									</el-option>
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 fa779ae..d02fff3 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
@@ -95,7 +95,7 @@
 					<el-table-column prop="executeTime" show-overflow-tooltip label="任务执行时间" />
 					<el-table-column prop="createTime" show-overflow-tooltip label="巡查任务创建时间" />
 					<el-table-column prop="taskDesc" show-overflow-tooltip label="巡查任务描述" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link type="primary" @click="viewDiaLogView(row)">查看</el-link>
 						</template>
diff --git a/applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue b/applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue
index 95dd3b5..c814364 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue
@@ -19,7 +19,7 @@
           <el-table-column prop="marketSpace" label="市场空间" align="center" show-overflow-tooltip></el-table-column>
           <el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
           <el-table-column prop="nickName" label="创建人" align="center"></el-table-column>
-          <el-table-column label="操作" width="180" align="center" class-name="operation-btns">
+          <el-table-column label="操作" width="180" align="center" class-name="operation-btns" fixed="right">
             <template #default="scope">
               <!-- <el-button icon="el-icon-view" type="text" @click="handleDetail(scope.row)">查看</el-button> -->
               <el-link type="primary" @click="handleEdit(scope.row)">编辑</el-link>
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 5141c8d..208c5e9 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
@@ -299,6 +299,7 @@
 	remark: '',
 	geom: '',
 	recommendDeviceIds: '',
+	typePinyinFirst: '',
 })
 
 const mapRef = ref(null)
@@ -686,6 +687,36 @@
 	}
 )
 
+// 取汉字(或英文)首字的拼音首字母,大写。如「占」→ Z
+function getFirstPinyinLetter(text) {
+	const char = String(text ?? '').trim().charAt(0)
+	if (!char) return ''
+	// 英文/数字直接取大写
+	if (/[a-zA-Z]/.test(char)) return char.toUpperCase()
+	// 按拼音排序的各首字母边界字,用 zh-CN 本地化比较定位所属字母
+	const boundaries = [
+		['A', '啊'], ['B', '芭'], ['C', '擦'], ['D', '搭'], ['E', '蛾'],
+		['F', '发'], ['G', '噶'], ['H', '哈'], ['J', '击'], ['K', '喀'],
+		['L', '垃'], ['M', '妈'], ['N', '拿'], ['O', '哦'], ['P', '啪'],
+		['Q', '期'], ['R', '然'], ['S', '撒'], ['T', '塌'], ['W', '挖'],
+		['X', '昔'], ['Y', '压'], ['Z', '匝'],
+	]
+	for (let i = boundaries.length - 1; i >= 0; i--) {
+		if (char.localeCompare(boundaries[i][1], 'zh-CN') >= 0) return boundaries[i][0]
+	}
+	return ''
+}
+
+// 工单类型变化时,用类型名称第一个字的拼音首字母(大写)赋值给 typePinyinFirst
+watch(
+	() => formData.value.workOrderType,
+	value => {
+		const label = getTaskTypeLabel(value, workOrderTypeXT.value)
+		formData.value.typePinyinFirst = getFirstPinyinLetter(label)
+	},
+	{ deep: true }
+)
+
 // 地图加载完毕
 function mapReady() {
 	dialogMode.value === 'add' && mapRef.value.flyBoundary()
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 89a664d..9d51b21 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
@@ -15,6 +15,16 @@
 				/>
 			</el-form-item>
 
+			<el-form-item label="工单编号" prop="workOrderCode">
+				<el-input
+					class="gd-input gray"
+					v-model="searchParams.workOrderCode"
+					placeholder="请输入"
+					clearable
+					@clear="handleSearch"
+				/>
+			</el-form-item>
+
 			<el-form-item label="工单类型" prop="workOrderType">
 				<el-cascader
 					class="gd-cascader gray"
@@ -60,6 +70,25 @@
 				/>
 			</el-form-item>
 
+			<el-form-item label="需求方名称" prop="createUserName">
+				<el-input
+					class="gd-input gray"
+					v-model="searchParams.createUserName"
+					placeholder="请输入"
+					clearable
+					@clear="handleSearch"
+				/>
+			</el-form-item>
+			<el-form-item label="服务方名称" prop="serviceParty">
+				<el-input
+					class="gd-input gray"
+					v-model="searchParams.serviceParty"
+					placeholder="请输入"
+					clearable
+					@clear="handleSearch"
+				/>
+			</el-form-item>
+
 			<el-form-item class="gd-search-actions">
 				<el-button :icon="RefreshRight" @click="resetForm"></el-button>
 				<el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button>
@@ -74,11 +103,11 @@
 			</div>
 
 			<div class="gd-table-content gd-table-content-bg">
-				<el-table class="gd-table" :data="list" @selection-change="handleSelectionChange">
+				<el-table class="gd-table" :data="list" @selection-change="handleSelectionChange" @sort-change="handleSortChange">
 					<el-table-column type="index" width="64" label="序号" />
 					<el-table-column prop="workOrderName" show-overflow-tooltip label="工单名称" />
 					<el-table-column prop="workOrderCode" show-overflow-tooltip label="工单编号" />
-					<el-table-column prop="workOrderType" show-overflow-tooltip label="工单类型">
+					<el-table-column prop="workOrderType" show-overflow-tooltip label="工单类型" sortable="custom">
 						<template v-slot="{ row }">
 							{{ getTaskTypeLabel(row.workOrderType, workOrderTypeXT) }}
 						</template>
@@ -104,7 +133,7 @@
 					<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">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link type="primary" @click="openFormChange(row)">查看</el-link>
 							<el-link type="primary" @click="routeManagement(row)">航线管理</el-link>
@@ -157,10 +186,14 @@
 // 初始化查询参数
 const initSearchParams = () => ({
 	workOrderName: '', // 工单名称
+	workOrderCode: '', // 工单编号
 	workOrderType: '', // 工单类型
 	workOrderStatus: '', // 工单状态
 	executeStartTime: '', // 执行开始时间
 	executeEndTime: '', // 执行结束时间
+	createUserName: '', // 需求方名称
+	serviceParty: '', // 服务方名称
+	typePinyinFirst: '', // 工单类型拼音首字母(大写)
 	current: 1, // 当前页
 	size: 10, // 每页大小
 })
@@ -196,6 +229,7 @@
 			endTime: range[1],
 			createUser: activeName.value === 'my' ? store.state.user.userInfo.user_id : '',
 			workOrderType: searchParams?.value?.workOrderType?.join?.(','),
+			typePinyinFirst: typePinyinFirst.value,
 		})
 		list.value = res?.data?.data?.records ?? []
 		total.value = res?.data?.data?.total ?? 0
@@ -311,10 +345,47 @@
 	myTotal.value = myRes?.data?.data?.total ?? 0
 }
 
+// 工单类型排序方向:asc(升序)/ desc(降序)/ ''(不排序)
+const typePinyinFirst = ref('')
+
+// 点击工单类型排序三角:上三角传 asc,下三角传 desc
+function handleSortChange({ prop, order }) {
+	if (prop !== 'workOrderType') return
+	typePinyinFirst.value = order === 'ascending' ? 'asc' : order === 'descending' ? 'desc' : ''
+	searchParams.value.current = 1
+	getList()
+}
+
 onMounted(() => {
 	getTabTotals()
 	getList()
 	getDictList()
 })
 </script>
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.gd-search-form {
+	// 搜索项较多,用栅格分两排整齐排列(4 列 × 2 行)
+	display: grid;
+	grid-template-columns: repeat(5, max-content);
+	gap: 16px 40px;
+	align-items: center;
+
+	// 清除公共样式里的行内间距,交给 grid 的 gap 统一控制
+	:deep(.el-form-item) {
+		margin: 0 !important;
+	}
+
+	// 固定 label 宽度,让每一列的输入框起点对齐
+	:deep(.el-form-item__label) {
+		width: 84px;
+		margin-right: 12px;
+		flex-shrink: 0;
+	}
+
+	// 操作按钮紧跟最后一个搜索项
+	:deep(.gd-search-actions) {
+		justify-self: start;
+		margin-left: 30px !important;
+	}
+}
+</style>
diff --git a/applications/task-work-order/src/views/orderView/orderManage/orderManage/orderManageApi.js b/applications/task-work-order/src/views/orderView/orderManage/orderManage/orderManageApi.js
index 66b3e6b..fe1fc79 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/orderManage/orderManageApi.js
+++ b/applications/task-work-order/src/views/orderView/orderManage/orderManage/orderManageApi.js
@@ -5,7 +5,7 @@
 	return request({
 		url: `/drone-gd/workOrder/gdWorkOrder/page`,
 		method: 'get',
-		params: { descs: 'create_time', ...params },
+		params: { ...params },
 	})
 }
 
diff --git a/applications/task-work-order/src/views/orderView/orderManage/orderManage/outcomeData.vue b/applications/task-work-order/src/views/orderView/orderManage/orderManage/outcomeData.vue
index dc6c7e4..4e2dc31 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/orderManage/outcomeData.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/orderManage/outcomeData.vue
@@ -79,7 +79,7 @@
           </el-table-column>
           
           <el-table-column prop="shootTime" show-overflow-tooltip label="拍摄时间" />
-          <el-table-column label="操作" class-name="operation-btns" width="120">
+          <el-table-column label="操作" class-name="operation-btns" width="120" fixed="right">
             <template v-slot="{ row }">
               <!-- <el-link type="primary" @click="handleDownload(row)">下载</el-link> -->
               <el-link type="primary" @click="handleDelete(row)">删除</el-link>
diff --git a/applications/task-work-order/src/views/orderView/organizational/agenciesManagement/index.vue b/applications/task-work-order/src/views/orderView/organizational/agenciesManagement/index.vue
index 560035b..cfd8c71 100644
--- a/applications/task-work-order/src/views/orderView/organizational/agenciesManagement/index.vue
+++ b/applications/task-work-order/src/views/orderView/organizational/agenciesManagement/index.vue
@@ -62,7 +62,7 @@
              {{ getDictLabel(row.status, dictObj.institutionStatus) }}
             </template>
           </el-table-column>
-          <el-table-column label="操作" class-name="operation-btns" width="200">
+          <el-table-column label="操作" class-name="operation-btns" width="200" fixed="right">
             <template v-slot="{ row }">
               <el-link type="primary" @click="openForm('view', row)">查看</el-link>
               <el-link type="primary"  @click="openForm('edit', row)">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/organizational/roleMange/index.vue b/applications/task-work-order/src/views/orderView/organizational/roleMange/index.vue
index 1f61d88..a59eaf1 100644
--- a/applications/task-work-order/src/views/orderView/organizational/roleMange/index.vue
+++ b/applications/task-work-order/src/views/orderView/organizational/roleMange/index.vue
@@ -57,7 +57,7 @@
 					<el-table-column prop="roleName" show-overflow-tooltip label="角色名称" />
 					<el-table-column prop="roleAlias" show-overflow-tooltip label="角色别名" />
 					<el-table-column prop="sort" show-overflow-tooltip label="角色排序" />
-					<el-table-column label="操作" class-name="operation-btns">
+					<el-table-column label="操作" class-name="operation-btns" fixed="right">
 						<template v-slot="{ row }">
 							<el-link @click="handleView(row)">查看</el-link>
 							<el-link @click="handleEdit(row)">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/organizational/userMange/index.vue b/applications/task-work-order/src/views/orderView/organizational/userMange/index.vue
index 5be373b..9558d5c 100644
--- a/applications/task-work-order/src/views/orderView/organizational/userMange/index.vue
+++ b/applications/task-work-order/src/views/orderView/organizational/userMange/index.vue
@@ -65,7 +65,7 @@
 					<el-table-column prop="roleName" show-overflow-tooltip label="所属角色" />
 					<el-table-column prop="deptName" show-overflow-tooltip label="所属部门" />
 					<el-table-column prop="phone" show-overflow-tooltip width="120" label="手机号" />
-					<el-table-column label="操作" class-name="operation-btns" width="180">
+					<el-table-column label="操作" class-name="operation-btns" width="180" fixed="right">
 						<template v-slot="{ row }">
 							<el-link  @click="handleView(row)">查看</el-link>
 							<el-link v-if="permission.orderUser_edit" @click="handleEdit(row)">编辑</el-link>
diff --git a/applications/task-work-order/src/views/orderView/organizational/zoningManagement/index.vue b/applications/task-work-order/src/views/orderView/organizational/zoningManagement/index.vue
index 0c6495d..8e4b893 100644
--- a/applications/task-work-order/src/views/orderView/organizational/zoningManagement/index.vue
+++ b/applications/task-work-order/src/views/orderView/organizational/zoningManagement/index.vue
@@ -66,7 +66,7 @@
               {{ getDictLabel(row.status, dictObj.zoningStatus) }}
             </template>
           </el-table-column>
-          <el-table-column label="操作" class-name="operation-btns" width="200">
+          <el-table-column label="操作" class-name="operation-btns" width="200" fixed="right">
             <template v-slot="{ row }">
               <el-link type="primary" @click="openForm('view', row)">查看</el-link>
               <el-link type="primary"  @click="openForm('edit', row)">编辑</el-link>
diff --git a/applications/task-work-order/src/views/system/helpCenter.vue b/applications/task-work-order/src/views/system/helpCenter.vue
index 8860f3c..6ee1cec 100644
--- a/applications/task-work-order/src/views/system/helpCenter.vue
+++ b/applications/task-work-order/src/views/system/helpCenter.vue
@@ -17,7 +17,7 @@
         <el-table-column prop="levelTwoType" label="二级类别" />
         <el-table-column prop="uploadUser" label="上传者" />
         <el-table-column prop="createTime" label="上传时间" />
-     <el-table-column label="操作" width="200" align="center">
+     <el-table-column label="操作" width="200" align="center" fixed="right">
   <template #default="scope">
     <div class="actionBar" >
       <el-button 
diff --git a/applications/task-work-order/src/views/system/user/index.vue b/applications/task-work-order/src/views/system/user/index.vue
index af2de07..cd7162e 100644
--- a/applications/task-work-order/src/views/system/user/index.vue
+++ b/applications/task-work-order/src/views/system/user/index.vue
@@ -137,7 +137,7 @@
 						</template>
 					</el-table-column>
 					<el-table-column prop="phone" label="手机号码" />
-					<el-table-column label="操作" width="180">
+					<el-table-column label="操作" width="180" fixed="right">
 						<template v-slot="{ row }">
 							<el-link v-if="permission.user_view" @click="openForm('view', row)" type="primary">查看</el-link>
 							<el-link v-if="permission.user_edit && !auditMode" @click="openForm('edit', row)" type="warning">
diff --git a/package.json b/package.json
index 40e09ed..b684a75 100644
--- a/package.json
+++ b/package.json
@@ -16,9 +16,6 @@
 		"prod": "pnpm -r prod",
 		"prod:drone-command": "pnpm -C applications/drone-command prod",
 		"prod:mobile-web-view": "pnpm -C applications/mobile-web-view prod",
-		"build:test:drone-command": "pnpm -C applications/drone-command build:test",
-		"build:test:mobile-web-view": "pnpm -C applications/mobile-web-view build:test",
-		"build:test:task-work-order": "pnpm -C applications/task-work-order build:test",
 		"build:prod:drone-command": "pnpm -C applications/drone-command build:prod",
 		"build:prod:mobile-web-view": "pnpm -C applications/mobile-web-view build:prod",
 		"build:prod:task-work-order": "pnpm -C applications/task-work-order build:prod"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7127c46..271eaf4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -18,6 +18,9 @@
     '@element-plus/icons-vue':
       specifier: ^2.3.1
       version: 2.3.2
+    '@onlyoffice/document-editor-vue':
+      specifier: ^1.6.1
+      version: 1.6.1
     '@saber/nf-design-base-elp':
       specifier: ^1.3.0
       version: 1.3.0
@@ -640,6 +643,9 @@
       '@element-plus/icons-vue':
         specifier: 'catalog:'
         version: 2.3.2(vue@3.5.27(typescript@5.9.3))
+      '@onlyoffice/document-editor-vue':
+        specifier: 'catalog:'
+        version: 1.6.1(vue@3.5.27(typescript@5.9.3))
       '@saber/nf-design-base-elp':
         specifier: 'catalog:'
         version: 1.3.0
@@ -2796,6 +2802,11 @@
   '@nuxt/kit@3.20.2':
     resolution: {integrity: sha512-laqfmMcWWNV1FsVmm1+RQUoGY8NIJvCRl0z0K8ikqPukoEry0LXMqlQ+xaf8xJRvoH2/78OhZmsEEsUBTXipcw==}
     engines: {node: '>=18.12.0'}
+
+  '@onlyoffice/document-editor-vue@1.6.1':
+    resolution: {integrity: sha512-sdU7h684ESSdXvGNDcMf73UmToiZGMVO5QRIazTmGfm+bKOnT5ildomeagYFdnQaHQH0J28EJqc4jqXOcQbicA==}
+    peerDependencies:
+      vue: ^3.0.0
 
   '@parcel/watcher-android-arm64@2.5.4':
     resolution: {integrity: sha512-hoh0vx4v+b3BNI7Cjoy2/B0ARqcwVNrzN/n7DLq9ZB4I3lrsvhrkCViJyfTj/Qi5xM9YFiH4AmHGK6pgH1ss7g==}
@@ -12004,6 +12015,11 @@
     transitivePeerDependencies:
       - magicast
 
+  '@onlyoffice/document-editor-vue@1.6.1(vue@3.5.27(typescript@5.9.3))':
+    dependencies:
+      lodash: 4.17.21
+      vue: 3.5.27(typescript@5.9.3)
+
   '@parcel/watcher-android-arm64@2.5.4':
     optional: true
 
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index c0d477a..aa718fd 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -8,6 +8,7 @@
   "@dvgis/dc-sdk": "3.4.0"
   "@dvgis/vite-plugin-dc": "2.2.0"
   "@element-plus/icons-vue": "^2.3.1"
+  "@onlyoffice/document-editor-vue": "^1.6.1"
   "@saber/nf-design-base-elp": "^1.3.0"
   "@saber/nf-form-design-elp": "^1.4.1"
   "@saber/nf-form-elp": "^1.4.4"
diff --git a/uniapps/work-app/src/hooks/useGlobalWS.js b/uniapps/work-app/src/hooks/useGlobalWS.js
index d4529ea..451a1e6 100644
--- a/uniapps/work-app/src/hooks/useGlobalWS.js
+++ b/uniapps/work-app/src/hooks/useGlobalWS.js
@@ -31,7 +31,8 @@
   const defaultUserId = '2021474815063486465';
   // WebSocket基础URL
   // const WS_BASE = 'wss://wrj.shuixiongit.com/ws/chat?userId=';
-  const WS_BASE = 'ws://218.202.104.82:38201/ws/chat';
+  // const WS_BASE = 'ws://218.202.104.82:38201/ws/chat';
+  const WS_BASE = 'ws://220.177.172.27:8100/webrtc/ws/chat';
 
 	// 获取通讯录数据
   async function fetchContactList() {
diff --git a/uniapps/work-wx/uploadCloudFunction.sh b/uniapps/work-wx/uploadCloudFunction.sh
new file mode 100644
index 0000000..df311b3
--- /dev/null
+++ b/uniapps/work-wx/uploadCloudFunction.sh
@@ -0,0 +1 @@
+${installPath} cloud functions deploy --e ${envId} --n quickstartFunctions --r --project ${projectPath}
\ No newline at end of file

--
Gitblit v1.9.3