Newer
Older
KaiFengPC / src / views / floodSys / floodYP / riskAsses.vue
@鲁yixuan 鲁yixuan on 19 Jun 14 KB update
<template>
  <!-- 排水防涝 态势研判 内涝风险评估 -->
  <div class="publicContainer riskEstimate">
    <!-- gis 地图 -->
    <RiskGisMap @loadCallback="mapInit"></RiskGisMap>
    <!-- 左侧分析方案 -->
    <div class="riskLeft animate__animated animate__bounceInLeft">
      <div class="mapTitle">模拟工况</div>
      <el-form label-width="90px">
        <el-form-item label="降雨重现期" prop="scenario">
          <el-select v-model="queryParams.scenario" placeholder="请选择" clearable @change="getZSList">
            <el-option v-for="item in drains_scenario" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="降雨时长" prop="duration">
          <el-select v-model="queryParams.duration" placeholder="请选择" clearable @change="getZSList">
            <el-option v-for="item in drains_rainfall_duration" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </el-form-item>
      </el-form>
      <!-- 方案名称 -->
      <div class="progranme">
        <el-radio-group v-model="caseId" @change="changeCase" style="justify-content: center">
          <div class="part" v-for="item in schemeData" :key="item.fid">
            <el-radio :label="item.fid">
              <div class="cont">
                <p class="ellipsis">{{ item.schemeName }}</p>
                <p>总降雨量:{{ item.rainfall }}mm</p>
              </div>
            </el-radio>
          </div>
        </el-radio-group>
      </div>
    </div>
    <!-- 中间操作 -->
    <div class="centerWarnRK flex">
      <el-select v-model="moduleTypeEnum" placeholder="请选择模拟对象" @change="changeObject">
        <el-option v-for="item in caseType" :key="item.value" :label="item.label" :value="item.value" />
      </el-select>
      <el-select v-model="searchValSpeed" placeholder="倍数" style="width: 80px; margin-left: 10px" @change="changeBS">
        <el-option v-for="item in bsType" :key="item.value" :label="item.label" :value="item.value" />
      </el-select>
      <!-- <div class="flex" style="position: relative; width: 600px">
        <TimeLine :list="timelineList" @getTimeLineIndex="getTimeLineIndex"> </TimeLine>
      </div> -->
      <el-progress :stroke-width="20" :percentage="processVal" status="success" :text-inside="true"></el-progress>
      <el-button type="warning" @click="startImitate" v-if="ifStart">开始</el-button>
      <el-button type="warning" @click="stopImitate" v-else>暂停</el-button>
    </div>
    <!-- 右侧具体数据展示 -->
    <div :class="['zksqImg', ifExpand ? 'leftZk' : 'leftSq']" @click="ifExpand = !ifExpand" title="展开收起"></div>
    <div :class="['riskRight', 'animate__animated', ifExpand ? 'animate__bounceInRight' : 'animate__bounceOutRight']">
      <RiskRCont :paramsCase="paramsCase"></RiskRCont>
    </div>
    <!-- 图例颜色,不同模型不同图例内容 -->
    <div
      :class="['mapLegendColor', ifExpand ? 'leftZk' : 'leftSq']"
      v-if="moduleTypeEnum == 'duration-depth' || moduleTypeEnum == 'max-depth'"
    >
      <p class="title">最大积水深度(米)</p>
      <p><span class="info"></span> 0.05-0.15</p>
      <p><span class="primary"></span> 0.15-0.3</p>
      <p><span class="yellow"></span> 0.3-0.5</p>
      <p><span class="pink"></span> 0.5-1.0</p>
      <p><span class="red"></span> 大于1.0</p>
    </div>
    <div :class="['mapLegendColor', ifExpand ? 'leftZk' : 'leftSq']" v-if="moduleTypeEnum == 'max-filling'">
      <!-- <p class="title" v-if="moduleTypeEnum == 'max-depth'">积水时长(小时)</p> -->
      <p class="title" v-if="moduleTypeEnum == 'max-filling'">满管时长(小时)</p>
      <p><span class="info"></span>0-4</p>
      <p><span class="primary"></span>4-8</p>
      <p><span class="yellow"></span>8-12</p>
      <p><span class="pink"></span>12-16</p>
      <p><span class="red"></span>16-20</p>
      <p><span class="reds"></span> >20</p>
    </div>
    <div :class="['mapLegendColor', ifExpand ? 'leftZk' : 'leftSq']" v-if="moduleTypeEnum == 'duration-filling'">
      <p class="title">管网充满度</p>
      <p><span class="green"></span>未充满</p>
      <p><span class="red"></span>满管</p>
    </div>
  </div>
</template>

<script setup name="riskEstimate">
import RiskGisMap from './riskGisMap.vue';
import { schemeList, moduleGeometryData } from '@/api/floodSys/floodYP';
import RiskRCont from './riskAssesRight.vue';
import xiaoganCityBoundary from '@/assets/geojson/xiaoganCityBoundary.json';
import TimeLine from '@/components/Map/TimeLine.vue';
const { proxy } = getCurrentInstance();
const ifExpand = ref(true);
const allData = reactive({
  queryParams: {
    scenario: '',
    duration: '',
  },
});
const { queryParams } = toRefs(allData);
const moduleTypeEnum = ref('duration-depth');
const schemeData = ref([]);
const caseId = ref(1);
const paramsCase = ref({}); //右侧传递参数
const { drains_scenario, drains_rainfall_duration } = proxy.useDict('drains_scenario', 'drains_rainfall_duration'); //获取接口返回字典数据
const timelineList = ref([]);
const caseType = ref([
  { value: 'duration-depth', label: '积水动态预演' },
  { value: 'max-depth', label: '最大积水范围' },
  { value: 'duration-filling', label: '充满度动态预演' },
  { value: 'max-filling', label: '最大满管风险' },
]);
const bsType = ref([
  { value: '1', label: '1倍' },
  { value: '2', label: '2倍' },
]);
const searchValSpeed = ref('1');
const features = ref([]);
const featureStep = ref(0);
//内涝风险评估 地图内涝
const gisJsonData = ref({});
const gisParams = ref({
  rainFall: '',
  ybTime: '',
  category: 'duration',
  type: 'depth',
  realTime: false,
});
const isdisabled = ref(false);
//根据步长更换颜色
const changeFeatureColor = step => {
  features.value.forEach(feature => {
    let lineColor = feature.extData[step] < 1 ? '#47E44E' : '#DD3737';
    feature.setColor(lineColor);
  });
};
const getTimeLineIndex = index => {
  if (!(index % 100 == 0)) return;
  featureStep.value = index / 100;
  paramsCase.value.featureStep = featureStep.value;
  newfiberMapbox.map.ogcLayers.filter(i => i.newfiberId == 'newfiber-CanvasLayer')[0].next(980);
};
//内涝风险评估 地图内涝渲染模拟
const gisModuleData = () => {
  moduleGeometryData(gisParams.value).then(res => {
    stopImitate();
    gisJsonData.value = res.data.result;
    let maxPoint = res.data.maxPoint.split(',');
    let minPoint = res.data.minPoint.split(',');
    timelineList.value = gisJsonData.value.map((i, idx) => ({
      id: idx,
      name: `${(((idx + 1) * 5) / 60).toFixed(0).padStart(2, 0)}:${((((idx + 1) * 5) % 60) + '').padStart(2, 0)}`,
    }));
    newfiberMapbox.map.ogcLayers
      .filter(i => i.newfiberId == 'newfiber-CanvasLayer')[0]
      .setInitializeParams({
        images: gisJsonData.value.map(i => i.url).reverse(),
        bbox: [...minPoint, ...maxPoint].map(Number).filter(Boolean),
        width: 8360,
        height: 5000,
      });
    if (!!gisJsonData.value.length && gisJsonData.value.length > 1) {
      isdisabled.value = false;
      !!newfiberMapbox.map.getLayer('riskAssesImage') && newfiberMapbox.map.removeLayer('riskAssesImage');
      !!newfiberMapbox.map.getSource('riskAssesImage') && newfiberMapbox.map.removeSource('riskAssesImage');
      addImageLayer(minPoint, maxPoint);
    } else {
      isdisabled.value = true;
      !!newfiberMapbox.map.getLayer('riskAssesImage') && newfiberMapbox.map.removeLayer('riskAssesImage');
      !!newfiberMapbox.map.getSource('riskAssesImage') && newfiberMapbox.map.removeSource('riskAssesImage');
    }
  });
};
//添加模型图
const addImageLayer = (minPoint, maxPoint) => {
  let coordinates;

  newfiberMapbox.map.addSource('riskAssesImage', {
    type: 'image',
    url: gisJsonData.value[gisJsonData.value.length - 1].url,
    coordinates: [
      [Number(minPoint[0]), Number(maxPoint[1])],
      [Number(maxPoint[0]), Number(maxPoint[1])],
      [Number(maxPoint[0]), Number(minPoint[1])],
      [Number(minPoint[0]), Number(minPoint[1])],
    ],
  });
  newfiberMapbox.map.addLayer({
    id: 'riskAssesImage',
    type: 'raster',
    source: 'riskAssesImage',
    paint: {
      'raster-fade-duration': 0,
    },
  });
};
// 获取积水方案列表
function getZSList() {
  schemeList(queryParams.value).then(res => {
    let datas = res.data;
    schemeData.value = datas;
    caseId.value = datas[0].fid;
    changeCase(caseId.value); //默认选中第一个
    paramsCase.value.depthArea = datas[0].depthArea;
    paramsCase.value.fillingLength = datas[0].fillingLength;
    paramsCase.value.rainfall = datas[0].rainfall;
    paramsCase.value.pipelineFillingLength = datas[0].pipelineFillingLength;
  });
}
// 方案列表点击
function changeCase(val) {
  caseId.value = val;
  let arr = schemeData.value.filter(item => item.fid == val);
  paramsCase.value.hours = arr[0].duration;
  paramsCase.value.scenario = arr[0].scenario;
  paramsCase.value.depthArea = arr[0].depthArea;
  paramsCase.value.fillingLength = arr[0].fillingLength;
  paramsCase.value.rainfall = arr[0].rainfall;
  paramsCase.value.pipelineFillingLength = arr[0].pipelineFillingLength;
  paramsCase.value.fid = caseId.value;
  paramsCase.value.moduleTypeEnum = moduleTypeEnum.value; //模型类型
  gisParams.value.scenario = paramsCase.value.scenario;
  gisParams.value.hours = paramsCase.value.hours;
  gisModuleData();
  // 模型数据加载
  stopTimer();
  processVal.value = 0;
  featureStep.value = 0;
  //startImitate();
}
// 不同模拟方案选择
function changeObject(val) {
  allData.queryParams.scenario = '';
  allData.queryParams.duration = '';
  if (val == 'duration-depth') {
    gisParams.value.category = 'duration';
    gisParams.value.type = 'depth';
    gisParams.value.realTime = false;
  } else if (val == 'max-depth') {
    gisParams.value.category = 'duration';
    gisParams.value.type = 'depth';
    gisParams.value.realTime = false;
  } else if (val == 'duration-filling') {
    gisParams.value.category = 'duration';
    gisParams.value.type = 'filling';
    gisParams.value.realTime = false;
  } else {
    gisParams.value.category = 'duration';
    gisParams.value.type = 'filling';
    gisParams.value.realTime = false;
  }
  moduleTypeEnum.value = val;
  paramsCase.value.moduleTypeEnum = val;
  // 模型数据加载
  processVal.value = 0;
}
const timer = ref(null);
const ifStart = ref(true);
const processVal = ref(0);

// 倍数切换
function changeBS() {
  stopTimer();
  startTimer(); // 定时器开启
}

// 开始模拟
function startImitate() {
  ifStart.value = false;
  startTimer(); // 定时器开启
}
// 开启定时器
function startTimer() {
  if (processVal.value == 100) processVal.value = 0;
  if (gisJsonData.value.length < 1) {
    return;
  }
  if (gisJsonData.value.length > 1) {
    let proStept = Math.round(100 / gisJsonData.value.length);
    timer.value = setInterval(() => {
      featureStep.value += 1;
      newfiberMapbox.map
        .getSource('riskAssesImage')
        .updateImage({ url: gisJsonData.value[gisJsonData.value.length - 1 - featureStep.value].url });

      processVal.value += proStept;
      // 子组件echarts动画添加
      paramsCase.value.featureStep = featureStep.value;

      let setp_play = `step${featureStep.value}`;
      if (processVal.value > 100) {
        processVal.value = 100;
        stopImitate();
        return;
      }
      if (featureStep.value == gisJsonData.value.length - 1) {
        featureStep.value = 0;
        processVal.value = 100;
        stopImitate();
      }
      changeFeatureColor(setp_play);
    }, 1000 / searchValSpeed.value);
  } else {
    timer.value = setInterval(() => {
      processVal.value += 100;
      if (processVal.value > 100) {
        processVal.value = 0;
        stopImitate();
      }
    }, 1000);
  }
}
const mapInit = () => {
  getZSList();
  addCityBoundary();
  newfiberMapbox.map.moveLayer('xiaoganWater', 'xiaoganCityBoundary');
};
// 暂停模拟
function stopImitate() {
  ifStart.value = true;
  stopTimer();
}
// 定时器清除
function stopTimer() {
  if (timer.value) {
    clearInterval(timer.value);
  }
}
//添加孝感城区边界
const addCityBoundary = () => {
  !newfiberMapbox.map.getSource('xiaoganCityBoundary') &&
    newfiberMapbox.map.addSource('xiaoganCityBoundary', { type: 'geojson', data: xiaoganCityBoundary });
  !newfiberMapbox.map.getLayer('xiaoganCityBoundary') &&
    !newfiberMapbox.map.addLayer({
      id: 'xiaoganCityBoundary',
      type: 'line',
      source: 'xiaoganCityBoundary',
      paint: {
        'line-color': 'rgba(255, 175, 71,1)',
        'line-width': 3,
      },
    });
  // setTimeout(() => {
  //   newfiberMapbox.map.moveLayer('xiaoganWater', 'xiaoganCityBoundary');
  // }, 3000);
};
onMounted(() => {
  // timer.value = setInterval(() => {
  //   if (!!!newfiberMapbox) {
  //     return;
  //   } else {
  //     addCityBoundary();
  //     // getZSList();
  //     clearInterval(timer.value);
  //   }
  // }, 100);
});
onBeforeMount(() => {
  stopTimer();
});
</script>
<style lang="scss">
@import '@/assets/styles/variables.module.scss';
.riskEstimate {
  width: 100%;
  position: relative;
  .riskLeft {
    width: 240px;
    height: calc(100% - 60px);
    background: $mainColor1;
    position: absolute;
    top: 30px;
    left: 10px;
    padding: 10px;
    z-index: 90;
    .mapTitle {
      margin: 20px auto;
    }
    .progranme {
      border-top: 1px solid #5b9cd8;
      height: calc(100% - 180px);
      overflow: auto;
      padding-top: 10px;
      .part {
        color: #5b9cd8;
        cursor: pointer;
        margin-bottom: 20px;
        border-bottom: 1px dashed #c6c6c6;
        height: 60px;
        line-height: 60px;
        .el-radio {
          .cont {
            p {
              line-height: 25px;
            }
          }
        }
      }
    }
  }
  .centerWarnRK {
    background: $mainColor1;
    box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
    border-radius: 8px;
    position: absolute;
    top: 30px;
    left: 300px;
    z-index: 99;
    padding: 10px;
    display: flex;
    align-items: center;
    .el-select {
      width: 150px;
    }
    .el-progress {
      width: 500px;
      margin: 0px 15px;
      .el-progress__text span {
        font-size: 12px;
      }
    }
  }
  .riskRight {
    width: 400px;
    height: calc(100vh - 130px);
    background: $mainColor1;
    position: absolute;
    top: 30px;
    right: 30px;
    padding: 10px;
    z-index: 90;
  }
  .leftZk {
    right: 435px;
  }
  .leftSq {
    right: 20px;
  }
  .zksqImg {
    width: 16px;
    height: 147px;
    background: url('@/assets/newImgs/down.png');
    background-size: 100% 100%;
    transform: rotate(180deg);
    position: absolute;
    top: 340px;
    z-index: 99;
    cursor: pointer;
    transition: 0.5s ease-in-out;
  }
}
</style>