| | |
| | | "filterObject": { |
| | | "belongObjList": [ |
| | | "1797461961110261762" |
| | | ] |
| | | ], |
| | | "townCode": data |
| | | // "id": "", |
| | | // "deviceName": "", |
| | | // "deviceCode": "", |
| | |
| | | // "dictCommunicationType": "", |
| | | // "dictDeviceStatus": "", |
| | | // "divisionDistrict": "", |
| | | // "townCode": "" |
| | | }, |
| | | "sortedList": [ |
| | | { |
| | |
| | | <script setup> |
| | | import { ref, computed, onMounted, watch, onBeforeUnmount } from "vue"; |
| | | import { useRoute, onBeforeRouteUpdate } from "vue-router"; |
| | | import { createPoint, removeEntities } from "@/utils/map"; |
| | | import { createPoint, removeEntities, clearAllPoints } from "@/utils/map"; |
| | | import { deviceDictList, getDictName } from "@/constant/dict.js"; |
| | | import { getDeviceInfoShg, getDeviceInfo } from "@/api/hpApi"; |
| | | import { initeWaterPrimitiveView } from "@/utils/water"; //相机flyTo函数,后续options列表中有对应经纬度后弃用 |
| | |
| | | } |
| | | }); |
| | | |
| | | onBeforeRouteUpdate((to, from, next) => { |
| | | if (to.path !== "/zhjc") { |
| | | handleCleanup(); |
| | | } |
| | | next(); |
| | | }); |
| | | // onBeforeRouteUpdate((to, from, next) => { |
| | | // if (to.path !== "/zhjc") { |
| | | // handleCleanup(); |
| | | // } |
| | | // next(); |
| | | // }); |
| | | const route = useRoute(); |
| | | |
| | | onBeforeUnmount(() => { |
| | | if (route.path !== "/zhjc") { |
| | | handleCleanup(); |
| | | clearAllPoints(); |
| | | } |
| | | }); |
| | | watch( |
| | |
| | | if (newValue) { |
| | | initializeDevicePoints(); |
| | | } else { |
| | | handleCleanup(); |
| | | clearAllPoints(); |
| | | } |
| | | } |
| | | ); |
| | | |
| | | const deviceListAll = ref([]); |
| | | const deviceEntities = ref([]); |
| | | const handleCleanup = () => { |
| | | deviceListAll.value.forEach((item) => { |
| | | removeEntities(item.deviceId); |
| | | }); |
| | | }; |
| | | |
| | | // const initializeDevicePoints = (val) => { |
| | | const initializeDevicePoints = () => { |
| | | const list = []; |
| | |
| | | // 根据区域名称加载设备列表 |
| | | const loadDeviceList = async (areaName) => { |
| | | try { |
| | | clearAllPoints(); |
| | | isLoading.value = true; |
| | | handleCleanup(); |
| | | // const res = await getDeviceInfoShg(); |
| | | // const allDevices = res.data.pageData; |
| | | const devicesInArea = allDevices.value.filter((item) => |
| | | deviceListAll.value = allDevices.value.filter((item) => |
| | | item.deviceName?.includes(areaName) |
| | | ); |
| | | deviceListAll.value = devicesInArea; |
| | | |
| | | initializeDevicePoints(); |
| | | // getDeviceInfo().then((res) => { |
| | | // const list = res.data.pageData; |
| | | // deviceListAll.value = []; |
| | |
| | | |
| | | .tree-container { |
| | | position: relative; |
| | | height: calc(100% - 80px); |
| | | margin-top: 10px; |
| | | height: calc(100% - 22px); |
| | | // margin-top: 10px; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, watch, onBeforeUnmount } from "vue"; |
| | | import { createPoint, removeEntities } from "@/utils/map"; |
| | | import { createPoint,clearAllPoints } from "@/utils/map"; |
| | | import { useSimStore } from "@/store/simulation"; |
| | | import { initeWaterPrimitiveView } from "@/utils/water"; //相机flyTo函数,后续options列表中有对应经纬度后弃用 |
| | | import { useRoute, onBeforeRouteUpdate } from "vue-router"; |
| | |
| | | const simStore = useSimStore(); |
| | | // onBeforeRouteUpdate((to, from, next) => { |
| | | // if (to.path !== "/yhgl") { |
| | | // handleCleanup(); |
| | | // clearAllPoints(); |
| | | // } |
| | | // next(); |
| | | // }); |
| | |
| | | |
| | | onBeforeUnmount(() => { |
| | | if (route.path !== "/yhgl") { |
| | | handleCleanup(); |
| | | clearAllPoints(); |
| | | } |
| | | }); |
| | | const selectValue = ref("孙胡沟"); |
| | |
| | | const loading = ref(true); // 控制加载状态 |
| | | |
| | | function handleClick(district) { |
| | | // 此处调用是因为GisView页面会在点击下一乡镇之前把上一个选择的区域的隐患点清除掉(如果刚好选择了孙胡沟,那么下一个点击将会清空孙胡沟的隐患点) |
| | | initializeDevicePoints(); |
| | | const entity = viewer.entities.getById(district.hdId); |
| | | if (entity) { |
| | | viewer.flyTo(entity, { |
| | |
| | | }); |
| | | } |
| | | } |
| | | const handleCleanup = async () => { |
| | | await Promise.all( |
| | | districtList.value.map((item) => removeEntities(item.hdId)) |
| | | ); |
| | | }; |
| | | |
| | | const initializeDevicePoints = async () => { |
| | | await Promise.all( |
| | | districtList.value.map(async (item, index) => { |
| | |
| | | }; |
| | | |
| | | const filterDataByArea = async (areaName) => { |
| | | handleCleanup(); |
| | | clearAllPoints(); |
| | | if (!areaName || !simStore.DangerPoint || simStore.DangerPoint.length === 0) { |
| | | districtList.value = []; |
| | | return; |
| | |
| | | isInitialized = true; |
| | | } |
| | | } else { |
| | | handleCleanup(); |
| | | clearAllPoints(); |
| | | isInitialized = false; |
| | | } |
| | | } |
| | |
| | | filterDataByArea(selectValue.value); |
| | | loading.value = false; // 数据加载完成 |
| | | } else { |
| | | handleCleanup(); |
| | | clearAllPoints(); |
| | | districtList.value = []; |
| | | loading.value = true; // 数据未准备就绪 |
| | | } |
| | |
| | | ); |
| | | |
| | | onMounted(() => { |
| | | handleCleanup(); |
| | | clearAllPoints(); |
| | | // initeWaterPrimitiveView(); |
| | | // 默认先检查一遍数据 |
| | | if (simStore.DangerPoint && simStore.DangerPoint.length > 0) { |
| | |
| | | import { showDeviceDetail, deviceDetail, className, dialogPositon } from "@/store"; |
| | | import { componentToSlot } from "element-plus/es/components/table-v2/src/utils.mjs"; |
| | | export function addTerrain(url) { |
| | | // console.log("加载地形"); |
| | | var terrainProvider = new Cesium.CesiumTerrainProvider({ |
| | |
| | | } |
| | | |
| | | let entities = []; |
| | | // 假设你有一个全局存储 entities 的结构(建议用 Map 提高性能查找) |
| | | const pointEntityMap = new Map(); // key: id, value: entity |
| | | |
| | | export function createPoint(option) { |
| | | const { |
| | | id, |
| | | type = "", |
| | | name = "默认名称", |
| | | view, |
| | | latitude, |
| | | longitude, |
| | | height, |
| | | callback, |
| | | imgWidth = 56, |
| | | imgHeight = 67, |
| | | showBillboard = true, |
| | | showLabel = true, |
| | | className = "device", |
| | | } = option; |
| | | let position = Cesium.Cartesian3.fromDegrees(longitude, latitude, 50); |
| | | const { id, type = "", name = "默认名称", view, latitude, longitude, height, callback, imgWidth = 56, imgHeight = 67, showBillboard = true, showLabel = true, className = "device" } = option; |
| | | // 如果已经存在该 id 的 entity,则跳过创建 |
| | | if (pointEntityMap.has(id)) { |
| | | console.log(`点 ${id} 已存在,跳过创建`); |
| | | return; |
| | | } |
| | | |
| | | let position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height || 50); |
| | | |
| | | let model = { |
| | | id, |
| | | name: name, |
| | |
| | | attrs: option, |
| | | className: className, |
| | | label: { |
| | | // 文本。支持显式换行符“ \ n” |
| | | text: name || "默认标签", |
| | | // 字体样式,以CSS语法指定字体 |
| | | font: "14pt Source Han Sans CN", |
| | | // 字体颜色 |
| | | |
| | | fillColor: type.includes("active") ? Cesium.Color.AQUA : Cesium.Color.WHITE, |
| | | // 背景颜色 |
| | | backgroundColor: showBillboard ? Cesium.Color.BLACK.withAlpha(0.5) : Cesium.Color.SKYBLUE, |
| | | // 是否显示背景颜色 |
| | | showBackground: true, |
| | | // 字体边框 |
| | | outline: false, |
| | | // 字体边框颜色 |
| | | outlineColor: Cesium.Color.WHITE, |
| | | // 字体边框尺寸 |
| | | outlineWidth: 0, |
| | | // 应用于图像的统一比例。比例大于会1.0放大标签,而比例小于会1.0缩小标签。 |
| | | scale: 1.0, |
| | | scaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.5), |
| | | // 设置样式:FILL:填写标签的文本,但不要勾勒轮廓;OUTLINE:概述标签的文本,但不要填写;FILL_AND_OUTLINE:填写并概述标签文本。 |
| | | style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
| | | // 相对于坐标的水平位置 |
| | | verticalOrigin: Cesium.VerticalOrigin.CENTER, |
| | | // 相对于坐标的水平位置 |
| | | horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
| | | // 该属性指定标签在屏幕空间中距此标签原点的像素偏移量 |
| | | pixelOffset: new Cesium.Cartesian2(0, -40), |
| | | // pixelOffset: new Cesium.Cartesian2(0, 0), |
| | | // 显示在距相机的距离处的属性,多少区间内是可以显示的 |
| | | distanceDisplayCondition: type.includes("河流") |
| | | ? new Cesium.DistanceDisplayCondition(0, 5000000) |
| | | : new Cesium.DistanceDisplayCondition(0, 50000), |
| | | heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, |
| | | // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, |
| | | // 是否显示 |
| | | show: showLabel, |
| | | }, |
| | | }; |
| | | |
| | | model.billboard = { |
| | | // 图像地址,URI或Canvas的属性 |
| | | image: type ? `/images/poi/${type}.png` : `/images/poi/村庄.png`, |
| | | // 高度(以像素为单位) |
| | | height: imgHeight || 20, |
| | | // 宽度(以像素为单位) |
| | | width: imgWidth || 20, |
| | | // 逆时针旋转 |
| | | // 大小是否以米为单位 |
| | | sizeInMeters: false, |
| | | // 相对于坐标的垂直位置 |
| | | verticalOrigin: Cesium.VerticalOrigin.CENTER, |
| | | // 相对于坐标的水平位置 |
| | | horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
| | | // 该属性指定标签在屏幕空间中距此标签原点的像素偏移量 |
| | | pixelOffset: new Cesium.Cartesian2(0, 3), |
| | | // 应用于图像的统一比例。比例大于会1.0放大标签,而比例小于会1.0缩小标签。 |
| | | scale: 0.8, |
| | | scaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.5), |
| | | // 显示在距相机的距离处的属性,多少区间内是可以显示的 |
| | | distanceDisplayCondition: type.includes("河流") |
| | | ? new Cesium.DistanceDisplayCondition(0, 5000000) |
| | | : new Cesium.DistanceDisplayCondition(0, 50000), |
| | | // 是否显示 |
| | | show: showBillboard, |
| | | heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, |
| | | backgroundColor: showBillboard ? Cesium.Color.BLACK.withAlpha(0.8) : Cesium.Color.SKYBLUE, |
| | | }; |
| | | |
| | | // 创建新实体并添加到地图中 |
| | | const entity = viewer.entities.add(model); |
| | | entities.push(entity); |
| | | pointEntityMap.set(id, entity); // 存入 map |
| | | |
| | | return entity; |
| | | } |
| | | // export function removeEntities() { |
| | | // entities.forEach(entity => { |
| | | // viewer.entities.remove(entity) |
| | | // entity.show = false; |
| | | // }); |
| | | // // entities = [] |
| | | // } |
| | | |
| | | |
| | | /** |
| | | * 删除所有已创建的点 |
| | | */ |
| | | export function clearAllPoints() { |
| | | for (let [id, entity] of pointEntityMap.entries()) { |
| | | viewer.entities.remove(entity); |
| | | } |
| | | pointEntityMap.clear(); |
| | | } |
| | | |
| | | export function removeEntities(id) { |
| | | entities.forEach((entity, index) => { |
| | | pointEntityMap.forEach((entity, index) => { |
| | | if (entity.id === id) { |
| | | viewer.entities.remove(entity); |
| | | } |
| | |
| | | addTileset, |
| | | addTerrain, |
| | | removeEntities, |
| | | clearAllPoints, |
| | | } from "@/utils/map.js"; |
| | | import { loadAreaPolygon } from "@/utils/area.js"; |
| | | import { loadAreaPolygonAll } from "@/utils/area_all.js"; |
| | |
| | | import { useSimStore } from "@/store/simulation"; |
| | | const simStore = useSimStore(); |
| | | |
| | | import { getDangerPoint } from "@/api/hpApi"; |
| | | import { getDangerPoint, getDeviceInfo } from "@/api/hpApi"; |
| | | /////////////////////////地图影像选择///////////////////////// |
| | | const views = [ |
| | | { label: "地图", value: "map", icon: "地图.png" }, |
| | |
| | | } |
| | | import { ElMessage } from "element-plus"; |
| | | |
| | | const districtList = ref([]); // 当前区域的隐患点列表 |
| | | const loadedPointIds = new Set(); // 已加载的隐患点ID集合 |
| | | const districtList = ref([]); |
| | | |
| | | // 设置二级区域点击处理(请求隐患点,监测设备等) |
| | | function secondaryHandler(html, item, config) { |
| | | html.element.addEventListener("click", async () => { |
| | | try { |
| | | // handleCleanup(); |
| | | // 清理已有点 |
| | | handleCleanup(); |
| | | |
| | | // 显示 loading 提示 |
| | | // 显示 loading 提示(无遮罩,仅文字+转圈) |
| | | const loadingInstance = ElMessage({ |
| | | type: "success", |
| | | message: "隐患点正在加载中...", |
| | | duration: 0, |
| | | icon: "el-icon-loading", // 确保使用的是Element Plus提供的loading图标类名 |
| | | grouping: true, |
| | | customClass: "custom-loading-message", // 添加自定义类名 |
| | | type: "info", |
| | | message: "数据正在加载中...", |
| | | duration: 0, // 持续显示,直到手动关闭 |
| | | icon: "loading", // 显示为 loading 图标(Element Plus 支持) |
| | | grouping: true, // 相同内容的消息合并,避免重复提示 |
| | | }); |
| | | // 请求隐患点数据 |
| | | const res = await getDangerPoint(item.districtCode); |
| | | |
| | | const newPoints = res.data.pageData; |
| | | let res; |
| | | if (route.path === "/yhgl") { |
| | | // 请求隐患点数据 |
| | | res = await getDangerPoint(item.districtCode); |
| | | } else if (route.path === "/zhjc") { |
| | | // 请求监测设备数据 |
| | | res = await getDeviceInfo(item.districtCode); |
| | | } else { |
| | | loadingInstance.close(); |
| | | return; |
| | | } |
| | | districtList.value = []; |
| | | // 更新数据 |
| | | districtList.value = res.data.pageData; |
| | | |
| | | if (newPoints.length === 0) { |
| | | ElMessage.warning("该区域暂无隐患点"); |
| | | districtList.value = []; |
| | | if (districtList.value.length === 0) { |
| | | ElMessage.warning("该区域暂无相关数据"); |
| | | loadingInstance.close(); |
| | | return; |
| | | } |
| | | |
| | | // 清空当前区域显示的隐患点列表(但不清除已加载的标记) |
| | | districtList.value = []; |
| | | |
| | | // 遍历新数据,过滤掉已加载过的点 |
| | | for (const [index, point] of newPoints.entries()) { |
| | | if (loadedPointIds.has(point.hdId)) { |
| | | continue; // 如果已加载,跳过 |
| | | } |
| | | |
| | | // 添加到已加载集合 |
| | | loadedPointIds.add(point.hdId); |
| | | |
| | | // 设置点属性 |
| | | point.id = point.hdId; |
| | | point.name = point.hdName; |
| | | point.latitude = point.lat; |
| | | point.longitude = point.lon; |
| | | // 创建地图点 |
| | | for (const [index, point] of districtList.value.entries()) { |
| | | point.id = point.hdId || point.deviceId; // 根据实际情况调整 |
| | | point.latitude = point.lat || point.latitude; // 根据实际情况调整 |
| | | point.longitude = point.lon || point.longitude; // 根据实际情况调整 |
| | | point.showBillboard = true; |
| | | point.type = point.disasterType; |
| | | point.type = point.disasterType || point.deviceTypeName; // 根据实际情况调整 |
| | | point.className = "district"; |
| | | |
| | | districtList.value.push(point); // 更新当前区域隐患点列表 |
| | | // ✅ 根据路由决定名称字段 |
| | | if (route.path === "/yhgl") { |
| | | point.name = point.hdName; // 隐患点名称 |
| | | point.className = "district"; |
| | | } else if (route.path === "/zhjc") { |
| | | point.name = point.deviceForShort; // 设备简称 |
| | | point.className = "device"; |
| | | } |
| | | |
| | | await createPoint(point); // 创建地图点 |
| | | await createPoint(point); |
| | | } |
| | | |
| | | // 飞向指定位置 |
| | | await flyToDistrict(item.longitude, item.latitude, config.flyToHeight); |
| | | |
| | | // 加载完成后关闭 loading |
| | | // 加载完成后关闭 loading 提示 |
| | | loadingInstance.close(); |
| | | } catch (error) { |
| | | console.error("区域点击处理失败:", error); |
| | | ElMessage.error("数据加载失败,请稍后再试"); |
| | | loadingInstance.close(); // 确保在发生错误时也关闭 loading 提示 |
| | | } |
| | | }); |
| | | } |
| | | |
| | | const handleCleanup = async () => { |
| | | await Promise.all( |
| | | districtList.value.map((item) => removeEntities(item.hdId)) |
| | | ); |
| | | districtList.value = []; |
| | | clearAllPoints(); |
| | | }; |
| | | |
| | | // 设置一级区域点击处理 |
| | |
| | | } |
| | | .earthBox.shift-right { |
| | | right: 13%; |
| | | } |
| | | .custom-loading-message .el-icon-loading { |
| | | color: #409eff !important; /* 设置为你想要的颜色 */ |
| | | font-size: 18px; /* 可选:调整图标大小 */ |
| | | } |
| | | </style> |