| | |
| | | <div class="left-top" v-if="simStore.selectTab == '重点区域仿真'"> |
| | | 重点区域仿真(10m精度) |
| | | </div> |
| | | <div class="forms"> |
| | | <el-form :model="forms" label-width="auto" style="max-width: 600px"> |
| | | <div class="left-top" v-if="simStore.selectTab == '重点沟仿真'"> |
| | | 历史模拟 |
| | | </div> |
| | | |
| | | <div class="forms" :class="{ 'no-background': !showBackground }"> |
| | | <el-form |
| | | :rules="rules" |
| | | :model="forms" |
| | | label-width="auto" |
| | | style="max-width: 600px" |
| | | > |
| | | <el-form-item label="方案名称:"> |
| | | <el-input |
| | | v-model="forms.name" |
| | | style="max-width: 600px" |
| | | placeholder="Please input" |
| | | placeholder="请输入方案名称" |
| | | > |
| | | </el-input> |
| | | </el-form-item> |
| | |
| | | <template #append>mm/h</template> |
| | | </el-upload> |
| | | </el-form-item> |
| | | <el-form-item label="雨强单位" v-if="forms.fileList.length !== 0"> |
| | | <el-select |
| | | v-model="forms.intensityUnit" |
| | | placeholder="Select" |
| | | style="max-width: 600px" |
| | | > |
| | | <el-option |
| | | v-for="item in intensityOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item |
| | | label="行政区域:" |
| | | v-if="simStore.selectTab == '行政区划仿真'" |
| | | > |
| | | <el-select |
| | | @change="changeGeom" |
| | | v-model="forms.geom" |
| | | placeholder="Select" |
| | | placeholder="请选择模拟区域" |
| | | style="max-width: 600px" |
| | | > |
| | | <el-option |
| | | v-for="item in options" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | :value="item" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | v-if="simStore.selectTab == '重点区域仿真'" |
| | | > |
| | | <el-select |
| | | @change="changeGeom" |
| | | v-model="forms.geom" |
| | | placeholder="Select" |
| | | placeholder="请选择模拟区域" |
| | | style="max-width: 600px" |
| | | > |
| | | <el-option |
| | | v-for="item in options" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | :value="item" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | <el-input |
| | | v-model="forms.rainfall" |
| | | style="max-width: 600px" |
| | | placeholder="Please input" |
| | | placeholder="请输入降雨量" |
| | | > |
| | | <template #append>mm</template> |
| | | </el-input> |
| | |
| | | v-if="forms.fileList.length !== 0" |
| | | v-model="forms.hours" |
| | | type="datetime" |
| | | placeholder="Select date and time" |
| | | placeholder="请选择开始时间" |
| | | /> |
| | | <el-date-picker |
| | | v-if="forms.fileList.length == 0" |
| | |
| | | disabled |
| | | v-model="forms.duration" |
| | | style="max-width: 600px" |
| | | placeholder="Please input" |
| | | placeholder="请输入降雨时长" |
| | | > |
| | | <template #append>h</template> |
| | | </el-input> |
| | |
| | | <el-input |
| | | v-model="forms.intensity" |
| | | style="max-width: 600px" |
| | | placeholder="Please input" |
| | | placeholder="请输入降雨强度" |
| | | > |
| | | <template #append>mm/h</template> |
| | | </el-input> |
| | |
| | | </el-form> |
| | | <div style="display: flex; justify-content: flex-end"> |
| | | <el-button type="primary" @click="addSimCheme">保存方案</el-button> |
| | | <el-button type="success" @click="startPlay">开始模拟</el-button> |
| | | <el-button type="success" @click="startPlay">保存并开始模拟</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { initeWaterPrimitiveView } from "@/utils/water"; |
| | | import { SimAPIStore } from "@/store/simAPI"; |
| | | import { getRegionData } from "@/api/trApi"; |
| | | import { getRegionData, getSimStart, getSimDataById } from "@/api/trApi"; |
| | | |
| | | import { storeToRefs } from "pinia"; |
| | | import dayjs from "dayjs"; |
| | | import { EventBus } from "@/eventBus"; // 引入事件总线 |
| | | |
| | | const simStore = SimAPIStore(); |
| | | const { selectTab } = storeToRefs(simStore); |
| | | |
| | | const options = reactive([]); |
| | | |
| | | // 历史模拟选中区域 |
| | | const props = defineProps({ |
| | | selectedArea: { |
| | | type: Object, |
| | | required: true, |
| | | }, |
| | | }); |
| | | |
| | | const intensityOptions = ref([ |
| | | { value: "mm/h", label: "mm/h" }, |
| | | { value: "mm/5min", label: "mm/5min" }, |
| | | ]); |
| | | |
| | | // 定义一个方法,用于根据 type 获取区域数据 |
| | | const fetchRegionData = (type) => { |
| | |
| | | fetchRegionData(1); |
| | | }); |
| | | |
| | | const showBackground = ref(true); // 默认显示背景图 |
| | | |
| | | // 监听 selectTab 的变化 |
| | | watch(selectTab, (newVal) => { |
| | | let type; |
| | |
| | | case "重点区域仿真": |
| | | type = 2; |
| | | break; |
| | | case "重点沟仿真": |
| | | type = 3; |
| | | break; |
| | | default: |
| | | type = 1; // 默认值 |
| | | } |
| | | // 根据 type 设置是否显示背景图(因为历史模拟中表单带了背景图) |
| | | if (type == 3) { |
| | | showBackground.value = false; |
| | | } else { |
| | | showBackground.value = true; |
| | | } |
| | | fetchRegionData(type); |
| | | // Tab切换的时候清空表单 |
| | | resetForm(); |
| | | }); |
| | | |
| | | // 注入父组件提供的方法 |
| | |
| | | const forms = reactive({ |
| | | name: "", |
| | | geom: "", |
| | | rainfall: "", |
| | | duration: "", |
| | | intensity: "", |
| | | rainfall: null, |
| | | duration: null, |
| | | intensity: null, |
| | | fileList: [], |
| | | type: 3, |
| | | rainFallList: [], |
| | | hours: "", |
| | | hours: null, |
| | | intensityUnit: "", |
| | | }); |
| | | |
| | | // 计算累计时长 |
| | | const calculateHoursDifference = (val) => { |
| | | if (!val || val.length !== 2) return 0; |
| | | const [startDate, endDate] = val; |
| | | const diffInHours = dayjs(endDate).diff(dayjs(startDate), "hour", true); // true 表示返回浮点数 |
| | | return diffInHours; |
| | | const flyHeight = ref(100000); |
| | | |
| | | // 将选中区域传递给gisView文件,做标红flyTo显示 |
| | | const changeGeom = (val) => { |
| | | if (selectTab.value == "行政区划仿真") { |
| | | flyHeight.value = 100000; |
| | | } else { |
| | | flyHeight.value = 5000; |
| | | } |
| | | EventBus.emit("select-geom", { geom: val.value, flyHeight: flyHeight.value }); |
| | | }; |
| | | |
| | | const { calculateHoursDifference } = inject("calculateHours"); |
| | | |
| | | const change = (val) => { |
| | | forms.duration = calculateHoursDifference(val); |
| | | }; |
| | | |
| | | const addSimCheme = async () => { |
| | | await simStore.addSimCheme(forms); |
| | | try { |
| | | if (selectTab.value == "重点沟仿真") { |
| | | forms.geom = props.selectedArea; |
| | | } |
| | | await simStore.addSimCheme(forms); |
| | | resetForm(); // 只有在保存成功后才重置表单 |
| | | EventBus.emit("close-selectArea"); |
| | | } catch (error) {} |
| | | }; |
| | | |
| | | // 重置表单 |
| | | const resetForm = () => { |
| | | forms.name = ""; |
| | | forms.geom = ""; |
| | | forms.eares = "孙胡沟"; |
| | | forms.rainfall = ""; |
| | | forms.duration = ""; |
| | | forms.intensity = ""; |
| | | forms.rainfall = null; |
| | | forms.duration = null; |
| | | forms.intensity = null; |
| | | forms.fileList = []; |
| | | forms.rainFallList = []; |
| | | forms.hours = ""; |
| | | forms.hours = null; |
| | | forms.intensityUnit = ""; |
| | | }; |
| | | |
| | | // 计算属性:获取上传文件的名称列表 |
| | |
| | | const transformKeys = (data) => { |
| | | return data.map((item) => ({ |
| | | time: item["时间"], // "时间" → "time" |
| | | intensity: item["小时雨强mm/h"], // "小时雨强mm/h" → "intensity" |
| | | total: item["累计雨量"], // "累计雨量" → "total" |
| | | intensity: parseFloat(item["小时雨强mm/h"]), // 转为浮点数 |
| | | total: parseFloat(item["累计雨量"]), // 转为浮点数 |
| | | })); |
| | | }; |
| | | |
| | | /** |
| | | * 检查时间列是否按升序排列 |
| | | * @param {Array} data - 表格数据 |
| | | * @param {string} timeColumn - 时间列的字段名 |
| | | * @returns {boolean} - 是否按升序排列 |
| | | */ |
| | | const isTimeColumnSorted = (data, timeColumn) => { |
| | | for (let i = 1; i < data.length; i++) { |
| | | const prevTime = parseDateTime(data[i - 1][timeColumn]); |
| | | const currentTime = parseDateTime(data[i][timeColumn]); |
| | | |
| | | // 如果前一个时间 > 当前时间,说明不是升序 |
| | | if (prevTime > currentTime) { |
| | | console.error(`时间乱序:第 ${i} 行`, { |
| | | prevTime: new Date(prevTime), |
| | | currentTime: new Date(currentTime), |
| | | }); |
| | | return false; |
| | | } |
| | | } |
| | | return true; // 所有时间都按升序排列 |
| | | }; |
| | | |
| | | /** |
| | | * 从表头提取单位(如 "小时雨强mm/h" → "mm/h") |
| | | * @param {string} header - 表头字符串 |
| | | * @returns {string} - 提取的单位(如 "mm/h"),默认返回空字符串 |
| | | */ |
| | | const extractUnitFromHeader = (header) => { |
| | | if (!header) return ""; |
| | | |
| | | // 直接匹配 "mm/h"、"m/s" 等常见单位 |
| | | const unitRegex = /(mm\/h|m\/s|mm|℃|%|hPa|km\/h)/; // 根据需要扩展 |
| | | const match = header.match(unitRegex); |
| | | return match ? match[0] : ""; |
| | | }; |
| | | |
| | | // 处理数据 |
| | | const processData = (data) => { |
| | | // 1. 检查数据是否为空 |
| | | if (data.length === 0) { |
| | | ElMessage.warning("文件内容为空!"); |
| | | return; |
| | | } |
| | | |
| | | // 2. 获取表头(第一列是时间列) |
| | | const tableColumns = Object.keys(data[0]); |
| | | const timeColumn = tableColumns[0]; // 假设第一列是时间 |
| | | |
| | | // 3. 校验时间列是否按升序排列 |
| | | if (!isTimeColumnSorted(data, timeColumn)) { |
| | | ElMessage.error("时间列必须按升序排列!"); |
| | | forms.fileList = []; |
| | | return; // 终止处理 |
| | | } |
| | | |
| | | const intensityColumn = tableColumns[1]; // 雨强列(如 "小时雨强(mm/h)") |
| | | console.log(intensityColumn, "intensityColumnintensityColumnintensityColumn"); |
| | | // 3. 提取第二列的单位(如 "(mm/h)" → "mm/h") |
| | | const intensityUnit = extractUnitFromHeader(intensityColumn); |
| | | forms.intensityUnit = intensityUnit; // 存储单位(可选) |
| | | |
| | | // 4. 如果校验通过,继续处理数据 |
| | | forms.rainFallList = transformKeys(data); |
| | | console.log(forms.rainFallList, "data"); |
| | | if (data.length === 0) return; |
| | | |
| | | const tableColumns = Object.keys(data[0]); |
| | | |
| | | // 第一列:时间 |
| | | const firstTime = parseDateTime(data[0][tableColumns[0]]); |
| | | const lastTime = parseDateTime(data[data.length - 1][tableColumns[0]]); |
| | | // 5. 计算降雨时长、最大雨强、累计雨量(原逻辑) |
| | | const firstTime = parseDateTime(data[0][timeColumn]); |
| | | const lastTime = parseDateTime(data[data.length - 1][timeColumn]); |
| | | const timeDuration = Math.floor((lastTime - firstTime) / 1000); |
| | | forms.duration = (timeDuration / 3600).toFixed(2); // 更新降雨时长 |
| | | forms.duration = (timeDuration / 3600).toFixed(2); |
| | | |
| | | // 第二列:降雨强度 |
| | | const maxValue = Math.max( |
| | | ...data.map((row) => { |
| | | const value = parseFloat(row[tableColumns[1]]); |
| | | return isNaN(value) ? -Infinity : value; |
| | | }) |
| | | ).toFixed(2); |
| | | forms.intensity = maxValue; // 更新降雨强度 |
| | | forms.intensity = maxValue; |
| | | |
| | | // 第三列:累计降雨量 |
| | | const lastValue = data[data.length - 1][tableColumns[2]]; |
| | | forms.rainfall = lastValue; // 更新降雨量 |
| | | forms.rainfall = lastValue; |
| | | }; |
| | | |
| | | /** |
| | |
| | | }; |
| | | |
| | | // 开始模拟 |
| | | function startPlay() { |
| | | initeWaterPrimitiveView(); |
| | | startSimulate(); |
| | | async function startPlay() { |
| | | try { |
| | | // 保存方案 |
| | | if (selectTab.value == "重点沟仿真") { |
| | | forms.geom = props.selectedArea; |
| | | } |
| | | const res = await simStore.addSimCheme(forms); |
| | | const schemeId = res.data?.data?.id; |
| | | |
| | | if (!schemeId) { |
| | | ElMessage.error("方案保存失败,未获取到有效 ID"); |
| | | return; |
| | | } |
| | | |
| | | // 调用求解器 |
| | | const simStartRes = await getSimStart(schemeId); |
| | | |
| | | // 关闭选择区域窗口、初始化视图并开始模拟 |
| | | EventBus.emit("close-selectArea"); |
| | | simStore.shouldPoll = true; |
| | | |
| | | // 暂时不在此处开始模拟,模拟都在方案列表中进行模拟 |
| | | // initeWaterPrimitiveView(); |
| | | // startSimulate(); |
| | | |
| | | ElMessage.warning({ |
| | | message: "请返回方案列表开始模拟!", |
| | | duration: 10000, // 提示框显示时长,单位为毫秒,默认是3000毫秒 |
| | | }); |
| | | } catch (error) { |
| | | console.error("启动模拟过程中发生错误:", error); |
| | | // ElMessage.error("启动模拟失败,请稍后再试"); |
| | | } |
| | | } |
| | | </script> |
| | | |
| | |
| | | height: 100%; |
| | | padding: 10px 10px 0px 0px; |
| | | box-sizing: border-box; |
| | | transition: background 0.3s ease; // 可选过渡效果 |
| | | } |
| | | |
| | | .forms.no-background { |
| | | margin-top: 0px; |
| | | background-image: none; |
| | | } |
| | | /deep/ .el-input-group__append, |
| | | .el-input-group__prepend { |