This commit is contained in:
扈兆增 2026-04-03 16:04:40 +08:00
commit 66a949a7a2
25 changed files with 6429 additions and 194 deletions

View File

@ -23,9 +23,11 @@
"default-passive-events": "^2.0.0", "default-passive-events": "^2.0.0",
"echarts": "^5.2.2", "echarts": "^5.2.2",
"element-plus": "^2.2.27", "element-plus": "^2.2.27",
"esri-leaflet": "^3.0.19",
"js-base64": "^3.7.5", "js-base64": "^3.7.5",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"jsencrypt": "^3.3.2", "jsencrypt": "^3.3.2",
"leaflet": "^1.9.4",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"path-to-regexp": "^6.2.0", "path-to-regexp": "^6.2.0",

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>map-dxsdzYijian</title>
<defs>
<path d="M10,0 C15.5228475,0 20,4.4771525 20,10 C20,15.5228475 15.5228475,20 10,20 C4.4771525,20 0,15.5228475 0,10 C0,4.4771525 4.4771525,0 10,0 Z" id="path-1"></path>
</defs>
<g id="1-首页" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1.1-首页-水电开发-全国" transform="translate(-158.000000, -812.000000)">
<g id="图例备份-4" transform="translate(16.000000, 737.000000)">
<g id="编组-9" transform="translate(142.000000, 74.000000)">
<g id="map-shuikudaxing-yijian" transform="translate(0.000000, 1.000000)">
<g id="路径" fill-rule="nonzero">
<use fill="#499934" xlink:href="#path-1"></use>
<use fill="#71B603" xlink:href="#path-1"></use>
<use fill="#78C300" xlink:href="#path-1"></use>
</g>
<path d="M10,1.66666667 C14.6023729,1.66666667 18.3333333,5.39762709 18.3333333,10 L18.3333333,10 L1.66666667,10 L1.67048694,9.74522729 C1.80514922,5.26072284 5.48285621,1.66666667 10,1.66666667 Z" id="形状结合" fill="#FFFFFF"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,7 @@
<svg width="37" height="37" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden">
<g transform="translate(-374 -236)">
<path d="M376.5 255C376.5 245.335 384.111 237.5 393.5 237.5 402.889 237.5 410.5 245.335 410.5 255 410.5 264.665 402.889 272.5 393.5 272.5 384.111 272.5 376.5 264.665 376.5 255Z" stroke="#00B0F0" stroke-width="1.33333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/>
<path d="M379.5 255.5 406.5 255.5 405.462 260.488C403.409 265.196 398.602 268.5 393 268.5 387.398 268.5 382.591 265.196 380.538 260.488Z" stroke="#00B0F0" stroke-width="1.33333" stroke-miterlimit="8" fill="#5DA6DF" fill-rule="evenodd"/>
<path d="M406.5 255.5 379.5 255.5 380.538 250.128C382.591 245.058 387.398 241.5 393 241.5 398.602 241.5 403.409 245.058 405.462 250.128Z" stroke="#00B0F0" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 925 B

View File

@ -0,0 +1,7 @@
<svg width="37" height="37" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden">
<g transform="translate(-374 -236)">
<path d="M376.5 255C376.5 245.335 384.111 237.5 393.5 237.5 402.889 237.5 410.5 245.335 410.5 255 410.5 264.665 402.889 272.5 393.5 272.5 384.111 272.5 376.5 264.665 376.5 255Z" stroke="#E1AB4F" stroke-width="1.33333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/>
<path d="M379.5 255.5 406.5 255.5 405.462 260.488C403.409 265.196 398.602 268.5 393 268.5 387.398 268.5 382.591 265.196 380.538 260.488Z" stroke="#E1AB4F" stroke-width="1.33333" stroke-miterlimit="8" fill="#E1AB4F" fill-rule="evenodd"/>
<path d="M406.5 255.5 379.5 255.5 380.538 250.128C382.591 245.058 387.398 241.5 393 241.5 398.602 241.5 403.409 245.058 405.462 250.128Z" stroke="#E1AB4F" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 925 B

View File

@ -0,0 +1,7 @@
<svg width="37" height="37" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden">
<g transform="translate(-374 -236)">
<path d="M376.5 255C376.5 245.335 384.111 237.5 393.5 237.5 402.889 237.5 410.5 245.335 410.5 255 410.5 264.665 402.889 272.5 393.5 272.5 384.111 272.5 376.5 264.665 376.5 255Z" stroke="#0FC55B" stroke-width="1.33333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/>
<path d="M379.5 255.5 406.5 255.5 405.462 260.488C403.409 265.196 398.602 268.5 393 268.5 387.398 268.5 382.591 265.196 380.538 260.488Z" stroke="#0FC55B" stroke-width="1.33333" stroke-miterlimit="8" fill="#0FC55B" fill-rule="evenodd"/>
<path d="M406.5 255.5 379.5 255.5 380.538 250.128C382.591 245.058 387.398 241.5 393 241.5 398.602 241.5 403.409 245.058 405.462 250.128Z" stroke="#0FC55B" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 925 B

View File

@ -0,0 +1,7 @@
<svg width="37" height="37" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden">
<g transform="translate(-374 -236)">
<path d="M376.5 255C376.5 245.335 384.111 237.5 393.5 237.5 402.889 237.5 410.5 245.335 410.5 255 410.5 264.665 402.889 272.5 393.5 272.5 384.111 272.5 376.5 264.665 376.5 255Z" stroke="#91938E" stroke-width="1.33333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/>
<path d="M379.5 255.5 406.5 255.5 405.462 260.488C403.409 265.196 398.602 268.5 393 268.5 387.398 268.5 382.591 265.196 380.538 260.488Z" stroke="#91938E" stroke-width="1.33333" stroke-miterlimit="8" fill="#91938E" fill-rule="evenodd"/>
<path d="M406.5 255.5 379.5 255.5 380.538 250.128C382.591 245.058 387.398 241.5 393 241.5 398.602 241.5 403.409 245.058 405.462 250.128Z" stroke="#91938E" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 925 B

View File

@ -0,0 +1,6 @@
<svg width="30" height="30" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden">
<g transform="translate(-194 -511)">
<path d="M195.5 526.5 223.5 526.5 222.423 531.488C220.294 536.196 215.31 539.5 209.5 539.5 203.69 539.5 198.706 536.196 196.577 531.488Z" stroke="#91938E" stroke-width="1.33333" stroke-miterlimit="8" fill="#91938E" fill-rule="evenodd"/>
<path d="M223.5 526.5 195.5 526.5 196.577 521.128C198.706 516.058 203.69 512.5 209.5 512.5 215.31 512.5 220.294 516.058 222.423 521.128Z" stroke="#91938E" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 647 B

View File

@ -0,0 +1,6 @@
<svg width="30" height="30" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden">
<g transform="translate(-194 -511)">
<path d="M195.5 526.5 223.5 526.5 222.423 531.488C220.294 536.196 215.31 539.5 209.5 539.5 203.69 539.5 198.706 536.196 196.577 531.488Z" stroke="#00B0F0" stroke-width="1.33333" stroke-miterlimit="8" fill="#5DA6DF" fill-rule="evenodd"/>
<path d="M223.5 526.5 195.5 526.5 196.577 521.128C198.706 516.058 203.69 512.5 209.5 512.5 215.31 512.5 220.294 516.058 222.423 521.128Z" stroke="#00B0F0" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 647 B

View File

@ -0,0 +1,6 @@
<svg width="30" height="30" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden">
<g transform="translate(-194 -511)">
<path d="M195.5 526.5 223.5 526.5 222.423 531.488C220.294 536.196 215.31 539.5 209.5 539.5 203.69 539.5 198.706 536.196 196.577 531.488Z" stroke="#E1AB4F" stroke-width="1.33333" stroke-miterlimit="8" fill="#E1AB4F" fill-rule="evenodd"/>
<path d="M223.5 526.5 195.5 526.5 196.577 521.128C198.706 516.058 203.69 512.5 209.5 512.5 215.31 512.5 220.294 516.058 222.423 521.128Z" stroke="#E1AB4F" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 647 B

View File

@ -0,0 +1,6 @@
<svg width="30" height="30" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden">
<g transform="translate(-194 -511)">
<path d="M195.5 526.5 223.5 526.5 222.423 531.488C220.294 536.196 215.31 539.5 209.5 539.5 203.69 539.5 198.706 536.196 196.577 531.488Z" stroke="#0FC55B" stroke-width="1.33333" stroke-miterlimit="8" fill="#0FC55B" fill-rule="evenodd"/>
<path d="M223.5 526.5 195.5 526.5 196.577 521.128C198.706 516.058 203.69 512.5 209.5 512.5 215.31 512.5 220.294 516.058 222.423 521.128Z" stroke="#0FC55B" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 647 B

View File

@ -24,10 +24,19 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from "vue";
import MapLegend from "@/components/mapLegend/index.vue"; import MapLegend from "@/components/mapLegend/index.vue";
import MapFilter from "@/components/mapFilter/index.vue"; import MapFilter from "@/components/mapFilter/index.vue";
import MapController from "@/components/mapController/index.vue"; import MapController from "@/components/mapController/index.vue";
import BaseLayerSwitcher from "@/components/baseLayerSwitcher/index.vue"; import BaseLayerSwitcher from "@/components/BaseLayerSwitcher/index.vue";
import { MapClass } from './map.class'
onMounted(() => {
const mapClass = MapClass.getInstance()
// const globalData = GlobalData.getInstance()
//@ts-ignore
window.mapClass = mapClass
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -40,7 +49,7 @@ import BaseLayerSwitcher from "@/components/baseLayerSwitcher/index.vue";
#mapContainer { #mapContainer {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative; position: absolute;
background-color: red; background-color: #fff;
} }
</style> </style>

View File

@ -0,0 +1,115 @@
type EventCallback = (...args: any[]) => void;
export class EventEmitter {
private events: Map<string, EventCallback[]> = new Map();
on(event: string, callback: EventCallback): this {
if (!this.events.has(event)) {
this.events.set(event, []);
}
this.events.get(event)!.push(callback);
return this;
}
off(event: string, callback?: EventCallback): this {
if (!this.events.has(event)) return this;
if (callback) {
const callbacks = this.events.get(event)!;
const index = callbacks.indexOf(callback);
if (index > -1) {
callbacks.splice(index, 1);
}
} else {
this.events.delete(event);
}
return this;
}
emit(event: string, ...args: any[]): this {
if (this.events.has(event)) {
this.events.get(event)!.forEach(callback => {
try {
callback(...args);
} catch (error) {
console.error(`Event ${event} handler error:`, error);
}
});
}
return this;
}
once(event: string, callback: EventCallback): this {
const onceCallback: EventCallback = (...args: any[]) => {
callback(...args);
this.off(event, onceCallback);
};
return this.on(event, onceCallback);
}
removeAllListeners(): this {
this.events.clear();
return this;
}
listenerCount(event: string): number {
return this.events.get(event)?.length || 0;
}
}type EventCallback = (...args: any[]) => void;
export class EventEmitter {
private events: Map<string, EventCallback[]> = new Map();
on(event: string, callback: EventCallback): this {
if (!this.events.has(event)) {
this.events.set(event, []);
}
this.events.get(event)!.push(callback);
return this;
}
off(event: string, callback?: EventCallback): this {
if (!this.events.has(event)) return this;
if (callback) {
const callbacks = this.events.get(event)!;
const index = callbacks.indexOf(callback);
if (index > -1) {
callbacks.splice(index, 1);
}
} else {
this.events.delete(event);
}
return this;
}
emit(event: string, ...args: any[]): this {
if (this.events.has(event)) {
this.events.get(event)!.forEach(callback => {
try {
callback(...args);
} catch (error) {
console.error(`Event ${event} handler error:`, error);
}
});
}
return this;
}
once(event: string, callback: EventCallback): this {
const onceCallback: EventCallback = (...args: any[]) => {
callback(...args);
this.off(event, onceCallback);
};
return this.on(event, onceCallback);
}
removeAllListeners(): this {
this.events.clear();
return this;
}
listenerCount(event: string): number {
return this.events.get(event)?.length || 0;
}
}

View File

@ -0,0 +1,29 @@
import type { layer, MapInterface } from "./map.d";
import { MapLeaflet } from "./map.leaflet";
interface MapClassInterface extends MapInterface {
layers: Map<string, layer>;
view: any;
}
export const mapServerBaseUrl = localStorage.getItem("gisurl") || "http://210.72.227.199:18084/";
export class MapClass implements MapClassInterface {
layers: Map<string, layer>;
view: any;
private static instance: MapClass;
private service: MapInterface;
static getInstance(): MapClass {
if (!this.instance) {
this.instance = new MapClass();
}
return this.instance;
}
constructor() {
this.layers = new Map();
this.view = null;
this.service = new MapLeaflet();
}
}

232
frontend/src/components/gis/map.d.ts vendored Normal file
View File

@ -0,0 +1,232 @@
export type layerType =
| "markers"
| "tiledMap"
| "tiledMapQuery"
| "geoJson"
| "arcgisFeature"
| "dynamicMapLayer"
| "arcgisMap"
| "label";
export type layerOption = {
opacity?: number;
data?: Array<any>;
zIndex?: number;
clickEvent?: Function;
hoverEvent?: Function;
legendImages?: Array<any> | null | undefined;
geoJsonLegend?: Array<any> | null | undefined;
tiledMapType?: undefined | "superMap";
};
export interface layer {
id: string;
key: string;
_layer?: any;
type?: layerType;
url?: string;
urlThd?: string;
label?: string;
thumbnail?: string;
visible?: boolean;
option?: layerOption;
tempobj?: any;
opacity?: any;
}
export interface MapInterface {
getRainColor: any;
getRainColor1: any;
removeContentmarkers: any;
removeGanliumarkers: any;
addarcgisLayerWithNotLine: any
/**
*
* @param container DOM容器
* @return any
*/
init(container: React.ReactNode, rectangle?: any, center?: any): Promise<any>;
/**
*
*/
addLayer(layer: layer): any;
/**
* canvasMarker
*/
addCanvasMarker(
data: Array<any>,
legend?: Array<any>,
option?: { skipRemoveHtml?: boolean },
flag?: any
): any;
invalidateSize(): void;
getRain(data: any): void;
/**
*
*/
addZoomEvent(func: Function, type?: string): void;
/**
*
* @param func
*/
addMouseMoveEvent(func: Function): void;
/**
*
* @param func
*/
addMouseClickEvent(func: Function): void;
/**
*
* @param data
*/
fitBounds(data: any): void;
/**
*
*/
getLayers(): Map<string, layer> | null;
/**
*
*/
getMapZoom(): number;
/**
*
*/
zoomEnlarge(): number;
/**
*
*/
zoomNarrow(): number;
/**
*
*/
getMapZoomOrScale(): { scale?: number; zoom?: number };
/**
*
* @param layers
*/
showLayer(id: string): void;
/**
*
* @param layers
*/
hideLayer(id: string): void;
/**
*
* @param position
*/
setCenter(position: { lat: number; lng: number }, zoom?: any): void;
/**
*
*/
removeAllLayer(): void;
/**
*
*/
removeAllLabel(): void;
/**
*
* @param layer
*/
removeLayer(layer: layer): void;
/**
*
*/
reRenderLayer(
key: string,
options?: { opacity?: number; data: Array<any>; zIndex?: number }
): Promise<any>;
/**
*
*/
removeMouseMoveEvent(): void;
/**
*
*/
removeEvent(type: string, func: Function): void;
/**
*
*/
removeFeatureLayer(): void;
/**
*
*/
removedataSource(item: any): void;
/**
*
*/
removeMouseClickEvent(): void;
/**
*
* out
* in
*/
zoomToggle(type: "out" | "in"): void;
/**
* arcgis图层
*/
addarcgisLayer(item: any, data?: any): void;
/**
* label
*/
addmapLabel(item: any, data: any, zoom: any): void;
addmapLine(item: any, data: any): void;
/**
* arcgis图层
*/
removearcgisLayer(): void;
/**
* label
*/
removearcgisLabel(): void;
removeLayermarkers(): void;
removeRainLayer(): void;
removeGroupLayer(): void;
removeMapLayer(): void;
/**
*
*/
handelstartDrawLine(): void;
/**
*
*/
handelstartDrawPolygon(): void;
/**
*
*/
handelclearLayer(): void;
}

View File

@ -0,0 +1,373 @@
import { layer, MapInterface } from "./map";
import * as L from "leaflet";
import * as esriLeaflet from "esri-leaflet";
import { mapServerBaseUrl } from "./map.class";
// @ts-ignore
import axios from "axios";
// import "@/components/thematicMap/leaflet/leaflet.inflatable-markers-group.js"
const tiledMapGroup = L.layerGroup();
const chartMapGroup = L.layerGroup();
const overlayGroup = L.layerGroup();
const CENTER_positionCN: any = [37.072654, 86.171125]; // [26.072654, 107.171125]; //中心纬经度 中国
let boundCavansLayer: any = null;
let ganliulist:any = []
export class MapLeaflet implements MapInterface {
map: any = null;
htmlMakerLayer: any = [];
minimumZoom = 7;
temperatureMapObj: any = [];
addLayer(layer: any): any {
// The WMTS URL
console.warn(layer)
switch (layer.type) {
case "tiledMap":
if (layer.url) {
let setzIndex = 1;
if (layer.zIndex && layer.zIndex != "" && layer.zIndex != "0") {
setzIndex = Number(layer.zIndex);
}
if (layer.title !== '干流河流') {
layer._layer = esriLeaflet
.dynamicMapLayer({
url: layer.url,
opacity: layer.opacity,
zIndex: 999999999999
})
?.addTo(this.map)
.bringToBack()
} else {
axios.get('http://210.72.227.199:18084/geoserver/cite/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=cite:glhl_epsg4326&maxFeatures=50&outputFormat=application%2Fjson')
.then((res) => {
res.data?.features.map((item: any, index: number) => {
const a = L.geoJSON(item, {
style: {
},
}).addTo(this.map);
ganliulist.push(a)
});
})
}
}
return layer;
break
case "geoserver-wmts":
if (layer.url) {
if (layer.title == "地图瓦片图层") {
console.log('地图瓦片')
//增加遮罩
axios.get('/zfile/qgcbuji/overlayLand3.json')
.then((res) => {
var landLayer = L.geoJson(res.data, {
style: {
opacity: 0,
//填充透明度
fillOpacity: 1,
//填充颜色
fillColor: '#ececec'
}
})?.addTo(overlayGroup).bringToBack();
})
axios.get('/zfile/qgcbuji/overlayOcean.json')
.then((res) => {
var oceanLayer = L.geoJson(res.data, {
style: {
opacity: 0,
//填充透明度
fillOpacity: 1,
//填充颜色
fillColor: '#8eccf1'
}
})?.addTo(overlayGroup).bringToFront();
})
overlayGroup?.addTo(this.map);
}
var optionobj = JSON.parse(layer.options);
if (optionobj) {
var ignLayer = L.tileLayer
.wmts(layer.url, {
tileMatrixSet: optionobj.tileMatrixSet, //"EPSG:3857_qgc_arcgistiles_l13_google",
tileSize: 256, //切片大小
maxZoom: 13,
noWrap: true,
opacity: 1.01,
minZoom: 4,
layer: optionobj.layer, //"qgc_arcgistiles_l13_google",
})
.addTo(this.map)
.bringToBack();
layer._layer = ignLayer;
layer._layer.layerGroup = overlayGroup;
}
}
return layer;
case "arcgisMap":
if (layer.url) {
if (this.map) {
const mapLayer = esriLeaflet
.tiledMapLayer({
url: layer.url,
format: "image/png",
maxNativeZoom: 17,
})
.addTo(this.map)
.bringToBack();
layer._layer = mapLayer;
}
}
return layer;
case "tiledMapQuery":
if (layer.url && layer.id) {
if (layer.title == "岛屿") {
layer.layers = "cite:nhqddt_epsg3857";
}
layer._layer = L.tileLayer
.wms(layer.url, {
id: layer.id,
format: "image/png",
transparent: true,
zIndex: 9999,
layers: layer.layers,
// maxZoom:10,
})
.addTo(this.map);
// .bringToBack();
return layer;
}
return layer;
case "label":
if (layer.url) {
const tileLayer: any = L.tileLayer(layer.url, {
subdomains: ["0", "1", "2", "3", "4", "5", "6", "7"],
crossOrigin: "anonymous",
});
const boundary = (providerName: any) => {
// return BoundaryCanvas(tileLayer, {});
};
let boundaryLayers;
if (layer.title == "行政标注") {
boundaryLayers = boundary(tileLayer._leaflet_id)
.addTo(this.map)
.bringToBack()
.setZIndex(10);
} else {
boundaryLayers = boundary(tileLayer._leaflet_id).addTo(this.map);
}
tileLayer.boundLayer = boundaryLayers;
layer._layer = boundaryLayers;
return layer;
}
break;
case "markers":
this.getRain(layer);
break;
default: {
return;
}
}
}
/**
* leaflet加载wmts在非整数缩放时瓦片间会有缝隙
*/
inittiles() {
var originalInitTile = L.GridLayer.prototype._initTile;
L.GridLayer.include({
_initTile: function (tile: any) {
originalInitTile.call(this, tile);
var tileSize = this.getTileSize();
tile.style.width = tileSize.x + 2 + "px";
tile.style.height = tileSize.y + 2 + "px";
},
});
}
init(container: React.ReactNode, rectangle?: any): Promise<any> {
try {
console.log("init初始化container", container);
this.inittiles();
// var corner1 = L.latLng(0.712, -10.227),
// corner2 = L.latLng(70.774, 204.125),
// var corner1 = L.latLng(-50.712, -10.227),
// corner2 = L.latLng(100.774, 204.125),
// var corner1 = L.latLng(20.712, 50.227),
// corner2 = L.latLng(51.774, 160.125),
var corner1 = L.latLng(20.712, 0),
corner2 = L.latLng(51.774, 179.125),
bounds = L.latLngBounds(corner1, corner2);
const map = L.map(container as any, {
preferCanvas: true,
minZoom: 4.4,
center: CENTER_positionCN,
zoom: 4.4,
maxZoom: 18,
zoomControl: false,
maxBounds: bounds,
zoomSnap: 0,
crs: L.CRS.EPSG3857,
});
this.map = map;
//遮罩
var pNW = { lat: 85.0, lng: -90.0 };
var pNE = { lat: 85.0, lng: 270.0 };
var pSE = { lat: -45.0, lng: 270.0 };
var pSW = { lat: -45.0, lng: -90.0 };
var pArray = [];
pArray.push(pNW);
pArray.push(pSW);
pArray.push(pSE);
pArray.push(pNE);
pArray.push(pNW);
let mapURL =
mapServerBaseUrl + "arcgis/rest/services/zh_boundary/MapServer/0/query";
esriLeaflet
.query({
url: mapURL,
})
// .where(mapWhere)
.run((error: any, result: any, response: any) => {
if (response) {
// let test = arcgisToGeoJSON(response);
// let chinaList = test.features[0].geometry.coordinates;
// var boundsCounty = [
// [0.0, -20.0],
// [276.0, -20.0],
// [276.0, 75.0],
// [0.0, 75.0],
// [0.0, -20.0],
// ];
// console.log("chinaList", chinaList);
// var geojsonRelt: any = {
// type: "Feature",
// properties: {},
// geometry: {
// type: "MultiPolygon",
// coordinates: [[boundsCounty, ...chinaList]],
// },
// };
// var chinaCavansLayer = L.geoJSON(geojsonRelt, {
// style: {
// color: "#8EA5BA",
// weight: 1,
// fillColor: "#ffffff",
// fillOpacity: 1,
// },
// });
//chinaCavansLayer.addTo(this.map).bringToBack().setZIndex(0);
}
});
let params = {
startTime: "2022-01-01 00:00:00",
};
L.control
.scale({ maxWidth: 150, metric: true, imperial: false })
.addTo(this.map);
this.map.on("zoomend", (e: any) => {
var scale = document.getElementsByClassName(
"leaflet-control-scale-line"
)[0].innerHTML;
var num = parseInt(scale);
if (scale.includes("km")) {
console.log("比例尺:1:" + num * 1000 + "m");
} else {
console.log("比例尺1:" + num + "m");
}
console.log("scale", scale);
console.log("当前缩放级别", e.target.getZoom());
});
console.log("rectangle", rectangle);
if (rectangle) {
if (rectangle[0] && rectangle[0][0] == 90) {
//this.map.setView([43.719771, 126.687641,], 9);
} else {
map.fitBounds(rectangle);
}
}
return Promise.resolve(map);
} catch (e) {
console.log("测试", e);
return Promise.reject({});
}
}
removeLayer(layer: layer | any): void {
switch (layer.type) {
case "geoJson":
break;
default:
if (layer._layer) {
if (layer._layer.layerGroup) {
layer._layer.layerGroup.clearLayers();
}
this.map?.off("zoom", layer._layer.func);
this.map && this.map.removeLayer(layer._layer);
} else if (layer) {
if (layer.layerGroup) {
layer.layerGroup.clearLayers();
}
this.map?.off("zoom", layer.func);
this.map && this.map.removeLayer(layer);
let mapvalue = tiledMapGroup.getLayers();
for (let i = 0; i < mapvalue.length; i++) {
if (mapvalue[i].options.id == layer.id) {
tiledMapGroup.removeLayer(mapvalue[i]);
}
}
}
break;
}
}
addboundCavansLayer = (list: any, bgStyle?: any) => {
if (boundCavansLayer && this.map.hasLayer(boundCavansLayer)) {
this.map.removeLayer(boundCavansLayer);
}
var boundsCounty = [
[0.0, -20.0],
[176.0, -20.0],
[176.0, 75.0],
[0.0, 75.0],
[0.0, -20.0],
];
var geojsonRelt: any = {
type: "Feature",
properties: {},
geometry: {
type: "MultiPolygon",
coordinates: [[boundsCounty, ...list]],
},
};
var boundCavansLayerRelt = L.geoJSON(
geojsonRelt,
bgStyle
? { ...bgStyle }
: {
color: "transparent",
fillColor: "#0a2b4b",
fillOpacity: 0.9,
}
);
boundCavansLayer = boundCavansLayerRelt;
console.warn(boundCavansLayerRelt.addTo)
boundCavansLayerRelt.addTo(this.map).bringToFront().setZIndex(99999999999);
};
}

View File

@ -1,8 +1,14 @@
<template> <template>
<a-tooltip placement="leftBottom" trigger="click" color="transparent" :overlayInnerStyle="{boxShadow: 'none'}"> <a-tooltip
placement="leftBottom"
trigger="click"
color="transparent"
:overlayInnerStyle="{ boxShadow: 'none' }"
>
<template #title> <template #title>
<div class="layers-tree"> <div class="layers-tree">
<div class="layers-tree-title">图层管理</div> <div class="layers-tree-title">图层管理</div>
<div class="layers-tree-content"> <div class="layers-tree-content">
<a-Tree <a-Tree
checkable checkable
@ -19,74 +25,73 @@
</a-tooltip> </a-tooltip>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, onMounted, computed } from "vue";
const onCheck = () => { import { useMapStore } from "@/store/modules/map";
console.log("点击了测量工具"); import { useRoute } from "vue-router";
}; let route = useRoute();
const mapStore: any = useMapStore();
//
const layerConfigs = computed(() => mapStore.layerData);
//
const checkedKeys = ref([]); const checkedKeys = ref([]);
const layerConfigs = ref([ const onCheck = (v: any, e: any) => {
{ //
title: "图层1", const fData = layerConfigs.value?.filter((e: any) => e.key === "facilities")?.[0];
key: "layer1", const fbData = layerConfigs.value?.filter((e: any) => e.key === "facilities_built")?.[0];
children: [ const facilities_built_data =
{ (fbData && [fbData.key, ...fbData?.children?.map((e: any) => e.key)]) || [];
title: "子图层1", const facilities_data =
key: "sublayer1", (fData && [fData.key, ...fData?.children?.map((e: any) => e.key)]) || [];
},
], let checkKeys = v;
},
{ if (e?.node.key === "rare_fish_point") {
title: "图层2", checkKeys = v?.filter((item: any) => item !== "fish_along_point");
key: "layer2", } else if (e?.node.key === "fish_along_point") {
}, checkKeys = v?.filter((item: any) => item !== "rare_fish_point");
{ }
title: "图层3", if (e.checked) {
key: "layer3", if (e?.node.key === "stinfo_video_point" || e?.node.key == "stinfo") {
}, checkKeys = v?.filter((item: any) => item !== "stinfo_ai_video_point");
{ } else if (e?.node.key === "stinfo_ai_video_point") {
title: "图层4", checkKeys = v?.filter(
key: "layer4", (item: any) => item !== "stinfo_video_point" && item !== "stinfo"
}, );
{ }
title: "图层5", console.log(checkKeys, "res111");
key: "layer5",
}, if (
{ checkKeys.some((e: any) => facilities_data.includes(e)) &&
title: "图层6", checkKeys.some((e: any) => facilities_built_data.includes(e))
key: "layer6", ) {
}, if (
{ facilities_built_data.some((e: any) =>
title: "图层7", e.includes(checkKeys[checkKeys.length - 1])
key: "layer7", )
}, ) {
{ checkKeys = checkKeys.filter((e: any) => !facilities_data.includes(e));
title: "图层8", } else if (
key: "layer8", facilities_data.some((e: any) => e.includes(checkKeys[checkKeys.length - 1]))
}, ) {
{ checkKeys = checkKeys.filter((e: any) => !facilities_built_data.includes(e));
title: "图层9", }
key: "layer9", }
}, }
{ checkedKeys.value = checkKeys;
title: "图层10", mapStore.updateLayerData(checkKeys);
key: "layer10",
},
{
title: "图层11",
key: "layer11",
},
{
title: "图层12",
key: "layer12",
},
{
title: "图层13",
key: "layer13",
},
]);
const onSelect = (selectedKeys: any) => {
console.log(selectedKeys);
}; };
const getCheckedKeys = () => {
const name = route.path.split("/")[2];
if (name === "shuiDianKaiFaZhuangKuang") {
checkedKeys.value = ["customBaseLayer", "eng", "eng_point"];
}
mapStore.updateLayerData(checkedKeys.value);
};
onMounted(() => {
getCheckedKeys();
// router.push({ name: 'map' })
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.map-item { .map-item {

View File

@ -0,0 +1,46 @@
<!-- LegendItem.vue -->
<template>
<div
class="legendItem"
:class="{ gray: item.checked == 0, disabled: item.canBeChecked == 0 }"
>
<div class="legendIcon" :class="{ smallIcon: item.layerCode == 'eng_point' }">
<img :src="getIconPath(item.icon)" alt="" />
</div>
<div class="legendIconTitle">
<span v-html="item.name" style="white-space: pre-wrap"></span>
</div>
</div>
</template>
<script setup lang="ts">
import { getIconPath } from '@/utils/index';
defineProps<{ item: any }>();
</script>
<style scoped lang="scss">
.legendItem {
cursor: pointer;
margin-right: 10px;
padding: 4px 0;
min-height: 30px;
display: flex;
flex-direction: row;
.legendIcon {
width: 25px !important;
height: 25px !important;
// background-color: red;
text-align: center;
}
.smallIcon {
width: 22px !important;
height: 22px !important;
}
.legendIconTitle {
cursor: pointer;
flex: 1 1;
}
&:hover {
color: #2f6b98;
}
}
</style>

View File

@ -8,20 +8,27 @@
</div> </div>
<div class="legendContent" v-show="isOpen"> <div class="legendContent" v-show="isOpen">
<a-spin :spinning="data === 0"> <a-spin :spinning="legendData.length === 0">
<div class="legendGroup" v-for="i in data"> <div class="legendGroup" v-for="i in legendData">
<div class="groupTitle">工程</div> <div class="groupTitle">{{ i.name }} {{ i.layerCode }}</div>
<div class="groupContent"> <div class="groupContent">
<div class="legendItem" v-for="j in 10" :key="j"> <template v-for="j in i.childrenList" :key="j.name">
<div class="legendIcon smallIcon"></div> <LegendItem v-if="j.layerCode" :item="j" @click="legendItemClick(j)" />
<div class="legendIconTitle"> <div
大型水电站-已建 v-else-if="j.childrenList && j.childrenList.length > 0"
<!-- <span class="legendGroup"
><br /> >
2.装机容量(万kW) <div class="groupTitle">{{ j.name }}</div>
</span> --> <div class="groupContent">
<LegendItem
v-for="item in j.childrenList"
:key="item.layerCode"
:item="item"
@click="legendItemClick(item)"
/>
</div> </div>
</div> </div>
</template>
</div> </div>
</div> </div>
</a-spin> </a-spin>
@ -29,13 +36,50 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from "vue"; import { onMounted, ref, computed, watch } from "vue";
const data = ref(0); import { useMapStore } from "@/store/modules/map";
import LegendItem from "@/components/mapLegend/LegendItem.vue";
const mapStore: any = useMapStore();
//
const legendData = ref(mapStore.legendDataSelected);
const legendItemClick = (item: any) => {
if (item.canBeChecked == 0) {
return;
}
item.checked = item.checked == 0 ? 1 : 0;
};
watch(
() => mapStore.legendDataSelected,
(newValue) => {
// layerConfigs.value = newValue;
console.log(newValue);
legendData.value = newValue;
// for (let i = 0; i < newValue.length; i++) {
// console.log(mapStore.layerData[i]);
// if (newValue[i].key != "-") {
// if (newValue[i].checked == 1) {
// if (newValue[i].children?.length > 0) {
// legendData.value.push(newValue[i]);
// }
// }
// }
// }
},
{ immediate: true, deep: true }
);
onMounted(() => { onMounted(() => {
setTimeout(() => { // for (let i = 0; i < mapStore.layerData.length; i++) {
data.value = 10; // console.log(mapStore.layerData[i]);
}, 1000); // if (mapStore.layerData[i].key != "-") {
console.log(data.value); // if (mapStore.layerData[i].checked == 1) {
// }
// }
// }
// console.log(layerConfigs.value)
// setTimeout(() => {
// data.value = 10;
// }, 1000);
// console.log(data.value);
}); });
const isOpen = ref(true); const isOpen = ref(true);
</script> </script>
@ -69,10 +113,6 @@ const isOpen = ref(true);
overflow-x: scroll; overflow-x: scroll;
overflow-y: scroll; overflow-y: scroll;
border-top: 1px solid #eeeeee; border-top: 1px solid #eeeeee;
overflow-y: hidden;
// &::-webkit-scrollbar {
// width: 0;
// }
.legendGroup { .legendGroup {
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
@ -91,22 +131,8 @@ const isOpen = ref(true);
filter: grayscale(100%); filter: grayscale(100%);
color: #00000073; color: #00000073;
} }
.legendItem { .disabled {
cursor: pointer; cursor: not-allowed !important;
margin-right: 10px;
padding: 4px 0;
min-height: 30px;
display: flex;
flex-direction: row;
.legendIcon {
width: 22px !important;
height: 22px !important;
background-color: red;
}
.legendIconTitle {
cursor: pointer;
flex: 1 1;
}
} }
} }
} }

View File

@ -9,17 +9,30 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted } from 'vue'; import { ref, onMounted, watch } from "vue";
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import SidePanelItem from "@/components/SidePanelItem/index.vue";
const JidiSelectEventStore = useJidiSelectEventStore();
// 便 // 便
defineOptions({ defineOptions({
name: 'jidiInfoMod' name: "jidiInfoMod",
}); });
const title_text = ref('我国水能资源丰富,主要集中在金沙江、长江上游、雅砻江、黄河上游、大渡河、南盘江-红水河、乌江和西南诸河等流域总技术可开发量约3.81亿kW占全国技术可开发量的55.5%。截至2023年年底雅砻江、金沙江、大渡河、乌江、长江上游、南盘江-红水河等流域已建和在建比例超80%,水能资源开发程度较高,剩余待开发水利资源主要集中在西南诸河,发展潜力巨大。') const title_text = ref(
"我国水能资源丰富,主要集中在金沙江、长江上游、雅砻江、黄河上游、大渡河、南盘江-红水河、乌江和西南诸河等流域总技术可开发量约3.81亿kW占全国技术可开发量的55.5%。截至2023年年底雅砻江、金沙江、大渡河、乌江、长江上游、南盘江-红水河等流域已建和在建比例超80%,水能资源开发程度较高,剩余待开发水利资源主要集中在西南诸河,发展潜力巨大。"
);
watch(
() => JidiSelectEventStore.selectedItem,
(newVal) => {
console.log(newVal);
if (newVal.name == '当前全部') {
}
},
{ deep: true }
);
// //
onMounted(() => { onMounted(() => {});
});
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -3,12 +3,11 @@ import { ref } from "vue";
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
const loading = ref(false); const loading = ref(false);
const isOpen = ref(true); const isOpen = ref(true);
const jidiData = useJidiSelectEventStore().jidiData; const JidiSelectEventStore = useJidiSelectEventStore();
const jidiDataNum = ref(9); const jidiDataNum = ref(9);
const selectedItem: any = ref(1); const itemClick = (index: any) => {
const itemClick = (id: any) => { useJidiSelectEventStore().updataJidiData(index);
selectedItem.value = id;
}; };
</script> </script>
@ -17,7 +16,7 @@ const itemClick = (id: any) => {
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<div <div
class="qgc-dropdown-select" class="qgc-dropdown-select"
@mouseenter="jidiDataNum = jidiData.length" @mouseenter="jidiDataNum = JidiSelectEventStore.jidiData.length"
@mouseleave="jidiDataNum = 9" @mouseleave="jidiDataNum = 9"
> >
<div class="title" @click="isOpen = !isOpen"> <div class="title" @click="isOpen = !isOpen">
@ -29,9 +28,9 @@ const itemClick = (id: any) => {
<div <div
v-if="isOpen" v-if="isOpen"
class="item" class="item"
v-for="i in jidiData.slice(0, jidiDataNum)" v-for="(i, index) in JidiSelectEventStore.jidiData.slice(0, jidiDataNum)"
:class="{ selected: selectedItem === i.id }" :class="{ selected: i.selected }"
@click="itemClick(i.id)" @click="itemClick(index)"
> >
<i class="icon iconfont icon-hydroPower"></i> <i class="icon iconfont icon-hydroPower"></i>
<span style="margin-left: 10px">{{ i.name }}</span> <span style="margin-left: 10px">{{ i.name }}</span>

View File

@ -5,51 +5,72 @@ export const useJidiSelectEventStore = defineStore('jidiSelectEvent', () => {
const jidiData = ref([ const jidiData = ref([
{ {
id: 1, id: 1,
name: "当前全部", name: '当前全部',
selected: true
}, },
{ {
id: 2, id: 2,
name: "水电基地2", name: '水电基地2',
selected: false
}, },
{ {
id: 3, id: 3,
name: "水电基地3", name: '水电基地3',
selected: false
}, },
{ {
id: 4, id: 4,
name: "水电基地4", name: '水电基地4',
selected: false
}, },
{ {
id: 5, id: 5,
name: "水电基地5", name: '水电基地5',
selected: false
}, },
{ {
id: 6, id: 6,
name: "水电基地6", name: '水电基地6',
selected: false
}, },
{ {
id: 7, id: 7,
name: "水电基地7", name: '水电基地7',
selected: false
}, },
{ {
id: 8, id: 8,
name: "水电基地8", name: '水电基地8',
selected: false
}, },
{ {
id: 9, id: 9,
name: "水电基地9", name: '水电基地9',
selected: false
}, },
{ {
id: 10, id: 10,
name: "水电基地10", name: '水电基地10',
selected: false
}, },
{ {
id: 11, id: 11,
name: "水电基地11", name: '水电基地11',
}, selected: false
}
]); ]);
const selectedItem = ref(jidiData.value[0]);
const updataJidiData = (index: any) => {
selectedItem.value = jidiData.value[index];
jidiData.value.forEach((item: any) => {
item.selected = false;
});
jidiData.value[index].selected = true;
};
return { return {
jidiData jidiData,
selectedItem,
updataJidiData
}; };
}); });

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,22 @@ body::-webkit-scrollbar {
width: 0; width: 0;
height: 0; height: 0;
} }
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-corner {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
border-radius: 4px;
background: #bbb;
-webkit-box-shadow: inset 0 0 6px #ddd;
}
::-webkit-scrollbar-track {
border-radius: 10px;
width: 10px;
}
// main-container global css // main-container global css
.app-container { .app-container {
padding: 20px; padding: 20px;
@ -79,4 +95,3 @@ svg {
height: 98%; height: 98%;
position: relative; position: relative;
} }

View File

@ -95,3 +95,19 @@ export function downloadFile(obj :any, name :any, suffix :any) {
link.click() link.click()
document.body.removeChild(link) document.body.removeChild(link)
} }
const modules = import.meta.glob('@/assets/legend/*.svg', { eager: true });
// 图例图标映射
export const iconMap: Record<string, string> = {};
Object.entries(modules).forEach(([path, module]) => {
const fileName = path.match(/\/([^/]+)\.svg$/)?.[1];
console.log(fileName)
if (fileName) {
iconMap[fileName] = (module as any).default;
}
});
// 获取图标路径
export const getIconPath = (icon: string): string => {
console.log(iconMap[icon] )
return iconMap[icon] || '';
};

View File

@ -33,8 +33,8 @@ service.interceptors.request.use(
service.interceptors.response.use( service.interceptors.response.use(
(response: AxiosResponse) => { (response: AxiosResponse) => {
const { status, msg } = response; const { status, msg } = response;
console.log(msg) // console.log(msg)
console.log(response); // console.log(response);
if (status === 200) { if (status === 200) {
if (response.data.code == 401) { if (response.data.code == 401) {
message.error(response.data.msg||'请求失败'); message.error(response.data.msg||'请求失败');