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
8316cb6572
commit
3d4aafa3dc
@ -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",
|
||||
|
@ -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": "测试播放",
|
||||
|
@ -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": "測試播放",
|
||||
|
@ -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,
|
||||
|
@ -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');
|
||||
|
@ -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('🌐 已更新統計資訊的語言顯示');
|
||||
}
|
||||
}
|
||||
|
||||
// 更新狀態徽章文字
|
||||
|
@ -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 = [
|
||||
|
@ -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 清理完成');
|
||||
|
@ -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)');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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) {
|
||||
|
@ -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}`;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -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 -->
|
||||
|
Loading…
x
Reference in New Issue
Block a user