From b4f08a561973b998036f6ffa9e843cfd5ee877be Mon Sep 17 00:00:00 2001
From: chenyao <1219716595@qq.com>
Date: Wed, 03 Jun 2026 14:35:24 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue            |   14 +
 applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue       |   51 ++++--
 applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue |  102 +++++++++---
 applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue             |   30 ++-
 AGENTS.md                                                                                     |    4 
 applications/task-work-order/src/api/zkxt/index.js                                            |   17 ++
 packages/utils/common/index.js                                                                |   10 +
 applications/task-work-order/src/styles/common/cockpit.scss                                   |   16 --
 applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue      |   14 +
 applications/task-work-order/src/api/system/dept.js                                           |    4 
 applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue        |   85 ++++++++++
 applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue |  105 +++++++++++-
 uniapps/work-app/src/pages/login/index.vue                                                    |    4 
 13 files changed, 357 insertions(+), 99 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index 4b3bba8..5b6b1b9 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -30,8 +30,7 @@
 - 文件与目录保持 kebabCase,遵循现有应用与包的命名风格。
 
 ## 测试指南
-- 当前未配置测试框架(`pnpm test` 会直接退出)。
-- 若新增测试,请在对应应用 `README.md` 说明测试框架,并补充根目录脚本。
+- 无需任何测试
 
 ## 提交与合并请求规范
 - 提交历史使用简短的约定式主题(如 `feat: ...`)。
@@ -54,3 +53,4 @@
   Prefer minimal changes.
 - 未被明确要求时,禁止大规模重构。
   Avoid large refactors unless requested.
+- 修改完不需要走打包编译校验
diff --git a/applications/task-work-order/src/api/system/dept.js b/applications/task-work-order/src/api/system/dept.js
index f0fcbc7..d4ae6b7 100644
--- a/applications/task-work-order/src/api/system/dept.js
+++ b/applications/task-work-order/src/api/system/dept.js
@@ -67,12 +67,12 @@
   });
 };
 
-export const getDeptTree = tenantId => {
+export const getDeptTree = id => {
   return request({
     url: '/blade-system/dept/getTree',
     method: 'get',
     params: {
-      tenantId,
+			id,
     },
   });
 };
diff --git a/applications/task-work-order/src/api/zkxt/index.js b/applications/task-work-order/src/api/zkxt/index.js
index 1b2f91b..6952651 100644
--- a/applications/task-work-order/src/api/zkxt/index.js
+++ b/applications/task-work-order/src/api/zkxt/index.js
@@ -53,4 +53,21 @@
 	})
 }
 
+// ai算法
+export const algorithmGroupedApi = (params) => {
+	return request({
+		url: `/webservice/webservice/algorithm/grouped`,
+		method: 'get',
+		params,
+	})
+}
+
+// 获取字典下拉 task_inspection_type
+export const getDictListApi = (str) => {
+	return request({
+		url: `/system/dict/data/type/${str}`,
+		method: 'get',
+	})
+}
+
 
diff --git a/applications/task-work-order/src/styles/common/cockpit.scss b/applications/task-work-order/src/styles/common/cockpit.scss
index 80a3512..fa358fb 100644
--- a/applications/task-work-order/src/styles/common/cockpit.scss
+++ b/applications/task-work-order/src/styles/common/cockpit.scss
@@ -1223,22 +1223,6 @@
 }
 
 .gd-dialog-form {
-  // 最后一排不需要设置 margin-bottom
-  // border: 1px solid red;
-  // 倒数第二个也设置为0
-  // .el-col:nth-last-child(2) {
-  //   margin-bottom: 0;
-  // }
-  // .el-col:nth-last-child(1) {
-  //   margin-bottom: 0;
-  // }
-
-  // .el-form-item:nth-last-child(2) {
-  //   margin-bottom: 0;
-  // }
-  //  .el-form-item:nth-last-child(1) {
-  //   margin-bottom: 0;
-  // }
   .gd-select {
     .el-select__wrapper {
       height: 36px;
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 a06920f..9e90a91 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
@@ -5,9 +5,9 @@
 				<el-table-column label="线索缩略图" width="120">
 					<template v-slot="{ row }">
 						<el-image
-							v-if="row.resultUrl"
-							:src="row.resultUrl"
-							:preview-src-list="[row.resultUrl]"
+							v-if="row.aiImg || row.resultUrl"
+							:src="row.aiImg || row.resultUrl"
+							:preview-src-list="[row.aiImg || row.resultUrl]"
 							fit="cover"
 							style="width: 80px; height: 60px"
 							preview-teleported
@@ -101,11 +101,90 @@
 	try {
 		const res = await gdTaskResultListApi({ patrolTaskId: currentRow.value.id })
 		list.value = res?.data?.data ?? []
+		list.value = await Promise.all(list.value.map(async i => {
+			const aiImg = await getAiImg(i.resultUrl)
+			return { ...i, aiImg }
+		}))
 	} finally {
 		loading.value = false
 	}
 }
 
+const aiFrame = [
+	"{\"score\":0.91357421875,\"bbox\":{\"x_cen\":1246.0,\"y_cen\":209.0,\"width\":166.0,\"height\":334.0},\"class_name\":\"car\",\"algorithmId\":\"e71116098eeb1d60cfebd04d30653b151\"}",
+	"{\"score\":0.89697265625,\"bbox\":{\"x_cen\":370.0,\"y_cen\":694.5,\"width\":162.0,\"height\":331.0},\"class_name\":\"car\",\"algorithmId\":\"e71116098eeb1d60cfebd04d30653b151\"}",
+	"{\"score\":0.89501953125,\"bbox\":{\"x_cen\":396.0,\"y_cen\":343.0,\"width\":168.0,\"height\":330.0},\"class_name\":\"car\",\"algorithmId\":\"e71116098eeb1d60cfebd04d30653b151\"}",
+	"{\"score\":0.79296875,\"bbox\":{\"x_cen\":409.5,\"y_cen\":52.5,\"width\":167.0,\"height\":105.0},\"class_name\":\"car\",\"algorithmId\":\"e71116098eeb1d60cfebd04d30653b151\"}"
+]
+
+function getAiImg(url) {
+	if (!url) return ''
+	const img = new Image()
+	img.crossOrigin = 'anonymous';
+	return new Promise(resolve => {
+		img.onload = () => {
+			if (!img.naturalWidth || !img.naturalHeight) {
+				resolve('')
+				return
+			}
+
+			const canvas = document.createElement('canvas')
+			const ctx = canvas.getContext('2d')
+			if (!ctx) {
+				resolve('')
+				return
+			}
+
+			canvas.width = img.naturalWidth
+			canvas.height = img.naturalHeight
+			ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
+
+			aiFrame.forEach(item => {
+				let target = item
+				try {
+					target = typeof item === 'string' ? JSON.parse(item) : item
+				} catch (error) {
+					return
+				}
+
+				const { x_cen, y_cen, width, height } = target.bbox || {}
+				if ([x_cen, y_cen, width, height].some(value => typeof value !== 'number')) return
+
+				const x = x_cen - width / 2
+				const y = y_cen - height / 2
+				const label = target.class_name || ''
+				const fontSize = Math.max(18, Math.round(canvas.width / 80))
+				const labelHeight = fontSize + 10
+				const labelY = y - labelHeight >= 0 ? y - labelHeight : y
+
+				ctx.strokeStyle = '#FF3B30'
+				ctx.lineWidth = Math.max(3, Math.round(canvas.width / 640))
+				ctx.strokeRect(x, y, width, height)
+
+				if (label) {
+					ctx.font = `${fontSize}px Arial`
+					const labelWidth = ctx.measureText(label).width + 16
+					ctx.fillStyle = '#FF3B30'
+					ctx.fillRect(x, labelY, labelWidth, labelHeight)
+					ctx.fillStyle = '#FFFFFF'
+					ctx.textBaseline = 'middle'
+					ctx.fillText(label, x + 8, labelY + labelHeight / 2)
+				}
+			})
+
+			try {
+				resolve(canvas.toDataURL('image/jpeg', 0.92))
+			} catch (error) {
+				console.log(error)
+				resolve('')
+			}
+		}
+		img.onerror = () => resolve('')
+		img.src = url
+	})
+}
+
+
 // 打开分发弹框
 function openDistributeDialog(row) {
 	distributeDialogVisible.value = true
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 17b0c7d..4808ea5 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
@@ -22,10 +22,10 @@
 					@change="handleSearch"
 				>
 					<el-option
-						v-for="item in dictObj.workOrderType"
-						:key="item.dictKey"
-						:label="item.dictValue"
-						:value="item.dictKey"
+						v-for="item in workOrderTypeXT"
+						:key="item.dictValue"
+						:label="item.dictLabel"
+						:value="item.dictValue"
 					/>
 				</el-select>
 			</el-form-item>
@@ -76,7 +76,7 @@
 					<el-table-column prop="taskNo" show-overflow-tooltip label="巡查任务编号" />
 					<el-table-column prop="patrolTaskType" show-overflow-tooltip label="巡查任务类型">
 						<template v-slot="{ row }">
-							{{ getDictLabel(row.patrolTaskType, dictObj.workOrderType) }}
+							{{ getDictLabelXT(row.patrolTaskType, workOrderTypeXT) }}
 						</template>
 					</el-table-column>
 					<el-table-column prop="taskStatus" show-overflow-tooltip label="巡查任务状态">
@@ -92,7 +92,7 @@
 					<el-table-column prop="taskDesc" show-overflow-tooltip label="巡查任务描述" />
 					<el-table-column label="操作" class-name="operation-btns">
 						<template v-slot="{ row }">
-							<el-link  type="primary"  @click="viewDiaLogView(row)">查看线索</el-link>
+							<el-link type="primary" @click="viewDiaLogView(row)">查看线索</el-link>
 						</template>
 					</el-table-column>
 				</el-table>
@@ -115,12 +115,14 @@
 </template>
 <script setup>
 import { Search, RefreshRight } from '@element-plus/icons-vue'
-import { onMounted, ref } from 'vue'
+import { computed, onMounted, ref } from 'vue'
 import { getDictionaryByCode } from '@/api/system/dictbiz'
-import { dateRangeFormat, getDictLabel } from '@ztzf/utils'
+import { dateRangeFormat, getDictLabel, getDictLabelXT } from '@ztzf/utils'
+import { getDictListApi } from '@/api/zkxt'
 import { gdPatrolTaskPageApi } from '../inspectionRequest/inspectionRequestApi'
 import { getDeptTree } from '@/api/system/dept'
 import ViewDiaLog from './ViewDiaLog.vue'
+import { useStore } from 'vuex'
 
 // 初始化查询参数
 const initSearchParams = () => ({
@@ -149,8 +151,10 @@
 	workOrderType: [], // 巡查任务类型
 	taskStatus: [], // 巡查任务状态
 })
+const workOrderTypeXT = ref([])
 
 provide('dictObj', dictObj)
+provide('workOrderTypeXT', workOrderTypeXT)
 provide('deptTree', deptTree)
 provide('treeProps', treeProps)
 
@@ -163,7 +167,7 @@
 			...searchParams.value,
 			startTime: range[0],
 			endTime: range[1],
-			taskStatus: 8
+			taskStatus: 8,
 		})
 		list.value = res?.data?.data?.records ?? []
 		total.value = res?.data?.data?.total ?? 0
@@ -199,11 +203,17 @@
 	getDictionaryByCode('workOrderType,taskStatus').then(res => {
 		dictObj.value = res.data.data
 	})
+	getDictListApi('task_inspection_type').then(res => {
+		workOrderTypeXT.value = res.data.data || []
+	})
 }
+
+const store = useStore()
+const userInfo = computed(() => store.state.user.userInfo)
 
 // 获取部门树
 function getDeptTreeFun() {
-	getDeptTree().then(res => {
+	getDeptTree(userInfo.value.dept_id).then(res => {
 		deptTree.value = res.data.data
 	})
 }
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 fca8cc3..24f51c2 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
@@ -5,10 +5,10 @@
 		:title="titleEnum[dialogMode]"
 		@closed="visible = false"
 		destroy-on-close
-		width="75%"
+		width="90%"
 		:close-on-click-modal="false"
 	>
-		<div class="gd-dialog-form">
+		<div>
 			<!-- 关联工单选择 -->
 			<div class="work-order-section">
 				<div class="detail-title" :style="{ marginBottom: 0, marginRight: pxToRem(10) }">选择工单</div>
@@ -33,7 +33,7 @@
 						<div class="info-item">
 							<span class="label">工单类型</span>
 							<span class="val" v-if="selectedWorkOrder">
-								{{ getDictLabel(selectedWorkOrder.workOrderType, dictObj.workOrderType) }}
+								{{ getDictLabelXT(selectedWorkOrder.workOrderType, workOrderTypeXT) }}
 							</span>
 							<span class="val grayText" v-else>选择工单后自动带出</span>
 						</div>
@@ -78,7 +78,7 @@
 						<el-table-column width="50" label="">
 							<template v-slot="{ $index }">{{ $index + 1 }}</template>
 						</el-table-column>
-						<el-table-column prop="patrolTaskName" min-width="120">
+						<el-table-column prop="patrolTaskName" min-width="100">
 							<template #header>
 								<span class="required-star">*</span>
 								巡查任务名称
@@ -92,7 +92,7 @@
 								/>
 							</template>
 						</el-table-column>
-						<el-table-column prop="patrolTaskType" min-width="140">
+						<el-table-column prop="patrolTaskType" min-width="100">
 							<template #header>
 								<span class="required-star">*</span>
 								巡查任务类型
@@ -106,15 +106,15 @@
 									@change="handlePatrolTaskTypeChange($index, $event)"
 								>
 									<el-option
-										v-for="item in dictObj.workOrderType"
-										:key="item.dictKey"
-										:label="item.dictValue"
-										:value="item.dictKey"
+										v-for="item in workOrderTypeXT"
+										:key="item.dictValue"
+										:label="item.dictLabel"
+										:value="item.dictValue"
 									/>
 								</el-select>
 							</template>
 						</el-table-column>
-						<el-table-column prop="executeTime" min-width="180">
+						<el-table-column prop="executeTime" width="200">
 							<template #header>
 								<span class="required-star">*</span>
 								任务执行时间
@@ -122,7 +122,7 @@
 							<template v-slot="{ row }">
 								<!--								gd-date-picker-popper-->
 								<el-date-picker
-									:style="{width: pxToRem(160)}"
+									:style="{width: pxToRem(165)}"
 									class="gd-date-picker"
 									popper-class=""
 									v-model="row.executeTime"
@@ -133,7 +133,7 @@
 								/>
 							</template>
 						</el-table-column>
-						<el-table-column prop="patrolRouteUrl" min-width="120">
+						<el-table-column prop="patrolRouteUrl" min-width="100">
 							<template #header>
 								<span class="required-star">*</span>
 								巡查任务航线
@@ -152,7 +152,7 @@
 								</el-select>
 							</template>
 						</el-table-column>
-						<el-table-column prop="recommendFlyerName" min-width="120">
+						<el-table-column prop="deviceFlyerId" min-width="100">
 							<template #header>
 								<span class="required-star">*</span>
 								推荐飞手
@@ -162,16 +162,17 @@
 									no-data-text="暂无推荐飞手"
 									class="gd-select"
 									popper-class="gd-select-popper"
-									v-model="row.recommendFlyerName"
+									v-model="row.deviceFlyerId"
 									placeholder="请选择"
 									filterable
 									:disabled="dialogReadonly || !taskList[$index].patrolTaskType"
+
 								>
 									<el-option
 										v-for="item in flyerListMap[$index] || []"
-										:key="item.id"
+										:key="item.flyerId"
 										:label="item.flyerName"
-										:value="item.flyerName"
+										:value="item.flyerId"
 									>
 										<template #default>
 										<!-- 匹配区域=1 显示红星号 -->
@@ -182,7 +183,7 @@
 									</el-select>
 							</template>
 						</el-table-column>
-						<el-table-column prop="deviceId" min-width="120">
+						<el-table-column prop="deviceId" min-width="100">
 							<template #header>
 								<span class="required-star">*</span>
 								选择设备
@@ -200,7 +201,31 @@
 								</el-select>
 							</template>
 						</el-table-column>
-						<el-table-column prop="taskDesc" label="巡查任务描述" min-width="120">
+						<el-table-column prop="algorithmIds" min-width="160">
+							<template #header>
+								算法
+							</template>
+							<template v-slot="{ row }">
+								<el-tree-select
+									class="gd-select"
+									popper-class="gd-tree-select-popper"
+									v-model="row.algorithmIds"
+									:data="algorithmTreeData"
+									:props="{ label: 'name', children: 'children', value: 'id' }"
+									node-key="id"
+									multiple
+									collapse-tags
+									collapse-tags-tooltip
+									check-strictly
+									filterable
+									placeholder="请选择"
+									:disabled="dialogReadonly"
+								/>
+							</template>
+						</el-table-column>
+
+
+						<el-table-column prop="taskDesc" label="巡查任务描述">
 							<template v-slot="{ row }">
 								<el-input class="gd-input" v-model="row.taskDesc" placeholder="请输入" :disabled="dialogReadonly" />
 							</template>
@@ -240,15 +265,16 @@
 </template>
 
 <script setup>
-import { computed, ref, onMounted } from 'vue'
+import { computed, ref, onMounted, inject } from 'vue'
 import { ElMessage } from 'element-plus'
 import { Plus, Delete } from '@element-plus/icons-vue'
-import { geomAnalysis, getDictLabel } from '@ztzf/utils'
+import { geomAnalysis, getDictLabel, getDictLabelXT } from '@ztzf/utils'
+
 import { gdPatrolTaskSaveApi, gdFlyerPageApi, gdPatrolTaskAuditApi } from './inspectionRequestApi'
 import { gdWorkOrderPageApi } from '../orderManage/orderManageApi'
 import { gdManageDeviceListApi } from '../orderManage/gdManageDeviceApi'
 import { pxToRem } from '@/utils/rem'
-import { airlineListApi } from '@/api/zkxt'
+import { airlineListApi, algorithmGroupedApi } from '@/api/zkxt'
 
 // 初始化任务行
 const initTaskRow = () => ({
@@ -256,8 +282,9 @@
 	patrolTaskType: '',
 	executeTime: '',
 	patrolRouteUrl: '',
-	recommendFlyerName: '',
+	deviceFlyerId: '',
 	deviceId: null,
+	algorithmIds: [],
 	taskDesc: '',
 })
 const dictObj = inject('dictObj')
@@ -278,6 +305,27 @@
 const deviceList = ref([]) // 设备列表
 const routeOptions = ref([]) // 航线选项(根据工单范围获取)
 const routeLoading = ref(false) // 航线加载中
+const algorithmTreeData = ref([]) // 算法树形数据
+const workOrderTypeXT = inject('workOrderTypeXT', ref([]))
+
+// 获取算法分组数据
+async function getAlgorithmList() {
+	try {
+		const res = await algorithmGroupedApi()
+		const list = res?.data?.data ?? []
+		algorithmTreeData.value = list.map(group => ({
+			id: 'group_' + group.type,
+			name: group.type,
+			disabled: true,
+			children: (group.algorithms || []).map(alg => ({
+				id: alg.id,
+				name: alg.name,
+			}))
+		}))
+	} catch (e) {
+		console.error('获取算法列表失败', e)
+	}
+}
 
 // 子任务列表
 const taskList = ref([initTaskRow()])
@@ -369,10 +417,12 @@
 // 处理巡查任务类型变化
 async function handlePatrolTaskTypeChange(index, skilledTaskType) {
 	// 清空该行已选择的飞手
-	taskList.value[index].recommendFlyerName = ''
+	taskList.value[index].deviceFlyerId = ''
 	// 获取对应的飞手列表
 	await getFlyerList(index, skilledTaskType)
 }
+
+
 
 import * as turf from '@turf/turf'
 
@@ -416,7 +466,7 @@
 
 // 判断一行是否已填写(至少填写了任务名称)
 function isTaskRowFilled(task) {
-	return !!(task.patrolTaskName || task.executeTime || task.patrolRouteUrl || task.recommendFlyerName || task.deviceId)
+	return !!(task.patrolTaskName || task.executeTime || task.patrolRouteUrl || task.deviceFlyerId || task.deviceId)
 }
 
 // 提交新增
@@ -453,7 +503,7 @@
 			ElMessage.warning(`第${i + 1}行: 请选择巡查任务航线`)
 			return
 		}
-		if (!task.recommendFlyerName) {
+		if (!task.deviceFlyerId) {
 			ElMessage.warning(`第${i + 1}行: 请选择推荐飞手`)
 			return
 		}
@@ -485,6 +535,8 @@
 async function open({ mode = 'add', row } = {}) {
 	dialogMode.value = mode
 	await getWorkOrderList()
+	getAlgorithmList()
+
 	if (dialogMode.value === 'add') {
 		selectedWorkOrderId.value = null
 		selectedWorkOrder.value = null
diff --git a/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue b/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue
index 4ba9521..ec7a7b3 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue
@@ -42,7 +42,7 @@
 						</el-col>
 						<el-col :span="12">
 							<div class="label">巡查任务类型</div>
-							<div class="val">{{ getDictLabel(formData.patrolTaskType, dictObj.workOrderType) }}</div>
+							<div class="val">{{ getDictLabelXT(formData.patrolTaskType, workOrderTypeXT) }}</div>
 						</el-col>
 						<el-col :span="12">
 							<div class="label">任务执行时间</div>
@@ -58,7 +58,7 @@
 						</el-col>
 						<el-col :span="12">
 							<div class="label">推荐飞手</div>
-							<div class="val">{{ formData.recommendFlyerName }}</div>
+							<div class="val">{{ getFlyerName(formData.deviceFlyerId) }}</div>
 						</el-col>
 						<el-col :span="12">
 							<div class="label">选择设备</div>
@@ -71,6 +71,10 @@
 						<el-col :span="12">
 							<div class="label">巡查任务描述</div>
 							<div class="val">{{ formData.taskDesc }}</div>
+						</el-col>
+						<el-col :span="12">
+							<div class="label">算法</div>
+							<div class="val">{{ getAlgorithmNames(formData.algorithmIds) }}</div>
 						</el-col>
 					</el-row>
 					<template v-if="['6', '7', '8'].includes(taskStatus)">
@@ -115,10 +119,10 @@
 									clearable
 								>
 									<el-option
-										v-for="item in dictObj.workOrderType"
-										:key="item.dictKey"
-										:label="item.dictValue"
-										:value="item.dictKey"
+										v-for="item in workOrderTypeXT"
+										:key="item.dictValue"
+										:label="item.dictLabel"
+										:value="item.dictValue"
 									/>
 								</el-select>
 							</el-form-item>
@@ -149,16 +153,16 @@
 							</el-form-item>
 						</el-col>
 						<el-col :span="12">
-							<el-form-item label="推荐飞手" prop="recommendFlyerName">
+							<el-form-item label="推荐飞手" prop="deviceFlyerId">
 								<el-select
 									class="gd-select"
 									popper-class="gd-select-popper"
-									v-model="formData.recommendFlyerName"
+									v-model="formData.deviceFlyerId"
 									placeholder="请选择"
 									filterable
 									clearable
 								>
-									<el-option v-for="item in flyerList" :key="item.id" :label="item.flyerName" :value="item.flyerName" />
+									<el-option v-for="item in flyerList" :key="item.id" :label="item.flyerName" :value="item.flyerId" />
 								</el-select>
 							</el-form-item>
 						</el-col>
@@ -179,6 +183,26 @@
 						<el-col :span="12">
 							<el-form-item label="关联工单">
 								<span>{{ getWorkOrderName(formData.workOrderId) }}</span>
+							</el-form-item>
+						</el-col>
+						<!-- 算法下拉 -->
+						<el-col :span="12">
+							<el-form-item label="算法" prop="algorithmIds">
+								<el-tree-select
+									class="gd-select"
+									popper-class="gd-tree-select-popper"
+									v-model="formData.algorithmIds"
+									:data="algorithmTreeData"
+									:props="{ label: 'name', children: 'children', value: 'id' }"
+									node-key="id"
+									multiple
+									collapse-tags
+									collapse-tags-tooltip
+									check-strictly
+									filterable
+									clearable
+									placeholder="请选择"
+								/>
 							</el-form-item>
 						</el-col>
 						<el-col :span="24">
@@ -212,7 +236,7 @@
 			</div>
 		</div>
 
-		<template #footer>
+		<template #footer v-if="detailLoaded">
 			<el-button v-if="['1', '4', '7'].includes(taskStatus)" @click="viewDescription" color="#F2F3F5">
 				{{ gdStatusObj[taskStatus].reason }}
 			</el-button>
@@ -260,9 +284,9 @@
 </template>
 
 <script setup>
-import { computed, ref, onMounted } from 'vue'
+import { computed, ref, onMounted, inject } from 'vue'
 import { ElMessage } from 'element-plus'
-import { fieldRules, flyVisual, getDictLabel, geomAnalysis } from '@ztzf/utils'
+import { fieldRules, flyVisual, getDictLabel, getDictLabelXT, geomAnalysis } from '@ztzf/utils'
 import {
 	gdPatrolTaskRepublish,
 	gdFlyerPageApi,
@@ -276,7 +300,7 @@
 import { gdTaskResultListApi } from '@/views/orderView/orderManage/clueEvents/achievementApi'
 import RefuseOrderDialog1 from '@/views/orderView/orderManage/inspectionRequest/RefuseOrderDialog1.vue'
 import { Check } from '@element-plus/icons-vue'
-import { queryAirById, airlineListApi } from '@/api/zkxt'
+import { queryAirById, airlineListApi, algorithmGroupedApi } from '@/api/zkxt'
 import * as Cesium from 'cesium'
 import { useStore } from 'vuex'
 
@@ -287,8 +311,9 @@
 	patrolTaskType: '',
 	executeTime: '',
 	patrolRouteUrl: '',
-	recommendFlyerName: '',
+	deviceFlyerId: null,
 	deviceId: null,
+	algorithmIds: [],
 	taskDesc: '',
 	workOrderId: null,
 })
@@ -304,6 +329,7 @@
 const visible = defineModel()
 const dialogMode = ref('view')
 const submitting = ref(false)
+const detailLoaded = ref(false)
 const dialogReadonly = computed(() => dialogMode.value === 'view')
 const titleEnum = ref({ edit: '编辑', view: '查看' })
 const taskStatus = computed(() => formData.value.taskStatus)
@@ -316,6 +342,38 @@
 const getAirName = id => {
 	const item = routeOptions.value.find(item => item.id === id)
 	return item ? item.name : id
+}
+
+const algorithmTreeData = ref([]) // 算法树形数据
+const workOrderTypeXT = inject('workOrderTypeXT', ref([]))
+
+// 获取算法分组数据
+async function getAlgorithmList() {
+	try {
+		const res = await algorithmGroupedApi()
+		const list = res?.data?.data ?? []
+		algorithmTreeData.value = list.map(group => ({
+			id: 'group_' + group.type,
+			name: group.type,
+			disabled: true,
+			children: (group.algorithms || []).map(alg => ({
+				id: alg.id,
+				name: alg.name,
+			}))
+		}))
+	} catch (e) {
+		console.error('获取算法列表失败', e)
+	}
+}
+
+// 根据 algorithmIds 数组获取算法名称,逗号分割回显
+function getAlgorithmNames(algorithmIds) {
+	if (!algorithmIds || !algorithmIds.length) return ''
+	const allAlgorithms = algorithmTreeData.value.flatMap(group => group.children || [])
+	return algorithmIds.map(id => {
+		const item = allAlgorithms.find(alg => alg.id === id)
+		return item ? item.name : id
+	}).join(', ')
 }
 
 const gdStatusObj = {
@@ -338,7 +396,7 @@
 	patrolTaskType: fieldRules(true),
 	executeTime: fieldRules(true),
 	patrolRouteUrl: fieldRules(true),
-	recommendFlyerName: fieldRules(true),
+	deviceFlyerId: fieldRules(true),
 	deviceId: fieldRules(true),
 }
 
@@ -382,6 +440,12 @@
 function getDeviceName(id) {
 	const item = deviceList.value.find(item => item.id === id)
 	return item ? item.nickname : id
+}
+
+// 获取飞手名称
+function getFlyerName(id) {
+	const item = flyerList.value.find(item => item.flyerId === id)
+	return item ? item.flyerName : id
 }
 
 // 获取工单名称
@@ -515,9 +579,20 @@
 
 // 打开弹框
 async function open({ mode = 'view', row } = {}) {
+	detailLoaded.value = false
 	dialogMode.value = mode
+
 	const res = await gdPatrolTaskDetailApi({ id: row.id })
 	formData.value = { ...initForm(), ...res.data.data }
+	// 确保 algorithmIds 是数组
+	if (formData.value.algorithmIds && typeof formData.value.algorithmIds === 'string') {
+		formData.value.algorithmIds = formData.value.algorithmIds.split(',').filter(Boolean)
+	} else if (!formData.value.algorithmIds) {
+		formData.value.algorithmIds = []
+	}
+	detailLoaded.value = true
+	// 获取算法列表
+	getAlgorithmList()
 	// 获取工单详情并根据geom范围获取航线列表
 	await getWorkOrderDetail(formData.value.workOrderId)
 	;['6', '7', '8'].includes(row.taskStatus) && await getTaskResultList()
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 9535e60..4f0e1c6 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
@@ -13,8 +13,8 @@
 			<el-form-item label="任务类型" prop="patrolTaskType">
 				<el-select class="gd-select gray" popper-class="gd-select-popper" v-model="searchParams.patrolTaskType"
 					placeholder="请选择" clearable @change="handleSearch">
-					<el-option v-for="item in dictObj.workOrderType" :key="item.dictKey" :label="item.dictValue"
-						:value="item.dictKey" />
+					<el-option v-for="item in workOrderTypeXT" :key="item.dictValue" :label="item.dictLabel"
+						:value="item.dictValue" />
 				</el-select>
 			</el-form-item>
 
@@ -55,7 +55,7 @@
 					<el-table-column prop="taskNo" show-overflow-tooltip label="巡查任务编号" />
 					<el-table-column prop="patrolTaskType" show-overflow-tooltip label="巡查任务类型">
 						<template v-slot="{ row }">
-							{{ getDictLabel(row.patrolTaskType, dictObj.workOrderType) }}
+							{{ getDictLabelXT(row.patrolTaskType, workOrderTypeXT) }}
 						</template>
 					</el-table-column>
 					<el-table-column prop="taskStatus" show-overflow-tooltip label="巡查任务状态">
@@ -93,7 +93,8 @@
 import { onMounted, ref } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { getDictionaryByCode } from '@/api/system/dictbiz'
-import { dateRangeFormat, getDictLabel } from '@ztzf/utils'
+import { dateRangeFormat, getDictLabel, getDictLabelXT } from '@ztzf/utils'
+import { getDictListApi } from '@/api/zkxt'
 import FormDiaLog from './FormDiaLog.vue'
 import { gdPatrolTaskPageApi, gdPatrolTaskRemoveApi } from './inspectionRequestApi'
 import ViewDiaLog from '@/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue'
@@ -130,8 +131,10 @@
 	deviceLoadDemand: [], // 设备负载需求
 	taskStatus: [], // 巡查任务状态
 })
+const workOrderTypeXT = ref([])
 const activeName = ref('all')
 provide('dictObj', dictObj)
+provide('workOrderTypeXT', workOrderTypeXT)
 
 const colors = {
 	0: '#F6A000',//0待签收
@@ -213,6 +216,9 @@
 	getDictionaryByCode('workOrderType,deviceLoadDemand,taskStatus').then(res => {
 		dictObj.value = res.data.data
 	})
+	getDictListApi('task_inspection_type').then(res => {
+		workOrderTypeXT.value = res.data.data || []
+	})
 }
 
 function refusalAccept (row) {
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 8fa1848..6abe86f 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
@@ -1,6 +1,6 @@
 <template>
 	<el-dialog
-		class="gd-dialog"
+		class="gd-dialog orderManageFormDlg"
 		v-model="visible"
 		:title="titleEnum[dialogMode]"
 		@closed="visible = false"
@@ -31,7 +31,7 @@
 						</el-col>
 						<el-col :span="12">
 							<div class="label">工单类型</div>
-							<div class="val">{{ getDictLabel(formData.workOrderType, dictObj.workOrderType) }}</div>
+							<div class="val">{{ getDictLabelXT(formData.workOrderType, workOrderTypeXT) }}</div>
 						</el-col>
 						<el-col :span="12">
 							<div class="label">执行时间范围</div>
@@ -62,7 +62,7 @@
 							<el-table-column prop="patrolTaskName" show-overflow-tooltip label="巡查任务名称" />
 							<el-table-column prop="patrolTaskType" show-overflow-tooltip label="巡查任务类型">
 								<template v-slot="{ row }">
-									{{ getDictLabel(row.patrolTaskType, dictObj.workOrderType) }}
+									{{ getDictLabelXT(row.patrolTaskType, workOrderTypeXT) }}
 								</template>
 							</el-table-column>
 							<el-table-column prop="taskStatus" show-overflow-tooltip label="任务状态">
@@ -102,10 +102,10 @@
 									clearable
 								>
 									<el-option
-										v-for="item in dictObj.workOrderType"
-										:key="item.dictKey"
-										:label="item.dictValue"
-										:value="item.dictKey"
+										v-for="item in workOrderTypeXT"
+										:key="item.dictValue"
+										:label="item.dictLabel"
+										:value="item.dictValue"
 									/>
 								</el-select>
 							</el-form-item>
@@ -156,7 +156,7 @@
 						</el-col>
 					</el-row>
 				</el-form>
-				<div class="detail-title" :style="{ marginTop: pxToRem(20) }">
+				<div class="detail-title" :style="{ marginTop: pxToRem(10) }">
 					<span class="required-star" v-if="!dialogReadonly">*</span>
 					工单执行范围
 				</div>
@@ -195,7 +195,7 @@
 			</div>
 		</div>
 
-		<template #footer v-if="activeName === 'basic'">
+		<template #footer v-if="activeName === 'basic' && detailLoaded">
 			<el-button v-if="['11', '21', '23', '31', '60'].includes(gdStatus)" @click="viewDescription" color="#F2F3F5">
 				{{ gdStatusObj[gdStatus]?.reason }}
 			</el-button>
@@ -262,9 +262,9 @@
 </template>
 
 <script setup>
-import { computed, ref, nextTick } from 'vue'
+import { computed, ref, nextTick, inject } from 'vue'
 import { ElMessage } from 'element-plus'
-import { dateRangeFormat, fieldRules, flyVisual, geomAnalysis, getDictLabel } from '@ztzf/utils'
+import { dateRangeFormat, fieldRules, flyVisual, geomAnalysis, getDictLabel, getDictLabelXT } from '@ztzf/utils'
 import {
 	gdWorkOrderDetailApi,
 	gdWorkOrderFlowListApi,
@@ -286,6 +286,7 @@
 import { useStore } from 'vuex'
 import OrderStepBar from '@/views/orderView/orderManage/orderManage/OrderStepBar.vue'
 import OutcomeData from './outcomeData.vue'
+import { getDictListApi } from '@/api/zkxt'
 const store = useStore()
 const permission = computed(() => store.state.user.permission)
 const activeName = ref('basic')
@@ -305,6 +306,7 @@
 const mapRef = ref(null)
 const rejectVisible = ref(false)
 const dictObj = inject('dictObj')
+const workOrderTypeXT = inject('workOrderTypeXT', ref([]))
 const dateRange = ref([])
 const patrolTaskList = ref([])
 const emit = defineEmits(['success'])
@@ -313,6 +315,7 @@
 const visible = defineModel() // 弹框显隐
 const dialogMode = ref('add') // 弹框模式
 const submitting = ref(false) // 提交中
+const detailLoaded = ref(false) // 详情加载完成
 const dialogReadonly = computed(() => dialogMode.value === 'view')
 const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' })
 const deviceList = ref([]) // 设备列表
@@ -631,6 +634,7 @@
 
 // 打开弹框
 async function open({ mode = 'add', row } = {}) {
+	detailLoaded.value = false
 	dialogMode.value = mode
 	getPayloadList()
 	initMap()
@@ -645,6 +649,7 @@
 		hasPatrolTaskList.value && gdPatrolTaskPage()
 		dialogMode.value === 'edit' ? editPolygon() : viewPolygon()
 	}
+	detailLoaded.value = true
 
 	await nextTick()
 	await getDeviceList()
@@ -691,7 +696,20 @@
 defineExpose({ open })
 </script>
 
-<style lang="scss" scoped>
+<style lang="scss">
+.orderManageFormDlg{
+		.el-dialog__body{
+			display: flex;
+			flex-direction: column;
+			.content{
+				height: 0;
+				flex: 1;
+			}
+		}
+}
+</style>
+
+<style scoped lang="scss">
 .separateTable {
 	height: 0;
 	flex: 1;
@@ -704,10 +722,12 @@
 		}
 	}
 }
+
+
 .content {
 	display: flex;
 	gap: 0 20px;
-	height: 630px;
+	//height: 630px;
 
 	.leftBox {
 		width: 0;
@@ -718,10 +738,9 @@
 
 		.gd-cesium {
 			position: relative;
-			overflow: hidden;
+			//overflow: hidden;
 			width: 100%;
-			min-height: 360px;
-			flex: 1;
+			height: 390px;
 		}
 	}
 
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 d52524c..8138358 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
@@ -13,8 +13,8 @@
 			<el-form-item label="工单类型" prop="workOrderType">
 				<el-select class="gd-select gray" popper-class="gd-select-popper" v-model="searchParams.workOrderType"
 					placeholder="请选择" clearable @change="handleSearch">
-					<el-option v-for="item in dictObj.workOrderType" :key="item.dictKey" :label="item.dictValue"
-						:value="item.dictKey" />
+					<el-option v-for="item in workOrderTypeXT" :key="item.dictValue" :label="item.dictLabel"
+						:value="item.dictValue" />
 				</el-select>
 			</el-form-item>
 
@@ -53,7 +53,7 @@
 					<el-table-column prop="workOrderCode" show-overflow-tooltip label="工单编号" />
 					<el-table-column prop="workOrderType" show-overflow-tooltip label="工单类型">
 						<template v-slot="{ row }">
-							{{ getDictLabel(row.workOrderType, dictObj.workOrderType) }}
+							{{ getDictLabelXT(row.workOrderType, workOrderTypeXT) }}
 						</template>
 					</el-table-column>
 					<el-table-column prop="status" show-overflow-tooltip label="阶段状态">
@@ -102,7 +102,8 @@
 import { onMounted, ref } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { getDictionaryByCode } from '@/api/system/dictbiz'
-import { dateRangeFormat, getDictLabel } from '@ztzf/utils'
+import { dateRangeFormat, getDictLabel, getDictLabelXT } from '@ztzf/utils'
+import { getDictListApi } from '@/api/zkxt'
 import FormDiaLog from './FormDiaLog.vue'
 import { gdWorkOrderPageApi, gdWorkOrderRemoveApi } from './orderManageApi'
 import dayjs from 'dayjs'
@@ -143,7 +144,9 @@
 	workOrderType: [], // 工单类型
 	workOrderStatus: [], // 工单状态
 })
+const workOrderTypeXT = ref([])
 provide('dictObj', dictObj)
+provide('workOrderTypeXT', workOrderTypeXT)
 
 // 获取列表
 async function getList () {
@@ -246,6 +249,9 @@
 	getDictionaryByCode('deviceLoadDemand,workOrderType,workOrderStatus,taskStatus').then(res => {
 		dictObj.value = res.data.data
 	})
+	getDictListApi('task_inspection_type').then(res => {
+		workOrderTypeXT.value = res.data.data || []
+	})
 }
 
 // 获取两个tab的总条数
diff --git a/packages/utils/common/index.js b/packages/utils/common/index.js
index c213e19..b7e1e97 100644
--- a/packages/utils/common/index.js
+++ b/packages/utils/common/index.js
@@ -38,6 +38,16 @@
 		.join(',');
 }
 
+// id转label xt
+export function getDictLabelXT(value, dictList = []) {
+	if (value === null || value === undefined || value === '') return '';
+	const values = String(value).split(',');
+	return dictList
+		.filter(item => values.includes(String(item.dictValue)))
+		.map(item => item.dictLabel)
+		.join(',');
+}
+
 export function blobDownload(res) {
 	const disposition = res.headers?.['content-disposition'] || res.headers?.['Content-Disposition']
 	const encodedName = disposition.split('filename=')[1]
diff --git a/uniapps/work-app/src/pages/login/index.vue b/uniapps/work-app/src/pages/login/index.vue
index 568b316..42f5775 100644
--- a/uniapps/work-app/src/pages/login/index.vue
+++ b/uniapps/work-app/src/pages/login/index.vue
@@ -201,8 +201,8 @@
     tenantId: "000000",
     deptId: "",
     roleId: "",
-    username: loginFormGd.value.username,
-    password: loginFormGd.value.password,
+    username: loginForm.value.username,
+    password: loginForm.value.username === 'admin' ? 'admin' : 'jadk@2026',
     type: "account",
     code: "",
     key: "",

--
Gitblit v1.9.3