<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>