| | |
| | | v-model="visible" |
| | | :title="titleEnum[dialogMode]" |
| | | @closed="visible = false" |
| | | :style="{ width: pxToRem(1216) }" |
| | | destroy-on-close |
| | | width="1000px" |
| | | > |
| | | <div class="detail-container" v-if="dialogReadonly"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <div class="label">工单名称</div> |
| | | <div class="val">{{ formData.workOrderName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">工单类型</div> |
| | | <div class="val">{{ getDictLabel(formData.workOrderType, dictObj.workOrderType) }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">执行开始时间</div> |
| | | <div class="val">{{ formData.executeStartTime }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">执行结束时间</div> |
| | | <div class="val">{{ formData.executeEndTime }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">设备需求</div> |
| | | <div class="val">{{ getDictLabel(formData.deviceLoadDemand, dictObj.deviceLoadDemand) }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">工单备注</div> |
| | | <div class="val">{{ formData.remark }}</div> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <div class="label">工单经纬度面</div> |
| | | <div class="val">{{ formData.geom }}</div> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <div class="label">推荐设备</div> |
| | | <div class="val">{{ formData.recommendDeviceIds }}</div> |
| | | </el-col> |
| | | </el-row> |
| | | <div style="display: flex"> |
| | | <div class="leftBox"> |
| | | <div class="detail-container" v-if="dialogReadonly"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <div class="label">工单名称</div> |
| | | <div class="val">{{ formData.workOrderName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">工单类型</div> |
| | | <div class="val">{{ getDictLabel(formData.workOrderType, dictObj.workOrderType) }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">执行时间范围</div> |
| | | <div class="val"> |
| | | {{ dayjs(formData.executeStartTime).format('YYYY-MM-DD') }} ~ |
| | | {{ dayjs(formData.executeEndTime).format('YYYY-MM-DD') }} |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">设备需求</div> |
| | | <div class="val">{{ getDictLabel(formData.deviceLoadDemand, dictObj.deviceLoadDemand) }}</div> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <div class="label">工单备注</div> |
| | | <div class="val">{{ formData.remark }}</div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <el-form |
| | | class="gd-dialog-form" |
| | | v-else |
| | | ref="formRef" |
| | | :model="formData" |
| | | :rules="rules" |
| | | :disabled="dialogReadonly" |
| | | label-width="90px" |
| | | > |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工单名称" prop="workOrderName"> |
| | | <el-input class="gd-input" v-model="formData.workOrderName" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工单类型" prop="workOrderType"> |
| | | <el-select |
| | | class="gd-select" |
| | | popper-class="gd-select-popper" |
| | | v-model="formData.workOrderType" |
| | | 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="executeStartTime"> |
| | | <el-date-picker |
| | | class="gd-date-picker" |
| | | popper-class="gd-date-picker-popper" |
| | | v-model="dateRange" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设备需求" prop="deviceLoadDemand"> |
| | | <el-select |
| | | class="gd-select" |
| | | popper-class="gd-select-popper" |
| | | v-model="formData.deviceLoadDemand" |
| | | placeholder="请选择" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="item in dictObj.deviceLoadDemand" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="工单备注" prop="remark"> |
| | | <el-input class="gd-input" type="textarea" v-model="formData.remark" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <div id="mapContainer" class="gd-cesium"></div> |
| | | </div> |
| | | <div> |
| | | <h3>推荐设备</h3> |
| | | <el-table |
| | | class="command-data-cockpit-table" |
| | | ref="deviceTableRef" |
| | | :data="deviceList" |
| | | row-key="id" |
| | | @selection-change="handleDeviceSelectionChange" |
| | | > |
| | | <el-table-column type="selection" width="55" :reserve-selection="true" /> |
| | | <el-table-column prop="nickname" label="设备名称" /> |
| | | <el-table-column prop="deviceName" label="设备型号" /> |
| | | <el-table-column prop="devicePayload" label="设备负载" /> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | |
| | | <el-form |
| | | class="gd-dialog-form" |
| | | v-else |
| | | ref="formRef" |
| | | :model="formData" |
| | | :rules="rules" |
| | | :disabled="dialogReadonly" |
| | | label-width="120px" |
| | | > |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工单名称" prop="workOrderName"> |
| | | <el-input class="gd-input" v-model="formData.workOrderName" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工单类型" prop="workOrderType"> |
| | | <el-select |
| | | class="gd-select" |
| | | popper-class="gd-select-popper" |
| | | v-model="formData.workOrderType" |
| | | 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="executeStartTime"> |
| | | <el-date-picker |
| | | class="gd-date-picker" |
| | | popper-class="gd-date-picker-popper" |
| | | v-model="formData.executeStartTime" |
| | | 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="executeEndTime"> |
| | | <el-date-picker |
| | | class="gd-date-picker" |
| | | popper-class="gd-date-picker-popper" |
| | | v-model="formData.executeEndTime" |
| | | 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="deviceLoadDemand"> |
| | | <el-select |
| | | class="gd-select" |
| | | popper-class="gd-select-popper" |
| | | v-model="formData.deviceLoadDemand" |
| | | placeholder="请选择" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="item in dictObj.deviceLoadDemand" |
| | | :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="remark"> |
| | | <el-input class="gd-input" v-model="formData.remark" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="工单经纬度面" prop="geom"> |
| | | <el-input class="gd-input" v-model="formData.geom" placeholder="预留输入框" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="推荐设备" prop="recommendDeviceIds"> |
| | | <el-form-item prop="recommendDeviceIds" label-width="0"> |
| | | <el-table |
| | | class="command-data-cockpit-table" |
| | | ref="deviceTableRef" |
| | | :data="deviceList" |
| | | row-key="id" |
| | | @selection-change="handleDeviceSelectionChange" |
| | | > |
| | | <el-table-column type="selection" width="55" :reserve-selection="true" /> |
| | | <el-table-column prop="deviceName" label="设备名称" /> |
| | | <el-table-column prop="deviceCode" label="设备编码" /> |
| | | <el-table-column prop="deviceType" label="设备类型" /> |
| | | </el-table> |
| | | </el-form-item> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button color="#F2F3F5" @click="visible = false">{{ dialogReadonly ? '关闭' : '取消' }}</el-button> |
| | | <el-button |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, ref, onMounted } from 'vue' |
| | | import { computed, ref, onMounted, nextTick } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { fieldRules } from '@ztzf/utils' |
| | | import { getDictLabel } from '@ztzf/utils' |
| | | import { dateRangeFormat, fieldRules, geomAnalysis, getDictLabel } from '@ztzf/utils' |
| | | import { gdWorkOrderDetailApi, gdWorkOrderSaveApi } from './orderManageApi' |
| | | import { gdManageDevicePageApi } from './gdManageDeviceApi' |
| | | import { gdManageDeviceListApi, gdManageDevicePageApi } from './gdManageDeviceApi' |
| | | import { cartesian3Convert } from '@/utils/cesium/mapUtil' |
| | | import * as turf from '@turf/turf' |
| | | import * as Cesium from 'cesium' |
| | | import { DrawPolygon } from '@/utils/cesium/DrawPolygon' |
| | | import { PublicCesium } from '@/utils/cesium/publicCesium' |
| | | import { pxToRem } from '@/utils/rem' |
| | | import dayjs from 'dayjs' |
| | | |
| | | // 初始化表单数据 |
| | | const initForm = () => ({ |
| | |
| | | }) |
| | | |
| | | const dictObj = inject('dictObj') |
| | | const deptTree = inject('deptTree') |
| | | const treeProps = inject('treeProps') |
| | | |
| | | const dateRange = ref([]) |
| | | const emit = defineEmits(['success']) |
| | | const formRef = ref(null) // 表单实例 |
| | | const formData = ref(initForm()) // 表单数据 |
| | |
| | | const deviceList = ref([]) // 设备列表 |
| | | const selectedDevices = ref([]) // 选中的设备 |
| | | const deviceTableRef = ref(null) // 设备表格实例 |
| | | let viewer |
| | | let drawPolygonExample |
| | | let pointList = [] |
| | | |
| | | const rules = { |
| | | workOrderName: fieldRules(true), |
| | | workOrderName: fieldRules(true, 50), |
| | | workOrderType: fieldRules(true), |
| | | executeStartTime: fieldRules(true), |
| | | executeEndTime: fieldRules(true), |
| | | deviceLoadDemand: fieldRules(true), |
| | | } |
| | | |
| | | // 获取推荐设备列表 |
| | | async function getDeviceList() { |
| | | try { |
| | | const res = await gdManageDevicePageApi({ current: 1, size: 1000 }) |
| | | deviceList.value = res?.data?.data?.records ?? [] |
| | | const res = await gdManageDeviceListApi({ current: 1, size: 1000, ids: formData.value.recommendDeviceIds }) |
| | | deviceList.value = res?.data?.data ?? [] |
| | | } catch (error) { |
| | | console.error('获取设备列表失败:', error) |
| | | } |
| | |
| | | async function handleSubmit() { |
| | | const isValid = await formRef.value?.validate().catch(() => false) |
| | | if (!isValid) return |
| | | if (!pointList.length) { |
| | | ElMessage.warning('请绘制范围') |
| | | return |
| | | } |
| | | submitting.value = true |
| | | try { |
| | | const str = [...pointList, pointList[0]].map(item => `${item.longitude} ${item.latitude}`).join(',') |
| | | formData.value.geom = `POLYGON((${str}))` |
| | | if (!formData.value.id) { |
| | | formData.value.workOrderStatus = '10' |
| | | } |
| | | await gdWorkOrderSaveApi(formData.value) |
| | | ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功') |
| | | visible.value = false |
| | |
| | | } |
| | | } |
| | | |
| | | watch( |
| | | () => dateRange.value, |
| | | newVal => { |
| | | const range = dateRangeFormat(dateRange.value) |
| | | formData.value.executeStartTime = range[0] |
| | | formData.value.executeEndTime = range[1] |
| | | } |
| | | ) |
| | | |
| | | // 加载详情 |
| | | async function loadDetail() { |
| | | if (!formData.value.id) return |
| | | const res = await gdWorkOrderDetailApi({ id: formData.value.id }) |
| | | formData.value = res?.data?.data ?? {} |
| | | dateRange.value = [formData.value.executeStartTime, formData.value.executeEndTime] |
| | | } |
| | | |
| | | // 回显选中的设备 |
| | | if (formData.value.recommendDeviceIds) { |
| | | const deviceIds = formData.value.recommendDeviceIds.split(',').map(id => parseInt(id)) |
| | | nextTick(() => { |
| | | deviceList.value.forEach(device => { |
| | | if (deviceIds.includes(device.id)) { |
| | | deviceTableRef.value?.toggleRowSelection(device, true) |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | // 新增模式绘制 |
| | | function addPolygon() { |
| | | drawPolygonExample = new DrawPolygon(viewer) |
| | | drawPolygonExample.initHandler(viewer) |
| | | drawPolygonExample.subscribe('getPolygonPositions', drawFinished) |
| | | } |
| | | |
| | | // 绘制完成回调 |
| | | const drawFinished = async data => { |
| | | pointList = _.cloneDeep(data).map(item => { |
| | | const val = cartesian3Convert(item, viewer) |
| | | return { ...val, lng: val.longitude, lat: val.latitude } |
| | | }) |
| | | } |
| | | |
| | | // 编辑面 |
| | | function editPolygon() { |
| | | if (!formData.value?.geom) return |
| | | pointList = geomAnalysis(formData.value.geom) |
| | | drawPolygonExample?.destroy() |
| | | drawPolygonExample = new DrawPolygon(viewer) |
| | | let noClosedList = _.cloneDeep(pointList) |
| | | noClosedList.pop() |
| | | drawPolygonExample.initPolygon( |
| | | viewer, |
| | | noClosedList.map(item => ({ lng: item.longitude, lat: item.latitude })) |
| | | ) |
| | | drawPolygonExample.subscribe('getPolygonPositions', drawFinished) |
| | | } |
| | | |
| | | // 查看面 |
| | | function viewPolygon() { |
| | | if (!formData.value?.geom) return |
| | | pointList = geomAnalysis(formData.value.geom) |
| | | const result = pointList.map(item => [item.longitude, item.latitude]).flat() |
| | | const mian = viewer.entities?.add({ |
| | | customType: 'control_group', |
| | | position: Cesium.Cartesian3.fromDegrees(result[0], result[1]), |
| | | polyline: { |
| | | positions: Cesium.Cartesian3.fromDegreesArray(result), |
| | | clampToGround: true, |
| | | width: 3, |
| | | material: Cesium.Color.RED, |
| | | }, |
| | | }) |
| | | viewer.flyTo(mian) |
| | | } |
| | | |
| | | // 同步关联场景 |
| | | function syncSelection() { |
| | | if (!deviceTableRef.value) return |
| | | deviceTableRef.value.clearSelection() |
| | | const deviceIds = formData.value.recommendDeviceIds.split(',') |
| | | deviceList.value.forEach(device => { |
| | | if (deviceIds.includes(String(device.id))) { |
| | | deviceTableRef.value?.toggleRowSelection(device, true) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 打开弹框 |
| | | async function open({ mode = 'add', row } = {}) { |
| | | dialogMode.value = mode |
| | | formData.value = dialogMode.value === 'add' ? initForm() : row |
| | | await getDeviceList() |
| | | initMap() |
| | | if (dialogMode.value !== 'add') { |
| | | await loadDetail() |
| | | } |
| | | await getDeviceList() |
| | | if (dialogMode.value === 'add') { |
| | | addPolygon() |
| | | } else if (dialogMode.value === 'edit') { |
| | | editPolygon() |
| | | } else { |
| | | viewPolygon() |
| | | } |
| | | await nextTick() |
| | | syncSelection() |
| | | } |
| | | |
| | | // 初始化地图实例 |
| | | function initMap() { |
| | | const publicCesiumInstance = new PublicCesium({ |
| | | dom: 'mapContainer', |
| | | flatMode: false, |
| | | terrain: true, |
| | | layerMode: 4, |
| | | boundary: false, |
| | | }) |
| | | viewer = publicCesiumInstance.getViewer() |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .leftBox { |
| | | width: 681px; |
| | | } |
| | | #mapContainer { |
| | | width: 681px; |
| | | height: 423px; |
| | | } |
| | | </style> |