Newer
Older
KaiFengPC / src / views / floodSys / floodYP / riskAsses.vue
@zhangdeliang zhangdeliang on 22 Jun 14 KB update
  1. <template>
  2. <!-- 排水防涝 态势研判 内涝风险评估 -->
  3. <div class="publicContainer riskEstimate">
  4. <!-- gis 地图 -->
  5. <RiskGisMap @loadCallback="mapInit"></RiskGisMap>
  6. <!-- 左侧分析方案 -->
  7. <div class="riskLeft animate__animated animate__bounceInLeft">
  8. <div class="mapTitle">模拟工况</div>
  9. <el-form label-width="90px">
  10. <el-form-item label="降雨重现期" prop="scenario">
  11. <el-select v-model="queryParams.scenario" placeholder="请选择" clearable @change="getZSList">
  12. <el-option v-for="item in drains_scenario" :key="item.value" :label="item.label" :value="item.value" />
  13. </el-select>
  14. </el-form-item>
  15. <el-form-item label="降雨时长" prop="duration">
  16. <el-select v-model="queryParams.duration" placeholder="请选择" clearable @change="getZSList">
  17. <el-option v-for="item in drains_rainfall_duration" :key="item.value" :label="item.label" :value="item.value" />
  18. </el-select>
  19. </el-form-item>
  20. </el-form>
  21. <!-- 方案名称 -->
  22. <div class="progranme">
  23. <el-radio-group v-model="caseId" @change="changeCase" style="justify-content: center">
  24. <div class="part" v-for="item in schemeData" :key="item.fid">
  25. <el-radio :label="item.fid">
  26. <div class="cont">
  27. <p class="ellipsis">{{ item.schemeName }}</p>
  28. <p>总降雨量:{{ item.rainfall }}mm</p>
  29. </div>
  30. </el-radio>
  31. </div>
  32. </el-radio-group>
  33. </div>
  34. </div>
  35. <!-- 中间操作 -->
  36. <div class="centerWarnRK flex">
  37. <el-select v-model="moduleTypeEnum" placeholder="请选择模拟对象" @change="changeObject">
  38. <el-option v-for="item in caseType" :key="item.value" :label="item.label" :value="item.value" />
  39. </el-select>
  40. <el-progress :stroke-width="20" :percentage="processVal" status="success" :text-inside="true"></el-progress>
  41. <el-button type="warning" @click="startImitate" v-if="ifStart" :disabled="isdisabled">开始</el-button>
  42. <el-button type="warning" @click="stopImitate" v-else :disabled="isdisabled">暂停</el-button>
  43. </div>
  44. <!-- 右侧具体数据展示 -->
  45. <div :class="['zksqImg', ifExpand ? 'leftZk' : 'leftSq']" @click="ifExpand = !ifExpand" title="展开收起"></div>
  46. <div :class="['riskRight', 'animate__animated', ifExpand ? 'animate__bounceInRight' : 'animate__bounceOutRight']">
  47. <RiskRCont :paramsCase="paramsCase"></RiskRCont>
  48. </div>
  49. <!-- 图例颜色,不同模型不同图例内容 -->
  50. <div
  51. :class="['mapLegendColor', ifExpand ? 'leftZk' : 'leftSq']"
  52. v-if="moduleTypeEnum == 'duration-depth' || moduleTypeEnum == 'max-depth'"
  53. >
  54. <p class="title">最大积水深度(米)</p>
  55. <p><span class="info"></span> 0.05-0.15</p>
  56. <p><span class="primary"></span> 0.15-0.3</p>
  57. <p><span class="yellow"></span> 0.3-0.5</p>
  58. <p><span class="pink"></span> 0.5-1.0</p>
  59. <p><span class="red"></span> 大于1.0</p>
  60. </div>
  61. <div :class="['mapLegendColor', ifExpand ? 'leftZk' : 'leftSq']" v-if="moduleTypeEnum == 'max-filling'">
  62. <!-- <p class="title" v-if="moduleTypeEnum == 'max-depth'">积水时长(小时)</p> -->
  63. <p class="title" v-if="moduleTypeEnum == 'max-filling'">满管时长(小时)</p>
  64. <p><span class="info"></span>0-4</p>
  65. <p><span class="primary"></span>4-8</p>
  66. <p><span class="yellow"></span>8-12</p>
  67. <p><span class="pink"></span>12-16</p>
  68. <p><span class="red"></span>16-20</p>
  69. <p><span class="reds"></span> >20</p>
  70. </div>
  71. <div :class="['mapLegendColor', ifExpand ? 'leftZk' : 'leftSq']" v-if="moduleTypeEnum == 'duration-filling'">
  72. <p class="title">管网充满度</p>
  73. <p><span class="green"></span>未充满</p>
  74. <p><span class="red"></span>满管</p>
  75. </div>
  76. </div>
  77. </template>
  78.  
  79. <script setup name="riskEstimate">
  80. import RiskGisMap from './riskGisMap.vue';
  81. import { schemeList, moduleGeometryData } from '@/api/floodSys/floodYP';
  82. import RiskRCont from './riskAssesRight.vue';
  83. import xiaoganCityBoundary from '@/assets/geojson/xiaoganCityBoundary.json';
  84. const { proxy } = getCurrentInstance();
  85. const ifExpand = ref(true);
  86. const allData = reactive({
  87. queryParams: {
  88. scenario: '',
  89. duration: '',
  90. },
  91. });
  92. const { queryParams } = toRefs(allData);
  93. const moduleTypeEnum = ref('duration-depth');
  94. const schemeData = ref([]);
  95. const caseId = ref(1);
  96. const paramsCase = ref({}); //右侧传递参数
  97. const { drains_scenario, drains_rainfall_duration } = proxy.useDict('drains_scenario', 'drains_rainfall_duration'); //获取接口返回字典数据
  98. const timelineList = ref([]);
  99. const caseType = ref([
  100. { value: 'duration-depth', label: '积水动态预演' },
  101. { value: 'max-depth', label: '最大积水范围' },
  102. { value: 'duration-filling', label: '充满度动态预演' },
  103. { value: 'max-filling', label: '最大满管风险' },
  104. ]);
  105.  
  106. const searchValSpeed = ref('1');
  107. const features = ref([]);
  108. const featureStep = ref(0);
  109. //内涝风险评估 地图内涝
  110. const gisJsonData = ref({});
  111. const gisParams = ref({
  112. rainFall: '',
  113. ybTime: '',
  114. category: 'duration',
  115. type: 'depth',
  116. realTime: false,
  117. });
  118. const isdisabled = ref(false);
  119. //根据步长更换颜色
  120. const changeFeatureColor = step => {
  121. features.value.forEach(feature => {
  122. let lineColor = feature.extData[step] < 1 ? '#47E44E' : '#DD3737';
  123. feature.setColor(lineColor);
  124. });
  125. };
  126. const getTimeLineIndex = index => {
  127. if (!(index % 100 == 0)) return;
  128. featureStep.value = index / 100;
  129. paramsCase.value.featureStep = featureStep.value;
  130. newfiberMapbox.map.ogcLayers.filter(i => i.newfiberId == 'newfiber-CanvasLayer')[0].next(980);
  131. };
  132. //内涝风险评估 地图内涝渲染模拟
  133. const gisModuleData = () => {
  134. moduleGeometryData(gisParams.value).then(res => {
  135. stopImitate();
  136. console.log('12------', res.data);
  137. gisJsonData.value = res.data.result;
  138. let maxPoint = res.data.maxPoint.split(',');
  139. let minPoint = res.data.minPoint.split(',');
  140. timelineList.value = gisJsonData.value.map((i, idx) => ({
  141. id: idx,
  142. name: `${(((idx + 1) * 5) / 60).toFixed(0).padStart(2, 0)}:${((((idx + 1) * 5) % 60) + '').padStart(2, 0)}`,
  143. }));
  144. newfiberMapbox.map.ogcLayers
  145. .filter(i => i.newfiberId == 'newfiber-CanvasLayer')[0]
  146. .setInitializeParams({
  147. images: gisJsonData.value.map(i => i.url).reverse(),
  148. bbox: [...minPoint, ...maxPoint].map(Number).filter(Boolean),
  149. width: 8360,
  150. height: 5000,
  151. });
  152. if (!!gisJsonData.value.length && gisJsonData.value.length > 1) {
  153. isdisabled.value = false;
  154. !!newfiberMapbox.map.getLayer('riskAssesImage') && newfiberMapbox.map.removeLayer('riskAssesImage');
  155. !!newfiberMapbox.map.getSource('riskAssesImage') && newfiberMapbox.map.removeSource('riskAssesImage');
  156. addImageLayer(minPoint, maxPoint);
  157. } else {
  158. isdisabled.value = true;
  159. !!newfiberMapbox.map.getLayer('riskAssesImage') && newfiberMapbox.map.removeLayer('riskAssesImage');
  160. !!newfiberMapbox.map.getSource('riskAssesImage') && newfiberMapbox.map.removeSource('riskAssesImage');
  161. }
  162. });
  163. };
  164. //添加模型图
  165. const addImageLayer = (minPoint, maxPoint) => {
  166. let coordinates;
  167.  
  168. newfiberMapbox.map.addSource('riskAssesImage', {
  169. type: 'image',
  170. url: gisJsonData.value[gisJsonData.value.length - 1].url,
  171. coordinates: [
  172. [Number(minPoint[0]), Number(maxPoint[1])],
  173. [Number(maxPoint[0]), Number(maxPoint[1])],
  174. [Number(maxPoint[0]), Number(minPoint[1])],
  175. [Number(minPoint[0]), Number(minPoint[1])],
  176. ],
  177. });
  178. newfiberMapbox.map.addLayer({
  179. id: 'riskAssesImage',
  180. type: 'raster',
  181. source: 'riskAssesImage',
  182. paint: {
  183. 'raster-fade-duration': 0,
  184. },
  185. });
  186. };
  187. // 获取积水方案列表
  188. function getZSList() {
  189. schemeList(queryParams.value).then(res => {
  190. let datas = res.data;
  191. schemeData.value = datas;
  192. caseId.value = datas[0].fid;
  193. changeCase(caseId.value); //默认选中第一个
  194. paramsCase.value.depthArea = datas[0].depthArea;
  195. paramsCase.value.fillingLength = datas[0].fillingLength;
  196. paramsCase.value.rainfall = datas[0].rainfall;
  197. paramsCase.value.pipelineFillingLength = datas[0].pipelineFillingLength;
  198. });
  199. }
  200. // 方案列表点击
  201. function changeCase(val) {
  202. caseId.value = val;
  203. let arr = schemeData.value.filter(item => item.fid == val);
  204. paramsCase.value.hours = arr[0].duration;
  205. paramsCase.value.scenario = arr[0].scenario;
  206. paramsCase.value.depthArea = arr[0].depthArea;
  207. paramsCase.value.fillingLength = arr[0].fillingLength;
  208. paramsCase.value.rainfall = arr[0].rainfall;
  209. paramsCase.value.pipelineFillingLength = arr[0].pipelineFillingLength;
  210. paramsCase.value.fid = caseId.value;
  211. paramsCase.value.moduleTypeEnum = moduleTypeEnum.value; //模型类型
  212. gisParams.value.scenario = paramsCase.value.scenario;
  213. gisParams.value.hours = paramsCase.value.hours;
  214. gisModuleData();
  215. // 模型数据加载
  216. stopTimer();
  217. processVal.value = 0;
  218. featureStep.value = 0;
  219. //startImitate();
  220. }
  221. // 不同模拟方案选择
  222. function changeObject(val) {
  223. allData.queryParams.scenario = '';
  224. allData.queryParams.duration = '';
  225. if (val == 'duration-depth') {
  226. gisParams.value.category = 'duration';
  227. gisParams.value.type = 'depth';
  228. gisParams.value.realTime = false;
  229. } else if (val == 'max-depth') {
  230. gisParams.value.category = 'duration';
  231. gisParams.value.type = 'depth';
  232. gisParams.value.realTime = false;
  233. } else if (val == 'duration-filling') {
  234. gisParams.value.category = 'duration';
  235. gisParams.value.type = 'filling';
  236. gisParams.value.realTime = false;
  237. } else {
  238. gisParams.value.category = 'duration';
  239. gisParams.value.type = 'filling';
  240. gisParams.value.realTime = false;
  241. }
  242. moduleTypeEnum.value = val;
  243. paramsCase.value.moduleTypeEnum = val;
  244. // 模型数据加载
  245. processVal.value = 0;
  246. }
  247. const timer = ref(null);
  248. const ifStart = ref(true);
  249. const processVal = ref(0);
  250.  
  251. // 倍数切换
  252. function changeBS() {
  253. stopTimer();
  254. startTimer(); // 定时器开启
  255. }
  256.  
  257. // 开始模拟
  258. function startImitate() {
  259. ifStart.value = false;
  260. startTimer(); // 定时器开启
  261. }
  262. // 开启定时器
  263. function startTimer() {
  264. if (processVal.value == 100) processVal.value = 0;
  265. if (gisJsonData.value.length < 1) {
  266. return;
  267. }
  268. if (gisJsonData.value.length > 1) {
  269. let proStept = Math.round(100 / gisJsonData.value.length);
  270. timer.value = setInterval(() => {
  271. console.log('timer------');
  272. featureStep.value += 1;
  273. newfiberMapbox.map
  274. .getSource('riskAssesImage')
  275. .updateImage({ url: gisJsonData.value[gisJsonData.value.length - 1 - featureStep.value].url });
  276.  
  277. processVal.value += proStept;
  278. // 子组件echarts动画添加
  279. paramsCase.value.featureStep = featureStep.value;
  280.  
  281. let setp_play = `step${featureStep.value}`;
  282. if (processVal.value > 100) {
  283. processVal.value = 100;
  284. stopImitate();
  285. return;
  286. }
  287. if (featureStep.value == gisJsonData.value.length - 1) {
  288. featureStep.value = 0;
  289. processVal.value = 100;
  290. stopImitate();
  291. }
  292. changeFeatureColor(setp_play);
  293. }, 1000 / searchValSpeed.value);
  294. } else {
  295. timer.value = setInterval(() => {
  296. processVal.value += 100;
  297. if (processVal.value > 100) {
  298. processVal.value = 0;
  299. stopImitate();
  300. }
  301. }, 1000);
  302. }
  303. }
  304. const mapInit = () => {
  305. getZSList();
  306. // addCityBoundary();
  307. // newfiberMapbox.map.moveLayer('xiaoganWater', 'xiaoganCityBoundary');
  308. };
  309. // 暂停模拟
  310. function stopImitate() {
  311. ifStart.value = true;
  312. stopTimer();
  313. }
  314. // 定时器清除
  315. function stopTimer() {
  316. if (timer.value) {
  317. clearInterval(timer.value);
  318. }
  319. }
  320. //添加孝感城区边界
  321. const addCityBoundary = () => {
  322. !newfiberMapbox.map.getSource('xiaoganCityBoundary') &&
  323. newfiberMapbox.map.addSource('xiaoganCityBoundary', { type: 'geojson', data: xiaoganCityBoundary });
  324. !newfiberMapbox.map.getLayer('xiaoganCityBoundary') &&
  325. !newfiberMapbox.map.addLayer({
  326. id: 'xiaoganCityBoundary',
  327. type: 'line',
  328. source: 'xiaoganCityBoundary',
  329. paint: {
  330. 'line-color': 'rgba(255, 175, 71,1)',
  331. 'line-width': 3,
  332. },
  333. });
  334. // setTimeout(() => {
  335. // newfiberMapbox.map.moveLayer('xiaoganWater', 'xiaoganCityBoundary');
  336. // }, 3000);
  337. };
  338. onMounted(() => {
  339. // timer.value = setInterval(() => {
  340. // if (!!!newfiberMapbox) {
  341. // return;
  342. // } else {
  343. // addCityBoundary();
  344. // // getZSList();
  345. // clearInterval(timer.value);
  346. // }
  347. // }, 100);
  348. });
  349. onBeforeMount(() => {
  350. stopTimer();
  351. });
  352. </script>
  353. <style lang="scss">
  354. @import '@/assets/styles/variables.module.scss';
  355. .riskEstimate {
  356. width: 100%;
  357. position: relative;
  358. .riskLeft {
  359. width: 240px;
  360. height: calc(100% - 60px);
  361. background: $mainColor1;
  362. position: absolute;
  363. top: 30px;
  364. left: 10px;
  365. padding: 10px;
  366. z-index: 90;
  367. .mapTitle {
  368. margin: 20px auto;
  369. }
  370. .progranme {
  371. border-top: 1px solid #5b9cd8;
  372. height: calc(100% - 180px);
  373. overflow: auto;
  374. padding-top: 10px;
  375. .part {
  376. color: #5b9cd8;
  377. cursor: pointer;
  378. margin-bottom: 20px;
  379. border-bottom: 1px dashed #c6c6c6;
  380. height: 60px;
  381. line-height: 60px;
  382. .el-radio {
  383. .cont {
  384. p {
  385. line-height: 25px;
  386. }
  387. }
  388. }
  389. }
  390. }
  391. }
  392. .centerWarnRK {
  393. background: $mainColor1;
  394. box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
  395. border-radius: 8px;
  396. position: absolute;
  397. top: 30px;
  398. left: 300px;
  399. z-index: 99;
  400. padding: 10px;
  401. display: flex;
  402. align-items: center;
  403. .el-select {
  404. width: 150px;
  405. }
  406. .el-progress {
  407. width: 500px;
  408. margin: 0px 15px;
  409. .el-progress__text span {
  410. font-size: 12px;
  411. }
  412. }
  413. }
  414. .riskRight {
  415. width: 400px;
  416. height: calc(100vh - 130px);
  417. background: $mainColor1;
  418. position: absolute;
  419. top: 30px;
  420. right: 30px;
  421. padding: 10px;
  422. z-index: 90;
  423. }
  424. .leftZk {
  425. right: 435px;
  426. }
  427. .leftSq {
  428. right: 20px;
  429. }
  430. .zksqImg {
  431. width: 16px;
  432. height: 147px;
  433. background: url('@/assets/newImgs/down.png');
  434. background-size: 100% 100%;
  435. transform: rotate(180deg);
  436. position: absolute;
  437. top: 340px;
  438. z-index: 99;
  439. cursor: pointer;
  440. transition: 0.5s ease-in-out;
  441. }
  442. }
  443. </style>