fix(admin,partner): harden Tencent locpicker coords and confirm flow
CI / verify (pull_request) Has been cancelled

Accept latlng-only postMessage, confirm before apply, and read LBS key per request.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-28 00:47:08 +08:00
parent 50349dd8e9
commit 9ed0c24d11
7 changed files with 157 additions and 35 deletions
@@ -40,9 +40,13 @@ export default function TencentLocPickerOverlay({
const [key, setKey] = useState<string | null>(cachedKey ?? null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const [pending, setPending] = useState<TencentPickedLocation | null>(null);
useEffect(() => {
if (!open) return;
if (!open) {
setPending(null);
return;
}
let cancelled = false;
setError('');
if (key) return;
@@ -67,23 +71,30 @@ export default function TencentLocPickerOverlay({
function onMessage(event: MessageEvent) {
const picked = parseTencentLocPickerMessage(event.data);
if (!picked) return;
onPick(picked);
onClose();
setPending(picked);
}
window.addEventListener('message', onMessage);
return () => window.removeEventListener('message', onMessage);
}, [open, onPick, onClose]);
}, [open]);
const src = useMemo(() => {
if (!key) return '';
const lat = latitude != null ? Number(latitude) : undefined;
const lng = longitude != null ? Number(longitude) : undefined;
return buildTencentLocPickerUrl(key, {
latitude: latitude != null ? Number(latitude) : undefined,
longitude: longitude != null ? Number(longitude) : undefined,
latitude: lat != null && Number.isFinite(lat) ? lat : undefined,
longitude: lng != null && Number.isFinite(lng) ? lng : undefined,
});
}, [key, latitude, longitude]);
if (!open) return null;
function confirmPick() {
if (!pending) return;
onPick(pending);
onClose();
}
return (
<div
style={{
@@ -109,21 +120,50 @@ export default function TencentLocPickerOverlay({
</button>
<span style={{ fontWeight: 600 }}></span>
<span style={{ width: 52 }} />
<button
type="button"
className="partner-btn-primary"
style={{ padding: '6px 12px', opacity: pending ? 1 : 0.45, width: 'auto' }}
disabled={!pending}
onClick={confirmPick}
>
</button>
</div>
{pending ? (
<p
className="label-md text-muted"
style={{
margin: 0,
padding: '8px 16px',
borderBottom: '1px solid rgba(0,0,0,0.04)',
flexShrink: 0,
}}
>
{pending.latitude.toFixed(6)}, {pending.longitude.toFixed(6)}
{pending.name ? ` · ${pending.name}` : ''}
</p>
) : null}
<div style={{ flex: 1, minHeight: 0, position: 'relative' }}>
{loading ? (
<p className="label-md text-muted" style={{ padding: 24, textAlign: 'center' }}>
</p>
) : error ? (
<p className="label-md" style={{ padding: 24, color: 'var(--color-heritage-red, #a61d24)' }}>
{error}
</p>
<div style={{ padding: 24 }}>
<p className="label-md" style={{ color: 'var(--color-heritage-red, #a61d24)' }}>
{error}
</p>
<p className="label-md text-muted" style={{ marginTop: 12 }}>
Key WebServiceAPI
apis.map.qq.com
</p>
</div>
) : src ? (
<iframe
title="腾讯地图选点"
src={src}
allow="geolocation *"
style={{ width: '100%', height: '100%', border: 0, display: 'block' }}
/>
) : null}