All checks were successful
Build and Push Docker Image / build (push) Successful in 5m10s
716 lines
21 KiB
TypeScript
716 lines
21 KiB
TypeScript
import { MyBetaModalFormProps } from '@/common';
|
||
import { MyModal } from '@/components/MyModal';
|
||
import L from 'leaflet';
|
||
import 'leaflet/dist/leaflet.css';
|
||
import { useEffect, useRef, useState } from 'react';
|
||
|
||
// 修复 Leaflet 图标问题
|
||
delete L.Icon.Default.prototype._getIconUrl;
|
||
L.Icon.Default.mergeOptions({
|
||
iconRetinaUrl:
|
||
'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png',
|
||
iconUrl:
|
||
'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png',
|
||
shadowUrl:
|
||
'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png',
|
||
});
|
||
|
||
// 创建自定义图标
|
||
const createCustomIcon = (color = 'red') => {
|
||
return L.divIcon({
|
||
className: 'custom-marker',
|
||
html: `
|
||
<div style="
|
||
background-color: ${color};
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 50%;
|
||
border: 3px solid white;
|
||
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
|
||
"></div>
|
||
`,
|
||
iconSize: [20, 20],
|
||
iconAnchor: [10, 10],
|
||
});
|
||
};
|
||
|
||
interface LocationResult {
|
||
lat: number;
|
||
lng: number;
|
||
address: string;
|
||
name?: string;
|
||
}
|
||
|
||
export default function ModalsMapLeaflet(
|
||
props: MyBetaModalFormProps & {
|
||
onChange?: (location?: LocationResult) => void;
|
||
},
|
||
) {
|
||
const modalRef = useRef<any>();
|
||
const mapRef = useRef<L.Map | null>(null);
|
||
const markersRef = useRef<L.LayerGroup | null>(null);
|
||
const [searchText, setSearchText] = useState('');
|
||
const [searchResults, setSearchResults] = useState<LocationResult[]>([]);
|
||
const [selectedLocation, setSelectedLocation] =
|
||
useState<LocationResult | null>(null);
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
const [mapReady, setMapReady] = useState(false);
|
||
const mapInitializedRef = useRef(false);
|
||
|
||
// 天地图配置
|
||
const TIANDITU_KEY = '4ce26ecef55ae1ec47910a72a098efc0';
|
||
const tiandituUrls = {
|
||
vector: `https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${TIANDITU_KEY}`,
|
||
label: `https://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${TIANDITU_KEY}`,
|
||
};
|
||
|
||
// 清理地图
|
||
useEffect(() => {
|
||
return () => {
|
||
if (mapRef.current) {
|
||
mapRef.current.remove();
|
||
mapRef.current = null;
|
||
mapInitializedRef.current = false;
|
||
setMapReady(false);
|
||
}
|
||
};
|
||
}, []);
|
||
|
||
// 初始化地图
|
||
const initializeMap = () => {
|
||
// 确保DOM已经渲染
|
||
setTimeout(() => {
|
||
const mapContainer = document.getElementById('map');
|
||
|
||
if (!mapContainer) {
|
||
console.error('地图容器不存在');
|
||
return;
|
||
}
|
||
|
||
// 如果地图已经存在,先清理
|
||
if (mapRef.current) {
|
||
mapRef.current.remove();
|
||
mapRef.current = null;
|
||
mapInitializedRef.current = false;
|
||
}
|
||
|
||
// 清理容器
|
||
while (mapContainer.firstChild) {
|
||
mapContainer.removeChild(mapContainer.firstChild);
|
||
}
|
||
|
||
try {
|
||
console.log('开始初始化地图...');
|
||
|
||
const map = L.map('map', {
|
||
center: [30.258134, 120.19382669582967],
|
||
zoom: 12,
|
||
zoomControl: true,
|
||
attributionControl: false,
|
||
});
|
||
|
||
mapRef.current = map;
|
||
mapInitializedRef.current = true;
|
||
|
||
// 添加天地图图层
|
||
const baseLayer = L.tileLayer(tiandituUrls.vector, {
|
||
attribution: '© 天地图',
|
||
minZoom: 3,
|
||
maxZoom: 18,
|
||
}).addTo(map);
|
||
|
||
const labelLayer = L.tileLayer(tiandituUrls.label, {
|
||
minZoom: 3,
|
||
maxZoom: 18,
|
||
}).addTo(map);
|
||
|
||
// 创建标记图层组
|
||
markersRef.current = L.layerGroup().addTo(map);
|
||
|
||
// 添加地图点击事件
|
||
map.on('click', (e: L.LeafletMouseEvent) => {
|
||
handleMapClick(e.latlng.lat, e.latlng.lng);
|
||
});
|
||
|
||
// 添加缩放和比例尺控件
|
||
L.control.scale({ imperial: false }).addTo(map);
|
||
|
||
// 地图加载完成
|
||
map.whenReady(() => {
|
||
console.log('地图加载完成');
|
||
setMapReady(true);
|
||
});
|
||
|
||
console.log('地图初始化成功');
|
||
} catch (error) {
|
||
console.error('地图初始化失败:', error);
|
||
mapInitializedRef.current = false;
|
||
setMapReady(false);
|
||
}
|
||
}, 300);
|
||
};
|
||
|
||
// 使用天地图 REST API 进行搜索
|
||
const searchWithTiandituAPI = async (
|
||
keyword: string,
|
||
): Promise<LocationResult[]> => {
|
||
try {
|
||
const url = `https://api.tianditu.gov.cn/v2/search?postStr={
|
||
"keyWord": "${encodeURIComponent(keyword)}",
|
||
"level": "12",
|
||
"mapBound": "115.38333,39.36667,117.68333,41.23333",
|
||
"queryType": "1",
|
||
"start": "0",
|
||
"count": "20"
|
||
}&type=query&tk=${TIANDITU_KEY}`;
|
||
|
||
console.log('搜索URL:', url);
|
||
|
||
const response = await fetch(url, {
|
||
method: 'GET',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP error! status: ${response.status}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
console.log('天地图搜索返回数据:', data);
|
||
|
||
// 根据不同的结果类型处理
|
||
const resultType = data.resultType;
|
||
|
||
switch (resultType) {
|
||
case 1: // POI点数据
|
||
if (data.pois && Array.isArray(data.pois)) {
|
||
return data.pois.map((poi: any) => ({
|
||
name: poi.name,
|
||
address: poi.address,
|
||
lng: parseFloat(poi.lonlat.split(',')[0]),
|
||
lat: parseFloat(poi.lonlat.split(',')[1]),
|
||
}));
|
||
}
|
||
break;
|
||
|
||
case 2: // 推荐城市
|
||
// 这里可以处理推荐城市,暂时返回空数组
|
||
console.log('推荐城市结果:', data.prompt);
|
||
return [];
|
||
|
||
case 3: // 行政区划
|
||
if (data.area) {
|
||
// 将行政区划转换为一个位置结果
|
||
const area = data.area;
|
||
const [lng, lat] = area.lonlat.split(',').map(parseFloat);
|
||
return [
|
||
{
|
||
name: area.name,
|
||
address: area.name,
|
||
lng: lng,
|
||
lat: lat,
|
||
},
|
||
];
|
||
}
|
||
break;
|
||
|
||
case 4: // 建议词
|
||
console.log('建议词结果:', data.prompt);
|
||
return [];
|
||
|
||
case 5: // 公交信息
|
||
console.log('公交信息结果:', data.lineData);
|
||
return [];
|
||
|
||
default:
|
||
console.log('未知结果类型:', resultType);
|
||
}
|
||
|
||
// 如果没有找到有效结果,尝试使用提示信息
|
||
if (data.prompt && data.prompt.length > 0) {
|
||
const prompt = data.prompt[0];
|
||
if (prompt.admins && prompt.admins.length > 0) {
|
||
const admin = prompt.admins[0];
|
||
return [
|
||
{
|
||
name: admin.name,
|
||
address: admin.name,
|
||
lng: parseFloat(admin.lonlat.split(',')[0]),
|
||
lat: parseFloat(admin.lonlat.split(',')[1]),
|
||
},
|
||
];
|
||
}
|
||
}
|
||
|
||
throw new Error('未找到相关地点');
|
||
} catch (error) {
|
||
console.error('天地图搜索API调用失败:', error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
// 搜索地点 - 使用天地图 REST API
|
||
const handleSearch = async () => {
|
||
if (!searchText.trim()) {
|
||
alert('请输入搜索关键词');
|
||
return;
|
||
}
|
||
|
||
// 检查天地图密钥
|
||
if (!TIANDITU_KEY) {
|
||
alert('请配置有效的天地图密钥');
|
||
return;
|
||
}
|
||
|
||
if (!mapReady) {
|
||
alert('地图尚未准备好,请稍后重试');
|
||
return;
|
||
}
|
||
|
||
setIsLoading(true);
|
||
|
||
try {
|
||
console.log('开始天地图搜索:', searchText);
|
||
|
||
// 清空之前的结果
|
||
setSearchResults([]);
|
||
if (markersRef.current) {
|
||
markersRef.current.clearLayers();
|
||
}
|
||
|
||
// 执行搜索
|
||
const results = await searchWithTiandituAPI(searchText);
|
||
console.log('搜索成功,结果数量:', results.length);
|
||
|
||
if (results.length === 0) {
|
||
alert('未找到相关地点');
|
||
return;
|
||
}
|
||
|
||
setSearchResults(results);
|
||
|
||
// 在地图上显示搜索结果
|
||
const bounds = L.latLngBounds([]);
|
||
results.forEach((result, index) => {
|
||
bounds.extend([result.lat, result.lng]);
|
||
addSearchResultMarker(result, index, results.length);
|
||
});
|
||
|
||
// 调整地图视野
|
||
if (mapRef.current) {
|
||
mapRef.current.fitBounds(bounds.pad(0.1));
|
||
}
|
||
} catch (error: any) {
|
||
console.error('搜索失败:', error);
|
||
alert(`搜索失败: ${error.message || '未知错误'}`);
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
};
|
||
|
||
// 添加搜索结果标记
|
||
const addSearchResultMarker = (
|
||
location: LocationResult,
|
||
index: number,
|
||
total: number,
|
||
) => {
|
||
if (!markersRef.current) return;
|
||
|
||
const marker = L.marker([location.lat, location.lng], {
|
||
icon: createCustomIcon(index === 0 ? '#1890ff' : '#52c41a'),
|
||
}).addTo(markersRef.current);
|
||
|
||
marker.bindPopup(`
|
||
<div style="min-width: 220px;">
|
||
<h4 style="margin: 0 0 8px 0; color: #1890ff; font-size: 14px;">${
|
||
location.name
|
||
}</h4>
|
||
<p style="margin: 4px 0; font-size: 12px;"><strong>地址:</strong> ${
|
||
location.address
|
||
}</p>
|
||
<p style="margin: 4px 0; font-size: 12px;"><strong>经纬度:</strong> ${location.lat.toFixed(
|
||
6,
|
||
)}, ${location.lng.toFixed(6)}</p>
|
||
<div style="margin-top: 10px; display: flex; gap: 8px;">
|
||
<button onclick="window.selectSearchResult(${index})" style="
|
||
padding: 6px 12px;
|
||
background: #1890ff;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-size: 12px;
|
||
flex: 1;
|
||
">选择此位置</button>
|
||
</div>
|
||
</div>
|
||
`);
|
||
|
||
// 第一个结果自动打开弹窗
|
||
if (index === 0) {
|
||
setTimeout(() => marker.openPopup(), 500);
|
||
}
|
||
|
||
// 将选择函数挂载到window对象
|
||
(window as any).selectSearchResult = (index: number) => {
|
||
console.log(location, searchResults, 'selectSearchResult');
|
||
if (searchResults && searchResults[index]) {
|
||
handleSelectResult(searchResults[index]);
|
||
} else {
|
||
handleConfirmLocation(location);
|
||
}
|
||
};
|
||
};
|
||
|
||
// 地图点击事件处理
|
||
const handleMapClick = async (lat: number, lng: number) => {
|
||
try {
|
||
setIsLoading(true);
|
||
|
||
// 使用天地图逆地理编码获取真实地址
|
||
const address = await reverseGeocodeWithTianditu(lat, lng);
|
||
|
||
const location: LocationResult = {
|
||
lat,
|
||
lng,
|
||
address,
|
||
name: '点击选择的位置',
|
||
};
|
||
|
||
setSelectedLocation(location);
|
||
addMarkerToMap(location);
|
||
} catch (error) {
|
||
console.error('获取地址信息失败:', error);
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
};
|
||
|
||
// 使用天地图逆地理编码服务
|
||
const reverseGeocodeWithTianditu = async (
|
||
lat: number,
|
||
lng: number,
|
||
): Promise<string> => {
|
||
try {
|
||
const url = `https://api.tianditu.gov.cn/geocoder?postStr={'lon':${lng},'lat':${lat},'ver':1}&type=geocode&tk=${TIANDITU_KEY}`;
|
||
|
||
const response = await fetch(url);
|
||
|
||
if (!response.ok) {
|
||
throw new Error('逆地理编码请求失败');
|
||
}
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.status === '0' && data.result) {
|
||
return data.result.formatted_address;
|
||
}
|
||
|
||
return `位置 ${lat.toFixed(6)}, ${lng.toFixed(6)}`;
|
||
} catch (error) {
|
||
console.error('天地图逆地理编码失败:', error);
|
||
return `位置 ${lat.toFixed(6)}, ${lng.toFixed(6)}`;
|
||
}
|
||
};
|
||
|
||
// 添加标记到地图
|
||
const addMarkerToMap = (location: LocationResult) => {
|
||
if (!mapRef.current || !markersRef.current) return;
|
||
|
||
markersRef.current.clearLayers();
|
||
|
||
const marker = L.marker([location.lat, location.lng], {
|
||
icon: createCustomIcon('#1890ff'),
|
||
}).addTo(markersRef.current);
|
||
|
||
marker
|
||
.bindPopup(
|
||
`
|
||
<div style="min-width: 200px;">
|
||
<h4 style="margin: 0 0 8px 0; color: #1890ff;">位置信息</h4>
|
||
<p style="margin: 4px 0;"><strong>地址:</strong> ${location.address}</p>
|
||
<p style="margin: 4px 0;"><strong>经纬度:</strong> ${location.lat.toFixed(
|
||
6,
|
||
)}, ${location.lng.toFixed(6)}</p>
|
||
<button onclick="window.confirmSelection()" style="
|
||
margin-top: 8px;
|
||
padding: 6px 12px;
|
||
background: #1890ff;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
">选择此位置</button>
|
||
</div>
|
||
`,
|
||
)
|
||
.openPopup();
|
||
|
||
(window as any).confirmSelection = () => {
|
||
console.log(location, 'confirmSelection');
|
||
handleConfirmLocation(location);
|
||
};
|
||
|
||
mapRef.current.setView([location.lat, location.lng], 15);
|
||
};
|
||
|
||
// 选择搜索结果
|
||
const handleSelectResult = (result: LocationResult) => {
|
||
setSelectedLocation(result);
|
||
addMarkerToMap(result);
|
||
setSearchResults([]);
|
||
setSearchText(result.name || result.address);
|
||
};
|
||
|
||
// 确认选择位置
|
||
const handleConfirmLocation = (location?: LocationResult) => {
|
||
const finalLocation = location || selectedLocation;
|
||
if (!finalLocation) return;
|
||
props?.onChange?.(location);
|
||
// if (props.onConfirm) {
|
||
// props.onConfirm(finalLocation);
|
||
// }
|
||
|
||
if (modalRef.current) {
|
||
modalRef.current.close();
|
||
}
|
||
};
|
||
|
||
// 清除选择
|
||
const handleClearSelection = () => {
|
||
setSelectedLocation(null);
|
||
setSearchText('');
|
||
setSearchResults([]);
|
||
if (markersRef.current) {
|
||
markersRef.current.clearLayers();
|
||
}
|
||
if (mapRef.current) {
|
||
mapRef.current.setView([30.258134, 120.19382669582967], 12);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<MyModal
|
||
title={'获取经纬度'}
|
||
width="1000px"
|
||
myRef={modalRef}
|
||
size="middle"
|
||
onOpen={() => {
|
||
console.log('模态框打开,初始化地图...');
|
||
setTimeout(initializeMap, 500);
|
||
}}
|
||
node={
|
||
<div style={{ padding: '20px' }}>
|
||
{/* 状态提示 */}
|
||
{!mapReady && (
|
||
<div
|
||
style={{
|
||
padding: '10px',
|
||
backgroundColor: '#fffbe6',
|
||
border: '1px solid #ffe58f',
|
||
borderRadius: '4px',
|
||
marginBottom: '10px',
|
||
textAlign: 'center',
|
||
}}
|
||
>
|
||
地图初始化中...
|
||
</div>
|
||
)}
|
||
|
||
{/* 搜索区域 */}
|
||
<div style={{ marginBottom: '20px' }}>
|
||
<div style={{ display: 'flex', gap: '10px', marginBottom: '10px' }}>
|
||
<input
|
||
type="text"
|
||
value={searchText}
|
||
onChange={(e) => setSearchText(e.target.value)}
|
||
placeholder="请输入地点名称进行搜索(如:杭州中大广场...)"
|
||
style={{
|
||
flex: 1,
|
||
padding: '8px 12px',
|
||
border: '1px solid #d9d9d9',
|
||
borderRadius: '4px',
|
||
fontSize: '14px',
|
||
}}
|
||
onKeyPress={(e) => e.key === 'Enter' && handleSearch()}
|
||
/>
|
||
<button
|
||
onClick={handleSearch}
|
||
disabled={isLoading || !mapReady}
|
||
style={{
|
||
padding: '8px 16px',
|
||
background: !isLoading && mapReady ? '#1890ff' : '#ccc',
|
||
color: 'white',
|
||
border: 'none',
|
||
borderRadius: '4px',
|
||
cursor: isLoading || !mapReady ? 'not-allowed' : 'pointer',
|
||
}}
|
||
>
|
||
{isLoading ? '搜索中...' : !mapReady ? '地图加载中' : '搜索'}
|
||
</button>
|
||
</div>
|
||
|
||
{/* 搜索结果 */}
|
||
{searchResults.length > 0 && (
|
||
<div
|
||
style={{
|
||
border: '1px solid #e8e8e8',
|
||
borderRadius: '4px',
|
||
maxHeight: '200px',
|
||
overflowY: 'auto',
|
||
backgroundColor: '#fafafa',
|
||
}}
|
||
>
|
||
<div
|
||
style={{
|
||
padding: '8px',
|
||
fontSize: '12px',
|
||
color: '#666',
|
||
borderBottom: '1px solid #e8e8e8',
|
||
}}
|
||
>
|
||
找到 {searchResults.length} 个结果
|
||
</div>
|
||
{searchResults.map((result, index) => (
|
||
<div
|
||
key={index}
|
||
onClick={() => handleSelectResult(result)}
|
||
style={{
|
||
padding: '10px',
|
||
borderBottom: '1px solid #f0f0f0',
|
||
cursor: 'pointer',
|
||
backgroundColor: index === 0 ? '#e6f7ff' : '#fafafa',
|
||
}}
|
||
onMouseEnter={(e) =>
|
||
(e.currentTarget.style.backgroundColor = '#e6f7ff')
|
||
}
|
||
onMouseLeave={(e) =>
|
||
(e.currentTarget.style.backgroundColor =
|
||
index === 0 ? '#e6f7ff' : '#fafafa')
|
||
}
|
||
>
|
||
<div
|
||
style={{
|
||
fontWeight: 'bold',
|
||
marginBottom: '4px',
|
||
color: '#1890ff',
|
||
}}
|
||
>
|
||
{result.name || '未知地点'}
|
||
</div>
|
||
<div style={{ fontSize: '12px', color: '#666' }}>
|
||
{result.address}
|
||
</div>
|
||
<div
|
||
style={{
|
||
fontSize: '11px',
|
||
color: '#999',
|
||
marginTop: '2px',
|
||
}}
|
||
>
|
||
经纬度: {result.lat.toFixed(6)}, {result.lng.toFixed(6)}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* 地图容器 */}
|
||
<div
|
||
id="map"
|
||
style={{
|
||
height: '400px',
|
||
border: '1px solid #e8e8e8',
|
||
borderRadius: '4px',
|
||
}}
|
||
/>
|
||
|
||
{/* 选择信息显示 */}
|
||
{selectedLocation && (
|
||
<div
|
||
style={{
|
||
marginTop: '20px',
|
||
padding: '15px',
|
||
backgroundColor: '#f6ffed',
|
||
border: '1px solid #b7eb8f',
|
||
borderRadius: '4px',
|
||
}}
|
||
>
|
||
<h4 style={{ margin: '0 0 10px 0', color: '#52c41a' }}>
|
||
已选择位置
|
||
</h4>
|
||
<p style={{ margin: '4px 0' }}>
|
||
<strong>地址:</strong> {selectedLocation.address}
|
||
</p>
|
||
<p style={{ margin: '4px 0' }}>
|
||
<strong>经纬度:</strong> {selectedLocation.lat.toFixed(6)},{' '}
|
||
{selectedLocation.lng.toFixed(6)}
|
||
</p>
|
||
<div style={{ marginTop: '10px', display: 'flex', gap: '10px' }}>
|
||
<button
|
||
onClick={() => handleConfirmLocation(selectedLocation)}
|
||
style={{
|
||
padding: '8px 16px',
|
||
background: '#52c41a',
|
||
color: 'white',
|
||
border: 'none',
|
||
borderRadius: '4px',
|
||
cursor: 'pointer',
|
||
fontWeight: 'bold',
|
||
}}
|
||
>
|
||
确认选择
|
||
</button>
|
||
<button
|
||
onClick={handleClearSelection}
|
||
style={{
|
||
padding: '8px 16px',
|
||
background: '#ff4d4f',
|
||
color: 'white',
|
||
border: 'none',
|
||
borderRadius: '4px',
|
||
cursor: 'pointer',
|
||
}}
|
||
>
|
||
清除选择
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* 使用说明 */}
|
||
<div
|
||
style={{
|
||
marginTop: '15px',
|
||
padding: '10px',
|
||
backgroundColor: '#f0f8ff',
|
||
border: '1px solid #91d5ff',
|
||
borderRadius: '4px',
|
||
fontSize: '12px',
|
||
color: '#666',
|
||
}}
|
||
>
|
||
<strong>使用说明:</strong>
|
||
<ul style={{ margin: '8px 0', paddingLeft: '20px' }}>
|
||
<li>等待地图加载完成后再进行搜索</li>
|
||
<li>在搜索框输入地点名称进行真实搜索(使用天地图搜索API)</li>
|
||
<li>直接点击地图选择位置(使用天地图逆地理编码)</li>
|
||
<li>搜索结果会自动在地图上标记并定位</li>
|
||
<li>点击标记弹出窗口可确认选择</li>
|
||
<li>经纬度精度可达小数点后14位</li>
|
||
</ul>
|
||
{!TIANDITU_KEY && (
|
||
<div style={{ color: '#ff4d4f', marginTop: '8px' }}>
|
||
⚠️ 请配置有效的天地图密钥
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
}
|
||
></MyModal>
|
||
);
|
||
}
|