mirror of
https://github.com/Minidoracat/mcp-feedback-enhanced.git
synced 2025-07-27 10:42:25 +08:00
✨ 更新翻譯文件,將「合併模式」更名為「工作區」,並調整相關描述;新增自動刷新功能的界面元素及樣式,提升使用者體驗與界面一致性。
This commit is contained in:
parent
b9d781f147
commit
568f7d986c
@ -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!",
|
||||
|
@ -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请测试这些功能并提供反馈!",
|
||||
|
@ -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請測試這些功能並提供回饋!",
|
||||
|
@ -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'):
|
||||
|
@ -1266,3 +1266,127 @@ 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;
|
||||
}
|
@ -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();
|
||||
}
|
||||
@ -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,19 +1958,12 @@ 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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateTabVisibility() {
|
||||
@ -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摘要頁籤
|
||||
// 只使用合併模式:顯示合併模式頁籤,隱藏回饋和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';
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -178,6 +178,10 @@ class I18nManager {
|
||||
if (window.feedbackApp) {
|
||||
window.feedbackApp.updateUIState();
|
||||
window.feedbackApp.updateStatusIndicator();
|
||||
// 更新自動檢測狀態文字
|
||||
if (window.feedbackApp.updateAutoRefreshStatus) {
|
||||
window.feedbackApp.updateAutoRefreshStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 @@
|
||||
<!-- 分頁導航 -->
|
||||
<div class="tabs">
|
||||
<div class="tab-buttons">
|
||||
<!-- 合併模式分頁 - 移到最左邊第一個 -->
|
||||
<!-- 工作區分頁 - 移到最左邊第一個 -->
|
||||
<button class="tab-button hidden" data-tab="combined" data-i18n="tabs.combined">
|
||||
📝 合併模式
|
||||
📝 工作區
|
||||
</button>
|
||||
<button class="tab-button active" data-tab="feedback" data-i18n="tabs.feedback">
|
||||
💬 回饋
|
||||
@ -499,16 +489,32 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 合併模式分頁 - 移動到此位置 -->
|
||||
<!-- 工作區分頁 - 移動到此位置 -->
|
||||
<div id="tab-combined" class="tab-content">
|
||||
<div class="section-description" style="margin-bottom: 12px; padding: 8px 12px; font-size: 13px;" data-i18n="combined.description">
|
||||
合併模式:AI 摘要和回饋輸入在同一頁面中,方便對照查看。
|
||||
AI 摘要和回饋輸入在同一頁面中,方便對照查看。
|
||||
</div>
|
||||
|
||||
<div class="combined-content">
|
||||
<!-- AI 摘要區域 -->
|
||||
<div class="combined-section">
|
||||
<div class="section-header-with-controls">
|
||||
<h3 class="combined-section-title" data-i18n="combined.summaryTitle">📋 AI 工作摘要</h3>
|
||||
<div class="auto-refresh-controls">
|
||||
<label class="auto-refresh-toggle">
|
||||
<input type="checkbox" id="autoRefreshEnabled" />
|
||||
<span class="toggle-label" data-i18n="autoRefresh.enable"></span>
|
||||
</label>
|
||||
<div class="auto-refresh-interval">
|
||||
<input type="number" id="autoRefreshInterval" min="5" max="300" value="5" />
|
||||
<span class="interval-unit" data-i18n="autoRefresh.seconds"></span>
|
||||
</div>
|
||||
<div class="auto-refresh-status" id="autoRefreshStatus">
|
||||
<span class="status-indicator" id="refreshStatusIndicator">⏸️</span>
|
||||
<span class="status-text" id="refreshStatusText" data-i18n="autoRefresh.disabled"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="combined-summary">
|
||||
<div id="combinedSummaryContent" class="text-input" style="min-height: 200px; white-space: pre-wrap !important; cursor: text; padding: 12px; line-height: 1.6; word-wrap: break-word; overflow-wrap: break-word;" data-dynamic-content="aiSummary">{{ summary }}</div>
|
||||
</div>
|
||||
@ -570,23 +576,16 @@
|
||||
</div>
|
||||
<div class="layout-mode-selector">
|
||||
<div class="layout-option">
|
||||
<input type="radio" id="separateMode" name="layoutMode" value="separate" checked>
|
||||
<label for="separateMode">
|
||||
<div class="layout-option-title" data-i18n="settings.separateMode">分離模式</div>
|
||||
<div class="layout-option-desc" data-i18n="settings.separateModeDesc">AI 摘要和回饋分別在不同頁籤</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="layout-option">
|
||||
<input type="radio" id="combinedVertical" name="layoutMode" value="combined-vertical">
|
||||
<input type="radio" id="combinedVertical" name="layoutMode" value="combined-vertical" checked>
|
||||
<label for="combinedVertical">
|
||||
<div class="layout-option-title" data-i18n="settings.combinedVertical">合併模式(垂直布局)</div>
|
||||
<div class="layout-option-title" data-i18n="settings.combinedVertical">垂直布局</div>
|
||||
<div class="layout-option-desc" data-i18n="settings.combinedVerticalDesc">AI 摘要在上,回饋輸入在下,摘要和回饋在同一頁面</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="layout-option">
|
||||
<input type="radio" id="combinedHorizontal" name="layoutMode" value="combined-horizontal">
|
||||
<label for="combinedHorizontal">
|
||||
<div class="layout-option-title" data-i18n="settings.combinedHorizontal">合併模式(水平布局)</div>
|
||||
<div class="layout-option-title" data-i18n="settings.combinedHorizontal">水平布局</div>
|
||||
<div class="layout-option-desc" data-i18n="settings.combinedHorizontalDesc">AI 摘要在左,回饋輸入在右,增大摘要可視區域</div>
|
||||
</label>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user