mirror of
https://github.com/Minidoracat/mcp-feedback-enhanced.git
synced 2025-07-27 02:22:26 +08:00
🔨 重新調整會話超時機制、增加設定功能
This commit is contained in:
parent
60e64c90dc
commit
441df85e1e
@ -122,7 +122,13 @@
|
||||
"resetError": "Error occurred while resetting settings",
|
||||
"timeout": "Connection Timeout (seconds)",
|
||||
"autorefresh": "Auto Refresh",
|
||||
"debug": "Debug Mode"
|
||||
"debug": "Debug Mode",
|
||||
"sessionTimeoutTitle": "⏱️ Session Timeout Settings",
|
||||
"sessionTimeoutEnable": "Enable Session Timeout",
|
||||
"sessionTimeoutEnableDesc": "When enabled, the session will automatically close after the specified time",
|
||||
"sessionTimeoutDuration": "Timeout Duration (seconds)",
|
||||
"sessionTimeoutDurationDesc": "Set session timeout duration, range: 300-86400 seconds (5 minutes - 24 hours)",
|
||||
"sessionTimeoutSeconds": "seconds"
|
||||
},
|
||||
"languages": {
|
||||
"zh-TW": "繁體中文",
|
||||
@ -200,7 +206,8 @@
|
||||
"timeout": "⏰ Session has timed out, interface will close automatically",
|
||||
"timeoutWarning": "Session is about to timeout",
|
||||
"timeoutDescription": "Due to prolonged inactivity, the session has timed out. The interface will automatically close in 3 seconds.",
|
||||
"closing": "Closing..."
|
||||
"closing": "Closing...",
|
||||
"label": "Session Timeout:"
|
||||
},
|
||||
"autoRefresh": {
|
||||
"enable": "Auto Detect",
|
||||
|
@ -123,7 +123,13 @@
|
||||
"timeout": "连线逾时 (秒)",
|
||||
"autorefresh": "自动重新整理",
|
||||
"debug": "除错模式",
|
||||
"autoCommitNoPrompt": "请先选择一个提示词作为自动提交内容"
|
||||
"autoCommitNoPrompt": "请先选择一个提示词作为自动提交内容",
|
||||
"sessionTimeoutTitle": "⏱️ 会话超时设置",
|
||||
"sessionTimeoutEnable": "启用会话超时",
|
||||
"sessionTimeoutEnableDesc": "启用后,会话将在指定时间后自动关闭",
|
||||
"sessionTimeoutDuration": "超时时间(秒)",
|
||||
"sessionTimeoutDurationDesc": "设置会话超时时间,范围:300-86400 秒(5分钟-24小时)",
|
||||
"sessionTimeoutSeconds": "秒"
|
||||
},
|
||||
"languages": {
|
||||
"zh-TW": "繁體中文",
|
||||
@ -201,7 +207,8 @@
|
||||
"timeout": "⏰ 会话已超时,界面将自动关闭",
|
||||
"timeoutWarning": "会话即将超时",
|
||||
"timeoutDescription": "由于长时间无响应,会话已超时。界面将在 3 秒后自动关闭。",
|
||||
"closing": "正在关闭..."
|
||||
"closing": "正在关闭...",
|
||||
"label": "会话超时:"
|
||||
},
|
||||
"autoRefresh": {
|
||||
"enable": "自动检测",
|
||||
|
@ -128,7 +128,13 @@
|
||||
"timeout": "連線逾時 (秒)",
|
||||
"autorefresh": "自動重新整理",
|
||||
"debug": "除錯模式",
|
||||
"autoCommitNoPrompt": "請先選擇一個提示詞作為自動提交內容"
|
||||
"autoCommitNoPrompt": "請先選擇一個提示詞作為自動提交內容",
|
||||
"sessionTimeoutTitle": "⏱️ 會話超時設定",
|
||||
"sessionTimeoutEnable": "啟用會話超時",
|
||||
"sessionTimeoutEnableDesc": "啟用後,會話將在指定時間後自動關閉",
|
||||
"sessionTimeoutDuration": "超時時間(秒)",
|
||||
"sessionTimeoutDurationDesc": "設定會話超時時間,範圍:300-86400 秒(5分鐘-24小時)",
|
||||
"sessionTimeoutSeconds": "秒"
|
||||
},
|
||||
"languages": {
|
||||
"zh-TW": "繁體中文",
|
||||
@ -206,7 +212,9 @@
|
||||
"timeout": "⏰ 會話已超時,介面將自動關閉",
|
||||
"timeoutWarning": "會話即將超時",
|
||||
"timeoutDescription": "由於長時間無回應,會話已超時。介面將在 3 秒後自動關閉。",
|
||||
"closing": "正在關閉..."
|
||||
"closing": "正在關閉...",
|
||||
"triggered": "會話已超時,程序即將關閉",
|
||||
"label": "會話超時:"
|
||||
},
|
||||
"autoRefresh": {
|
||||
"enable": "自動檢測",
|
||||
|
@ -168,6 +168,11 @@ class WebFeedbackSession:
|
||||
# 新增:活躍標籤頁管理
|
||||
self.active_tabs: dict[str, Any] = {}
|
||||
|
||||
# 新增:用戶設定的會話超時
|
||||
self.user_timeout_enabled = False
|
||||
self.user_timeout_seconds = 3600 # 預設 1 小時
|
||||
self.user_timeout_timer: threading.Timer | None = None
|
||||
|
||||
# 確保臨時目錄存在
|
||||
TEMP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@ -421,6 +426,39 @@ class WebFeedbackSession:
|
||||
)
|
||||
return stats
|
||||
|
||||
def update_timeout_settings(self, enabled: bool, timeout_seconds: int = 3600):
|
||||
"""
|
||||
更新用戶設定的會話超時
|
||||
|
||||
Args:
|
||||
enabled: 是否啟用超時
|
||||
timeout_seconds: 超時秒數
|
||||
"""
|
||||
debug_log(f"更新會話超時設定: enabled={enabled}, seconds={timeout_seconds}")
|
||||
|
||||
# 先停止現有的計時器
|
||||
if self.user_timeout_timer:
|
||||
self.user_timeout_timer.cancel()
|
||||
self.user_timeout_timer = None
|
||||
|
||||
self.user_timeout_enabled = enabled
|
||||
self.user_timeout_seconds = timeout_seconds
|
||||
|
||||
# 如果啟用且會話還在等待中,啟動計時器
|
||||
if enabled and self.status == SessionStatus.WAITING:
|
||||
|
||||
def timeout_handler():
|
||||
debug_log(f"用戶設定的超時已到: {self.session_id}")
|
||||
# 設置超時標誌
|
||||
self.status = SessionStatus.TIMEOUT
|
||||
self.status_message = "用戶設定的會話超時"
|
||||
# 設置完成事件,讓 wait_for_feedback 結束等待
|
||||
self.feedback_completed.set()
|
||||
|
||||
self.user_timeout_timer = threading.Timer(timeout_seconds, timeout_handler)
|
||||
self.user_timeout_timer.start()
|
||||
debug_log(f"已啟動用戶超時計時器: {timeout_seconds}秒")
|
||||
|
||||
async def wait_for_feedback(self, timeout: int = 600) -> dict[str, Any]:
|
||||
"""
|
||||
等待用戶回饋,包含圖片,支援超時自動清理
|
||||
@ -450,6 +488,12 @@ class WebFeedbackSession:
|
||||
completed = await loop.run_in_executor(None, wait_in_thread)
|
||||
|
||||
if completed:
|
||||
# 檢查是否是用戶設定的超時
|
||||
if self.status == SessionStatus.TIMEOUT and self.user_timeout_enabled:
|
||||
debug_log(f"會話 {self.session_id} 因用戶設定超時而結束")
|
||||
await self._cleanup_resources_on_timeout()
|
||||
raise TimeoutError("會話已因用戶設定的超時而關閉")
|
||||
|
||||
debug_log(f"會話 {self.session_id} 收到用戶回饋")
|
||||
return {
|
||||
"logs": "\n".join(self.command_logs),
|
||||
@ -753,6 +797,12 @@ class WebFeedbackSession:
|
||||
self.cleanup_timer = None
|
||||
resources_cleaned += 1
|
||||
|
||||
# 1.5. 取消用戶超時計時器
|
||||
if self.user_timeout_timer:
|
||||
self.user_timeout_timer.cancel()
|
||||
self.user_timeout_timer = None
|
||||
resources_cleaned += 1
|
||||
|
||||
# 2. 關閉 WebSocket 連接
|
||||
if self.websocket:
|
||||
try:
|
||||
|
@ -672,6 +672,17 @@ async def handle_websocket_message(manager: "WebUIManager", session, data: dict)
|
||||
debug_log(f"收到 pong 回應,時間戳: {data.get('timestamp', 'N/A')}")
|
||||
# 可以在這裡記錄延遲或更新連接狀態
|
||||
|
||||
elif message_type == "update_timeout_settings":
|
||||
# 處理超時設定更新
|
||||
settings = data.get("settings", {})
|
||||
debug_log(f"收到超時設定更新: {settings}")
|
||||
if settings.get("enabled"):
|
||||
session.update_timeout_settings(
|
||||
enabled=True, timeout_seconds=settings.get("seconds", 3600)
|
||||
)
|
||||
else:
|
||||
session.update_timeout_settings(enabled=False)
|
||||
|
||||
else:
|
||||
debug_log(f"未知的消息類型: {message_type}")
|
||||
|
||||
|
@ -2011,3 +2011,67 @@ textarea:-ms-input-placeholder,
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* 會話超時倒數樣式 */
|
||||
.session-timeout-display {
|
||||
background: rgba(255, 193, 7, 0.1);
|
||||
border: 1px solid rgba(255, 193, 7, 0.3);
|
||||
border-radius: 4px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
.session-timeout-display .timeout-label {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.session-timeout-display .countdown-timer {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.session-timeout-display.countdown-warning .countdown-timer {
|
||||
color: var(--error-color);
|
||||
animation: pulse 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* 自動提交倒數樣式 */
|
||||
.auto-submit-display {
|
||||
background: rgba(76, 175, 80, 0.1);
|
||||
border: 1px solid rgba(76, 175, 80, 0.3);
|
||||
border-radius: 4px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
.auto-submit-display .countdown-label {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.auto-submit-display .countdown-timer {
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 倒數控制按鈕 */
|
||||
.countdown-control-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 2px 6px;
|
||||
margin-left: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.countdown-control-btn:hover {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.6; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
|
@ -271,7 +271,16 @@
|
||||
}
|
||||
}, 800); // 延遲 800ms 確保所有初始化完成且避免與其他音效衝突
|
||||
|
||||
// 17. 建立 WebSocket 連接
|
||||
// 17. 初始化會話超時設定
|
||||
if (self.settingsManager.get('sessionTimeoutEnabled')) {
|
||||
const timeoutSettings = {
|
||||
enabled: self.settingsManager.get('sessionTimeoutEnabled'),
|
||||
seconds: self.settingsManager.get('sessionTimeoutSeconds')
|
||||
};
|
||||
self.webSocketManager.updateSessionTimeoutSettings(timeoutSettings);
|
||||
}
|
||||
|
||||
// 18. 建立 WebSocket 連接
|
||||
self.webSocketManager.connect();
|
||||
|
||||
resolve();
|
||||
@ -361,6 +370,9 @@
|
||||
// 設置設定管理器的事件監聽器
|
||||
self.settingsManager.setupEventListeners();
|
||||
|
||||
// 設置用戶活動監聽(用於重置會話超時)
|
||||
self.setupUserActivityListeners();
|
||||
|
||||
console.log('✅ 事件監聽器設置完成');
|
||||
resolve();
|
||||
});
|
||||
@ -836,13 +848,20 @@
|
||||
|
||||
// 4. 重置回饋狀態為等待中
|
||||
if (self.uiManager) {
|
||||
self.uiManager.setFeedbackState(
|
||||
window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING,
|
||||
self.currentSessionId
|
||||
);
|
||||
self.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, self.currentSessionId);
|
||||
}
|
||||
|
||||
// 5. 檢查並啟動自動提交
|
||||
// 5. 重新啟動會話超時計時器(如果已啟用)
|
||||
if (self.settingsManager && self.settingsManager.get('sessionTimeoutEnabled')) {
|
||||
console.log('🔄 新會話創建,重新啟動會話超時計時器');
|
||||
const timeoutSettings = {
|
||||
enabled: self.settingsManager.get('sessionTimeoutEnabled'),
|
||||
seconds: self.settingsManager.get('sessionTimeoutSeconds')
|
||||
};
|
||||
self.webSocketManager.updateSessionTimeoutSettings(timeoutSettings);
|
||||
}
|
||||
|
||||
// 6. 檢查並啟動自動提交
|
||||
self.checkAndStartAutoSubmit();
|
||||
|
||||
console.log('✅ 局部更新完成,頁面已準備好接收新的回饋');
|
||||
@ -1158,6 +1177,12 @@
|
||||
this.autoSubmitManager.stop();
|
||||
}
|
||||
|
||||
// 停止會話超時計時器
|
||||
if (this.webSocketManager) {
|
||||
console.log('⏸️ 提交反饋,停止會話超時計時器');
|
||||
this.webSocketManager.stopSessionTimeout();
|
||||
}
|
||||
|
||||
// 3. 發送回饋到 AI 助手
|
||||
const success = this.webSocketManager.send({
|
||||
type: 'submit_feedback',
|
||||
@ -1898,6 +1923,30 @@
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 設置用戶活動監聽器(用於重置會話超時)
|
||||
*/
|
||||
FeedbackApp.prototype.setupUserActivityListeners = function() {
|
||||
const self = this;
|
||||
|
||||
// 定義需要監聽的活動事件
|
||||
const activityEvents = ['click', 'keypress', 'mousemove', 'touchstart', 'scroll'];
|
||||
|
||||
// 防抖處理,避免過於頻繁地重置計時器
|
||||
const resetTimeout = window.MCPFeedback.Utils.DOM.debounce(function() {
|
||||
if (self.webSocketManager) {
|
||||
self.webSocketManager.resetSessionTimeout();
|
||||
}
|
||||
}, 5000, false); // 5秒內的連續活動只重置一次
|
||||
|
||||
// 為每個事件添加監聽器
|
||||
activityEvents.forEach(function(eventType) {
|
||||
document.addEventListener(eventType, resetTimeout, { passive: true });
|
||||
});
|
||||
|
||||
console.log('✅ 用戶活動監聽器已設置');
|
||||
};
|
||||
|
||||
/**
|
||||
* 清理資源
|
||||
*/
|
||||
|
@ -50,7 +50,10 @@
|
||||
userMessageRecordingEnabled: true,
|
||||
userMessagePrivacyLevel: 'full', // 'full', 'basic', 'disabled'
|
||||
// UI 元素尺寸設定
|
||||
combinedFeedbackTextHeight: 150 // combinedFeedbackText textarea 的高度(px)
|
||||
combinedFeedbackTextHeight: 150, // combinedFeedbackText textarea 的高度(px)
|
||||
// 會話超時設定
|
||||
sessionTimeoutEnabled: false, // 預設關閉
|
||||
sessionTimeoutSeconds: 3600 // 預設 1 小時(秒)
|
||||
};
|
||||
|
||||
// 當前設定
|
||||
@ -417,6 +420,9 @@
|
||||
|
||||
// 應用用戶訊息記錄設定
|
||||
this.applyUserMessageSettings();
|
||||
|
||||
// 應用會話超時設定
|
||||
this.applySessionTimeoutSettings();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -599,6 +605,28 @@
|
||||
this.updatePrivacyLevelDescription(this.currentSettings.userMessagePrivacyLevel);
|
||||
};
|
||||
|
||||
/**
|
||||
* 應用會話超時設定
|
||||
*/
|
||||
SettingsManager.prototype.applySessionTimeoutSettings = function() {
|
||||
// 更新會話超時啟用開關
|
||||
const sessionTimeoutEnabled = Utils.safeQuerySelector('#sessionTimeoutEnabled');
|
||||
if (sessionTimeoutEnabled) {
|
||||
sessionTimeoutEnabled.checked = this.currentSettings.sessionTimeoutEnabled;
|
||||
}
|
||||
|
||||
// 更新會話超時時間輸入框
|
||||
const sessionTimeoutSeconds = Utils.safeQuerySelector('#sessionTimeoutSeconds');
|
||||
if (sessionTimeoutSeconds) {
|
||||
sessionTimeoutSeconds.value = this.currentSettings.sessionTimeoutSeconds;
|
||||
}
|
||||
|
||||
console.log('會話超時設定已應用到 UI:', {
|
||||
enabled: this.currentSettings.sessionTimeoutEnabled,
|
||||
seconds: this.currentSettings.sessionTimeoutSeconds
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新隱私等級描述文字
|
||||
*/
|
||||
@ -896,6 +924,59 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 會話超時啟用開關
|
||||
const sessionTimeoutEnabled = Utils.safeQuerySelector('#sessionTimeoutEnabled');
|
||||
if (sessionTimeoutEnabled) {
|
||||
sessionTimeoutEnabled.addEventListener('change', function() {
|
||||
const newValue = sessionTimeoutEnabled.checked;
|
||||
self.set('sessionTimeoutEnabled', newValue);
|
||||
console.log('會話超時狀態已更新:', newValue);
|
||||
|
||||
// 觸發 WebSocket 通知後端更新超時設定
|
||||
if (window.MCPFeedback && window.MCPFeedback.app && window.MCPFeedback.app.webSocketManager) {
|
||||
window.MCPFeedback.app.webSocketManager.send({
|
||||
type: 'update_timeout_settings',
|
||||
settings: {
|
||||
enabled: newValue,
|
||||
seconds: self.get('sessionTimeoutSeconds')
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 會話超時時間設定
|
||||
const sessionTimeoutSeconds = Utils.safeQuerySelector('#sessionTimeoutSeconds');
|
||||
if (sessionTimeoutSeconds) {
|
||||
sessionTimeoutSeconds.addEventListener('change', function(e) {
|
||||
const seconds = parseInt(e.target.value);
|
||||
|
||||
// 驗證輸入值範圍
|
||||
if (isNaN(seconds) || seconds < 300) {
|
||||
e.target.value = 300;
|
||||
self.set('sessionTimeoutSeconds', 300);
|
||||
} else if (seconds > 86400) {
|
||||
e.target.value = 86400;
|
||||
self.set('sessionTimeoutSeconds', 86400);
|
||||
} else {
|
||||
self.set('sessionTimeoutSeconds', seconds);
|
||||
}
|
||||
|
||||
console.log('會話超時時間已更新:', self.get('sessionTimeoutSeconds'), '秒');
|
||||
|
||||
// 觸發 WebSocket 通知後端更新超時設定
|
||||
if (window.MCPFeedback && window.MCPFeedback.app && window.MCPFeedback.app.webSocketManager) {
|
||||
window.MCPFeedback.app.webSocketManager.send({
|
||||
type: 'update_timeout_settings',
|
||||
settings: {
|
||||
enabled: self.get('sessionTimeoutEnabled'),
|
||||
seconds: self.get('sessionTimeoutSeconds')
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 重置設定
|
||||
const resetBtn = Utils.safeQuerySelector('#resetSettingsBtn');
|
||||
if (resetBtn) {
|
||||
|
@ -47,6 +47,15 @@
|
||||
// 網路狀態檢測
|
||||
this.networkOnline = navigator.onLine;
|
||||
this.setupNetworkStatusDetection();
|
||||
|
||||
// 會話超時計時器
|
||||
this.sessionTimeoutTimer = null;
|
||||
this.sessionTimeoutInterval = null; // 用於更新倒數顯示
|
||||
this.sessionTimeoutRemaining = 0; // 剩餘秒數
|
||||
this.sessionTimeoutSettings = {
|
||||
enabled: false,
|
||||
seconds: 3600
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -285,6 +294,12 @@
|
||||
timestamp: data.timestamp
|
||||
});
|
||||
break;
|
||||
case 'update_timeout_settings':
|
||||
// 處理超時設定更新
|
||||
if (data.settings) {
|
||||
this.updateSessionTimeoutSettings(data.settings);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// 其他訊息類型由外部處理
|
||||
break;
|
||||
@ -461,11 +476,139 @@
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新會話超時設定
|
||||
*/
|
||||
WebSocketManager.prototype.updateSessionTimeoutSettings = function(settings) {
|
||||
this.sessionTimeoutSettings = settings;
|
||||
console.log('會話超時設定已更新:', settings);
|
||||
|
||||
// 重新啟動計時器
|
||||
if (settings.enabled) {
|
||||
this.startSessionTimeout();
|
||||
} else {
|
||||
this.stopSessionTimeout();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 啟動會話超時計時器
|
||||
*/
|
||||
WebSocketManager.prototype.startSessionTimeout = function() {
|
||||
// 先停止現有計時器
|
||||
this.stopSessionTimeout();
|
||||
|
||||
if (!this.sessionTimeoutSettings.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeoutSeconds = this.sessionTimeoutSettings.seconds;
|
||||
this.sessionTimeoutRemaining = timeoutSeconds;
|
||||
|
||||
console.log('啟動會話超時計時器:', timeoutSeconds, '秒');
|
||||
|
||||
// 顯示倒數計時器
|
||||
const displayElement = document.getElementById('sessionTimeoutDisplay');
|
||||
if (displayElement) {
|
||||
displayElement.style.display = '';
|
||||
}
|
||||
|
||||
const self = this;
|
||||
|
||||
// 更新倒數顯示
|
||||
function updateDisplay() {
|
||||
const minutes = Math.floor(self.sessionTimeoutRemaining / 60);
|
||||
const seconds = self.sessionTimeoutRemaining % 60;
|
||||
const displayText = minutes.toString().padStart(2, '0') + ':' +
|
||||
seconds.toString().padStart(2, '0');
|
||||
|
||||
const timerElement = document.getElementById('sessionTimeoutTimer');
|
||||
if (timerElement) {
|
||||
timerElement.textContent = displayText;
|
||||
}
|
||||
|
||||
// 當剩餘時間少於60秒時,改變顯示樣式
|
||||
if (self.sessionTimeoutRemaining < 60 && displayElement) {
|
||||
displayElement.classList.add('countdown-warning');
|
||||
}
|
||||
}
|
||||
|
||||
// 立即更新一次顯示
|
||||
updateDisplay();
|
||||
|
||||
// 每秒更新倒數
|
||||
this.sessionTimeoutInterval = setInterval(function() {
|
||||
self.sessionTimeoutRemaining--;
|
||||
updateDisplay();
|
||||
|
||||
if (self.sessionTimeoutRemaining <= 0) {
|
||||
clearInterval(self.sessionTimeoutInterval);
|
||||
self.sessionTimeoutInterval = null;
|
||||
|
||||
console.log('會話超時,準備關閉程序');
|
||||
|
||||
// 發送超時通知給後端
|
||||
if (self.isConnected) {
|
||||
self.send({
|
||||
type: 'user_timeout',
|
||||
timestamp: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
// 顯示超時訊息
|
||||
const timeoutMessage = window.i18nManager ?
|
||||
window.i18nManager.t('sessionTimeout.triggered', '會話已超時,程序即將關閉') :
|
||||
'會話已超時,程序即將關閉';
|
||||
Utils.showMessage(timeoutMessage, Utils.CONSTANTS.MESSAGE_WARNING);
|
||||
|
||||
// 延遲關閉,讓用戶看到訊息
|
||||
setTimeout(function() {
|
||||
window.close();
|
||||
}, 3000);
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
/**
|
||||
* 停止會話超時計時器
|
||||
*/
|
||||
WebSocketManager.prototype.stopSessionTimeout = function() {
|
||||
if (this.sessionTimeoutTimer) {
|
||||
clearTimeout(this.sessionTimeoutTimer);
|
||||
this.sessionTimeoutTimer = null;
|
||||
}
|
||||
|
||||
if (this.sessionTimeoutInterval) {
|
||||
clearInterval(this.sessionTimeoutInterval);
|
||||
this.sessionTimeoutInterval = null;
|
||||
}
|
||||
|
||||
// 隱藏倒數顯示
|
||||
const displayElement = document.getElementById('sessionTimeoutDisplay');
|
||||
if (displayElement) {
|
||||
displayElement.style.display = 'none';
|
||||
displayElement.classList.remove('countdown-warning');
|
||||
}
|
||||
|
||||
console.log('會話超時計時器已停止');
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置會話超時計時器(用戶有活動時調用)
|
||||
*/
|
||||
WebSocketManager.prototype.resetSessionTimeout = function() {
|
||||
if (this.sessionTimeoutSettings.enabled) {
|
||||
console.log('重置會話超時計時器');
|
||||
this.startSessionTimeout();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 關閉連接
|
||||
*/
|
||||
WebSocketManager.prototype.close = function() {
|
||||
this.stopHeartbeat();
|
||||
this.stopSessionTimeout();
|
||||
if (this.websocket) {
|
||||
this.websocket.close();
|
||||
this.websocket = null;
|
||||
|
@ -429,9 +429,10 @@
|
||||
</div>
|
||||
|
||||
<!-- 倒數計時器(條件顯示) -->
|
||||
<div id="countdownDisplay" class="countdown-display-compact" style="display: none;">
|
||||
<div id="countdownDisplay" class="countdown-display-compact auto-submit-display" style="display: none;">
|
||||
<span class="info-separator">·</span>
|
||||
<span>⏱️</span>
|
||||
<span class="countdown-label" data-i18n="autoSubmit.countdownLabel">提交倒數:</span>
|
||||
<span id="countdownTimer" class="countdown-timer">--:--</span>
|
||||
<button id="countdownPauseBtn" class="countdown-control-btn"
|
||||
data-i18n-title="autoSubmit.pauseCountdown"
|
||||
@ -442,6 +443,14 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 會話超時倒數(條件顯示) -->
|
||||
<div id="sessionTimeoutDisplay" class="countdown-display-compact session-timeout-display" style="display: none;">
|
||||
<span class="info-separator">·</span>
|
||||
<span>⏰</span>
|
||||
<span class="timeout-label" data-i18n="sessionTimeout.label">會話超時:</span>
|
||||
<span id="sessionTimeoutTimer" class="countdown-timer">--:--</span>
|
||||
</div>
|
||||
|
||||
<!-- 分隔符 -->
|
||||
<span class="info-separator">·</span>
|
||||
|
||||
@ -870,6 +879,43 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 會話超時設定卡片 -->
|
||||
<div class="settings-card">
|
||||
<div class="settings-card-header">
|
||||
<h3 class="settings-card-title" data-i18n="settingsUI.sessionTimeoutTitle">⏱️ 會話超時設定</h3>
|
||||
</div>
|
||||
<div class="settings-card-body">
|
||||
<div class="setting-item">
|
||||
<div class="setting-info">
|
||||
<div class="setting-label" data-i18n="settingsUI.sessionTimeoutEnable">啟用會話超時</div>
|
||||
<div class="setting-description" data-i18n="settingsUI.sessionTimeoutEnableDesc">
|
||||
啟用後,會話將在指定時間後自動關閉
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-control">
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="sessionTimeoutEnabled" class="toggle-input">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-item">
|
||||
<div class="setting-info">
|
||||
<div class="setting-label" data-i18n="settingsUI.sessionTimeoutDuration">超時時間(秒)</div>
|
||||
<div class="setting-description" data-i18n="settingsUI.sessionTimeoutDurationDesc">
|
||||
設定會話超時時間,範圍:300-86400 秒(5分鐘-24小時)
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-control">
|
||||
<input type="number" id="sessionTimeoutSeconds" min="300" max="86400" value="3600"
|
||||
class="form-input" style="width: 120px;">
|
||||
<span class="input-suffix" data-i18n="settingsUI.sessionTimeoutSeconds">秒</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 會話歷史管理卡片 -->
|
||||
<div class="settings-card">
|
||||
<div class="settings-card-header">
|
||||
|
Loading…
x
Reference in New Issue
Block a user