diff --git a/src/mcp_feedback_enhanced/web/locales/en/translation.json b/src/mcp_feedback_enhanced/web/locales/en/translation.json
index 70b4f49..b365da2 100644
--- a/src/mcp_feedback_enhanced/web/locales/en/translation.json
+++ b/src/mcp_feedback_enhanced/web/locales/en/translation.json
@@ -128,6 +128,15 @@
"light": "Light",
"auto": "Auto"
},
+ "timeUnits": {
+ "seconds": "seconds",
+ "minutes": "minutes",
+ "hours": "hours",
+ "days": "days",
+ "ago": "ago",
+ "justNow": "just now",
+ "about": "about"
+ },
"status": {
"connected": "Connected",
"connecting": "Connecting...",
@@ -205,7 +214,7 @@
"refresh": "Refresh",
"noHistory": "No session history",
"todaySessions": "Today's Sessions",
- "averageDuration": "Average Duration",
+ "todayAverageDuration": "Today's Average Duration",
"createdTime": "Created Time",
"project": "Project",
"aiSummary": "AI Summary",
@@ -411,6 +420,7 @@
"title": "Audio Notification Settings",
"description": "Configure audio notifications for session updates",
"enabled": "Enable Audio Notifications",
+ "enabledDesc": "Play audio notifications when there are new session updates",
"volume": "Volume",
"selectAudio": "Select Audio",
"testPlay": "Test Play",
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 5c7d697..9dfd2f4 100644
--- a/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json
+++ b/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json
@@ -128,6 +128,15 @@
"light": "浅色",
"auto": "自动"
},
+ "timeUnits": {
+ "seconds": "秒",
+ "minutes": "分钟",
+ "hours": "小时",
+ "days": "天",
+ "ago": "前",
+ "justNow": "刚刚",
+ "about": "约"
+ },
"status": {
"connected": "已连接",
"connecting": "连接中...",
@@ -205,7 +214,7 @@
"refresh": "重新整理",
"noHistory": "暂无历史会话",
"todaySessions": "今日会话",
- "averageDuration": "平均时长",
+ "todayAverageDuration": "今日平均时长",
"createdTime": "建立时间",
"project": "项目",
"aiSummary": "AI 总结",
@@ -411,6 +420,7 @@
"title": "音效通知设定",
"description": "设定会话更新时的音效通知",
"enabled": "启用音效通知",
+ "enabledDesc": "启用后将在有新会话更新时播放音效通知",
"volume": "音量",
"selectAudio": "选择音效",
"testPlay": "测试播放",
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 90d26f6..a31ff2a 100644
--- a/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json
+++ b/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json
@@ -133,6 +133,15 @@
"light": "淺色",
"auto": "自動"
},
+ "timeUnits": {
+ "seconds": "秒",
+ "minutes": "分鐘",
+ "hours": "小時",
+ "days": "天",
+ "ago": "前",
+ "justNow": "剛剛",
+ "about": "約"
+ },
"status": {
"connected": "已連線",
"connecting": "連線中...",
@@ -210,7 +219,7 @@
"refresh": "重新整理",
"noHistory": "暫無歷史會話",
"todaySessions": "今日會話",
- "averageDuration": "平均時長",
+ "todayAverageDuration": "今日平均時長",
"createdTime": "建立時間",
"project": "專案",
"aiSummary": "AI 摘要",
@@ -416,6 +425,7 @@
"title": "音效通知設定",
"description": "設定會話更新時的音效通知",
"enabled": "啟用音效通知",
+ "enabledDesc": "啟用後將在有新會話更新時播放音效通知",
"volume": "音量",
"selectAudio": "選擇音效",
"testPlay": "測試播放",
diff --git a/src/mcp_feedback_enhanced/web/static/css/styles.css b/src/mcp_feedback_enhanced/web/static/css/styles.css
index d7864f8..0d67c00 100644
--- a/src/mcp_feedback_enhanced/web/static/css/styles.css
+++ b/src/mcp_feedback_enhanced/web/static/css/styles.css
@@ -1331,6 +1331,45 @@ h3.combined-section-title {
margin: 0;
}
+/* Combined 標籤頁頂部佈局 */
+.combined-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+ padding: 8px 12px;
+ gap: 16px;
+}
+
+.combined-header .section-description {
+ flex: 1;
+ font-size: 13px;
+ margin: 0;
+ padding: 0;
+}
+
+/* Combined 標籤頁提交按鈕樣式 */
+.combined-submit-btn {
+ flex-shrink: 0;
+ padding: 8px 16px;
+ font-size: 13px;
+ white-space: nowrap;
+}
+
+/* 響應式設計 - 小螢幕時垂直排列 */
+@media (max-width: 768px) {
+ .combined-header {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 12px;
+ }
+
+ .combined-submit-btn {
+ align-self: flex-end;
+ width: auto;
+ }
+}
+
/* Placeholder 文本換行修復 - 全局樣式 */
textarea::placeholder,
#feedbackText::placeholder,
diff --git a/src/mcp_feedback_enhanced/web/static/js/app.js b/src/mcp_feedback_enhanced/web/static/js/app.js
index 851c9fd..e25ebcd 100644
--- a/src/mcp_feedback_enhanced/web/static/js/app.js
+++ b/src/mcp_feedback_enhanced/web/static/js/app.js
@@ -240,8 +240,7 @@
return new Promise(function(resolve) {
// 提交按鈕事件
const submitButtons = [
- window.MCPFeedback.Utils.safeQuerySelector('#submitBtn'),
- window.MCPFeedback.Utils.safeQuerySelector('#combinedSubmitBtn')
+ window.MCPFeedback.Utils.safeQuerySelector('#submitBtn')
].filter(function(btn) { return btn !== null; });
submitButtons.forEach(function(button) {
@@ -250,17 +249,7 @@
});
});
- // 取消按鈕事件
- const cancelButtons = [
- window.MCPFeedback.Utils.safeQuerySelector('#cancelBtn'),
- window.MCPFeedback.Utils.safeQuerySelector('#combinedCancelBtn')
- ].filter(function(btn) { return btn !== null; });
-
- cancelButtons.forEach(function(button) {
- button.addEventListener('click', function() {
- self.cancelFeedback();
- });
- });
+ // 取消按鈕事件 - 已移除取消按鈕,保留 ESC 快捷鍵功能
// 命令執行事件
const runCommandBtn = window.MCPFeedback.Utils.safeQuerySelector('#runCommandBtn');
diff --git a/src/mcp_feedback_enhanced/web/static/js/i18n.js b/src/mcp_feedback_enhanced/web/static/js/i18n.js
index f022ce5..40dc4e5 100644
--- a/src/mcp_feedback_enhanced/web/static/js/i18n.js
+++ b/src/mcp_feedback_enhanced/web/static/js/i18n.js
@@ -218,6 +218,14 @@ class I18nManager {
if (typeof window.feedbackApp.sessionManager.updateDisplay === 'function') {
window.feedbackApp.sessionManager.updateDisplay();
}
+
+ // 重新渲染統計資訊以更新時間單位
+ if (window.feedbackApp.sessionManager.dataManager &&
+ window.feedbackApp.sessionManager.uiRenderer) {
+ const stats = window.feedbackApp.sessionManager.dataManager.getStats();
+ window.feedbackApp.sessionManager.uiRenderer.renderStats(stats);
+ console.log('🌐 已更新統計資訊的語言顯示');
+ }
}
// 更新狀態徽章文字
diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/audio/audio-settings-ui.js b/src/mcp_feedback_enhanced/web/static/js/modules/audio/audio-settings-ui.js
index e0da350..bc24e70 100644
--- a/src/mcp_feedback_enhanced/web/static/js/modules/audio/audio-settings-ui.js
+++ b/src/mcp_feedback_enhanced/web/static/js/modules/audio/audio-settings-ui.js
@@ -79,11 +79,18 @@
-
-
+
+
+
啟用音效通知
+
+ 啟用後將在有新會話更新時播放音效通知
+
+
+
+
+
@@ -156,8 +163,9 @@
// 啟用開關事件
if (this.enabledToggle) {
- this.enabledToggle.addEventListener('change', function(e) {
- self.handleEnabledChange(e.target.checked);
+ this.enabledToggle.addEventListener('click', function() {
+ const newValue = !self.enabledToggle.classList.contains('active');
+ self.handleEnabledChange(newValue);
});
}
@@ -219,7 +227,7 @@
console.error('❌ 設定啟用狀態失敗:', error);
this.showError(error.message);
// 恢復原狀態
- this.enabledToggle.checked = this.audioManager.getSettings().enabled;
+ this.enabledToggle.classList.toggle('active', this.audioManager.getSettings().enabled);
}
};
@@ -342,7 +350,7 @@
// 更新啟用狀態
if (this.enabledToggle) {
- this.enabledToggle.checked = settings.enabled;
+ this.enabledToggle.classList.toggle('active', settings.enabled);
}
// 更新音量
@@ -496,7 +504,7 @@
* 更新控制項狀態
*/
AudioSettingsUI.prototype.updateControlsState = function() {
- const enabled = this.enabledToggle ? this.enabledToggle.checked : false;
+ const enabled = this.enabledToggle ? this.enabledToggle.classList.contains('active') : false;
// 根據啟用狀態禁用/啟用控制項
const controls = [
diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-data-manager.js b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-data-manager.js
index c0d5b32..fb53b1c 100644
--- a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-data-manager.js
+++ b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-data-manager.js
@@ -29,8 +29,7 @@
// 統計數據
this.sessionStats = {
todayCount: 0,
- averageDuration: 0,
- totalSessions: 0
+ averageDuration: 0
};
// localStorage 相關設定
@@ -453,21 +452,20 @@
SessionDataManager.prototype.updateStats = function() {
// 計算今日會話數
const todayStart = TimeUtils.getTodayStartTimestamp();
- this.sessionStats.todayCount = this.sessionHistory.filter(function(session) {
+ const todaySessions = this.sessionHistory.filter(function(session) {
return session.created_at && session.created_at >= todayStart;
- }).length;
+ });
+ this.sessionStats.todayCount = todaySessions.length;
- // 計算平均持續時間
- const completedSessions = this.sessionHistory.filter(s => s.duration && s.duration > 0);
- if (completedSessions.length > 0) {
- const totalDuration = completedSessions.reduce((sum, s) => sum + s.duration, 0);
- this.sessionStats.averageDuration = Math.round(totalDuration / completedSessions.length);
+ // 計算今日平均持續時間
+ const todayCompletedSessions = todaySessions.filter(s => s.duration && s.duration > 0);
+ if (todayCompletedSessions.length > 0) {
+ const totalDuration = todayCompletedSessions.reduce((sum, s) => sum + s.duration, 0);
+ this.sessionStats.averageDuration = Math.round(totalDuration / todayCompletedSessions.length);
} else {
this.sessionStats.averageDuration = 0;
}
- this.sessionStats.totalSessions = this.sessionHistory.length;
-
// 觸發回調
if (this.onStatsChange) {
this.onStatsChange(this.sessionStats);
@@ -671,7 +669,7 @@
const self = this;
const exportData = {
exportedAt: new Date().toISOString(),
- totalSessions: this.sessionHistory.length,
+ sessionCount: this.sessionHistory.length,
sessions: this.sessionHistory.map(function(session) {
const sessionData = {
session_id: session.session_id,
@@ -774,8 +772,7 @@
this.lastStatusUpdate = null;
this.sessionStats = {
todayCount: 0,
- averageDuration: 0,
- totalSessions: 0
+ averageDuration: 0
};
console.log('📊 SessionDataManager 清理完成');
diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-ui-renderer.js b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-ui-renderer.js
index a1a21f6..a6c9408 100644
--- a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-ui-renderer.js
+++ b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-ui-renderer.js
@@ -51,8 +51,7 @@
// 統計元素
this.statsElements = {
todayCount: DOMUtils.safeQuerySelector('.stat-today-count'),
- averageDuration: DOMUtils.safeQuerySelector('.stat-average-duration'),
- totalSessions: DOMUtils.safeQuerySelector('.stat-total-sessions')
+ averageDuration: DOMUtils.safeQuerySelector('.stat-average-duration')
};
};
@@ -371,8 +370,7 @@
console.log('🎨 渲染統計資訊:', stats);
console.log('🎨 統計元素狀態:', {
todayCount: !!this.statsElements.todayCount,
- averageDuration: !!this.statsElements.averageDuration,
- totalSessions: !!this.statsElements.totalSessions
+ averageDuration: !!this.statsElements.averageDuration
});
// 更新今日會話數
@@ -383,22 +381,14 @@
console.warn('🎨 找不到今日會話數元素 (.stat-today-count)');
}
- // 更新平均時長
+ // 更新今日平均時長
if (this.statsElements.averageDuration) {
const durationText = TimeUtils.formatDuration(stats.averageDuration);
DOMUtils.safeSetTextContent(this.statsElements.averageDuration, durationText);
- console.log('🎨 已更新平均時長:', durationText);
+ console.log('🎨 已更新今日平均時長:', durationText);
} else {
console.warn('🎨 找不到平均時長元素 (.stat-average-duration)');
}
-
- // 更新總會話數
- if (this.statsElements.totalSessions) {
- DOMUtils.safeSetTextContent(this.statsElements.totalSessions, stats.totalSessions.toString());
- console.log('🎨 已更新總會話數:', stats.totalSessions);
- } else {
- console.warn('🎨 找不到總會話數元素 (.stat-total-sessions)');
- }
};
/**
diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/ui-manager.js b/src/mcp_feedback_enhanced/web/static/js/modules/ui-manager.js
index e929185..09f73bc 100644
--- a/src/mcp_feedback_enhanced/web/static/js/modules/ui-manager.js
+++ b/src/mcp_feedback_enhanced/web/static/js/modules/ui-manager.js
@@ -204,8 +204,7 @@
*/
UIManager.prototype.updateSubmitButton = function() {
const submitButtons = [
- Utils.safeQuerySelector('#submitBtn'),
- Utils.safeQuerySelector('#combinedSubmitBtn')
+ Utils.safeQuerySelector('#submitBtn')
].filter(function(btn) { return btn !== null; });
const self = this;
@@ -404,8 +403,7 @@
// 重新啟用提交按鈕
const submitButtons = [
- Utils.safeQuerySelector('#submitBtn'),
- Utils.safeQuerySelector('#combinedSubmitBtn')
+ Utils.safeQuerySelector('#submitBtn')
].filter(function(btn) { return btn !== null; });
submitButtons.forEach(function(button) {
diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/utils/time-utils.js b/src/mcp_feedback_enhanced/web/static/js/modules/utils/time-utils.js
index 728e573..195ada9 100644
--- a/src/mcp_feedback_enhanced/web/static/js/modules/utils/time-utils.js
+++ b/src/mcp_feedback_enhanced/web/static/js/modules/utils/time-utils.js
@@ -63,26 +63,55 @@
},
/**
- * 格式化持續時間(秒)
+ * 格式化持續時間(秒)- 支援國際化
*/
formatDuration: function(seconds) {
- if (!seconds || seconds < 0) return '0秒';
+ if (!seconds || seconds < 0) {
+ const secondsText = this.getTimeUnitText('seconds');
+ return `0${secondsText}`;
+ }
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = Math.floor(seconds % 60);
+ const hoursText = this.getTimeUnitText('hours');
+ const minutesText = this.getTimeUnitText('minutes');
+ const secondsText = this.getTimeUnitText('seconds');
+
if (hours > 0) {
- return `${hours}小時${minutes > 0 ? minutes + '分鐘' : ''}`;
+ return `${hours}${hoursText}${minutes > 0 ? minutes + minutesText : ''}`;
} else if (minutes > 0) {
- return `${minutes}分鐘${remainingSeconds > 0 ? remainingSeconds + '秒' : ''}`;
+ return `${minutes}${minutesText}${remainingSeconds > 0 ? remainingSeconds + secondsText : ''}`;
} else {
- return `${remainingSeconds}秒`;
+ return `${remainingSeconds}${secondsText}`;
}
},
/**
- * 格式化相對時間(多久之前)
+ * 獲取時間單位文字(支援國際化)
+ */
+ getTimeUnitText: function(unit) {
+ if (window.i18nManager && typeof window.i18nManager.t === 'function') {
+ return window.i18nManager.t(`timeUnits.${unit}`, unit);
+ }
+
+ // 回退到預設值(繁體中文)
+ const fallbackUnits = {
+ 'seconds': '秒',
+ 'minutes': '分鐘',
+ 'hours': '小時',
+ 'days': '天',
+ 'ago': '前',
+ 'justNow': '剛剛',
+ 'about': '約'
+ };
+
+ return fallbackUnits[unit] || unit;
+ },
+
+ /**
+ * 格式化相對時間(多久之前)- 支援國際化
*/
formatRelativeTime: function(timestamp) {
if (!timestamp) return '未知';
@@ -96,17 +125,23 @@
const now = Date.now() / 1000;
const diff = now - normalizedTimestamp;
+ const minutesText = this.getTimeUnitText('minutes');
+ const hoursText = this.getTimeUnitText('hours');
+ const daysText = this.getTimeUnitText('days');
+ const agoText = this.getTimeUnitText('ago');
+ const justNowText = this.getTimeUnitText('justNow');
+
if (diff < 60) {
- return '剛剛';
+ return justNowText;
} else if (diff < 3600) {
const minutes = Math.floor(diff / 60);
- return `${minutes}分鐘前`;
+ return `${minutes}${minutesText}${agoText}`;
} else if (diff < 86400) {
const hours = Math.floor(diff / 3600);
- return `${hours}小時前`;
+ return `${hours}${hoursText}${agoText}`;
} else {
const days = Math.floor(diff / 86400);
- return `${days}天前`;
+ return `${days}${daysText}${agoText}`;
}
} catch (error) {
console.warn('相對時間計算失敗:', timestamp, error);
@@ -353,7 +388,7 @@
},
/**
- * 估算會話持續時間(用於歷史會話)
+ * 估算會話持續時間(用於歷史會話)- 支援國際化
*/
estimateSessionDuration: function(sessionData) {
// 基礎時間 2 分鐘
@@ -377,7 +412,9 @@
// 限制在合理範圍內
estimatedMinutes = Math.max(1, Math.min(estimatedMinutes, 15));
- return `約 ${estimatedMinutes} 分鐘`;
+ const aboutText = this.getTimeUnitText('about');
+ const minutesText = this.getTimeUnitText('minutes');
+ return `${aboutText} ${estimatedMinutes} ${minutesText}`;
},
/**
diff --git a/src/mcp_feedback_enhanced/web/templates/feedback.html b/src/mcp_feedback_enhanced/web/templates/feedback.html
index 7900cba..66ec327 100644
--- a/src/mcp_feedback_enhanced/web/templates/feedback.html
+++ b/src/mcp_feedback_enhanced/web/templates/feedback.html
@@ -481,7 +481,7 @@
@@ -642,8 +642,13 @@
-
- AI 摘要和回饋輸入在同一頁面中,方便對照查看。
+
@@ -1078,15 +1083,7 @@
-
-
+