src/api/hpApi.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/menu/Device.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/menu/TimeLine.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/monifangzhen/schemeCard.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/tools/LayerTree.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/store/simulation.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/utils/map.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/hpApi.js
@@ -146,7 +146,20 @@ return response.data; } // 查询孙胡沟监测设备 // 接口多写几个应该无妨吧 export async function getDeviceNWJ(data, townCode) { const response = await axios.post("/hp/deviceInfo/getData", { filterObject: { "dictDeviceTypeList": [data], "townCodeList": [townCode], "year": 2025, }, "pageSize": 10000 }); return response.data; } // 查询孙胡沟监测设备,dictCommunicationType为查询孙胡沟的雨量计 export async function getDeviceInfoSHG(data) { const response = await axios.post("/hp/deviceInfo/getData", { filterObject: { src/components/menu/Device.vue
@@ -106,7 +106,7 @@ <script setup> import { ref, computed, onMounted, watch, onBeforeUnmount } from "vue"; import { useRoute, onBeforeRouteUpdate } from "vue-router"; import { createPoint, removeEntities, clearAllPoints } from "@/utils/map"; import { createPoint, clearAllPoints } from "@/utils/map"; import { deviceDictList, getDictName } from "@/constant/dict.js"; import { initeWaterPrimitiveView } from "@/utils/water"; //相机flyTo函数,后续options列表中有对应经纬度后弃用 import { useSimStore } from "@/store/simulation"; @@ -177,6 +177,7 @@ }); }; // 单个点渲染 const DevicePoints = async (item) => { // 根据需求可增删 item.type = getDictName(deviceDictList, item.dictDeviceType); src/components/menu/TimeLine.vue
@@ -2,20 +2,30 @@ <div class="timeline-container"> <div class="controls"> <div class="control-btn" @click="skipBackward"> <img src="@/assets/img/timeline/left.png" class="fas fa-step-backward" /> <img src="@/assets/img/timeline/left.png" class="fas fa-step-backward" /> </div> <div class="control-btn play-btn" @click="togglePlay"> <img v-show="isPlaying" src="@/assets/img/timeline/stop.png" /> <img v-show="!isPlaying" src="@/assets/img/timeline/start.png" /> </div> <div class="control-btn" @click="skipForward"> <img src="@/assets/img/timeline/right.png" class="fas fa-step-forward" /> <img src="@/assets/img/timeline/right.png" class="fas fa-step-forward" /> </div> <div class="speed-control" v-show="speedShow"> <div @click="toggleSpeedMenu">{{ playbackRate }}X</div> <div class="speed-menu" v-show="showSpeedMenu"> <div v-for="rate in playbackRates" :key="rate" @click.capture="setPlaybackRate(rate)" :class="{ active: playbackRate === rate }"> <div v-for="rate in playbackRates" :key="rate" @click.capture="setPlaybackRate(rate)" :class="{ active: playbackRate === rate }" > {{ rate }}X </div> </div> @@ -25,19 +35,33 @@ <div class="timeline"> <div class="dates"> <div class="current-date">当前播放时间:{{ currentPlayingTime }}</div> <div v-for="(date, index) in visibleDates" :key="index" class="date-label"> <div v-for="(date, index) in visibleDates" :key="index" class="date-label" > <!-- {{ formatDate(date) }} --> </div> <div> 专题渲染: <el-switch v-model="isColorRenderEnabled" @change="handleColorRenderChange" style="margin-top: -3px" :disabled="!isPlaying || !isWaterPrimitiveCreated" /> <el-switch v-model="isColorRenderEnabled" @change="handleColorRenderChange" style="margin-top: -3px" :disabled="!isPlaying || !isWaterPrimitiveCreated" /> <!-- active-text="开" inactive-text="关" --> </div> </div> <div class="timeline-track" ref="timelineTrack" @click="seekToPosition"> <div class="timeline-progress" :style="{ width: progressPercentage + '%' }"></div> <div class="timeline-cursor" :style="{ left: progressPercentage + '%' }"></div> <div class="timeline-progress" :style="{ width: progressPercentage + '%' }" ></div> <div class="timeline-cursor" :style="{ left: progressPercentage + '%' }" ></div> <div class="scale-markers"> <div class="scale-marker" style="left: 0%"></div> <div class="scale-marker" style="left: 25%"></div> @@ -46,8 +70,12 @@ <div class="scale-marker" style="left: 100%"></div> </div> <div class="time-markers"> <div v-for="(time, index) in timeMarkers" :key="index" class="time-marker" :style="{ left: `${index * 25}%`, transform: 'translateX(-50%)' }"> <div v-for="(time, index) in timeMarkers" :key="index" class="time-marker" :style="{ left: `${index * 25}%`, transform: 'translateX(-50%)' }" > <div class="date-part">{{ time.split(" ")[0] }}</div> <div class="time-part">{{ time.split(" ")[1] }}</div> </div> @@ -56,27 +84,38 @@ </div> <div> <div style="display: flex"> <ratelevel ref="ratelevelRef" :playing-time="sendCurrentPlayingTime" @finish-calculation="handleFinishCalculation" style=" <ratelevel ref="ratelevelRef" :playing-time="sendCurrentPlayingTime" @finish-calculation="handleFinishCalculation" style=" margin-top: 12px; margin-left: 28px; margin-right: 10px; justify-content: flex-end; " /> <crossanalysis ref="crossRef" style=" " /> <crossanalysis ref="crossRef" style=" margin-top: 12px; margin-left: 16px; margin-right: 20px; justify-content: flex-end; " /> " /> </div> <el-button @click="handleBack" style=" <el-button @click="handleBack" style=" margin-top: 3px; margin-left: 28px; margin-right: 10px; width: 75%; height: 30%; ">结束模拟</el-button> " >结束模拟</el-button > </div> </div> </template> @@ -114,7 +153,9 @@ import { useSimStore } from "@/store/simulation"; import { storeToRefs } from "pinia"; const simStore = useSimStore(); const { selectedScheme, frameNum, layerDate, schemWaterInfo } = storeToRefs(simStore); const { selectedScheme, frameNum, layerDate, schemWaterInfo } = storeToRefs(simStore); import { clearAllPoints } from "@/utils/map"; const emit = defineEmits([ "timeUpdate", @@ -352,7 +393,7 @@ // 降雨数据相关变量 let rainFallValues = ref([]); // 存储原始降雨量数据 let minRainValue = ref(Infinity); let averageRainIntensity = ref() let averageRainIntensity = ref(); let maxRainValue = ref(-Infinity); // 获取降雨数据 function getRainfallData() { @@ -435,7 +476,10 @@ rainFallValues.value = hourlyRainfallList.map((r) => r.intensity); // 计算平均雨强 if (rainFallValues.value.length > 0) { const sumIntensity = rainFallValues.value.reduce((sum, val) => sum + val, 0); const sumIntensity = rainFallValues.value.reduce( (sum, val) => sum + val, 0 ); averageRainIntensity.value = sumIntensity / rainFallValues.value.length; } else { averageRainIntensity.value = 0; // 或者 null 表示无数据 @@ -451,7 +495,6 @@ minRainValue.value, maxRainValue.value ); } // 定义降雨等级及其对应的视觉参数 const rainLevels = [ @@ -709,7 +752,8 @@ // console.log("========================================"); // console.log(`【时间戳】: ${new Date(currentTimeMs).toLocaleString()}`); console.log( `【累计降雨量 R】: ${currentTotal !== null ? currentTotal.toFixed(2) : "未知" `【累计降雨量 R】: ${ currentTotal !== null ? currentTotal.toFixed(2) : "未知" } mm` ); // console.log(`【当前阶段】: 第 ${currentStage} 阶段`); @@ -982,8 +1026,12 @@ watersMaxHeight, watersMinHeight ); const waterInfoArr = [watersMaxHeight, maxRainValue.value,averageRainIntensity.value] schemWaterInfo.value = waterInfoArr const waterInfoArr = [ watersMaxHeight, maxRainValue.value, averageRainIntensity.value, ]; schemWaterInfo.value = waterInfoArr; // 更新时间轴相关数据 if (timestamps) { frameNum.value = timestamps.length; @@ -1103,6 +1151,8 @@ } async function endSimulation() { clearAllPoints(); simStore.openDia = true; // 结束模拟之后清除layer列表 simStore.rePlayList = []; console.log(simStore.rePlayList, "结束模拟清除rePlayListrePlayList列表"); src/components/monifangzhen/schemeCard.vue
@@ -79,6 +79,10 @@ getSimresult, } from "@/api/trApi.js"; import { getAeraTownCode, getDeviceNWJ } from "@/api/hpApi"; import { createPoint, removeEntities, clearAllPoints } from "@/utils/map"; import { deviceDictList, getDictName } from "@/constant/dict.js"; const simStore = useSimStore(); const simAPIStore = SimAPIStore(); // 选中的方案 ID @@ -114,7 +118,89 @@ const { startSimulate, endSimulate } = inject("simulateActions"); const BJCode = ref([ { label: "密云区", value: "110118000000" }, { label: "房山区", value: "110111000000" }, { label: "门头沟区", value: "110109000000" }, { label: "延庆区", value: "110119000000" }, { label: "怀柔区", value: "110116000000" }, { label: "昌平区", value: "110114000000" }, { label: "平谷区", value: "110117000000" }, { label: "海淀区", value: "110108000000" }, { label: "石景山区", value: "110107000000" }, { label: "丰台区", value: "110106000000" }, ]); async function startPlay(item) { simStore.openDia = false; clearAllPoints(); const areaName = item.areaName; let districtCode; // 1. 判断是否包含 “区” if (!areaName.includes("区")) { console.log( `方案中模拟【${areaName}】不包含“区”,使用默认编码:怀柔区(110116000000)` ); districtCode = "110116000000"; // 手动指定为怀柔区编码 } else { // 2. 在 BJCode 中查找匹配的区域 value const matchedArea = BJCode.value.find((area) => area.label === areaName); if (!matchedArea) { console.warn(`未找到 ${areaName} 对应的区域编码`); return; } districtCode = matchedArea.value; } // 1. 获取乡镇区域编码 const areaRes = await getAeraTownCode(districtCode); const districtCodes = areaRes.data.map((item) => item.districtCode); // 2. 泥位计类型ID const ids = "1437295811"; // 3. 并行请求所有设备数据 const requests = districtCodes.map((code) => getDeviceNWJ(ids, code) .then((res) => res.data?.pageData || []) // 安全提取 pageData .catch((err) => { console.error(`请求失败 (code: ${code})`, err); return []; // 出错时也返回空数组,避免 Promise.all 中断 }) ); // 4. 等待所有请求完成 const allPageDataArrays = await Promise.all(requests); // 5. 合并二维数组为一维数组 const mergedPageData = allPageDataArrays.flat(); // 6. 如果不是“区”,则过滤出 deviceName 包含 "孙胡沟" 的设备 const filteredPageData = areaName.includes("区") ? mergedPageData : mergedPageData.filter((device) => device.deviceName.includes("孙胡沟")); console.log( filteredPageData, areaName.includes("区") ? "全部泥位计设备列表" : "孙胡沟泥位计设备列表" ); // 7. 创建点 filteredPageData.forEach((item) => { // 根据需求可增删 item.type = getDictName(deviceDictList, item.dictDeviceType); item.name = item.deviceName; item.id = item.deviceId; item.className = "device"; item.showLabel = true; createPoint(item); }); if (item.status === 2) { ElMessage.warning("当前方案正在分析中,无法进入模拟!"); return; src/components/tools/LayerTree.vue
@@ -323,7 +323,6 @@ */ function addTetrahedron() { getSafePoint().then((res) => { console.log(res,'resresresres') const geoJsonData = convertToGeoJson(res.data); // 转换为 GeoJSON // 加载 GeoJSON 数据到地图 loadAreaPolygon(geoJsonData, true).then((entities) => { src/store/simulation.js
@@ -2,6 +2,7 @@ import { defineStore } from 'pinia' import { ref } from 'vue' export const useSimStore = defineStore('simulation', () => { const openDia = ref(true) // 历史回放列表 const rePlayList = ref([]) // 北京市所有村的code @@ -16,6 +17,8 @@ const DeviceShowSwitch = ref(false) const DangerShowSwitch = ref(false) const DangerPoint = ref([]) // 泥位计 const selectNWJ = ref() // 监测设备列表 const devices = ref([]) const navigationShow = ref(true) @@ -218,6 +221,8 @@ schemWaterInfo, layerDate, rePlayList, selectNWJ, openDia, // 方案相关方法 setSchemCard, src/utils/map.js
@@ -1,5 +1,8 @@ import { showDeviceDetail, deviceDetail, className, dialogPositon } from "@/store"; import { componentToSlot } from "element-plus/es/components/table-v2/src/utils.mjs"; import { useSimStore } from '@/store/simulation' export function addTerrain(url) { // console.log("加载地形"); var terrainProvider = new Cesium.CesiumTerrainProvider({ @@ -84,7 +87,7 @@ // 如果已经存在该 id 的 entity,则跳过创建 if (pointEntityMap.has(id)) { clearAllPoints() console.log(`点 ${id} 已存在,跳过创建`); console.log(`点 ${id} 已存在,已清除重建`); } let position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height || 50); @@ -196,8 +199,19 @@ if (Cesium.defined(picked) && id) { const entity = picked?.id; console.log(entity.attrs, 'attrsattrsattrs') if (entity && entity.className) { const simStore = useSimStore() if (entity && !simStore.openDia) { let obj = { deviceName: entity.attrs.deviceName, latitude: entity.attrs.latitude, longitude: entity.attrs.longitude } simStore.selectNWJ = obj showDeviceDetail.value = false; console.log(simStore.selectNWJ, 'map.js点击泥位计') } if (entity && entity.className && simStore.openDia) { showDeviceDetail.value = true; deviceDetail.value = entity.attrs; className.value = entity.className;