feat(platform): add realtime auto refresh controls

This commit is contained in:
lingniu
2026-07-04 17:07:51 +08:00
parent 5ca6b51d0b
commit 34a9def4ff
2 changed files with 93 additions and 1 deletions

View File

@@ -71,6 +71,15 @@ function realtimeMapPointId(row: VehicleRealtimeRow, index = 0) {
return row.vin?.trim() || `${row.primaryProtocol || 'source'}-${index}`;
}
function formatRefreshTime(date: Date) {
return date.toLocaleTimeString('zh-CN', {
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
function amapMarkerURL(row: VehicleRealtimeRow) {
const name = encodeURIComponent(row.plate || row.vin || '车辆位置');
return `https://uri.amap.com/marker?position=${row.longitude},${row.latitude}&name=${name}&src=lingniu-vehicle-platform`;
@@ -200,6 +209,9 @@ export function Realtime({
const [pagination, setPagination] = useState({ currentPage: 1, pageSize: 50, total: 0 });
const [opsHealth, setOpsHealth] = useState<OpsHealth | null>(null);
const [selectedMapPointId, setSelectedMapPointId] = useState('');
const [lastRefreshAt, setLastRefreshAt] = useState('');
const [autoRefresh, setAutoRefresh] = useState(true);
const refreshIntervalSeconds = 15;
const amapConfig = getAMapConfig();
const runtime = opsHealth?.runtime;
const amapConfigured = runtime?.amapWebJsConfigured ?? isAMapConfigured(amapConfig);
@@ -214,10 +226,11 @@ export function Realtime({
if (values?.protocol) params.set('protocol', values.protocol);
if (values?.online) params.set('online', values.online);
if (values?.serviceStatus) params.set('serviceStatus', values.serviceStatus);
api.vehicleRealtime(params)
return api.vehicleRealtime(params)
.then((nextPage) => {
setRows(nextPage.items);
setPagination({ currentPage: page, pageSize, total: nextPage.total });
setLastRefreshAt(formatRefreshTime(new Date()));
})
.catch((error: Error) => Toast.error(error.message))
.finally(() => setLoading(false));
@@ -231,6 +244,16 @@ export function Realtime({
.catch(() => setOpsHealth(null));
}, [JSON.stringify(initialFilters)]);
useEffect(() => {
if (!autoRefresh) {
return undefined;
}
const timer = window.setInterval(() => {
load(filters, pagination.currentPage, pagination.pageSize);
}, refreshIntervalSeconds * 1000);
return () => window.clearInterval(timer);
}, [autoRefresh, JSON.stringify(filters), pagination.currentPage, pagination.pageSize]);
const applyFilters = (nextFilters: Record<string, string>) => {
setFilters(nextFilters);
onFiltersChange?.(nextFilters);
@@ -367,6 +390,18 @@ export function Realtime({
}}></Button>
</Space>
</Form>
<div className="vp-table-toolbar">
<Space wrap>
<Tag color={autoRefresh ? 'green' : 'grey'}> {refreshIntervalSeconds}</Tag>
<Typography.Text type="secondary">{lastRefreshAt || '等待首次刷新'}</Typography.Text>
<Button size="small" theme="light" aria-label="刷新实时数据" loading={loading} onClick={() => load(filters, pagination.currentPage, pagination.pageSize)}>
</Button>
<Button size="small" theme="light" aria-label={autoRefresh ? '暂停自动刷新' : '开启自动刷新'} onClick={() => setAutoRefresh((value) => !value)}>
{autoRefresh ? '暂停自动刷新' : '开启自动刷新'}
</Button>
</Space>
</div>
{filterSummary.length > 0 ? (
<Card bordered title="当前实时筛选" style={{ marginBottom: 12 }}>
<Space wrap>