Merge branch 'feature/v8.0/8.0.1' into prod
| | |
| | | }); |
| | | }; |
| | | |
| | | // 获取返航最高 高度 |
| | | export const getWaylineMaxTerrainHeight = data => { |
| | | return request({ |
| | | url: `/drone-odm/odmTaskInfo/odmTaskInfo/getWaylineMaxTerrainHeight`, |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | |
| | | prop: 'login_time', |
| | | type: 'date', |
| | | viewDisplay: true, //查看显示 |
| | | editDisabled: true, |
| | | labelWidth: 145, |
| | | overHidden: true, |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | |
| | | type: 'date', |
| | | hide: true, |
| | | viewDisplay: true, //查看显示 |
| | | editDisabled: true, |
| | | overHidden: true, |
| | | labelWidth: 145, |
| | | width: 160, |
| | |
| | | { name: '任务时间', value: '', field: 'cycle_time_value' }, |
| | | { name: '关联算法', value: '', field: 'ai_type_str' }, |
| | | { name: '任务描述', value: '', field: 'remark' }, |
| | | { name: '自定义识别区', value: '', field: 'enable_custom_area' }, |
| | | // { name: '任务执行次数', value: '', field: 'job_num' }, |
| | | ]) |
| | | // 机巢状态 |
| | |
| | | droneEventList.filter(({ value }) => actionActuatorFunc === value) |
| | | ) |
| | | } |
| | | if (item.name === '自定义识别区') { |
| | | item.value = res.data.data.enable_custom_area ? '是': '否' |
| | | } |
| | | getJobsAllFiles({ |
| | | wayLineJobId: detailsData.value.way_lines.map(item => item.job_id).join(','), |
| | | resultTypes: [0, 2, 4, 5], |
| | |
| | | <el-input class="ztzf-layer-input inputName" v-model="formData.name" placeholder="请输入" /> |
| | | </div> |
| | | </div> |
| | | <div class="itemRow" v-if="layerParams.addAnEditingFolder === 1 && layerParams.fileType !==2 && !itSLandPlanning"> |
| | | <div class="itemRow" v-if="(layerParams.addAnEditingFolder === 1 && layerParams.fileType !==2) || (layerParams.addAnEditingFolder === 2 && layerParams.fileType !==2) && !itSLandPlanning"> |
| | | <div class="label">关联算法</div> |
| | | <div> |
| | | <el-select |
| | |
| | | width: 324px; |
| | | |
| | | overflow: hidden; |
| | | background: rgba(0, 0, 0, 0.8); |
| | | background: rgba(0,0,0,0.51); |
| | | backdrop-filter: blur(4px); |
| | | border-radius: 8px 8px 8px 8px; |
| | | padding: 16px 12px; |
| | | |
| | |
| | | node-key="id" |
| | | default-expand-all |
| | | :expand-on-click-node="false" |
| | | :check-on-click-node="false" |
| | | :filter-node-method="filterNode" |
| | | @check="handleCheck" |
| | | :props="{ |
| | |
| | | ); |
| | | }; |
| | | const handleCheck = (checkedNodesData, checkedKeysData) => { |
| | | layerParams.value.isSingleLocating = false |
| | | const filteredNodes = checkedKeysData.checkedNodes.filter(node => node.level === 3); |
| | | checkedNodes.value = checkedNodesData.checkedNodes; |
| | | checkedNodes.value = filteredNodes |
| | | checkedKeys.value = filteredNodes.map(node => node.id); |
| | | coverData.value = filteredNodes; |
| | | emit('update:coverData', coverData.value); |
| | |
| | | ); |
| | | }; |
| | | const selectAll = () => { |
| | | layerParams.value.isSingleLocating = false |
| | | if (treeRef.value) { |
| | | const allFenceKeys = getAllFenceKeys(); |
| | | const allFenceNodes = treeData.value.flatMap(folder => folder.children); |
| | |
| | | }; |
| | | // 定位按钮事件 |
| | | const handleLocation = node => { |
| | | checkedKeys.value = []; |
| | | checkedNodes.value = []; |
| | | coverData.value = []; |
| | | if (node.data.level === 2) { |
| | | layerParams.value.isSingleLocating = false; |
| | | } else if (node.data.level === 3) { |
| | | layerParams.value.isSingleLocating = true; |
| | | } |
| | | |
| | | const currentCheckedKeys = [...checkedKeys.value]; |
| | | const currentCheckedNodes = [...checkedNodes.value]; |
| | | EventBus.emit('focusOnNode', node.data); |
| | | if (node.data.level === 2) { |
| | | const folderChildren = node.data.children || []; |
| | | // const childrenIds = folderChildren.map(child => child.id); |
| | | // treeRef.value.setCheckedKeys(childrenIds); |
| | | // checkedKeys.value = childrenIds; |
| | | // checkedNodes.value = folderChildren; |
| | | coverData.value = folderChildren; |
| | | emit('update:coverData', coverData.value); |
| | | } else { |
| | | // const currentNodeId = node.data.id; |
| | | // treeRef.value.setCheckedKeys([currentNodeId]); |
| | | // checkedKeys.value = [currentNodeId]; |
| | | // checkedNodes.value = [node.data]; |
| | | coverData.value = [node.data]; |
| | | emit('update:coverData', coverData.value); |
| | | const childrenIds = folderChildren.map(child => child.id); |
| | | // 合并已选中的节点和当前文件夹的子节点 |
| | | const newCheckedKeys = [...new Set([...currentCheckedKeys, ...childrenIds])]; |
| | | const newCheckedNodes = [...currentCheckedNodes, ...folderChildren]; |
| | | treeRef.value.setCheckedKeys(newCheckedKeys); |
| | | checkedKeys.value = newCheckedKeys; |
| | | checkedNodes.value = newCheckedNodes; |
| | | coverData.value = newCheckedNodes; |
| | | } |
| | | // 如果是单个节点(level 3),仅添加到选中列表(如果未选中) |
| | | else if (!currentCheckedKeys.includes(node.data.id)) { |
| | | layerParams.value.isSingleLocating = true |
| | | currentCheckedKeys.push(node.data.id); |
| | | currentCheckedNodes.push(node.data); |
| | | treeRef.value.setCheckedKeys(currentCheckedKeys); |
| | | checkedKeys.value = currentCheckedKeys; |
| | | checkedNodes.value = currentCheckedNodes; |
| | | coverData.value = currentCheckedNodes; |
| | | } |
| | | emit('update:coverData', coverData.value); |
| | | }; |
| | | |
| | | // 编辑按钮事件 |
| | | const handleEdit = node => { |
| | | 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); |
| | | }); |
| | | } |
| | |
| | | layerParams.value.fileType = 2; |
| | | } |
| | | }; |
| | | |
| | | function uploadFlightFile(file, t) { |
| | | const fileSuffix = file.name.substring(file.name.lastIndexOf('.') + 1); |
| | | if (!['zip'].includes(fileSuffix)) { |
| | |
| | | z-index: 99; |
| | | width: 382px; |
| | | overflow: hidden; |
| | | background: rgba(0, 0, 0, 0.8); |
| | | background: rgba(0,0,0,0.51); |
| | | backdrop-filter: blur(4px); |
| | | border-radius: 8px 8px 8px 8px; |
| | | padding: 16px 0 16px 12px; |
| | | display: flex; |
| | |
| | | width: 324px; |
| | | |
| | | overflow: hidden; |
| | | background: rgba(0, 0, 0, 0.8); |
| | | background: rgba(0,0,0,0.51); |
| | | backdrop-filter: blur(4px); |
| | | border-radius: 8px 8px 8px 8px; |
| | | padding: 16px 12px; |
| | | |
| | |
| | | </div> |
| | | <!-- 地图 --> |
| | | <div class="mapContainer"> |
| | | <!-- <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 |
| | |
| | | editFolderData: null, |
| | | editingIsProhibited: false, //禁止编辑 |
| | | isDetailShow: false, |
| | | isSingleLocating:false |
| | | }); |
| | | |
| | | const handleClick = tab => { |
| | |
| | | const handleCoverDataUpdate = data => { |
| | | selectDataList.value = data; |
| | | if (selectDataList.value.length > 0) { |
| | | |
| | | loadDataToMap(selectDataList.value); |
| | | } else { |
| | | viewer.entities.removeAll(); |
| | |
| | | zIndex: 99, |
| | | }); |
| | | }); |
| | | |
| | | |
| | | if (!layerParams.value.isSingleLocating) { |
| | | focusOnAllFeatures(); |
| | | } |
| | | viewInstance.value?.addLeftClickEvent(null, handleFenceClick); |
| | | }; |
| | | const focusOnAllFeatures = () => { |
| | |
| | | flyVisual({ |
| | | positionsData, |
| | | viewer, |
| | | multiple: 13, // 缩放倍数 |
| | | multiple:activeName.value == '国土空间规划' ? 13 :4, // 缩放倍数 |
| | | pitch: -90 |
| | | }); |
| | | }; |
| | |
| | | const handleFenceClick = movement => { |
| | | if (!viewer) return; |
| | | layerParams.value.editDetailData = null; |
| | | const pickedObject = viewer.scene.pick(movement.position); |
| | | if (Cesium.defined(pickedObject) && pickedObject.id?.customType === 'fence_polygon') { |
| | | const selectedEntity = pickedObject.id; |
| | | const selectedData = selectedEntity.customInfo; |
| | | |
| | | if(activeName.value !== '国土空间规划') { |
| | | const pickedObjects = viewer.scene.drillPick(movement.position, 10); |
| | | // 遍历所有被点击的实体,找到围栏类型(customType: 'fence_polygon') |
| | | let selectedEntity = null; |
| | | for (let i = 0; i < pickedObjects.length; i++) { |
| | | const pick = pickedObjects[i]; |
| | | if (Cesium.defined(pick.id) && pick.id?.customType === 'fence_polygon') { |
| | | selectedEntity = pick.id; |
| | | break; |
| | | } |
| | | } |
| | | // viewer.entities.values.forEach(entity => { |
| | | // if (entity.customType === 'fence_polygon') { |
| | | // entity.polygon.material = entity === selectedEntity |
| | |
| | | // : Cesium.Color.YELLOW.withAlpha(0.5); |
| | | // } |
| | | // }); |
| | | if (selectedEntity) { |
| | | const selectedData = selectedEntity.customInfo; |
| | | if (activeName.value !== '国土空间规划') { |
| | | layerParams.value.editNest = true; // 显示右侧编辑组件 |
| | | layerParams.value.decideWhetherToAddOrEdit = 2; // 标记为编辑模式 |
| | | // 根据围栏类型设置fenceType |
| | | layerParams.value.editNest = true; |
| | | layerParams.value.decideWhetherToAddOrEdit = 2; |
| | | if (activeName.value === '自定义识别区') { |
| | | layerParams.value.fenceType = 1; |
| | | } else if (activeName.value === '自定义禁飞区') { |
| | |
| | | layerParams.value.editingIsProhibited = true; |
| | | } |
| | | } |
| | | }else { |
| | | |
| | | |
| | | } |
| | | |
| | | }; |
| | | let publicCesiumInstance = null; |
| | | let viewer = null; |
| | |
| | | dom: 'layMap', |
| | | flatMode: false, |
| | | terrain: true, |
| | | layerMode: 4, |
| | | contour: false, |
| | | layerMode: 4, //轮廓线 |
| | | dockOptions:{showDock:true}//机巢 |
| | | }); |
| | | viewer = publicCesiumInstance.getViewer(); |
| | | viewInstance.value = publicCesiumInstance; |
| | | viewInstance.value?.flyToContour(); |
| | | const nanChangPosition = Cesium.Cartesian3.fromDegrees( |
| | | 115.892151, // 经度 |
| | | 28.676493, // 纬度 |
| | |
| | | } |
| | | }; |
| | | provide('layerParams', layerParams); |
| | | // onMounted(() => { |
| | | // initMap(); |
| | | // cesiumContextMenu(); |
| | | // getdataFolderApi(); |
| | | // EventBus.on('deleteMapEntityById', deleteMapEntityById); |
| | | // EventBus.on('deleteMapEntitiesByFolderId', deleteMapEntitiesByFolderId); |
| | | |
| | | // }); |
| | | onMounted(() => { |
| | | initMap(); |
| | | cesiumContextMenu(); |
| | | getdataFolderApi(); |
| | | // 监听定位事件 |
| | | EventBus.on('focusOnNode', (nodeData) => { |
| | | focusOnNode(nodeData); |
| | | }); |
| | | EventBus.on('deleteMapEntityById', deleteMapEntityById); |
| | | EventBus.on('deleteMapEntitiesByFolderId', deleteMapEntitiesByFolderId); |
| | | }); |
| | | |
| | | //定位到指定节点 |
| | | const focusOnNode = (nodeData) => { |
| | | |
| | | if (!viewer || !nodeData?.geo_data) return; |
| | | |
| | | // 解析节点坐标 |
| | | const positions = parseGeoDataToPositions(nodeData.geo_data, nodeData.altitude); |
| | | if (positions.length < 3) { |
| | | |
| | | return; |
| | | } |
| | | flyVisual({ |
| | | positionsData: positions.map(pos => [pos.lng, pos.lat, pos.height || 0]), |
| | | viewer, |
| | | multiple:activeName.value == '国土空间规划' ? 13 :7, // 缩放倍数 |
| | | pitch: -90 |
| | | }); |
| | | |
| | | }; |
| | | onBeforeUnmount(() => { |
| | | destroyMap(); |
| | | cesiumContextMenu(false); |
| | |
| | | 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%; |
| | |
| | | <el-button type="danger" plain icon="el-icon-delete" v-if="permission.user_delete && !auditMode" |
| | | @click="handleDelete">删 除 |
| | | </el-button> |
| | | <el-button type="primary" plain icon="el-icon-operation" |
| | | v-if="userInfo.role_name.includes('admin') && !auditMode" @click="handleAudit">审 核 |
| | | </el-button> |
| | | <!-- <el-button type="primary" plain icon="el-icon-operation"--> |
| | | <!-- v-if="userInfo.role_name.includes('admin') && !auditMode" @click="handleAudit">审 核--> |
| | | <!-- </el-button>--> |
| | | <el-button type="success" plain icon="el-icon-check" |
| | | v-if="userInfo.role_name.includes('admin') && auditMode" @click="handleAuditPass">通 过 |
| | | </el-button> |
| | |
| | | <el-button type="info" plain v-if="permission.user_reset && !auditMode" icon="el-icon-refresh" |
| | | @click="handleReset">密码重置 |
| | | </el-button> |
| | | <el-button type="info" plain v-if="userInfo.role_name.includes('admin') && !auditMode" |
| | | icon="el-icon-setting" @click="handlePlatform">平台配置 |
| | | </el-button> |
| | | <!-- <el-button type="info" plain v-if="userInfo.role_name.includes('admin') && !auditMode"--> |
| | | <!-- icon="el-icon-setting" @click="handlePlatform">平台配置--> |
| | | <!-- </el-button>--> |
| | | <el-button type="info" plain v-if="userInfo.role_name.includes('admin') && !auditMode" |
| | | icon="el-icon-coordinate" @click="handleLock">账号解封 |
| | | </el-button> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="关联算法" prop="ai_types"> |
| | | <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple> |
| | | <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="自定义识别区" prop="enable_custom_area" class="safe-height"> |
| | | <el-checkbox v-model="form.enable_custom_area"></el-checkbox> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="关联算法" prop="ai_types"> |
| | | <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple :disabled="detailTitle === '工单详情'"> |
| | | <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="自定义识别区" prop="enable_custom_area" class="safe-height"> |
| | | <el-checkbox v-model="form.enable_custom_area"></el-checkbox> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="关联算法" prop="ai_types"> |
| | | <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple :disabled="true"> |
| | | <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="自定义识别区" prop="enable_custom_area" class="safe-height"> |
| | | <el-checkbox v-model="form.enable_custom_area"></el-checkbox> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20"> |
| | |
| | | ? `${longitude.toFixed(6)}, ${latitude.toFixed(6)}` |
| | | : '未知位置', |
| | | address: item.address, |
| | | creator: item.event_num?.slice(0, 2) === 'AI' ? 'AI 小飞' : item.create_user, |
| | | creator: item.event_num?.slice(0, 2) === 'AI' ? '智飞agent' : item.create_user, |
| | | handler: item.update_user || '未分配', |
| | | status: Number(item.status || 0), |
| | | // 保存原始字段 |