diff --git a/vehicle-data-platform/apps/web/src/v2/routing/RouteBoundary.test.tsx b/vehicle-data-platform/apps/web/src/v2/routing/RouteBoundary.test.tsx
index 04ea6d4c..452a2c81 100644
--- a/vehicle-data-platform/apps/web/src/v2/routing/RouteBoundary.test.tsx
+++ b/vehicle-data-platform/apps/web/src/v2/routing/RouteBoundary.test.tsx
@@ -58,4 +58,29 @@ describe('route recovery boundary', () => {
expect(screen.getByText('本地状态 1')).toBeInTheDocument();
expect(mounts).toBe(1);
});
+
+ it('retries a failed route when its search scope changes without remounting healthy scopes', () => {
+ vi.spyOn(console, 'error').mockImplementation(() => undefined);
+ let healthyMounts = 0;
+ function ScopeSensitivePage() {
+ const [params] = useSearchParams();
+ if (params.get('scope') === 'broken') throw new Error('invalid route scope');
+ useEffect(() => { healthyMounts += 1; }, []);
+ return 新筛选范围已恢复;
+ }
+ function RecoveryHarness() {
+ const [, setSearchParams] = useSearchParams();
+ return <>>;
+ }
+
+ render();
+ expect(screen.getByRole('alert')).toHaveTextContent('当前模块暂时无法显示');
+ expect(screen.getByText(/更换筛选条件会自动重试/)).toBeInTheDocument();
+
+ fireEvent.click(screen.getByRole('button', { name: '修正筛选条件' }));
+
+ expect(screen.queryByRole('alert')).not.toBeInTheDocument();
+ expect(screen.getByText('新筛选范围已恢复')).toBeInTheDocument();
+ expect(healthyMounts).toBe(1);
+ });
});
diff --git a/vehicle-data-platform/apps/web/src/v2/routing/RouteBoundary.tsx b/vehicle-data-platform/apps/web/src/v2/routing/RouteBoundary.tsx
index 289c02a6..d4be24fc 100644
--- a/vehicle-data-platform/apps/web/src/v2/routing/RouteBoundary.tsx
+++ b/vehicle-data-platform/apps/web/src/v2/routing/RouteBoundary.tsx
@@ -42,6 +42,12 @@ class RecoverableRouteBoundary extends Component<{ children: ReactNode; routeKey
}
}
+ componentDidUpdate(previous: Readonly<{ children: ReactNode; routeKey: string }>) {
+ if (this.state.error && previous.routeKey !== this.props.routeKey) {
+ this.setState({ error: undefined });
+ }
+ }
+
render() {
const { error } = this.state;
if (!error) return this.props.children;
@@ -51,7 +57,7 @@ class RecoverableRouteBoundary extends Component<{ children: ReactNode; routeKey
{chunkError ? '检测到页面版本更新' : '页面运行异常'}
{chunkError ? '正在等待加载最新页面资源' : '当前模块暂时无法显示'}
-
{chunkError ? '通常是发布后旧标签页仍引用上一版本资源。刷新后会恢复,不会丢失服务端数据。' : '页面已被安全隔离,侧栏和其他模块仍可使用。可刷新当前页面重试。'}
+
{chunkError ? '通常是发布后旧标签页仍引用上一版本资源。刷新后会恢复,不会丢失服务端数据。' : '页面已被安全隔离,侧栏和其他模块仍可使用。更换筛选条件会自动重试,也可刷新当前页面。'}
{error.message || error.name}