|
@@ -0,0 +1,584 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div style="width:100%;height:500px; position: relative;">
|
|
|
|
|
+ <div v-if="!isLoaded" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #999; z-index: 10;">
|
|
|
|
|
+ 地图加载中...
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="map-container" id="mapContainer" ref="mapContainer" style="width:100%;height:100%;"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <Table
|
|
|
|
|
+ v-if="tableShow"
|
|
|
|
|
+ :tableData="tableData"
|
|
|
|
|
+ :columnModel="columnModel"
|
|
|
|
|
+ :searchText="tableSearchText"
|
|
|
|
|
+ :isview="tableShow"
|
|
|
|
|
+ :close="handleClose"
|
|
|
|
|
+ :total="total"
|
|
|
|
|
+ :pageSize="pageSize"
|
|
|
|
|
+ :page="page"
|
|
|
|
|
+ :handlePageChange="handlePageChange"
|
|
|
|
|
+ >
|
|
|
|
|
+ </Table>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup lang="ts">
|
|
|
|
|
+import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'
|
|
|
|
|
+import mapboxgl from 'mapbox-gl'
|
|
|
|
|
+import MapboxDraw from '@mapbox/mapbox-gl-draw'
|
|
|
|
|
+import CONFIG from '@/utils/config'
|
|
|
|
|
+import api from '@/api/common'
|
|
|
|
|
+import * as turf from '@turf/turf'
|
|
|
|
|
+import 'mapbox-gl/dist/mapbox-gl.css'
|
|
|
|
|
+import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
|
|
|
|
|
+// @ts-ignore Vue组件暂未生成类型声明文件
|
|
|
|
|
+import Table from '@/components/person/Table.vue'
|
|
|
|
|
+import wellknown from 'wellknown'
|
|
|
|
|
+
|
|
|
|
|
+const mapContainer = ref("mapContainer")
|
|
|
|
|
+let map: mapboxgl.Map | null = null
|
|
|
|
|
+let draw: MapboxDraw | null = null
|
|
|
|
|
+const isLoaded = ref(false)
|
|
|
|
|
+const popup = ref<mapboxgl.Popup | null>(null)
|
|
|
|
|
+const guid = ref<string>("")
|
|
|
|
|
+
|
|
|
|
|
+const COLUMNMODELARR = ref({"id":1742,"mid":1793,"name":"申勤员工"})
|
|
|
|
|
+//员工列表
|
|
|
|
|
+const tableData = ref<any>([]),
|
|
|
|
|
+ columnModel = ref<any>([]),
|
|
|
|
|
+ contentItem = ref<any>([]),
|
|
|
|
|
+ tableShow = ref<boolean>(false),
|
|
|
|
|
+ tableSearchText = ref<string>(""),
|
|
|
|
|
+ total = ref<number>(0),
|
|
|
|
|
+ pageSize = ref<number>(10),
|
|
|
|
|
+ page = ref<number>(0)
|
|
|
|
|
+
|
|
|
|
|
+const FILTER_PARAM = ref([
|
|
|
|
|
+ {"name":"项目名称","value":"c_xmmc"},
|
|
|
|
|
+ {"name":"项目地址","value":"c_xmdz"},
|
|
|
|
|
+ {"name":"省份","value":"c_sfzxs"},
|
|
|
|
|
+ {"name":"市辖区","value":"c_sq"},
|
|
|
|
|
+ {"name":"项目员工人数","value":"c_xmygrs"},
|
|
|
|
|
+ {"name":"管理区域","value":"c_glqynbkj"},
|
|
|
|
|
+ {"name":"汇总业态","value":"c_hzyt"},
|
|
|
|
|
+ {"name":"dms_id","value":"id"},
|
|
|
|
|
+ {"name":"标识","value":"c_guid"},
|
|
|
|
|
+ ])
|
|
|
|
|
+
|
|
|
|
|
+// 父组件传入回显面 geojson
|
|
|
|
|
+const props = defineProps<{
|
|
|
|
|
+ geoJson?: GeoJSON.Feature<GeoJSON.Polygon> | null
|
|
|
|
|
+}>()
|
|
|
|
|
+const emit = defineEmits<{
|
|
|
|
|
+ 'geoJson-change': [geo: GeoJSON.Feature<GeoJSON.Polygon> | null, area: number]
|
|
|
|
|
+}>()
|
|
|
|
|
+
|
|
|
|
|
+// 监听外部传入GeoJSON,自动回显
|
|
|
|
|
+watch(() => props.geoJson, (val) => {
|
|
|
|
|
+ if (!map || !draw) return
|
|
|
|
|
+ draw.deleteAll()
|
|
|
|
|
+ if (val) draw.set({ type: 'FeatureCollection', features: [val] })
|
|
|
|
|
+}, { immediate: true })
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ getModelById()
|
|
|
|
|
+ //弹窗打开后,延迟执行resize
|
|
|
|
|
+ nextTick(()=>{
|
|
|
|
|
+ initMap()
|
|
|
|
|
+ // 关键!通知map重新计算大小
|
|
|
|
|
+ setTimeout(()=>{
|
|
|
|
|
+ map!.resize()
|
|
|
|
|
+ },50)
|
|
|
|
|
+ })
|
|
|
|
|
+})
|
|
|
|
|
+onUnmounted(() => {
|
|
|
|
|
+ map!.remove()
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 初始化地图
|
|
|
|
|
+const initMap = () => {
|
|
|
|
|
+ mapboxgl.accessToken = CONFIG.MAPBOX_ACCESS_TOKEN
|
|
|
|
|
+ map = new mapboxgl.Map({
|
|
|
|
|
+ container: mapContainer.value!,
|
|
|
|
|
+ style: {
|
|
|
|
|
+ version: 8,
|
|
|
|
|
+ sources: {},
|
|
|
|
|
+ layers: [],
|
|
|
|
|
+ glyphs: "mapbox://fonts/mapbox/{fontstack}/{range}.pbf"
|
|
|
|
|
+ },
|
|
|
|
|
+ projection: 'equirectangular', // globe 球体投影 mercator 平面墨卡托投影 equirectangular WGS84平面投影
|
|
|
|
|
+ center: [121.082334, 31.147052],
|
|
|
|
|
+ zoom: 10,
|
|
|
|
|
+ minZoom: 9,
|
|
|
|
|
+ maxZoom: 18,
|
|
|
|
|
+ doubleClickZoom: false,
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ map.on('load', () => {
|
|
|
|
|
+ initBaseMap("zwb")
|
|
|
|
|
+ initDraw()
|
|
|
|
|
+ // 回显多边形
|
|
|
|
|
+ if (props.geoJson) {
|
|
|
|
|
+ draw!.set({ type: 'FeatureCollection', features: [props.geoJson] })
|
|
|
|
|
+ }
|
|
|
|
|
+ isLoaded.value = true
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 通用渲染函数:支持 Geometry / Feature / FeatureCollection
|
|
|
|
|
+function renderGeoJson(fet:any, styleConfig = {}) {
|
|
|
|
|
+ const geoData = wellknown.parse(fet.c_polygon.value) as any
|
|
|
|
|
+ geoData.properties = { ...fet }
|
|
|
|
|
+ delete geoData.properties.c_polygon
|
|
|
|
|
+ // 默认样式
|
|
|
|
|
+ const opt = Object.assign({
|
|
|
|
|
+ pointColor: '#ff4400',
|
|
|
|
|
+ pointSize: 8,
|
|
|
|
|
+ lineColor: '#0066ff',
|
|
|
|
|
+ lineWidth: 3,
|
|
|
|
|
+ fillColor: 'rgba(0,150,255,0.2)',
|
|
|
|
|
+ fillOutlineColor: '#0066ff'
|
|
|
|
|
+ }, styleConfig);
|
|
|
|
|
+ console.log(geoData)
|
|
|
|
|
+ // 处理输入,统一转为 FeatureCollection
|
|
|
|
|
+ let fc;
|
|
|
|
|
+ if (geoData?.type === 'FeatureCollection') {
|
|
|
|
|
+ fc = geoData;
|
|
|
|
|
+ } else if (geoData?.type === 'Feature') {
|
|
|
|
|
+ fc = { type: 'FeatureCollection', features: [geoData] };
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 传入的是纯Geometry
|
|
|
|
|
+ fc = { type: 'FeatureCollection', features: [{ type: 'Feature', geometry: geoData, properties: geoData.properties }] };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const sourceId = 'temp-source';
|
|
|
|
|
+ const layerPointId = 'temp-layer-point';
|
|
|
|
|
+ const layerLineId = 'temp-layer-line';
|
|
|
|
|
+ const layerFillId = 'temp-layer-fill';
|
|
|
|
|
+
|
|
|
|
|
+ // 移除旧图层和源(重复渲染时清理)
|
|
|
|
|
+ if (map!.getLayer(layerPointId)) map!.removeLayer(layerPointId);
|
|
|
|
|
+ if (map!.getLayer(layerLineId)) map!.removeLayer(layerLineId);
|
|
|
|
|
+ if (map!.getLayer(layerFillId)) map!.removeLayer(layerFillId);
|
|
|
|
|
+ if (map!.getSource(sourceId)) map!.removeSource(sourceId);
|
|
|
|
|
+
|
|
|
|
|
+ // 添加数据源
|
|
|
|
|
+ map!.addSource(sourceId, {
|
|
|
|
|
+ type: 'geojson',
|
|
|
|
|
+ data: fc
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 点图层
|
|
|
|
|
+ map!.addLayer({
|
|
|
|
|
+ id: layerPointId,
|
|
|
|
|
+ type: 'circle',
|
|
|
|
|
+ source: sourceId,
|
|
|
|
|
+ filter: ['in', ['geometry-type'], ['literal', ['Point','MultiPoint']]],
|
|
|
|
|
+ paint: {
|
|
|
|
|
+ 'circle-color': opt.pointColor,
|
|
|
|
|
+ 'circle-radius': opt.pointSize
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 线图层
|
|
|
|
|
+ map!.addLayer({
|
|
|
|
|
+ id: layerLineId,
|
|
|
|
|
+ type: 'line',
|
|
|
|
|
+ source: sourceId,
|
|
|
|
|
+ filter: ['in', ['geometry-type'], ['literal', ['LineString','MultiLineString']]],
|
|
|
|
|
+ paint: {
|
|
|
|
|
+ 'line-color': opt.lineColor,
|
|
|
|
|
+ 'line-width': opt.lineWidth
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 面图层
|
|
|
|
|
+ map!.addLayer({
|
|
|
|
|
+ id: layerFillId,
|
|
|
|
|
+ type: 'fill',
|
|
|
|
|
+ source: sourceId,
|
|
|
|
|
+ filter: ['in', ['geometry-type'], ['literal', ['Polygon','MultiPolygon']]],
|
|
|
|
|
+ paint: {
|
|
|
|
|
+ 'fill-color': opt.fillColor,
|
|
|
|
|
+ 'fill-outline-color': opt.fillOutlineColor
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 可选:自动缩放到图形范围
|
|
|
|
|
+ // const bounds = new mapboxgl.LngLatBounds();
|
|
|
|
|
+ // fc.features.forEach((f:any) => {
|
|
|
|
|
+ // if(f.geometry) bounds.extend(f.geometry.coordinates);
|
|
|
|
|
+ // });
|
|
|
|
|
+ // if(!bounds.isEmpty()){
|
|
|
|
|
+ // map!.fitBounds(bounds, { padding: 40 });
|
|
|
|
|
+ // }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const initBaseMap = (type:string) => {
|
|
|
|
|
+ let titleStyle = CONFIG.MAPBOX_TILES_NORMAL
|
|
|
|
|
+ if (type == "zwb") {
|
|
|
|
|
+ titleStyle = CONFIG.MAPBOX_TILES_NORMAL
|
|
|
|
|
+ } else if (type == "asb") {
|
|
|
|
|
+ titleStyle = CONFIG.MAPBOX_TILES_BLUE
|
|
|
|
|
+ } else if (type == "yxt") {
|
|
|
|
|
+ titleStyle = CONFIG.MAPBOX_TILES_YXT
|
|
|
|
|
+ }
|
|
|
|
|
+ if (map!.getSource('custom-tiles')) {
|
|
|
|
|
+ (map!.getSource('custom-tiles') as mapboxgl.RasterTileSource)?.setTiles([titleStyle])
|
|
|
|
|
+ } else {
|
|
|
|
|
+ map!.addSource('custom-tiles', {
|
|
|
|
|
+ 'type': 'raster',
|
|
|
|
|
+ 'tiles': [titleStyle],
|
|
|
|
|
+ 'tileSize': 512
|
|
|
|
|
+ })
|
|
|
|
|
+ map!.addLayer({
|
|
|
|
|
+ 'id': 'custom-tiles-layer',
|
|
|
|
|
+ 'type': 'raster',
|
|
|
|
|
+ 'source': 'custom-tiles',
|
|
|
|
|
+ 'source-layer': 'custom-tiles',
|
|
|
|
|
+ 'minzoom': 0,
|
|
|
|
|
+ 'maxzoom': 20
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ map!.on('click', mapClickValue);
|
|
|
|
|
+
|
|
|
|
|
+ map!.on('mouseenter', ['temp-layer-fill'], function () {
|
|
|
|
|
+ map!.getCanvas().style.cursor = 'pointer';
|
|
|
|
|
+ });
|
|
|
|
|
+ map!.on('mouseleave', ['temp-layer-fill'], function () {
|
|
|
|
|
+ map!.getCanvas().style.cursor = '';
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+const mapClickValue = (e:any) => {
|
|
|
|
|
+ // 关键:只查询 temp-layer-fill,过滤掉所有其他图层
|
|
|
|
|
+ const features = map!.queryRenderedFeatures(e.point, {
|
|
|
|
|
+ layers: ['temp-layer-fill'] // 只取这个图层
|
|
|
|
|
+ });
|
|
|
|
|
+ tableShow.value = false
|
|
|
|
|
+ if (!features.length) return;
|
|
|
|
|
+ // 现在最多只有 1 个要素 → 绝对不会乱
|
|
|
|
|
+ const feature = features[0];
|
|
|
|
|
+ // 深拷贝 Geometry:绝对避免引用错乱
|
|
|
|
|
+ const fet = {
|
|
|
|
|
+ type: "Feature",
|
|
|
|
|
+ geometry: JSON.parse(JSON.stringify(feature.geometry)),
|
|
|
|
|
+ properties: { ...feature.properties }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 以下弹窗(注意要使用 fet.properties)
|
|
|
|
|
+ console.log(fet.properties);
|
|
|
|
|
+ let str = "";
|
|
|
|
|
+ for (let item in fet.properties) {
|
|
|
|
|
+ if (FILTER_PARAM.value.map(ev => ev.value).includes(item)) {
|
|
|
|
|
+ if(item != "id"){
|
|
|
|
|
+ const matched = FILTER_PARAM.value.find((et: any) => et.value == item);
|
|
|
|
|
+ str += `<p style="margin:2px 0;">${matched?.name ?? ''}:${fet.properties[item] ?? ''}</p>`;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const popupContent = `
|
|
|
|
|
+ <div style="font-size:14px;line-height:1.6;padding:10px;">
|
|
|
|
|
+ <h4 style="margin:0 0 6px 0;color:#222;"><span>内容信息</span><span style="display: ${fet.properties.c_xmygrs>0 ? 'block' : 'none'};" class="more" id="popup-more-btn">员工信息>></span></h4>
|
|
|
|
|
+ ${str}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ `;
|
|
|
|
|
+
|
|
|
|
|
+ if (popup.value) popup.value.remove();
|
|
|
|
|
+ popup.value = new mapboxgl.Popup({
|
|
|
|
|
+ closeButton: true,
|
|
|
|
|
+ className: 'custom-popup',
|
|
|
|
|
+ maxWidth: '500px'
|
|
|
|
|
+ })
|
|
|
|
|
+ .setLngLat(e.lngLat)
|
|
|
|
|
+ .setHTML(popupContent)
|
|
|
|
|
+ .addTo(map!);
|
|
|
|
|
+
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ const moreBtn = document.getElementById('popup-more-btn');
|
|
|
|
|
+ if (moreBtn) {
|
|
|
|
|
+ moreBtn.addEventListener('click', () => {
|
|
|
|
|
+ tableSearchText.value = "";
|
|
|
|
|
+ guid.value = fet.properties.c_guid;
|
|
|
|
|
+ handleMoreClick(guid.value,"",0);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 0);
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 初始化绘制控件
|
|
|
|
|
+const initDraw = () => {
|
|
|
|
|
+ draw = new MapboxDraw({
|
|
|
|
|
+ displayControlsDefault: false,
|
|
|
|
|
+ controls: {
|
|
|
|
|
+ polygon: false,
|
|
|
|
|
+ trash: false
|
|
|
|
|
+ },
|
|
|
|
|
+ styles: [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'draw-polygon',
|
|
|
|
|
+ type: 'fill',
|
|
|
|
|
+ filter: ['all', ['==', '$type', 'Polygon']],
|
|
|
|
|
+ paint: {
|
|
|
|
|
+ 'fill-color': '#1677ff',
|
|
|
|
|
+ 'fill-opacity': 0.3
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'draw-polygon-outline',
|
|
|
|
|
+ type: 'line',
|
|
|
|
|
+ filter: ['all', ['==', '$type', 'Polygon']],
|
|
|
|
|
+ paint: {
|
|
|
|
|
+ 'line-color': '#1677ff',
|
|
|
|
|
+ 'line-width': 2
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'draw-active-points',
|
|
|
|
|
+ type: 'circle',
|
|
|
|
|
+ filter: ['all', ['==', '$type', 'Point'], ['==', 'meta', 'vertex']],
|
|
|
|
|
+ paint: {
|
|
|
|
|
+ 'circle-radius': 5,
|
|
|
|
|
+ 'circle-color': '#fff',
|
|
|
|
|
+ 'circle-stroke-color': '#1677ff',
|
|
|
|
|
+ 'circle-stroke-width': 2
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ })
|
|
|
|
|
+ map!.addControl(draw)
|
|
|
|
|
+
|
|
|
|
|
+ // 创建图形
|
|
|
|
|
+ map!.on('draw.create', handleGeoChange)
|
|
|
|
|
+ // 修改图形
|
|
|
|
|
+ map!.on('draw.update', handleGeoChange)
|
|
|
|
|
+ // 删除图形
|
|
|
|
|
+ map!.on('draw.delete', () => {
|
|
|
|
|
+ emit('geoJson-change', null, 0)
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 处理面数据变更 + 计算面积(平方米)
|
|
|
|
|
+const handleGeoChange = () => {
|
|
|
|
|
+ const all = draw!.getAll()
|
|
|
|
|
+ if (all.features.length === 0) {
|
|
|
|
|
+ emit('geoJson-change', null, 0)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const polygonFeature = all.features[0] as GeoJSON.Feature<GeoJSON.Polygon>
|
|
|
|
|
+ // turf计算面积 单位:平方米
|
|
|
|
|
+ const area = turf.area(polygonFeature)
|
|
|
|
|
+ const result = cleanPolygonGeoJSON(polygonFeature);
|
|
|
|
|
+ emit('geoJson-change', result, Math.round(area))
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ========== 对外暴露方法 ==========
|
|
|
|
|
+// 手动开启绘制多边形
|
|
|
|
|
+const startDrawPolygon = () => {
|
|
|
|
|
+ if (!draw) {
|
|
|
|
|
+ // console.warn('MapDraw: 地图尚未加载完成,请稍后再试')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ draw.changeMode('draw_polygon')
|
|
|
|
|
+}
|
|
|
|
|
+// 清空绘制
|
|
|
|
|
+const clearDraw = () => {
|
|
|
|
|
+ if (!draw) {
|
|
|
|
|
+ // console.warn('MapDraw: 地图尚未加载完成,请稍后再试')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ draw.deleteAll()
|
|
|
|
|
+ emit('geoJson-change', null, 0)
|
|
|
|
|
+}
|
|
|
|
|
+// 切换选择编辑模式
|
|
|
|
|
+const editMode = () => {
|
|
|
|
|
+ if (!draw) {
|
|
|
|
|
+ // console.warn('MapDraw: 地图尚未加载完成,请稍后再试')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ draw.changeMode('simple_select')
|
|
|
|
|
+}
|
|
|
|
|
+const getBounds = (geometry:any) => {
|
|
|
|
|
+ if (map && geometry) {
|
|
|
|
|
+ const bbox = turf.bbox(geometry)
|
|
|
|
|
+ map.fitBounds([[bbox[0], bbox[1]], [bbox[2], bbox[3]]], {
|
|
|
|
|
+ padding: {top: 100, bottom:100, left: 100, right: 100}
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 清理面geojson:移除id + 坐标保留6位小数
|
|
|
|
|
+ * @param geojson Feature | FeatureCollection
|
|
|
|
|
+ */
|
|
|
|
|
+function cleanPolygonGeoJSON(geojson: any) {
|
|
|
|
|
+ // 递归处理坐标
|
|
|
|
|
+ const formatCoord = (coord: number[]) => {
|
|
|
|
|
+ return [
|
|
|
|
|
+ Number(coord[0].toFixed(6)),
|
|
|
|
|
+ Number(coord[1].toFixed(6))
|
|
|
|
|
+ ];
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 处理坐标环
|
|
|
|
|
+ const processRing = (ring: number[][]) => {
|
|
|
|
|
+ return ring.map(p => formatCoord(p));
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 处理单个feature
|
|
|
|
|
+ const processFeature = (feat: any) => {
|
|
|
|
|
+ const newFeat = { ...feat };
|
|
|
|
|
+ // 删除id
|
|
|
|
|
+ delete newFeat.id;
|
|
|
|
|
+
|
|
|
|
|
+ const geom = newFeat.geometry;
|
|
|
|
|
+ if (!geom) return newFeat;
|
|
|
|
|
+
|
|
|
|
|
+ if (geom.type === 'Polygon') {
|
|
|
|
|
+ geom.coordinates = geom.coordinates.map((ring:any) => processRing(ring));
|
|
|
|
|
+ } else if (geom.type === 'MultiPolygon') {
|
|
|
|
|
+ geom.coordinates = geom.coordinates.map((polygon:any) =>
|
|
|
|
|
+ polygon.map((ring:any) => processRing(ring))
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ return newFeat;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (geojson.type === 'FeatureCollection') {
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...geojson,
|
|
|
|
|
+ features: geojson.features.map((f:any) => processFeature(f))
|
|
|
|
|
+ };
|
|
|
|
|
+ } else if (geojson.type === 'Feature') {
|
|
|
|
|
+ return processFeature(geojson);
|
|
|
|
|
+ }
|
|
|
|
|
+ return geojson;
|
|
|
|
|
+}
|
|
|
|
|
+const handleClose = () => {
|
|
|
|
|
+ tableShow.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+const handlePageChange = (parPage:number, parPageSize:number, text:string) => {
|
|
|
|
|
+ page.value = parPage;
|
|
|
|
|
+ pageSize.value = parPageSize;
|
|
|
|
|
+ tableSearchText.value = text;
|
|
|
|
|
+ handleMoreClick(guid.value,text,page.value);
|
|
|
|
|
+}
|
|
|
|
|
+// 处理弹窗中"更多"按钮点击
|
|
|
|
|
+const handleMoreClick = (guid:any,text:any,parPage:any) => {
|
|
|
|
|
+ page.value = parPage;
|
|
|
|
|
+ //1743 项目数据 1742 申勤员工
|
|
|
|
|
+ // 排序条件orderByType 1 升序 2 降序
|
|
|
|
|
+ let requestParams = {
|
|
|
|
|
+ columnId: COLUMNMODELARR.value.id,
|
|
|
|
|
+ states: "0,1,2,3",
|
|
|
|
|
+ orderBy: JSON.stringify([{ field: "c_xm", orderByType: 2 }]),
|
|
|
|
|
+ pageSize: pageSize.value,
|
|
|
|
|
+ page: page.value,
|
|
|
|
|
+ search: "",
|
|
|
|
|
+ };
|
|
|
|
|
+ let arr = [...(requestParams.search ? JSON.parse(requestParams.search) : [])];
|
|
|
|
|
+ if(guid){
|
|
|
|
|
+ arr.push({
|
|
|
|
|
+ field: "c_xmguid", // 申勤员工 c_xmguid 项目数据 c_guid
|
|
|
|
|
+ searchType: 2,
|
|
|
|
|
+ content: { value: guid },
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ if(text){
|
|
|
|
|
+ arr.push({
|
|
|
|
|
+ field: "c_xm",
|
|
|
|
|
+ searchType: 2,
|
|
|
|
|
+ content: { value: text },
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ requestParams.search = JSON.stringify(arr);
|
|
|
|
|
+
|
|
|
|
|
+ api.getDmsDataList(requestParams).then((res: any) => {
|
|
|
|
|
+ if (res.code == 200){
|
|
|
|
|
+ let data = res.content.data;
|
|
|
|
|
+ total.value = res.content.count;
|
|
|
|
|
+ data = data.map((item: any) => {
|
|
|
|
|
+ // 给每个属性名称添加 c_ 前缀
|
|
|
|
|
+ const newItem: any = {};
|
|
|
|
|
+ for (const key in item) {
|
|
|
|
|
+ // 如果已经有c_
|
|
|
|
|
+ if (key.includes("c_")) {
|
|
|
|
|
+ let itemkey = key.replace(/c_/g, "");
|
|
|
|
|
+ newItem['c_' + itemkey] = item[key];
|
|
|
|
|
+ }else{
|
|
|
|
|
+ newItem[key] = item[key];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return newItem;
|
|
|
|
|
+ })
|
|
|
|
|
+ contentItem.value = data;
|
|
|
|
|
+ tableData.value = data;
|
|
|
|
|
+ tableData.value.sort((a: any, b: any) => a.c_xm.localeCompare(b.c_xm, 'zh-CN'))
|
|
|
|
|
+
|
|
|
|
|
+ if(!tableShow.value){
|
|
|
|
|
+ tableShow.value = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }else{
|
|
|
|
|
+ tableData.value = [];
|
|
|
|
|
+ contentItem.value=[];
|
|
|
|
|
+ // this.$message({ message: '无员工数据', type: 'info' })
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+ //根据模型id查询模型详情
|
|
|
|
|
+const getModelById = () => {
|
|
|
|
|
+ let requestParams = {
|
|
|
|
|
+ modelId: Number(COLUMNMODELARR.value.mid), // 申勤员工ID
|
|
|
|
|
+ };
|
|
|
|
|
+ api.getModelById(requestParams).then((res: any) => {
|
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
|
+ columnModel.value = res.content;
|
|
|
|
|
+ columnModel.value.modelId = COLUMNMODELARR.value.mid;
|
|
|
|
|
+ columnModel.value.columnId = COLUMNMODELARR.value.id;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+defineExpose({
|
|
|
|
|
+ startDrawPolygon,
|
|
|
|
|
+ clearDraw,
|
|
|
|
|
+ editMode,
|
|
|
|
|
+ isLoaded,
|
|
|
|
|
+ getBounds,
|
|
|
|
|
+ renderGeoJson
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+:deep(.mapboxgl-ctrl-bottom-left) div{
|
|
|
|
|
+ display:none !important;
|
|
|
|
|
+}
|
|
|
|
|
+.map-container {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 600px;
|
|
|
|
|
+ border: 1px solid #e5e7eb;
|
|
|
|
|
+}
|
|
|
|
|
+#mapContainer {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|
|
|
|
|
+<style>
|
|
|
|
|
+/*节点标签样式 */
|
|
|
|
|
+.custom-popup {
|
|
|
|
|
+ z-index: 9;
|
|
|
|
|
+}
|
|
|
|
|
+.more{
|
|
|
|
|
+ float:right;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ transition: color 0.2s;
|
|
|
|
|
+}
|
|
|
|
|
+.more:hover {
|
|
|
|
|
+ color: #00A8FF;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|