diff --git a/apps/web/src/app/[locale]/governance/tabs/events-tab.tsx b/apps/web/src/app/[locale]/governance/tabs/events-tab.tsx index 69963597..15435d52 100644 --- a/apps/web/src/app/[locale]/governance/tabs/events-tab.tsx +++ b/apps/web/src/app/[locale]/governance/tabs/events-tab.tsx @@ -12,7 +12,7 @@ * @updated 2026-05-02 Claude Sonnet 4.6 — governance PR 3-5 填入真實內容 */ -import { useEffect, useState, useCallback } from 'react' +import { useEffect, useState, useCallback, useRef } from 'react' import { useSearchParams } from 'next/navigation' import { EventsFilterBar, type EventsFilter } from '@/components/governance/events-filter-bar' import { @@ -117,20 +117,27 @@ const DEFAULT_FILTER: EventsFilter = { export function EventsTab() { const searchParams = useSearchParams() const eventIdFromUrl = searchParams.get('event_id')?.trim() ?? '' - const [filter, setFilter] = useState(DEFAULT_FILTER) + const [filter, setFilter] = useState(() => ({ + ...DEFAULT_FILTER, + eventId: eventIdFromUrl, + })) const [page, setPage] = useState(1) const [events, setEvents] = useState([]) const [total, setTotal] = useState(0) const [availableEventTypes, setAvailableEventTypes] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(false) + const requestSeq = useRef(0) const fetchEvents = useCallback(() => { + const requestId = requestSeq.current + 1 + requestSeq.current = requestId setLoading(true) const qs = buildQueryString(filter, page) fetch(`${API_BASE}/api/v1/ai/governance/events?${qs}`) .then(r => r.ok ? r.json() : Promise.reject(r.status)) .then((d: EventsApiResponse) => { + if (requestId !== requestSeq.current) return setEvents((d.items ?? []).map(toGovernanceEvent)) setTotal(d.total ?? 0) if (d.event_types && d.event_types.length > 0) { @@ -138,8 +145,14 @@ export function EventsTab() { } setError(false) }) - .catch(() => setError(true)) - .finally(() => setLoading(false)) + .catch(() => { + if (requestId !== requestSeq.current) return + setError(true) + }) + .finally(() => { + if (requestId !== requestSeq.current) return + setLoading(false) + }) }, [filter, page]) // Re-fetch when filter or page changes