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
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useState } from 'react';
import { Modal, Spin, Typography, message } from 'antd';
import { Button, Modal, Space, Spin, Typography, message } from 'antd';
import type { ClientRuntimeConfig } from '@dukang/shared-types';
import { request } from '../lib/api';
import {
@@ -39,9 +39,13 @@ export default function TencentLocPickerModal({
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;
@@ -70,30 +74,56 @@ export default function TencentLocPickerModal({
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]);
function confirmPick() {
if (!pending) {
message.warning('请先在地图上选择或搜索一个位置');
return;
}
onPick(pending);
onClose();
}
return (
<Modal
title="腾讯地图选点"
open={open}
onCancel={onClose}
footer={null}
width={720}
destroyOnClose
styles={{ body: { padding: 0, height: 560 } }}
footer={
<Space style={{ width: '100%', justifyContent: 'space-between' }}>
<Typography.Text type="secondary" style={{ maxWidth: 420 }} ellipsis>
{pending
? `${pending.latitude.toFixed(6)}, ${pending.longitude.toFixed(6)}${
pending.name ? ` · ${pending.name}` : ''
}`
: '在地图中点选 / 搜索后,点击确认选点'}
</Typography.Text>
<Space>
<Button onClick={onClose}></Button>
<Button type="primary" disabled={!pending} onClick={confirmPick}>
</Button>
</Space>
</Space>
}
>
{loading ? (
<div style={{ height: 560, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
@@ -102,11 +132,16 @@ export default function TencentLocPickerModal({
) : error ? (
<div style={{ padding: 24 }}>
<Typography.Text type="danger">{error}</Typography.Text>
<Typography.Paragraph type="secondary" style={{ marginTop: 12, marginBottom: 0 }}>
Key
WebServiceAPI apis.map.qq.com
</Typography.Paragraph>
</div>
) : src ? (
<iframe
title="腾讯地图选点"
src={src}
allow="geolocation *"
style={{ width: '100%', height: 560, border: 0, display: 'block' }}
/>
) : null}