|
@@ -1,15 +1,22 @@
|
|
|
-import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
|
-import { Amap, Marker } from '@amap/amap-react';
|
|
|
-import { AutoComplete, Button, Input, Space } from 'antd';
|
|
|
-import { debounce } from 'lodash';
|
|
|
+import {
|
|
|
+ forwardRef,
|
|
|
+ useCallback,
|
|
|
+ useEffect,
|
|
|
+ useImperativeHandle,
|
|
|
+ useRef,
|
|
|
+ useState,
|
|
|
+} from "react";
|
|
|
+import { Amap, Marker } from "@amap/amap-react";
|
|
|
+import { AutoComplete, Button, Input, Space, message } from "antd";
|
|
|
+import { debounce, isNumber } from "lodash";
|
|
|
import {
|
|
|
AMapGeocoderGetAddressResult,
|
|
|
DageMapMethods,
|
|
|
DageMapPoisType,
|
|
|
DageMapProps,
|
|
|
-} from './types';
|
|
|
-import { DageMapGeocoder } from './plugins';
|
|
|
-import { getAmapInputTips } from './utils';
|
|
|
+} from "./types";
|
|
|
+import { DageMapGeocoder } from "./plugins";
|
|
|
+import { getAmapInputTips } from "./utils";
|
|
|
|
|
|
export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
|
|
|
(
|
|
@@ -19,28 +26,43 @@ export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
|
|
|
disabled,
|
|
|
address,
|
|
|
city,
|
|
|
+ onlyCityArea,
|
|
|
inputTipsApi,
|
|
|
+ outCityAreaMessage,
|
|
|
onAddressChange,
|
|
|
onLngLatChange,
|
|
|
onMapComplete,
|
|
|
},
|
|
|
- ref,
|
|
|
+ ref
|
|
|
) => {
|
|
|
const mapRef = useRef<AMap.Map_2>();
|
|
|
/** 是否禁用坐标解析地址 */
|
|
|
const geocoderDisabled = useRef(false);
|
|
|
const [loaded, setLoaded] = useState(false);
|
|
|
- /** 经度 */
|
|
|
+ /** 上一个坐标地址 */
|
|
|
+ const prevPosition = useRef([longitude, latitude]);
|
|
|
+ /** 输入框经度 */
|
|
|
const [lng, setLng] = useState<number>(longitude);
|
|
|
- /** 纬度 */
|
|
|
+ /** 输入框纬度 */
|
|
|
const [lat, setLat] = useState<number>(latitude);
|
|
|
const [options, setOptions] = useState<DageMapPoisType[]>([]);
|
|
|
- const position = useMemo(() => [longitude, latitude], [longitude, latitude]);
|
|
|
+ const [position, setPosition] = useState([longitude, latitude]);
|
|
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
|
mapRef: mapRef.current,
|
|
|
}));
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ if (longitude === lng && latitude === lat) return;
|
|
|
+
|
|
|
+ // 外部改动经纬度,不需要解析地址
|
|
|
+ geocoderDisabled.current = true;
|
|
|
+ setPosition([longitude, latitude]);
|
|
|
+ setLat(latitude);
|
|
|
+ setLng(longitude);
|
|
|
+ prevPosition.current = [longitude, latitude];
|
|
|
+ }, [longitude, latitude]);
|
|
|
+
|
|
|
const handleSearch = useCallback(
|
|
|
debounce(async (value: string) => {
|
|
|
if (!value) {
|
|
@@ -51,7 +73,7 @@ export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
|
|
|
const { tips } = await getAmapInputTips(inputTipsApi, value, city);
|
|
|
setOptions(tips || []);
|
|
|
}, 500),
|
|
|
- [city],
|
|
|
+ [city]
|
|
|
);
|
|
|
|
|
|
const handleClick = useCallback(
|
|
@@ -64,12 +86,13 @@ export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
|
|
|
|
|
|
setLat(lat);
|
|
|
setLng(lng);
|
|
|
+ setPosition([lng, lat]);
|
|
|
onLngLatChange?.({
|
|
|
lat,
|
|
|
lng,
|
|
|
});
|
|
|
},
|
|
|
- [disabled, onLngLatChange],
|
|
|
+ [disabled, onLngLatChange]
|
|
|
);
|
|
|
|
|
|
/**
|
|
@@ -91,20 +114,24 @@ export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
|
|
|
lat,
|
|
|
lng,
|
|
|
});
|
|
|
+ setPosition(e._position);
|
|
|
}, 200),
|
|
|
- [onLngLatChange],
|
|
|
+ [onLngLatChange]
|
|
|
);
|
|
|
|
|
|
const handlePosition = useCallback(
|
|
|
(long = lng, lati = lat) => {
|
|
|
if (!long || !lati) return;
|
|
|
+
|
|
|
onLngLatChange?.({
|
|
|
lat: lati,
|
|
|
lng: long,
|
|
|
});
|
|
|
+ setPosition([long, lati]);
|
|
|
+
|
|
|
mapRef.current?.setCenter([long, lati], false, 1000);
|
|
|
},
|
|
|
- [lng, lat, onLngLatChange],
|
|
|
+ [lng, lat, onLngLatChange]
|
|
|
);
|
|
|
|
|
|
/**
|
|
@@ -117,7 +144,7 @@ export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
|
|
|
|
|
|
const handleSelect = useCallback(
|
|
|
(val: string, opts: DageMapPoisType) => {
|
|
|
- const [lng, lat] = opts.location.split(',').map((i) => Number(i));
|
|
|
+ const [lng, lat] = opts.location.split(",").map((i) => Number(i));
|
|
|
|
|
|
setLng(lng);
|
|
|
setLat(lat);
|
|
@@ -129,23 +156,42 @@ export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
|
|
|
lat,
|
|
|
lng,
|
|
|
});
|
|
|
+
|
|
|
+ prevPosition.current = [lng, lat];
|
|
|
},
|
|
|
- [handlePosition, onLngLatChange],
|
|
|
+ [handlePosition, onLngLatChange]
|
|
|
);
|
|
|
|
|
|
const handleAutoCompleteChange = useCallback(
|
|
|
(val: string) => {
|
|
|
onAddressChange?.(val);
|
|
|
},
|
|
|
- [onAddressChange],
|
|
|
+ [onAddressChange]
|
|
|
);
|
|
|
|
|
|
- const handleGeocoderAddress = useCallback(
|
|
|
- (res: AMapGeocoderGetAddressResult) => {
|
|
|
- !geocoderDisabled.current && onAddressChange?.(res.regeocode.formattedAddress);
|
|
|
- },
|
|
|
- [onAddressChange],
|
|
|
- );
|
|
|
+ const handleGeocoderAddress = (res: AMapGeocoderGetAddressResult) => {
|
|
|
+ if (geocoderDisabled.current) return;
|
|
|
+
|
|
|
+ if (
|
|
|
+ onlyCityArea &&
|
|
|
+ isNumber(city) &&
|
|
|
+ !res.regeocode.addressComponent.adcode.startsWith(
|
|
|
+ city.toString().substring(0, 2)
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ // 超出市区范围
|
|
|
+ outCityAreaMessage && message.error(outCityAreaMessage, 2);
|
|
|
+ setTimeout(() => {
|
|
|
+ setLat(prevPosition.current[1]);
|
|
|
+ setLng(prevPosition.current[0]);
|
|
|
+ handlePosition(prevPosition.current[0], prevPosition.current[1]);
|
|
|
+ }, 2000);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ onAddressChange?.(res.regeocode.formattedAddress);
|
|
|
+ prevPosition.current = [lng, lat];
|
|
|
+ };
|
|
|
|
|
|
return (
|
|
|
<>
|
|
@@ -167,7 +213,7 @@ export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
|
|
|
</AutoComplete>
|
|
|
</div>
|
|
|
|
|
|
- <Space style={{ margin: '15px 0' }}>
|
|
|
+ <Space style={{ margin: "15px 0" }}>
|
|
|
<Input
|
|
|
readOnly={disabled}
|
|
|
value={lng}
|
|
@@ -190,10 +236,19 @@ export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
|
|
|
</Space>
|
|
|
|
|
|
<div style={{ width: 650, height: 400 }}>
|
|
|
- <Amap ref={mapRef} zoom={17} onComplete={handleComplete} onClick={handleClick}>
|
|
|
+ <Amap
|
|
|
+ ref={mapRef}
|
|
|
+ zoom={17}
|
|
|
+ onComplete={handleComplete}
|
|
|
+ onClick={handleClick}
|
|
|
+ >
|
|
|
{loaded && position ? (
|
|
|
<>
|
|
|
- <Marker position={position} draggable={!disabled} onDragging={handleMarker} />
|
|
|
+ <Marker
|
|
|
+ position={position}
|
|
|
+ draggable={!disabled}
|
|
|
+ onDragging={handleMarker}
|
|
|
+ />
|
|
|
|
|
|
{!disabled && (
|
|
|
<DageMapGeocoder
|
|
@@ -210,8 +265,8 @@ export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
|
|
|
</div>
|
|
|
</>
|
|
|
);
|
|
|
- },
|
|
|
+ }
|
|
|
);
|
|
|
|
|
|
-export * from './types';
|
|
|
-export * from './utils';
|
|
|
+export * from "./types";
|
|
|
+export * from "./utils";
|