feat(workbench): expand SCADA monitoring and investigation presentation
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import type { EventGpsCoordinate } from "./event-location-coordinate";
|
||||
|
||||
export type EventLocationAddressResolver = (coordinate: EventGpsCoordinate, signal: AbortSignal) => Promise<string>;
|
||||
|
||||
export type EventLocationAddressLookup = {
|
||||
pending: boolean;
|
||||
error: string | null;
|
||||
changeLocation: (value: string) => void;
|
||||
retry: () => void;
|
||||
};
|
||||
|
||||
export function useEventLocationAddress({ active = true, coordinate, resolveAddress, onChange }: {
|
||||
active?: boolean;
|
||||
coordinate: EventGpsCoordinate | null;
|
||||
resolveAddress: EventLocationAddressResolver;
|
||||
onChange: (value: string) => void;
|
||||
}): EventLocationAddressLookup {
|
||||
const [pending, setPending] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [retryGeneration, setRetryGeneration] = useState(0);
|
||||
const requestRef = useRef<AbortController | null>(null);
|
||||
const longitude = coordinate?.[0];
|
||||
const latitude = coordinate?.[1];
|
||||
|
||||
useEffect(() => {
|
||||
setError(null);
|
||||
if (!active || longitude === undefined || latitude === undefined) {
|
||||
setPending(false);
|
||||
return;
|
||||
}
|
||||
const controller = new AbortController();
|
||||
requestRef.current = controller;
|
||||
setPending(true);
|
||||
onChange("");
|
||||
// Coalesce keyboard adjustments. GPS stays immediate while only the final
|
||||
// point is reverse-geocoded; a former point's address must never be reused.
|
||||
const timer = window.setTimeout(async () => {
|
||||
if (controller.signal.aborted) return;
|
||||
try {
|
||||
const address = await resolveAddress([longitude, latitude], controller.signal);
|
||||
if (!controller.signal.aborted) onChange(address);
|
||||
} catch (failure) {
|
||||
if (!controller.signal.aborted) {
|
||||
setError(failure instanceof Error ? failure.message : "地址查询失败,请重试或手动填写");
|
||||
}
|
||||
} finally {
|
||||
if (!controller.signal.aborted) setPending(false);
|
||||
}
|
||||
}, 250);
|
||||
return () => {
|
||||
window.clearTimeout(timer);
|
||||
controller.abort();
|
||||
if (requestRef.current === controller) requestRef.current = null;
|
||||
};
|
||||
}, [active, longitude, latitude, resolveAddress, onChange, retryGeneration]);
|
||||
|
||||
const changeLocation = useCallback((value: string) => {
|
||||
requestRef.current?.abort();
|
||||
setPending(false);
|
||||
setError(null);
|
||||
onChange(value);
|
||||
}, [onChange]);
|
||||
|
||||
return { pending, error, changeLocation, retry: () => setRetryGeneration((current) => current + 1) };
|
||||
}
|
||||
Reference in New Issue
Block a user