Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
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;
|