<template>
|
<el-dialog class="command-page-view-dialog" v-model="visible" :title="titleEnum[dialogMode]" destroy-on-close
|
:close-on-click-modal="false" @closed="handleClosed">
|
<div v-if="readonly" class="detail-container">
|
<el-row>
|
<el-col :span="12">
|
<div class="label">设备名称</div>
|
<div class="val">{{ formData.deviceName }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">设备编码</div>
|
<div class="val">{{ formData.deviceSn }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">区域</div>
|
<div class="val">{{ formData.areaDivideName }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">场景</div>
|
<div class="val">{{ formData.defenseSceneName }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">调度人员</div>
|
<div class="val">{{ formData.dispatchUser }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">调度位置</div>
|
<div class="val">{{ formData.longitude }}, {{ formData.latitude }}</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="label">调度日期</div>
|
<div class="val">{{ formData.dispatchStartTime }} ~ {{ formData.dispatchEndTime }}</div>
|
</el-col>
|
<el-col :span="24">
|
<div class="label">调度内容</div>
|
<div class="val">{{ formData.dispatchContent }}</div>
|
</el-col>
|
<el-col :span="24">
|
<div class="label">调度结果</div>
|
<div class="val">{{ formData.dispatchResult }}</div>
|
</el-col>
|
<el-col :span="24">
|
<div class="label">处理措施</div>
|
<div class="val">{{ formData.disposeMeasure }}</div>
|
</el-col>
|
</el-row>
|
</div>
|
<el-form v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly" label-width="100px"
|
class="dialog-form">
|
<el-row>
|
<el-col :span="12">
|
<el-form-item label="设备" prop="deviceId">
|
<el-select class="command-select" popper-class="command-select-popper"
|
v-model="formData.deviceId" placeholder="请选择" clearable @change="handleDeviceChange">
|
<el-option v-for="item in deviceList" :key="item.id" :label="item.deviceName"
|
:value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="设备编码" prop="deviceSn">
|
<el-input class="command-input" v-model="formData.deviceSn" disabled placeholder="选择设备后自动带出" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="设备状态">
|
<el-select class="command-select" popper-class="command-select-popper"
|
v-model="deviceStatus" disabled placeholder="选择设备后自动带出">
|
<el-option v-for="item in dictObj.deviceStatus" :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="defenseSceneId">
|
<el-select class="command-select" popper-class="command-select-popper"
|
v-model="formData.defenseSceneId" placeholder="选择设备后自动带出" clearable
|
disabled>
|
<el-option v-for="item in sceneList" :key="item.id" :label="item.sceneName"
|
:value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="区域" prop="areaDivideId">
|
<el-select class="command-select" popper-class="command-select-popper"
|
v-model="formData.areaDivideId" placeholder="选择设备后自动带出" clearable
|
disabled>
|
<el-option v-for="item in areaList" :key="item.id" :label="item.areaName"
|
:value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="调度位置" prop="longitude">
|
<!-- <el-button @click="selectLocation" style="width: 100%">-->
|
<el-button style="width: 100%" disabled>
|
{{
|
formData.longitude && formData.latitude ? `${formData.longitude}, ${formData.latitude}` :
|
'选择设备后自动带出'
|
}}
|
</el-button>
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="调度人员" prop="dispatchUser">
|
<el-input class="command-input" v-model="formData.dispatchUser" maxlength="50" placeholder="选择设备后自动带出"
|
disabled clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="调度日期" prop="dispatchDateRange">
|
<el-date-picker class="command-date-picker" popper-class="command-date-picker-popper"
|
v-model="formData.dispatchDateRange" type="daterange" range-separator="至"
|
start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD HH:mm:ss" />
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="24">
|
<el-form-item label="调度内容" prop="dispatchContent">
|
<el-input class="command-input" v-model="formData.dispatchContent" type="textarea" :rows="3"
|
maxlength="500" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="24">
|
<el-form-item label="调度结果" prop="dispatchResult">
|
<el-input class="command-input" v-model="formData.dispatchResult" type="textarea" :rows="3"
|
maxlength="500" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="24">
|
<el-form-item label="处理措施" prop="disposeMeasure">
|
<el-input class="command-input" v-model="formData.disposeMeasure" type="textarea" :rows="3"
|
maxlength="500" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
|
<template #footer>
|
<el-button v-if="dialogMode != 'view'" color="#2B2B4C" @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
|
<el-button color="#284FE3" v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting"
|
@click="handleSubmit">
|
保存
|
</el-button>
|
</template>
|
|
<el-dialog v-model="visible1" title="选择位置" destroy-on-close @closed="positionClosed">
|
<div class="command-cesium" id="mapContainer"></div>
|
<template #footer>
|
<el-button @click="handleMapCancel">取消</el-button>
|
<el-button type="primary" @click="handleMapConfirm">确定</el-button>
|
</template>
|
</el-dialog>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import { computed, nextTick, ref } from 'vue'
|
import { ElMessage } from 'element-plus'
|
import { fwTaskScheduleDetailApi, fwTaskScheduleSubmitApi } from './taskScheduleApi'
|
import { fwAreaDivideListApi } from '@/views/areaManage/partition/partitionApi'
|
import { fwDefenseSceneManageListApi } from '@/views/areaManage/sceneManage/sceneManageApi'
|
import { fieldRules } from '@ztzf/utils'
|
import { PublicCesium } from '@/utils/cesium/publicCesium'
|
import * as Cesium from 'cesium'
|
import { saveOperationLog } from '@ztzf/apis'
|
import { useRoute } from 'vue-router'
|
|
// 初始化表单
|
const initForm = () => ({
|
deviceId: '', // 设备ID
|
deviceSn: '', // 设备编码
|
deviceName: '', // 设备名称
|
deviceStatus: '', // 设备状态
|
deviceStatusLabel: '', // 设备状态标签
|
defenseSceneId: '', // 场景ID
|
defenseSceneName: '', // 场景名称
|
areaDivideId: '', // 区域ID
|
areaDivideName: '', // 区域名称
|
areaCode: '', // 区域编码
|
dispatchUser: '', // 调度人员
|
dispatchStartTime: '', // 调度开始时间
|
dispatchEndTime: '', // 调度结束时间
|
dispatchDateRange: [], // 调度日期范围
|
dispatchContent: '', // 调度内容
|
dispatchResult: '', // 调度结果
|
disposeMeasure: '', // 处理措施
|
longitude: null, // 经度
|
latitude: null, // 纬度
|
})
|
|
const props = defineProps({
|
deviceList: { type: Array, default: () => [] },
|
})
|
|
const dictObj = inject('dictObj')
|
|
const emit = defineEmits(['success'])
|
const formRef = ref(null) // 表单实例
|
const formData = ref(initForm()) // 表单数据
|
const visible = defineModel() // 弹框显隐
|
const visible1 = ref(false) // 地图弹框显隐
|
const dialogMode = ref('add') // 弹框模式
|
const submitting = ref(false) // 提交中
|
const readonly = computed(() => dialogMode.value === 'view')
|
const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' })
|
const tempLocation = ref({ longitude: null, latitude: null })
|
const areaList = ref([]) // 区域列表
|
const sceneList = ref([]) // 场景列表
|
const deviceStatus = ref('')
|
const route = useRoute()
|
|
const rules = {
|
deviceId: fieldRules(true),
|
areaDivideId: fieldRules(true),
|
defenseSceneId: fieldRules(true),
|
dispatchUser: fieldRules(true, 50),
|
dispatchDateRange: fieldRules(true),
|
}
|
|
// 设备选择变化处理
|
function handleDeviceChange (deviceId) {
|
const device = props.deviceList.find(item => item.id === deviceId)
|
if (device) {
|
formData.value.deviceName = device.deviceName
|
formData.value.deviceSn = device.deviceSn
|
formData.value.deviceStatus = device.status
|
formData.value.dispatchUser = device.charger
|
formData.value.areaDivideId = device.areaDivideId
|
formData.value.defenseSceneId = device.defenseSceneManageId
|
|
formData.value.longitude = device.longitude
|
formData.value.latitude = device.latitude
|
|
deviceStatus.value = String(device.status)
|
} else {
|
formData.value.deviceName = ''
|
formData.value.deviceSn = ''
|
formData.value.deviceStatus = ''
|
formData.value.dispatchUser = ''
|
formData.value.areaDivideId = ''
|
formData.value.defenseSceneId = ''
|
|
formData.value.longitude = ''
|
formData.value.latitude = ''
|
|
deviceStatus.value = ''
|
}
|
}
|
|
// 加载区域列表
|
async function loadAreaList () {
|
const res = await fwAreaDivideListApi()
|
areaList.value = res?.data?.data ?? []
|
}
|
|
// 加载场景列表
|
async function loadSceneList() {
|
const res = await fwDefenseSceneManageListApi()
|
sceneList.value = res?.data?.data ?? []
|
}
|
|
// 关闭弹框
|
function handleCancel () {
|
visible.value = false
|
}
|
|
function handleClosed () {
|
formData.value = initForm()
|
}
|
|
// 提交新增/编辑
|
async function handleSubmit () {
|
const isValid = await formRef.value?.validate().catch(() => false)
|
if (!isValid) return
|
submitting.value = true
|
try {
|
// 处理调度日期
|
if (formData.value.dispatchDateRange?.length === 2) {
|
formData.value.dispatchStartTime = formData.value.dispatchDateRange[0]
|
formData.value.dispatchEndTime = formData.value.dispatchDateRange[1]
|
}
|
await fwTaskScheduleSubmitApi(formData.value)
|
|
const actionText = dialogMode.value === 'add' ? '新增' : '修改'
|
saveOperationLog({
|
requestUri: route.path,
|
title: `${route.name || '任务调度'}-${actionText}`,
|
type: 1
|
})
|
|
ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功')
|
visible.value = false
|
emit('success')
|
} finally {
|
submitting.value = false
|
}
|
}
|
|
// 加载详情
|
async function loadDetail () {
|
if (!formData.value.id) return
|
const res = await fwTaskScheduleDetailApi({ id: formData.value.id })
|
const data = res?.data?.data ?? {}
|
formData.value = {
|
...data,
|
dispatchDateRange:
|
data.dispatchStartTime && data.dispatchEndTime ? [data.dispatchStartTime, data.dispatchEndTime] : [],
|
}
|
}
|
|
// 左键点击事件处理
|
function LeftClickEvent (click) {
|
const pos = click.position
|
const cartesian3 = viewer.camera.pickEllipsoid(pos, viewer.scene.globe.ellipsoid)
|
if (!cartesian3) {
|
return { longitude: 112, latitude: 23 }
|
}
|
const carto = Cesium.Cartographic.fromCartesian(cartesian3)
|
const longitude = Cesium.Math.toDegrees(carto.longitude)
|
const latitude = Cesium.Math.toDegrees(carto.latitude)
|
tempLocation.value = { longitude, latitude }
|
// 添加红点并渲染经纬度标签
|
if (!redPointEntity) {
|
redPointEntity = viewer.entities.add({
|
position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
|
point: {
|
color: Cesium.Color.RED,
|
pixelSize: 10,
|
},
|
label: {
|
text: `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`,
|
font: '14px',
|
fillColor: Cesium.Color.WHITE,
|
backgroundColor: Cesium.Color.BLACK.withAlpha(0.6),
|
backgroundPadding: new Cesium.Cartesian2(5, 5),
|
pixelOffset: new Cesium.Cartesian2(0, -20),
|
showBackground: true,
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
verticalOrigin: Cesium.VerticalOrigin.CENTER,
|
outlineWidth: 1,
|
outlineColor: Cesium.Color.WHITE,
|
eyeOffset: new Cesium.Cartesian3(0, 0, -20),
|
},
|
})
|
} else {
|
redPointEntity.position = Cesium.Cartesian3.fromDegrees(longitude, latitude)
|
redPointEntity.label.text = `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`
|
}
|
}
|
|
// 地图弹框关闭处理
|
function positionClosed () {
|
redPointEntity = null
|
}
|
|
let viewer
|
let redPointEntity
|
|
// 选择位置
|
async function selectLocation () {
|
visible1.value = true
|
await nextTick()
|
const publicCesiumInstance = new PublicCesium({
|
dom: 'mapContainer',
|
flatMode: false,
|
terrain: true,
|
layerMode: 4,
|
boundary: false,
|
})
|
publicCesiumInstance.addLeftClickEvent(null, LeftClickEvent)
|
viewer = publicCesiumInstance.getViewer()
|
}
|
|
// 地图取消
|
function handleMapCancel () {
|
tempLocation.value = { longitude: null, latitude: null }
|
visible1.value = false
|
}
|
|
// 地图确认
|
function handleMapConfirm () {
|
if (tempLocation.value.longitude != null && tempLocation.value.latitude != null) {
|
formData.value.longitude = _.round(tempLocation.value.longitude, 6)
|
formData.value.latitude = _.round(tempLocation.value.latitude, 6)
|
}
|
visible1.value = false
|
}
|
|
// 打开弹框
|
async function open ({ mode, row } = {}) {
|
dialogMode.value = mode || 'add'
|
formData.value = dialogMode.value === 'add' ? initForm() : { ...row }
|
if (dialogMode.value !== 'add') {
|
await loadDetail()
|
}
|
}
|
|
defineExpose({ open })
|
|
onMounted(() => {
|
loadSceneList()
|
loadAreaList()
|
})
|
</script>
|
<style scoped lang="scss">
|
#mapContainer {
|
width: 100%;
|
height: 500px;
|
}
|
</style>
|