diff --git a/config/config.ts b/config/config.ts index e660b9e4e84ed15f6c30efa09c97dba0b11348a9..57b9f66ab4151cf5c83a6bd51f0e8cd9c51555a8 100644 --- a/config/config.ts +++ b/config/config.ts @@ -30,6 +30,11 @@ export default defineConfig({ cssLoaderModules: { exportLocalsConvention: 'camelCase', }, + headScripts: [ + { + src: '//api.map.baidu.com/api?type=webgl&v=1.0&ak=U5XoaKW8QCNaROPQ96oh5a7NlVP9N4hW"', + }, + ], base: '/cd-comprehensive/', publicPath: '/cd-comprehensive/', hash: true, diff --git a/package.json b/package.json index 153644849d6530842a159075166e3e71f54f02ea..b7cf5742c1a7e5579d87392aeaa1a9745863352b 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "dependencies": { "@ant-design/icons": "^5.0.1", "@ant-design/pro-components": "^2.4.4", + "@types/bmapgl": "^0.0.7", "@types/crypto-js": "^4.2.2", "@types/lodash": "^4.17.12", "@umijs/max": "^4.3.1", @@ -27,6 +28,7 @@ "gsap": "^3.12.5", "js-base64": "^3.7.7", "lodash": "^4.17.21", + "react-bmapgl": "^0.2.28", "react-countup": "^6.5.3", "react-infinite-scroller": "^1.2.6" }, diff --git a/src/assets/images/keyArea/avatar.png b/src/assets/images/keyArea/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..f5f059ae7586cd3c66d27e8576f023e7b1ba516e Binary files /dev/null and b/src/assets/images/keyArea/avatar.png differ diff --git a/src/assets/images/keyArea/img.png b/src/assets/images/keyArea/img.png new file mode 100644 index 0000000000000000000000000000000000000000..c8230a6b4fa0a65a8d7451fa5143d9a7117f46b9 Binary files /dev/null and b/src/assets/images/keyArea/img.png differ diff --git a/src/components/MapView/index.less b/src/components/MapView/index.less new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/components/MapView/index.tsx b/src/components/MapView/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9e7465c085c2a758761e1f16e680931cc1624c07 --- /dev/null +++ b/src/components/MapView/index.tsx @@ -0,0 +1,22 @@ +import { forwardRef, PropsWithChildren } from 'react'; +import { Map } from 'react-bmapgl'; +import type { MapProps } from 'react-bmapgl/dist/Map/Map'; +import mapStyle from './mapStyle.json'; +interface PropsType extends MapProps {} + +/** 封装地图 */ +const MapView = forwardRef<any, PropsWithChildren<PropsType>>((props, ref) => { + const { children, ...reset } = props; + return ( + <Map + enableScrollWheelZoom + ref={ref} + mapStyleV2={{ styleJson: mapStyle }} + {...reset} + > + {children} + </Map> + ); +}); + +export default MapView; diff --git a/src/components/MapView/mapStyle.json b/src/components/MapView/mapStyle.json new file mode 100644 index 0000000000000000000000000000000000000000..ec4143baa5ace1bb323c1fb7dd4df10fca1be9ca --- /dev/null +++ b/src/components/MapView/mapStyle.json @@ -0,0 +1,1323 @@ +[ + { + "featureType": "land", + "elementType": "geometry", + "stylers": { + "color": "#1e588bff" + } + }, + { + "featureType": "water", + "elementType": "geometry", + "stylers": { + "color": "#3472c0ff", + "opacity": "3b" + } + }, + { + "featureType": "green", + "elementType": "geometry", + "stylers": { + "color": "#3bff65ff", + "opacity": "21" + } + }, + { + "featureType": "building", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "manmade", + "elementType": "geometry", + "stylers": { + "color": "#414a64ff", + "opacity": "14" + } + }, + { + "featureType": "local", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "subwaystation", + "elementType": "geometry", + "stylers": { + "color": "#113549ff" + } + }, + { + "featureType": "education", + "elementType": "geometry", + "stylers": { + "color": "#2ea1b9ff", + "opacity": "1a" + } + }, + { + "featureType": "road", + "elementType": "geometry.stroke", + "stylers": { + "color": "#1a3158ff", + "opacity": "14" + } + }, + { + "featureType": "railway", + "elementType": "geometry", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "poilabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "poilabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "highway", + "elementType": "geometry.fill", + "stylers": { + "color": "#87b0d4ff", + "opacity": "ed" + } + }, + { + "featureType": "cityhighway", + "elementType": "geometry.fill", + "stylers": { + "color": "#87b0d4ff", + "opacity": "82" + } + }, + { + "featureType": "road", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "districtlabel", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff" + } + }, + { + "featureType": "districtlabel", + "elementType": "labels.text.fill", + "stylers": { + "color": "#a4c2e2ff" + } + }, + { + "featureType": "manmade", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#102031ff", + "opacity": "7a" + } + }, + { + "featureType": "manmade", + "elementType": "labels.text.fill", + "stylers": { + "color": "#8ec1e6ff", + "opacity": "7a" + } + }, + { + "featureType": "shopping", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "road", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "ff", + "weight": "2" + } + }, + { + "featureType": "road", + "elementType": "labels.text.fill", + "stylers": { + "color": "#c2d9f1ff", + "opacity": "d9" + } + }, + { + "featureType": "entertainment", + "elementType": "geometry", + "stylers": { + "visibility": "on", + "color": "#ebaff8ff", + "opacity": "14" + } + }, + { + "featureType": "medical", + "elementType": "geometry", + "stylers": { + "color": "#ffa3b6ff", + "opacity": "1a" + } + }, + { + "featureType": "medical", + "elementType": "labels.text.fill", + "stylers": { + "color": "#ffcdcdff", + "opacity": "70" + } + }, + { + "featureType": "education", + "elementType": "labels.text.fill", + "stylers": { + "color": "#7ae8ffff", + "opacity": "70" + } + }, + { + "featureType": "water", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#102031ff" + } + }, + { + "featureType": "water", + "elementType": "labels.text.fill", + "stylers": { + "color": "#dfe8ffff" + } + }, + { + "featureType": "subwaylabel", + "elementType": "labels", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "subwaylabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "highrailway", + "elementType": "geometry", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "local", + "elementType": "labels.icon", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "local", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "arterial", + "elementType": "labels.icon", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "arterial", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "cityhighway", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "provincialway", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "nationalway", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "tertiaryway", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "tertiaryway", + "elementType": "labels.text", + "stylers": { + "fontsize": "30" + } + }, + { + "featureType": "nationalway", + "elementType": "labels.text", + "stylers": { + "fontsize": "30" + } + }, + { + "featureType": "provincialway", + "elementType": "labels.text", + "stylers": { + "fontsize": "30" + } + }, + { + "featureType": "cityhighway", + "elementType": "labels.text", + "stylers": { + "fontsize": "30" + } + }, + { + "featureType": "arterial", + "elementType": "labels.text", + "stylers": { + "fontsize": "30" + } + }, + { + "featureType": "fourlevelway", + "elementType": "labels.text", + "stylers": { + "fontsize": "30" + } + }, + { + "featureType": "road", + "elementType": "labels.text", + "stylers": { + "fontsize": "34" + } + }, + { + "featureType": "highway", + "elementType": "labels.text", + "stylers": { + "fontsize": "30" + } + }, + { + "featureType": "highwaysign", + "elementType": "labels.text.fill", + "stylers": { + "color": "#ffffffff" + } + }, + { + "featureType": "provincialwaysign", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "73", + "weight": "1" + } + }, + { + "featureType": "nationalwaysign", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "4f" + } + }, + { + "featureType": "nationalwaysign", + "elementType": "labels.text.fill", + "stylers": { + "color": "#fdfbfbff" + } + }, + { + "featureType": "provincialwaysign", + "elementType": "labels.text.fill", + "stylers": { + "color": "#fdfcfcff" + } + }, + { + "featureType": "subwaylabel", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "80" + } + }, + { + "featureType": "subwaylabel", + "elementType": "labels.text.fill", + "stylers": { + "color": "#ffffffff" + } + }, + { + "featureType": "tertiarywaysign", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "00" + } + }, + { + "featureType": "tertiarywaysign", + "elementType": "labels.text.fill", + "stylers": { + "color": "#112031ff" + } + }, + { + "featureType": "subway", + "elementType": "geometry.fill", + "stylers": { + "color": "#15be6cff", + "opacity": "80" + } + }, + { + "featureType": "transportation", + "elementType": "geometry", + "stylers": { + "visibility": "on", + "opacity": "14" + } + }, + { + "featureType": "nationalway", + "elementType": "geometry.fill", + "stylers": { + "color": "#87b0d4ff", + "opacity": "ff" + } + }, + { + "featureType": "provincialway", + "elementType": "geometry.fill", + "stylers": { + "color": "#87b0d4ff" + } + }, + { + "featureType": "subway", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "subway", + "elementType": "labels", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "highwaysign", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#141616ff", + "opacity": "4f" + } + }, + { + "featureType": "vacationway", + "elementType": "geometry", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "scenicspotsway", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "local", + "elementType": "geometry.fill", + "stylers": { + "color": "#a39999ff", + "opacity": "1c" + } + }, + { + "featureType": "fourlevelway", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "scenicspots", + "elementType": "geometry", + "stylers": { + "color": "#3bff65ff", + "opacity": "0f" + } + }, + { + "featureType": "scenicspots", + "elementType": "labels.text", + "stylers": { + "fontsize": "28" + } + }, + { + "featureType": "scenicspots", + "elementType": "labels.text.fill", + "stylers": { + "color": "#fffeeeff" + } + }, + { + "featureType": "scenicspots", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#14180aff", + "opacity": "4a" + } + }, + { + "featureType": "water", + "elementType": "labels.text", + "stylers": { + "fontsize": "26" + } + }, + { + "featureType": "manmade", + "elementType": "labels.text", + "stylers": { + "fontsize": "26" + } + }, + { + "featureType": "education", + "elementType": "labels.text", + "stylers": { + "fontsize": "26" + } + }, + { + "featureType": "HDLLCX", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "HDLLDX", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "HDLLSS", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "trafficlight", + "elementType": "labels.icon", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "HDLLSX", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "HDLLZSYX", + "elementType": "geometry", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "HDLLZXYS", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "HDLLDS", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "HDLLDD", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "roadarrow", + "elementType": "labels.icon", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "HDLLDS", + "elementType": "geometry.fill", + "stylers": { + "color": "#722c2cff", + "opacity": "0f" + } + }, + { + "featureType": "HDTEXTBUS", + "elementType": "labels.text.fill", + "stylers": { + "color": "#f3efa9ff" + } + }, + { + "featureType": "footbridge", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "highwaysign", + "elementType": "labels", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "highwaysign", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "nationalwaysign", + "elementType": "labels", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "nationalwaysign", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "provincialwaysign", + "elementType": "labels", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "provincialwaysign", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "tertiarywaysign", + "elementType": "labels", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "tertiarywaysign", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "local", + "stylers": { + "level": "18", + "curZoomRegionId": "0", + "curZoomRegion": "18-21" + } + }, + { + "featureType": "local", + "stylers": { + "level": "19", + "curZoomRegionId": "0", + "curZoomRegion": "18-21" + } + }, + { + "featureType": "local", + "stylers": { + "level": "20", + "curZoomRegionId": "0", + "curZoomRegion": "18-21" + } + }, + { + "featureType": "local", + "stylers": { + "level": "21", + "curZoomRegionId": "0", + "curZoomRegion": "18-21" + } + }, + { + "featureType": "local", + "stylers": { + "level": "16", + "curZoomRegionId": "1", + "curZoomRegion": "16-17" + } + }, + { + "featureType": "local", + "stylers": { + "level": "17", + "curZoomRegionId": "1", + "curZoomRegion": "16-17" + } + }, + { + "featureType": "local", + "elementType": "geometry", + "stylers": { + "visibility": "off", + "level": "16", + "curZoomRegionId": "1", + "curZoomRegion": "16-17" + } + }, + { + "featureType": "local", + "elementType": "geometry", + "stylers": { + "visibility": "off", + "level": "17", + "curZoomRegionId": "1", + "curZoomRegion": "16-17" + } + }, + { + "featureType": "local", + "elementType": "labels", + "stylers": { + "visibility": "off", + "level": "16", + "curZoomRegionId": "1", + "curZoomRegion": "16-17" + } + }, + { + "featureType": "local", + "elementType": "labels", + "stylers": { + "visibility": "off", + "level": "17", + "curZoomRegionId": "1", + "curZoomRegion": "16-17" + } + }, + { + "featureType": "local", + "elementType": "labels.icon", + "stylers": { + "visibility": "off", + "level": "16", + "curZoomRegionId": "1", + "curZoomRegion": "16-17" + } + }, + { + "featureType": "local", + "elementType": "labels.icon", + "stylers": { + "visibility": "off", + "level": "17", + "curZoomRegionId": "1", + "curZoomRegion": "16-17" + } + }, + { + "featureType": "local", + "elementType": "geometry.stroke", + "stylers": { + "opacity": "7a" + } + }, + { + "featureType": "subway", + "elementType": "geometry", + "stylers": { + "visibility": "off", + "weight": "6" + } + }, + { + "featureType": "road", + "elementType": "geometry.fill", + "stylers": { + "color": "#708fb6ff" + } + }, + { + "featureType": "education", + "elementType": "labels.text.stroke", + "stylers": { + "opacity": "75" + } + }, + { + "featureType": "medical", + "elementType": "labels.text.stroke", + "stylers": { + "opacity": "70" + } + }, + { + "featureType": "entertainmentlabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "estatelabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "businesstowerlabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "businesstowerlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "companylabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "restaurantlabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "restaurantlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "hotellabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "hotellabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "shoppinglabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "shoppinglabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "lifeservicelabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "lifeservicelabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "carservicelabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "carservicelabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "transportationlabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "transportationlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "trainstationlabel", + "elementType": "labels", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "trainstationlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "parklotinlabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "parklotinlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "parklotoutlabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "parklotoutlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "parklotlabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "parklotlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "subwaypoilabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "subwaypoilabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "transportationother", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "transportationother", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "financelabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "financelabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "INTERNATIONALIZEICONICON", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "INTERNATIONALIZEICONICON", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "airportlabel", + "elementType": "labels.text", + "stylers": { + "fontsize": "26" + } + }, + { + "featureType": "airportlabel", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "4f" + } + }, + { + "featureType": "airportlabel", + "elementType": "labels.text.fill", + "stylers": { + "color": "#f6f4f4ff" + } + }, + { + "featureType": "scenicspotslabel", + "elementType": "labels.text", + "stylers": { + "fontsize": "24" + } + }, + { + "featureType": "scenicspotslabel", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "5c" + } + }, + { + "featureType": "scenicspotslabel", + "elementType": "labels.text.fill", + "stylers": { + "color": "#fcfafaff", + "opacity": "7a" + } + }, + { + "featureType": "educationlabel", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "7a" + } + }, + { + "featureType": "educationlabel", + "elementType": "labels.text.fill", + "stylers": { + "color": "#fcfafaff", + "opacity": "7a" + } + }, + { + "featureType": "medicallabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "estatelabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "companylabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "governmentlabel", + "elementType": "labels.text.fill", + "stylers": { + "color": "#ffffffff", + "opacity": "73" + } + }, + { + "featureType": "governmentlabel", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "69" + } + }, + { + "featureType": "trainstationlabel", + "elementType": "labels.text.fill", + "stylers": { + "color": "#f8f1f1ff", + "opacity": "70" + } + }, + { + "featureType": "trainstationlabel", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "75" + } + }, + { + "featureType": "busstationlabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "busstationlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "medicallabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "poilabel", + "elementType": "labels.text.fill", + "stylers": { + "color": "#f8f7f7ff", + "opacity": "75" + } + }, + { + "featureType": "poilabel", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "6e" + } + }, + { + "featureType": "subwaypoilabel", + "elementType": "labels.text.fill", + "stylers": { + "color": "#ffffffff", + "opacity": "c9" + } + }, + { + "featureType": "subwaypoilabel", + "elementType": "labels.text.stroke", + "stylers": { + "color": "#112031ff", + "opacity": "85" + } + }, + { + "featureType": "building", + "elementType": "geometry.topfill", + "stylers": { + "color": "#3a4658ff" + } + }, + { + "featureType": "building", + "elementType": "geometry.sidefill", + "stylers": { + "color": "#1c2431ff" + } + }, + { + "featureType": "highway", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "tertiaryway", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "entertainmentlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "educationlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "educationlabel", + "elementType": "labels", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "transportationother", + "elementType": "labels.text", + "stylers": { + "fontsize": "26" + } + }, + { + "featureType": "road", + "elementType": "geometry", + "stylers": { + "visibility": "on" + } + }, + { + "featureType": "scenicspotslabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "airportlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + }, + { + "featureType": "governmentlabel", + "elementType": "labels.icon", + "stylers": { + "visibility": "off" + } + } +] diff --git a/src/models/regionalIndex.ts b/src/models/regionalIndex.ts new file mode 100644 index 0000000000000000000000000000000000000000..f56f27fda133161ee39146eff6202989e9dc87d0 --- /dev/null +++ b/src/models/regionalIndex.ts @@ -0,0 +1,44 @@ +import services from '@/services'; +import { useState } from 'react'; + +/** + * 地区指数 + * @module TheOperationOfTheDistrictCityAndCounty + * @description 地区列表的管理 + * + */ +const useRegionalIndex = () => { + const [areaListDto, setAreaListDto] = useState< + DistrictAPI.RealtimeIndexDTO[] + >([]); + /** 当前选择的区市县 */ + const [selectDistrict, setSelectDistrict] = + useState<DistrictAPI.RealtimeIndexDTO>(); + + /** 列表加载状态 */ + const [loading, setLoading] = useState(false); + + /** 获取地区列表 */ + const getAreaListDto = async () => { + setLoading(true); + + services.districtController + .getDistrictIndexList() + .then((res) => { + setAreaListDto(res.data); + }) + .finally(() => { + setLoading(false); + }); + }; + + return { + areaListDto, + loading, + getAreaListDto, + selectDistrict, + setSelectDistrict, + }; +}; + +export default useRegionalIndex; diff --git a/src/pages/GlobalModalServices/modals/DistrictIndex/StreetMap/index.less b/src/pages/GlobalModalServices/modals/DistrictIndex/StreetMap/index.less index 97125c3058bc5bd861ea82d7a804f2ca7a6b94ed..b3de4d2d878723bce32ab02a809ed9437eeee59f 100644 --- a/src/pages/GlobalModalServices/modals/DistrictIndex/StreetMap/index.less +++ b/src/pages/GlobalModalServices/modals/DistrictIndex/StreetMap/index.less @@ -11,6 +11,8 @@ .statusBar { position: absolute; top: 10px; + z-index: 100; + right: 10px; width: 625px; height: 39px; @@ -37,6 +39,8 @@ height: 40px; position: absolute; top: 30px; + z-index: 100; + left: 40px; } @@ -72,6 +76,7 @@ height: 605px; top: 90px; left: 0; + z-index: 100; border-radius: 0px 0 20px 0px; -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px); @@ -191,3 +196,18 @@ height: 350px; overflow: auto; } + +.indexMarker { + width: 44px; + height: 44px; + box-sizing: border-box; + border: 3px solid rgba(255, 255, 255, 0.5); + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.5); + background: var(--bg-color); + border-radius: 22px; + display: flex; + align-items: center; + justify-content: center; + + color: var(--color); +} diff --git a/src/pages/GlobalModalServices/modals/DistrictIndex/StreetMap/index.tsx b/src/pages/GlobalModalServices/modals/DistrictIndex/StreetMap/index.tsx index 1aeca7f9d522f6305133db630f2e59ec4d9cba48..ac668a30c1a7f02cc9d5bdb4e1e83d6cb92bc11e 100644 --- a/src/pages/GlobalModalServices/modals/DistrictIndex/StreetMap/index.tsx +++ b/src/pages/GlobalModalServices/modals/DistrictIndex/StreetMap/index.tsx @@ -1,9 +1,20 @@ +import MapView from '@/components/MapView'; +import BMapService from '@/utils/mapService'; +import { getColorByIndex } from '@/utils/ui'; import { DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons'; +import { useModel } from '@umijs/max'; import { useToggle } from 'ahooks'; import { ConfigProvider, Flex, Input, Popover, Space } from 'antd'; import classNames from 'classnames'; import gsap from 'gsap'; -import React, { useRef, useState } from 'react'; +import React, { + CSSProperties, + Fragment, + useEffect, + useRef, + useState, +} from 'react'; +import { CustomOverlay, Polygon } from 'react-bmapgl'; import PopoverCard from '../PopoverCard'; import styles from './index.less'; @@ -12,6 +23,10 @@ const StreetMap: React.FC = () => { const [state, { toggle }] = useToggle('left', 'right'); const listRef = useRef<HTMLDivElement>(null); const [expandStatus, setExpandStatus] = useState(true); + /** @description store */ + const { selectDistrict, areaListDto } = useModel('regionalIndex'); + + const MapRef = useRef<any>(); const expandSlider = () => { if (expandStatus === true) { @@ -98,6 +113,28 @@ const StreetMap: React.FC = () => { </Popover> ); }; + + /** + * @description 设置地图视野 + */ + const setViewport = () => { + const points = areaListDto + .map((item) => { + return BMapService.buildPoints(item.points); + }) + .flat(1); + + const map = MapRef.current?.map as BMapGL.Map; + if (map) { + map.setViewport(points); + } + }; + /** @description 移动视角到能显示全部覆盖物 */ + useEffect(() => { + setTimeout(() => { + setViewport(); + }, 500); + }, [MapRef.current, areaListDto]); const data = [ { name: '华阳街道', @@ -178,15 +215,49 @@ const StreetMap: React.FC = () => { }, ]; return ( - <div - className={styles.container} - style={{ - backgroundImage: - state === 'left' - ? 'url(' + require('@/assets/images/map/mapDemo3.png') + ')' - : 'url(' + require('@/assets/images/map/mapDemo4.png') + ')', - }} - > + <div className={styles.container}> + <MapView + zoom={13} + ref={MapRef} + style={{ width: '100%', height: '110%' }} + center={new BMapGL.Point(104.066349, 30.658842)} + > + <Fragment> + {areaListDto.map((item, index) => { + return ( + <Polygon + fillColor={getColorByIndex(Number(item.qualitySign))} + key={index} + strokeColor="#fff" + fillOpacity={0.3} + strokeWeight={2} + path={BMapService.buildPoints(item.points)} + ></Polygon> + ); + })} + {areaListDto.map((item, index) => { + const point = BMapService.buildPoint( + Number(item.centerX), + Number(item.centerY), + ); + + return ( + <CustomOverlay position={point}> + <div + className={styles.indexMarker} + style={ + BMapService.getMakerCSS( + Number(item.qualitySign), + ) as CSSProperties + } + > + {Number(item.qualitySign)} + </div> + </CustomOverlay> + ); + })} + </Fragment> + </MapView> <div className={styles.btnGroup}> <div onClick={toggle} diff --git a/src/pages/GlobalModalServices/modals/KeyArea/Map/index.less b/src/pages/GlobalModalServices/modals/KeyArea/Map/index.less index 66f7543d800285892ea58547a83aa1fcbeef48d6..417b557e4f528091bb67bde66e5dcb275489d308 100644 --- a/src/pages/GlobalModalServices/modals/KeyArea/Map/index.less +++ b/src/pages/GlobalModalServices/modals/KeyArea/Map/index.less @@ -1,8 +1,7 @@ .container { height: 710px; width: 2014px; - background-image: url(@/assets/images/keyArea/mapBg.png); - background-size: 100% 100%; + overflow: hidden; position: relative; > img { @@ -26,6 +25,7 @@ position: absolute; right: 30px; bottom: 30px; + z-index: 1001; > div { width: 40px; @@ -48,6 +48,8 @@ top: 10px; right: 10px; width: 625px; + z-index: 1001; + height: 39px; border-radius: 10px; background: rgba(2, 106, 167, 0.9); @@ -68,6 +70,7 @@ .leftList { width: 352px; height: 605px; + z-index: 1001; border-radius: 0px 20px 20px 0px; -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px); @@ -128,3 +131,36 @@ } } } + +.indexMarker { + display: flex; + flex-direction: column; + align-items: center; +} +.markerIcon { + width: 22px; + height: 22px; + box-sizing: border-box; + border: 4px solid rgb(87, 239, 88); + background: rgba(87, 239, 88, 0.1); + border-radius: 50%; +} + +.markerContent { + background-color: rgba(33, 50, 88, 0.9); + border-radius: 10px; + color: #fff; + font-weight: 700; + white-space: nowrap; + margin-bottom: 10px; + display: flex; + align-items: center; + padding: 4px 15px; + cursor: pointer; + + > span { + font-size: 28px; + font-family: D-DIN; + margin-left: 12px; + } +} diff --git a/src/pages/GlobalModalServices/modals/KeyArea/Map/index.tsx b/src/pages/GlobalModalServices/modals/KeyArea/Map/index.tsx index 79a13832368f8f03996d5288a7955fa7f0b54cb4..f5068d812fd55cdfe98fd85885e8a52af0d09961 100644 --- a/src/pages/GlobalModalServices/modals/KeyArea/Map/index.tsx +++ b/src/pages/GlobalModalServices/modals/KeyArea/Map/index.tsx @@ -1,3 +1,4 @@ +import MapView from '@/components/MapView'; import { useGlobalModalServices } from '@/pages/GlobalModalServices/provider'; import { getColorByIndex } from '@/utils/ui'; import { @@ -7,13 +8,17 @@ import { UpCircleFilled, } from '@ant-design/icons'; import { Flex, Space } from 'antd'; -import React, { useRef, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; +import { CustomOverlay } from 'react-bmapgl'; import styles from './index.less'; const Map: React.FC = () => { const [expand, setExpand] = useState<number>(); const ref = useRef(0); const { dispatch } = useGlobalModalServices(); + + const MapRef = useRef<any>(); + const data = [ { name: '党政机关', @@ -86,8 +91,76 @@ const Map: React.FC = () => { ], }, ]; + + const addZoom = () => { + const map = MapRef.current?.map as BMapGL.Map; + map.centerAndZoom(map.getCenter(), map.getZoom() + 1); + }; + + const reduceZoom = () => { + const map = MapRef.current?.map as BMapGL.Map; + map.centerAndZoom(map.getCenter(), map.getZoom() - 1); + }; + + const p1 = new BMapGL.Point(103.74243115816007, 30.79721665183887); + + const p2 = new BMapGL.Point(104.48437948789275, 30.807638945537175); + + /** + * @description 设置地图视野 + */ + const setViewport = () => { + // const map = MapRef.current?.map as BMapGL.Map; + // if (map) { + // map.setViewport([p1, p2]); + // } + }; + + /** @description 移动视角到能显示全部覆盖物 */ + useEffect(() => { + setViewport(); + }, [MapRef.current]); return ( <div className={styles.container}> + <MapView + zoom={13} + ref={MapRef} + style={{ width: '100%', height: '110%' }} + center={new BMapGL.Point(104.066349, 30.658842)} + onClick={(e) => console.log(e)} + > + <CustomOverlay position={p1}> + <div + className={styles.indexMarker} + onClick={(e) => { + e.stopPropagation(); + + dispatch.push('KeyAreaDetail', { + title: '市委市政府', + }); + }} + > + <div className={styles.markerContent}> + 市委市政府<span style={{ color: getColorByIndex(89) }}>89</span> + </div> + <div + className={styles.markerIcon} + style={{ borderColor: getColorByIndex(89) }} + ></div> + </div> + </CustomOverlay> + <CustomOverlay position={p2}> + <div className={styles.indexMarker}> + <div className={styles.markerContent}> + 市城管委<span style={{ color: getColorByIndex(98.5) }}>98.5</span> + </div> + <div + className={styles.markerIcon} + style={{ borderColor: getColorByIndex(98.5) }} + ></div> + </div> + </CustomOverlay> + </MapView> <div className={styles.leftList}> <div className={styles.listTitle}>重点区域列表</div> <div> @@ -143,24 +216,7 @@ const Map: React.FC = () => { })} </div> </div> - <img - src={require('@/assets/images/keyArea/mark1.png')} - alt="" - onClick={() => { - dispatch.push('KeyAreaDetail', { - title: '市委市政府', - }); - }} - ></img> - <img - src={require('@/assets/images/keyArea/mark2.png')} - onClick={() => { - dispatch.push('KeyAreaDetail', { - title: '市城管委', - }); - }} - alt="" - ></img> + <div className={styles.statusBar}> <Space> <div className={styles.mark} style={{ backgroundColor: '#F24F4F' }} /> @@ -184,10 +240,10 @@ const Map: React.FC = () => { <img src={require('@/assets/images/map/mapReload.png')} alt="" /> </div> <div> - <PlusOutlined /> + <PlusOutlined onClick={addZoom} /> </div> <div> - <MinusOutlined /> + <MinusOutlined onClick={reduceZoom} /> </div> </div> </div> diff --git a/src/pages/GlobalModalServices/modals/KeyAreaDetail/FilterTree/index.tsx b/src/pages/GlobalModalServices/modals/KeyAreaDetail/FilterTree/index.tsx index 7303bb2585497ba4e22390dc86d9067ab7ac8de9..cbff490a4a0032ddef449d62280ac1ca278f0902 100644 --- a/src/pages/GlobalModalServices/modals/KeyAreaDetail/FilterTree/index.tsx +++ b/src/pages/GlobalModalServices/modals/KeyAreaDetail/FilterTree/index.tsx @@ -132,7 +132,7 @@ const FilterTree: React.FC = () => { <img src={require('@/assets/images/keyArea/people.png')} alt="" - ></img> + /> <div className={styles.checkTitle2}>监督员</div> </Flex> </Checkbox> diff --git a/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/components/InfoWindow/index.less b/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/components/InfoWindow/index.less new file mode 100644 index 0000000000000000000000000000000000000000..7367966c04b375ae0ac87645fe116e516681afcb --- /dev/null +++ b/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/components/InfoWindow/index.less @@ -0,0 +1,174 @@ +.window { + box-sizing: border-box; + border: 2px solid rgba(64, 146, 217, 0.95); + border-radius: 10px; + background: rgb(3, 85, 135); + width: 460px; + + &::after { + position: absolute; + content: ''; + /**三角形 */ + width: 0; + height: 0; + border-style: solid; + border-width: 10px 10px 0 10px; + border-color: rgb(3, 85, 135) transparent transparent transparent; + bottom: -7px; + left: 50%; + transform: translateX(-50%); + z-index: 999; + } + &::before { + position: absolute; + content: ''; + /**三角形 */ + width: 0; + height: 0; + border-style: solid; + border-width: 10px 10px 0 10px; + border-color: rgba(64, 146, 217, 0.95) transparent transparent transparent; + bottom: -10px; + left: 50%; + transform: translateX(-50%); + z-index: 998; + } +} + +.header { + white-space: nowrap; + color: rgb(255, 255, 255); + font-family: 'DingTalk JinBuTi'; + display: flex; + justify-content: space-between; + font-size: 24px; + font-weight: 400; + height: 54px; + padding: 0 24px; + align-items: center; + border-bottom: 2px solid rgb(62, 145, 215); +} + +.content { + padding: 20px; +} + +.btnGroup { + display: flex; + align-items: center; + justify-content: center; + margin-top: 16px; + gap: 12px; + + .btn { + border-radius: 25px; + background: linear-gradient( + 180deg, + rgb(28, 192, 255), + rgb(82, 148, 255) 100% + ); + padding: 0 16px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + } +} + +.type1Content { + position: relative; + + .qImg { + width: 100%; + height: 157px; + } + + .overTime { + position: absolute; + border-radius: 13.5px; + color: rgb(255, 167, 95); + background: rgba(0, 0, 0, 50%); + padding: 4px 12px; + right: 16px; + top: 120px; + } + + .toBeProcessed { + position: absolute; + border-radius: 13.5px; + color: rgb(102, 165, 255); + background: rgba(0, 0, 0, 50%); + padding: 4px 12px; + right: 16px; + top: 120px; + } +} + +.type3Content { + overflow: hidden; + + .avatar { + width: 90px; + height: 90px; + } + .avatarWrapper { + flex-direction: row; + display: flex; + gap: 12px; + } +} + +.type4Content { + overflow: hidden; + + .qImg { + width: 100%; + height: 157px; + } +} + +.todayQNum { + color: rgb(255, 255, 255); + + font-size: 18px; + font-weight: 400; + + > span { + background: linear-gradient(180deg, rgb(170, 255, 246), rgb(37, 187, 255)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + margin: 0 8px; + font-family: D-DIN; + font-size: 30px; + } +} + +.type1Content { + position: relative; + + .qImg { + width: 100%; + height: 157px; + } + + .overTime { + position: absolute; + border-radius: 13.5px; + color: rgb(255, 167, 95); + background: rgba(0, 0, 0, 50%); + padding: 4px 12px; + right: 16px; + top: 120px; + } + + .toBeProcessed { + position: absolute; + border-radius: 13.5px; + color: rgb(102, 165, 255); + background: rgba(0, 0, 0, 50%); + padding: 4px 12px; + right: 16px; + top: 120px; + } +} diff --git a/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/components/InfoWindow/index.tsx b/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/components/InfoWindow/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1b64b8f1b8244eff45402456a2d17f47da76c8ed --- /dev/null +++ b/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/components/InfoWindow/index.tsx @@ -0,0 +1,268 @@ +import { CloseCircleOutlined } from '@ant-design/icons'; +import { ConfigProvider, Descriptions, Image } from 'antd'; +import React from 'react'; +import { CustomOverlay } from 'react-bmapgl'; +import styles from './index.less'; + +interface PropsType { + data: any; + map?: BMapGL.Map; + onClose?: () => void; +} + +const InfoWindow: React.FC<PropsType> = (props) => { + const { data, map, onClose } = props; + + const labelStyle = { + color: 'rgb(203, 237, 255)', + fontSize: 16, + }; + const renderContent = () => { + switch (data.type) { + case 1: + return ( + <div className={styles.type1Content}> + <Image + className={styles.qImg} + width="100%" + src={require('@/assets/images/keyArea/img.png')} + ></Image> + <div className={styles.overTime}>已超期 105 天</div> + <Descriptions + style={{ marginTop: 16 }} + column={1} + labelStyle={labelStyle} + contentStyle={{ + color: '#fff', + fontSize: 16, + }} + > + <Descriptions.Item label="上报时间"> + 2024-05-28 10:20:20 + </Descriptions.Item> + <Descriptions.Item label="发生位置"> + 锦江区牛市口街道办事... + </Descriptions.Item> + </Descriptions> + <div className={styles.btnGroup}> + <div className={styles.btn}>查看详情</div> + </div> + </div> + ); + case 2: + return ( + <div className={styles.type1Content}> + <Image + className={styles.qImg} + width="100%" + src={require('@/assets/images/keyArea/img.png')} + ></Image> + <div className={styles.toBeProcessed}>待派遣</div> + <Descriptions + style={{ marginTop: 16 }} + column={1} + labelStyle={labelStyle} + contentStyle={{ + color: '#fff', + fontSize: 16, + }} + > + <Descriptions.Item label="上报时间"> + 2024-05-28 10:20:20 + </Descriptions.Item> + <Descriptions.Item label="发生位置"> + 锦江区牛市口街道办事... + </Descriptions.Item> + </Descriptions> + <div className={styles.btnGroup}> + <div className={styles.btn}>查看详情</div> + </div> + </div> + ); + case 3: + return ( + <div className={styles.type3Content}> + <div className={styles.avatarWrapper}> + <Image + className={styles.avatar} + width={90} + height={90} + src={require('@/assets/images/keyArea/avatar.png')} + ></Image> + <Descriptions + column={1} + title={'市级监督员 - 张明明'} + labelStyle={labelStyle} + contentStyle={{ + color: '#fff', + fontSize: 16, + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + overflow: 'hidden', + }} + > + <Descriptions.Item label="工卡号"> + XDSDWE15266 + </Descriptions.Item> + <Descriptions.Item label="联系电话"> + 15887465232 + </Descriptions.Item> + </Descriptions> + </div> + <Descriptions + column={1} + labelStyle={labelStyle} + contentStyle={{ + color: '#fff', + fontSize: 16, + }} + > + <Descriptions.Item label="责任网格"> + 迪庆街道、崇阳街道、迪庆街道、崇阳街道、迪庆街道、崇阳街道、迪庆街道、崇阳街道、 + </Descriptions.Item> + </Descriptions> + <div className={styles.btnGroup}> + <div className={styles.btn}>查看详情</div> + </div> + </div> + ); + case 4: + return ( + <div className={styles.type4Content}> + <Image + className={styles.qImg} + width="100%" + src={require('@/assets/images/keyArea/img.png')} + ></Image> + + <div className={styles.btnGroup}> + <div className={styles.btn}>查看详情</div> + </div> + </div> + ); + case 5: + return ( + <div className={styles.type5Content}> + <Descriptions + style={{ marginTop: 16 }} + column={2} + labelStyle={labelStyle} + contentStyle={{ + color: '#fff', + fontSize: 16, + }} + > + <Descriptions.Item label="设备ID">SDFSDFS156</Descriptions.Item> + <Descriptions.Item label="设备类型">AI固定视频</Descriptions.Item> + <Descriptions.Item label="感知场景" span={2}> + 垃圾分类 + </Descriptions.Item> + <Descriptions.Item label="所在位置" span={2}> + XXXXXXXXXXXXXXXXXXXXXX + </Descriptions.Item> + </Descriptions> + <div className={styles.todayQNum}> + 今日识别问题<span>1208</span>件 + </div> + <div className={styles.btnGroup}> + <div className={styles.btn}>运行视频</div> + <div className={styles.btn}>发现问题</div> + </div> + </div> + ); + case 6: + return ( + <div className={styles.type6Content}> + <Descriptions + style={{ marginTop: 16 }} + column={2} + labelStyle={labelStyle} + contentStyle={{ + color: '#fff', + fontSize: 16, + }} + > + <Descriptions.Item label="设备ID">SDFSDFS156</Descriptions.Item> + <Descriptions.Item label="设备状态"> + <span style={{ color: 'green' }}>在线</span> + </Descriptions.Item> + <Descriptions.Item label="设备类型">AI车载</Descriptions.Item> + <Descriptions.Item label="车辆类型">公交车</Descriptions.Item> + </Descriptions> + <div className={styles.todayQNum}> + 今日识别问题<span>1208</span>件 + </div> + <div className={styles.btnGroup}> + <div className={styles.btn}>运行轨迹</div> + + <div className={styles.btn}>运行视频</div> + <div className={styles.btn}>识别问题</div> + <div className={styles.btn}>运行详情</div> + </div> + </div> + ); + case 7: + return ( + <div className={styles.type1Content}> + <Image + className={styles.qImg} + width="100%" + src={require('@/assets/images/keyArea/img.png')} + ></Image> + <div className={styles.toBeProcessed}>待派遣</div> + <Descriptions + style={{ marginTop: 16 }} + column={1} + labelStyle={labelStyle} + contentStyle={{ + color: '#fff', + fontSize: 16, + }} + > + <Descriptions.Item label="预警时间:"> + 2024-05-28 10:20:20 + </Descriptions.Item> + <Descriptions.Item label="预警地点:"> + 锦江区牛市口街道办事... + </Descriptions.Item> + </Descriptions> + <div className={styles.btnGroup}> + <div className={styles.btn}>查看详情</div> + </div> + </div> + ); + default: + return <div>无内容</div>; + } + }; + + return ( + <CustomOverlay + map={map!} + position={data?.l} + offset={new BMapGL.Size(0, -30)} + > + <div className={styles.window}> + <div className={styles.header}> + 道路交通设施 + <CloseCircleOutlined onClick={onClose} /> + </div> + <ConfigProvider + theme={{ + components: { + Descriptions: { + itemPaddingBottom: 4, + titleColor: '#fff', + titleMarginBottom: 10, + }, + }, + }} + > + <div className={styles.content}>{renderContent()}</div> + </ConfigProvider> + </div> + </CustomOverlay> + ); +}; + +export default InfoWindow; diff --git a/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/index.less b/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/index.less index 61f8c16d4870109b781bd504f20ee92abfa27dad..15bce0e7337b859f075d1b295f5c3c623246a4f1 100644 --- a/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/index.less +++ b/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/index.less @@ -10,11 +10,14 @@ position: absolute; left: 20px; top: 20px; + z-index: 1001; } } .onDutyWrap { position: absolute; + z-index: 1001; + width: 384px; height: 55px; border-radius: 27.5px 0px 0px 27.5px; @@ -48,6 +51,7 @@ position: absolute; width: 275px; height: 595px; + z-index: 1001; right: 0; top: 93px; padding: 20px; @@ -145,4 +149,5 @@ left: 50%; transform: translateX(-50%); bottom: 20px; + z-index: 1001; } diff --git a/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/index.tsx b/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/index.tsx index 5d92fdc0ffd32c7545a9bd96d41422fd02dbabcb..c809fd97db6d4063fd577b0cd853a4e77b950065 100644 --- a/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/index.tsx +++ b/src/pages/GlobalModalServices/modals/KeyAreaDetail/Map/index.tsx @@ -1,16 +1,21 @@ import myVideo1 from '@/assets/media/movie.mp4'; +import MapView from '@/components/MapView'; +import BMapService from '@/utils/mapService'; import { DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons'; import { Flex, Space } from 'antd'; import gsap from 'gsap'; import React, { useRef, useState } from 'react'; +import { Marker } from 'react-bmapgl'; import FilterTree from '../FilterTree'; import LiveSlideshow from '../LiveSlideshow'; +import InfoWindow from './components/InfoWindow'; import styles from './index.less'; const Map: React.FC = () => { const [expandStatus, setExpandStatus] = useState(true); const listRef = useRef<HTMLDivElement>(null); - + const MapRef = useRef<any>(); + const [selected, setSelected] = useState<any>(); const expandSlider = () => { if (expandStatus === true) { setExpandStatus(false); @@ -24,8 +29,84 @@ const Map: React.FC = () => { }); } }; + const pList = [ + { + l: BMapService.buildPoint(103.87453593938976, 30.746739203687397), + type: 1, + }, + { + l: BMapService.buildPoint(103.9541617397942, 30.735316951515046), + type: 2, + }, + { + l: BMapService.buildPoint(103.87424848162657, 30.72240319350852), + type: 3, + }, + { + l: BMapService.buildPoint(103.92455359018533, 30.71569728382409), + type: 4, + }, + { + l: BMapService.buildPoint(103.87453593938976, 30.71569728382409), + type: 5, + }, + { + l: BMapService.buildPoint(104.0033170173002, 30.69681886124258), + type: 6, + }, + { + l: BMapService.buildPoint(103.89954476478755, 30.736558566919108), + type: 7, + }, + ]; + + const iconList = { + 1: require('@/assets/images/keyArea/risk1.png'), + 2: require('@/assets/images/keyArea/risk2.png'), + 3: require('@/assets/images/keyArea/risk3.png'), + 4: require('@/assets/images/keyArea/q3.png'), + 5: require('@/assets/images/keyArea/q4.png'), + 6: require('@/assets/images/keyArea/phone.png'), + 7: require('@/assets/images/keyArea/car.png'), + 8: require('@/assets/images/keyArea/people.png'), + }; + return ( <div className={styles.container}> + <MapView + zoom={13} + ref={MapRef} + onClick={(e) => console.log(e)} + style={{ width: '100%', height: '110%' }} + center={new BMapGL.Point(104.066349, 30.658842)} + > + {pList.map((item, index) => { + return ( + <Marker + key={index} + onClick={() => { + setSelected(item); + }} + position={item.l} + icon={ + new BMapGL.Icon( + iconList[item.type] as string, + new BMapGL.Size(30, 30), + ) + } + ></Marker> + ); + })} + {selected && ( + <InfoWindow + data={selected} + onClose={() => { + setSelected(undefined); + }} + ></InfoWindow> + )} + </MapView> + <div className={styles.leftController}> <FilterTree></FilterTree> </div> diff --git a/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DIstrictDetailBar/index.less b/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DIstrictDetailBar/index.less index 3b361e48e08cc989294f9f27a9877a2a594d3029..4a6baadcca90ff6bfa3c433851d3d2c63bd8c269 100644 --- a/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DIstrictDetailBar/index.less +++ b/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DIstrictDetailBar/index.less @@ -12,6 +12,7 @@ box-sizing: border-box; transform: translateX(-50%); display: flex; + z-index: 50; } .leftWrap { width: 50%; diff --git a/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DIstrictDetailBar/index.tsx b/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DIstrictDetailBar/index.tsx index 5ff2f7a76f50b5a17ae0ebfdcbc08503946d5c13..afd7dbdbf4130ce6f3d0373f8470feca3aeaba82 100644 --- a/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DIstrictDetailBar/index.tsx +++ b/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DIstrictDetailBar/index.tsx @@ -8,11 +8,16 @@ import { } from '@ant-design/icons'; import { Col, Flex, Row, Space } from 'antd'; import React from 'react'; -import { useDistrictContext } from '../..'; + +import { useModel } from '@umijs/max'; import LineCharts from '../LineCharts'; import styles from './index.less'; const DistrictDetailBar: React.FC = () => { - const { selectDistrict } = useDistrictContext(); + /** @description store */ + const { selectDistrict } = useModel('regionalIndex', (store) => ({ + selectDistrict: store.selectDistrict!, + })); + const { dispatch } = useGlobalModalServices(); const cards = [ { diff --git a/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DistrictList/index.tsx b/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DistrictList/index.tsx index 4b3c6122dc1f8ef60782c942240b54a73771ce32..11d747373a41cbe78de61f7483ba50fa311a2f38 100644 --- a/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DistrictList/index.tsx +++ b/src/pages/TheOperationOfTheDistrictCityAndCounty/components/DistrictList/index.tsx @@ -1,68 +1,40 @@ -import services from '@/services'; import { getColorByIndex } from '@/utils/ui'; import { CaretDownOutlined, CaretUpOutlined, LeftOutlined, } from '@ant-design/icons'; +import { useModel } from '@umijs/max'; import { useToggle } from 'ahooks'; import { Flex, Popover, Progress, Space, Spin } from 'antd'; import classNames from 'classnames'; import { cloneDeep } from 'lodash'; -import React, { useEffect, useMemo, useState } from 'react'; -import { useDistrictContext } from '../..'; +import React, { useEffect, useMemo } from 'react'; import PopoverCard from '../PopoverCard'; import styles from './index.less'; -const List = [ - { - name: '温江区', - value: 98.6, - problemNum: 235, - compare: 1.3, - id: 1, - }, - { - name: '都江堰市', - value: 88.6, - problemNum: 200, - compare: -1.3, - id: 2, - }, - { - name: '天府新区', - value: 82.6, - problemNum: 150, - compare: 1.3, - id: 3, - }, -]; /** @name 地区列表 */ const DistrictList: React.FC = () => { const [state, { setLeft, setRight }] = useToggle('low', 'hight'); + /** @description store */ + const { + getAreaListDto, + loading, + areaListDto, + selectDistrict, + setSelectDistrict, + } = useModel('regionalIndex'); - const { selectDistrict, setSelectDistrict } = useDistrictContext(); - const [loading, setLoading] = useState(false); - const [dataSource, setDataSource] = useState<DistrictAPI.RealtimeIndexDTO[]>( - [], - ); const result = useMemo(() => { if (state === 'low') { - return cloneDeep(dataSource); + return cloneDeep(areaListDto); } else { - return cloneDeep(dataSource).reverse(); + return cloneDeep(areaListDto).reverse(); } - }, [state, dataSource]); + }, [state, areaListDto]); + useEffect(() => { - setLoading(true); - services.districtController - .getDistrictIndexList() - .then((res) => { - setDataSource(res.data); - }) - .finally(() => { - setLoading(false); - }); + getAreaListDto(); }, []); return ( @@ -124,7 +96,7 @@ const DistrictList: React.FC = () => { <div className={classNames( styles.listItem, - item.objectId === selectDistrict?.id + item.objectId === selectDistrict?.objectId ? styles.active : undefined, )} diff --git a/src/pages/TheOperationOfTheDistrictCityAndCounty/components/Map/index.less b/src/pages/TheOperationOfTheDistrictCityAndCounty/components/Map/index.less index 8b1d891c3d0422ee492ec165555656627e0e48ab..e94eaa2d7bb08f07a4a1f9b2da7fc28b4065b24d 100644 --- a/src/pages/TheOperationOfTheDistrictCityAndCounty/components/Map/index.less +++ b/src/pages/TheOperationOfTheDistrictCityAndCounty/components/Map/index.less @@ -2,6 +2,7 @@ background-color: #005a8f; position: relative; background-size: 100% 100%; + overflow: hidden; } .districtName { @@ -44,6 +45,7 @@ right: 30px; bottom: 30px; + z-index: 100; > div { width: 40px; height: 40px; @@ -59,3 +61,18 @@ margin-top: 10px; } } + +.indexMarker { + width: 44px; + height: 44px; + box-sizing: border-box; + border: 3px solid rgba(255, 255, 255, 0.5); + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.5); + background: var(--bg-color); + border-radius: 22px; + display: flex; + align-items: center; + justify-content: center; + + color: var(--color); +} diff --git a/src/pages/TheOperationOfTheDistrictCityAndCounty/components/Map/index.tsx b/src/pages/TheOperationOfTheDistrictCityAndCounty/components/Map/index.tsx index 9a0228dda30282bd90f7b05a85f686ed36baa829..3545513ed818b99b94802f23e84e52ed1fcbd178 100644 --- a/src/pages/TheOperationOfTheDistrictCityAndCounty/components/Map/index.tsx +++ b/src/pages/TheOperationOfTheDistrictCityAndCounty/components/Map/index.tsx @@ -1,25 +1,100 @@ +import MapView from '@/components/MapView'; +import BMapService from '@/utils/mapService'; +import { getColorByIndex } from '@/utils/ui'; import { MinusOutlined, PlusOutlined } from '@ant-design/icons'; +import { useModel } from '@umijs/max'; import { Space } from 'antd'; -import React from 'react'; -import { useDistrictContext } from '../..'; +import React, { CSSProperties, Fragment, useEffect, useRef } from 'react'; +import { CustomOverlay, Polygon } from 'react-bmapgl'; import DistrictDetailBar from '../DIstrictDetailBar'; import styles from './index.less'; /** 地图 */ const DistrictMap: React.FC = () => { - const { selectDistrict } = useDistrictContext(); + /** @description store */ + const { selectDistrict, areaListDto } = useModel('regionalIndex'); + + const MapRef = useRef<any>(); + + /** + * @description 设置地图视野 + */ + const setViewport = () => { + const points = areaListDto + .map((item) => { + return BMapService.buildPoints(item.points); + }) + .flat(1); + + const map = MapRef.current?.map as BMapGL.Map; + if (map) { + map.setViewport(points); + } + }; + + const addZoom = () => { + const map = MapRef.current?.map as BMapGL.Map; + map.centerAndZoom(map.getCenter(), map.getZoom() + 1); + }; + + const reduceZoom = () => { + const map = MapRef.current?.map as BMapGL.Map; + map.centerAndZoom(map.getCenter(), map.getZoom() - 1); + }; + + /** @description 移动视角到能显示全部覆盖物 */ + useEffect(() => { + setViewport(); + }, [MapRef.current]); return ( - <div - className={styles.container} - style={{ - backgroundImage: selectDistrict - ? 'url(' + require('@/assets/images/map/mapDemo2.png') + ')' - : 'url(' + require('@/assets/images/map/mapDemo1.png') + ')', - }} - > + <div className={styles.container}> + <MapView + zoom={13} + ref={MapRef} + style={{ width: '100%', height: '110%' }} + center={new BMapGL.Point(104.066349, 30.658842)} + > + {!selectDistrict ? ( + <Fragment> + {areaListDto.map((item, index) => { + return ( + <Polygon + fillColor={getColorByIndex(Number(item.qualitySign))} + key={index} + strokeColor="#fff" + fillOpacity={0.3} + strokeWeight={2} + path={BMapService.buildPoints(item.points)} + ></Polygon> + ); + })} + {areaListDto.map((item, index) => { + const point = BMapService.buildPoint( + Number(item.centerX), + Number(item.centerY), + ); + + return ( + <CustomOverlay position={point}> + <div + className={styles.indexMarker} + style={ + BMapService.getMakerCSS( + Number(item.qualitySign), + ) as CSSProperties + } + > + {Number(item.qualitySign)} + </div> + </CustomOverlay> + ); + })} + </Fragment> + ) : undefined} + </MapView> {selectDistrict && ( - <div className={styles.districtName}>{selectDistrict.name}</div> + <div className={styles.districtName}>{selectDistrict.objectName}</div> )} <div className={styles.statusBar}> <Space> @@ -40,13 +115,13 @@ const DistrictMap: React.FC = () => { </Space> </div> <div className={styles.mapController}> - <div> + <div onClick={() => setViewport()}> <img src={require('@/assets/images/map/mapReload.png')} alt="" /> </div> - <div> + <div onClick={addZoom}> <PlusOutlined></PlusOutlined> </div> - <div> + <div onClick={reduceZoom}> <MinusOutlined /> </div> </div> diff --git a/src/pages/TheOperationOfTheDistrictCityAndCounty/index.tsx b/src/pages/TheOperationOfTheDistrictCityAndCounty/index.tsx index 68985fcc7ac82dc2456dce1def8f59befafb27da..9262365e117738c9a615b30d45edd46e0b479af2 100644 --- a/src/pages/TheOperationOfTheDistrictCityAndCounty/index.tsx +++ b/src/pages/TheOperationOfTheDistrictCityAndCounty/index.tsx @@ -1,65 +1,50 @@ import { useToggle } from 'ahooks'; import { Flex, message, Space } from 'antd'; import classNames from 'classnames'; -import React, { useState } from 'react'; +import React from 'react'; import DistrictList from './components/DistrictList'; import DistrictMap from './components/Map'; import styles from './index.less'; -const Context = React.createContext<{ - selectDistrict?: any; - setSelectDistrict?: (value: any) => void; -}>({}); - -export const useDistrictContext = () => React.useContext(Context); - /** @module 区市县运行情况 */ const TheOperationOfTheDistrictCityAndCounty: React.FC = () => { const [state, { toggle }] = useToggle('left', 'right'); - const [selectDistrict, setSelectDistrict] = useState<any>(); return ( - <Context.Provider - value={{ - selectDistrict, - setSelectDistrict, - }} - > - <div className={styles.container}> - <Flex justify="space-between" align="center" className={styles.header}> - <div>区(市)县运行情况</div> - <Space align="center" size={24}> - <div className={styles.header_right_text}>10:20 更新</div> - <div className={styles.btnGroup}> - <div - onClick={toggle} - className={classNames( - styles.btn, - state === 'left' ? styles.btnSelected : undefined, - )} - > - 实时态势 - </div> - <div - onClick={() => { - message.warning('功能未开放'); - }} - className={classNames( - styles.btn, - state === 'right' ? styles.btnSelected : undefined, - )} - > - 历史态势 - </div> + <div className={styles.container}> + <Flex justify="space-between" align="center" className={styles.header}> + <div>区(市)县运行情况</div> + <Space align="center" size={24}> + <div className={styles.header_right_text}>10:20 更新</div> + <div className={styles.btnGroup}> + <div + onClick={toggle} + className={classNames( + styles.btn, + state === 'left' ? styles.btnSelected : undefined, + )} + > + 实时态势 + </div> + <div + onClick={() => { + message.warning('功能未开放'); + }} + className={classNames( + styles.btn, + state === 'right' ? styles.btnSelected : undefined, + )} + > + 历史态势 </div> - </Space> - </Flex> - <div className={styles.content}> - <DistrictList /> - <DistrictMap /> - </div> + </div> + </Space> + </Flex> + <div className={styles.content}> + <DistrictList /> + <DistrictMap /> </div> - </Context.Provider> + </div> ); }; diff --git a/src/utils/mapService.ts b/src/utils/mapService.ts new file mode 100644 index 0000000000000000000000000000000000000000..b31673ae2c4ff2bad47e691d14049313ffde0f38 --- /dev/null +++ b/src/utils/mapService.ts @@ -0,0 +1,39 @@ +/** + * @description 地图服务 + * + */ +export default class BMapService { + /** @description 构建地图点 */ + static buildPoints(points: number[][]) { + return points.map((item) => { + return new BMapGL.Point(item[0], item[1]); + }); + } + + static buildPoint(lng: number, lat: number) { + return new BMapGL.Point(lng, lat); + } + /** @description 获取图标样式 */ + static getMakerCSS(index: number) { + if (index > 95) { + return { + '--color': 'rgb(61, 191, 62)', + '--bg-color': + 'linear-gradient(180.00deg, rgb(255, 255, 255),rgb(197, 255, 197) 100%)', + }; + } + if (index < 95 && index > 85) { + return { + '--color': 'rgb(68, 127, 240)', + '--bg-color': + 'linear-gradient(180.00deg, rgb(255, 255, 255),rgb(172, 200, 255) 100%)', + }; + } + + return { + '--color': 'rgb(255, 162, 80)', + '--bg-color': + 'linear-gradient(180.00deg, rgb(255, 255, 255),rgb(255, 229, 206) 100%);', + }; + } +} diff --git a/yarn.lock b/yarn.lock index f619b32a8150c2b7f334dcbc198a11348aba7cc7..487cfae451080e3a1bca1508dee259c2e7898bdb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1751,6 +1751,11 @@ dependencies: "@babel/types" "^7.20.7" +"@types/bmapgl@^0.0.7": + version "0.0.7" + resolved "https://registry.npmmirror.com/@types/bmapgl/-/bmapgl-0.0.7.tgz#005bd208b782f1c611964f50f58f792aa239b243" + integrity sha512-3R0wFbZtynfHBJq0v477amaNH3t2u2CzBo46ViIPDdOTEJJ+Ma/ql4X8tS2XjDZcZhDAr6QDWoqV8SZvp6STvA== + "@types/crypto-js@^4.2.2": version "4.2.2" resolved "https://registry.npmmirror.com/@types/crypto-js/-/crypto-js-4.2.2.tgz#771c4a768d94eb5922cc202a3009558204df0cea" @@ -6423,6 +6428,11 @@ map-obj@^4.0.0: resolved "https://registry.npmmirror.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== +mapvgl@^1.0.0-beta.189: + version "1.0.0-beta.191" + resolved "https://registry.npmmirror.com/mapvgl/-/mapvgl-1.0.0-beta.191.tgz#3e77a834ffcf44385512390ecd0b484b267dd2ba" + integrity sha512-kbcLSXPSZybMgvJ0RTPEpISC6hpc27P/UwYCFASKLRe6Z7LC0Z11FwNXvQT/jkAK/LdBm2GqsE9i+GQViqRIYg== + mathml-tag-names@^2.1.3: version "2.1.3" resolved "https://registry.npmmirror.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" @@ -8410,6 +8420,14 @@ rc-virtual-list@^3.14.2, rc-virtual-list@^3.2.0, rc-virtual-list@^3.5.1, rc-virt rc-resize-observer "^1.0.0" rc-util "^5.36.0" +react-bmapgl@^0.2.28: + version "0.2.28" + resolved "https://registry.npmmirror.com/react-bmapgl/-/react-bmapgl-0.2.28.tgz#b04fd995f5469fb3e67369577b5bb248712dbf3a" + integrity sha512-qqIyuoDril0424/MQA418D20KtvNeE7MBRnWL1EttaX/kNfGzAUjJRoVzROD8bLiDytYSzvodyr+hl0/6MniCQ== + dependencies: + mapvgl "^1.0.0-beta.189" + shallowequal "^1.1.0" + react-countup@^6.5.3: version "6.5.3" resolved "https://registry.npmmirror.com/react-countup/-/react-countup-6.5.3.tgz#e892aa3eab2d6ba9c3cdba30bf4ed6764826d848"