| applications/drone-command/src/utils/cesium/DrawPolygon.js | ●●●●● patch | view | raw | blame | history | |
| applications/drone-command/src/utils/cesium/mapUtil.js | ●●●●● patch | view | raw | blame | history | |
| applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue | ●●●●● patch | view | raw | blame | history | |
| applications/drone-command/src/views/areaManage/partition/index.vue | ●●●●● patch | view | raw | blame | history | |
| applications/drone-command/src/views/areaManage/partition/partitionApi.js | ●●●●● patch | view | raw | blame | history |
applications/drone-command/src/utils/cesium/DrawPolygon.js
@@ -88,18 +88,18 @@ // ============ 发布订阅机制 ============ // 外部订阅数据变化 subscribe (key, listener) { subscribe(key, listener) { this.listeners.push({ key, listener }) } // 通知订阅者 notify (key, data) { notify(key, data) { this.listeners.filter(subscriber => subscriber.key === key).forEach(subscriber => subscriber.listener(data)) } // ============ 绘制相关 ============ // 编辑图斑 editThePatch (data) { editThePatch(data) { this.isPreviewMode = data // 关闭编辑能力时隐藏端点/中点,并清空中点,避免残留交互 if (!this.isPreviewMode) { @@ -117,12 +117,12 @@ } } // 删除测区 deleteTheArea (data) { deleteTheArea(data) { this.isDeleteTheArea = data } // 开始绘制 startDrawing () { startDrawing() { this.drawingMode = true this.curPolygon = new Cesium.PolygonHierarchy() @@ -150,7 +150,7 @@ } // 创建多边形实体(含边界线) createPolygonEntity () { createPolygonEntity() { this.polygonEntity = this.editPolygonDataSource.entities.add({ name: DrawPolygon.ENTITY_NAMES.POLYGON, id: DrawPolygon.ENTITY_NAMES.POLYGON_ID, @@ -174,7 +174,7 @@ } // 创建端点实体 createPointEntity (position, isAdd) { createPointEntity(position, isAdd) { const pointIndex = isAdd ? this.curPolygon.positions.length - 2 : this.curPolygon.positions.length - 1 this.editPolygonPointDataSource.entities.add({ @@ -193,7 +193,7 @@ }) } createMidPointEntity (startInd, position) { createMidPointEntity(startInd, position) { // 使用 CallbackProperty 让中点位置随端点拖拽实时计算 // startInd 表示该中点属于边:(startInd) -> (startInd + 1) const updatePosition = () => { @@ -224,7 +224,7 @@ }) } rebuildEditPoints () { rebuildEditPoints() { // 插入/删除端点后:端点实体 id 与 customData.ind 需要全量重建,保证索引与 positions 一致 if (!this.isPreviewMode) return if (!this.editPolygonPointDataSource || !this.curPolygon?.positions) return @@ -248,7 +248,7 @@ }) } rebuildMidPoints () { rebuildMidPoints() { // 仅在“顶点数量变化/切换编辑态”时维护中点实体数量 // 拖拽过程中中点位置由 CallbackProperty 自动更新,不需要重建 if (!this.isPreviewMode) return @@ -286,7 +286,7 @@ }) } insertPointFromMidPoint (midPointEntity) { insertPointFromMidPoint(midPointEntity) { // 点击中点:在对应边上插入一个新端点(白点),并立即进入拖拽态 if (!this.isPreviewMode) return if (!this.editingMode) return @@ -319,7 +319,7 @@ this.notify('getPolygonPositions', this.curPolygon.positions) } // 清除不在范围内的点 removeLastInvalidPoint () { removeLastInvalidPoint() { const posLen = this.curPolygon.positions.length if (posLen === 0) return @@ -348,7 +348,7 @@ } } // 添加一个点 addPosition (position, isAdd = true) { addPosition(position, isAdd = true) { // 第一个点要重复压入一次,形成动态绘制效果 if (this.curPolygon.positions.length === 0 && isAdd) { this.curPolygon.positions.push(position.clone()) @@ -372,7 +372,7 @@ // ============ 鼠标事件 ============ // 鼠标左键按下(选中端点拖动) handleLeftDown (movement) { handleLeftDown(movement) { if (!this.editingMode) return const pickedEntity = this.viewer.scene.pick(movement.position)?.id @@ -393,7 +393,7 @@ } // 鼠标左键抬起(拖拽结束) handleLeftUp () { handleLeftUp() { if (!(this.editingMode && this.curPolygon?.positions && this.draggedEntity)) return if (this.currentDragPointIsValid && this.isDragging) { @@ -426,7 +426,7 @@ } // 鼠标移动 handleMouseMove (movement) { handleMouseMove(movement) { if (!this.drawingMode && !this.editingMode) return const cartesian = this.viewer.scene.pickPosition(movement.endPosition) @@ -464,7 +464,7 @@ } // 鼠标左键点击 handleLeftClick (click) { handleLeftClick(click) { this.removeMenuPopup() const pickedAllEntity = this.viewer.scene.drillPick(click.position).filter(i => i.id) @@ -520,7 +520,7 @@ } // 鼠标右键点击(弹出菜单) handleRightClick (click) { handleRightClick(click) { const that = this if (that.drawingMode) return @@ -556,7 +556,7 @@ // ============ 删除相关 ============ // 删除所有实体 removeEntities () { removeEntities() { if (this.editPolygonDataSource) { this.editPolygonDataSource.entities.removeAll() this.editPolygonDataSource = null @@ -577,7 +577,7 @@ } // 完成绘制 finishDrawing () { finishDrawing() { this.curPolygon.positions.pop() if (this.curPolygon.positions.length >= 3) { @@ -603,20 +603,20 @@ } // 删除多边形 delPolygon () { delPolygon() { this.removeEntities() this.removeMenuPopup() this.notify('getPolygonPositions', []) this.startDrawing() } // 删除图斑 delSpot () { delSpot() { this.removeEntities() this.isPreviewMode = true this.startDrawing() } // 删除端点 delPoint () { delPoint() { if (this.curPolygon.positions.length <= 3) { this.removeMenuPopup() return ElMessage.warning('端点不可少于3个') @@ -634,7 +634,7 @@ // ============ 工具方法 ============ // 创建右键菜单 createMenuPopup (type = 'polygon') { createMenuPopup(type = 'polygon') { const menuPopupVBox = document.createElement('div') menuPopupVBox.id = 'planarPolygonEdit' menuPopupVBox.className = 'planar-polygon-edit-tooltip' @@ -660,7 +660,7 @@ } // 移除菜单 removeMenuPopup () { removeMenuPopup() { const that = this if (that.menuPopup) { that.menuPopup.removeEventListener('click', that.delPolygon) @@ -672,13 +672,13 @@ } // 更新多边形样式(正常/错误) updatePolygonAppearance (polygonColor, lineColor) { updatePolygonAppearance(polygonColor, lineColor) { this.polygonEntity.polygon.material = polygonColor this.polygonEntity.polyline.material = lineColor } // 禁用地图交互 disableMapControl () { disableMapControl() { const controller = this.viewer.scene.screenSpaceCameraController controller.enableRotate = false controller.enableTranslate = false @@ -686,7 +686,7 @@ } // 启用地图交互 enableMapControl () { enableMapControl() { const controller = this.viewer.scene.screenSpaceCameraController controller.enableRotate = true controller.enableTranslate = true @@ -694,7 +694,7 @@ } // 检查多边形是否自交 curDragPointIsValid (positions) { curDragPointIsValid(positions) { if (positions.length < 3) return true const cartographics = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(positions) @@ -710,12 +710,12 @@ return intersections.features.length === 0 } // 初始化已有多边形 async initPolygon (viewer, positions, isPurePreview = false) { async initPolygon(viewer, positions, isPurePreview = false) { this.initHandler(viewer) this.isPureSpotPreview = isPurePreview this.startDrawing() let newPosition = positions.map(item => { return Cesium.Cartesian3.fromDegrees(Number(item.lng), Number(item.lat), Number(item?.height||0)) return Cesium.Cartesian3.fromDegrees(Number(item.lng), Number(item.lat), Number(item?.height || 0)) }) // 预览航线的时候调用 if (!this.isPureSpotPreview) { @@ -737,7 +737,7 @@ duration: 0.5, }) const pointList = await getPointPositionsHeight(positions, viewer) let pointList = await getPointPositionsHeight(positions, viewer) flyVisual({ positionsData: pointList.map(item => [item.lng, item.lat, item.ASL]), viewer }) this.drawingMode = false @@ -748,7 +748,7 @@ } // 初始化事件处理器 initHandler (viewer) { initHandler(viewer) { this.viewer = viewer this.startDrawing() @@ -771,7 +771,7 @@ } // 移除事件处理器 removeHandler () { removeHandler() { if (this.handler) { const eventTypes = [ Cesium.ScreenSpaceEventType.LEFT_DOWN, @@ -792,7 +792,7 @@ /** * 销毁实例,释放资源 */ destroy () { destroy() { if (!this.viewer) return this.removeMenuPopup() applications/drone-command/src/utils/cesium/mapUtil.js
@@ -346,31 +346,24 @@ return new Promise((resolve, reject) => { if (!data || !data.length) { resolve([]) return } // 假设 viewer 已经初始化并且 terrainProvider 是有效的 const terrainProvider = viewer?.terrainProvider // 创建 Cartographic 对象 const cartographics = data.map(item => { const { lng, lat } = item return Cesium.Cartographic.fromDegrees(Number(lng), Number(lat)) }) // 获取地形数据的Promise const promise = Cesium.sampleTerrainMostDetailed(terrainProvider, cartographics) // 使用 Cesium.when 处理 Promise promise .then(function (updatedPositions) { // updatedPositions 是一个数组,包含更新后的 Cartographic 对象 // 是一个数组,包含更新后的 Cartographic 对象 const newPosition = updatedPositions.map((item, index) => { const longitude = Cesium.Math.toDegrees(item.longitude) const latitude = Cesium.Math.toDegrees(item.latitude) let pointData = { ...data[index], longitude, @@ -378,18 +371,14 @@ ASL: Number(item.height), customHeight: Number(item.height), } if (droneHeight) pointData.TH = Number(item.height) + Number(droneHeight) return pointData }) resolve(newPosition) // 在这里,你可以使用 height 值进行后续操作 }) .catch(function (error) { // console.error('获取高程时发生错误:', error); reject(error) console.log('获取高程时发生错误:', error) resolve(data.map(item => ({ ...item, ASL: 0, customHeight: 0, longitude: item.lng, latitude: item.lat }))) }) }) } applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
New file @@ -0,0 +1,379 @@ <template> <el-dialog v-model="visible" :title="titleEnum[dialogMode]" :close-on-click-modal="false" width="80%"> <div class="bodyBox"> <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 }}</div> </el-col> <el-col :span="24"> <div>区域类型: {{ getOptionLabel(formData.areaType, areaTypeOptions) }}</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>管控级别: {{ getOptionLabel(formData.controlLevel, controlLevelOptions) }}</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> <el-form v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly" label-width="100px"> <el-row> <el-col :span="24"> <el-form-item label="区域名称" prop="areaName"> <el-input v-model="formData.areaName" maxlength="50" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="区域位置" prop="longitude"> <div>{{ formatLocation(formData) }}</div> </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="区域面积" prop="areaSize"> {{ formData.areaSize }} </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="区域类型" prop="areaType"> <el-select v-model="formData.areaType" placeholder="请选择" clearable> <el-option v-for="item in areaTypeOptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="响应机制" prop="responseMechanism"> <el-input v-model="formData.responseMechanism" maxlength="200" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="触发条件" prop="triggerCondition"> <el-input v-model="formData.triggerCondition" maxlength="200" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="管控级别" prop="controlLevel"> <el-select v-model="formData.controlLevel" placeholder="请选择" clearable> <el-option v-for="item in controlLevelOptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="可飞行时段" prop="flyDateRange"> <el-date-picker v-model="flyDateRange" type="datetimerange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" value-format="YYYY-MM-DD HH:mm:ss" clearable /> </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="关联派出所" prop="policeStationId"> <el-select v-model="formData.policeStationId" placeholder="请选择" clearable> <el-option v-for="item in policeStationOptions" :key="item.id" :label="item.stationName" :value="item.id" /> </el-select> </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="关联设备" prop="deviceIds"> <el-select v-model="deviceIdList" multiple collapse-tags placeholder="请选择" clearable> <el-option v-for="item in deviceOptions" :key="item.id" :label="item.deviceName" :value="item.id" /> </el-select> </el-form-item> </el-col> </el-row> </el-form> </div> </div> <template #footer> <el-button @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button> <el-button v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit"> 确定 </el-button> </template> </el-dialog> </template> <script setup> import { computed, nextTick, onMounted, ref, watch } from 'vue' import { ElMessage } from 'element-plus' import { fwAreaDivideDetailApi, fwAreaDivideSubmitApi, fwDevicePageApi, fwPoliceStationPageApi } from './partitionApi' import { fieldRules } from '@ztzf/utils' import { PublicCesium } from '@/utils/cesium/publicCesium' import { DrawPolygon } from '@/utils/cesium/DrawPolygon' import { cartesian3Convert } from '@/utils/cesium/mapUtil' import * as turf from '@turf/turf' import * as Cesium from 'cesium' const initForm = () => ({ areaName: '', // 区域名称 areaSize: null, // 区域面积 areaType: '', // 区域类型 controlLevel: '', // 管控级别 deviceIds: '', // 关联设备ID flyDateEnd: '', // 可飞行结束 flyDateStart: '', // 可飞行开始 latitude: null, // 区域中心纬度 longitude: null, // 区域中心经度 policeStationId: '', // 关联派出所id responseMechanism: '', // 响应机制 triggerCondition: '', // 触发条件 }) const areaTypeOptions = [ { label: '报警区', value: '报警区' }, { label: '重点管制区', value: '重点管制区' }, ] const controlLevelOptions = [ { label: '日常', value: '日常' }, { label: '重点', value: '重点' }, { label: '严密', value: '严密' }, ] const emit = defineEmits(['success']) const formRef = ref(null) // 表单实例 const formData = ref(initForm()) // 表单数据 const visible = defineModel() // 弹框显隐 const dialogMode = ref('add') // 弹框模式 const submitting = ref(false) // 提交中 const readonly = computed(() => dialogMode.value === 'view') const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' }) const flyDateRange = ref([]) // 飞行时间 const deviceIdList = ref([]) // 关联设备ID const policeStationOptions = ref([]) // 关联派出所 const deviceOptions = ref([]) // 关联设备 let viewer let drawPolygonExample let pointList = [] const rules = { areaName: fieldRules(true, 50), areaType: fieldRules(true, 0), controlLevel: fieldRules(true, 0), } // 关闭弹框 function handleCancel() { visible.value = false } // 提交新增/编辑 async function handleSubmit() { const isValid = await formRef.value?.validate().catch(() => false) if (!isValid) return submitting.value = true try { const [start, end] = flyDateRange.value ?? [] formData.value.flyDateStart = start || '' formData.value.flyDateEnd = end || '' formData.value.deviceIds = deviceIdList.value.length ? deviceIdList.value.join(',') : '' let str = [...pointList, pointList[0]].map(item => `${item.longitude} ${item.latitude}`).join(',') formData.value.geom = `POLYGON((${str})) | 4326` await fwAreaDivideSubmitApi(formData.value) 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 fwAreaDivideDetailApi({ id: formData.value.id }) formData.value = res?.data?.data ?? initForm() flyDateRange.value = [formData.value.flyDateStart, formData.value.flyDateEnd].filter(Boolean) deviceIdList.value = formData.value.deviceIds ? formData.value.deviceIds.split(',') : [] } // 格式化区域位置 function formatLocation(row) { if (row?.longitude == null || row?.latitude == null) return '' return `${row.longitude}, ${row.latitude}` } // 格式化可飞行时间段 function formatFlyDate(row) { if (!row?.flyDateStart && !row?.flyDateEnd) return '' return `${row.flyDateStart || '-'} ~ ${row.flyDateEnd || '-'}` } // 获取选项文本 function getOptionLabel(value, options) { const match = options.find(item => item.value === value) return match?.label ?? value ?? '' } // 初始化地图实例 function initMap() { const publicCesiumInstance = new PublicCesium({ dom: 'mapContainer', flatMode: false, terrain: true, layerMode: 4, boundary: false, }) viewer = publicCesiumInstance.getViewer() } // 绘制完成回调 const drawFinished = async data => { pointList = _.cloneDeep(data).map(item => { const val = cartesian3Convert(item, viewer) return { ...val, lng: val.longitude, lat: val.latitude } }) const polygon = turf.polygon([ [...pointList.map(item => [item.longitude, item.latitude]), [pointList[0].longitude, pointList[0].latitude]], ]) const center = turf.centerOfMass(polygon) formData.value.areaSize = _.round(turf.area(polygon), 2) formData.value.longitude = center.geometry.coordinates[0] formData.value.latitude = center.geometry.coordinates[1] } // 新增模式绘制 function addPolygon() { drawPolygonExample = new DrawPolygon(viewer) drawPolygonExample.initHandler(viewer) drawPolygonExample.subscribe('getPolygonPositions', drawFinished) } // 解析经纬度 function getLonLat(str) { if (!str) return [] return str .replace('POLYGON((', '') .replace(')) | 4326', '') .split(',') .map(pair => { const [lat, lon] = 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] })) drawPolygonExample?.destroy() drawPolygonExample = new DrawPolygon(viewer) drawPolygonExample.initPolygon( viewer, grouped.map(item => ({ lng: item[0], lat: item[1] })) ) drawPolygonExample.subscribe('getPolygonPositions', drawFinished) } // 查看面 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() 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) } // 获取派出所列表 async function getPoliceStationList() { const res = await fwPoliceStationPageApi({ current: 1, size: 9999 }) policeStationOptions.value = res?.data?.data?.records ?? [] } // 获取设备列表 async function getDeviceList() { const res = await fwDevicePageApi({ current: 1, size: 9999 }) deviceOptions.value = res?.data?.data?.records ?? [] } // 打开弹框 async function open({ mode, row } = {}) { dialogMode.value = mode || 'add' formData.value = dialogMode.value === 'add' ? initForm() : row await nextTick() initMap() if (dialogMode.value === 'add') { addPolygon() } else if (dialogMode.value === 'edit') { await loadDetail() editPolygon() } else { await loadDetail() viewPolygon() } } onMounted(() => { getPoliceStationList() getDeviceList() }) defineExpose({ open, }) </script> <style scoped lang="scss"> .bodyBox { display: flex; height: 800px; .leftMap { width: 70%; height: 100%; } .rightInfo { width: 30%; height: 100%; overflow: auto; } } </style> applications/drone-command/src/views/areaManage/partition/index.vue
@@ -1,9 +1,178 @@ <template> <basic-container> 区域划分 </basic-container> <basic-container> <el-form ref="queryParamsRef" :model="searchParams"> <el-row :gutter="16"> <el-col :span="4"> <el-form-item label="区域名称" prop="areaName"> <el-input v-model="searchParams.areaName" placeholder="请输入" clearable @clear="handleSearch" /> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="区域类型" prop="areaType"> <el-select v-model="searchParams.areaType" placeholder="请选择" clearable @change="handleSearch"> <el-option v-for="item in areaTypeOptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-col> <el-col :span="4"> <el-form-item> <el-button @click="resetForm">重置</el-button> <el-button type="primary" @click="handleSearch">查询</el-button> </el-form-item> </el-col> </el-row> </el-form> <div> <el-button type="primary" @click="openForm('add')">新增</el-button> <el-button type="danger" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button> </div> <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="areaName" label="区域名称" /> <el-table-column label="区域位置"> <template v-slot="{ row }"> {{ formatLocation(row) }} </template> </el-table-column> <el-table-column prop="areaSize" label="区域面积" /> <el-table-column prop="areaType" label="区域类型"> <template v-slot="{ row }"> {{ getOptionLabel(row.areaType, areaTypeOptions) }} </template> </el-table-column> <el-table-column prop="triggerCondition" label="触发条件" /> <el-table-column prop="responseMechanism" label="响应机制" /> <el-table-column prop="controlLevel" label="管控级别"> <template v-slot="{ row }"> {{ getOptionLabel(row.controlLevel, controlLevelOptions) }} </template> </el-table-column> <el-table-column prop="policeStationName" label="关联派出所" /> <el-table-column label="可飞行时间段"> <template v-slot="{ row }"> {{ formatFlyDate(row) }} </template> </el-table-column> <el-table-column label="操作"> <template v-slot="{ row }"> <el-link @click="openForm('view', row)" type="primary">查看</el-link> <el-link @click="openForm('edit', row)" type="warning">编辑</el-link> <el-link @click="handleDelete(row)" type="danger">删除</el-link> </template> </el-table-column> </el-table> <div> <el-pagination v-model:current-page="searchParams.current" v-model:page-size="searchParams.size" :total="total" @change="getList" /> </div> <FormDiaLog v-if="dialogVisible" v-model="dialogVisible" ref="dialogRef" @success="getList" /> </basic-container> </template> <script setup> import { nextTick, onMounted, ref } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import { fwAreaDividePageApi, fwAreaDivideRemoveApi } from './partitionApi' import FormDiaLog from './FormDiaLog.vue' const initSearchParams = () => ({ areaName: '', // 区域名称 areaType: '', // 区域类型 current: 1, // 当前页 size: 10, // 每页大小 }) const areaTypeOptions = [ { label: '报警区', value: '报警区' }, { label: '重点管制区', value: '重点管制区' }, ] const controlLevelOptions = [ { label: '日常', value: '日常' }, { label: '重点', value: '重点' }, { label: '严密', value: '严密' }, ] const searchParams = ref(initSearchParams()) // 查询参数 const total = ref(0) // 总条数 const loading = ref(false) // 列表加载中 const list = ref([]) // 列表数据 const selectedIds = ref([]) // 勾选的ID列表 const queryParamsRef = ref(null) // 查询表单实例 const dialogRef = ref(null) // 弹框实例 const dialogVisible = ref(false) // 获取列表 async function getList() { loading.value = true try { const res = await fwAreaDividePageApi(searchParams.value) list.value = res?.data?.data?.records ?? [] total.value = res?.data?.data?.total ?? 0 } finally { loading.value = false } } // 查询 function handleSearch() { searchParams.value.current = 1 getList() } // 重置查询 function resetForm() { queryParamsRef.value?.resetFields() searchParams.value.current = 1 getList() } // 删除 async function handleDelete(row) { const tips = row ? '该条' : '选中的项' await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', { type: 'warning' }) const ids = row ? row.id : selectedIds.value.join(',') await fwAreaDivideRemoveApi({ ids }) ElMessage.success('删除成功') selectedIds.value = [] getList() } // 勾选值设置 function handleSelectionChange(rows) { selectedIds.value = rows.map(item => item.id) } function formatLocation(row) { if (row?.longitude == null || row?.latitude == null) return '' return `${row.longitude}, ${row.latitude}` } function formatFlyDate(row) { if (!row?.flyDateStart && !row?.flyDateEnd) return '' return `${row.flyDateStart || '-'} ~ ${row.flyDateEnd || '-'}` } function getOptionLabel(value, options) { const match = options.find(item => item.value === value) return match?.label ?? value ?? '' } // 新增/编辑/查看 弹框 function openForm(mode, row) { dialogVisible.value = true nextTick(() => { dialogRef.value?.open({ mode, row }) }) } onMounted(() => { getList() }) </script> <style scoped lang="scss"> </style> <style scoped lang="scss"></style> applications/drone-command/src/views/areaManage/partition/partitionApi.js
New file @@ -0,0 +1,55 @@ import request from '@/axios' // 查list export const fwAreaDividePageApi = params => { return request({ url: `/drone-fw/area/fwAreaDivide/page`, method: 'get', params, }) } // 增加或更新 export const fwAreaDivideSubmitApi = data => { return request({ url: `/drone-fw/area/fwAreaDivide/submit`, method: 'post', data, }) } //删除 export const fwAreaDivideRemoveApi = params => { return request({ url: `/drone-fw/area/fwAreaDivide/remove`, method: 'post', params, }) } //详情 export const fwAreaDivideDetailApi = params => { return request({ url: `/drone-fw/area/fwAreaDivide/detail`, method: 'get', params, }) } // 关联派出所列表 export const fwPoliceStationPageApi = params => { return request({ url: `/drone-fw/area/fwPoliceStation/page`, method: 'get', params, }) } // 关联设备列表 export const fwDevicePageApi = params => { return request({ url: `/drone-fw/device/fwDevice/page`, method: 'get', params, }) }