From f37845dd0a787dd42bf6c72e923433f30fcd8cc3 Mon Sep 17 00:00:00 2001 From: guonan <guonan201020@163.com> Date: 星期四, 03 七月 2025 15:40:09 +0800 Subject: [PATCH] 实时模拟 --- src/components/menu/TimeLine.vue | 238 +++++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 183 insertions(+), 55 deletions(-) diff --git a/src/components/menu/TimeLine.vue b/src/components/menu/TimeLine.vue index 5f1eaf0..1483981 100644 --- a/src/components/menu/TimeLine.vue +++ b/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> @@ -107,9 +146,9 @@ updateWaterColor, } from "@/utils/water"; import mapUtils from "@/utils/tools.js"; -import { fetchWaterSimulationData } from "@/api/trApi.js"; +import { fetchWaterSimulationData, stopSim } from "@/api/trApi.js"; import { EventBus } from "@/eventBus"; -import { ElMessage } from "element-plus"; +import { ElMessage, ElMessageBox } from "element-plus"; // 鐘舵�佺鐞嗗櫒 import { useSimStore } from "@/store/simulation"; import { storeToRefs } from "pinia"; @@ -278,7 +317,8 @@ const startPlayback = () => { clearInterval(playInterval); - if (selectedScheme.value.type === 2) { + // 鏂板缓鏂规涓殑瀹炴椂妯℃嫙涓嶈兘鍊嶉�� + if (selectedScheme.value.type === 2 && simStore.rePlayList.length == 0) { // 绫诲瀷涓� 2锛氭瘡 5 绉掕烦鍔ㄤ竴娆� playInterval = setInterval(() => { const fiveSeconds = 5; @@ -541,9 +581,9 @@ // 鍏ㄥ眬鐘舵�佽褰� const colorState = { currentColor: "#F5F0E6", // 褰撳墠棰滆壊 - currentAlpha: -0.3, // 褰撳墠閫忔槑搴� - colorStages: null, // 棰勮绠楃殑棰滆壊闃舵鏃堕棿鐐� - maxColorTime: null // 璁板綍杈惧埌鏈�娣遍鑹叉椂鐨勬椂闂寸偣 + currentAlpha: -0.3, // 褰撳墠閫忔槑搴� + colorStages: null, // 棰勮绠楃殑棰滆壊闃舵鏃堕棿鐐� + maxColorTime: null, // 璁板綍杈惧埌鏈�娣遍鑹叉椂鐨勬椂闂寸偣 }; // 棰勮绠楅鑹查樁娈垫椂闂寸偣 @@ -556,17 +596,17 @@ { hex: "#D4B483", luminance: 184.0 }, // stage 2 { hex: "#B78B6A", luminance: 148.4 }, // stage 3 { hex: "#8B5A3A", luminance: 101.0 }, // stage 4 - { hex: "#744C33", luminance: 84.5 }, // stage 5 - { hex: "#5D3D2C", luminance: 68.1 } // stage 6 + { hex: "#744C33", luminance: 84.5 }, // stage 5 + { hex: "#5D3D2C", luminance: 68.1 }, // stage 6 ]; const alphaStops = [ - -0.2, // stage 0 - -0.3, // stage 1 - -0.4, // stage 2 - -0.5, // stage 3 - -0.6, // stage 4 - -0.7, // stage 5 - -0.8 // stage 6 + -0.2, // stage 0 + -0.3, // stage 1 + -0.4, // stage 2 + -0.5, // stage 3 + -0.6, // stage 4 + -0.7, // stage 5 + -0.8, // stage 6 ]; // 绱闄嶉洦閲忛槇鍊硷紙mm锛� const R_THRESHOLDS = [0, 200, 240, 280, 310, 350]; // 鍏�6涓樁娈靛搴�6涓槇鍊� @@ -579,7 +619,7 @@ const total = rainTotalInfo.value[i].total; // 浣跨敤 total 鏇夸唬 intensity timeTotals.push({ time, - total + total, }); } @@ -594,7 +634,7 @@ startTime: time, color: COLOR_STOPS[stage].hex, alpha: alphaStops[stage], - threshold + threshold, }; break; } @@ -606,7 +646,7 @@ startTime: 0, color: COLOR_STOPS[0].hex, alpha: alphaStops[0], - threshold: 0 + threshold: 0, }; colorState.colorStages = stages; @@ -623,7 +663,10 @@ // 鏌ユ壘褰撳墠鏃堕棿鐐规墍灞炵殑闃舵 let currentStage = 0; for (let i = colorState.colorStages.length - 1; i >= 0; i--) { - if (colorState.colorStages[i] && currentTime.value >= colorState.colorStages[i].startTime) { + if ( + colorState.colorStages[i] && + currentTime.value >= colorState.colorStages[i].startTime + ) { currentStage = i; break; } @@ -631,15 +674,21 @@ // 璁板綍杈惧埌鏈�娣遍鑹茬殑鏃堕棿鐐� if (currentStage >= colorState.colorStages.length - 1) { - if (colorState.maxColorTime === null || currentTime.value > colorState.maxColorTime) { + if ( + colorState.maxColorTime === null || + currentTime.value > colorState.maxColorTime + ) { colorState.maxColorTime = currentTime.value; } } // 鍒ゆ柇鏄惁闇�瑕佸己鍒舵洿鏂伴鑹� const isTimeGoingBackward = currentTime.value < colorState.lastTime; - const isBeforeMaxColorTime = colorState.maxColorTime !== null && currentTime.value <= colorState.maxColorTime; - const shouldForceUpdate = isForceUpdate && (isTimeGoingBackward || isBeforeMaxColorTime); + const isBeforeMaxColorTime = + colorState.maxColorTime !== null && + currentTime.value <= colorState.maxColorTime; + const shouldForceUpdate = + isForceUpdate && (isTimeGoingBackward || isBeforeMaxColorTime); // 鏇存柊棰滆壊閫昏緫 if (shouldForceUpdate || isTimeGoingBackward) { @@ -652,7 +701,9 @@ const newAlpha = colorState.colorStages[currentStage].alpha; // 鍙簲鐢ㄦ洿鏆楃殑棰滆壊鍜屾洿浣庣殑閫忔槑搴� - if (calculateLuminance(newColor) < calculateLuminance(colorState.currentColor)) { + if ( + calculateLuminance(newColor) < calculateLuminance(colorState.currentColor) + ) { colorState.currentColor = newColor; } if (newAlpha < colorState.currentAlpha) { @@ -717,7 +768,8 @@ // 鍒ゆ柇鏄惁闇�瑕佸己鍒舵洿鏂伴鑹� const isGoingBackward = newTime < currentTime.value; - const isBeforeMaxColor = colorState.maxColorTime !== null && newTime <= colorState.maxColorTime; + const isBeforeMaxColor = + colorState.maxColorTime !== null && newTime <= colorState.maxColorTime; const shouldForceUpdate = isGoingBackward || isBeforeMaxColor; currentTime.value = newTime; @@ -910,16 +962,25 @@ ); const jsonFetch = ref(null); - +const currentReplayIndex = ref(0); // 褰撳墠鎾斁鐨剅ePlayList绱㈠紩 // 鎻愬彇涓虹嫭绔嬪嚱鏁� -async function initializeSimulationData(force = false) { +async function initializeSimulationData(replayItem = null) { try { const schemeInfo = selectedScheme.value; serviceInfo = schemeInfo.serviceName; if (schemeInfo.type == 2) { - speedShow.value = false; - jsonFetch.value = layerDate.value; + if ( + replayItem || + (simStore.rePlayList && simStore.rePlayList.length != 0) + ) { + jsonFetch.value = + replayItem || simStore.rePlayList[currentReplayIndex.value]; + speedShow.value = true; + } else { + jsonFetch.value = layerDate.value; + speedShow.value = false; + } } else { getRainfallData(); speedShow.value = true; @@ -962,11 +1023,36 @@ } } -// 鎸傝浇鏃惰皟鐢� -onMounted(async () => { - // 鍥犱负杩欎釜鍑芥暟瀹炴椂妯℃嫙鐩戝惉涔熼渶瑕佷娇鐢紝鎵�浠ュ皝瑁呬簡涓�涓嚱鏁� - await initializeSimulationData(); -}); +// 鎾斁瀹屾垚鍚庣殑鍥炶皟 +function handlePlayFinished() { + if (selectedScheme.value.type !== 2) return; + finishPlay.value = false; + currentReplayIndex.value++; + + if (currentReplayIndex.value < simStore.rePlayList.length) { + console.log(currentReplayIndex.value); + + // 鑷姩鎾斁涓嬩竴涓� + initializeSimulationData(simStore.rePlayList[currentReplayIndex.value]); + togglePlay(); + shouldAutoPlay.value = false; + } else { + // 鎵�鏈夐」鐩挱鏀惧畬鎴� + currentReplayIndex.value = 0; // 閲嶇疆绱㈠紩 + isPlaying.value = false; // 鍋滄鎾斁 + } +} + +// 鐩戝惉鎾斁瀹屾垚浜嬩欢 +watch( + () => finishPlay.value, + (newVal) => { + if (newVal && selectedScheme.value.type === 2) { + handlePlayFinished(); + } + } +); + const shouldAutoPlay = ref(false); // 鐩戝惉 layerDate 鍙樺寲鍚庢爣璁板噯澶囨挱鏀� watch( @@ -986,6 +1072,13 @@ shouldAutoPlay.value = false; } }); + +// 鎸傝浇鏃惰皟鐢� +onMounted(async () => { + // 鍥犱负杩欎釜鍑芥暟瀹炴椂妯℃嫙鐩戝惉涔熼渶瑕佷娇鐢紝鎵�浠ュ皝瑁呬簡涓�涓嚱鏁� + await initializeSimulationData(); +}); + // 鏍规嵁杩斿洖鏁版嵁鐨勪釜鏁板幓娓叉煋鏃堕棿杞� function updateTimelineRange() { if (waterTimestamps.value.length > 0) { @@ -1002,28 +1095,63 @@ }); const { endSimulate } = inject("simulateActions"); -function handleBack() { - endSimulate(); - // 鍋滄瀹炴椂妯℃嫙瀹氭椂鍣� - EventBus.emit("close-time"); +async function handleBack() { + // 瀹炴椂妯℃嫙寮圭獥纭鏄繑鍥炴柟妗堝垪琛ㄨ繕鏄仠姝㈡ā鎷� + if (selectedScheme.value.type === 2) { + try { + await ElMessageBox.confirm("鏂规鏈仠姝㈡椂缁撴潫妯℃嫙鍚庯紝鍚庡彴灏嗗仠姝㈣绠�", { + confirmButtonText: "杩斿洖鍒楄〃", + cancelButtonText: "缁撴潫妯℃嫙", + type: "warning", + }); + // 鐢ㄦ埛鐐瑰嚮浜嗙‘璁わ紝杩欓噷涓嶆墽琛屼换浣曟搷浣滐紝浠呭叧闂璇濇 + } catch (error) { + stopSim(selectedScheme.value.id).then((res) => { + if (res.code == 404) { + ElMessage.warning("璇ユ湇鍔″凡鍋滄"); + } else { + ElMessage.success("鏈嶅姟姝e湪鍋滄涓�"); + } + }); + // return; + } + } + // 涓嶇type鏄笉鏄�2锛屾渶缁堥兘鎵ц缁撴潫妯℃嫙鐨勬搷浣� + endSimulation(); +} + +async function endSimulation() { + EventBus.emit("close-time"); + endSimulate(); isWaterPrimitiveCreated.value = false; + + // 缁撴潫璁$畻鍜屽仠姝㈡嬀鍙� if (ratelevelRef.value) { ratelevelRef.value.endCalculation(); ratelevelRef.value.stopPicking(); } + + // 娓呴櫎鐐� if (crossRef.value) { crossRef.value.clearPoints(); console.log("鎵ц鍒犻櫎鐐瑰姛鑳�"); } + emit("isColorRender", false); + + // 寤惰繜鍒犻櫎闆ㄩ噺鍥惧眰 setTimeout(() => { mapUtils.delRain(); }, 3000); + destoryWaterPrimitive(); + + // 鍙戦�佷簨浠堕殣钘忕浉鍏充俊鎭� EventBus.emit("hide-schemeInfo"); EventBus.emit("clear-water-depth"); EventBus.emit("clear-water-velocity"); + ElMessage({ message: "妯℃嫙杩涚▼姝e湪鍏抽棴涓�...", type: "success" }); } </script> -- Gitblit v1.9.3