227 lines
7.6 KiB
TypeScript
227 lines
7.6 KiB
TypeScript
|
|
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;
|