提交位置變動、會話管理平均時長調整為今日

This commit is contained in:
Minidoracat 2025-06-14 10:37:25 +08:00
parent 8316cb6572
commit 3d4aafa3dc
12 changed files with 175 additions and 82 deletions

View File

@ -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",

View File

@ -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": "测试播放",

View File

@ -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": "測試播放",

View File

@ -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,

View File

@ -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');

View File

@ -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('🌐 已更新統計資訊的語言顯示');
}
}
// 更新狀態徽章文字

View File

@ -79,11 +79,18 @@
<div class="audio-settings-controls">
<!-- 啟用開關 -->
<div class="audio-setting-item">
<label class="audio-setting-label">
<input type="checkbox" id="audioNotificationEnabled" class="audio-toggle">
<span data-i18n="audio.notification.enabled">啟用音效通知</span>
</label>
<div class="setting-item">
<div class="setting-info">
<div class="setting-label" data-i18n="audio.notification.enabled">啟用音效通知</div>
<div class="setting-description" data-i18n="audio.notification.enabledDesc">
啟用後將在有新會話更新時播放音效通知
</div>
</div>
<div class="setting-control">
<button type="button" id="audioNotificationEnabled" class="toggle-btn" aria-label="切換音效通知">
<span class="toggle-slider"></span>
</button>
</div>
</div>
<!-- 音量控制 -->
@ -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 = [

View File

@ -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 清理完成');

View File

@ -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)');
}
};
/**

View File

@ -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) {

View File

@ -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}`;
},
/**

View File

@ -481,7 +481,7 @@
</div>
<div class="stat-item">
<div class="stat-value stat-average-duration">--</div>
<div class="stat-label" data-i18n="sessionManagement.averageDuration">平均時長</div>
<div class="stat-label" data-i18n="sessionManagement.todayAverageDuration">今日平均時長</div>
</div>
</div>
</div>
@ -642,8 +642,13 @@
<!-- 工作區分頁 - 移動到此位置 -->
<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 摘要和回饋輸入在同一頁面中,方便對照查看。
<div class="combined-header">
<div class="section-description" data-i18n="combined.description">
AI 摘要和回饋輸入在同一頁面中,方便對照查看。
</div>
<button id="submitBtn" class="btn btn-success combined-submit-btn" data-i18n="buttons.submit">
✅ 提交回饋
</button>
</div>
<div class="combined-content">
@ -1078,15 +1083,7 @@
</div> <!-- 關閉 main-content-area -->
</main>
<!-- 底部操作按鈕 -->
<footer class="footer-actions">
<button id="cancelBtn" class="btn btn-secondary" data-i18n="buttons.cancel">
❌ 取消
</button>
<button id="submitBtn" class="btn btn-success" data-i18n="buttons.submit">
✅ 提交回饋
</button>
</footer>
</div>
<!-- WebSocket 和 JavaScript -->