优化桌面端界面布局

This commit is contained in:
Cheng Zhou
2026-07-07 11:11:43 +08:00
parent 84d5daebab
commit e7b18758b2
30 changed files with 3158 additions and 659 deletions
@@ -8,14 +8,32 @@ vi.mock("../router", () => ({
}));
const channelPostMessage = vi.fn();
const runtimeMocks = vi.hoisted(() => ({
isTauriRuntime: vi.fn(() => false),
}));
vi.mock("../runtime", async (importOriginal) => {
const actual = await importOriginal<typeof import("../runtime")>();
return {
...actual,
isTauriRuntime: runtimeMocks.isTauriRuntime,
};
});
vi.mock("../api/authClient", () => ({
extendToken: vi.fn(),
}));
const encodeJson = (value: unknown): string => Buffer.from(JSON.stringify(value)).toString("base64url");
const createJwt = (expiresAtMs: number): string =>
`${encodeJson({ alg: "none", typ: "JWT" })}.${encodeJson({ exp: Math.floor(expiresAtMs / 1000) })}.signature`;
describe("session manager idle logout", () => {
beforeEach(() => {
vi.resetModules();
vi.clearAllMocks();
runtimeMocks.isTauriRuntime.mockReturnValue(false);
vi.useFakeTimers();
setActivePinia(createPinia());
const storage = (() => {
@@ -82,6 +100,24 @@ describe("session manager idle logout", () => {
expect(router.replace).toHaveBeenCalledWith("/login");
});
it("does not force desktop logout after local inactivity", async () => {
runtimeMocks.isTauriRuntime.mockReturnValue(true);
vi.setSystemTime(new Date("2026-03-10T01:00:00.000Z"));
const { useSessionStore } = await import("../store/session");
const router = (await import("../router")).default;
const { IDLE_TIMEOUT_MINUTES, markUserActive } = await import("./sessionManager");
const session = useSessionStore();
const oldTs = Date.now() - (IDLE_TIMEOUT_MINUTES * 60 * 1000 + 1_000);
session.recordUserActivity(oldTs);
markUserActive(Date.now());
expect(window.sessionStorage.getItem("ctms_logout_reason")).toBeNull();
expect(router.replace).not.toHaveBeenCalled();
expect(session.timeoutWarningVisible).toBe(false);
});
it("clears the timeout warning when user activity resumes", async () => {
vi.setSystemTime(new Date("2026-03-10T01:00:00.000Z"));
const { useSessionStore } = await import("../store/session");
@@ -115,4 +151,27 @@ describe("session manager idle logout", () => {
expect(channelPostMessage).toHaveBeenCalledWith({ type: "TOKEN_UPDATED", token: "new-token" });
expect(window.localStorage.getItem("ctms_auth_broadcast")).toBeNull();
});
it("extends desktop tokens even when there has been no recent local activity", async () => {
vi.setSystemTime(new Date("2026-03-10T01:00:00.000Z"));
const { setToken } = await import("../utils/auth");
await setToken(createJwt(Date.now() + 30_000));
runtimeMocks.isTauriRuntime.mockReturnValue(true);
const { extendToken } = await import("../api/authClient");
vi.mocked(extendToken).mockResolvedValue({
data: {
accessToken: createJwt(Date.now() + 3_600_000),
expiresAt: "2026-03-10T02:00:00.000Z",
},
} as any);
const { useSessionStore } = await import("../store/session");
const { IDLE_TIMEOUT_MINUTES, startTokenKeepAlive } = await import("./sessionManager");
const session = useSessionStore();
session.recordUserActivity(Date.now() - (IDLE_TIMEOUT_MINUTES * 60 * 1000 + 1_000));
startTokenKeepAlive();
await vi.advanceTimersByTimeAsync(10_000);
expect(extendToken).toHaveBeenCalledTimes(1);
});
});