<template>
|
<el-dialog
|
class="gd-dialog"
|
v-model="visible"
|
:title="titleEnum[dialogMode]"
|
@closed="visible = false"
|
destroy-on-close
|
:close-on-click-modal="false"
|
width="80%"
|
>
|
<div class="detail-container" style="display: flex">
|
<div class="detail-left" v-if="dialogMode !== 'add' && processList.length">
|
<el-timeline class="gd-timeline">
|
<el-timeline-item
|
v-for="(activity, index) in processList"
|
:key="index"
|
:icon="Check"
|
:type="index === processList.length - 1 ? 'success' : 'info'"
|
:color="activity.color"
|
:hollow="activity.hollow"
|
:timestamp="activity.createTime"
|
>
|
<div class="item-content">
|
<div>{{ activity.operator }}</div>
|
<div class="flowName">{{ activity.flowName }}</div>
|
</div>
|
</el-timeline-item>
|
</el-timeline>
|
</div>
|
|
<div class="detail-right">
|
<!-- 查看模式 -->
|
<div class="view-container" v-if="dialogReadonly">
|
<div class="detail-title">巡查任务详情</div>
|
<el-row class="detail-row-view">
|
<el-col :span="12">
|
<div class="label">巡查任务名称</div>
|
<div class="val">{{ formData.patrolTaskName }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">巡查任务类型</div>
|
<div class="val">{{ getDictLabel(formData.patrolTaskType, dictObj.workOrderType) }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">任务执行时间</div>
|
<div class="val">{{ formData.executeTime }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">巡查任务航线</div>
|
<div class="val val-long">
|
<el-tooltip :content="getAirName(formData.patrolRouteUrl)" placement="top">
|
{{ getAirName(formData.patrolRouteUrl) }}
|
</el-tooltip>
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">推荐飞手</div>
|
<div class="val">{{ formData.recommendFlyerName }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">选择设备</div>
|
<div class="val">{{ getDeviceName(formData.deviceId) }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">关联工单</div>
|
<div class="val">{{ getWorkOrderName(formData.workOrderId) }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">巡查任务描述</div>
|
<div class="val">{{ formData.taskDesc }}</div>
|
</el-col>
|
</el-row>
|
<template v-if="['6', '7', '8'].includes(taskStatus)">
|
<div class="detail-title" :style="{ marginTop: pxToRem(10) }">
|
任务成果({{ taskResultList.length || 0 }}条)
|
</div>
|
<div class="imgBox">
|
<div v-for="item in taskResultList">
|
<el-image
|
v-if="item.resultUrl"
|
:src="item.resultUrl"
|
:preview-src-list="[item.resultUrl]"
|
fit="cover"
|
preview-teleported
|
/>
|
</div>
|
</div>
|
</template>
|
</div>
|
|
<!-- 编辑模式 -->
|
<el-form class="gd-dialog-form" v-else ref="formRef" :model="formData" :rules="rules" label-width="110px">
|
<el-row>
|
<el-col :span="12">
|
<el-form-item label="巡查任务名称" prop="patrolTaskName">
|
<el-input class="gd-input" v-model="formData.patrolTaskName" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="巡查任务类型" prop="patrolTaskType">
|
<el-select
|
class="gd-select"
|
popper-class="gd-select-popper"
|
v-model="formData.patrolTaskType"
|
placeholder="请选择"
|
clearable
|
>
|
<el-option
|
v-for="item in dictObj.workOrderType"
|
:key="item.dictKey"
|
:label="item.dictValue"
|
:value="item.dictKey"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="任务执行时间" prop="executeTime">
|
<el-date-picker
|
class="gd-date-picker"
|
popper-class="gd-date-picker-popper"
|
v-model="formData.executeTime"
|
type="datetime"
|
placeholder="请选择"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="巡查任务航线" prop="patrolRouteUrl">
|
<el-select
|
class="gd-select"
|
popper-class="gd-select-popper"
|
v-model="formData.patrolRouteUrl"
|
placeholder="请选择"
|
clearable
|
@change="getAirDetails"
|
>
|
<el-option v-for="item in routeOptions" :key="item.id" :label="item.name" :value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="推荐飞手" prop="recommendFlyerName">
|
<el-select
|
class="gd-select"
|
popper-class="gd-select-popper"
|
v-model="formData.recommendFlyerName"
|
placeholder="请选择"
|
filterable
|
clearable
|
>
|
<el-option v-for="item in flyerList" :key="item.id" :label="item.flyerName" :value="item.flyerName" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="选择设备" prop="deviceId">
|
<el-select
|
class="gd-select"
|
popper-class="gd-select-popper"
|
v-model="formData.deviceId"
|
placeholder="请选择"
|
filterable
|
clearable
|
>
|
<el-option v-for="item in deviceList" :key="item.id" :label="item.nickname" :value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="关联工单">
|
<span>{{ getWorkOrderName(formData.workOrderId) }}</span>
|
</el-form-item>
|
</el-col>
|
<el-col :span="24">
|
<el-form-item label="巡查任务描述" prop="taskDesc">
|
<el-input
|
class="gd-input"
|
type="textarea"
|
:rows="4"
|
v-model="formData.taskDesc"
|
placeholder="请输入"
|
clearable
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
|
<div class="detail-title" :style="{ marginTop: pxToRem(10) }">任务航线</div>
|
<!-- 地图组件 -->
|
<CommonCesiumMap
|
ref="mapRef"
|
class="gd-cesium"
|
:active="visible"
|
:flat-mode="false"
|
:terrain="true"
|
:layer-mode="4"
|
:boundary="false"
|
:zoomToBoundary="false"
|
@ready="readyMap"
|
/>
|
</div>
|
</div>
|
|
<template #footer>
|
<el-button v-if="['1', '4', '7'].includes(taskStatus)" @click="viewDescription" color="#F2F3F5">
|
{{ gdStatusObj[taskStatus].reason }}
|
</el-button>
|
<el-button @click="statusChange(3)" v-if="taskStatus === '3' && permission.flyOrder_revoke" color="#4C34FF">
|
撤回任务
|
</el-button>
|
|
<template v-if="permission.flyOrder_controlAcceptance">
|
<el-button @click="refusalToAccept" v-if="taskStatus === '6'" color="#F2F3F5">拒绝验收</el-button>
|
<el-button @click="statusChange(6)" v-if="taskStatus === '6'" color="#4C34FF">验收通过</el-button>
|
</template>
|
<el-button
|
v-if="!dialogReadonly || (['1', '4'].includes(taskStatus) && permission.flyOrder_add)"
|
:loading="submitting"
|
:disabled="submitting"
|
color="#4C34FF"
|
@click="handleSubmit"
|
>
|
提交
|
</el-button>
|
<template v-if="permission.flyOrder_controlSignFor">
|
<el-button v-if="taskStatus === '0'" @click="addDescription" color="#F2F3F5">拒绝签收</el-button>
|
<el-button v-if="taskStatus === '0'" @click="statusChange(1)" color="#4C34FF">签收</el-button>
|
</template>
|
<template v-if="permission.flyOrder_controlReview">
|
<el-button v-if="taskStatus === '3'" @click="addDescription" color="#F2F3F5">驳回</el-button>
|
<el-button v-if="taskStatus === '3'" @click="statusChange(4)" color="#4C34FF">同意</el-button>
|
</template>
|
</template>
|
<RefuseOrderDialog1
|
ref="refuseOrderDialogRef"
|
v-if="rejectVisible"
|
v-model="rejectVisible"
|
@success="rejectSuccess"
|
/>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import { computed, ref, onMounted } from 'vue'
|
import { ElMessage } from 'element-plus'
|
import { fieldRules, flyVisual, getDictLabel } from '@ztzf/utils'
|
import { gdPatrolTaskRepublish, gdFlyerPageApi, gdPatrolTaskAuditApi } from './inspectionRequestApi'
|
import { gdWorkOrderFlowListApi, gdWorkOrderFlowPatrolListApi, gdWorkOrderPageApi } from '../orderManage/orderManageApi'
|
import { gdManageDeviceListApi } from '../orderManage/gdManageDeviceApi'
|
import { pxToRem } from '@/utils/rem'
|
import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue'
|
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 } from '@/api/zkxt'
|
import * as Cesium from 'cesium'
|
import { useStore } from 'vuex'
|
|
// 初始化表单数据
|
const initForm = () => ({
|
id: null,
|
patrolTaskName: '',
|
patrolTaskType: '',
|
executeTime: '',
|
patrolRouteUrl: '',
|
recommendFlyerName: '',
|
deviceId: null,
|
taskDesc: '',
|
workOrderId: null,
|
})
|
const store = useStore()
|
const permission = computed(() => store.state.user.permission)
|
|
const rejectVisible = ref(false)
|
const mapRef = ref(null)
|
const dictObj = inject('dictObj')
|
const emit = defineEmits(['success', 'refusalAccept'])
|
const formRef = ref(null)
|
const formData = ref(initForm())
|
const visible = defineModel()
|
const dialogMode = ref('view')
|
const submitting = ref(false)
|
const dialogReadonly = computed(() => dialogMode.value === 'view')
|
const titleEnum = ref({ edit: '编辑', view: '查看' })
|
const taskStatus = computed(() => formData.value.taskStatus)
|
const refuseOrderDialogRef = ref(null)
|
|
// 下拉选项
|
const flyerList = ref([])
|
const deviceList = ref([])
|
const workOrderList = ref([])
|
const routeOptions = inject('routeOptions')
|
const getAirName = inject('getAirName')
|
|
const gdStatusObj = {
|
'0': { reason: '拒绝原因', operationType: '2' },
|
'1': { reason: '拒绝原因' },
|
'2': { reason: '' },
|
'3': { reason: '驳回原因', operationType: '5' },
|
'4': { reason: '驳回原因' },
|
'5': { reason: '' },
|
'6': { reason: '拒绝原因' },
|
'7': { reason: '拒绝原因' },
|
'8': { reason: '' },
|
}
|
|
let viewer
|
|
// 校验规则
|
const rules = {
|
patrolTaskName: fieldRules(true, 50),
|
patrolTaskType: fieldRules(true),
|
executeTime: fieldRules(true),
|
patrolRouteUrl: fieldRules(true),
|
recommendFlyerName: fieldRules(true),
|
deviceId: fieldRules(true),
|
}
|
|
function rejectSuccess() {
|
visible.value = false
|
emit('success')
|
}
|
|
// 填写说明
|
function addDescription() {
|
rejectVisible.value = true
|
nextTick(() => {
|
refuseOrderDialogRef.value.open({
|
mode: 'add',
|
row: formData.value,
|
type: gdStatusObj[taskStatus.value].operationType,
|
formLabel: gdStatusObj[taskStatus.value].reason,
|
})
|
})
|
}
|
// 查看说明
|
function viewDescription() {
|
rejectVisible.value = true
|
nextTick(() => {
|
refuseOrderDialogRef.value.open({
|
mode: 'view',
|
row: formData.value,
|
formLabel: gdStatusObj[taskStatus.value].reason,
|
})
|
})
|
}
|
|
// 获取航线名称
|
function getRouteName(id) {
|
const item = routeOptions.value.find(item => item.id === id)
|
return item ? item.name : id
|
}
|
|
// 获取设备名称
|
function getDeviceName(id) {
|
const item = deviceList.value.find(item => item.id === id)
|
return item ? item.nickname : id
|
}
|
|
// 获取工单名称
|
function getWorkOrderName(id) {
|
const item = workOrderList.value.find(item => item.id === id)
|
return item ? item.workOrderName : id
|
}
|
|
// 获取工单列表
|
async function getWorkOrderList() {
|
const res = await gdWorkOrderPageApi({ size: 999 })
|
workOrderList.value = res?.data?.data?.records ?? []
|
}
|
|
// 获取飞手列表
|
async function getFlyerList() {
|
const res = await gdFlyerPageApi({ size: 999, current: 1 })
|
flyerList.value = res?.data?.data?.records ?? []
|
}
|
|
// 操作类型:1.同意签收、2.拒绝签收 、3.撤回任务 、4.同意审核、 5.拒绝审核、 6.验收通过、 7.验收拒绝
|
function statusChange(auditStatus) {
|
gdPatrolTaskAuditApi({ auditStatus, id: formData.value.id }).then(res => {
|
visible.value = false
|
emit('success')
|
})
|
}
|
|
function refusalToAccept() {
|
emit('refusalAccept', formData.value)
|
visible.value = false
|
}
|
|
// 获取设备列表
|
async function getDeviceList() {
|
const res = await gdManageDeviceListApi()
|
deviceList.value = res?.data?.data ?? []
|
}
|
|
const processList = ref([])
|
// 加载时间线list
|
function loadList() {
|
gdWorkOrderFlowPatrolListApi({ workOrderId: formData.value.id, type: '1' }).then(res => {
|
processList.value = res.data.data
|
})
|
}
|
|
// 提交编辑
|
async function handleSubmit() {
|
const isValid = await formRef.value?.validate().catch(() => false)
|
if (!isValid) return
|
submitting.value = true
|
try {
|
await gdPatrolTaskRepublish(formData.value)
|
ElMessage.success('更新成功')
|
visible.value = false
|
emit('success')
|
} finally {
|
submitting.value = false
|
}
|
}
|
|
let taskResultList = ref([])
|
// 获取成果列表
|
async function getTaskResultList() {
|
if (!formData.value?.id) return
|
try {
|
const res = await gdTaskResultListApi({ patrolTaskId: formData.value.id })
|
taskResultList.value = res?.data?.data ?? []
|
} finally {
|
}
|
}
|
import { ArrowLineMaterialProperty } from '@/utils/cesium/Material'
|
import OrderStepBar from '@/views/orderView/orderManage/orderManage/OrderStepBar.vue'
|
let arrowLineMaterialProperty = new ArrowLineMaterialProperty({
|
color: new Cesium.Color(128 / 255, 215 / 255, 255 / 255, 1),
|
directionColor: new Cesium.Color(1, 1, 1, 1),
|
outlineColor: new Cesium.Color(1, 1, 1, 1),
|
outlineWidth: 0,
|
speed: 5,
|
})
|
// 获取航线详情
|
function getAirDetails() {
|
queryAirById(formData.value.patrolRouteUrl).then(res => {
|
const list = res.data.data.airlineWaypoints
|
if (!list.length) return mapRef.value?.flyBoundary()
|
const result = list.map(item => [Number(item.longitude), Number(item.latitude)]).flat()
|
viewer.entities.add({
|
polyline: {
|
positions: Cesium.Cartesian3.fromDegreesArray(result),
|
clampToGround: true,
|
width: 4,
|
material: arrowLineMaterialProperty,
|
},
|
})
|
// 渲染起点(蓝色)
|
const startPoint = list[0]
|
viewer.entities.add({
|
position: Cesium.Cartesian3.fromDegrees(
|
Number(startPoint.longitude),
|
Number(startPoint.latitude),
|
startPoint.height || 0
|
),
|
point: {
|
pixelSize: 12,
|
color: Cesium.Color.BLUE,
|
outlineColor: Cesium.Color.WHITE,
|
outlineWidth: 2,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
},
|
})
|
// 渲染终点(红色)
|
const endPoint = list[list.length - 1]
|
viewer.entities.add({
|
position: Cesium.Cartesian3.fromDegrees(
|
Number(endPoint.longitude),
|
Number(endPoint.latitude),
|
endPoint.height || 0
|
),
|
point: {
|
pixelSize: 12,
|
color: Cesium.Color.RED,
|
outlineColor: Cesium.Color.WHITE,
|
outlineWidth: 2,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
},
|
})
|
flyVisual({
|
positionsData: list.map(i => [Number(i.longitude), Number(i.latitude), i.height || 0]),
|
viewer,
|
})
|
})
|
}
|
|
// 打开弹框
|
async function open({ mode = 'view', row } = {}) {
|
dialogMode.value = mode
|
formData.value = { ...initForm(), ...row }
|
;['6', '7', '8'].includes(row.taskStatus) && getTaskResultList()
|
loadList()
|
initMap()
|
}
|
|
const readyMap = () => {
|
// mapRef.value?.flyBoundary()
|
getAirDetails()
|
}
|
|
// 初始化地图实例
|
function initMap() {
|
if (viewer) return
|
const map = mapRef.value?.getMap()
|
viewer = map?.viewer || null
|
}
|
|
onMounted(() => {
|
getWorkOrderList()
|
getFlyerList()
|
getDeviceList()
|
})
|
|
defineExpose({ open })
|
</script>
|
|
<style lang="scss" scoped>
|
/* 时间线样式 */
|
:deep(.gd-timeline) {
|
padding-left: 90px;
|
}
|
|
:deep(.el-timeline-item) {
|
padding-bottom: 20px;
|
.item-content {
|
position: relative;
|
.flowName {
|
width: 80px;
|
position: absolute;
|
left: -120px;
|
top: 0px;
|
}
|
}
|
}
|
.imgBox {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 10px;
|
> div {
|
width: calc((100% - 40px) / 5); /* 5列布局,减去4个10px间隙 */
|
height: 110px;
|
flex-shrink: 0;
|
}
|
.el-image {
|
width: 100%;
|
height: 100%;
|
}
|
}
|
:deep(.el-timeline-item__timestamp) {
|
font-size: 12px;
|
color: #999;
|
margin-top: 2px;
|
}
|
</style>
|