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