登录页UI及长时间未操作锁定逻辑优化

This commit is contained in:
Cheng Zhou
2026-03-10 10:10:58 +08:00
parent 7936c55f3f
commit 4c98147f3e
12 changed files with 2225 additions and 470 deletions
@@ -0,0 +1,86 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createPinia, setActivePinia } from "pinia";
vi.mock("../router", () => ({
default: {
replace: vi.fn(),
},
}));
vi.mock("../api/authClient", () => ({
extendToken: vi.fn(),
unlockSession: vi.fn(),
}));
describe("session manager idle recovery", () => {
beforeEach(() => {
vi.resetModules();
vi.useFakeTimers();
setActivePinia(createPinia());
const storage = (() => {
const data = new Map<string, string>();
return {
getItem: (key: string) => data.get(key) ?? null,
setItem: (key: string, value: string) => {
data.set(key, String(value));
},
removeItem: (key: string) => {
data.delete(key);
},
clear: () => {
data.clear();
},
};
})();
Object.defineProperty(window, "localStorage", {
value: storage,
configurable: true,
});
Object.defineProperty(window, "sessionStorage", {
value: storage,
configurable: true,
});
Object.defineProperty(window, "BroadcastChannel", {
value: class {
onmessage: ((event: MessageEvent) => void) | null = null;
postMessage() {}
close() {}
},
configurable: true,
});
});
it("locks instead of refreshing activity after long inactivity when user activity resumes", async () => {
vi.setSystemTime(new Date("2026-03-10T01:00:00.000Z"));
const { useSessionStore } = await import("../store/session");
const { IDLE_TIMEOUT_MINUTES, AUTO_LOGOUT_TIMEOUT_HOURS, markUserActive } = await import("./sessionManager");
const session = useSessionStore();
const oldTs = Date.now() - (IDLE_TIMEOUT_MINUTES * 60 * 1000 + 1_000);
session.recordUserActivity(oldTs);
session.recordNetworkActivity(oldTs);
markUserActive(Date.now());
expect(session.locked).toBe(true);
expect(session.lockReason).toBe("idle");
expect(session.lockAutoLogoutDeadlineAt).toBe(oldTs + AUTO_LOGOUT_TIMEOUT_HOURS * 60 * 60 * 1000);
});
it("locks instead of refreshing activity after long inactivity when network activity resumes", async () => {
vi.setSystemTime(new Date("2026-03-10T01:00:00.000Z"));
const { useSessionStore } = await import("../store/session");
const { IDLE_TIMEOUT_MINUTES, AUTO_LOGOUT_TIMEOUT_HOURS, markNetworkActive } = await import("./sessionManager");
const session = useSessionStore();
const oldTs = Date.now() - (IDLE_TIMEOUT_MINUTES * 60 * 1000 + 1_000);
session.recordUserActivity(oldTs);
session.recordNetworkActivity(oldTs);
markNetworkActive(Date.now());
expect(session.locked).toBe(true);
expect(session.lockReason).toBe("idle");
expect(session.lockAutoLogoutDeadlineAt).toBe(oldTs + AUTO_LOGOUT_TIMEOUT_HOURS * 60 * 60 * 1000);
});
});