Files
model-platform/frontend/app/features/platform/hooks/useEditSessionLifecycle.ts
T
2026-08-07 12:23:50 +08:00

71 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect } from "react";
import {
bindScriptWorkspaceApi,
editSessionHandle,
useScriptWorkspaceStore,
} from "../state/scriptWorkspaceStore";
type ActivePage = "home" | "scripts" | "schedules" | "system";
/**
* 必须在 layout 层挂载,不能放在 ScriptsPage。
* 原因:心跳 / cleanup / beforeunload 需要在用户切到 /schedules 时仍运行,
* 否则其他 tab 中的编辑会话锁会过期。
*/
export function useEditSessionLifecycle({
activePage,
}: {
activePage: ActivePage;
}) {
// 1) 切到非 scripts 页时,如果当前有 active session,结束编辑
useEffect(() => {
if (activePage === "scripts") return;
const editBusy = useScriptWorkspaceStore.getState().editBusy;
if (editBusy) return;
if (!editSessionHandle.current) return;
void useScriptWorkspaceStore.getState().endEditing(true, false);
}, [activePage]);
// 2) 心跳 + cleanup 定时器(15s 心跳,60s 检查 cleanup
useEffect(() => {
let heartbeatRunning = false;
let cleanupRunning = false;
const heartbeatTimer = window.setInterval(() => {
if (heartbeatRunning) return;
heartbeatRunning = true;
void useScriptWorkspaceStore.getState().tickHeartbeats().finally(() => {
heartbeatRunning = false;
});
}, 15 * 1000);
const cleanupTimer = window.setInterval(() => {
if (cleanupRunning) return;
cleanupRunning = true;
try {
useScriptWorkspaceStore.getState().tickCleanup();
} finally {
cleanupRunning = false;
}
}, 60 * 1000);
return () => {
window.clearInterval(heartbeatTimer);
window.clearInterval(cleanupTimer);
};
}, []);
// 3) 卸载前释放编辑锁
useEffect(() => {
const handleUnload = () => {
useScriptWorkspaceStore.getState().releaseActiveOnUnload();
};
window.addEventListener("beforeunload", handleUnload);
return () => window.removeEventListener("beforeunload", handleUnload);
}, []);
// 4) layout 卸载时解绑 api
useEffect(() => {
return () => {
bindScriptWorkspaceApi(null);
};
}, []);
}