<template> <div class="publicContainer homeBuildMain"> <div class="homeLeft"> <div class="footer"> <gisMap2D :initJson="`/static/libs/mapbox/style/projectIndex.json`" @map-click="clickMap"></gisMap2D> <div class="projectLegendList"> <div v-for="item in legendList" :key="item.layername" class="legend_item"> <div class="part" @click="changeLegend(item)"> <img :src="getImageUrl(item.url, 'newImgs/layerIcon')" class="img" /> <p class="title">{{ item.name }}({{ item.projectCount }}个)</p> <el-checkbox v-model="item.isCheck" size="small" class="legbox"></el-checkbox> </div> </div> <el-select v-model="searchText" placeholder="请输入关键字搜索" style="width: 180px; margin-top: 3px" filterable @change="selectStation" > <el-option v-for="item in bsType" :key="item.projectName" :label="item.projectName" :value="item.projectName" /> </el-select> </div> <!-- 管控分区图例 --> <div class="arealegendList"> <el-radio-group v-model="selectedArea" @change="changeAreaLegend"> <el-radio :label="'GKFQ1'">管控分区一级</el-radio> <el-radio :label="'GKFQ2'">管控分区二级</el-radio> <el-radio :label="'GKFQ3'">管控分区三级</el-radio> </el-radio-group> </div> </div> <!-- 暂不做切换事件,初设需要 --> <div class="typeBtns"> <el-button type="warning">项目类型</el-button> <el-button type="primary">开工年份</el-button> <el-button type="primary">竣工年份</el-button> <el-button type="primary">任务类型</el-button> <el-button type="primary">库里库外项目</el-button> </div> </div> <div class="homeRight"> <div class="selectTitle"> <div class="name">项目数量统计</div> </div> <BarEchart :echartData="projectData" :yAxisName="'个'" :refresh="refresh" style="height: 200px"></BarEchart> <div class="selectTitle"> <div class="name">项目资金投入</div> <div class="flex"> <el-select v-model="projectMoney" filterable @change="changeProjectMoney" size="small" style="width: 150px"> <el-option label="投资总额" value="1"></el-option> <el-option label="海绵投资额" value="2"></el-option> </el-select> </div> </div> <div class="flex flex-justcontent-center"> 总投资:{{ statisticsData.homePageMoney.totalMoney }}万元,海绵总投资:{{ statisticsData.homePageMoney.spongeTotalMoney }}万元 </div> <PieChart v-if="isChart1" :echartData="moneyData" :title="''" :refresh="refresh2" style="height: 200px"></PieChart> <div class="selectTitle" style="margin-bottom: 10px"> <div class="name">项目过程管控</div> <div class="flex"> <el-select v-model="projectTypeGC" filterable size="small" @change="changeProjectType" style="width: 150px"> <el-option :label="`施工审批(${GCGKData.constructionPermit.length})`" value="1"></el-option> <el-option :label="`质量整改(${GCGKData.qualityReformRecord.length})`" value="2"></el-option> <el-option :label="`竣工审批(${GCGKData.completionAcceptance.length})`" value="3"></el-option> </el-select> </div> </div> <el-table :data="tableData" v-loading="tableLoading" stripe height="240" @row-click="clickPipeSupervise" highlight-current-row> <el-table-column label="项目名称" prop="projectName" /> <el-table-column label="提交时间" prop="createTime" width="165" /> </el-table> </div> <!-- 地图点击项目查看详细信息 --> <el-dialog v-model="showDialog" title="工程项目详情" :close-on-click-modal="false" @close="closeProjectInfo" width="1000px"> <detail v-if="showDialog" :cur-row="curRow" :types="projectTypes" :build-category="build_category" :project-library-type="project_library_type" :project-content-type="project_content_type" /> </el-dialog> </div> <!-- 基础信息弹窗 --> <div id="rasterPopupInfo" v-show="PopupShow"> <div class="title"> <div class="infoTitle">{{ rasterData.name }}</div> <div class="closePopup"> <el-icon :size="18" @click="closePopup"> <Close /> </el-icon> </div> </div> <div class="dividerLine"></div> <div class="infoContentPI" v-if="rasterData.code"> <div class="infoName">分区编码:</div> <div class="infoData">{{ rasterData.code }}</div> </div> <div class="infoContentPI"> <div class="infoName">分区面积:</div> <div class="infoData">{{ rasterData.area }}km²</div> </div> <div class="infoContentPI" v-if="rasterData.designrain"> <div class="infoName">设计降雨量:</div> <div class="infoData">{{ rasterData.designrain }}</div> </div> <div class="infoContentPI" v-if="rasterData.flow"> <div class="infoName">目标年径流总量控制率:</div> <div class="infoData">{{ rasterData.flow }}</div> </div> </div> </template> <script setup name="Index"> import { getImageUrl } from '@/utils/ruoyi'; import PieChart from '@/components/Echarts/pieChart.vue'; //饼图 import { useDicts } from '@/hooks'; import gisMap2D from '../../gisMapPage/gisMapBox1.vue'; import BarEchart from '@/components/Echarts/barChart.vue'; //柱状图 import detail from '@/views/project/projectInformation/details.vue'; //工程详细信息 import { getHomeStatistics, getHomePageInfoByType } from '@/api/project/home'; import { projectTypeList, getUndoProjectInfo } from '@/api/project/projectInformationNew'; import bus from '@/bus'; import axios from 'axios'; const showDialog = ref(false); const curRow = shallowRef({}); const projectTypeGC = ref('1'); const { proxy } = getCurrentInstance(); const { build_status } = proxy.useDict('build_status'); const { build_category, project_library_type, project_content_type } = useDicts(proxy); const searchText = ref(); const bsType = ref([]); const isChart = ref(false); const isChart1 = ref(false); const tableData = ref([]); const tableLoading = ref(false); const timer = ref(null); const timerProject = ref(null); const selectedArea = ref('GKFQ1'); const projectMoney = ref('1'); const projectTypes = ref([]); const selectedRaster = ref([]); const rasterData = ref({}); const PopupShow = ref(false); const projectData = ref({ xAxisData: [], seriesData: [ { type: 'bar', name: '项目数', barWidth: 10, data: [] }, { type: 'bar', name: '竣工数', barWidth: 10, data: [] }, { type: 'bar', name: '开工数', barWidth: 10, data: [] }, ], }); const refresh = ref(1); const refresh2 = ref(1); const moneyData = ref([ { name: '已开工项目完成投资', value: 2 }, { name: '已竣工项目完成投资', value: 2 }, { name: '计划总投资', value: 12 }, ]); const GCGKData = ref({ completionAcceptance: [], constructionPermit: [], qualityReformRecord: [], }); const statisticsData = reactive({ accumulativeTotal: {}, currentYear: {}, homePageMoney: {}, buildTypeStatistics: [], projectTypeStatistics: [], }); const legendList = ref([ { name: '海绵型建设与社区', layername: 'HMJZYSQ', url: 'orinigns.png', isCheck: false, }, { name: '海绵型道路广场', layername: 'HMXDLGC', url: 'DFHZ1.png', isCheck: false, }, { name: '海绵型公园与绿地', layername: 'HMXGYLD', url: 'yuanTous.png', isCheck: true, }, { name: '海绵型水系', layername: 'HMXSX', url: 'KDJZWMX s.png', isCheck: false, }, { name: '管网排查与修复', layername: 'GWPCYXF', url: 'paiKous.png', isCheck: false, }, { name: '雨水管网及泵站', layername: 'GWJBZ', url: 'paiLaoBengs.png', isCheck: false, }, { name: 'GIS平台建设与监测设施', layername: 'GIS', url: 'yiLaos.png', isCheck: false, }, ]); // 规划过程管控表格点击 function clickPipeSupervise(row) { curRow.value = row; showDialog.value = true; } // 地图标注点点击 const clickMap = (point, properties) => { curRow.value = properties; showDialog.value = true; }; // 加载数据 const getData = async () => { getGCGKData(); //规划管控 const res = await getHomeStatistics(); if (res?.code !== 200) return; const { currentYear, accumulativeTotal, projectTypeStatistics, buildTypeStatistics, homePageMoney } = res.data; statisticsData.currentYear = currentYear; statisticsData.accumulativeTotal = accumulativeTotal; statisticsData.homePageMoney = homePageMoney; statisticsData.buildTypeStatistics = buildTypeStatistics.map(item => ({ typeCount: item.typeCount, typeName: build_status.value.find(it => it.value === item.typeName)?.label || '', })); statisticsData.projectTypeStatistics = projectTypeStatistics; renderPie(statisticsData.projectTypeStatistics, 1); //项目数量统计 renderPie(statisticsData.buildTypeStatistics, 2); //项目资金投入 }; const renderPie = (data, type) => { let arrayX = [], arrayY = [], arrayJG = [], arrayKG = []; data.forEach(i => { arrayX.push(i.typeName); arrayY.push(i.typeCount); arrayJG.push(i.completedCount); arrayKG.push(i.openedCount); }); switch (type) { case 1: //项目数量统计 projectData.value.xAxisData = arrayX; projectData.value.seriesData[0].data = arrayY; //总数 projectData.value.seriesData[1].data = arrayJG; //竣工数 projectData.value.seriesData[2].data = arrayKG; //开工数 refresh.value = Math.random(); isChart.value = true; break; case 2: //项目资金投入 moneyData.value[0].value = statisticsData.homePageMoney.openedTotalMoney; //已开工 moneyData.value[1].value = statisticsData.homePageMoney.completedTotalMoney; //已竣工 moneyData.value[2].value = statisticsData.homePageMoney.totalMoney; //总投资 refresh2.value = Math.random(); isChart1.value = true; break; default: break; } }; // 资金切换选择 function changeProjectMoney(val) { if (val == '1') { // 投资总额 moneyData.value[0].value = statisticsData.homePageMoney.openedTotalMoney; moneyData.value[1].value = statisticsData.homePageMoney.completedTotalMoney; moneyData.value[2].value = statisticsData.homePageMoney.totalMoney; //总投资 refresh2.value = Math.random(); isChart1.value = true; } else { // 海绵投资额 moneyData.value[0].value = statisticsData.homePageMoney.openedSpongeTotalMoney; moneyData.value[1].value = statisticsData.homePageMoney.completedSpongeTotalMoney; moneyData.value[2].value = statisticsData.homePageMoney.spongeTotalMoney; //总投资 refresh2.value = Math.random(); isChart1.value = true; } } // 项目过程管控 async function getGCGKData() { tableLoading.value = true; let res = await getUndoProjectInfo(); if (res && res.code == 200) { GCGKData.value = res.data; tableData.value = GCGKData.value.constructionPermit; //默认施工审批 } tableLoading.value = false; } // 规划过程管控切换点击 function changeProjectType(val) { if (val == '1') { tableData.value = GCGKData.value.constructionPermit; } else if (val == '2') { tableData.value = GCGKData.value.qualityReformRecord; } else { tableData.value = GCGKData.value.completionAcceptance; } } //图例点击事件 const changeLegend = item => { item.isCheck = !item.isCheck; bus.emit('setLayerVisible', item); }; //选择站点触发事件 const selectStation = () => { let types = ['HMJZYSQ', 'HMXDLGC', 'HMXGYLD', 'HMXSX', 'GWPCYXF', 'GWJBZ', 'GIS']; let fy = ['HMJZYSQ_1', 'HMXDLGC_1', 'HMXGYLD_1', 'HMXSX_1', 'GWPCYXF_1', 'GWJBZ_1', 'GIS_1']; let selectedStation = bsType.value.filter(item => item.projectName == searchText.value)[0]; selectedStation.type = null; if (!!!selectedStation.projectLocation) { proxy.$modal.msgError('站点坐标缺失'); return; } let projectWKT = `POINT(${selectedStation.projectLocation.split(',').join(' ')})`; let selectedStationJson = turf.featureCollection([{ geometry: Terraformer.WKT.parse(projectWKT), properties: selectedStation }]); bus.emit('removeMapDatas', fy); let layerName = fy[types.indexOf(selectedStation.projectTypeCode)]; bus.emit('setGeoJSON', { json: selectedStationJson, key: layerName }); bus.emit('setLayerVisible', { layername: layerName, isCheck: true }); newfiberMapbox.map.easeTo({ center: [selectedStationJson.features[0].geometry.coordinates[0], selectedStationJson.features[0].geometry.coordinates[1]], zoom: 15, }); }; //关闭弹窗回调 const closeProjectInfo = () => { let clearSelectedFeature = []; newfiberMapbox.getLayers().forEach(feature => { if (feature.newfiberId == 'highlight_point') { clearSelectedFeature.push(feature); } }); if (!!clearSelectedFeature.length) { clearSelectedFeature[0].setData({ type: 'FeatureCollection', features: [] }); } }; // 图例渲染 const getHomePageInfoByTypes = async id => { let res = await getHomePageInfoByType(id); if (res?.code !== 200) return; let projectListMap = res?.data || {}; console.log('接口数据', projectListMap); let mapData = Object.values(projectListMap); bsType.value = mapData.flat(); let projectLegend = []; mapData.forEach(data => { let mapDataFeatures = []; data.forEach(item => { if (!!!item.projectLocation) return; let projectWKT = `POINT(${item.projectLocation.split(',').join(' ')})`; let feature = { geometry: Terraformer.WKT.parse(projectWKT), properties: item }; mapDataFeatures.push(feature); }); let mapDataGeojson = turf.featureCollection(mapDataFeatures); if (!mapDataGeojson.features.length) return; let legendDataList = { layername: mapDataGeojson.features[0].properties.projectTypeCode, data: mapDataGeojson, isCheck: true, projectCount: mapDataGeojson.features.length, }; projectLegend.push(legendDataList); }); legendList.value.forEach(item => { projectLegend.forEach(element => { if (item.layername == element.layername) { item.projectCount = element.projectCount; } }); }); console.log('legendList.value', projectLegend); bus.emit('setLegendData', projectLegend); timer.value = setInterval(() => { if (!!!newfiberMapbox.map.getLayer('point')) { return; } else { bus.emit('setLayerVisible', projectLegend[0]); clearInterval(timer.value); } }, 1000); }; const getProjectTypeList = async () => { const res = await projectTypeList({ status: '0' }); if (res?.code !== 200) return; projectTypes.value = res?.data || []; }; //管控分区图例选择 let gkfqList = ['GKFQ1', 'GKFQ2', 'GKFQ3']; const changeAreaLegend = value => { closePopup(); selectedArea.value = value; selectedRaster.value = gkfqList.filter(item => item == selectedArea.value); let unselectedRaster = gkfqList.filter(item => item != selectedArea.value); if (!!newfiberMapbox.map.getLayer('heighLightAreaLayer')) { newfiberMapbox.map.removeLayer('heighLightAreaLayer'); newfiberMapbox.map.removeSource('heighLightAreaLayer'); } unselectedRaster.forEach(item => { if (newfiberMapbox.map.getLayer(item)) { newfiberMapbox.map.removeLayer(item); newfiberMapbox.map.removeSource(item); } }); addGuanKongLayer(selectedArea.value); }; //添加管控分区三级 const addGuanKongLayer = layerName => { !!!newfiberMapbox.map.getSource(layerName) && newfiberMapbox.map.addSource(layerName, { type: 'raster', tiles: [ `/geoserver/xiaoganMapServer/wms?service=WMS&version=1.1.0&request=GetMap&layers=xiaoganMapServer:${layerName}&styles=&bbox={bbox-epsg-3857}&width=768&height=556&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE`, ], tileSize: 768, }); !!!newfiberMapbox.map.getLayer(layerName) && newfiberMapbox.map.addLayer({ id: layerName, type: 'raster', source: layerName, paint: { 'raster-opacity': 0.6, }, }); timerProject.value = setInterval(() => { if (!newfiberMapbox.map.getLayer('point')) { return; } else { newfiberMapbox.map.moveLayer(layerName, 'point'); clearInterval(timerProject.value); } }, 1000); }; //地图选中高亮 const mapSelectedHeighLight = geojson => { if (!!newfiberMapbox.map.getLayer('heighLightAreaLayer')) { newfiberMapbox.map.getSource('heighLightAreaLayer').setData(geojson); } else { newfiberMapbox.map.addSource('heighLightAreaLayer', { type: 'geojson', data: geojson }); newfiberMapbox.map.addLayer({ id: 'heighLightAreaLayer', source: 'heighLightAreaLayer', type: 'line', paint: { 'line-color': 'red', 'line-width': 8, }, }); } }; //管控分区点击事件 const rasterLayerClick = e => { if (!selectedRaster.value.length) { return; } const { lng, lat } = e.lngLat; const radius = Math.pow(2, 10); const pointM = turf.toMercator(turf.point([lng, lat])); const pointC = pointM.geometry.coordinates; const bbox = [pointC[0] - radius, pointC[1] - radius, pointC[0] + radius, pointC[1] + radius]; const url = `/geoserver/xiaoganMapServer/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&FORMAT=image%2Fpng&TRANSPARENT=true&QUERY_LAYERS=${selectedRaster.value[0]}&STYLES&LAYERS=${selectedRaster.value[0]}&exceptions=application%2Fvnd.ogc.se_inimage&INFO_FORMAT=application/json&FEATURE_COUNT=50&X=50&Y=50&SRS=EPSG%3A3857&WIDTH=101&HEIGHT=101&BBOX=` + bbox.join(); axios.get(url).then(function (res) { if (!!!res.data.features.length) { if (!!newfiberMapbox.map.getLayer('heighLightAreaLayer')) { newfiberMapbox.map.removeLayer('heighLightAreaLayer'); newfiberMapbox.map.removeSource('heighLightAreaLayer'); } closePopup(); return; } else { let selectedAreaJson = res.data; let heighLightArea = turf.toWgs84(selectedAreaJson.features[0].geometry); let poylgonToLine = { type: 'FeatureCollection', features: [ { type: 'Feature', geometry: { type: 'LineString', coordinates: heighLightArea.coordinates[0][0], }, }, ], }; rasterData.value = selectedAreaJson.features[0].properties; mapSelectedHeighLight(poylgonToLine); let layerCenter = turf.center(heighLightArea).geometry.coordinates; let rasterLayerPopupDiv = document.getElementById('rasterPopupInfo'); window.rasterLayerPopup = new mapboxL7.Popup({ html: rasterLayerPopupDiv, lngLat: { lng: layerCenter[0], lat: layerCenter[1], }, anchor: 'center', offsets: [0, 0], autoClose: false, }); newfiberMapbox.addPopup(rasterLayerPopup); PopupShow.value = true; } }); }; //关闭弹窗 const closePopup = () => { PopupShow.value = false; }; onMounted(() => { getData(); getProjectTypeList(); getHomePageInfoByTypes(1); setTimeout(() => { changeAreaLegend('GKFQ1'); newfiberMapbox.map.on('click', function (e) { rasterLayerClick(e); }); }, 3000); }); onBeforeUnmount(() => { if (timer.value) { clearInterval(timer.value); } if (timerProject.value) { clearInterval(timerProject.value); } !!newfiberMapbox.map.getLayer(selectedArea.value) && newfiberMapbox.map.removeLayer(selectedArea.value); !!newfiberMapbox.map.getSource(selectedArea.value) && newfiberMapbox.map.removeSource(selectedArea.value); }); </script> <style lang="scss"> @import '@/assets/styles/variables.module.scss'; .homeBuildMain { height: calc(100vh - 64px); width: 100%; overflow: hidden; padding: 10px; .homeLeft, .homeRight { height: 100%; } .homeLeft { width: 100%; } .homeRight { width: 22%; height: calc(100vh - 160px); background: #00314e; position: absolute; right: 10px; top: 70px; z-index: 122; } } .center { // justify-content: space-between; // margin: 10px 0px; height: 100%; // padding: 10px 0; > div { height: calc(33.33% - 7px); box-sizing: border-box; padding: 10px; // flex: 1; background: $mainColor1; position: relative; margin-bottom: 10px; &:last-of-type { margin-bottom: 0; } } } .typeBtns { position: absolute; width: 30%; left: 5%; bottom: 50px; z-index: 122; display: flex; justify-content: space-around; } .footer { position: relative; height: calc(100vh - 90px); .arealegendList { position: absolute; background: #00314e; border: 1px solid #094065; box-shadow: 0px 0px 14px 0px rgba(0, 0, 0, 0.68); opacity: 0.7; border-radius: 10px; position: absolute; bottom: 30px; right: 25%; z-index: 110; padding: 10px; .areaLegend_item { .part { display: flex; align-items: center; cursor: pointer; &:hover { background: #08596a; } .title { margin: 0px 5px 0px 5px; font-size: 14px; } .legbox { margin-right: 10px; } } } } .projectLegendList { background: #00314e; border: 1px solid #094065; box-shadow: 0px 0px 14px 0px rgba(0, 0, 0, 0.68); opacity: 0.7; border-radius: 10px; position: absolute; top: 10px; left: 5px; right: 10px; z-index: 110; height: 40px; overflow: auto; display: flex; justify-content: space-around; .legend_item { display: flex; align-items: center; .part { display: flex; align-items: center; cursor: pointer; &:hover { background: #08596a; } .img { width: 20px; height: 20px; margin: 0px 0px 0px 10px; } .title { margin: 0px 5px 0px 5px; font-size: 14px; } .legbox { margin-right: 15px; } } } } } #rasterPopupInfo { width: 350px; padding: 10px; background: rgba(0, 49, 78, 0.5); border: 1px solid #094065; z-index: 111; } .title { display: flex; .infoTitle { display: flex; align-items: center; height: 22px; font-size: 14px; font-family: PingFang SC; font-weight: 400; color: #ccf1ff; line-height: 22px; margin: 5px; width: 330px; &:before { display: block; content: ''; width: 3px; height: 16px; background: #00d1ff; margin-right: 10px; } } .closePopup { margin-right: 20px; height: 22px; cursor: pointer; } } .infoContentPI { display: flex; height: 20px; font-size: 14px; font-weight: 400; line-height: 20px; color: #00d1ff; .infoName { width: 200px; margin: 3px; } .infoData { width: 40px; margin: 3px; } } .l7-popup-tip { display: none; } .l7-popup .l7-popup-content { padding: 0px; background: #033b4f; } .l7-popup .l7-popup-content .l7-popup-close-button { display: none; } .l7-popup .l7-popup-content .l7-popup-content__title { align-items: center; height: 22px; font-size: 16px; font-family: PingFang SC; font-weight: 400; color: #ccf1ff; line-height: 22px; } </style>