| | |
| | | <template> |
| | | <div class="listCard"> |
| | | <div class="left-top"> |
| | | <span>方案详情</span> |
| | | <el-button class="clickable-text" @click="handleBack">结束模拟</el-button> |
| | | </div> |
| | | <div class="top"><span>方案详情</span></div> |
| | | <div class="details"> |
| | | <div v-if="selectedScheme"> |
| | | <div class="input-group"> |
| | | <div class="input-item"> |
| | | <label>方案名称:</label> |
| | | <span>{{ selectedScheme.name }}</span> |
| | | </div> |
| | | <div class="input-item"> |
| | | <label>创建时间:</label> |
| | | <span>{{ formatTime(selectedScheme.createTime) }}</span> |
| | | </div> |
| | | <div class="input-item"> |
| | | <label>方案状态:</label> |
| | | <span>{{ statusText[selectedScheme.taskStatus] || "未知" }}</span> |
| | | </div> |
| | | <div class="input-item"> |
| | | <label>开始时间:</label> |
| | | <span>{{ selectedScheme.startTime }}</span> |
| | | </div> |
| | | <div class="input-item"> |
| | | <label>结束时间:</label> |
| | | <span>{{ selectedScheme.endTime }}</span> |
| | | </div> |
| | | <div class="input-item"> |
| | | <label>文件数量:</label> |
| | | <span>{{ selectedScheme.fileCount }}</span> |
| | | </div> |
| | | <div class="input-item"> |
| | | <label>输出周期:</label> |
| | | <span>{{ selectedScheme.outputPeriod }} 秒</span> |
| | | </div> |
| | | <div v-if="formattedData.length" class="input-group"> |
| | | <div |
| | | v-for="(item, index) in formattedData" |
| | | :key="index" |
| | | class="input-item" |
| | | > |
| | | <label>{{ item.name }}</label> |
| | | <span |
| | | :class="{ clickable: item.isClickable }" |
| | | @click="item.isClickable ? openGaugeDialog(item.gauges) : null" |
| | | > |
| | | {{ item.value }} |
| | | </span> |
| | | </div> |
| | | </div> |
| | | <div v-else> |
| | | <p style="text-align: center;">暂无方案信息</p> |
| | | <p style="text-align: center">暂无方案信息</p> |
| | | </div> |
| | | </div> |
| | | <div></div> |
| | | </div> |
| | | <Message |
| | | @close="close" |
| | |
| | | v-show="messageShow" |
| | | :mesData="mesData" |
| | | /> |
| | | <!-- 添加雨量计弹窗 --> |
| | | <div class="dialoog"> |
| | | <el-dialog |
| | | v-model="dialogVisible" |
| | | title="雨量计详情" |
| | | width="50%" |
| | | :before-close="handleClose" |
| | | > |
| | | <div class="table-container"> |
| | | <el-table :data="gaugesData" border stripe height="100%"> |
| | | <el-table-column prop="name" label="名称"></el-table-column> |
| | | <el-table-column prop="x" label="经度(X)"></el-table-column> |
| | | <el-table-column prop="y" label="纬度(Y)"></el-table-column> |
| | | <el-table-column prop="r" label="半径(r)"></el-table-column> |
| | | </el-table> |
| | | </div> |
| | | <!-- <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">关闭</el-button> |
| | | </span> |
| | | </template> --> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { defineProps, defineEmits, inject } from "vue"; |
| | | import { defineProps, defineEmits, inject, ref, watch } from "vue"; |
| | | import { |
| | | ElDialog, |
| | | ElTable, |
| | | ElTableColumn, |
| | | ElButton, |
| | | ElMessage, |
| | | } from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import { ElMessage } from 'element-plus' |
| | | |
| | | // 定义 emit 方法 |
| | | // 公共依赖 |
| | | const props = defineProps({ selectedScheme: { type: Object, default: null } }); |
| | | const emit = defineEmits(["back"]); |
| | | const { startSimulate, endSimulate } = inject("simulateActions"); |
| | | const { endSimulate } = inject("simulateActions"); |
| | | |
| | | // 返回按钮点击事件 |
| | | function handleBack() { |
| | | ElMessage({ |
| | | message: '模拟进程正在关闭中...', |
| | | type: 'success', |
| | | }) |
| | | emit("back", false); // 向父组件传递 false 值 |
| | | endSimulate(); |
| | | } |
| | | // 状态管理 |
| | | const formattedData = ref([]); |
| | | |
| | | // 接收父组件传递的 props |
| | | const props = defineProps({ |
| | | selectedScheme: { |
| | | type: Object, |
| | | default: null, |
| | | }, |
| | | }); |
| | | |
| | | // 格式化时间 |
| | | function formatTime(time) { |
| | | return dayjs(time).format("YYYY-MM-DD HH:mm:ss"); |
| | | } |
| | | |
| | | // 定义任务状态的文本映射 |
| | | const statusText = { |
| | | 0: "未开始", |
| | | 1: "进行中", |
| | | 2: "已完成", |
| | | // 映射表 |
| | | const areaTypeMap = { |
| | | 0: "自定义区域仿真", |
| | | 1: "行政区划仿真", |
| | | 2: "重点区域仿真", |
| | | 3: "重点沟仿真", |
| | | }; |
| | | |
| | | const statusMap = { |
| | | 0: "创建仿真", |
| | | 1: "预处理", |
| | | 2: "分析中", |
| | | 10: "完成", |
| | | 20: "出错", |
| | | }; |
| | | |
| | | const typeMap = { |
| | | 1: "预测模拟", |
| | | 2: "实时模拟", |
| | | 3: "历史模拟", |
| | | }; |
| | | |
| | | // 跳过字段列表 |
| | | const skipKeys = [ |
| | | "geom", |
| | | "id", |
| | | "serviceName", |
| | | "updateTime", |
| | | "updateUser", |
| | | "createUser", |
| | | "bak", |
| | | ]; |
| | | |
| | | // 处理 data 字段解析 |
| | | function parseDataField(dataStr) { |
| | | if (typeof dataStr !== "string") return []; |
| | | // console.log(dataStr, '方案详情内的降雨数据'); |
| | | |
| | | try { |
| | | const parsed = JSON.parse(dataStr); |
| | | const fields = { |
| | | total: "降雨总量(mm):", |
| | | duration: "降雨时长(小时):", |
| | | intensity: "降雨强度(mm/小时):", // 统一为 mm/h |
| | | prediction: "降雨场次:", |
| | | model: "降雨模式:", |
| | | history: "历史降雨:", |
| | | }; |
| | | |
| | | let { total, duration, intensity, intensityUnit } = parsed; |
| | | |
| | | // 根据 intensityUnit 确定转换系数 |
| | | let factor = 1; |
| | | switch (intensityUnit) { |
| | | case "mm/min": |
| | | factor = 60; |
| | | break; |
| | | case "mm/5min": |
| | | factor = 12; |
| | | break; |
| | | case "mm/h": |
| | | factor = 1; |
| | | break; |
| | | default: |
| | | factor = 1; |
| | | } |
| | | |
| | | // 转换单位:将 intensity 和 total 统一为按小时计算的值 |
| | | intensity = intensity != null ? (intensity * factor).toFixed(2) : "无"; |
| | | total = total != null ? (total * factor).toFixed(2) : "无"; |
| | | |
| | | // 控制台输出你需要的关键字段 |
| | | // console.log('转换后的降雨强度(mm/h):', intensity); |
| | | // console.log('转换后的降雨总量(mm):', total); |
| | | |
| | | // 处理 duration,如果非数字则设为默认值 |
| | | duration = duration != null ? parseInt(duration) : "无"; |
| | | |
| | | const result = Object.entries(parsed) |
| | | .filter(([k]) => fields[k]) |
| | | .map(([k, v]) => { |
| | | let displayValue = v || "无"; |
| | | if (k === "total") displayValue = total; |
| | | if (k === "duration") displayValue = duration; |
| | | if (k === "intensity") displayValue = intensity; |
| | | |
| | | return { |
| | | name: fields[k], |
| | | value: displayValue, |
| | | }; |
| | | }); |
| | | |
| | | // 处理雨量计数据 |
| | | if (parsed.type == 2 && parsed.gauges && Array.isArray(parsed.gauges)) { |
| | | const gaugeNames = parsed.gauges.map((g) => g.name).join(", ") || "无"; |
| | | result.push({ |
| | | name: "雨量计列表:", |
| | | value: "查看雨量计列表", |
| | | isClickable: true, |
| | | gauges: parsed.gauges, |
| | | }); |
| | | } |
| | | |
| | | return result; |
| | | } catch (e) { |
| | | console.error("解析 dataStr 出错:", e); |
| | | return [{ name: "数据:", value: dataStr || "无" }]; |
| | | } |
| | | } |
| | | |
| | | // 格式化时间戳 |
| | | function formatDate(timestamp) { |
| | | return dayjs(timestamp).format("YYYY-MM-DD HH:mm:ss"); |
| | | } |
| | | |
| | | // 格式化 selectedScheme 数据 |
| | | watch( |
| | | () => props.selectedScheme, |
| | | (newScheme) => { |
| | | if (!newScheme || typeof newScheme !== "object") { |
| | | formattedData.value = []; |
| | | return; |
| | | } |
| | | |
| | | const entries = Object.entries(newScheme); |
| | | const areaType = newScheme.areaType; |
| | | |
| | | // console.log(newScheme, "news"); |
| | | |
| | | const result = entries.reduce((acc, [key, value]) => { |
| | | if (skipKeys.includes(key)) return acc; |
| | | |
| | | switch (key) { |
| | | case "createTime": |
| | | acc.push({ name: "创建时间:", value: formatDate(value) }); |
| | | break; |
| | | case "areaType": |
| | | acc.push({ name: "区域类别:", value: areaTypeMap[value] || "未知" }); |
| | | break; |
| | | case "status": |
| | | acc.push({ name: "仿真状态:", value: statusMap[value] || "未知" }); |
| | | break; |
| | | case "type": |
| | | if (![1, 2].includes(areaType)) { |
| | | acc.push({ name: "模拟类别:", value: typeMap[value] || "未知" }); |
| | | } |
| | | break; |
| | | case "areaName": |
| | | acc.push({ name: "区域名称:", value: value || "无" }); |
| | | break; |
| | | case "result": |
| | | acc.push({ name: "仿真结果:", value: value || "无" }); |
| | | break; |
| | | case "name": |
| | | acc.push({ name: "仿真方案:", value: value || "无" }); |
| | | break; |
| | | case "data": |
| | | acc.push(...parseDataField(value)); |
| | | break; |
| | | default: |
| | | acc.push({ name: `${key}:`, value: value || "无" }); |
| | | } |
| | | |
| | | return acc; |
| | | }, []); |
| | | |
| | | formattedData.value = result; |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | const dialogVisible = ref(false); |
| | | const gaugesData = ref([]); |
| | | |
| | | // 打开雨量计弹窗 |
| | | function openGaugeDialog(gauges) { |
| | | if (Array.isArray(gauges) && gauges.length > 0) { |
| | | gaugesData.value = gauges.map((g) => ({ |
| | | name: g.name || "未知", |
| | | x: g.x != null ? g.x.toFixed(2) : "-", |
| | | y: g.y != null ? g.y.toFixed(2) : "-", |
| | | r: g.r || "-", |
| | | })); |
| | | dialogVisible.value = true; |
| | | } else { |
| | | ElMessage({ |
| | | message: "雨量计数据出错,请重新新建模拟方案!", |
| | | type: "warning", |
| | | }); |
| | | } |
| | | } |
| | | |
| | | // 关闭弹窗 |
| | | function handleClose(done) { |
| | | done(); |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | |
| | | margin-bottom: 20px; |
| | | border-radius: 8px; |
| | | color: white; |
| | | |
| | | .left-top { |
| | | display: flex; |
| | | justify-content: space-between; |
| | |
| | | } |
| | | |
| | | .details { |
| | | padding: 8px; |
| | | padding-left: 8px; |
| | | |
| | | .input-group { |
| | | display: flex; |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | .mess { |
| | | position: absolute; |
| | | top: 10%; |
| | | left: 100%; |
| | | z-index: 5000; |
| | | } |
| | | </style> |
| | | |
| | | .top { |
| | | display: flex; |
| | | width: 100%; |
| | | height: 41px; |
| | | color: white; |
| | | line-height: 41px; |
| | | font-size: 16px; |
| | | font-weight: 700; |
| | | cursor: pointer; |
| | | text-indent: 7px; |
| | | letter-spacing: 2px; |
| | | font-weight: bolder; |
| | | } |
| | | |
| | | .clickable { |
| | | color: #5bc0de; |
| | | cursor: pointer; |
| | | text-decoration: underline; |
| | | } |
| | | |
| | | .dialoog { |
| | | ::v-deep .el-dialog__title { |
| | | color: #fff !important; |
| | | } |
| | | |
| | | ::v-deep .el-dialog { |
| | | background-color: rgb(5, 75, 69) !important; |
| | | } |
| | | |
| | | .el-dialog__body { |
| | | padding-top: 10px; |
| | | padding-bottom: 10px; |
| | | } |
| | | |
| | | .table-container .el-table { |
| | | font-size: 14px; |
| | | border-radius: 4px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | } |
| | | } |
| | | </style> |