From ca0dbbf0c58b66af44a4865e91c7f14f6adf28fb Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Sun, 27 Sep 2026 14:51:52 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E7=99=BB=E5=BD=95=E6=80=81):=20=E9=80=80?= =?UTF-8?q?=E5=87=BA=E5=92=8C=E6=8D=A2=E4=BA=BA=E7=99=BB=E5=BD=95=E6=97=B6?= =?UTF-8?q?=E6=95=B4=E9=A1=B5=E9=87=8D=E8=BD=BD=EF=BC=8C=E4=B8=8D=E7=95=99?= =?UTF-8?q?=E4=B8=8A=E4=B8=80=E4=B8=AA=E4=BA=BA=E7=9A=84=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit signOut 只清了 profile 和 localStorage,AI 分析、学情小结等 store 还在内存里。 机房一台机器轮着用,下一个学生登进来就能看到上一个人的 AI 分析。 - 主动退出:router.replace 换成 window.location.replace("/") - 被动下线(会话过期、别的标签页登出)仍然原地弹登录框,学生正在写的代码不丢; getMyProfile 记住本页最后一个登录的用户,登进来的换了人就整页重载 挨个 store 去 reset 迟早漏一个,重载一次最彻底。 Co-Authored-By: Claude Opus 5.5 --- apps/web/src/shared/components/Header.vue | 4 +++- apps/web/src/shared/store/user.ts | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/web/src/shared/components/Header.vue b/apps/web/src/shared/components/Header.vue index 7a09de2..2a19fc9 100644 --- a/apps/web/src/shared/components/Header.vue +++ b/apps/web/src/shared/components/Header.vue @@ -90,7 +90,9 @@ const active = computed(() => route.path.split("/")[1] || "problem") async function handleLogout() { await userStore.signOut() - router.replace("/") + // 整页跳转而不是 router.replace:AI 分析、学情小结这些 store 还装着这个人的数据, + // 机房下一个学生坐下来就能看到。重载一次把内存清干净,比挨个 reset 可靠。 + window.location.replace("/") } function handleToggleDemoMode() { diff --git a/apps/web/src/shared/store/user.ts b/apps/web/src/shared/store/user.ts index 8272f09..f169bc5 100644 --- a/apps/web/src/shared/store/user.ts +++ b/apps/web/src/shared/store/user.ts @@ -66,11 +66,24 @@ export const useUserStore = defineStore("user", () => { // 登录后和改完设置仍然要能重新拉一份。 let inflight: Promise | null = null + // 这个页面生命周期里最后一个登录过的人。**clearProfile 不清它**,就是为了下面那道闸。 + let lastUserId: number | null = null + function getMyProfile() { if (inflight) return inflight isFinished.value = false inflight = getProfile() .then((res) => { + // 换了人就整页重载。会话过期、别的标签页登出这类被动下线是**原地**弹登录框 + // 的(学生正在写的代码不能丢),可内存里的 store 全是上一个人的:AI 分析、 + // 学情小结、协作状态……机房一台机器轮着用,下一个学生登进来就能看到。 + // 挨个 store 去 reset 迟早漏一个,重载一次最彻底;同一个人重新登录不受影响。 + const id = res?.user?.id ?? null + if (id !== null && lastUserId !== null && id !== lastUserId) { + window.location.reload() + return + } + if (id !== null) lastUserId = id profile.value = res isFinished.value = true storage.set(STORAGE_KEY.AUTHED, !!user.value?.email) @@ -90,7 +103,8 @@ export const useUserStore = defineStore("user", () => { } // 退登的两步(吊销服务端会话、清本地状态)绑在一起:只清本地会留一个还活着 - // 的 cookie,下次进站又被 /profile 认回来。跳转留给调用方,store 里不碰路由。 + // 的 cookie,下次进站又被 /profile 认回来。跳转留给调用方,store 里不碰路由 —— + // 调用方要**整页**跳走,别用 router:各个 store 里还留着这个人的数据。 async function signOut() { await logout() clearProfile()