diff --git a/apps/admin-web/src/components/TencentLocPickerModal.tsx b/apps/admin-web/src/components/TencentLocPickerModal.tsx new file mode 100644 index 0000000..ad05635 --- /dev/null +++ b/apps/admin-web/src/components/TencentLocPickerModal.tsx @@ -0,0 +1,115 @@ +import { useEffect, useMemo, useState } from 'react'; +import { Modal, Spin, Typography, message } from 'antd'; +import type { ClientRuntimeConfig } from '@dukang/shared-types'; +import { request } from '../lib/api'; +import { + buildTencentLocPickerUrl, + parseTencentLocPickerMessage, + type TencentPickedLocation, +} from '../lib/tencentLocPicker'; + +type Props = { + open: boolean; + onClose: () => void; + onPick: (loc: TencentPickedLocation) => void; + latitude?: number | null; + longitude?: number | null; +}; + +let cachedKey: string | null | undefined; + +async function loadTencentLbsKey(): Promise { + if (cachedKey) return cachedKey; + const cfg = await request('/common/client-config'); + const key = (cfg.tencentLbsKey || '').trim(); + if (!key) { + throw new Error('未配置腾讯位置服务 Key,请在系统设置中填写 TENCENT_LBS_KEY'); + } + cachedKey = key; + return key; +} + +export default function TencentLocPickerModal({ + open, + onClose, + onPick, + latitude, + longitude, +}: Props) { + const [key, setKey] = useState(cachedKey ?? null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + + useEffect(() => { + if (!open) return; + let cancelled = false; + setError(''); + if (key) return; + setLoading(true); + void loadTencentLbsKey() + .then((k) => { + if (!cancelled) setKey(k); + }) + .catch((e) => { + if (!cancelled) { + const msg = e instanceof Error ? e.message : '加载地图配置失败'; + setError(msg); + message.error(msg); + } + }) + .finally(() => { + if (!cancelled) setLoading(false); + }); + return () => { + cancelled = true; + }; + }, [open, key]); + + useEffect(() => { + if (!open) return; + function onMessage(event: MessageEvent) { + const picked = parseTencentLocPickerMessage(event.data); + if (!picked) return; + onPick(picked); + onClose(); + } + window.addEventListener('message', onMessage); + return () => window.removeEventListener('message', onMessage); + }, [open, onPick, onClose]); + + const src = useMemo(() => { + if (!key) return ''; + return buildTencentLocPickerUrl(key, { + latitude: latitude != null ? Number(latitude) : undefined, + longitude: longitude != null ? Number(longitude) : undefined, + }); + }, [key, latitude, longitude]); + + return ( + + {loading ? ( +
+ +
+ ) : error ? ( +
+ {error} +
+ ) : src ? ( +