feat: 全面快取資料設計 & heartbeat 機制除錯完成
This commit is contained in:
parent
9365fef8c5
commit
98e78789e5
File diff suppressed because it is too large
Load Diff
|
|
@ -13,7 +13,13 @@ let currentEditElementId = null;
|
|||
let currentEditIsSuccess = false;
|
||||
let currentEditType = null; // 💡 新增:用來記錄是 'folder' 還是 'leaf'
|
||||
|
||||
window.onload = initTerminal;
|
||||
// 💤 全域閒置偵測
|
||||
let idleTimer;
|
||||
const IDLE_TIMEOUT = 300000; // 5 分鐘 (毫秒)
|
||||
window.onload = () => {
|
||||
initTerminal();
|
||||
resetIdleTimer(); // 頁面載入時啟動閒置計時器
|
||||
};
|
||||
window.onresize = () => { if (fitAddon) fitAddon.fit(); };
|
||||
|
||||
// ==========================================
|
||||
|
|
@ -22,16 +28,67 @@ window.onresize = () => { if (fitAddon) fitAddon.fit(); };
|
|||
const SESSION_USER_ID = crypto.randomUUID ? crypto.randomUUID() : 'user-' + Math.random().toString(36).substr(2, 9);
|
||||
const ACTIVE_HEARTBEATS = {};
|
||||
|
||||
// 💤 閒置超時,自動釋放所有鎖
|
||||
async function releaseAllLocks() {
|
||||
const pathsToRelease = Object.keys(ACTIVE_HEARTBEATS);
|
||||
if (pathsToRelease.length === 0) return; // 如果沒有鎖,就不用執行
|
||||
|
||||
// 建立一個 Promise 陣列,來平行處理所有釋放請求
|
||||
const releasePromises = pathsToRelease.map(path => {
|
||||
// 1. 清除心跳計時器
|
||||
clearInterval(ACTIVE_HEARTBEATS[path]);
|
||||
delete ACTIVE_HEARTBEATS[path];
|
||||
|
||||
// 2. 發送釋放請求
|
||||
return fetch('/api/v1/locks/release', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: path, user_id: SESSION_USER_ID })
|
||||
}).catch(err => console.error(`釋放鎖定 ${path} 失敗:`, err));
|
||||
});
|
||||
|
||||
// 3. 等待所有釋放請求完成
|
||||
await Promise.all(releasePromises);
|
||||
|
||||
// 4. 提示並重整頁面
|
||||
alert("您已閒置超過 5 分鐘,系統已自動釋放編輯鎖定並重新整理頁面。");
|
||||
location.reload();
|
||||
}
|
||||
|
||||
// 💓 發送心跳,告訴後端「我還在編輯」,請延長鎖定時間
|
||||
async function sendHeartbeat(path) {
|
||||
try {
|
||||
await fetch('/api/v1/locks/heartbeat', {
|
||||
const response = await fetch('/api/v1/locks/heartbeat', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: path, user_id: SESSION_USER_ID })
|
||||
});
|
||||
} catch (error) {}
|
||||
|
||||
if (!response.ok) {
|
||||
console.warn(`心跳發送失敗 (${path}): 伺服器回傳 ${response.status}`);
|
||||
// 如果回傳 404,代表後端的鎖已經被清掉了,停止發送心跳
|
||||
if (response.status === 404) {
|
||||
clearInterval(ACTIVE_HEARTBEATS[path]);
|
||||
delete ACTIVE_HEARTBEATS[path];
|
||||
}
|
||||
} else {
|
||||
console.log(`💓 心跳已送出,鎖定已延長 (${path})`); // 測試用,確認沒問題後可刪除這行
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`心跳請求發生錯誤 (${path}):`, error);
|
||||
}
|
||||
}
|
||||
|
||||
// 實作閒置計時器重置邏輯
|
||||
function resetIdleTimer() {
|
||||
clearTimeout(idleTimer);
|
||||
idleTimer = setTimeout(releaseAllLocks, IDLE_TIMEOUT); // IDLE_TIMEOUT 是 300000
|
||||
}
|
||||
|
||||
// 監聽使用者的互動事件,只要有動作就重置計時器
|
||||
window.addEventListener('mousemove', resetIdleTimer);
|
||||
window.addEventListener('keydown', resetIdleTimer);
|
||||
window.addEventListener('click', resetIdleTimer);
|
||||
// 🎨 輔助函數:解析終端機輸出,僅將錯誤/警告行標紅
|
||||
function highlightTerminalOutput(text) {
|
||||
if (!text) return '';
|
||||
|
|
|
|||
Loading…
Reference in New Issue