From 4b7b8185bdce4272cd5f256fcc777056f54add6d Mon Sep 17 00:00:00 2001 From: wangjuncheng <1> Date: 星期一, 16 六月 2025 17:03:09 +0800 Subject: [PATCH] 123 --- src/components/monifangzhen/schemeInfo.vue | 3 src/components/monifangzhen/WaterDepthContent.vue | 306 +++++++++++++++++ src/components/menu/flowRate_waterLevel多点测量.vue | 254 ++++++++++++++ src/api/trApi.js | 6 src/utils/tools.js | 5 src/components/tools/Tools.vue | 8 src/components/menu/flowRate_waterLevel.vue | 40 + src/components/monifangzhen/schemeCard.vue | 5 src/components/monifangzhen/flowRateTab.vue | 69 +++ src/utils/water.js | 46 + src/components/monifangzhen/DangerAssess.vue | 2 src/components/monifangzhen/WaterVelocityContent.vue | 300 ++++++++++++++++ src/components/menu/TimeLine.vue | 27 13 files changed, 1,019 insertions(+), 52 deletions(-) diff --git a/src/api/trApi.js b/src/api/trApi.js index 3581efe..53d8f50 100644 --- a/src/api/trApi.js +++ b/src/api/trApi.js @@ -107,7 +107,9 @@ flowUrl: jsonData.flowUrl, waterUrl: jsonData.waterUrl, version: jsonData.version, - waterTimestamps: waterTimestamps, // 鍘熷鏃堕棿鏁扮粍 + waterTimestamps: waterTimestamps, + watersMaxHeight: jsonData.waters.maxHeight, + watersMinHeight: jsonData.waters.minHeight, }; } catch (error) { console.error("瑙f瀽姘存ā鎷熸暟鎹椂鍑洪敊:", error); @@ -124,7 +126,7 @@ throw new Error(`HTTP error! status: ${response.status}`); } const jsonData = await response.json(); // 瑙f瀽 JSON 鏁版嵁 - console.log(jsonData, "jsonjsonjsonjson"); + // console.log(jsonData, "jsonjsonjsonjson"); return parseWaterSimulationData(jsonData); // 璋冪敤瑙f瀽鍑芥暟 } catch (error) { console.error("璇锋眰鎴栬В鏋愭暟鎹椂鍑洪敊:", error); diff --git a/src/components/menu/TimeLine.vue b/src/components/menu/TimeLine.vue index f799f1e..c2cd6ea 100644 --- a/src/components/menu/TimeLine.vue +++ b/src/components/menu/TimeLine.vue @@ -58,10 +58,12 @@ <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="margin-top: 12px; margin-left: 16px; margin-right: 20px;justify-content: flex-end;" /> + <crossanalysis ref="crossRef" + style="margin-top: 12px; margin-left: 16px; margin-right: 20px;justify-content: flex-end;" /> </div> - <el-button @click="handleBack" style="margin-top: 3px; margin-left: 28px; margin-right: 10px;width: 75%;height: 30%;">缁撴潫妯℃嫙</el-button> + <el-button @click="handleBack" + style="margin-top: 3px; margin-left: 28px; margin-right: 10px;width: 75%;height: 30%;">缁撴潫妯℃嫙</el-button> </div> </div> @@ -136,8 +138,8 @@ rainColor: "#99B3CC", rainDensity: 30 // 闆ㄧ殑瀵嗗害 }); -let minFlowRate =ref() -let maxFlowRate =ref() +let minFlowRate = ref() +let maxFlowRate = ref() // 璁$畻灞炴�� const progressPercentage = computed( () => (currentTime.value / duration.value) * 100 @@ -167,8 +169,8 @@ // baseUrl: `/simu/c2h1dc`, interval: intervalMap[playbackRate.value], colorRender: isColorRenderEnabled.value, - minFlowRate:0.1, - maxFlowRate:10, + minFlowRate, + maxFlowRate, }); isWaterPrimitiveCreated.value = true; } else { @@ -545,12 +547,13 @@ // 褰撳墠鏂规鐨勬墍鏈変俊鎭� const schemeInfo = selectedScheme.value; serviceInfo = schemeInfo.serviceName; - // minFlowRate = schemeInfo.鏈�灏忔按娣� - // maxFlowRate = schemeInfo.鏈�澶ф按娣� + // console.log('鑾峰彇鍒扮殑 serviceName:', serviceInfo); getRainfallData() // 鏍规嵁layer.json鍘昏幏鍙栨椂闂磋酱淇℃伅 - const { waterTimestamps: timestamps } = await fetchWaterSimulationData(serviceInfo); + const { waterTimestamps: timestamps, watersMaxHeight, watersMinHeight } = await fetchWaterSimulationData(serviceInfo); + console.log('褰撳墠鏂规涓嬬殑鏈�澶ф按浣嶆繁搴﹀拰鏈�灏忔按浣嶆繁搴�',watersMaxHeight,watersMinHeight); + // 鐜板湪鏄寜鐓ф�诲叡鏈夊灏戜釜鐐规潵娓叉煋鏃堕棿杞� if (timestamps) { waterTimestamps.value = timestamps; @@ -561,6 +564,8 @@ "YYYY-MM-DD HH:mm:ss" ); } + minFlowRate = watersMinHeight + maxFlowRate = watersMaxHeight } catch (error) { console.error("Error loading water simulation data:", error); ElMessage({ @@ -596,7 +601,7 @@ if (crossRef.value) { crossRef.value.clearPoints(); console.log('鎵ц鍒犻櫎鐐瑰姛鑳�'); - + } emit("isColorRender", false); setTimeout(() => { @@ -604,6 +609,8 @@ }, 3000); destoryWaterPrimitive(); EventBus.emit("hide-schemeInfo"); + EventBus.emit("clear-water-depth"); + EventBus.emit("clear-water-velocity"); ElMessage({ message: "妯℃嫙杩涚▼姝e湪鍏抽棴涓�...", type: "success" }); } </script> diff --git a/src/components/menu/flowRate_waterLevel.vue b/src/components/menu/flowRate_waterLevel.vue index 21082db..dbb557f 100644 --- a/src/components/menu/flowRate_waterLevel.vue +++ b/src/components/menu/flowRate_waterLevel.vue @@ -53,7 +53,8 @@ import { useSimStore } from "@/store/simulation"; import { storeToRefs } from "pinia"; const simStore = useSimStore(); -const { selectedScheme } = storeToRefs(simStore); +const { selectedScheme, currentInfo } = storeToRefs(simStore); +import { EventBus } from "@/eventBus"; const pickedPoints = ref([]); const handler = ref(null); @@ -89,11 +90,16 @@ const schemeInfo = selectedScheme.value; serviceInfo = schemeInfo.serviceName; + // 濡傛灉宸叉湁閫変腑鐐癸紝鍒欏厛娓呴櫎 + if (pickedPoints.value.length >= 1) { + endCalculation(); // 娓呴櫎鎵�鏈夊凡鏈夌偣 + } + // 鍒涘缓 label 瀹炰綋 const labelEntity = viewer.entities.add({ position: point.cartesian, label: { - text: `娴嬮噺鐐� ${pickedPoints.value.length + 1}\n姘存繁: 绛夊緟鍚姩...\n娴侀��: 绛夊緟鍚姩...`, + text: `娴嬮噺鐐筡n姘存繁: 绛夊緟鍚姩...\n娴侀��: 绛夊緟鍚姩...`, font: 'bold 14pt monospace', style: Cesium.LabelStyle.FILL_AND_OUTLINE, fillColor: Cesium.Color.YELLOW, @@ -109,6 +115,7 @@ pixelOffsetScaleByDistance: new Cesium.NearFarScalar(100, 1.0, 5000, 0.3), } }); + const groundPosition = Cesium.Cartesian3.fromRadians( point.longitude * Math.PI / 180, point.latitude * Math.PI / 180, @@ -128,16 +135,21 @@ distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 5000) } }); - + // 瀛樺偍瀹炰綋寮曠敤涔嬪墠灏辨洿鏂� currentInfo + currentInfo.value = { + longitude: point.longitude, + latitude: point.latitude, + serviceInfo: serviceInfo + }; // 璇锋眰鏁版嵁骞舵洿鏂� label getFlowRateInfo(point.longitude, point.latitude, displayTime).then(result => { - updateLabel(pickedPoints.value.length - 1, result.depth, result.velocity); + updateLabel(pickedPoints.value.length, result.depth, result.velocity); }); // 瀛樺偍瀹炰綋寮曠敤 pickedPoints.value.push({ labelEntity, - cylinderEntity, // 浣跨敤鍦嗘煴浠f浛 line 鍜� circle + cylinderEntity, longitude: point.longitude, latitude: point.latitude }); @@ -199,18 +211,19 @@ ); async function updateAllLabels() { - for (const pointInfo of pickedPoints.value) { + for (let i = 0; i < pickedPoints.value.length; i++) { + const pointInfo = pickedPoints.value[i]; if (!pointInfo || !pointInfo.labelEntity) continue; - const result = await getFlowRateInfo(pointInfo.longitude, pointInfo.latitude, currentTime.value); - updateLabel(pointInfo, result.depth, result.velocity); + updateLabel(i, result.depth, result.velocity); } } -function updateLabel(pointInfo, depth, velocity) { - if (pointInfo.labelEntity && pointInfo.labelEntity.label) { +function updateLabel(index, depth, velocity) { + const pointInfo = pickedPoints.value[index]; + if (pointInfo && pointInfo.labelEntity && pointInfo.labelEntity.label) { pointInfo.labelEntity.label.text = ` -娴嬮噺鐐� ${pickedPoints.value.findIndex(p => p === pointInfo) + 1} +娴嬮噺鐐� 姘存繁: ${depth} m 娴侀��: ${velocity} m/s `.trim(); @@ -222,6 +235,9 @@ if (pointInfo.cylinderEntity) viewer.entities.remove(pointInfo.cylinderEntity); }); pickedPoints.value = []; + EventBus.emit("clear-water-depth"); + EventBus.emit("clear-water-velocity"); + } defineExpose({ @@ -236,7 +252,7 @@ serviceName: serviceInfo }; return getFlowRate(params).then(data => { - // console.log('鑾峰彇鍒扮殑鏁版嵁:', data); + console.log('鑾峰彇鍒扮殑鏁版嵁:', data); if (data && data.code === 200) { return { depth: data.data.depth.toFixed(2), diff --git "a/src/components/menu/flowRate_waterLevel\345\244\232\347\202\271\346\265\213\351\207\217.vue" "b/src/components/menu/flowRate_waterLevel\345\244\232\347\202\271\346\265\213\351\207\217.vue" new file mode 100644 index 0000000..21082db --- /dev/null +++ "b/src/components/menu/flowRate_waterLevel\345\244\232\347\202\271\346\265\213\351\207\217.vue" @@ -0,0 +1,254 @@ +<template> + <div style="display: flex;justify-content: space-between;"> + <el-tooltip class="box-item" effect="dark" placement="top" show-after="1000"> + <template #content> + 姘存繁/娴侀�熷垎鏋愬姛鑳借鏄庯細 + <br /><br /> + 馃敼 鐐瑰嚮鎸夐挳鍒囨崲鐘舵�侊細 + <br /> + - 鐧借壊锛氬叧闂嬀鍙栧姛鑳斤紙涓嶅彲閫夌偣锛� + <br /> + - 榛勮壊锛氬紑鍚嬀鍙栧姛鑳斤紙鍙偣鍑诲湴鍥鹃�夋嫨鍒嗘瀽鐐癸級 + <br /><br /> + 馃敼 浣跨敤娴佺▼锛� + <br /> + 1. 鐐瑰嚮鎸夐挳鍒囨崲涓洪粍鑹茬姸鎬� 鉃� 寮�濮嬫嬀鍙栧潗鏍囩偣 + <br /> + 2. 鍦ㄥ湴鍥句笂鐐瑰嚮鎵�闇�浣嶇疆 鉃� 娣诲姞姘存繁/娴侀�熷垎鏋愮偣 + <br /> + 3. 瀹屾垚閫夌偣鍚庯紝璇峰皢鎸夐挳鍒囧洖鐧借壊 鉃� 鍏抽棴鎷惧彇鍔熻兘 + <br /><br /> + 鈿狅笍 娓╅Θ鎻愮ず锛� + <br /> + 浣跨敤瀹屾瘯璇峰姟蹇呭叧闂嬀鍙栧姛鑳斤紝閬垮厤璇搷浣滃奖鍝嶅叾浠栧姛鑳姐�� + </template> + <div @click="togglePick" :class="['pick-button', { active: isPickingActive }]"> + <img v-if="!isPickingActive" src="@/assets/img/timeline/娴侀��.png" style="width: 28px;height: 28px;" /> + <img v-else src="@/assets/img/timeline/宸叉祦閫�.png" style="width: 28px;height: 28px;" /> + </div> + </el-tooltip> + <el-tooltip class="box-item" effect="dark" placement="top" show-after="1000"> + <template #content> + 娓呴櫎鎵�鏈夊垎鏋愬潗鏍囩偣鍙婂垎鏋愮粨鏋滐細 + <br /><br /> + 馃攣 鍔熻兘璇存槑锛� + <br /> + 鐐瑰嚮鍚庡皢绉婚櫎鍦板浘涓婄殑鎵�鏈夋按娣�/娴侀�熷垎鏋愮偣浠ュ強鐩稿叧鍒嗘瀽鍥捐〃 + <br /><br /> + 鈿狅笍 娓╅Θ鎻愮ず锛� + <br /> + 姝ゆ搷浣滀細娓呯┖褰撳墠鍒嗘瀽杩涘害锛岃纭鍚庡啀鎵ц + </template> + <div @click="endCalculation"> + <img src="@/assets/img/timeline/娓呴櫎.png" style="width: 26px;height: 26px;" /> + </div> + </el-tooltip> + </div> +</template> + +<script setup> +import { defineProps, watch, ref, onMounted, defineExpose } from "vue"; +import { ElMessage } from 'element-plus'; +import { getFlowRate } from "@/api/trApi.js"; +import { useSimStore } from "@/store/simulation"; +import { storeToRefs } from "pinia"; +const simStore = useSimStore(); +const { selectedScheme } = storeToRefs(simStore); + +const pickedPoints = ref([]); +const handler = ref(null); +const isPickingActive = ref(false); +const currentTime = ref(0); +let serviceInfo = ref(null); + +const props = defineProps({ + playingTime: { + type: String, + required: true + } +}); + +const viewer = window.viewer; + +function getPickPosition(windowPosition) { + if (!viewer) return null; + viewer.scene.globe.depthTestAgainstTerrain = true; + const cartesian = viewer.scene.pickPosition(windowPosition); + if (!cartesian) return null; + const cartographic = Cesium.Cartographic.fromCartesian(cartesian); + cartographic.height += 110.0; + return { + cartesian: Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height), + longitude: Cesium.Math.toDegrees(cartographic.longitude), + latitude: Cesium.Math.toDegrees(cartographic.latitude), + height: cartographic.height + }; +} +function addPointToViewer(point, index) { + const displayTime = currentTime.value || "鏈缃椂闂�"; + const schemeInfo = selectedScheme.value; + serviceInfo = schemeInfo.serviceName; + + // 鍒涘缓 label 瀹炰綋 + const labelEntity = viewer.entities.add({ + position: point.cartesian, + label: { + text: `娴嬮噺鐐� ${pickedPoints.value.length + 1}\n姘存繁: 绛夊緟鍚姩...\n娴侀��: 绛夊緟鍚姩...`, + font: 'bold 14pt monospace', + style: Cesium.LabelStyle.FILL_AND_OUTLINE, + fillColor: Cesium.Color.YELLOW, + outlineColor: Cesium.Color.BLACK, + outlineWidth: 2, + verticalOrigin: Cesium.VerticalOrigin.CENTER, + horizontalOrigin: Cesium.HorizontalOrigin.CENTER, + backgroundColor: Cesium.Color.fromCssColorString('rgba(0,0,0,0.7)'), + backgroundPadding: new Cesium.Cartesian2(10, 10), + showBackground: true, + scale: 1, + distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 5000), + pixelOffsetScaleByDistance: new Cesium.NearFarScalar(100, 1.0, 5000, 0.3), + } + }); + const groundPosition = Cesium.Cartesian3.fromRadians( + point.longitude * Math.PI / 180, + point.latitude * Math.PI / 180, + 0 + ); + const cylinderEntity = viewer.entities.add({ + position: groundPosition, // 搴曢儴浣嶇疆 + cylinder: { + length: 100.0, + topRadius: 1.0, + bottomRadius: 1.0, + material: Cesium.Color.YELLOW, + outline: true, + outlineColor: Cesium.Color.YELLOW, + slices: 32, + heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, + distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 5000) + } + }); + + // 璇锋眰鏁版嵁骞舵洿鏂� label + getFlowRateInfo(point.longitude, point.latitude, displayTime).then(result => { + updateLabel(pickedPoints.value.length - 1, result.depth, result.velocity); + }); + + // 瀛樺偍瀹炰綋寮曠敤 + pickedPoints.value.push({ + labelEntity, + cylinderEntity, // 浣跨敤鍦嗘煴浠f浛 line 鍜� circle + longitude: point.longitude, + latitude: point.latitude + }); +} + +function initPickHandler() { + if (!viewer?.scene?.canvas) return; + if (handler.value) { + handler.value.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); + handler.value.destroy(); + handler.value = null; + } + handler.value = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); + + handler.value.setInputAction((movement) => { + const position = getPickPosition(movement.position); + if (position) { + const index = pickedPoints.value.length; + addPointToViewer(position, index); + + } + }, Cesium.ScreenSpaceEventType.LEFT_CLICK); +} + +function startPicking() { + if (!handler.value) { + initPickHandler(); + } + isPickingActive.value = true; + ElMessage.success(`寮�濮�--娴侀噺娴侀��--鎷惧彇鍧愭爣鍔熻兘锛岃鐐瑰嚮鍦板浘閫夋嫨鐐逛綅锛侀�夊彇瀹岃鍙婃椂鍏抽棴锛岄伩鍏嶅奖鍝嶅叾浠栧姛鑳斤紒`); +} +function stopPicking() { + if (handler.value) { + handler.value.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); + handler.value.destroy(); + handler.value = null; + } + isPickingActive.value = false; +} +function togglePick() { + if (isPickingActive.value) { + stopPicking(); + isPickingActive.value = false; + ElMessage.info('宸插叧闂�--娴侀噺娴侀��--鎷惧彇鐐瑰潗鏍囧姛鑳斤紒'); + } else { + startPicking(); + isPickingActive.value = true; + } +} +watch( + () => props.playingTime, + async (newVal, oldVal) => { + if (newVal !== oldVal) { + currentTime.value = newVal || "鏈缃椂闂�"; + await updateAllLabels(); + } + }, + { immediate: true } +); + +async function updateAllLabels() { + for (const pointInfo of pickedPoints.value) { + if (!pointInfo || !pointInfo.labelEntity) continue; + + const result = await getFlowRateInfo(pointInfo.longitude, pointInfo.latitude, currentTime.value); + updateLabel(pointInfo, result.depth, result.velocity); + } +} + +function updateLabel(pointInfo, depth, velocity) { + if (pointInfo.labelEntity && pointInfo.labelEntity.label) { + pointInfo.labelEntity.label.text = ` +娴嬮噺鐐� ${pickedPoints.value.findIndex(p => p === pointInfo) + 1} +姘存繁: ${depth} m +娴侀��: ${velocity} m/s +`.trim(); + } +} +function endCalculation() { + pickedPoints.value.forEach(pointInfo => { + if (pointInfo.labelEntity) viewer.entities.remove(pointInfo.labelEntity); + if (pointInfo.cylinderEntity) viewer.entities.remove(pointInfo.cylinderEntity); + }); + pickedPoints.value = []; +} + +defineExpose({ + endCalculation, + stopPicking +}); +function getFlowRateInfo(lon, lat, time) { + const params = { + lon: lon, + lat: lat, + time: time, + serviceName: serviceInfo + }; + return getFlowRate(params).then(data => { + // console.log('鑾峰彇鍒扮殑鏁版嵁:', data); + if (data && data.code === 200) { + return { + depth: data.data.depth.toFixed(2), + velocity: data.data.velocity.toFixed(2) + }; + } else { + return { depth: 'N/A', velocity: 'N/A' }; + } + }).catch(error => { + console.error('鑾峰彇鏁版嵁鏃跺彂鐢熼敊璇�:', error); + return { depth: 'N/A', velocity: 'N/A' }; + }); +} +</script> +<style lang="less" scoped></style> \ No newline at end of file diff --git a/src/components/monifangzhen/DangerAssess.vue b/src/components/monifangzhen/DangerAssess.vue index 6cdeb6c..5954560 100644 --- a/src/components/monifangzhen/DangerAssess.vue +++ b/src/components/monifangzhen/DangerAssess.vue @@ -1,7 +1,7 @@ <template> <div class="right"> <div class="right-top"> - <span>妯℃嫙缁撴灉</span> + <span>姘存繁娴侀�熺粨鏋�</span> </div> <div class="right-content" > <div class="listinfo-title">鍙楃伨缁熻</div> diff --git a/src/components/monifangzhen/WaterDepthContent.vue b/src/components/monifangzhen/WaterDepthContent.vue new file mode 100644 index 0000000..e2dc36c --- /dev/null +++ b/src/components/monifangzhen/WaterDepthContent.vue @@ -0,0 +1,306 @@ +<template> + <div class="water-depth-content"> + <!-- 鎻愮ず淇℃伅 --> + <div v-if="showSelectPrompt" style=" font-weight: bold;"> + 璇峰湪鍦板浘涓�夊彇鍞竴娴嬮噺鐐� + </div> + + <!-- 姝e父鍐呭 --> + <div v-else> + <!-- 浣嶇疆淇℃伅 --> + <div class="location-info"> + <h3>浣嶇疆淇℃伅</h3> + <p class="coordinates"> + 缁忓害锛� <strong>{{ safeCurrentInfo.longitude.toFixed(3) }} </strong> + 绾害锛�<strong>{{ safeCurrentInfo.latitude.toFixed(3) }}</strong> + </p> + </div> + + <!-- 姘存繁淇℃伅 --> + <div class="depth-info"> + <h3>姘存繁淇℃伅 (m)</h3> + <p> + 骞冲潎锛�<strong>2.45</strong> + 鏈�澶э細<strong>3.10</strong> + 鏈�灏忥細<strong>1.80</strong> + </p> + </div> + </div> + <div class="chart-placeholder"> + <div ref="chartDom" style="width: 100%; height:300px;"></div> + </div> + </div> +</template> + +<script setup> +import { ref, onMounted, watch, computed, onBeforeUnmount, onBeforeMount } from 'vue'; +import * as echarts from 'echarts'; +import { useSimStore } from "@/store/simulation"; +import { storeToRefs } from "pinia"; +import { getFlowRate } from "@/api/trApi.js"; +import { EventBus } from "@/eventBus"; // 寮曞叆浜嬩欢鎬荤嚎 + +const simStore = useSimStore(); +const { currentInfo } = storeToRefs(simStore); + +// 瀹氫箟鍥捐〃鐨� DOM 鍏冪礌寮曠敤 +const chartDom = ref(null); +let myChart = null; + +// 璁$畻灞炴�э細瀹夊叏鑾峰彇缁忕含搴� +const safeCurrentInfo = computed(() => { + const info = currentInfo.value || {}; + return { + longitude: info.longitude !== undefined ? info.longitude : 0.0, + latitude: info.latitude !== undefined ? info.latitude : 0.0 + }; +}); + +// 鍒ゆ柇鏄惁闇�瑕佹樉绀洪�夋嫨鎻愮ず +const showSelectPrompt = computed(() => { + const info = safeCurrentInfo.value; + return info.longitude === 0.0 && info.latitude === 0.0; +}); + +// 闃叉姈鍑芥暟 +function debounce(func, wait) { + let timeout; + return function () { + const context = this; + const args = arguments; + clearTimeout(timeout); + timeout = setTimeout(() => { + func.apply(context, args); + }, wait); + }; +} + +// 绠�鍖栨暟鎹簮 +function generateSampleData() { + const now = new Date(); + const data = []; + // 鐢熸垚7涓暟鎹偣锛屾瘡10鍒嗛挓涓�涓� + for (let i = 99; i >= 0; i--) { + const time = new Date(now.getTime() - i * 10 * 60 * 1000); + // 闅忔満鐢熸垚1.8-3.1涔嬮棿鐨勬按娣辨暟鎹� + const depth = (1.8 + Math.random() * 1.3).toFixed(2); + data.push({ + time: time, + value: parseFloat(depth) + }); + } + return data; +} + +function initChart(chart) { + const data = generateSampleData(); + + const option = { + title: { + text: '姘存繁鍙樺寲瓒嬪娍', + textStyle: { + color: '#fff', + fontSize: 16 + }, + left: '-1%' // 鍜岀粍浠� A 瀵归綈 + }, + tooltip: { + trigger: 'axis', + formatter: (params) => { + const date = new Date(params[0].value[0]); + return `${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}<br/>姘存繁锛�${params[0].value[1]} m`; + }, + backgroundColor: 'rgba(0,0,0,0.7)', + textStyle: { + color: '#fff', + fontSize: 14 + } + }, + xAxis: { + type: 'time', + name: '', // 鍘婚櫎X杞村崟浣嶅悕绉� + axisLabel: { + color: '#fff', + fontSize: 12, + formatter: function (value) { + const date = new Date(value); + return `${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`; + }, + interval: 'auto', // 鑷姩璁$畻闂撮殧闃叉閲嶅彔 + rotate: 45 // 鍊炬枩45搴﹂槻姝㈤噸鍙� + }, + nameTextStyle: { + color: '#fff', + fontSize: 14 + } + }, + yAxis: { + type: 'value', + name: '姘存繁(m)', // 鍗曚綅绠�鍐欎负灏忓啓m + min: 1.5, + max: 3.5, + axisLabel: { + color: '#fff', + fontSize: 12 + }, + nameTextStyle: { + color: '#fff', + fontSize: 14 + } + }, + series: [{ + name: '姘存繁', + type: 'line', + data: data.map(item => [item.time, item.value]), + showSymbol: true, + lineStyle: { + color: '#f97316', // 鏀逛负姗欒壊锛屼笌娴侀�熶竴鑷� + width: 2 + }, + itemStyle: { + color: '#f97316' + }, + smooth: false + }], + // dataZoom: [{ + // type: 'slider', + // start: 0, + // end: 100, + // bottom: '0%', // 涓嬬Щ缂╂斁鎺т欢 + // textStyle: { + // color: '#fff', + // fontSize: 12 + // }, + // filterMode: 'filter' + // }], + // 鍏ㄥ眬鏂囧瓧鏍峰紡 + textStyle: { + color: '#fff', + fontSize: 14 + }, + animation: false + }; + + chart.setOption(option); + + window.addEventListener('resize', debounce(() => { + chart.resize(); + }, 200)); +} + +watch( + () => currentInfo.value, + (newVal) => { + if (!newVal || showSelectPrompt.value || !chartDom.value) return; + + console.log('缁忓害:', newVal.longitude); + console.log('绾害:', newVal.latitude); + console.log('鏈嶅姟鍚嶇О:', newVal.serviceInfo); + + // 閿�姣佹棫鍥捐〃 + if (myChart) { + myChart.dispose(); + } + + // 鍒涘缓鏂板浘琛� + myChart = echarts.init(chartDom.value); + initChart(myChart); + }, + { deep: true } +); + +onMounted(() => { + if (!showSelectPrompt.value && chartDom.value) { + myChart = echarts.init(chartDom.value); + initChart(myChart); + } +}); +onBeforeMount(() => { + EventBus.on('clear-water-depth', clear); +}); +onBeforeUnmount(() => { + if (myChart) { + myChart.dispose(); + myChart = null; + } + EventBus.off('clear-water-depth', clear); + +}); +function clear() { + // 娓呯┖ store 涓殑缁忕含搴︿俊鎭� + currentInfo.value.longitude = 0.0; + currentInfo.value.latitude = 0.0; + + // 娓呴櫎 ECharts 鍥捐〃 + if (myChart) { + myChart.clear(); // 娓呴櫎鍥捐〃鏁版嵁鍜屽浘褰� + myChart.dispose(); // 閿�姣佸疄渚嬶紝閲婃斁璧勬簮 + myChart = null; + } +} +function getFlowRateInfo(lon, lat, serviceInfo) { + const params = { + lon: lon, + lat: lat, + serviceName: serviceInfo + }; + return getFlowRate(params).then(data => { + console.log('鑾峰彇鍒扮殑鏁版嵁:', data); + if (data && data.code === 200) { + return { + depth: data.data.depth.toFixed(2), + velocity: data.data.velocity.toFixed(2) + }; + } else { + return { depth: 'N/A', velocity: 'N/A' }; + } + }).catch(error => { + console.error('鑾峰彇鏁版嵁鏃跺彂鐢熼敊璇�:', error); + return { depth: 'N/A', velocity: 'N/A' }; + }); +} + +function resizeChart() { + if (myChart) { + myChart.resize(); + } +} + +defineExpose({ resizeChart }); +</script> + +<style scoped> +.water-depth-content { + padding-left: 8px; + padding-top: 8px; + border-radius: 6px; +} + +.chart-placeholder { + margin-top: 10px; +} + +.location-info, +.depth-info { + margin-bottom: 10px; +} + +.coordinates { + font-size: 15px; + color: #fff; + user-select: all; + display: inline-block; + border-radius: 4px; + transition: background-color 0.2s ease; +} + +.depth-info p { + font-size: 14px; + color: #fff; +} + +.depth-info strong { + color: #fff; + margin: 0 4px; +} +</style> \ No newline at end of file diff --git a/src/components/monifangzhen/WaterVelocityContent.vue b/src/components/monifangzhen/WaterVelocityContent.vue new file mode 100644 index 0000000..124f60b --- /dev/null +++ b/src/components/monifangzhen/WaterVelocityContent.vue @@ -0,0 +1,300 @@ +<template> + <div class="water-velocity-content"> + <!-- 鎻愮ず淇℃伅 --> + <div v-if="showSelectPrompt" style=" font-weight: bold;"> + 璇峰湪鍦板浘涓�夊彇鍞竴娴嬮噺鐐� + </div> + + <!-- 姝e父鍐呭 --> + <div v-else> + <!-- 浣嶇疆淇℃伅 --> + <div class="location-info"> + <h3>浣嶇疆淇℃伅</h3> + <p class="coordinates"> + 缁忓害锛� <strong>{{ safeCurrentInfo.longitude.toFixed(3) }} </strong> + 绾害锛�<strong>{{ safeCurrentInfo.latitude.toFixed(3) }}</strong> + </p> + </div> + + <!-- 娴侀�熶俊鎭� --> + <div class="velocity-info"> + <h3>娴侀�熶俊鎭� (m/s)</h3> + <p> + 骞冲潎锛�<strong>1.25</strong> + 鏈�澶э細<strong>1.80</strong> + 鏈�灏忥細<strong>0.70</strong> + </p> + </div> + </div> + + <!-- 鍥捐〃鍖哄煙 --> + <div class="chart-placeholder"> + <div ref="chartDom" style="width: 100%; height: 300px;"></div> + </div> + </div> +</template> + +<script setup> +import { ref, onMounted, watch, computed, onBeforeUnmount,onBeforeMount } from 'vue'; +import * as echarts from 'echarts'; +import { useSimStore } from "@/store/simulation"; +import { storeToRefs } from "pinia"; +import { EventBus } from "@/eventBus"; // 寮曞叆浜嬩欢鎬荤嚎 + +const simStore = useSimStore(); +const { currentInfo } = storeToRefs(simStore); + +// 瀹氫箟鍥捐〃鐨� DOM 鍏冪礌寮曠敤 +const chartDom = ref(null); +let myChart = null; + +// 璁$畻灞炴�э細瀹夊叏鑾峰彇缁忕含搴� +const safeCurrentInfo = computed(() => { + const info = currentInfo.value || {}; + return { + longitude: info.longitude !== undefined ? info.longitude : 0.0, + latitude: info.latitude !== undefined ? info.latitude : 0.0 + }; +}); + +// 鍒ゆ柇鏄惁闇�瑕佹樉绀洪�夋嫨鎻愮ず +const showSelectPrompt = computed(() => { + const info = safeCurrentInfo.value; + return info.longitude === 0.0 && info.latitude === 0.0; +}); + +// 闃叉姈鍑芥暟 +function debounce(func, wait) { + let timeout; + return function () { + const context = this; + const args = arguments; + clearTimeout(timeout); + timeout = setTimeout(() => { + func.apply(context, args); + }, wait); + }; +} + +// 绠�鍖栨暟鎹簮 +function generateSampleData() { + const now = new Date(); + const data = []; + // 鐢熸垚7涓暟鎹偣锛屾瘡10鍒嗛挓涓�涓� + for (let i = 100; i >= 0; i--) { + const time = new Date(now.getTime() - i * 10 * 60 * 1000); + // 闅忔満鐢熸垚0.7-1.8涔嬮棿鐨勬祦閫熸暟鎹� + const velocity = (0.7 + Math.random() * 3).toFixed(2); + data.push({ + time: time, + value: parseFloat(velocity) + }); + } + return data; +} + +function initChart(chart) { + const data = generateSampleData(); + + const option = { + // grid: { + // top: '5%', // 涓婅竟璺濆噺灏� => 鎶樼嚎鍥惧彉楂� + // bottom: '%', // 涓嬭竟璺濆噺灏� => 鎶樼嚎鍥惧彉楂� + // left: '10%', // 宸﹁竟璺濆噺灏� => 鎶樼嚎鍥惧彉瀹� + // right: '10%' // 鍙宠竟璺濆噺灏� => 鎶樼嚎鍥惧彉瀹� + // }, + title: { + text: '娴侀�熷彉鍖栬秼鍔�', + textStyle: { + color: '#fff', + fontSize: 16 + }, + // 灏嗘爣棰樺悜宸︾Щ鍔� 1% + left: '-1%' + }, + tooltip: { + trigger: 'axis', + formatter: (params) => { + const date = new Date(params[0].value[0]); + return `${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}<br/>娴侀�燂細${params[0].value[1]} m/s`; + }, + backgroundColor: 'rgba(0,0,0,0.7)', + textStyle: { + color: '#fff', + fontSize: 14 + } + }, + xAxis: { + type: 'time', + // 鍙栨秷 X 杞村崟浣� + name: '', + axisLabel: { + color: '#fff', + fontSize: 12, + formatter: function (value) { + const date = new Date(value); + return `${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`; + }, + interval: 'auto', // 鑷姩璁$畻闂撮殧闃叉閲嶅彔 + rotate: 45 // 鍊炬枩45搴﹂槻姝㈤噸鍙� + }, + nameTextStyle: { + color: '#fff', + fontSize: 14 + } + }, + yAxis: { + type: 'value', + name: '娴侀��(m/s)', + min: 0.5, // 璁剧疆鏈�灏忓�� + max: 6.0, // 璁剧疆鏈�澶у�� + axisLabel: { + color: '#fff', + fontSize: 12, + }, + nameTextStyle: { + color: '#fff', + fontSize: 14 + }, + }, + series: [{ + name: '娴侀��', + type: 'line', + data: data.map(item => [item.time, item.value]), + showSymbol: true, + lineStyle: { + color: '#f97316', // 姗欒壊 + width: 2 + }, + itemStyle: { + color: '#f97316' + }, + smooth: true // 骞虫粦鏇茬嚎 + }], + // dataZoom: [{ + // type: 'slider', + // start: 0, + // end: 100, + // textStyle: { + // color: '#fff', + // fontSize: 12 + // }, + // filterMode: 'filter', // 閬垮厤閲嶅娓叉煋 + // // 缂╂斁鎺т欢鍚戜笅绉诲姩 2% + // bottom: '0%' + // }], + // 鍏ㄥ眬鏂囧瓧鏍峰紡 + textStyle: { + color: '#fff', + fontSize: 14 + }, + animation: false // 绂佺敤鍔ㄧ敾锛屾彁楂樻�ц兘 + }; + + chart.setOption(option); + + // 娣诲姞闃叉姈鐨剅esize鐩戝惉 + window.addEventListener('resize', debounce(() => { + chart.resize(); + }, 200)); +} + +watch( + () => currentInfo.value, + (newVal) => { + if (!newVal || showSelectPrompt.value || !chartDom.value) return; + + console.log('缁忓害:', newVal.longitude); + console.log('绾害:', newVal.latitude); + console.log('鏈嶅姟鍚嶇О:', newVal.serviceInfo); + + // 閿�姣佹棫鍥捐〃 + if (myChart) { + myChart.dispose(); + } + + // 鍒涘缓鏂板浘琛� + myChart = echarts.init(chartDom.value); + initChart(myChart); + }, + { deep: true } +); + +onMounted(() => { + if (!showSelectPrompt.value && chartDom.value) { + myChart = echarts.init(chartDom.value); + initChart(myChart); + } +}); +onBeforeMount(() => { + EventBus.on('clear-water-velocity', clear); +}); +onBeforeUnmount(() => { + if (myChart) { + myChart.dispose(); + myChart = null; + } + EventBus.off('clear-water-velocity', clear); + +}); +function clear() { + // 娓呯┖ store 涓殑缁忕含搴︿俊鎭� + currentInfo.value.longitude = 0.0; + currentInfo.value.latitude = 0.0; + + // 娓呴櫎 ECharts 鍥捐〃 + if (myChart) { + myChart.clear(); // 娓呴櫎鍥捐〃鏁版嵁鍜屽浘褰� + myChart.dispose(); // 閿�姣佸疄渚嬶紝閲婃斁璧勬簮 + myChart = null; + } +} +// 娣诲姞 resizeChart 鏂规硶 +function resizeChart() { + if (myChart) { + myChart.resize(); + } +} + +// 鏆撮湶鏂规硶缁欑埗缁勪欢璋冪敤 +defineExpose({ resizeChart }); +</script> + +<style scoped> +.water-velocity-content { + padding-left: 8px; + padding-top: 8px; + padding-bottom: -8px; + border-radius: 6px; +} + +.location-info, +.velocity-info { + margin-bottom: 10px; +} + +.coordinates { + font-size: 15px; + color: #fff; + user-select: all; + display: inline-block; + border-radius: 4px; + transition: background-color 0.2s ease; +} + +.velocity-info p { + font-size: 14px; + color: #fff; +} + +.velocity-info strong { + color: #fff; + margin: 0 4px; +} + +.chart-placeholder { + overflow: hidden; + height: 284px; + /* margin-top: 10px; */ +} +</style> \ No newline at end of file diff --git a/src/components/monifangzhen/flowRateTab.vue b/src/components/monifangzhen/flowRateTab.vue new file mode 100644 index 0000000..d9d6380 --- /dev/null +++ b/src/components/monifangzhen/flowRateTab.vue @@ -0,0 +1,69 @@ +<template> + <div class="right-top"> + <span>妯℃嫙缁撴灉</span> + </div> + <el-tabs v-model="activeTab" class="full-width-tabs" @tab-change="handleTabChange"> + <el-tab-pane label="姘存繁" name="depth"> + <WaterDepthContent ref="depthRef"/> + </el-tab-pane> + <el-tab-pane label="娴侀��" name="velocity"> + <WaterVelocityContent ref="velocityRef" /> + </el-tab-pane> + </el-tabs> +</template> + +<script setup> +import { ref } from 'vue' +import { nextTick } from 'vue' +import WaterDepthContent from './WaterDepthContent.vue' +import WaterVelocityContent from './WaterVelocityContent.vue' + +const activeTab = ref('depth') +const depthRef = ref(null) +const velocityRef = ref(null) + +const handleTabChange = () => { + nextTick(() => { + if (activeTab.value === 'depth' && depthRef.value?.resizeChart) { + depthRef.value.resizeChart() + } else if (activeTab.value === 'velocity' && velocityRef.value?.resizeChart) { + velocityRef.value.resizeChart() + } + }) +} +</script> + +<style scoped> +.full-width-tabs { + width: 100%; +} + +</style> + +<style scoped> +.full-width-tabs :deep(.el-tabs__header) { + margin: 0; +} + +.full-width-tabs :deep(.el-tabs__nav) { + width: 100%; +} + +.full-width-tabs :deep(.el-tabs__item) { + width: 50%; + text-align: center; + padding: 0; + font-size: 16px; + font-weight: bold; + color: #fff; +} +.full-width-tabs :deep(.el-tabs__item.is-active) { + color: #61f7d4; + +} +.full-width-tabs :deep(.el-tabs__active-bar) { + background-color: #61f7d4; + +} + +</style> \ No newline at end of file diff --git a/src/components/monifangzhen/schemeCard.vue b/src/components/monifangzhen/schemeCard.vue index b8e371f..2888c7d 100644 --- a/src/components/monifangzhen/schemeCard.vue +++ b/src/components/monifangzhen/schemeCard.vue @@ -37,6 +37,10 @@ :selectedScheme="currentScheme" @back="handleBack" /> + <flowRateTab + v-if="schemeInfoShow"> + 123 + </flowRateTab> </div> <Message @close="close" @@ -55,6 +59,7 @@ import { useSimStore } from "@/store/simulation.js"; import { SimAPIStore } from "@/store/simAPI"; import schemeInfo from "@/components/monifangzhen/schemeInfo.vue"; +import flowRateTab from "@/components/monifangzhen/flowRateTab.vue"; import { ElMessage, ElMessageBox } from "element-plus"; const emit = defineEmits(["start", "end", "reset", "closeBtn"]); import { diff --git a/src/components/monifangzhen/schemeInfo.vue b/src/components/monifangzhen/schemeInfo.vue index 100d392..f1f0c89 100644 --- a/src/components/monifangzhen/schemeInfo.vue +++ b/src/components/monifangzhen/schemeInfo.vue @@ -236,7 +236,6 @@ margin-bottom: 20px; border-radius: 8px; color: white; - .left-top { display: flex; justify-content: space-between; @@ -264,7 +263,7 @@ } .details { - padding: 8px; + padding-left: 8px; .input-group { display: flex; diff --git a/src/components/tools/Tools.vue b/src/components/tools/Tools.vue index bb8ab22..2d9d51e 100644 --- a/src/components/tools/Tools.vue +++ b/src/components/tools/Tools.vue @@ -233,12 +233,8 @@ } }, 鏃ョ収鍒嗘瀽: () => { - showSunAnalysis.value = !showSunAnalysis.value - if (showSunAnalysis.value) { - // mapUtils.AnalysisSunshine() - } else { - // mapUtils.disableAtmosphere() - } + window.Viewer = earthCtrl.viewer; + mapUtils.AnalysisSunshine() }, 鏂囧瓧鏍囩粯: () => mapUtils.CreateLabel("label", true), diff --git a/src/utils/tools.js b/src/utils/tools.js index cc49b1f..3892160 100644 --- a/src/utils/tools.js +++ b/src/utils/tools.js @@ -674,8 +674,6 @@ // 闃村奖鍒嗘瀽 AnalysisSunshine() { - if (!layerIsOpen) { - layerIsOpen = true; let currentTime = viewer.clock.currentTime.clone(); let startTime = viewer.clock.startTime.clone(); let stopTime = viewer.clock.stopTime.clone(); @@ -684,7 +682,7 @@ type: 2, title: "闃村奖鍒嗘瀽", shade: false, - area: ["350px", "540px"], + area: ["350px", "350px"], offset: "r", skin: "other-class", content: SmartEarthRootUrl + "Workers/analysis/AnalysisShadow.html", @@ -697,7 +695,6 @@ Viewer.shadowLayer = false; } }); - } }, transformCartesianToCoord(position) { const cartographic = SmartEarth.Cesium.Cartographic.fromCartesian(position); diff --git a/src/utils/water.js b/src/utils/water.js index c9c543d..7f5c102 100644 --- a/src/utils/water.js +++ b/src/utils/water.js @@ -38,30 +38,46 @@ "#ffe930", "#fdd10a", "#feb652", "#fd7f06", "#fe2b07", "#4d0a08" ]; - // 鏋勯�� waterHeightLevels锛氫粠 min 鍒� max 浣跨敤鎸囨暟澧為暱锛岀‘淇濆皬鍊煎尯鍩熸洿瀵嗛泦 - const levelCount = colorStops.length; // 淇濇寔鍜岄鑹叉暟閲忎竴鑷� + + const levelCount = colorStops.length; + const minAllowed = 0.01; // 鏈�灏忓厑璁稿�� + const threshold = 1; // 灏忓�间笌澶у�煎垎鐣岀偣 + + let effectiveMin = Math.max(minFlowRate, minAllowed); // 鏈�灏忎笉鑳藉皬浜� 0.01 + const waterHeightLevels = []; - // 鎸囨暟澧為暱鍏紡锛歽 = base^x - const base = Math.exp(Math.log(maxFlowRate / minFlowRate) / (levelCount - 1)); + + // 鍒嗕袱娈垫瀯閫犻珮搴︽暟缁� for (let i = 0; i < levelCount; i++) { - const ratio = i / (levelCount - 1); // 0 ~ 1 - // 浣跨敤鎸囨暟鎻掑�硷紝淇濊瘉浣庡�煎尯鍩熸洿瀵嗛泦 - const height = minFlowRate * Math.pow(base, i); - const color = colorStops[i]; + let ratio = i / (levelCount - 1); // 0 ~ 1 + + let height; + if (ratio <= 0.5) { + // 鍓嶅崐娈碉細浣庡�煎尯鍩燂紝浣跨敤寮烘寚鏁板闀匡紝浠� effectiveMin 鍒� threshold + const localRatio = ratio * 2; // 鏄犲皠鍒� 0~1 + const expRatio = Math.pow(localRatio, 2); // 鏇村己璋冧綆鍊煎尯鍩熷瘑搴� + height = effectiveMin + (threshold - effectiveMin) * expRatio; + } else { + // 鍚庡崐娈碉細楂樺�煎尯鍩燂紝浠� threshold 鍒� maxFlowRate锛屼娇鐢ㄦ寚鏁板闀� + const localRatio = (ratio - 0.5) * 2; // 鏄犲皠鍒� 0~1 + const expBase = Math.exp(Math.log(maxFlowRate / threshold) / 1); + height = threshold * Math.pow(expBase, localRatio); + } waterHeightLevels.push({ - height: height.toFixed(2), // 鍙�夛細淇濈暀涓や綅灏忔暟 - color + height: parseFloat(height.toFixed(2)), // 淇濈暀涓や綅灏忔暟 + color: colorStops[i] }); } - waterLegendData.value = waterHeightLevels - console.log(waterLegendData.value,'鍥鹃噷鏁版嵁'); - + + waterLegendData.value = waterHeightLevels; + console.log(waterLegendData.value, '鍥句緥鏁版嵁'); + // 鍒涘缓鍥惧眰 water = earthCtrl.simulate.createWaterSimulateLayer({ baseUrl, interval, - color: new SmartEarth.Cesium.Color.fromCssColorString("#D4F2E7"), + color: SmartEarth.Cesium.Color.fromCssColorString("#D4F2E7"), loop: false, callback: timeCallback, alphaByDepth: -0.3, @@ -70,7 +86,7 @@ }); console.log( - `浠跨湡妯℃嫙鍙傛暟锛氳姹傝矾寰� ${baseUrl}, 甯ч棿闂撮殧 ${interval}ms, 鏄惁寮�鍚笓棰樻覆鏌� ${colorRender},鍥句緥鍙傛暟${waterHeightLevels}` + `浠跨湡妯℃嫙鍙傛暟锛氳姹傝矾寰� ${baseUrl}, 甯ч棿闂撮殧 ${interval}ms, 鏄惁寮�鍚笓棰樻覆鏌� ${colorRender}` ); } /** -- Gitblit v1.9.3