| src/views/layerManagement/components/leftList.vue | ●●●●● patch | view | raw | blame | history | |
| src/views/layerManagement/components/rightEdit.vue | ●●●●● patch | view | raw | blame | history | |
| src/views/layerManagement/index.vue | ●●●●● patch | view | raw | blame | history |
src/views/layerManagement/components/leftList.vue
@@ -15,7 +15,9 @@ <el-button v-if="activeName !== '国土空间规划'" class="ztzf-button" @click="addFence">{{ props.activeName === '电子围栏' ? '新增围栏' : '新增禁飞区' }}</el-button> <el-button v-if="activeName !== '国土空间规划'" class="ztzf-button" @click="addFolder">新增文件夹</el-button> <el-button v-if="activeName !== '国土空间规划'" class="ztzf-button" @click="addFolder" >新增文件夹</el-button > <el-upload v-if="activeName === '国土空间规划'" action="#" @@ -28,25 +30,18 @@ <template v-if="activeName === '自定义禁飞区'"> <template v-if="failuresInfo.length"> <el-button class="ztzf-button" @click="synchronize"> 继续同步 </el-button> <el-button class="ztzf-button" @click="failuresDel"> 取消同步 </el-button> <el-button class="ztzf-button" @click="synchronize"> 继续同步 </el-button> <el-button class="ztzf-button" @click="failuresDel"> 取消同步 </el-button> </template> <el-button v-else class="ztzf-button" @click="synchronize"> 同步 </el-button> <el-button v-else class="ztzf-button" @click="synchronize"> 同步 </el-button> </template> <el-button class="ztzf-button" @click="selectAll">全选</el-button> </div> <div class="tableListBox"> <el-tree class="ztzf-el-tree" :class="{isTheTerritory:activeName === '国土空间规划'}" :class="{ isTheTerritory: activeName === '国土空间规划' }" ref="treeRef" v-model="checkedKeys" :data="treeData" @@ -68,7 +63,8 @@ <span>{{ node.label }}</span> <!-- 操作按钮组 --> <div class="tree-node-actions"> <el-button link <el-button link icon="el-icon-location" @click.stop="handleLocation(node)" ></el-button> @@ -90,7 +86,8 @@ deleteFolderApi, spatialPlanningApi, failuresListApi, failuresDelApi, areasUpdateApi failuresDelApi, areasUpdateApi, } from '@/api/layer/index'; import { inject, nextTick, onMounted, watch } from 'vue'; const emit = defineEmits(['update:coverData', 'update:deitData', 'newFencesMethods']); @@ -129,7 +126,7 @@ newVal => { const matchedCategory = treeAllData.value.find(item => item.name === newVal); treeData.value = matchedCategory.children; nextTick(search) nextTick(search); if (treeData.value && treeData.value.length > 0) { const folderNode = treeData.value[0]; // 赋值给 layerParams @@ -172,10 +169,10 @@ } }; // 定位按钮事件 const handleLocation = (node) => { checkedKeys.value = []; checkedNodes.value = []; coverData.value = []; const handleLocation = node => { checkedKeys.value = []; checkedNodes.value = []; coverData.value = []; if (node.data.level === 2) { const folderChildren = node.data.children || []; const childrenIds = folderChildren.map(child => child.id); @@ -183,11 +180,11 @@ checkedKeys.value = childrenIds; checkedNodes.value = folderChildren; coverData.value = folderChildren; emit('update:coverData', coverData.value); }else{ console.log('node',node.data); emit('update:coverData', [node.data]); } else { console.log('node', node.data); emit('update:coverData', [node.data]); } }; // 编辑按钮事件 @@ -219,32 +216,33 @@ // 删除按钮事件 const handleDelete = node => { let id = node.data.id; // 弹出确认弹框 ElMessageBox.confirm( '确定要删除该内容吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ).then(() => { // 点击确定,执行删除逻辑 if (node.data.level === 2) { deleteFolderApi(id).then(res => { ElMessage.success('删除成功'); gettreeDataApi(); }); } else if (node.data.level === 3) { deleteFenceApi(id).then(res => { ElMessage.success('删除成功'); gettreeDataApi(); }); } }).catch(() => { // 点击取消,不执行操作 ElMessage.warning('已取消删除'); }); ElMessageBox.confirm('确定要删除该内容吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }) .then(() => { if (node.data.level === 2) { // 删除文件夹 deleteFolderApi(id).then(res => { ElMessage.success('删除成功'); gettreeDataApi(); // 通知父组件删除该文件夹下所有围栏的地图实体 EventBus.emit('deleteMapEntitiesByFolderId', id); }); } else if (node.data.level === 3) { // 删除单个围栏/禁飞区 deleteFenceApi(id).then(res => { ElMessage.success('删除成功'); gettreeDataApi(); // 通知父组件删除对应的地图实体 EventBus.emit('deleteMapEntityById', id); }); } }) .catch(() => { ElMessage.warning('已取消删除'); }); }; // 新增围栏 const addFence = () => { @@ -281,64 +279,63 @@ Object.keys(params).forEach(key => { data.append(key, params[key]); }); spatialPlanningApi(data).then(res =>{ spatialPlanningApi(data).then(res => { ElMessage.success('上传成功'); gettreeDataApi(); }) }); } function search() { treeRef.value?.filter(formData.value.dkbh) treeRef.value?.filter(formData.value.dkbh); } function reset() { formData.value.dkbh = '' treeRef.value?.filter('') formData.value.dkbh = ''; treeRef.value?.filter(''); } function filterNode(value,data) { if (props.activeName === '国土空间规划'){ if (!value) return (data.level===2 || data.level===1) return (data.level===2 || data.level===1) && data.name.includes(value) function filterNode(value, data) { if (props.activeName === '国土空间规划') { if (!value) return data.level === 2 || data.level === 1; return (data.level === 2 || data.level === 1) && data.name.includes(value); } if (!value) return true return data.name.includes(value) if (!value) return true; return data.name.includes(value); } // 同步信息 const failuresInfo = ref([]) const failuresInfo = ref([]); function failuresList() { failuresListApi().then(res => { failuresInfo.value = res.data.data || [] }) failuresInfo.value = res.data.data || []; }); } // 同步 function synchronize() { const data = failuresInfo.value.map(item => item.device_sn) const data = failuresInfo.value.map(item => item.device_sn); areasUpdateApi(data).then(res => { if (res.data.data.length){ if (res.data.data.length) { let stringVal = res.data.data.reduce((acc, cur) => { return acc + cur.nickname + '(' + cur.reason + ')' + ',' }, '') stringVal = stringVal.slice(0, -1) return acc + cur.nickname + '(' + cur.reason + ')' + ','; }, ''); stringVal = stringVal.slice(0, -1); ElMessageBox.alert(stringVal, '同步失败', { confirmButtonText: '确定', }) }else{ }); } else { ElMessage.success('同步成功'); } }) }); } // 取消同步 function failuresDel() { failuresDelApi().then(res => { ElMessage.success('取消同步成功'); }) }); } onMounted(() => { failuresList() failuresList(); gettreeDataApi(); EventBus.on('gettreeDataApi', gettreeDataApi); }); @@ -411,7 +408,7 @@ display: flex; gap: 0 10px; .el-button{ .el-button { margin: 0 !important; } } @@ -426,12 +423,12 @@ // background-color: rgba(30, 45, 81, 0.5) !important; // } //} overflow-y: scroll; height: 0; flex-grow: 1; .isTheTerritory{ :deep(){ .el-tree-node__expand-icon{ overflow-y: scroll; height: 0; flex-grow: 1; .isTheTerritory { :deep() { .el-tree-node__expand-icon { visibility: hidden; } } src/views/layerManagement/components/rightEdit.vue
@@ -8,7 +8,6 @@ <el-select :disabled="isDisabled" class="ztzf-layer-search" clearable v-model="formData.folder_id" placeholder="请选择" @@ -36,11 +35,10 @@ <div class="itemRow" v-if="layerParams.fenceType === 2"> <div class="label">禁飞区管控时间</div> <div> <!-- popper-class="ztzf-layer-date-picker-popper " --> <!-- popper-class="ztzf-layer-date-picker-popper " --> <el-date-picker :disabled="isDisabled" class="ztzf-layer-date-picker " class="ztzf-layer-date-picker" v-model="timeValue" type="datetimerange" format="YYYY-MM-DD HH:mm" @@ -123,7 +121,7 @@ </div> </div> <div class="btnGroups"> <img src="/src/assets/images/layerManagement/savebtn.svg" alt="" @click="submitHandle" /> <img src="/src/assets/images/layerManagement/savebtn.svg" alt="" @click="submitHandle" /> <img src="/src/assets/images/layerManagement/cancelbtn.svg" @click="cancelHandel" alt="" /> </div> </div> @@ -173,6 +171,8 @@ watch( () => layerParams.value.editDetailData, newVal => { console.log('newVal', newVal); if (newVal && layerParams.value.editingIsProhibited) { // 当editDetailData有值时,填充表单 formData.value = { @@ -263,10 +263,13 @@ is_enabled: true, area: formData.value.area, altitude: formData.value.altitude, geo_data: layerParams.value.polygonPosition || formData.value.geo_data, geo_data: layerParams.value.polygonPosition ? layerParams.value.polygonPosition : formData.value.geo_data, control_start_time: formData.value.control_start_time, control_end_time: formData.value.control_end_time, }; // 如果是编辑模式,才添加 id if (layerParams.value.decideWhetherToAddOrEdit === 2) { params.id = detailData.value.id; @@ -284,6 +287,7 @@ deitFenceApi(params).then(res => { ElMessage.success('编辑成功'); EventBus.emit('gettreeDataApi'); clearAllData(); emit('callParentMethod'); }); @@ -365,9 +369,9 @@ width: auto !important; background: transparent !important; } :deep(.el-range-editor.is-disabled input ){ background-color: transparent !important; } :deep(.el-range-editor.is-disabled input) { background-color: transparent !important; } } .detailInfo { .infpItem { src/views/layerManagement/index.vue
@@ -9,9 +9,13 @@ </div> <!-- 地图 --> <div class="mapContainer"> <div class="tool-tip" v-if="layerParams.addNest "> 点击地图生成测绘区域 </div> <!-- <div class="tool-tip warning" v-show="isShowWaringTip"> <span class="icon"> <el-icon><WarningFilled /></el-icon> </span> <span>测区不支持交叉面,无法生成航线</span> </div> --> <div class="tool-tip" v-if="layerParams.addNest">点击地图生成测绘区域</div> <div id="layMap" class="ztzf-cesium"></div> <leftList v-if=" @@ -27,13 +31,13 @@ @newFencesMethods="newFencesMethods" ></leftList> <rightEdit v-if="layerParams.addNest || (layerParams.editNest)" v-if="layerParams.addNest || layerParams.editNest" @callParentMethod="parentMethod" ></rightEdit> <folderFile @refreshMethod="refreshMethod" @refreshMethod="refreshMethod" :activeName="activeName" v-if="layerParams.addFolder || (layerParams.editFolder)" v-if="layerParams.addFolder || layerParams.editFolder" ></folderFile> </div> </div> @@ -41,6 +45,7 @@ </template> <script setup> import EventBus from '@/utils/eventBus'; import * as turf from '@turf/turf'; import { dataFolderApi } from '@/api/layer/index'; import folderFile from '@/views/layerManagement/components/folderFile.vue'; @@ -60,7 +65,8 @@ const userInfo = computed(() => store.getters.userInfo); const areaCode = userInfo.value?.detail?.areaCode || ''; // console.log('用户信息',areaCode); // 红色警告交叉面提示窗 const isShowWaringTip = ref(false); const activeName = ref('电子围栏'); const activeType = ref('0'); let tbJwdList = []; @@ -97,8 +103,8 @@ fenceArea: 0, //围栏面积 fileType: 1, //文件夹类型 editFolderData: null, editingIsProhibited:false,//禁止编辑 isDetailShow:false editingIsProhibited: false, //禁止编辑 isDetailShow: false, }); const handleClick = tab => { @@ -106,11 +112,11 @@ activeType.value = clickedTab.type; activeName.value = clickedTab.name; getdataFolderApi(); parentMethod() parentMethod(); }; const refreshMethod =()=>{ getdataFolderApi() } const refreshMethod = () => { getdataFolderApi(); }; const getdataFolderApi = () => { let id; if (activeName.value === '电子围栏') { @@ -126,7 +132,7 @@ label: folder.name, value: folder.id.toString(), })); layerParams.value.folderOption = formattedFolderOption; layerParams.value.folderOption = formattedFolderOption; }); }; // 编辑围栏区域 @@ -134,7 +140,7 @@ viewer.entities.removeAll(); layerParams.value.editDetailData = val; drawPolygonExample.editThePatch(true); drawPolygonExample.drawTheArea(true); drawPolygonExample.drawTheArea(true); const positions = parseGeoDataToPositions(val.geo_data, val.altitude); if (positions.length < 3) return; // 少于3个点无法构成多边形 drawPolygonExample.initPolygon(viewer, positions, true); @@ -154,7 +160,7 @@ const parentMethod = () => { drawPolygonExample.delPolygon(); drawPolygonExample.drawTheArea(false); viewer.entities.removeAll(); viewer.entities.removeAll(); }; // 点击显示区域 const handleCoverDataUpdate = data => { @@ -209,7 +215,6 @@ }); focusOnAllFeatures(); viewInstance.value?.addLeftClickEvent(null, handleFenceClick); }; //计算所有图斑的包围球并定位 const focusOnAllFeatures = () => { @@ -236,29 +241,28 @@ const pickedObject = viewer.scene.pick(movement.position); if (Cesium.defined(pickedObject) && pickedObject.id?.customType === 'fence_polygon') { const selectedEntity = pickedObject.id; const selectedData = selectedEntity.customInfo; // viewer.entities.values.forEach(entity => { // if (entity.customType === 'fence_polygon') { // entity.polygon.material = entity === selectedEntity // ? Cesium.Color.RED.withAlpha(0.5) // : Cesium.Color.YELLOW.withAlpha(0.5); // } // }); if (activeName.value !== '国土空间规划') { layerParams.value.editNest = true; // 显示右侧编辑组件 layerParams.value.decideWhetherToAddOrEdit = 2; // 标记为编辑模式 // 根据围栏类型设置fenceType if (activeName.value === '电子围栏') { layerParams.value.fenceType = 1; } else if (activeName.value === '自定义禁飞区') { layerParams.value.fenceType = 2; const selectedData = selectedEntity.customInfo; // viewer.entities.values.forEach(entity => { // if (entity.customType === 'fence_polygon') { // entity.polygon.material = entity === selectedEntity // ? Cesium.Color.RED.withAlpha(0.5) // : Cesium.Color.YELLOW.withAlpha(0.5); // } // }); if (activeName.value !== '国土空间规划') { layerParams.value.editNest = true; // 显示右侧编辑组件 layerParams.value.decideWhetherToAddOrEdit = 2; // 标记为编辑模式 // 根据围栏类型设置fenceType if (activeName.value === '电子围栏') { layerParams.value.fenceType = 1; } else if (activeName.value === '自定义禁飞区') { layerParams.value.fenceType = 2; } layerParams.value.editDetailData = selectedData; layerParams.value.fenceArea = selectedData.area; layerParams.value.editingIsProhibited = true; } layerParams.value.editDetailData = selectedData; layerParams.value.fenceArea = selectedData.area; layerParams.value.editingIsProhibited = true } } }; let publicCesiumInstance = null; let viewer = null; @@ -300,6 +304,7 @@ // 编辑/绘制 const loadPlanarRoute = async (positions = null, save = false) => { isShowWaringTip.value = false; if (positions) { curPolygonPosition = positions.map(item => { let cartographic = Cesium.Cartographic.fromCartesian(item); @@ -314,9 +319,9 @@ }); } let polygon = curPolygonPosition.map(item => [item?.lng, item?.lat]); let polygon = curPolygonPosition.map(item => [item?.lng, item?.lat]); let polygonString = JSON.stringify(polygon); layerParams.value.polygonPosition = polygonString; layerParams.value.polygonPosition = polygon.length > 0 ? polygonString : null; if (polygon.length >= 3) { // 确保多边形闭合:最后一个点与第一个点一致(避免计算偏差) const firstPoint = polygon[0]; @@ -337,6 +342,9 @@ layerParams.value.fenceArea = 0; } }; drawPolygonExample.subscribe('getShowWaringTip', data => { isShowWaringTip.value = data; }); const throttleLoadPlanarRoute = throttle(loadPlanarRoute, 200); drawPolygonExample.subscribe('getPolygonPositions', data => { throttleLoadPlanarRoute(data); @@ -366,16 +374,60 @@ } }; provide('layerParams', layerParams); // onMounted(() => { // initMap(); // cesiumContextMenu(); // getdataFolderApi(); // }); // onBeforeUnmount(() => { // destroyMap(); // cesiumContextMenu(false); // }); onMounted(() => { initMap(); cesiumContextMenu(); getdataFolderApi(); // 监听单个实体删除事件 EventBus.on('deleteMapEntityById', deleteMapEntityById); // 监听文件夹下所有实体删除事件 EventBus.on('deleteMapEntitiesByFolderId', deleteMapEntitiesByFolderId); }); onBeforeUnmount(() => { destroyMap(); cesiumContextMenu(false); // 移除事件监听 EventBus.off('deleteMapEntityById', deleteMapEntityById); EventBus.off('deleteMapEntitiesByFolderId', deleteMapEntitiesByFolderId); }); // 删除单个地图实体 const deleteMapEntityById = entityId => { if (!viewer) return; const entity = viewer.entities.getById(`polygon_${entityId}`); if (entity) { viewer.entities.remove(entity); } // 更新选中数据列表 selectDataList.value = selectDataList.value.filter(item => item.id !== entityId); }; // 删除文件夹下所有地图实体 const deleteMapEntitiesByFolderId = folderId => { if (!viewer) return; // 假设围栏数据中包含 folder_id 字段,根据文件夹ID过滤 const entitiesToDelete = viewer.entities.values.filter(entity => { return entity.customInfo?.folder_id === folderId; }); entitiesToDelete.forEach(entity => { viewer.entities.remove(entity); }); // 更新选中数据列表 selectDataList.value = selectDataList.value.filter(item => item.folder_id !== folderId); }; </script> <style scoped lang="scss"> @@ -387,28 +439,40 @@ position: relative; width: 100%; height: 80vh; .warning { position: absolute; top: 234px; color: #fff; background: rgba(140, 0, 0, 0.4); .icon { display: flex; align-items: center; color: #ff1f1f; } } #layMap { width: 100%; height: 100%; } .tool-tip { display: flex; justify-content: center; align-items: center; position: absolute; width: 800px; height: 64px; right: 430px; top: 60px; font-family: Source Han Sans CN, Source Han Sans CN; font-size: 18px; color: #ffffff; display: flex; justify-content: center; align-items: center; position: absolute; width: 800px; height: 64px; right: 430px; top: 60px; font-family: Source Han Sans CN, Source Han Sans CN; font-size: 18px; color: #ffffff; background: rgba(11, 31, 58, 0.7); -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; } background: rgba(11, 31, 58, 0.7); -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; } } </style>