From f37845dd0a787dd42bf6c72e923433f30fcd8cc3 Mon Sep 17 00:00:00 2001 From: guonan <guonan201020@163.com> Date: 星期四, 03 七月 2025 15:40:09 +0800 Subject: [PATCH] 实时模拟 --- src/views/left/KGSimOption/RealTimeSimulation.vue | 423 +++++++++++++++++++++++++++++++++++----------------- 1 files changed, 287 insertions(+), 136 deletions(-) diff --git a/src/views/left/KGSimOption/RealTimeSimulation.vue b/src/views/left/KGSimOption/RealTimeSimulation.vue index b998506..14c3105 100644 --- a/src/views/left/KGSimOption/RealTimeSimulation.vue +++ b/src/views/left/KGSimOption/RealTimeSimulation.vue @@ -23,15 +23,16 @@ </el-form-item> <el-form-item label="闆ㄩ噺鏁版嵁:"> <el-select + @change="handleChange" v-model="formData.selectedRainfall" placeholder="璇烽�夋嫨" popper-class="mySelectStyle" > <el-option - v-for="item in rainfallData" + v-for="item in options" :key="item.id" :label="item.name" - :value="item.id" + :value="item.name" ></el-option> </el-select> </el-form-item> @@ -39,11 +40,11 @@ <div class="table-container"> <div class="table-row" - v-for="(item, index) in filteredTableData" + v-for="(item, index) in shgList" :key="index" > <input type="checkbox" v-model="item.selected" /> - <span>{{ item.name }}</span> + <span>{{ item.deviceName }}</span> </div> </div> </el-form-item> @@ -56,7 +57,7 @@ <div style="width: 100%; height: 60px; background-color: #fff;"></div> </div> --> <div class="buttons"> - <el-button type="primary" @click="openSaveDialog">淇濆瓨鏂规</el-button> + <el-button type="primary" @click="saveSim">淇濆瓨鏂规</el-button> <el-button type="success" @click="startPlay">寮�濮嬫ā鎷�</el-button> <el-button type="success" @click="futurePredictions">鏈潵棰勬祴</el-button> </div> @@ -64,46 +65,37 @@ </template> <script setup> -import { ref, watch, defineProps, computed, inject, reactive } from "vue"; +import { + ref, + watch, + defineProps, + computed, + inject, + reactive, + onMounted, + onUnmounted, +} from "vue"; import { ElMessage } from "element-plus"; import { initeWaterPrimitiveView } from "@/utils/water"; import { SimAPIStore } from "@/store/simAPI"; +import { useSimStore } from "@/store/simulation.js"; import { EventBus } from "@/eventBus"; // 寮曞叆浜嬩欢鎬荤嚎 +import { getDeviceInfoSHG, getYLJData } from "@/api/hpApi"; +import { getSimStart, getSimDataById, getSimresult } from "@/api/trApi"; +import { ControlSchemeType } from "@/assets/js/lib-pixelstreamingfrontend.esm"; // 鑾峰彇 Store 瀹炰緥 -const simStore = SimAPIStore(); +const simAPIStore = SimAPIStore(); + +const simStore = useSimStore(); // 琛ㄥ崟鏁版嵁 const formData = reactive({ name: "鏂规鍚嶇О", selectedRainfall: "", type: 2, - gauges: [ - { - id: "xxxxxxxxxxxxxx", - name: "闆ㄩ噺璁�1", - x: 119.0, - y: 28.0, - r: 10000, - }, - { - id: "xxxxxxxxxxxxxx", - name: "闆ㄩ噺璁�2", - x: 119.0, - y: 28.0, - r: 10000, - }, - ], + gauges: [], }); - -// 宸ュ叿鍑芥暟锛氭繁鎷疯礉骞惰缃粯璁ら�変腑鐘舵�� -function deepCloneAndSetSelected(data) { - const newData = {}; - for (const key in data) { - newData[key] = data[key].map((item) => ({ ...item, selected: true })); - } - return newData; -} // 鎺ユ敹鐖剁粍浠朵紶閫掔殑 props const props = defineProps({ @@ -112,113 +104,112 @@ required: true, }, }); -const rainfallData = ref([]); + const tableData = ref({}); // 琛ㄦ牸鏁版嵁锛堟寜闆ㄩ噺鏁版嵁鍒嗙粍锛� const isCollapsed = ref(false); // 鎺у埗灞曞紑/鏀惰捣鐘舵�� -// 妯℃嫙涓嶅悓鍖哄煙鐨勬暟鎹� -const areaDataMap = { - 瀛欒儭娌�: { - rainfallData: [ - { id: "1", name: "姘旇薄瀹炴椂鏁版嵁 - 瀛欒儭娌�" }, - { id: "2", name: "闆ㄩ噺璁″疄鏃舵暟鎹� - 瀛欒儭娌�" }, - ], - tableData: { - 1: [ - { id: "001", name: "瀛欒儭娌熸皵璞$珯001" }, - { id: "002", name: "瀛欒儭娌熸皵璞$珯002" }, - ], - 2: [ - { id: "003", name: "瀛欒儭娌熼洦閲忚003" }, - { id: "004", name: "瀛欒儭娌熼洦閲忚004" }, - ], - }, - }, - 楸兼按娲炲悗娌�: { - rainfallData: [ - { id: "1", name: "姘旇薄瀹炴椂鏁版嵁 - 楸兼按娲炲悗娌�" }, - { id: "2", name: "闆ㄩ噺璁″疄鏃舵暟鎹� - 楸兼按娲炲悗娌�" }, - ], - tableData: { - 1: [ - { id: "005", name: "楸兼按娲炲悗娌熸皵璞$珯005" }, - { id: "006", name: "楸兼按娲炲悗娌熸皵璞$珯006" }, - ], - 2: [ - { id: "007", name: "楸兼按娲炲悗娌熼洦閲忚007" }, - { id: "008", name: "楸兼按娲炲悗娌熼洦閲忚008" }, - ], - }, - }, - 浜庡瑗挎矡: { - rainfallData: [ - { id: "1", name: "姘旇薄瀹炴椂鏁版嵁 - 浜庡瑗挎矡" }, - { id: "2", name: "闆ㄩ噺璁″疄鏃舵暟鎹� - 浜庡瑗挎矡" }, - ], - tableData: { - 1: [ - { id: "009", name: "浜庡瑗挎矡姘旇薄绔�009" }, - { id: "010", name: "浜庡瑗挎矡姘旇薄绔�010" }, - ], - 2: [ - { id: "011", name: "浜庡瑗挎矡闆ㄩ噺璁�011" }, - { id: "012", name: "浜庡瑗挎矡闆ㄩ噺璁�012" }, - ], - }, - }, +// 闆ㄩ噺璁′笅鎷夋 +const options = ref([ + { id: "1", name: "姘旇薄瀹炴椂鏁版嵁" }, + { id: "2", name: "闆ㄩ噺璁″疄鏃舵暟鎹�" }, +]); + +// 闆ㄩ噺璁″垪琛� +const shgList = ref([]); +// 鎵�鏈夌殑闆ㄩ噺璁″垪琛� +const rainListNoFilter = ref([]); + +// 鑾峰彇鎵�鏈夐洦閲忚鏁版嵁锛堟潵鑷帴鍙o級 +const getRainListAll = () => { + // 闆ㄩ噺璁$被鍨媔d + const ids = "1917487171642212354"; + getDeviceInfoSHG(ids).then((res) => { + rainListNoFilter.value = res.data.pageData; + // 鏍规嵁褰撳墠閫夋嫨鐨勫尯鍩熻嚜鍔ㄨ繃婊� + updateShgListByArea(); + }); }; -// 鏍规嵁 selectedArea 鏇存柊鏁版嵁 +// 鏍规嵁 props.selectedArea.label 杩囨护闆ㄩ噺璁″垪琛紝骞惰缃� selected: true +const updateShgListByArea = () => { + const currentArea = props.selectedArea?.label; + + if (!currentArea) { + shgList.value = []; + return; + } + + shgList.value = rainListNoFilter.value + .filter((item) => item.deviceName?.includes(currentArea)) + .map((device) => ({ + ...device, + selected: true, // 榛樿閫変腑 + })); + + console.log(shgList.value, "shgList.valueshgList.value"); +}; + +// 涓嬫媺妗嗛�変腑鍊肩殑琛ㄦ牸鏁版嵁鍙樺寲 +const handleChange = async (item) => { + formData.selectedRainfall = item; + + if (item === "闆ㄩ噺璁″疄鏃舵暟鎹�") { + if (!props.selectedArea) { + ElMessage.warning("璇峰厛閫夋嫨鍖哄煙"); + shgList.value = []; + return; + } + // 濡傛灉杩樻病鏈夊姞杞借繃鏁版嵁锛屽垯鍏堣姹傛帴鍙e姞杞� + if (rainListNoFilter.value.length === 0) { + getRainListAll(); // 鍔犺浇鍏ㄩ儴鏁版嵁鍚庝細鑷姩杩囨护 + } else { + updateShgListByArea(); // 宸叉湁鏁版嵁灏辩洿鎺ヨ繃婊� + } + } else { + shgList.value = []; + } +}; + +// 鐩戝惉鍖哄煙鍙樺寲锛岄噸鏂拌繃婊ゆ暟鎹� watch( () => props.selectedArea, (newArea) => { - console.log(newArea.label, "new"); - if (areaDataMap[newArea.label]) { - rainfallData.value = areaDataMap[newArea.label].rainfallData; - // 浣跨敤娣辨嫹璐濊缃粯璁ら�変腑鐘舵�� - tableData.value = deepCloneAndSetSelected( - areaDataMap[newArea.label].tableData - ); - formData.selectedRainfall = ""; // 娓呯┖閫変腑鐨勯洦閲忔暟鎹� - } else { - rainfallData.value = []; - tableData.value = {}; - formData.selectedRainfall = ""; + if (!newArea) { + ElMessage.warning("璇烽�夋嫨涓�涓尯鍩�"); + shgList.value = []; + } else if (formData.selectedRainfall === "闆ㄩ噺璁″疄鏃舵暟鎹�") { + handleChange(formData.selectedRainfall); } - } - // { immediate: true } // 绔嬪嵆鎵ц涓�娆★紝纭繚鍒濆鏁版嵁姝g‘ + }, + { immediate: true } ); -// 鍔ㄦ�佽绠楄〃鏍兼暟鎹� -const filteredTableData = computed(() => { - return formData.selectedRainfall && tableData.value[formData.selectedRainfall] - ? tableData.value[formData.selectedRainfall] - : []; -}); - -// 鑾峰彇褰撳墠閫変腑鐨勯洦閲忔暟鎹悕绉� -const selectedRainfallName = computed(() => { - const selected = rainfallData.value.find( - (item) => item.id === formData.selectedRainfall - ); - return selected ? selected.name : ""; -}); - -// 鑾峰彇褰撳墠閫変腑鐨勮澶囦俊鎭� -const selectedDevices = computed(() => { - return filteredTableData.value.filter((item) => item.selected); -}); - +// 閲嶇疆琛ㄥ崟 const resetForm = () => { formData.name = ""; formData.selectedRainfall = ""; + shgList.value = []; }; -// 鎵撳紑淇濆瓨鏂规瀵硅瘽妗� -const openSaveDialog = async () => { +const updateSelectedGauges = () => { + formData.gauges = shgList.value + .filter((item) => item.selected) + .map((item) => ({ + id: item.deviceCode, + name: item.deviceName, + x: item.longitude, + y: item.latitude, + r: 10000, + })); +}; + +// 淇濆瓨鏂规 +const saveSim = async () => { try { + // getYLJData("1101160300070101") + updateSelectedGauges(); formData.geom = props.selectedArea; - await simStore.addSimCheme(formData); + await simAPIStore.addSimCheme(formData); resetForm(); EventBus.emit("close-selectArea"); } catch (err) {} @@ -227,24 +218,179 @@ // 娉ㄥ叆妯℃嫙鎿嶄綔鏂规硶 const { startSimulate, endSimulate } = inject("simulateActions"); +// 瀹炴椂妯℃嫙瀹氭椂鍣� +let pollingInterval = null; +// 鐢ㄤ簬璁板綍涓婃鏁版嵁鏉℃暟 +let lastDataLength = 0; + +let pollingTimer = null; // 鐢ㄤ簬淇濆瓨瀹氭椂鍣ㄥ紩鐢� + async function startPlay() { - const selectedItems = filteredTableData.value.filter((item) => item.selected); - if (selectedItems.length > 0) { - console.log( - "閫変腑鐨勯」锛�", - selectedItems.map((item) => item.name) - ); - } else { - console.log("鏈�変腑浠讳綍椤�"); - } - console.log("褰撳墠閫変腑鐨勫尯鍩燂細", props.selectedArea); - // 寮�濮嬫ā鎷熷墠闇�瑕佸厛淇濆瓨鏂规 + updateSelectedGauges(); formData.geom = props.selectedArea; - await simStore.addSimCheme(formData); + + const resApi = await simAPIStore.addSimCheme(formData); + const schemeId = resApi.data?.data?.id; + + if (!schemeId) { + ElMessage.error("鏂规淇濆瓨澶辫触锛屾湭鑾峰彇鍒版湁鏁� ID"); + return; + } + EventBus.emit("close-selectArea"); - initeWaterPrimitiveView(); - startSimulate(); + + const loadingMessage = ElMessage({ + type: "info", + message: "姝e湪鍚姩妯℃嫙...", + duration: 0, + offset: 80, + }); + + try { + await getSimStart(schemeId); + + // 瀹氫箟涓�涓嚱鏁扮敤浜庤疆璇㈣幏鍙栨暟鎹� + const pollForResult = async () => { + try { + const res = await getSimresult(schemeId); + console.log(res.data, "瀹炴椂妯℃嫙 - 杞缁撴灉"); + + if (res.code === 200 && res.data.length > 0) { + // 鎴愬姛鎷垮埌鏁版嵁 + loadingMessage.close(); + handleNewData(res.data, schemeId); + startPolling(schemeId); + + // 鉁� 娓呴櫎瀹氭椂鍣� + if (pollingTimer) { + clearTimeout(pollingTimer); + pollingTimer = null; + } + } else { + // 鏁版嵁鏃犳晥锛岀户缁疆璇� + pollingTimer = setTimeout(pollForResult, 10 * 1000); + } + } catch (error) { + console.error("璇锋眰妯℃嫙缁撴灉澶辫触", error); + pollingTimer = setTimeout(pollForResult, 10 * 1000); // 璇锋眰鍑洪敊涔熺户缁疆璇� + } + }; + + // 棣栨寤惰繜 2 鍒嗛挓寮�濮嬭疆璇� + pollingTimer = setTimeout(async () => { + await pollForResult(); // 寮�濮嬬涓�娆¤疆璇� + }, 3 * 60 * 1000); // 3鍒嗛挓鍚庣涓�娆¤姹� + } catch (error) { + loadingMessage.close(); + ElMessage.error("璇锋眰澶辫触锛�" + (error.message || "鏈煡閿欒")); + console.error("璋冪敤 getSimStart 鍑洪敊锛�", error); + + if (pollingTimer) { + clearTimeout(pollingTimer); + pollingTimer = null; + } + } } + +// 瀹氭椂浜斿垎閽熻姹� +function startPolling(schemeId) { + stopPolling(); // 纭繚涓嶄細閲嶅鍚姩 + + pollingInterval = setInterval(async () => { + try { + const res = await getSimresult(schemeId); + + if (res.data && res.data.length > 0) { + if (res.data.length === lastDataLength) { + console.log("涓昏疆璇細鏃犳柊鏁版嵁锛屽垏鎹负 10 绉掗珮棰戣疆璇�"); + + clearInterval(pollingInterval); + pollingInterval = null; + + startFastPolling(schemeId); // 鍚姩楂橀杞 + } else { + handleNewData(res.data, schemeId); + } + } + } catch (error) { + console.error("杞鑾峰彇妯℃嫙缁撴灉澶辫触", error); + } + }, 5.6 * 60 * 1000); // 姣� 5.5 鍒嗛挓鎵ц涓�娆� +} + +let fastPollingInterval = null; +// 濡傛灉浜斿垎閽熸病鎷垮埌鏈�鏂扮殑鏁版嵁锛屽垯寮�鍚崄绉掗挓璋冪敤涓�娆★紝鎷垮埌鏈�鏂扮殑鏁版嵁灏卞仠姝� +function startFastPolling(schemeId) { + fastPollingInterval = setInterval(async () => { + try { + const res = await getSimresult(schemeId); + + if (res.data && res.data.length > 0) { + if (res.data.length !== lastDataLength) { + console.log("楂橀杞锛氭娴嬪埌鏂版暟鎹紝鎭㈠涓昏疆璇�"); + + clearInterval(fastPollingInterval); + fastPollingInterval = null; + + handleNewData(res.data, schemeId); + + startPolling(schemeId); // 閲嶆柊鍚姩涓昏疆璇� + } + } + } catch (error) { + console.error("楂橀杞鑾峰彇妯℃嫙缁撴灉澶辫触", error); + } + }, 10 * 1000); // 姣� 10 绉掓墽琛屼竴娆� +} + +// 鎷垮彇鏈�鏂扮殑layer.json瀛樺偍鍒皃inia涓� +async function handleNewData(dataArray, schemeId) { + // 鎷挎湇鍔″悕绉� + const res = await getSimDataById(schemeId); + simStore.setSelectedScheme(res.data[0]); // 鏇存柊鏂规鏁版嵁 + + const latestItem = dataArray[dataArray.length - 1]; + const currentLength = dataArray.length; + + if (currentLength <= lastDataLength) { + console.log("鏈疆鏃犳柊鏁版嵁锛堥暱搴︽湭鍙樺寲锛�"); + return; + } + + // 鏇存柊鏍囪瘑 + lastDataLength = currentLength; + + // 鎵ц鏇存柊閫昏緫 + console.log("妫�娴嬪埌鏂版暟鎹紝鏇存柊涓�..."); + console.log(latestItem, "last"); + simStore.layerDate = latestItem; + initeWaterPrimitiveView(); + + try { + startSimulate(); + } catch (error) { + console.error("璋冪敤 startSimulate 鍑洪敊锛�", error); + } +} + +// 鍋滄杞鍑芥暟 +function stopPolling() { + if (pollingInterval) { + clearInterval(pollingInterval); + pollingInterval = null; + } + + if (fastPollingInterval) { + clearInterval(fastPollingInterval); + fastPollingInterval = null; + } + + console.log("杞宸插仠姝�"); +} + +EventBus.on("close-time", () => { + stopPolling(); +}); const toggleDetails = () => { isCollapsed.value = !isCollapsed.value; @@ -253,6 +399,11 @@ const futurePredictions = () => { console.log("鏈潵棰勬祴鎸夐挳琚偣鍑�"); }; + +onUnmounted(() => { + EventBus.off("close-time"); + stopPolling(); +}); </script> <style scoped> @@ -309,7 +460,7 @@ .table-container { font-size: 12px; height: 120px; - width: 90%; + width: 96%; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; -- Gitblit v1.9.3