ソースを参照

fix: 阻塞服务未就绪时的认证检查和页面导航

1. server store 添加 servicesReady 状态
2. App.vue 在服务就绪时设置全局状态
3. router 守卫在服务未就绪时等待,仅在服务就绪后调用 checkAuth
   - Login/Register/ServerConfig 可直接访问(无需等待)
   - 其他页面需要等待服务就绪后再导航

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ethanfly 4 日 前
コミット
9224e6f8c0
3 ファイル変更28 行追加9 行削除
  1. 1 0
      client/src/App.vue
  2. 24 8
      client/src/router/index.ts
  3. 3 1
      client/src/stores/server.ts

+ 1 - 0
client/src/App.vue

@@ -63,6 +63,7 @@ async function onServicesStatusChanged(status: { nodeOk: boolean; pythonOk: bool
 
   if (status.nodeOk && status.pythonOk) {
     servicesReady.value = true;
+    serverStore.servicesReady = true;  // 通知全局服务已就绪
     // 自动配置本地服务
     autoConfigLocalServices();
     // 路由首次导航完成后隐藏加载界面

+ 24 - 8
client/src/router/index.ts

@@ -117,37 +117,53 @@ let configLoaded = false;
 router.beforeEach(async (to, _from, next) => {
   const authStore = useAuthStore();
   const serverStore = useServerStore();
-  
+
   // 加载服务器配置(异步,仅执行一次)
   if (!configLoaded) {
     configLoaded = true;
     await serverStore.loadConfig();
   }
-  
+
   // 检查服务器配置
   if (!serverStore.isConfigured && to.name !== 'ServerConfig') {
     next({ name: 'ServerConfig' });
     return;
   }
-  
-  // 首次进入需要认证的页面时,先检查认证状态
-  if (!authInitialized && serverStore.isConfigured) {
+
+  // 如果服务未就绪,等待服务就绪(不阻止 /login 和 /register 页面)
+  if (!serverStore.servicesReady && !['Login', 'Register', 'ServerConfig'].includes(to.name as string)) {
+    // 等待服务就绪后再导航
+    const waitForServices = () => {
+      return new Promise<void>((resolve) => {
+        const checkInterval = setInterval(() => {
+          if (serverStore.servicesReady) {
+            clearInterval(checkInterval);
+            resolve();
+          }
+        }, 100);
+      });
+    };
+    await waitForServices();
+  }
+
+  // 首次进入需要认证的页面时,先检查认证状态(仅在服务就绪后)
+  if (!authInitialized && serverStore.isConfigured && serverStore.servicesReady) {
     authInitialized = true;
     await authStore.checkAuth();
   }
-  
+
   // 检查认证
   if (to.meta.requiresAuth && !authStore.isAuthenticated) {
     next({ name: 'Login' });
     return;
   }
-  
+
   // 已登录用户不能访问登录/注册页
   if (authStore.isAuthenticated && ['Login', 'Register'].includes(to.name as string)) {
     next({ name: 'Dashboard' });
     return;
   }
-  
+
   next();
 });
 

+ 3 - 1
client/src/stores/server.ts

@@ -19,8 +19,9 @@ export const useServerStore = defineStore('server', () => {
   const currentServerId = ref<string | null>(null);
   const connectionStatus = ref<'connected' | 'disconnected' | 'checking'>('disconnected');
   const lastConnectionError = ref<string | null>(null);
+  const servicesReady = ref(false);  // 服务是否已就绪
 
-  const currentServer = computed(() => 
+  const currentServer = computed(() =>
     servers.value.find(s => s.id === currentServerId.value)
   );
 
@@ -156,6 +157,7 @@ export const useServerStore = defineStore('server', () => {
     currentServerId,
     connectionStatus,
     lastConnectionError,
+    servicesReady,
     isConfigured,
     loadConfig,
     addServer,