From 568f7d986cbbe6e1ad284f04d49adb21d9d92e7f Mon Sep 17 00:00:00 2001 From: Minidoracat Date: Sat, 7 Jun 2025 04:22:24 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E6=9B=B4=E6=96=B0=E7=BF=BB?= =?UTF-8?q?=E8=AD=AF=E6=96=87=E4=BB=B6=EF=BC=8C=E5=B0=87=E3=80=8C=E5=90=88?= =?UTF-8?q?=E4=BD=B5=E6=A8=A1=E5=BC=8F=E3=80=8D=E6=9B=B4=E5=90=8D=E7=82=BA?= =?UTF-8?q?=E3=80=8C=E5=B7=A5=E4=BD=9C=E5=8D=80=E3=80=8D=EF=BC=8C=E4=B8=A6?= =?UTF-8?q?=E8=AA=BF=E6=95=B4=E7=9B=B8=E9=97=9C=E6=8F=8F=E8=BF=B0=EF=BC=9B?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=87=AA=E5=8B=95=E5=88=B7=E6=96=B0=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E7=9A=84=E7=95=8C=E9=9D=A2=E5=85=83=E7=B4=A0=E5=8F=8A?= =?UTF-8?q?=E6=A8=A3=E5=BC=8F=EF=BC=8C=E6=8F=90=E5=8D=87=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=80=85=E9=AB=94=E9=A9=97=E8=88=87=E7=95=8C=E9=9D=A2=E4=B8=80?= =?UTF-8?q?=E8=87=B4=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/locales/en/translation.json | 23 +- .../web/locales/zh-CN/translation.json | 23 +- .../web/locales/zh-TW/translation.json | 23 +- .../web/routes/main_routes.py | 10 +- .../web/static/css/styles.css | 124 ++++++++ .../web/static/js/app.js | 293 ++++++++++++++---- .../web/static/js/i18n.js | 4 + .../web/templates/feedback.html | 59 ++-- 8 files changed, 448 insertions(+), 111 deletions(-) diff --git a/src/mcp_feedback_enhanced/web/locales/en/translation.json b/src/mcp_feedback_enhanced/web/locales/en/translation.json index f82e688..a77db81 100644 --- a/src/mcp_feedback_enhanced/web/locales/en/translation.json +++ b/src/mcp_feedback_enhanced/web/locales/en/translation.json @@ -10,7 +10,7 @@ "commands": "⚡ Commands", "command": "⚡ Commands", "settings": "⚙️ Settings", - "combined": "📝 Combined Mode", + "combined": "📝 Workspace", "about": "ℹ️ About" }, "feedback": { @@ -73,7 +73,7 @@ "history": "Command History" }, "combined": { - "description": "Combined mode: AI summary and feedback input are on the same page for easy comparison.", + "description": "AI summary and feedback input are on the same page for easy comparison.", "summaryTitle": "📋 AI Work Summary", "feedbackTitle": "💬 Provide Feedback" }, @@ -86,12 +86,10 @@ "interface": "Interface Settings", "layoutMode": "Interface Layout Mode", "layoutModeDesc": "Select how AI summary and feedback input are displayed", - "separateMode": "Separate Mode", - "separateModeDesc": "AI summary and feedback are in separate tabs", - "combinedVertical": "Combined Mode (Vertical Layout)", - "combinedVerticalDesc": "AI summary on top, feedback input below, both on the same page", - "combinedHorizontal": "Combined Mode (Horizontal Layout)", - "combinedHorizontalDesc": "AI summary on left, feedback input on right, expanding summary viewing area", + "combinedVertical": "Vertical Layout", + "combinedVerticalDesc": "AI summary on top, feedback input below, suitable for standard screens", + "combinedHorizontal": "Horizontal Layout", + "combinedHorizontalDesc": "AI summary on left, feedback input on right, suitable for widescreen displays", "autoClose": "Auto Close Page", "autoCloseDesc": "Automatically close page after submitting feedback", "theme": "Theme", @@ -172,6 +170,15 @@ "timeoutDescription": "Due to prolonged inactivity, the session has timed out. The interface will automatically close in 3 seconds.", "closing": "Closing..." }, + "autoRefresh": { + "enable": "Auto Detect", + "seconds": "seconds", + "disabled": "Disabled", + "enabled": "Detecting", + "checking": "Checking", + "detected": "Detected", + "error": "Failed" + }, "dynamic": { "aiSummary": "Test Web UI Functionality\n\n🎯 **Test Items:**\n- Web UI server startup and operation\n- WebSocket real-time communication\n- Feedback submission functionality\n- Image upload and preview\n- Command execution functionality\n- Smart Ctrl+V image pasting\n- Multi-language interface functionality\n\n📋 **Test Steps:**\n1. Test image upload (drag-drop, file selection, clipboard)\n2. Press Ctrl+V in text box to test smart pasting\n3. Try switching languages (Traditional Chinese/Simplified Chinese/English)\n4. Test command execution functionality\n5. Submit feedback and images\n\nPlease test these features and provide feedback!", diff --git a/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json b/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json index ca91af0..e1944df 100644 --- a/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json +++ b/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json @@ -10,7 +10,7 @@ "commands": "⚡ 命令", "command": "⚡ 命令", "settings": "⚙️ 设置", - "combined": "📝 合并模式", + "combined": "📝 工作区", "about": "ℹ️ 关于" }, "feedback": { @@ -73,7 +73,7 @@ "history": "命令历史" }, "combined": { - "description": "合并模式:AI 摘要和反馈输入在同一页面中,方便对照查看。", + "description": "AI 摘要和反馈输入在同一页面中,方便对照查看。", "summaryTitle": "📋 AI 工作摘要", "feedbackTitle": "💬 提供反馈" }, @@ -86,12 +86,10 @@ "interface": "界面设定", "layoutMode": "界面布局模式", "layoutModeDesc": "选择 AI 摘要和反馈输入的显示方式", - "separateMode": "分离模式", - "separateModeDesc": "AI 摘要和反馈分别在不同页签", - "combinedVertical": "合并模式(垂直布局)", - "combinedVerticalDesc": "AI 摘要在上,反馈输入在下,摘要和反馈在同一页面", - "combinedHorizontal": "合并模式(水平布局)", - "combinedHorizontalDesc": "AI 摘要在左,反馈输入在右,增大摘要可视区域", + "combinedVertical": "垂直布局", + "combinedVerticalDesc": "AI 摘要在上,反馈输入在下,适合标准屏幕使用", + "combinedHorizontal": "水平布局", + "combinedHorizontalDesc": "AI 摘要在左,反馈输入在右,适合宽屏幕使用", "autoClose": "自动关闭页面", "autoCloseDesc": "提交回馈后自动关闭页面", "theme": "主题", @@ -172,6 +170,15 @@ "timeoutDescription": "由于长时间无响应,会话已超时。界面将在 3 秒后自动关闭。", "closing": "正在关闭..." }, + "autoRefresh": { + "enable": "自动检测", + "seconds": "秒", + "disabled": "停用", + "enabled": "检测中", + "checking": "检查中", + "detected": "已检测", + "error": "失败" + }, "dynamic": { "aiSummary": "测试 Web UI 功能\n\n🎯 **功能测试项目:**\n- Web UI 服务器启动和运行\n- WebSocket 实时通讯\n- 反馈提交功能\n- 图片上传和预览\n- 命令执行功能\n- 智能 Ctrl+V 图片粘贴\n- 多语言界面功能\n\n📋 **测试步骤:**\n1. 测试图片上传(拖拽、选择文件、剪贴板)\n2. 在文本框内按 Ctrl+V 测试智能粘贴\n3. 尝试切换语言(繁中/简中/英文)\n4. 测试命令执行功能\n5. 提交反馈和图片\n\n请测试这些功能并提供反馈!", diff --git a/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json b/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json index c43af12..4cdd204 100644 --- a/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json +++ b/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json @@ -10,7 +10,7 @@ "commands": "⚡ 命令", "command": "⚡ 命令", "settings": "⚙️ 設定", - "combined": "📝 合併模式", + "combined": "📝 工作區", "about": "ℹ️ 關於" }, "feedback": { @@ -73,7 +73,7 @@ "history": "命令歷史" }, "combined": { - "description": "合併模式:AI 摘要和回饋輸入在同一頁面中,方便對照查看。", + "description": "AI 摘要和回饋輸入在同一頁面中,方便對照查看。", "summaryTitle": "📋 AI 工作摘要", "feedbackTitle": "💬 提供回饋" }, @@ -86,12 +86,10 @@ "interface": "介面設定", "layoutMode": "界面佈局模式", "layoutModeDesc": "選擇 AI 摘要和回饋輸入的顯示方式", - "separateMode": "分離模式", - "separateModeDesc": "AI 摘要和回饋分別在不同頁籤", - "combinedVertical": "合併模式(垂直布局)", - "combinedVerticalDesc": "AI 摘要在上,回饋輸入在下,摘要和回饋在同一頁面", - "combinedHorizontal": "合併模式(水平布局)", - "combinedHorizontalDesc": "AI 摘要在左,回饋輸入在右,增大摘要可視區域", + "combinedVertical": "垂直佈局", + "combinedVerticalDesc": "AI 摘要在上,回饋輸入在下,適合標準螢幕使用", + "combinedHorizontal": "水平佈局", + "combinedHorizontalDesc": "AI 摘要在左,回饋輸入在右,適合寬螢幕使用", "autoClose": "自動關閉頁面", "autoCloseDesc": "提交回饋後自動關閉頁面", "theme": "主題", @@ -172,6 +170,15 @@ "timeoutDescription": "由於長時間無回應,會話已超時。介面將在 3 秒後自動關閉。", "closing": "正在關閉..." }, + "autoRefresh": { + "enable": "自動檢測", + "seconds": "秒", + "disabled": "停用", + "enabled": "檢測中", + "checking": "檢查中", + "detected": "已檢測", + "error": "失敗" + }, "dynamic": { "aiSummary": "測試 Web UI 功能\n\n🎯 **功能測試項目:**\n- Web UI 服務器啟動和運行\n- WebSocket 即時通訊\n- 回饋提交功能\n- 圖片上傳和預覽\n- 命令執行功能\n- 智能 Ctrl+V 圖片貼上\n- 多語言介面功能\n\n📋 **測試步驟:**\n1. 測試圖片上傳(拖拽、選擇檔案、剪貼簿)\n2. 在文字框內按 Ctrl+V 測試智能貼上\n3. 嘗試切換語言(繁中/簡中/英文)\n4. 測試命令執行功能\n5. 提交回饋和圖片\n\n請測試這些功能並提供回饋!", diff --git a/src/mcp_feedback_enhanced/web/routes/main_routes.py b/src/mcp_feedback_enhanced/web/routes/main_routes.py index a8ca0eb..f7f3097 100644 --- a/src/mcp_feedback_enhanced/web/routes/main_routes.py +++ b/src/mcp_feedback_enhanced/web/routes/main_routes.py @@ -33,15 +33,15 @@ def load_user_layout_settings() -> str: if settings_file.exists(): with open(settings_file, 'r', encoding='utf-8') as f: settings = json.load(f) - layout_mode = settings.get('layoutMode', 'separate') + layout_mode = settings.get('layoutMode', 'combined-vertical') debug_log(f"從設定檔案載入佈局模式: {layout_mode}") return layout_mode else: - debug_log("設定檔案不存在,使用預設佈局模式: separate") - return 'separate' + debug_log("設定檔案不存在,使用預設佈局模式: combined-vertical") + return 'combined-vertical' except Exception as e: - debug_log(f"載入佈局設定失敗: {e},使用預設佈局模式: separate") - return 'separate' + debug_log(f"載入佈局設定失敗: {e},使用預設佈局模式: combined-vertical") + return 'combined-vertical' def setup_routes(manager: 'WebUIManager'): diff --git a/src/mcp_feedback_enhanced/web/static/css/styles.css b/src/mcp_feedback_enhanced/web/static/css/styles.css index b268490..518fe87 100644 --- a/src/mcp_feedback_enhanced/web/static/css/styles.css +++ b/src/mcp_feedback_enhanced/web/static/css/styles.css @@ -1265,4 +1265,128 @@ body { .compatibility-hint-btn:hover { background: #f57c00; +} + +/* 自動刷新控制項樣式 */ +.section-header-with-controls { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; +} + +/* AI 工作摘要標題樣式 */ +h3.combined-section-title { + font-size: 16px; + font-weight: 600; + color: var(--text-primary); + margin: 0; +} + +.auto-refresh-controls { + display: flex; + align-items: center; + gap: 8px; + font-size: 14px; + background: var(--bg-tertiary); + border: 1px solid var(--border-color); + border-radius: 6px; + padding: 6px 10px; + transition: all 0.3s ease; +} + +.auto-refresh-controls:hover { + border-color: var(--accent-color); + background: var(--surface-color); +} + +.auto-refresh-toggle { + display: flex; + align-items: center; + gap: 4px; + cursor: pointer; + user-select: none; +} + +.auto-refresh-toggle input[type="checkbox"] { + appearance: none; + width: 14px; + height: 14px; + border: 1px solid var(--border-color); + border-radius: 2px; + background: var(--bg-primary); + cursor: pointer; + transition: all 0.3s ease; + position: relative; +} + +.auto-refresh-toggle input[type="checkbox"]:checked { + background: var(--accent-color); + border-color: var(--accent-color); +} + +.auto-refresh-toggle input[type="checkbox"]:checked::after { + content: '✓'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: white; + font-size: 9px; + font-weight: bold; +} + +.toggle-label { + color: var(--text-primary); + font-size: 14px; + font-weight: 500; + white-space: nowrap; +} + +.auto-refresh-interval { + display: flex; + align-items: center; + gap: 2px; +} + +.auto-refresh-interval input[type="number"] { + width: 50px; + background: var(--bg-primary); + color: var(--text-primary); + border: 1px solid var(--border-color); + border-radius: 3px; + padding: 4px 6px; + font-size: 13px; + text-align: center; +} + +.auto-refresh-interval input[type="number"]:focus { + outline: none; + border-color: var(--accent-color); +} + +.interval-unit { + color: var(--text-secondary); + font-size: 14px; + white-space: nowrap; +} + +.auto-refresh-status { + display: flex; + align-items: center; + gap: 3px; + padding: 1px 4px; + background: var(--bg-primary); + border-radius: 3px; + border: 1px solid var(--border-color); +} + +.auto-refresh-status .status-indicator { + font-size: 13px; +} + +.auto-refresh-status .status-text { + color: var(--text-secondary); + font-size: 14px; + white-space: nowrap; } \ No newline at end of file diff --git a/src/mcp_feedback_enhanced/web/static/js/app.js b/src/mcp_feedback_enhanced/web/static/js/app.js index 0b512a6..fa46a44 100644 --- a/src/mcp_feedback_enhanced/web/static/js/app.js +++ b/src/mcp_feedback_enhanced/web/static/js/app.js @@ -185,11 +185,17 @@ class FeedbackApp { // 設定 this.autoClose = false; - this.layoutMode = 'separate'; + this.layoutMode = 'combined-vertical'; // 語言設定 this.currentLanguage = 'zh-TW'; + // 自動刷新設定 + this.autoRefreshEnabled = false; + this.autoRefreshInterval = 5; // 默認5秒 + this.autoRefreshTimer = null; + this.lastKnownSessionId = null; + this.init(); } @@ -223,6 +229,9 @@ class FeedbackApp { // 確保狀態指示器使用正確的翻譯(在國際化系統載入後) this.updateStatusIndicators(); + // 初始化自動刷新功能 + this.initAutoRefresh(); + // 設置頁面關閉時的清理 window.addEventListener('beforeunload', () => { if (this.tabManager) { @@ -231,6 +240,9 @@ class FeedbackApp { if (this.heartbeatInterval) { clearInterval(this.heartbeatInterval); } + if (this.autoRefreshTimer) { + clearInterval(this.autoRefreshTimer); + } }); console.log('MCP Feedback Enhanced 應用程式初始化完成'); @@ -259,6 +271,12 @@ class FeedbackApp { this.commandOutput = document.getElementById('commandOutput'); this.runCommandBtn = document.getElementById('runCommandBtn'); + // 自動刷新相關元素 + this.autoRefreshCheckbox = document.getElementById('autoRefreshEnabled'); + this.autoRefreshIntervalInput = document.getElementById('autoRefreshInterval'); + this.refreshStatusIndicator = document.getElementById('refreshStatusIndicator'); + this.refreshStatusText = document.getElementById('refreshStatusText'); + // 動態初始化圖片相關元素 this.initImageElements(); } @@ -1016,7 +1034,7 @@ class FeedbackApp { if (event.code !== 1000 && this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; const delay = Math.min(3000 * this.reconnectAttempts, 15000); // 最大延遲15秒 - console.log(`${delay/1000}秒後嘗試重連... (第${this.reconnectAttempts}次)`); + console.log(`${delay / 1000}秒後嘗試重連... (第${this.reconnectAttempts}次)`); setTimeout(() => { console.log(`🔄 開始重連 WebSocket... (第${this.reconnectAttempts}次)`); this.setupWebSocket(); @@ -1410,9 +1428,9 @@ class FeedbackApp { word-wrap: break-word; `; messageDiv.textContent = message; - + document.body.appendChild(messageDiv); - + // 3秒後自動移除 setTimeout(() => { if (messageDiv.parentNode) { @@ -1450,12 +1468,12 @@ class FeedbackApp { async loadFeedbackInterface(sessionInfo) { if (!this.mainContainer) return; - + this.sessionInfo = sessionInfo; - + // 載入完整的回饋界面 this.mainContainer.innerHTML = await this.generateFeedbackHTML(sessionInfo); - + // 重新設置事件監聽器 this.setupFeedbackEventListeners(); } @@ -1801,6 +1819,8 @@ class FeedbackApp { this.currentLanguage = settings.language || 'zh-TW'; this.imageSizeLimit = settings.imageSizeLimit || 0; this.enableBase64Detail = settings.enableBase64Detail || false; + this.autoRefreshEnabled = settings.autoRefreshEnabled || false; + this.autoRefreshInterval = settings.autoRefreshInterval || 5; // 處理 activeTab 設定 if (settings.activeTab) { @@ -1846,6 +1866,8 @@ class FeedbackApp { language: this.currentLanguage, imageSizeLimit: this.imageSizeLimit, enableBase64Detail: this.enableBase64Detail, + autoRefreshEnabled: this.autoRefreshEnabled, + autoRefreshInterval: this.autoRefreshInterval, activeTab: this.currentTab }; @@ -1904,6 +1926,15 @@ class FeedbackApp { if (this.enableBase64DetailCheckbox) { this.enableBase64DetailCheckbox.checked = this.enableBase64Detail; } + + // 應用自動刷新設定 + if (this.autoRefreshCheckbox) { + this.autoRefreshCheckbox.checked = this.autoRefreshEnabled; + } + + if (this.autoRefreshIntervalInput) { + this.autoRefreshIntervalInput.value = this.autoRefreshInterval; + } } applyLayoutMode() { @@ -1927,18 +1958,11 @@ class FeedbackApp { // 同步合併佈局和分頁中的內容 this.syncCombinedLayoutContent(); - // 如果是合併模式,確保內容同步 - if (this.layoutMode.startsWith('combined')) { - this.setupCombinedModeSync(); - // 如果當前頁籤不是合併模式,則切換到合併模式頁籤 - if (this.currentTab !== 'combined') { - this.currentTab = 'combined'; - } - } else { - // 分離模式時,如果當前頁籤是合併模式,則切換到回饋頁籤 - if (this.currentTab === 'combined') { - this.currentTab = 'feedback'; - } + // 確保合併模式內容同步 + this.setupCombinedModeSync(); + // 如果當前頁籤不是合併模式,則切換到合併模式頁籤 + if (this.currentTab !== 'combined') { + this.currentTab = 'combined'; } } @@ -1947,17 +1971,10 @@ class FeedbackApp { const feedbackTab = document.querySelector('.tab-button[data-tab="feedback"]'); const summaryTab = document.querySelector('.tab-button[data-tab="summary"]'); - if (this.layoutMode.startsWith('combined')) { - // 合併模式:顯示合併模式頁籤,隱藏回饋和AI摘要頁籤 - if (combinedTab) combinedTab.style.display = 'inline-block'; - if (feedbackTab) feedbackTab.style.display = 'none'; - if (summaryTab) summaryTab.style.display = 'none'; - } else { - // 分離模式:隱藏合併模式頁籤,顯示回饋和AI摘要頁籤 - if (combinedTab) combinedTab.style.display = 'none'; - if (feedbackTab) feedbackTab.style.display = 'inline-block'; - if (summaryTab) summaryTab.style.display = 'inline-block'; - } + // 只使用合併模式:顯示合併模式頁籤,隱藏回饋和AI摘要頁籤 + if (combinedTab) combinedTab.style.display = 'inline-block'; + if (feedbackTab) feedbackTab.style.display = 'none'; + if (summaryTab) summaryTab.style.display = 'none'; } syncCombinedLayoutContent() { @@ -2012,27 +2029,6 @@ class FeedbackApp { } setupCombinedModeSync() { - // 設置文字輸入的雙向同步 - const feedbackText = document.getElementById('feedbackText'); - const combinedFeedbackText = document.getElementById('combinedFeedbackText'); - - if (feedbackText && combinedFeedbackText) { - // 移除舊的事件監聽器(如果存在) - feedbackText.removeEventListener('input', this.syncToCombinetText); - combinedFeedbackText.removeEventListener('input', this.syncToSeparateText); - - // 添加新的事件監聽器 - this.syncToCombinetText = (e) => { - combinedFeedbackText.value = e.target.value; - }; - this.syncToSeparateText = (e) => { - feedbackText.value = e.target.value; - }; - - feedbackText.addEventListener('input', this.syncToCombinetText); - combinedFeedbackText.addEventListener('input', this.syncToSeparateText); - } - // 設置圖片設定的同步 this.setupImageSettingsSync(); @@ -2111,11 +2107,13 @@ class FeedbackApp { resetSettings() { localStorage.removeItem('mcp-feedback-settings'); - this.layoutMode = 'separate'; + this.layoutMode = 'combined-vertical'; this.autoClose = false; this.currentLanguage = 'zh-TW'; this.imageSizeLimit = 0; this.enableBase64Detail = false; + this.autoRefreshEnabled = false; + this.autoRefreshInterval = 5; this.applySettings(); this.saveSettings(); } @@ -2169,6 +2167,197 @@ class FeedbackApp { // 不需要手動複製,updateStatusIndicator() 會處理所有狀態指示器 } + /** + * 初始化自動刷新功能 + */ + initAutoRefresh() { + console.log('🔄 初始化自動刷新功能...'); + + // 檢查必要元素是否存在 + if (!this.autoRefreshCheckbox || !this.autoRefreshIntervalInput) { + console.warn('⚠️ 自動刷新元素不存在,跳過初始化'); + return; + } + + // 設置開關事件監聽器 + this.autoRefreshCheckbox.addEventListener('change', (e) => { + this.autoRefreshEnabled = e.target.checked; + this.handleAutoRefreshToggle(); + this.saveSettings(); + }); + + // 設置間隔輸入事件監聽器 + this.autoRefreshIntervalInput.addEventListener('change', (e) => { + const newInterval = parseInt(e.target.value); + if (newInterval >= 5 && newInterval <= 300) { + this.autoRefreshInterval = newInterval; + this.saveSettings(); + + // 如果自動刷新已啟用,重新啟動定時器 + if (this.autoRefreshEnabled) { + this.stopAutoRefresh(); + this.startAutoRefresh(); + } + } + }); + + // 從設定中恢復狀態 + this.autoRefreshCheckbox.checked = this.autoRefreshEnabled; + this.autoRefreshIntervalInput.value = this.autoRefreshInterval; + + // 延遲更新狀態指示器,確保 i18n 已完全載入 + setTimeout(() => { + this.updateAutoRefreshStatus(); + }, 100); + + console.log('✅ 自動刷新功能初始化完成'); + } + + /** + * 處理自動刷新開關切換 + */ + handleAutoRefreshToggle() { + if (this.autoRefreshEnabled) { + this.startAutoRefresh(); + } else { + this.stopAutoRefresh(); + } + this.updateAutoRefreshStatus(); + } + + /** + * 啟動自動刷新 + */ + startAutoRefresh() { + if (this.autoRefreshTimer) { + clearInterval(this.autoRefreshTimer); + } + + // 記錄當前會話 ID + this.lastKnownSessionId = this.currentSessionId; + + this.autoRefreshTimer = setInterval(() => { + this.checkForSessionUpdate(); + }, this.autoRefreshInterval * 1000); + + console.log(`🔄 自動刷新已啟動,間隔: ${this.autoRefreshInterval}秒`); + } + + /** + * 停止自動刷新 + */ + stopAutoRefresh() { + if (this.autoRefreshTimer) { + clearInterval(this.autoRefreshTimer); + this.autoRefreshTimer = null; + } + console.log('⏸️ 自動刷新已停止'); + } + + /** + * 檢查會話更新 + */ + async checkForSessionUpdate() { + try { + this.updateAutoRefreshStatus('checking'); + + const response = await fetch('/api/current-session'); + if (!response.ok) { + throw new Error(`API 請求失敗: ${response.status}`); + } + + const sessionData = await response.json(); + + // 檢查會話 ID 是否變化 + if (sessionData.session_id && sessionData.session_id !== this.lastKnownSessionId) { + console.log(`🔄 檢測到新會話: ${this.lastKnownSessionId} -> ${sessionData.session_id}`); + + // 更新記錄的會話 ID + this.lastKnownSessionId = sessionData.session_id; + this.currentSessionId = sessionData.session_id; + + // 觸發局部刷新 + await this.updatePageContentPartially(); + + this.updateAutoRefreshStatus('detected'); + + // 短暫顯示檢測成功狀態,然後恢復為檢測中 + setTimeout(() => { + if (this.autoRefreshEnabled) { + this.updateAutoRefreshStatus('enabled'); + } + }, 2000); + } else { + this.updateAutoRefreshStatus('enabled'); + } + + } catch (error) { + console.error('❌ 自動刷新檢測失敗:', error); + this.updateAutoRefreshStatus('error'); + + // 短暫顯示錯誤狀態,然後恢復 + setTimeout(() => { + if (this.autoRefreshEnabled) { + this.updateAutoRefreshStatus('enabled'); + } + }, 3000); + } + } + + /** + * 更新自動刷新狀態指示器 + */ + updateAutoRefreshStatus(status = null) { + console.log(`🔧 updateAutoRefreshStatus 被調用,status: ${status}`); + console.log(`🔧 refreshStatusIndicator: ${this.refreshStatusIndicator ? 'found' : 'null'}`); + console.log(`🔧 refreshStatusText: ${this.refreshStatusText ? 'found' : 'null'}`); + + if (!this.refreshStatusIndicator || !this.refreshStatusText) { + console.log(`⚠️ 自動檢測狀態元素未找到,跳過更新`); + return; + } + + let indicator = '⏸️'; + let textKey = 'autoRefresh.disabled'; + + if (status === null) { + status = this.autoRefreshEnabled ? 'enabled' : 'disabled'; + } + + switch (status) { + case 'enabled': + indicator = '🔄'; + textKey = 'autoRefresh.enabled'; + break; + case 'checking': + indicator = '🔍'; + textKey = 'autoRefresh.checking'; + break; + case 'detected': + indicator = '✅'; + textKey = 'autoRefresh.detected'; + break; + case 'error': + indicator = '❌'; + textKey = 'autoRefresh.error'; + break; + case 'disabled': + default: + indicator = '⏸️'; + textKey = 'autoRefresh.disabled'; + break; + } + + this.refreshStatusIndicator.textContent = indicator; + + // 使用多語系翻譯 + + const translatedText = window.i18nManager.t(textKey); + console.log(`🔄 自動檢測狀態翻譯: ${textKey} -> ${translatedText} (語言: ${window.i18nManager.currentLanguage})`); + this.refreshStatusText.textContent = translatedText; + + } + } diff --git a/src/mcp_feedback_enhanced/web/static/js/i18n.js b/src/mcp_feedback_enhanced/web/static/js/i18n.js index 9bd4d42..93bcb38 100644 --- a/src/mcp_feedback_enhanced/web/static/js/i18n.js +++ b/src/mcp_feedback_enhanced/web/static/js/i18n.js @@ -178,6 +178,10 @@ class I18nManager { if (window.feedbackApp) { window.feedbackApp.updateUIState(); window.feedbackApp.updateStatusIndicator(); + // 更新自動檢測狀態文字 + if (window.feedbackApp.updateAutoRefreshStatus) { + window.feedbackApp.updateAutoRefreshStatus(); + } } } diff --git a/src/mcp_feedback_enhanced/web/templates/feedback.html b/src/mcp_feedback_enhanced/web/templates/feedback.html index 2318419..4ae16be 100644 --- a/src/mcp_feedback_enhanced/web/templates/feedback.html +++ b/src/mcp_feedback_enhanced/web/templates/feedback.html @@ -23,18 +23,8 @@ /* 頁面特定的佈局模式樣式 */ - /* 佈局模式樣式 */ - /* 預設分離模式 - 顯示回饋和AI摘要頁籤,隱藏合併模式頁籤 */ - body.layout-separate .tab-button[data-tab="combined"] { - display: none; - } - - body.layout-separate .tab-button[data-tab="feedback"], - body.layout-separate .tab-button[data-tab="summary"] { - display: inline-block; - } - - /* 合併模式 - 顯示合併模式頁籤,隱藏回饋和AI摘要頁籤 */ + /* 佈局模式樣式 - 工作區模式 */ + /* 工作區模式 - 顯示工作區頁籤,隱藏回饋和AI摘要頁籤 */ body.layout-combined-vertical .tab-button[data-tab="combined"], body.layout-combined-horizontal .tab-button[data-tab="combined"] { display: inline-block; @@ -62,7 +52,7 @@ - /* 合併模式分頁的水平佈局樣式 */ + /* 工作區分頁的水平佈局樣式 */ #tab-combined.active.combined-horizontal .combined-content { display: flex !important; flex-direction: row !important; @@ -99,7 +89,7 @@ min-height: 200px; } - /* 合併模式分頁的垂直佈局樣式 */ + /* 工作區分頁的垂直佈局樣式 */ #tab-combined.active.combined-vertical .combined-content { display: flex !important; flex-direction: column !important; @@ -144,7 +134,7 @@ flex: 1; } - /* 合併模式基礎樣式 */ + /* 工作區基礎樣式 */ .combined-section { background: var(--bg-tertiary); border: 1px solid var(--border-color); @@ -395,9 +385,9 @@
- +
- +
- 合併模式:AI 摘要和回饋輸入在同一頁面中,方便對照查看。 + AI 摘要和回饋輸入在同一頁面中,方便對照查看。
-

📋 AI 工作摘要

+
+

📋 AI 工作摘要

+
+ +
+ + +
+
+ ⏸️ + +
+
+
{{ summary }}
@@ -570,23 +576,16 @@
- - -
-
- +