guonan
6 天以前 a57caa72a54efe9de3fe26a6c36d3e8038267377
src/components/monifangzhen/schemeCard.vue
@@ -1,24 +1,47 @@
<template>
  <div class="listCard">
    <!-- <div>方案数量: {{ simStore.schemCard.length }}</div> -->
    <el-card v-for="(item, key) in simStore.schemCard" :key="key" :class="{ selected: selectedId === item.id }"
    @click="selectScheme(item.id)">
    <el-card
      v-if="!schemeInfoShow"
      v-for="(item, key) in schemeList"
      :key="key"
      :class="{ selected: selectedId === item.id }"
      @click="selectScheme(item.id)"
    >
      <div>
        <p>方案名称 : {{ item.name }}</p>
        <p>创建时间 : {{ formatTime(item.createTime) }}</p>
        <p>
          方案状态 :
          <span style="color: aquamarine">{{ statusText[item.taskStatus] || "未知" }}</span>
          <span style="color: aquamarine">
            {{ item.result === "-1" ? "出错" : item.result || "创建仿真" }}
          </span>
        </p>
      </div>
      <div class="cardMenu">
        <div style="float: right; margin-top: 3px">
          <el-button size="small" @click="setSchemClick(item)">方案详情</el-button>
          <el-button size="small" @click="startPlay(item)">进入模拟</el-button>
          <!--  :disabled="item.taskStatus !== 2" -->
          <el-button size="small" @click="setSchemClick(item)"
            >方案详情</el-button
          >
          <el-button
            size="small"
            v-show="item.type !== 2"
            @click="startPlay(item)"
            >进入模拟</el-button
          >
          <el-button size="small" v-show="item.type == 2" @click="rePlay(item)"
            >历史回放</el-button
          >
          <!--  :disabled="item.status !== 2" -->
        </div>
      </div>
    </el-card>
    <schemeInfo
      v-if="schemeInfoShow"
      :selectedScheme="currentScheme"
      @back="handleBack"
    />
    <flowRateTab v-if="schemeInfoShow"> 123 </flowRateTab>
  </div>
  <Message
    @close="close"
@@ -29,294 +52,415 @@
</template>
<script setup>
import { ref } from "vue";
import { EventBus } from "@/eventBus"; // 引入事件总线
import {
  nextTick,
  onMounted,
  ref,
  watch,
  defineEmits,
  onUnmounted,
  inject,
} from "vue";
import dayjs from "dayjs";
import { initeWaterPrimitiveView } from "@/utils/water";
import Message from "@/components/tools/Message.vue";
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 {
  getSimData,
  deleteSimData,
  getSimStart,
  getSimDataById,
  getSimresult,
} from "@/api/trApi.js";
import { getAeraTownCode, getDeviceNWJ } from "@/api/hpApi";
import { createPoint, removeEntities, clearAllPoints } from "@/utils/map";
import { deviceDictList, getDictName } from "@/constant/dict.js";
const simStore = useSimStore();
const simAPIStore = SimAPIStore();
// 选中的方案 ID
const selectedId = ref(null);
// 当前选中的方案信息
const currentScheme = ref(null);
// 选中方案
function selectScheme(id) {
  selectedId.value = id;
}
simStore.setSchemCard([
  {
    area: "孙胡沟",
    areaId: "0",
    createTime: "2025-01-13 19:33:04",
    datPath: "e:/data/hydro/11011611021801/1878767214615695362",
    dataType: 2,
    dataValue: "",
    depthThreshold: 0,
    endTime: "2023-08-01 01:59:59",
    fileCount: 299,
    fileName: "东江沟雨量计0110.xls",
    hotStart: false,
    id: "1878767214431145986",
    name: "降雨数据:房山区东江沟数据",
    noRainTime: 0,
    outputPeriod: 600,
    shpPath: "e:/data/hydro/11011611021801/shp",
    simulateType: 1,
    startTime: "2023-07-30 00:00:00",
    taskId: "1878767214615695362",
    taskStatus: 2,
    updateTime: "2025-01-13 19:33:04",
    userId: "0",
  },
  {
    area: "孙胡沟",
    areaId: "0",
    createTime: "2025-01-10 14:33:49",
    datPath: "e:/data/hydro/11011611021801/1877604741980196866",
    dataType: 2,
    dataValue: "",
    depthThreshold: 0,
    endTime: "2023-08-02 01:00:00",
    fileCount: 450,
    fileName: "东江沟雨量计0110.xls",
    hotStart: false,
    id: "1877604741590126594",
    name: "东江沟0729-0801",
    noRainTime: 0,
    outputPeriod: 600,
    shpPath: "e:/data/hydro/11011611021801/shp",
    simulateType: 1,
    startTime: "2023-07-29 22:00:00",
    taskId: "1877604741980196866",
    taskStatus: 2,
    updateTime: "2025-01-10 14:33:49",
    userId: "0",
  },
  {
    area: "孙胡沟",
    areaId: "0",
    createTime: "2024-12-27 12:28:45",
    datPath: "e:/data/hydro/11011611021801/1872499838538584065",
    dataType: 2,
    dataValue: "",
    depthThreshold: 0,
    endTime: "2023-08-02 09:00:00",
    fileCount: 654,
    fileName: "东江沟雨量计0110.xls",
    hotStart: false,
    id: "1872499838278537217",
    name: "北京市731暴雨",
    noRainTime: 0,
    outputPeriod: 600,
    shpPath: "e:/data/hydro/11011611021801/shp",
    simulateType: 1,
    startTime: "2023-07-28 20:00:00",
    taskId: "1872499838538584065",
    taskStatus: 2,
    updateTime: "2024-12-27 12:28:45",
    userId: "0",
  },
  {
    area: "孙胡沟",
    areaId: "0",
    createTime: "2024-12-20 15:00:11",
    datPath: "e:/data/hydro/11011611021801/1870001233680502786",
    dataType: 0,
    dataValue: "",
    depthThreshold: 0,
    endTime: "2024-12-20 06:00:00",
    fileCount: 86,
    fileName: "",
    hotStart: false,
    id: "1870001233646948354",
    name: "雨强30mm",
    noRainTime: 0,
    outputPeriod: 300,
    shpPath: "e:/data/hydro/11011611021801/shp",
    simulateType: 1,
    startTime: "2024-12-20 00:00:00",
    taskId: "1870001233680502786",
    taskStatus: 2,
    updateTime: "2024-12-20 15:00:11",
    userId: "0",
  },
  {
    area: "孙胡沟",
    areaId: "0",
    createTime: "2024-12-19 17:34:34",
    datPath: "e:/data/hydro/11011611021801/1869677696923045889",
    dataType: 2,
    dataValue: "",
    depthThreshold: 0,
    endTime: "2023-08-01 03:00:44",
    fileCount: 388,
    fileName: "截流坝雨量计0068.xls",
    hotStart: false,
    id: "1869677696608473090",
    name: "截流坝数据模拟0729-0731",
    noRainTime: 0,
    outputPeriod: 600,
    shpPath: "e:/data/hydro/11011611021801/shp",
    simulateType: 1,
    startTime: "2023-07-29 21:00:13",
    taskId: "1869677696923045889",
    taskStatus: 2,
    updateTime: "2024-12-19 17:34:34",
    userId: "0",
  },
  {
    area: "孙胡沟",
    areaId: "0",
    createTime: "2024-12-13 15:03:24",
    datPath: "e:/data/hydro/11011611021801/1867465327392165890",
    dataType: 2,
    dataValue: "",
    depthThreshold: 0,
    endTime: "2023-07-31 12:00:00",
    fileCount: 288,
    fileName: "东江沟雨量计0110.xls",
    hotStart: false,
    id: "1867465327106953218",
    name: "东江沟数据模拟0729-0731",
    noRainTime: 0,
    outputPeriod: 600,
    shpPath: "e:/data/hydro/11011611021801/shp",
    simulateType: 1,
    startTime: "2023-07-29 12:00:00",
    taskId: "1867465327392165890",
    taskStatus: 2,
    updateTime: "2024-12-13 15:03:24",
    userId: "0",
  },
  {
    area: "孙胡沟",
    areaId: "0",
    createTime: "2024-11-28 19:01:16",
    datPath: "e:/data/hydro/11011611021801/1862089369491931138",
    dataType: 2,
    dataValue: "",
    depthThreshold: 0,
    endTime: "2023-07-31 00:00:00",
    fileCount: 145,
    fileName: "东江沟雨量计0110.xls",
    hotStart: false,
    id: "1862089369462571010",
    name: "东江沟雨量0731",
    noRainTime: 0,
    outputPeriod: 600,
    shpPath: "e:/data/hydro/11011611021801/shp",
    simulateType: 1,
    startTime: "2023-07-30 00:00:00",
    taskId: "1862089369491931138",
    taskStatus: 2,
    updateTime: "2024-11-28 19:01:16",
    userId: "0",
  },
  {
    area: "孙胡沟",
    areaId: "0",
    createTime: "2024-11-28 18:47:45",
    datPath: "e:/data/hydro/11011611021801/1862085967261270017",
    dataType: 0,
    dataValue: "",
    depthThreshold: 0,
    endTime: "2024-08-31 00:00:00",
    fileCount: 145,
    fileName: "",
    hotStart: false,
    id: "1862085967252881410",
    name: "雨强模拟方案0830",
    noRainTime: 0,
    outputPeriod: 600,
    shpPath: "e:/data/hydro/11011611021801/shp",
    simulateType: 1,
    startTime: "2024-08-30 00:00:00",
    taskId: "1862085967261270017",
    taskStatus: 2,
    updateTime: "2024-11-28 18:47:45",
    userId: "0",
  },
  {
    area: "孙胡沟",
    areaId: "0",
    createTime: "2024-11-28 18:39:49",
    datPath: "e:/data/hydro/11011611021801/1862083971414294529",
    dataType: 1,
    dataValue: "",
    depthThreshold: 0,
    endTime: "2024-07-31 00:00:00",
    fileCount: 145,
    fileName: "",
    hotStart: false,
    id: "1862083971003252737",
    name: "雨量模拟方案0730",
    noRainTime: 0,
    outputPeriod: 600,
    shpPath: "e:/data/hydro/11011611021801/shp",
    simulateType: 1,
    startTime: "2024-07-30 00:00:00",
    taskId: "1862083971414294529",
    taskStatus: 2,
    updateTime: "2024-11-28 18:39:49",
    userId: "0",
  },
  {
    area: "孙胡沟",
    areaId: "0",
    createTime: "2024-11-28 17:26:45",
    datPath: "e:/data/hydro/11011611021801/1862065584806100994",
    dataType: 0,
    dataValue: "",
    depthThreshold: 0,
    endTime: "2024-11-28 09:26:17",
    fileCount: 57,
    fileName: "",
    hotStart: false,
    id: "1862065584743186434",
    name: "雨强模拟方案1128",
    noRainTime: 0,
    outputPeriod: 600,
    shpPath: "e:/data/hydro/11011611021801/shp",
    simulateType: 1,
    startTime: "2024-11-28 00:00:00",
    taskId: "1862065584806100994",
    taskStatus: 2,
    updateTime: "2024-11-28 17:26:45",
    userId: "0",
  },
]);
const statusText = {
  0: "未开始",
  1: "进行中",
  2: "已完成",
};
function formatTime(time) {
  return dayjs(time).format("YYYY-MM-DD HH:mm:ss");
}
const messageShow = ref(false);
const schemeInfoShow = ref(false);
const mesData = ref(null);
function setSchemClick(item) {
  mesData.value = item;
  messageShow.value = true;
}
function close() {
  messageShow.value = false;
}
function startPlay(item) {
  // if (item.taskStatus !== 2) {
  //   alert("当前方案尚未完成,无法进入模拟!");
  //   return;
  // }
  initeWaterPrimitiveView();
  emit("start");
// 实时模拟五分钟请求一次的定时器
const realTimeSimInterval = ref(null);
const { startSimulate, endSimulate } = inject("simulateActions");
const BJCode = ref([
  { label: "密云区", value: "110118000000" },
  { label: "房山区", value: "110111000000" },
  { label: "门头沟区", value: "110109000000" },
  { label: "延庆区", value: "110119000000" },
  { label: "怀柔区", value: "110116000000" },
  { label: "昌平区", value: "110114000000" },
  { label: "平谷区", value: "110117000000" },
  { label: "海淀区", value: "110108000000" },
  { label: "石景山区", value: "110107000000" },
  { label: "丰台区", value: "110106000000" },
]);
async function startPlay(item) {
  simStore.openDia = false;
  clearAllPoints();
  const areaName = item.areaName;
  let districtCode;
  // 1. 判断是否包含 “区”
  if (!areaName.includes("区")) {
    console.log(
      `方案中模拟【${areaName}】不包含“区”,使用默认编码:怀柔区(110116000000)`
    );
    districtCode = "110116000000"; // 手动指定为怀柔区编码
  } else {
    // 2. 在 BJCode 中查找匹配的区域 value
    const matchedArea = BJCode.value.find((area) => area.label === areaName);
    if (!matchedArea) {
      console.warn(`未找到 ${areaName} 对应的区域编码`);
      return;
    }
    districtCode = matchedArea.value;
  }
  // 1. 获取乡镇区域编码
  const areaRes = await getAeraTownCode(districtCode);
  const districtCodes = areaRes.data.map((item) => item.districtCode);
  // 2. 泥位计类型ID
  const ids = "1437295811";
  // 3. 并行请求所有设备数据
  const requests = districtCodes.map((code) =>
    getDeviceNWJ(ids, code)
      .then((res) => res.data?.pageData || []) // 安全提取 pageData
      .catch((err) => {
        console.error(`请求失败 (code: ${code})`, err);
        return []; // 出错时也返回空数组,避免 Promise.all 中断
      })
  );
  // 4. 等待所有请求完成
  const allPageDataArrays = await Promise.all(requests);
  // 5. 合并二维数组为一维数组
  const mergedPageData = allPageDataArrays.flat();
  // 6. 如果不是“区”,则过滤出 deviceName 包含 "孙胡沟" 的设备
  const filteredPageData = areaName.includes("区")
    ? mergedPageData
    : mergedPageData.filter((device) => device.deviceName.includes("孙胡沟"));
  // 孙胡沟设备经纬度映射
  const deviceMapping = {
    怀柔区琉璃庙镇孙胡沟椴树底下东沟泥位计5007: {
      lon: 116.598891,
      lat: 40.554979,
    },
    怀柔区琉璃庙镇孙胡沟村上台子河东南沟泥位计5006: {
      lon: 116.593215,
      lat: 40.554399,
    },
  };
  let displayedData = filteredPageData;
  if (!areaName.includes("区")) {
    // 添加 lon 和 lan 字段
    displayedData = filteredPageData.map((device) => {
      const mapping = deviceMapping[device.deviceName];
      return {
        ...device,
        ...(mapping && { lon: mapping.lon, lat: mapping.lat }), // 如果 mapping 存在,才添加
      };
    });
    // 添加额外的两个点位
    const extraPoint1 = {
      deviceName: "弯沟1",
      longitude: 116.597836,
      latitude: 40.564962,
      // height: 530.14,
      type: "泥位计",
      lon: 116.597836,
      lat: 40.564962,
      dictDeviceType: "1437295811",
      deviceId: "custom_extraPoint1", // 手动加一个唯一 ID
    };
    const extraPoint2 = {
      deviceName: "弯沟2",
      longitude: 116.591571,
      latitude: 40.573093,
      // height: 483.89,
      type: "泥位计",
      lon: 116.591571,
      lat: 40.573093,
      dictDeviceType: "1437295811",
      deviceId: "custom_extraPoint2", // 手动加一个唯一 ID
    };
    displayedData = [...displayedData, extraPoint1, extraPoint2];
    // displayedData = [...displayedData, extraPoint1];
  }
  console.log(
    displayedData,
    areaName.includes("区")
      ? "全部泥位计设备列表"
      : "孙胡沟泥位计 + 额外点位列表"
  );
  // 7. 创建点
  displayedData.forEach((item) => {
    // 根据需求可增删
    item.type = getDictName(deviceDictList, item.dictDeviceType);
    item.name = item.deviceName;
    item.id = item.deviceId;
    item.className = "device";
    item.showLabel = true;
    createPoint(item);
  });
  if (item.status === 2) {
    ElMessage.warning("当前方案正在分析中,无法进入模拟!");
    return;
  }
  if (item.status === 20) {
    ElMessage.error("当前方案分析出错,请重新新建方案!");
    return;
  }
  // 如果是已完成的方案(status == 10)
  if (item.status === 10) {
    const flyHeight = item.areaType === 1 ? 100000 : 50000;
    simStore.setSelectedScheme(item);
    if (item.areaType === 1) {
      EventBus.emit("select-geom", {
        geom: item.geom,
        flyHeight,
        shouldShowFill: false,
      });
    } else {
      initeWaterPrimitiveView();
    }
    currentScheme.value = item;
    schemeInfoShow.value = true;
    emit("closeBtn", false);
    startSimulate();
    return;
  }
  // 新建方案,没有 status 和 serviceName 且 type != 2
  if (!item.status && !item.serviceName && item.type !== 2) {
    try {
      await getSimStart(item.id);
      const res = await getSimDataById(item.id);
      item.serviceName = res.data[0]?.serviceName || null;
      simStore.setSelectedScheme(item);
      ElMessage.warning("当前方案正在分析中,请稍后再模拟");
      getScheme();
    } catch (e) {
      console.error("获取模拟数据失败:", e);
    }
    return;
  }
  // 默认情况:有服务名称
  simStore.setSelectedScheme(item);
}
const emit = defineEmits(["start", "end"]);
function endPlay() {
  emit("end");
// 实时模拟历史回放
function rePlay(item) {
  // 当前选中的方案
  simStore.setSelectedScheme(item);
  // 拿id去请求results接口,如果长度不为0,则可以进行历史回放
  getSimresult(item.id)
    .then((res) => {
      if (res.code == 500) {
        // 如果长度为0,提示用户并且不进行后续操作
        ElMessage.warning("提示:没有可回放的数据!");
        return; // 阻止后续操作
      } else {
        simStore.rePlayList = res.data;
        console.log(simStore.rePlayList, "实时模拟历史回放列表");
      }
      // 使用 nextTick 确保 DOM 更新后再执行后续操作
      nextTick(() => {
        initeWaterPrimitiveView();
        startSimulate();
      });
    })
    .catch((error) => {
      console.log("请求失败:", error);
      // 错误处理
    });
}
// 暴露选中的 ID 给父组件
defineExpose({
  getSelectedId: () => selectedId.value,
function handleBack(value) {
  if (value === false) {
    schemeInfoShow.value = false;
  }
}
const handleHideSchemeInfo = () => {
  schemeInfoShow.value = false;
  emit("closeBtn", true);
};
// 注册事件监听器
EventBus.on("hide-schemeInfo", handleHideSchemeInfo);
const schemeList = ref([]);
let intervalId = null; // 用于存储 setInterval 的返回值
// 获取方案列表
async function getScheme() {
  try {
    const res = await getSimData();
    schemeList.value = res.data;
    const shouldStop = schemeList.value.every(
      (item) =>
        item.result == "创建仿真" ||
        item.result == "完成" ||
        item.result == "-1" ||
        item.result == "已停止" ||
        item.result == "运行中"
    );
    simAPIStore.shouldPoll = !shouldStop; // 修改 Pinia 状态
    // 3. 如果需要停止
    if (shouldStop) {
      if (intervalId) {
        clearInterval(intervalId);
        intervalId = null;
        console.log("停止轮询");
      }
      return;
    }
  } catch (error) {
    console.error("Error fetching data:", error);
  }
}
// 监听 shouldPoll 状态变化
watch(
  () => simAPIStore.shouldPoll,
  (isStarted) => {
    if (isStarted) {
      getScheme(); // 首次立即获取一次
      intervalId = setInterval(getScheme, 60 * 1000); // 每隔一分钟执行
    }
    // else if (intervalId !== null) {
    //   clearInterval(intervalId);
    //   intervalId = null;
    // }
  },
  { immediate: true }
);
const props = defineProps({
  deleteSim: Boolean, // 接收父组件传递的函数
  showAddIns: Boolean,
});
// 新建方案完成之后方案列表需实时刷新
watch(
  () => props.showAddIns,
  (newVal) => {
    if (newVal == false) {
      getScheme();
    }
  }
);
// 删除仿真列表
watch(
  () => props.deleteSim,
  (newVal) => {
    if (newVal) {
      deleteSim();
      emit("reset");
    }
  }
);
const deleteSim = () => {
  // 确保有选中的方案
  if (!selectedId.value) {
    ElMessage({
      type: "warning",
      message: "请先选择一个方案进行删除!",
    });
    return;
  }
  const selectedScheme = schemeList.value.find(
    (item) => item.id === selectedId.value
  );
  const schemeName = selectedScheme ? selectedScheme.name : "未知方案";
  ElMessageBox.confirm(`确定要删除方案 "${schemeName}" 吗?`, "删除方案", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      deleteSimData(selectedId.value).then((res) => {
        getScheme();
      });
      ElMessage({
        type: "success",
        message: `方案 "${schemeName}" 删除成功`,
      });
    })
    .catch(() => {});
};
onMounted(() => {
  getScheme(); // 页面加载时立即获取数据
});
onUnmounted(() => {
  EventBus.off("hide-schemeInfo", handleHideSchemeInfo);
  if (intervalId !== null) {
    clearInterval(intervalId); // 清除定时器
    intervalId = null; // 重置 intervalId
  }
});
</script>
@@ -361,6 +505,7 @@
.listCard-btn:hover {
  background: url("@/assets/img/left/cardbtnac.png") no-repeat;
}
.mess {
  position: absolute;
  top: 10%;
@@ -384,7 +529,9 @@
  scale: (1.02);
  border: 1px solid #acf1dd;
}
.selected {
  border: 2px solid #acf1dd !important; /* 选中时的边框样式 */
  border: 2px solid #acf1dd !important;
  /* 选中时的边框样式 */
}
</style>