applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
@@ -4,35 +4,23 @@ <div class="leftMap ztzf-cesium" id="mapContainer"></div> <div class="rightInfo"> <div v-if="readonly"> <el-row> <el-col :span="24"> <div>区域名称: {{ formData.areaName }}</div> </el-col> <el-col :span="24"> <div>区域位置: {{ formatLocation(formData) }}</div> </el-col> <el-col :span="24"> <div>区域面积: {{ formData.areaSize || '-' }}k㎡</div> </el-col> <el-col :span="24"> <div>区域类型: {{ getDictLabel(formData.areaType, dictObj.areaType) }}</div> </el-col> <el-col :span="24"> <div>触发条件: {{ formData.triggerCondition }}</div> </el-col> <el-col :span="24"> <div>响应机制: {{ formData.responseMechanism }}</div> </el-col> <el-col :span="24"> <div>管控级别: {{ getDictLabel(formData.controlLevel, dictObj.controlLevel) }}</div> </el-col> <el-col :span="24"> <div>关联派出所: {{ formData.policeStationName }}</div> </el-col> <el-col :span="24"> <div>可飞行时间段: {{ formatFlyDate(formData) }}</div> </el-col> </el-row> <div>区域名称: {{ formData.areaName }}</div> <div>区域位置: {{ formatLocation(formData) }}</div> <div>区域面积: {{ formData.areaSize || '-' }}k㎡</div> <div>区域类型: {{ getDictLabel(formData.areaType, dictObj.areaType) }}</div> <div>触发条件: {{ formData.triggerCondition }}</div> <div>响应机制: {{ formData.responseMechanism }}</div> <div>管控级别: {{ getDictLabel(formData.controlLevel, dictObj.controlLevel) }}</div> <div>关联派出所: {{ formData.policeStationName }}</div> <div>可飞行时间段: {{ formatFlyDate(formData) }}</div> <el-table ref="deviceTableRef" :data="deviceOptions" row-key="id"> <el-table-column prop="deviceName" label="设备名称" /> <el-table-column prop="deviceType" label="类型"> <template v-slot="{ row }"> {{ getDictLabel(row.deviceType, dictObj.deviceType) }} </template> </el-table-column> </el-table> </div> <el-form v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly" label-width="100px"> <el-row> @@ -118,6 +106,11 @@ > <el-table-column type="selection" width="55" /> <el-table-column prop="deviceName" label="设备名称" /> <el-table-column prop="deviceType" label="类型"> <template v-slot="{ row }"> {{ getDictLabel(row.deviceType, dictObj.deviceType) }} </template> </el-table-column> </el-table> </el-form-item> </el-col> @@ -138,7 +131,7 @@ import { computed, inject, nextTick, onMounted, ref, watch } from 'vue' import { ElMessage } from 'element-plus' import { fwAreaDivideDetailApi, fwAreaDivideSubmitApi } from './partitionApi' import { fieldRules, getDictLabel } from '@ztzf/utils' import { fieldRules, geomAnalysis, getDictLabel } from '@ztzf/utils' import { PublicCesium } from '@/utils/cesium/publicCesium' import { DrawPolygon } from '@/utils/cesium/DrawPolygon' import { cartesian3Convert } from '@/utils/cesium/mapUtil' @@ -277,30 +270,17 @@ drawPolygonExample.subscribe('getPolygonPositions', drawFinished) } // 解析经纬度 function getLonLat(str) { if (!str) return [] return str .replace('POLYGON((', '') .replace('))', '') .split(',') .map(pair => { const [lon, lat] = pair.trim().split(' ').map(Number) return [lon, lat] }) } // 编辑面 function editPolygon() { if (!formData.value?.geom) return const grouped = getLonLat(formData.value.geom) grouped.pop() pointList = grouped.map(item => ({ longitude: item[0], latitude: item[1] })) pointList = geomAnalysis(formData.value.geom) drawPolygonExample?.destroy() drawPolygonExample = new DrawPolygon(viewer) let pointList1 = _.cloneDeep(pointList) pointList1.pop() drawPolygonExample.initPolygon( viewer, grouped.map(item => ({ lng: item[0], lat: item[1] })) pointList.map(item => ({ lng: item.longitude, lat: item.latitude })) ) drawPolygonExample.subscribe('getPolygonPositions', drawFinished) } @@ -308,10 +288,8 @@ // 查看面 function viewPolygon() { if (!formData.value?.geom) return const grouped = getLonLat(formData.value.geom) grouped.pop() pointList = grouped.map(item => ({ longitude: item[0], latitude: item[1] })) const result = grouped.flat().flat() 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]), @@ -334,8 +312,11 @@ // 获取设备列表 async function getDeviceList() { if (deviceOptions.value.length) return const res = await fwDeviceListApi({ isAreaSelect: 1 }) const res = await fwDeviceListApi({ isAreaSelect: 1, areaId: formData.value.id }) deviceOptions.value = res?.data?.data ?? [] if (dialogMode.value === 'view') { deviceOptions.value = deviceOptions.value.filter(item => formData.value.deviceIds.includes(item.id)) } } // 关联设备变更 @@ -345,19 +326,13 @@ formData.value.deviceIds = ids.join(',') } function getDeviceIdList() { if (!formData.value.deviceIds) return [] return formData.value.deviceIds.split(',').filter(Boolean) } // 同步选择状态 function syncDeviceSelection() { if (!deviceTableRef.value) return deviceTableRef.value.clearSelection() console.log(getDeviceIdList()) const ids = new Set(getDeviceIdList().map(String)) const rows = [] deviceOptions.value.forEach(row => { if (ids.has(String(row.id))) { if (formData.value.deviceIds.includes(row.id)) { deviceTableRef.value.toggleRowSelection(row, true) rows.push(row) } applications/drone-command/src/views/areaManage/partition/index.vue
@@ -158,12 +158,13 @@ const dictObj = ref({ areaType: [], //区域类型 controlLevel: [], //管控级别 deviceType: [], }) provide('dictObj', dictObj) // 获取字典 function getDictList() { getDictionaryByCode('areaType,controlLevel').then(res => { getDictionaryByCode('areaType,controlLevel,deviceType').then(res => { dictObj.value = res.data.data }) } applications/drone-command/src/views/areaManage/precinctInfo/FormDiaLog.vue
@@ -144,12 +144,18 @@ }, label: { text: `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`, fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 2, font: '14px', fillColor: Cesium.Color.WHITE, // 文字颜色:白色 backgroundColor: Cesium.Color.BLACK.withAlpha(0.45), //背景颜色 backgroundPadding: new Cesium.Cartesian2(5, 5), // 水平/垂直内边距(像素) pixelOffset: new Cesium.Cartesian2(0, -20), // 可选:微调位置 showBackground: true, // 确保背景显示(某些版本需要) style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(0, -12), horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.CENTER, outlineWidth: 1, outlineColor: Cesium.Color.WHITE, eyeOffset: new Cesium.Cartesian3(0, 0, -20), // 负值更靠近相机(显示在前) }, }) } else { applications/drone-command/src/views/areaManage/sceneConfig/FormDiaLog.vue
@@ -4,32 +4,21 @@ <div class="leftMap ztzf-cesium" id="mapContainer"></div> <div class="rightInfo"> <div v-if="readonly"> <el-row> <el-col :span="24"> <div>场景名称: {{ formData.sceneName }}</div> </el-col> <el-col :span="24"> <div>指挥点位置: {{ formatLocation(formData) }}</div> </el-col> <el-col :span="24"> <div>场景类型: {{ getDictLabel(formData.sceneType, dictObj.sceneType) }}</div> </el-col> <el-col :span="24"> <div>防控负责人: {{ formData.defenseLeader }}</div> </el-col> <el-col :span="24"> <div>防控负责人电话: {{ formData.leaderPhone }}</div> </el-col> <el-col :span="24"> <div>设备模式: {{ getDictLabel(formData.deviceMode, dictObj.deviceMode) }}</div> </el-col> <el-col :span="24"> <div>关联区域: {{ formatAreaNames() }}</div> </el-col> <el-col :span="24"> <div>防控面积: {{ formatDefenseArea(formData.defenseArea) }}</div> </el-col> </el-row> <div>场景名称: {{ formData.sceneName }}</div> <div>指挥点位置: {{ formatLocation(formData) }}</div> <div>场景类型: {{ getDictLabel(formData.sceneType, dictObj.sceneType) }}</div> <div>防控负责人: {{ formData.defenseLeader }}</div> <div>防控负责人电话: {{ formData.leaderPhone }}</div> <div>设备模式: {{ getDictLabel(formData.deviceMode, dictObj.deviceMode) }}</div> <div>防控面积: {{ formatDefenseArea(formData.defenseArea) }}</div> <el-table ref="areaTableRef" :data="areaList" row-key="id"> <el-table-column prop="areaName" label="区域名称" /> <el-table-column prop="areaType" label="区域类型"> <template v-slot="{ row }"> {{ getDictLabel(row.areaType, dictObj.areaType) }} </template> </el-table-column> </el-table> </div> <el-form v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly" label-width="100px"> <el-row> @@ -117,10 +106,11 @@ import { computed, inject, nextTick, onMounted, ref } from 'vue' import { ElMessage } from 'element-plus' import { fwDefenseSceneDetailApi, fwDefenseSceneSubmitApi } from './sceneConfigApi' import { fieldRules, getDictLabel } from '@ztzf/utils' import { fieldRules, geomAnalysis, getDictLabel } from '@ztzf/utils' import { PublicCesium } from '@/utils/cesium/publicCesium' import * as Cesium from 'cesium' import { fwAreaDivideListApi } from '../partition/partitionApi' import { DrawPolygon } from '@/utils/cesium/DrawPolygon' const initForm = () => ({ sceneName: '', // 场景名称 @@ -145,8 +135,10 @@ const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' }) const areaTableRef = ref(null) const areaList = ref([]) // 关联区域列表 const selectedAreaRows = ref([]) const selectedAreaRows = ref([]) //选中列表 const dictObj = inject('dictObj') let viewer let redPointEntity const rules = { sceneName: fieldRules(true, 50), @@ -192,36 +184,53 @@ // 获取区域列表 async function getAreaList() { if (areaList.value.length) return const res = await fwAreaDivideListApi() const res = await fwAreaDivideListApi({ filterSelected: 1, sceneId: formData.value.id }) areaList.value = res?.data?.data ?? [] } // 关联区域变更 function handleAreaSelectionChange(rows) { selectedAreaRows.value = rows const ids = rows.map(item => item.id) formData.value.areaDivideIds = ids.join(',') formData.value.areaCount = ids.length formData.value.areaDivideIds = rows.map(item => item.id) formData.value.areaCount = rows.length formData.value.defenseArea = calcDefenseArea(rows) } // 渲染面 function renderingSurface() { geometricSource && geometricSource.entities.removeAll() selectedAreaRows.value.forEach(item => { if (item.geom) { const pointList = geomAnalysis(item.geom) const result = pointList.map(item => [item.longitude, item.latitude]).flat() geometricSource.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, }, }) } }) } watch(() => selectedAreaRows.value, renderingSurface) function calcDefenseArea(rows) { const total = rows.reduce((sum, item) => sum + (Number(item.areaSize) || 0), 0) return _.round(total, 2) } function getAreaIdList() { if (!formData.value.areaDivideIds) return [] return formData.value.areaDivideIds.split(',').filter(Boolean) } // 同步关联区域 function syncAreaSelection() { if (!areaTableRef.value) return areaTableRef.value.clearSelection() const ids = new Set(getAreaIdList()) const rows = [] areaList.value.forEach(row => { if (ids.has(row.id)) { if (formData.value.areaDivideIds.includes(row.id)) { areaTableRef.value.toggleRowSelection(row, true) rows.push(row) } @@ -230,16 +239,6 @@ if (!rows.length) return formData.value.areaCount = rows.length formData.value.defenseArea = calcDefenseArea(rows) } function formatAreaNames() { const rows = selectedAreaRows.value.length ? selectedAreaRows.value : getAreaRowsByIds() return rows.map(item => item.areaName).join(', ') } function getAreaRowsByIds() { const ids = new Set(getAreaIdList().map(String)) return areaList.value.filter(item => ids.has(String(item.id))) } function formatDefenseArea(value) { @@ -253,6 +252,7 @@ return `${_.round(row.longitude, 6)}, ${_.round(row.latitude, 6)}` } let geometricSource // 初始化地图实例 function initMap() { const publicCesiumInstance = new PublicCesium({ @@ -266,6 +266,8 @@ publicCesiumInstance.addLeftClickEvent(null, LeftClickEvent) } viewer = publicCesiumInstance.getViewer() geometricSource = new Cesium.CustomDataSource('geometricSource') viewer.dataSources.add(geometricSource) } function LeftClickEvent(click) { @@ -291,12 +293,18 @@ }, label: { text: `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`, fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 2, font: '14px', fillColor: Cesium.Color.WHITE, // 文字颜色:白色 backgroundColor: Cesium.Color.BLACK.withAlpha(0.45), //背景颜色 backgroundPadding: new Cesium.Cartesian2(5, 5), // 水平/垂直内边距(像素) pixelOffset: new Cesium.Cartesian2(0, -20), // 可选:微调位置 showBackground: true, // 确保背景显示(某些版本需要) style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(0, -12), horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.CENTER, outlineWidth: 1, outlineColor: Cesium.Color.WHITE, eyeOffset: new Cesium.Cartesian3(0, 0, -20), // 负值更靠近相机(显示在前) }, }) } else { @@ -304,9 +312,6 @@ redPointEntity.label.text = `${longitude.toFixed(6)}, ${latitude.toFixed(6)}` } } let viewer let redPointEntity // 打开弹框 async function open({ mode, row } = {}) { applications/drone-command/src/views/areaManage/sceneConfig/index.vue
@@ -41,7 +41,6 @@ <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="55" /> <el-table-column type="index" width="60" label="序号" /> <el-table-column prop="deviceName" label="设备名称" /> <el-table-column prop="sceneName" label="场景名称" /> <el-table-column prop="sceneType" label="场景类型"> <template v-slot="{ row }"> applications/drone-command/src/views/job/components/DeviceJobDetailsMap.vue
@@ -215,18 +215,7 @@ renderOrthophoto() }) } // 解析经纬度 function getLonLat(str) { if (!str) return [] return str .replace('POLYGON((', '') .replace('))', '') .split(',') .map(pair => { const [lon, lat] = pair.trim().split(' ').map(Number) return [lon, lat] }) } // 渲染正射 function renderOrthophoto() { zsList.value.forEach((item, index) => { packages/utils/common/index.js
@@ -30,3 +30,15 @@ elink.click() document.body.removeChild(elink) } export function geomAnalysis(str) { if (!str) return [] return str .replace('POLYGON((', '') .replace('))', '') .split(',') .map(pair => { const [longitude, latitude] = pair.trim().split(' ').map(Number) return { longitude, latitude } }) }