|
@@ -7,7 +7,7 @@
|
|
|
</div>
|
|
|
|
|
|
<div style="height: 1200px; overflow: auto">
|
|
|
- <div style="margin-left: 30px;">
|
|
|
+ <div style="margin-left: 30px">
|
|
|
<span>风流场</span>
|
|
|
<img :src="switchStatus ? switchOn : switchOff" style="margin-left: 30px; cursor: pointer;" @click="switchControl" />
|
|
|
</div>
|
|
@@ -91,9 +91,9 @@
|
|
|
<div class="gradient-text">空间分析</div>
|
|
|
</div>
|
|
|
<div class="btn-box">
|
|
|
- <div class="btn" @click="handleShowMore">
|
|
|
+ <div class="btn" @click="handleToShowDrawTools">
|
|
|
<i class="more-icon"></i>
|
|
|
- <div class="btn-text">开启圈选</div>
|
|
|
+ <div class="btn-text">{{ !openSelect ? '开启圈选' : '结束圈选' }}</div>
|
|
|
</div>
|
|
|
<div class="btn" @click="exportData">
|
|
|
<i class="export-icon"></i>
|
|
@@ -153,52 +153,52 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="data-box2">
|
|
|
- <div class="data-item">
|
|
|
- <div class="icon1"></div>
|
|
|
- <div class="item-right">
|
|
|
- <div class="text-box">
|
|
|
- <div class="text1">行政镇</div>
|
|
|
- <div class="text2">(个)</div>
|
|
|
- </div>
|
|
|
- <div class="text3">{{ analyzeData.town_num }}</div>
|
|
|
- </div>
|
|
|
+ <div class="analyze-data-container">
|
|
|
+ <div class="item" @click="handleShowDetail">
|
|
|
+ <div class="item-label">行政镇(个)</div>
|
|
|
+ <div class="item-value">{{ validateNum(analysisData.townCount) }}</div>
|
|
|
</div>
|
|
|
- <div class="data-item">
|
|
|
- <div class="icon2"></div>
|
|
|
- <div class="item-right">
|
|
|
- <div class="text-box">
|
|
|
- <div class="text1">人口</div>
|
|
|
- <div class="text2">(万)</div>
|
|
|
- </div>
|
|
|
- <div class="text4">{{ analyzeData.populationSize }}</div>
|
|
|
- </div>
|
|
|
+ <div class="item" @click="handleShowDetail">
|
|
|
+ <div class="item-label">行政村(个)</div>
|
|
|
+ <div class="item-value">{{ validateNum(analysisData.villageCount) }}</div>
|
|
|
</div>
|
|
|
- <div class="data-item">
|
|
|
- <div class="icon3"></div>
|
|
|
- <div class="item-right">
|
|
|
- <div class="text-box">
|
|
|
- <div class="text1">面积</div>
|
|
|
- <div class="text2">(km²)</div>
|
|
|
- </div>
|
|
|
- <div class="text5">{{ analyzeData.areaSize }}</div>
|
|
|
- </div>
|
|
|
+ <div class="item" @click="handleShowDetail">
|
|
|
+ <div class="item-label">面积(km²)</div>
|
|
|
+ <div class="item-value">{{ validateNum(analysisData.areaSize) }}</div>
|
|
|
</div>
|
|
|
- <div class="data-item">
|
|
|
- <div class="icon4"></div>
|
|
|
- <div class="item-right">
|
|
|
- <div class="text-box">
|
|
|
- <div class="text1">GDP</div>
|
|
|
- <div class="text2">(亿)</div>
|
|
|
- </div>
|
|
|
- <div class="text6">{{ analyzeData.GDP }}</div>
|
|
|
- </div>
|
|
|
+ <div class="item" @click="handleShowDetail">
|
|
|
+ <div class="item-label">常住人口(万)</div>
|
|
|
+ <div class="item-value">{{ validateNum(analysisData.populationSize) }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="item" @click="handleShowDetail">
|
|
|
+ <div class="item-label">GDP(万元)</div>
|
|
|
+ <div class="item-value">{{ validateNum(analysisData.GDP) }}</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<WindSpeedRank v-if="showMore" v-model="showMore" />
|
|
|
+ <Dialog v-model="showDetail" title="空间分析" hide-footer>
|
|
|
+ <div class="common-table">
|
|
|
+ <div class="table-header">
|
|
|
+ <div class="td">序号</div>
|
|
|
+ <div class="td">行政镇</div>
|
|
|
+ <div class="td">行政村</div>
|
|
|
+ <div class="td">常住人口(万)</div>
|
|
|
+ <div class="td">面积(km2)</div>
|
|
|
+ <div class="td">GDP(亿元)</div>
|
|
|
+ </div>
|
|
|
+ <div v-for="(item, index) in analysisData.townData" :key="index" class="tr">
|
|
|
+ <div class="td">{{ index + 1 }}</div>
|
|
|
+ <div class="td">{{ item.townName }}</div>
|
|
|
+ <div class="td">{{ item.villageName ? item.villageName : '-' }}</div>
|
|
|
+ <div class="td">{{ item.populationSize }}</div>
|
|
|
+ <div class="td">{{ item.areaSize }}</div>
|
|
|
+ <div class="td">{{ item.GDP }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Dialog>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
@@ -208,7 +208,12 @@ import switchOn from '@/assets/images/map/rightMenu/windMonitor/switch-on.png';
|
|
|
import WindSpeedRank from '@/views/globalMap/RightMenu/WindMonitor/windSpeedRank.vue';
|
|
|
import { getRainfallTownNumCount } from '@/api/globalMap/rainMonitor';
|
|
|
import BigNumber from 'bignumber.js';
|
|
|
-import { debounce } from '@/utils';
|
|
|
+import { debounce, deepClone } from '@/utils';
|
|
|
+import useMapStore from '@/store/modules/map';
|
|
|
+import { nanoid } from 'nanoid';
|
|
|
+import { getSpatialAnalysis } from '@/api/globalMap';
|
|
|
+import { validateNum } from '@/utils/ruoyi';
|
|
|
+import * as turf from '@turf/turf';
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
const { wind_time } = toRefs<any>(proxy?.useDict('wind_time'));
|
|
@@ -347,7 +352,6 @@ watch(endLeft, () => {
|
|
|
getRainRange();
|
|
|
});
|
|
|
const getNewRange = (index, value) => {
|
|
|
-
|
|
|
if (value >= 0 && value < 193) {
|
|
|
const data = new BigNumber(value).dividedBy(new BigNumber(49.4)).toFixed(1.6);
|
|
|
rainRange[index] = data;
|
|
@@ -399,10 +403,186 @@ const initData = () => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
+const getDrawTool = inject('getDrawTool');
|
|
|
+const getMap = inject('getMap');
|
|
|
+const getMapUtils = inject('getMapUtils');
|
|
|
+const mapStore = useMapStore();
|
|
|
+let map, mapUtils, overlay;
|
|
|
+let showDetail = ref(false);
|
|
|
+const handleShowDetail = () => {
|
|
|
+ showDetail.value = true;
|
|
|
+};
|
|
|
+watch(
|
|
|
+ () => mapStore.mapLoaded,
|
|
|
+ (loaded) => {
|
|
|
+ if (loaded) {
|
|
|
+ map = getMap();
|
|
|
+ mapUtils = getMapUtils();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ immediate: true
|
|
|
+ }
|
|
|
+);
|
|
|
+let openSelect = ref(false);
|
|
|
+const drawOptions = {
|
|
|
+ color: '#f80102',
|
|
|
+ drawType: '1',
|
|
|
+ graphicsType: 'circle'
|
|
|
+};
|
|
|
+let analysisData = ref({
|
|
|
+ townCount: '',
|
|
|
+ villageCount: '',
|
|
|
+ areaSize: '',
|
|
|
+ populationSize: '',
|
|
|
+ GDP: '',
|
|
|
+ townData: [],
|
|
|
+ list: []
|
|
|
+});
|
|
|
+let locationData = ref([]);
|
|
|
+// 开始圈选
|
|
|
+const handleToShowDrawTools = () => {
|
|
|
+ openSelect.value = !openSelect.value;
|
|
|
+ const drawTool = getDrawTool();
|
|
|
+ if (openSelect.value) {
|
|
|
+ removeOverlays();
|
|
|
+ analysisData.value = {
|
|
|
+ townCount: '',
|
|
|
+ villageCount: '',
|
|
|
+ areaSize: '',
|
|
|
+ populationSize: '',
|
|
|
+ GDP: '',
|
|
|
+ townData: [],
|
|
|
+ list: []
|
|
|
+ };
|
|
|
+ drawTool.drawGraphics2(drawOptions);
|
|
|
+ if (mapStore.isAMap) {
|
|
|
+ drawTool.getMouseTool().on('draw', onDraw);
|
|
|
+ } else {
|
|
|
+ drawTool.getMouseTool().on('drawend', onDraw2);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ drawTool.closeDraw();
|
|
|
+ }
|
|
|
+};
|
|
|
+// 高德地图绘制结束
|
|
|
+const onDraw = (event) => {
|
|
|
+ const obj = event.obj;
|
|
|
+ const id = nanoid();
|
|
|
+ obj._opts.extData = {
|
|
|
+ id: id
|
|
|
+ };
|
|
|
+ const data: any = {
|
|
|
+ id: id,
|
|
|
+ type: drawOptions.graphicsType,
|
|
|
+ color: obj._opts.strokeColor,
|
|
|
+ drawType: obj._opts.fillOpacity === 0 ? '1' : '2'
|
|
|
+ };
|
|
|
+ if (data.type === 'circle') {
|
|
|
+ data.center = [obj.getCenter().lng, obj.getCenter().lat];
|
|
|
+ data.radius = obj.getRadius();
|
|
|
+ }
|
|
|
+ const path = obj.getPath();
|
|
|
+ // 将AMap.LngLat对象数组转换为经纬度数组
|
|
|
+ const pathArr = path.map((lngLat) => {
|
|
|
+ // 返回经度和纬度的数组
|
|
|
+ return [lngLat.lng, lngLat.lat];
|
|
|
+ });
|
|
|
+ data.path = pathArr;
|
|
|
+ overlay = obj;
|
|
|
+ analysisSpatial(data);
|
|
|
+};
|
|
|
+// 粤政图绘制结束
|
|
|
+const onDraw2 = (event) => {
|
|
|
+ const feature = event.feature;
|
|
|
+ const geometry = feature.getGeometry();
|
|
|
+ const geometryType = geometry.getType();
|
|
|
+ const id = nanoid();
|
|
|
+ feature.set('id', id);
|
|
|
+ feature.set('dotType', 'analysisSpatial');
|
|
|
+ const data: any = {
|
|
|
+ id: id,
|
|
|
+ type: drawOptions.graphicsType,
|
|
|
+ color: drawOptions.color,
|
|
|
+ drawType: drawOptions.drawType
|
|
|
+ };
|
|
|
+ feature.set('extraData', data);
|
|
|
+ if (geometryType === 'Circle') {
|
|
|
+ data.center = geometry.getCenter();
|
|
|
+ data.radius = geometry.getRadius();
|
|
|
+ const data2 = turf.sector(data.center, data.radius, 0, 360);
|
|
|
+ const pathArr = data2.geometry.coordinates[0];
|
|
|
+ data.path = pathArr;
|
|
|
+ } else if (geometryType === 'Polygon') {
|
|
|
+ const coordinates = geometry.getCoordinates();
|
|
|
+ data.path = coordinates[0];
|
|
|
+ }
|
|
|
+ overlay = feature;
|
|
|
+ analysisSpatial(data);
|
|
|
+};
|
|
|
+// 空间分析数据
|
|
|
+const analysisSpatial = (data) => {
|
|
|
+ openSelect.value = false;
|
|
|
+ let location = [];
|
|
|
+ let itemLocation = [];
|
|
|
+ data.path.forEach((item) => {
|
|
|
+ itemLocation.push({
|
|
|
+ x: item[0],
|
|
|
+ y: item[1]
|
|
|
+ });
|
|
|
+ });
|
|
|
+ itemLocation.push(itemLocation[0]);
|
|
|
+ location.push(itemLocation);
|
|
|
+ locationData.value = location;
|
|
|
+ getSpatialAnalysis(locationData.value).then((res) => {
|
|
|
+ if (res.data && res.data.list) {
|
|
|
+ const list = [];
|
|
|
+ res.data.list.forEach((item) => {
|
|
|
+ if (item.num > 0) {
|
|
|
+ list.push(item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ res.data.list = list;
|
|
|
+ }
|
|
|
+ if (res.data && res.data.townData) {
|
|
|
+ const data = [];
|
|
|
+ res.data.townData.forEach((item) => {
|
|
|
+ data.push(item);
|
|
|
+ item.children.forEach((item2) => {
|
|
|
+ const obj = deepClone(item2);
|
|
|
+ obj.townName = item.townName;
|
|
|
+ data.push(obj);
|
|
|
+ });
|
|
|
+ delete item.children;
|
|
|
+ });
|
|
|
+ res.data.townData = data;
|
|
|
+ }
|
|
|
+ analysisData.value = res.data;
|
|
|
+ });
|
|
|
+};
|
|
|
+const removeOverlays = () => {
|
|
|
+ if (!overlay) return;
|
|
|
+ if (mapStore.isAMap) {
|
|
|
+ overlay.setMap(null);
|
|
|
+ } else {
|
|
|
+ mapUtils.getDrawVector().getSource().removeFeature(overlay);
|
|
|
+ }
|
|
|
+ overlay = null;
|
|
|
+};
|
|
|
//调用函数
|
|
|
onMounted(() => {
|
|
|
initData();
|
|
|
});
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ removeOverlays();
|
|
|
+ const drawTool = getDrawTool();
|
|
|
+ if (mapStore.isAMap) {
|
|
|
+ drawTool.getMouseTool().off('draw', onDraw);
|
|
|
+ } else {
|
|
|
+ drawTool.getMouseTool().un('drawend', onDraw2);
|
|
|
+ }
|
|
|
+ drawTool.closeDraw();
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
@@ -652,82 +832,34 @@ onMounted(() => {
|
|
|
.rank-other {
|
|
|
background: url('@/assets/images/map/rightMenu/rainMonitor/other.png') no-repeat;
|
|
|
}
|
|
|
-.data-box2 {
|
|
|
- width: 1492px;
|
|
|
- height: 200px;
|
|
|
- background: url('@/assets/images/map/rightMenu/rainMonitor/dataBox.png') no-repeat;
|
|
|
- background-size: 1492px 123px;
|
|
|
- background-position: bottom;
|
|
|
- margin-left: 28px;
|
|
|
+.analyze-data-container {
|
|
|
+ width: 100%;
|
|
|
+ font-size: 16px;
|
|
|
+ padding: 15px;
|
|
|
display: flex;
|
|
|
- padding: 0 70px;
|
|
|
- align-items: center;
|
|
|
- .data-item {
|
|
|
+ flex-wrap: wrap;
|
|
|
+ margin-top: 20px;
|
|
|
+ .item {
|
|
|
+ width: 342px;
|
|
|
+ height: 160px;
|
|
|
+ background: url('@/assets/images/map/rightMenu/ironTower/boxBg.png') no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ color: #fff;
|
|
|
display: flex;
|
|
|
- flex: 1;
|
|
|
- .item-right {
|
|
|
- margin-left: 20px;
|
|
|
- .text-box {
|
|
|
- display: flex;
|
|
|
- margin-bottom: 20px;
|
|
|
- .text1 {
|
|
|
- font-size: 32px;
|
|
|
- color: #ffffff;
|
|
|
- }
|
|
|
- .text2 {
|
|
|
- font-size: 32px;
|
|
|
- color: #a7ccdf;
|
|
|
- margin-left: 5px;
|
|
|
- }
|
|
|
- }
|
|
|
- .text3,
|
|
|
- .text4,
|
|
|
- .text5,
|
|
|
- .text6 {
|
|
|
- font-size: 38px;
|
|
|
- font-family: BEBAS-1;
|
|
|
- /* 设置字体透明 */
|
|
|
- color: transparent;
|
|
|
- /* 使用 -webkit-background-clip 属性将背景剪裁至文本形状 */
|
|
|
- -webkit-background-clip: text;
|
|
|
- /* 非Webkit内核浏览器需要使用标准前缀 */
|
|
|
- background-clip: text;
|
|
|
- /* 把当前元素设置为行内块,以便能够应用背景 */
|
|
|
- display: inline-block;
|
|
|
- }
|
|
|
- .text3 {
|
|
|
- background-image: linear-gradient(to bottom, #ffffff 25%, #e58400 100%);
|
|
|
- }
|
|
|
- .text4 {
|
|
|
- background-image: linear-gradient(to bottom, #ffffff 25%, #6fe695 100%);
|
|
|
- }
|
|
|
- .text5 {
|
|
|
- background-image: linear-gradient(to bottom, #ffffff 25%, #00fde8 100%);
|
|
|
- }
|
|
|
- .text6 {
|
|
|
- background-image: linear-gradient(to bottom, #ffffff 25%, #2b72d6 100%);
|
|
|
- }
|
|
|
- }
|
|
|
- .icon1,
|
|
|
- .icon2,
|
|
|
- .icon3,
|
|
|
- .icon4 {
|
|
|
- width: 152px;
|
|
|
- height: 138px;
|
|
|
- }
|
|
|
- .icon1 {
|
|
|
- width: 141px;
|
|
|
- height: 126px;
|
|
|
- background: url('@/assets/images/map/rightMenu/rainMonitor/icon1.png') no-repeat;
|
|
|
- }
|
|
|
- .icon2 {
|
|
|
- background: url('@/assets/images/map/rightMenu/rainMonitor/icon2.png') no-repeat;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 38px;
|
|
|
+ margin-right: 42px;
|
|
|
+ cursor: pointer;
|
|
|
+ &:nth-child(4) {
|
|
|
+ margin-right: 0;
|
|
|
}
|
|
|
- .icon3 {
|
|
|
- background: url('@/assets/images/map/rightMenu/rainMonitor/icon3.png') no-repeat;
|
|
|
+ &:nth-child(5) {
|
|
|
+ margin-top: 20px;
|
|
|
}
|
|
|
- .icon4 {
|
|
|
- background: url('@/assets/images/map/rightMenu/rainMonitor/icon4.png') no-repeat;
|
|
|
+ .item-label {
|
|
|
+ margin-bottom: 18px;
|
|
|
}
|
|
|
}
|
|
|
}
|