This commit is contained in:
李振民 2025-06-26 09:43:16 +08:00
parent 9c412a1321
commit 2cd8d91bb9
10 changed files with 281 additions and 209 deletions

View File

@ -156,6 +156,10 @@
"submitted": {
"title": "Submitted",
"message": "Waiting for next MCP call"
},
"completed": {
"title": "Completed",
"message": "Session completed"
}
},
"notifications": {

View File

@ -156,6 +156,10 @@
"submitted": {
"title": "反馈已提交",
"message": "等待下次 MCP 调用"
},
"completed": {
"title": "已完成",
"message": "会话已完成"
}
},
"notifications": {

View File

@ -161,6 +161,10 @@
"submitted": {
"title": "回饋已提交",
"message": "等待下次 MCP 調用"
},
"completed": {
"title": "已完成",
"message": "會話已完成"
}
},
"notifications": {

View File

@ -318,25 +318,46 @@ class WebUIManager:
def create_session(self, project_directory: str, summary: str) -> str:
"""創建新的回饋會話 - 重構為單一活躍會話模式,保留標籤頁狀態"""
# 保存舊會話的 WebSocket 連接以便發送更新通知
# 保存舊會話的引用和 WebSocket 連接
old_session = self.current_session
old_websocket = None
if self.current_session and self.current_session.websocket:
old_websocket = self.current_session.websocket
if old_session and old_session.websocket:
old_websocket = old_session.websocket
debug_log("保存舊會話的 WebSocket 連接以發送更新通知")
# 如果已有活躍會話,先保存其標籤頁狀態到全局狀態
if self.current_session:
debug_log("保存現有會話的標籤頁狀態並清理會話")
# 保存標籤頁狀態到全局
if hasattr(self.current_session, "active_tabs"):
self._merge_tabs_to_global(self.current_session.active_tabs)
# 同步清理會話資源(但保留 WebSocket 連接)
self.current_session._cleanup_sync()
# 創建新會話
session_id = str(uuid.uuid4())
session = WebFeedbackSession(session_id, project_directory, summary)
# 如果有舊會話,處理狀態轉換和清理
if old_session:
debug_log(f"處理舊會話 {old_session.session_id} 的狀態轉換,當前狀態: {old_session.status.value}")
# 保存標籤頁狀態到全局
if hasattr(old_session, "active_tabs"):
self._merge_tabs_to_global(old_session.active_tabs)
# 如果舊會話是已提交狀態,進入下一步(已完成)
if old_session.status == SessionStatus.FEEDBACK_SUBMITTED:
debug_log(f"舊會話 {old_session.session_id} 進入下一步:已提交 → 已完成")
success = old_session.next_step("反饋已處理,會話完成")
if success:
debug_log(f"✅ 舊會話 {old_session.session_id} 成功進入已完成狀態")
else:
debug_log(f"❌ 舊會話 {old_session.session_id} 無法進入下一步")
else:
debug_log(f"舊會話 {old_session.session_id} 狀態為 {old_session.status.value},無需轉換")
# 確保舊會話仍在字典中用於API獲取
if old_session.session_id in self.sessions:
debug_log(f"舊會話 {old_session.session_id} 仍在會話字典中")
else:
debug_log(f"⚠️ 舊會話 {old_session.session_id} 不在會話字典中,重新添加")
self.sessions[old_session.session_id] = old_session
# 同步清理會話資源(但保留 WebSocket 連接)
old_session._cleanup_sync()
# 將全局標籤頁狀態繼承到新會話
session.active_tabs = self.global_active_tabs.copy()
@ -348,25 +369,11 @@ class WebUIManager:
debug_log(f"創建新的活躍會話: {session_id}")
debug_log(f"繼承 {len(session.active_tabs)} 個活躍標籤頁")
# 處理會話更新通知
# 處理WebSocket連接轉移
if old_websocket:
# 有舊連接,立即發送會話更新通知並轉移連接
self._old_websocket_for_update = old_websocket
self._new_session_for_update = session
debug_log("已保存舊 WebSocket 連接,準備發送會話更新通知")
# 立即發送會話更新通知
import asyncio
try:
# 在後台任務中發送通知並轉移連接
asyncio.create_task(self._send_immediate_session_update())
except Exception as e:
debug_log(f"創建會話更新任務失敗: {e}")
# 即使任務創建失敗,也要嘗試直接轉移連接
session.websocket = old_websocket
debug_log("任務創建失敗,直接轉移 WebSocket 連接到新會話")
self._pending_session_update = True
# 直接轉移連接到新會話,消息發送由 smart_open_browser 統一處理
session.websocket = old_websocket
debug_log("已將舊 WebSocket 連接轉移到新會話")
else:
# 沒有舊連接,標記需要發送會話更新通知(當新 WebSocket 連接建立時)
self._pending_session_update = True
@ -682,107 +689,9 @@ class WebUIManager:
else:
debug_log("沒有活躍的桌面應用程式實例")
async def notify_session_update(self, session):
"""向活躍標籤頁發送會話更新通知"""
try:
# 檢查是否有活躍的 WebSocket 連接
if session.websocket:
# 直接通過當前會話的 WebSocket 發送
await session.websocket.send_json(
{
"type": "session_updated",
"action": "new_session_created",
"message": "新會話已創建,正在更新頁面內容",
"session_info": {
"project_directory": session.project_directory,
"summary": session.summary,
"session_id": session.session_id,
},
}
)
debug_log("會話更新通知已通過 WebSocket 發送")
else:
# 沒有活躍連接,設置待更新標記
self._pending_session_update = True
debug_log("沒有活躍 WebSocket 連接,設置待更新標記")
except Exception as e:
debug_log(f"發送會話更新通知失敗: {e}")
# 設置待更新標記作為備用方案
self._pending_session_update = True
async def _send_immediate_session_update(self):
"""立即發送會話更新通知(使用舊的 WebSocket 連接)"""
try:
# 檢查是否有保存的舊 WebSocket 連接
if hasattr(self, "_old_websocket_for_update") and hasattr(
self, "_new_session_for_update"
):
old_websocket = self._old_websocket_for_update
new_session = self._new_session_for_update
# 改進的連接有效性檢查
websocket_valid = False
if old_websocket:
try:
# 檢查 WebSocket 連接狀態
if hasattr(old_websocket, "client_state"):
websocket_valid = (
old_websocket.client_state
!= old_websocket.client_state.DISCONNECTED
)
else:
# 如果沒有 client_state 屬性,嘗試發送測試消息來檢查連接
websocket_valid = True
except Exception as check_error:
debug_log(f"檢查 WebSocket 連接狀態失敗: {check_error}")
websocket_valid = False
if websocket_valid:
try:
# 發送會話更新通知
await old_websocket.send_json(
{
"type": "session_updated",
"action": "new_session_created",
"message": "新會話已創建,正在更新頁面內容",
"session_info": {
"project_directory": new_session.project_directory,
"summary": new_session.summary,
"session_id": new_session.session_id,
},
}
)
debug_log("已通過舊 WebSocket 連接發送會話更新通知")
# 延遲一小段時間讓前端處理消息
await asyncio.sleep(0.2)
# 將 WebSocket 連接轉移到新會話
new_session.websocket = old_websocket
debug_log("已將 WebSocket 連接轉移到新會話")
except Exception as send_error:
debug_log(f"發送會話更新通知失敗: {send_error}")
# 如果發送失敗,仍然嘗試轉移連接
new_session.websocket = old_websocket
debug_log("發送失敗但仍轉移 WebSocket 連接到新會話")
else:
debug_log("舊 WebSocket 連接無效,設置待更新標記")
self._pending_session_update = True
# 清理臨時變數
delattr(self, "_old_websocket_for_update")
delattr(self, "_new_session_for_update")
else:
# 沒有舊連接,設置待更新標記
self._pending_session_update = True
debug_log("沒有舊 WebSocket 連接,設置待更新標記")
except Exception as e:
debug_log(f"立即發送會話更新通知失敗: {e}")
# 回退到待更新標記
self._pending_session_update = True
async def _safe_close_websocket(self, websocket):
"""安全關閉 WebSocket 連接,避免事件循環衝突 - 僅在連接已轉移後調用"""
@ -1127,7 +1036,7 @@ async def launch_web_feedback_ui(
"""
manager = get_web_ui_manager()
# 創建或更當前活躍會話
# 創建新會話每次AI調用都應該創建新會話
manager.create_session(project_directory, summary)
session = manager.get_current_session()
@ -1154,9 +1063,9 @@ async def launch_web_feedback_ui(
debug_log(f"[DEBUG] 服務器地址: {feedback_url}")
# 如果檢測到活躍標籤頁但沒有開啟新視窗,立即發送會話更新通知
# 如果檢測到活躍標籤頁,消息已在 smart_open_browser 中發送,無需額外處理
if has_active_tabs:
debug_log("檢測到活躍標籤頁,跳過額外的會話更新通知在 smart_open_browser 中發送")
debug_log("檢測到活躍標籤頁,會話更新通知已發送")
try:
# 等待用戶回饋,傳遞 timeout 參數

View File

@ -29,15 +29,13 @@ from ...utils.resource_manager import get_resource_manager, register_process
class SessionStatus(Enum):
"""會話狀態枚舉"""
"""會話狀態枚舉 - 單向流轉設計"""
WAITING = "waiting" # 等待中
ACTIVE = "active" # 活躍中
FEEDBACK_SUBMITTED = "feedback_submitted" # 已提交反饋
COMPLETED = "completed" # 已完成
TIMEOUT = "timeout" # 超時
ERROR = "error" # 錯誤
EXPIRED = "expired" # 已過期
ERROR = "error" # 錯誤(終態)
EXPIRED = "expired" # 已過期(終態)
class CleanupReason(Enum):
@ -174,21 +172,79 @@ class WebFeedbackSession:
f"會話 {self.session_id} 初始化完成,自動清理延遲: {auto_cleanup_delay}秒,最大空閒: {max_idle_time}"
)
def update_status(self, status: SessionStatus, message: str | None = None):
"""更新會話狀態"""
self.status = status
def next_step(self, message: str | None = None) -> bool:
"""進入下一個狀態 - 單向流轉,不可倒退"""
old_status = self.status
# 定義狀態流轉路徑
next_status_map = {
SessionStatus.WAITING: SessionStatus.FEEDBACK_SUBMITTED,
SessionStatus.FEEDBACK_SUBMITTED: SessionStatus.COMPLETED,
SessionStatus.COMPLETED: None, # 終態
SessionStatus.ERROR: None, # 終態
SessionStatus.EXPIRED: None # 終態
}
next_status = next_status_map.get(self.status)
if next_status is None:
debug_log(f"⚠️ 會話 {self.session_id} 已處於終態 {self.status.value},無法進入下一步")
return False
# 執行狀態轉換
self.status = next_status
if message:
self.status_message = message
# 統一使用 time.time()
else:
# 默認消息
default_messages = {
SessionStatus.FEEDBACK_SUBMITTED: "用戶已提交反饋",
SessionStatus.COMPLETED: "會話已完成"
}
self.status_message = default_messages.get(next_status, "狀態已更新")
self.last_activity = time.time()
# 如果會話變為活躍狀態,重置清理定時器
if status in [SessionStatus.ACTIVE, SessionStatus.FEEDBACK_SUBMITTED]:
# 如果會話變為已提交狀態,重置清理定時器
if next_status == SessionStatus.FEEDBACK_SUBMITTED:
self._schedule_auto_cleanup()
debug_log(
f"會話 {self.session_id} 狀態更新: {status.value} - {self.status_message}"
f"會話 {self.session_id} 狀態流轉: {old_status.value}{next_status.value} - {self.status_message}"
)
return True
def set_error(self, message: str = "會話發生錯誤") -> bool:
"""設置錯誤狀態(特殊方法,可從任何狀態進入)"""
old_status = self.status
self.status = SessionStatus.ERROR
self.status_message = message
self.last_activity = time.time()
debug_log(
f"❌ 會話 {self.session_id} 設置為錯誤狀態: {old_status.value}{self.status.value} - {message}"
)
return True
def set_expired(self, message: str = "會話已過期") -> bool:
"""設置過期狀態(特殊方法,可從任何狀態進入)"""
old_status = self.status
self.status = SessionStatus.EXPIRED
self.status_message = message
self.last_activity = time.time()
debug_log(
f"⏰ 會話 {self.session_id} 設置為過期狀態: {old_status.value}{self.status.value} - {message}"
)
return True
def can_proceed(self) -> bool:
"""檢查是否可以進入下一步"""
return self.status in [SessionStatus.WAITING, SessionStatus.FEEDBACK_SUBMITTED]
def is_terminal(self) -> bool:
"""檢查是否處於終態"""
return self.status in [SessionStatus.COMPLETED, SessionStatus.ERROR, SessionStatus.EXPIRED]
def get_status_info(self) -> dict[str, Any]:
"""獲取會話狀態信息"""
@ -404,10 +460,8 @@ class WebFeedbackSession:
self.settings = settings or {}
self.images = self._process_images(images)
# 更新狀態為已提交反饋
self.update_status(
SessionStatus.FEEDBACK_SUBMITTED, "已送出反饋,等待下次 MCP 調用"
)
# 進入下一步:等待中 → 已提交反饋
self.next_step("已送出反饋,等待下次 MCP 調用")
self.feedback_completed.set()

View File

@ -157,6 +157,41 @@ def setup_routes(manager: "WebUIManager"):
}
)
@manager.app.get("/api/all-sessions")
async def get_all_sessions():
"""獲取所有會話的實時狀態"""
try:
sessions_data = []
# 獲取所有會話的實時狀態
for session_id, session in manager.sessions.items():
session_info = {
"session_id": session.session_id,
"project_directory": session.project_directory,
"summary": session.summary,
"status": session.status.value,
"status_message": session.status_message,
"created_at": int(session.created_at * 1000), # 轉換為毫秒
"last_activity": int(session.last_activity * 1000),
"feedback_completed": session.feedback_completed.is_set(),
"has_websocket": session.websocket is not None,
"is_current": session == manager.current_session
}
sessions_data.append(session_info)
# 按創建時間排序(最新的在前)
sessions_data.sort(key=lambda x: x["created_at"], reverse=True)
debug_log(f"返回 {len(sessions_data)} 個會話的實時狀態")
return JSONResponse(content={"sessions": sessions_data})
except Exception as e:
debug_log(f"獲取所有會話狀態失敗: {e}")
return JSONResponse(
status_code=500,
content={"error": f"獲取會話狀態失敗: {e!s}"}
)
@manager.app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
"""WebSocket 端點 - 重構後移除 session_id 依賴"""

View File

@ -686,7 +686,7 @@
// 檢查是否是新會話創建的通知
if (data.action === 'new_session_created') {
console.log('🆕 檢測到新會話創建,準備刷新頁面顯示新內容');
console.log('🆕 檢測到新會話創建,完全刷新頁面以確保狀態同步');
// 播放音效通知
if (this.audioManager) {
@ -699,9 +699,9 @@
window.MCPFeedback.Utils.CONSTANTS.MESSAGE_SUCCESS
);
// 延遲一小段時間讓用戶看到通知,然後刷新頁面
// 延遲一小段時間讓用戶看到通知,然後完全刷新頁面
setTimeout(function() {
console.log('🔄 刷新頁面以顯示新會話內容');
console.log('🔄 完全刷新頁面以顯示新會話內容');
window.location.reload();
}, 1500);
@ -831,7 +831,16 @@
* 處理狀態更新原始版本供防抖使用
*/
FeedbackApp.prototype._originalHandleStatusUpdate = function(statusInfo) {
console.log('處理狀態更新:', statusInfo);
console.log('📊 處理狀態更新:', statusInfo);
const sessionId = statusInfo.session_id;
console.log('🔍 狀態更新詳情:', {
currentSessionId: this.currentSessionId,
newSessionId: sessionId,
status: statusInfo.status,
message: statusInfo.message,
isNewSession: sessionId !== this.currentSessionId
});
// 更新 SessionManager 的狀態資訊
if (this.sessionManager && this.sessionManager.updateStatusInfo) {
@ -844,43 +853,36 @@
document.title = 'MCP Feedback - ' + projectName;
}
// 提取會話 ID
const sessionId = statusInfo.session_id || this.currentSessionId;
// 使用之前已聲明的 sessionId
// 根據狀態更新 UI
// 前端只管理會話ID所有狀態都從服務器獲取
console.log('📊 收到服務器狀態更新:', statusInfo.status, '會話ID:', sessionId);
// 更新當前會話ID
if (sessionId) {
this.currentSessionId = sessionId;
console.log('🔄 更新當前會話ID:', sessionId.substring(0, 8) + '...');
}
// 根據服務器狀態更新消息顯示(不修改前端狀態)
switch (statusInfo.status) {
case 'feedback_submitted':
this.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED, sessionId);
const submittedMessage = window.i18nManager ? window.i18nManager.t('feedback.submittedWaiting') : '已送出反饋,等待下次 MCP 調用...';
this.updateSummaryStatus(submittedMessage);
break;
case 'active':
case 'waiting':
// 檢查是否是新會話
if (sessionId && sessionId !== this.currentSessionId) {
// 新會話:重置為等待狀態
this.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, sessionId);
} else {
// 同一會話:保護已提交狀態,避免被覆蓋
const currentState = this.uiManager.getFeedbackState();
if (currentState !== window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED) {
this.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, sessionId);
} else {
console.log('🔒 保護已提交狀態,不重置為等待狀態');
}
}
const waitingMessage = window.i18nManager ? window.i18nManager.t('feedback.waitingForUser') : '等待用戶回饋...';
this.updateSummaryStatus(waitingMessage);
if (statusInfo.status === 'waiting') {
const waitingMessage = window.i18nManager ? window.i18nManager.t('feedback.waitingForUser') : '等待用戶回饋...';
this.updateSummaryStatus(waitingMessage);
// 檢查並啟動自動提交(如果條件滿足)
const self = this;
setTimeout(function() {
self.checkAndStartAutoSubmit();
}, 100); // 短暫延遲確保狀態更新完成
}
// 檢查並啟動自動提交(如果條件滿足)
const self = this;
setTimeout(function() {
self.checkAndStartAutoSubmit();
}, 100);
break;
case 'completed':
const completedMessage = window.i18nManager ? window.i18nManager.t('feedback.completed') : '會話已完成';
this.updateSummaryStatus(completedMessage);
break;
}
};
@ -923,10 +925,15 @@
* 檢查是否可以提交回饋
*/
FeedbackApp.prototype.canSubmitFeedback = function() {
return this.webSocketManager &&
this.webSocketManager.isReady() &&
this.uiManager &&
this.uiManager.getFeedbackState() === window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING;
// 簡化檢查只檢查WebSocket連接狀態由服務器端驗證
const wsReady = this.webSocketManager && this.webSocketManager.isReady();
console.log('🔍 提交檢查:', {
wsReady: wsReady,
sessionId: this.currentSessionId
});
return wsReady;
};
/**
@ -1203,14 +1210,9 @@
FeedbackApp.prototype.handleSessionUpdate = function(sessionData) {
console.log('🔄 處理自動檢測到的會話更新:', sessionData);
// 更新當前會話 ID
// 更新當前會話 ID,不管理狀態
this.currentSessionId = sessionData.session_id;
// 重置回饋狀態
if (this.uiManager) {
this.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, sessionData.session_id);
}
// 局部更新頁面內容
this.refreshPageContent();
};
@ -1233,9 +1235,17 @@
.then(function(sessionData) {
console.log('📥 獲取到最新會話資料:', sessionData);
// 重置回饋狀態
// 檢查並保護已提交狀態
if (sessionData.session_id && self.uiManager) {
self.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, sessionData.session_id);
const currentState = self.uiManager.getFeedbackState();
if (currentState !== window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED) {
self.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, sessionData.session_id);
console.log('🔄 局部更新:重置回饋狀態為等待中');
} else {
console.log('🔒 局部更新:保護已提交狀態,不重置');
// 只更新會話ID保持已提交狀態
self.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED, sessionData.session_id);
}
}
// 更新 AI 摘要內容

View File

@ -62,9 +62,13 @@
if (this.currentSession && this.currentSession.session_id) {
console.log('📊 檢測到會話 ID 變更,處理舊會話:', this.currentSession.session_id, '->', sessionData.session_id);
// 將舊會話標記為完成並加入歷史記錄
// 將舊會話加入歷史記錄,保持其原有狀態
const oldSession = Object.assign({}, this.currentSession);
oldSession.status = 'completed';
// 完全保持舊會話的原有狀態,不做任何修改
// 讓服務器端負責狀態轉換,前端只負責顯示
console.log('📊 保持舊會話的原有狀態:', oldSession.status);
oldSession.completed_at = TimeUtils.getCurrentTimestamp();
// 計算持續時間
@ -589,23 +593,25 @@
};
/**
* 從伺服器載入會話歷史
* 從伺服器載入會話歷史包含實時狀態
*/
SessionDataManager.prototype.loadFromServer = function() {
const self = this;
fetch('/api/load-session-history')
// 首先嘗試獲取實時會話狀態
fetch('/api/all-sessions')
.then(function(response) {
if (response.ok) {
return response.json();
} else {
throw new Error('伺服器回應錯誤: ' + response.status);
throw new Error('獲取實時會話狀態失敗: ' + response.status);
}
})
.then(function(data) {
if (data && Array.isArray(data.sessions)) {
// 使用實時會話狀態
self.sessionHistory = data.sessions;
console.log('📊 從伺服器載入', self.sessionHistory.length, '個會話');
console.log('📊 從伺服器載入', self.sessionHistory.length, '個實時會話狀態');
// 載入完成後進行清理和統計更新
self.cleanupExpiredSessions();
@ -621,13 +627,53 @@
self.onDataChanged();
}
} else {
console.warn('📊 伺服器回應格式錯誤:', data);
self.sessionHistory = [];
console.warn('📊 實時會話狀態回應格式錯誤,回退到歷史文件');
self.loadFromHistoryFile();
}
})
.catch(function(error) {
console.warn('📊 獲取實時會話狀態失敗,回退到歷史文件:', error);
self.loadFromHistoryFile();
});
};
// 即使沒有資料也要更新統計
/**
* 從歷史文件載入會話數據備用方案
*/
SessionDataManager.prototype.loadFromHistoryFile = function() {
const self = this;
fetch('/api/load-session-history')
.then(function(response) {
if (response.ok) {
return response.json();
} else {
throw new Error('伺服器回應錯誤: ' + response.status);
}
})
.then(function(data) {
if (data && Array.isArray(data.sessions)) {
self.sessionHistory = data.sessions;
console.log('📊 從歷史文件載入', self.sessionHistory.length, '個會話');
// 載入完成後進行清理和統計更新
self.cleanupExpiredSessions();
self.updateStats();
// 觸發歷史記錄變更回調
if (self.onHistoryChange) {
self.onHistoryChange(self.sessionHistory);
}
// 觸發資料變更回調
if (self.onDataChanged) {
self.onDataChanged();
}
} else {
console.warn('📊 歷史文件回應格式錯誤:', data);
self.sessionHistory = [];
self.updateStats();
// 觸發歷史記錄變更回調(空列表)
if (self.onHistoryChange) {
self.onHistoryChange(self.sessionHistory);
}
@ -638,13 +684,10 @@
}
})
.catch(function(error) {
console.warn('📊 從伺服器載入會話歷史失敗:', error);
console.warn('📊 從歷史文件載入失敗:', error);
self.sessionHistory = [];
// 載入失敗時也要更新統計
self.updateStats();
// 觸發歷史記錄變更回調(空列表)
if (self.onHistoryChange) {
self.onHistoryChange(self.sessionHistory);
}

View File

@ -486,9 +486,18 @@
// 狀態徽章
const statusContainer = DOMUtils.createElement('div', { className: 'session-status' });
const statusText = StatusUtils.getStatusText(sessionData.status);
// 添加調試信息
console.log('🎨 會話狀態調試:', {
sessionId: sessionData.session_id ? sessionData.session_id.substring(0, 8) + '...' : 'unknown',
rawStatus: sessionData.status,
displayText: statusText
});
const statusBadge = DOMUtils.createElement('span', {
className: 'status-badge ' + (sessionData.status || 'waiting'),
textContent: StatusUtils.getStatusText(sessionData.status)
textContent: statusText
});
statusContainer.appendChild(statusBadge);

View File

@ -47,7 +47,7 @@
'waiting_for_feedback': 'connectionMonitor.waiting',
'active': 'status.processing.title',
'feedback_submitted': 'status.submitted.title',
'completed': 'status.submitted.title',
'completed': 'status.completed.title',
'timeout': 'session.timeout',
'error': 'status.error',
'expired': 'session.timeout',