Files
shz-front-cms/src/components/ProFromMap/index.tsx

227 lines
7.6 KiB
TypeScript
Raw Normal View History

2025-10-24 09:40:46 +08:00
import React, { Fragment, useEffect, useRef, useState } from 'react';
import style from './index.less';
import AMapLoader from '@amap/amap-jsapi-loader';
import { ProFormSelect } from '@ant-design/pro-components';
import img from './point.png';
import { Modal } from 'antd';
import { debounce } from '@/utils/tools';
declare global {
interface Window {
_AMapSecurityConfig?: {
securityJsCode: string;
};
}
}
export type MapProps = {
onSelect: (flag?: boolean, formVals?: unknown) => void;
onCancel: (flag?: boolean, formVals?: unknown) => void;
open: boolean;
};
export const aMapConfig = {
key: '9cfc9370bd8a941951da1cea0308e9e3',
securityJsCode: '7b16386c7f744c3ca05595965f2b037f',
};
const ProFromMap: React.FC<MapProps> = ({ open, onSelect, onCancel }) => {
const mapRef = useRef<any>(null);
const geocoderRef = useRef<any>(null);
const autoCompleteRef = useRef<any>(null);
const addMarkerRef = useRef<any>(null);
const markerRef = useRef<any>(null);
const locationList = useRef<any>([]);
const localData = useRef(null);
const [selectValue, setSelectValue] = useState<any>(null);
const [locationOptions, setLocationOptions] = useState(null);
useEffect(() => {
console.log('open', open);
if (!open) return;
window._AMapSecurityConfig = {
securityJsCode: aMapConfig.securityJsCode,
};
AMapLoader.load({
key: aMapConfig.key, // 申请好的Web端开发者Key首次调用 load 时必填
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: ['AMap.Scale'], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['...','...']
})
.then((AMap) => {
mapRef.current = new AMap.Map('container', {
// 设置地图容器id
viewMode: '3D', // 是否为3D地图模式
zoom: 11, // 初始化地图级别
center: [120.384599, 36.062687], // 初始化地图中心点位置
});
// 浏览器定位
AMap.plugin('AMap.Geolocation', function () {
var geolocation = new AMap.Geolocation({
enableHighAccuracy: false, //是否使用高精度定位,默认:true
timeout: 10000, //超过10秒后停止定位默认5s
position: 'RB', //定位按钮的停靠位置
offset: [10, 20], //定位按钮与设置的停靠位置的偏移量,默认:[10, 20]
zoomToAccuracy: true, //定位成功后是否自动调整地图视野到定位点
});
mapRef.current.addControl(geolocation);
geolocation.getCurrentPosition();
});
// 添加插件
AMap.plugin('AMap.AutoComplete', function () {
// 注意输入提示插件2.0版本需引入AMap.AutoComplete而1.4版本应使用AMap.Autocomplete
// 实例化AutoComplete
autoCompleteRef.current = new AMap.AutoComplete({
city: '370200', // 青岛市
citylimit: false,
});
});
// 将经纬度坐标转化为详细地址
AMap.plugin('AMap.Geocoder', () => {
geocoderRef.current = new AMap.Geocoder({
extensions: 'base',
batch: false,
city: '370200', // 青岛市
});
});
// 添加事件
mapRef.current.on('click', (eve) => {
console.log(eve);
const { lat, lng } = eve.lnglat;
if (geocoderRef.current && addMarkerRef.current) {
const lnglat1 = [lng, lat];
geocoderRef.current.getAddress(lnglat1, (status, result) => {
if (status === 'complete' && result.info === 'OK') {
const { formattedAddress } = result.regeocode;
const id = Date.now();
result.id = id;
result.address = formattedAddress;
result.location = {
lat: lat,
lng: lng,
};
setSelectValue(id);
setLocationOptions([result]);
localData.current = result;
console.log(result, '详细地址');
}
});
addMarkerRef.current && addMarkerRef.current(lnglat1);
}
});
addMarkerRef.current = (LngLat: any) => {
if (markerRef.current) {
mapRef.current.remove(markerRef.current);
markerRef.current = null;
addMarkerRef.current && addMarkerRef.current(LngLat);
} else {
markerRef.current = new AMap.Marker({
icon: new AMap.Icon({
size: new AMap.Size(32, 32), // 图标显示大小
image: img, // 自定义图标 URL
imageSize: new AMap.Size(32, 32), // 强制缩放原始图片大小
}),
anchor: 'bottom-center', // 设置锚点方位
position: LngLat, //标注点位置
title: `鼠标移入显示的提示`, //标注点标题
map: mapRef.current, //将标注点添加到地图上
});
}
};
// 获取输入提示信息
})
.catch((e) => {
console.log(e);
});
}, [open]);
useEffect(() => {
return () => {
mapRef.current?.destroy();
};
}, []);
function autoInput(keywords: string) {
return new Promise((resolve, reject) => {
autoCompleteRef.current.search(keywords, function (status: string, result) {
if (status === 'complete' && result.info === 'OK') {
// 搜索成功时result即是对应的匹配数据
resolve(result.tips);
} else {
reject(null);
}
});
});
}
const searchLocation = async (keyWords: string) => {
const keywordsToSearch = keyWords || '青岛';
const resData = await autoInput(keywordsToSearch);
locationList.current = resData;
setLocationOptions(resData);
return resData || [];
};
// 防抖版本(确保组件卸载时清除)
const debounceSearch = useRef(debounce(searchLocation, 500)).current;
function selectItem(id: any) {
const items = locationList.current.filter((item) => item.id === id);
if (items.length) {
const value = items[0];
setSelectValue(value.id);
addMarkerRef.current([value.location.lng, value.location.lat]);
mapRef.current.setZoomAndCenter(16, [value.location.lng, value.location.lat]);
localData.current = value;
}
}
function locationSuccess() {
if (localData.current) {
onSelect && onSelect(localData.current);
}
}
return (
<Fragment>
<Modal
open={open}
title="选择位置"
okText="确定"
cancelText="取消"
width={800}
onCancel={onCancel}
onOk={locationSuccess}
>
<div className={style.AmapContainer}>
<div className={style.Amap_search}>
<ProFormSelect
style={{
width: '100%',
}}
debounceTime={500}
name="select"
// request={searchLocation}
showSearch
placeholder="请输入地点"
fieldProps={{
onSelect: selectItem,
onSearch: debounceSearch,
value: selectValue,
options: locationOptions,
fieldNames: {
label: 'address',
value: 'id',
},
}}
/>
</div>
<div id="container" className={style.mapContent}></div>
</div>
</Modal>
</Fragment>
);
};
export default ProFromMap;