Add files via upload

This commit is contained in:
公明
2026-03-09 23:00:24 +08:00
committed by GitHub
parent 2fce15f82a
commit 71f6a97a90
5 changed files with 54 additions and 21 deletions

View File

@@ -158,7 +158,10 @@
"searching": "Searching...",
"loadFailedRetry": "Load failed, please retry",
"dataFormatError": "Data format error",
"progressInProgress": "Penetration test in progress..."
"progressInProgress": "Penetration test in progress...",
"executionFailed": "Execution failed",
"penetrationTestComplete": "Penetration test complete",
"yesterday": "Yesterday"
},
"progress": {
"callingAI": "Calling AI model...",
@@ -200,6 +203,10 @@
"unknownTime": "Unknown time",
"clearHistoryConfirm": "Clear all task history?",
"cancelTaskFailed": "Cancel task failed",
"cancelFailed": "Cancel failed",
"taskInfoNotSynced": "Task info not synced yet, please try again later.",
"loadActiveTasksFailed": "Failed to load active tasks",
"cannotGetTaskStatus": "Cannot get task status",
"copiedToast": "Copied!",
"cancelling": "Cancelling...",
"enterTaskPrompt": "Enter at least one task",

View File

@@ -158,7 +158,10 @@
"searching": "搜索中...",
"loadFailedRetry": "加载失败,请重试",
"dataFormatError": "数据格式错误",
"progressInProgress": "渗透测试进行中..."
"progressInProgress": "渗透测试进行中...",
"executionFailed": "执行失败",
"penetrationTestComplete": "渗透测试完成",
"yesterday": "昨天"
},
"progress": {
"callingAI": "正在调用AI模型...",
@@ -200,6 +203,10 @@
"unknownTime": "未知时间",
"clearHistoryConfirm": "确定要清空所有任务历史记录吗?",
"cancelTaskFailed": "取消任务失败",
"cancelFailed": "取消失败",
"taskInfoNotSynced": "任务信息尚未同步,请稍后再试。",
"loadActiveTasksFailed": "获取活跃任务失败",
"cannotGetTaskStatus": "无法获取任务状态",
"copiedToast": "已复制!",
"cancelling": "取消中...",
"enterTaskPrompt": "请输入至少一个任务",

View File

@@ -1188,7 +1188,8 @@ function addMessage(role, content, mcpExecutionIds = null, progressId = null, cr
} else {
messageTime = new Date();
}
timeDiv.textContent = messageTime.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
const msgTimeLocale = (typeof window.__locale === 'string' && window.__locale.startsWith('zh')) ? 'zh-CN' : 'en-US';
timeDiv.textContent = messageTime.toLocaleTimeString(msgTimeLocale, { hour: '2-digit', minute: '2-digit' });
contentWrapper.appendChild(timeDiv);
// 如果有MCP执行ID或进度ID添加查看详情区域统一使用"渗透测试详情"样式)
@@ -1433,6 +1434,8 @@ function renderProcessDetails(messageId, processDetails) {
itemTitle = '❌ ' + (typeof window.t === 'function' ? window.t('chat.error') : '错误');
} else if (eventType === 'cancelled') {
itemTitle = '⛔ ' + (typeof window.t === 'function' ? window.t('chat.taskCancelled') : '任务已取消');
} else if (eventType === 'progress') {
itemTitle = typeof window.translateProgressMessage === 'function' ? window.translateProgressMessage(detail.message || '') : (detail.message || '');
}
addTimelineItem(timeline, eventType, {
@@ -1533,8 +1536,9 @@ async function showMCPDetail(executionId) {
const normalizedStatus = (exec.status || 'unknown').toLowerCase();
statusEl.textContent = getStatusText(exec.status);
statusEl.className = `status-chip status-${normalizedStatus}`;
const detailTimeLocale = (typeof window.__locale === 'string' && window.__locale.startsWith('zh')) ? 'zh-CN' : 'en-US';
document.getElementById('detail-time').textContent = exec.startTime
? new Date(exec.startTime).toLocaleString('zh-CN')
? new Date(exec.startTime).toLocaleString(detailTimeLocale)
: '—';
// 请求参数
@@ -1950,28 +1954,30 @@ function formatConversationTimestamp(dateObj, todayStart, yesterdayStart) {
const referenceToday = todayStart || new Date(now.getFullYear(), now.getMonth(), now.getDate());
const referenceYesterday = yesterdayStart || new Date(referenceToday.getTime() - 24 * 60 * 60 * 1000);
const messageDate = new Date(dateObj.getFullYear(), dateObj.getMonth(), dateObj.getDate());
const fmtLocale = (typeof window.__locale === 'string' && window.__locale.startsWith('zh')) ? 'zh-CN' : 'en-US';
const yesterdayLabel = typeof window.t === 'function' ? window.t('chat.yesterday') : '昨天';
if (messageDate.getTime() === referenceToday.getTime()) {
return dateObj.toLocaleTimeString('zh-CN', {
return dateObj.toLocaleTimeString(fmtLocale, {
hour: '2-digit',
minute: '2-digit'
});
}
if (messageDate.getTime() === referenceYesterday.getTime()) {
return '昨天 ' + dateObj.toLocaleTimeString('zh-CN', {
return yesterdayLabel + ' ' + dateObj.toLocaleTimeString(fmtLocale, {
hour: '2-digit',
minute: '2-digit'
});
}
if (dateObj.getFullYear() === referenceToday.getFullYear()) {
return dateObj.toLocaleString('zh-CN', {
return dateObj.toLocaleString(fmtLocale, {
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
return dateObj.toLocaleString('zh-CN', {
return dateObj.toLocaleString(fmtLocale, {
year: 'numeric',
month: 'short',
day: 'numeric',
@@ -5663,7 +5669,8 @@ async function loadGroupConversations(groupId, searchQuery = '') {
const timeWrapper = document.createElement('div');
timeWrapper.className = 'group-conversation-time';
const dateObj = fullConv.updatedAt ? new Date(fullConv.updatedAt) : new Date();
timeWrapper.textContent = dateObj.toLocaleString('zh-CN', {
const convListLocale = (typeof window.__locale === 'string' && window.__locale.startsWith('zh')) ? 'zh-CN' : 'en-US';
timeWrapper.textContent = dateObj.toLocaleString(convListLocale, {
year: 'numeric',
month: 'long',
day: 'numeric',

View File

@@ -148,6 +148,9 @@
}
applyTranslations(document);
updateLangLabel();
try {
window.__locale = lang;
} catch (e) { /* ignore */ }
try {
document.dispatchEvent(new CustomEvent('languagechange', { detail: { lang: lang } }));
} catch (e) { /* ignore */ }
@@ -170,6 +173,9 @@
await loadLanguageResources(initialLang);
applyTranslations(document);
updateLangLabel();
try {
window.__locale = i18next.language || initialLang;
} catch (e) { /* ignore */ }
// 导出全局函数供其他脚本调用(支持插值参数,如 _t('key', { count: 2 })
window.t = function (key, opts) {

View File

@@ -23,6 +23,9 @@ function translateProgressMessage(message) {
}
return message;
}
if (typeof window !== 'undefined') {
window.translateProgressMessage = translateProgressMessage;
}
// 存储工具调用ID到DOM元素的映射用于更新执行状态
const toolCallStatusMap = new Map();
@@ -101,7 +104,7 @@ async function requestCancel(conversationId) {
});
const result = await response.json().catch(() => ({}));
if (!response.ok) {
throw new Error(result.error || '取消失败');
throw new Error(result.error || (typeof window.t === 'function' ? window.t('tasks.cancelFailed') : '取消失败'));
}
return result;
}
@@ -186,7 +189,7 @@ function collapseAllProgressDetails(assistantMessageId, progressId) {
if (timeline) {
timeline.classList.remove('expanded');
if (toggleBtn) {
toggleBtn.textContent = '展开详情';
toggleBtn.textContent = typeof window.t === 'function' ? window.t('chat.expandDetail') : '展开详情';
}
}
});
@@ -198,7 +201,7 @@ function collapseAllProgressDetails(assistantMessageId, progressId) {
if (progressTimeline) {
progressTimeline.classList.remove('expanded');
if (progressToggleBtn) {
progressToggleBtn.textContent = '展开详情';
progressToggleBtn.textContent = typeof window.t === 'function' ? window.t('chat.expandDetail') : '展开详情';
}
}
}
@@ -347,7 +350,7 @@ async function cancelProgressTask(progressId) {
stopBtn.disabled = false;
}, 1500);
}
alert('任务信息尚未同步,请稍后再试。');
alert(typeof window.t === 'function' ? window.t('tasks.taskInfoNotSynced') : '任务信息尚未同步,请稍后再试。');
return;
}
@@ -358,7 +361,7 @@ async function cancelProgressTask(progressId) {
markProgressCancelling(progressId);
if (stopBtn) {
stopBtn.disabled = true;
stopBtn.textContent = '取消中...';
stopBtn.textContent = typeof window.t === 'function' ? window.t('tasks.cancelling') : '取消中...';
}
try {
@@ -686,7 +689,7 @@ function handleStreamEvent(event, progressElement, progressId,
case 'error':
// 显示错误
addTimelineItem(timeline, 'error', {
title: '❌ 错误',
title: '❌ ' + (typeof window.t === 'function' ? window.t('chat.error') : '错误'),
message: event.message,
data: event.data
});
@@ -694,7 +697,7 @@ function handleStreamEvent(event, progressElement, progressId,
// 更新进度标题为错误状态
const errorTitle = document.querySelector(`#${progressId} .progress-title`);
if (errorTitle) {
errorTitle.textContent = '❌ 执行失败';
errorTitle.textContent = '❌ ' + (typeof window.t === 'function' ? window.t('chat.executionFailed') : '执行失败');
}
// 更新进度容器为已完成状态添加completed类
@@ -759,7 +762,7 @@ function handleStreamEvent(event, progressElement, progressId,
// 完成,更新进度标题(如果进度消息还存在)
const doneTitle = document.querySelector(`#${progressId} .progress-title`);
if (doneTitle) {
doneTitle.textContent = '✅ 渗透测试完成';
doneTitle.textContent = '✅ ' + (typeof window.t === 'function' ? window.t('chat.penetrationTestComplete') : '渗透测试完成');
}
// 更新对话ID
if (event.data && event.data.conversationId) {
@@ -872,7 +875,8 @@ function addTimelineItem(timeline, type, options) {
eventTime = new Date();
}
const time = eventTime.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
const timeLocale = (typeof window.__locale === 'string' && window.__locale.startsWith('zh')) ? 'zh-CN' : 'en-US';
const time = eventTime.toLocaleTimeString(timeLocale, { hour: '2-digit', minute: '2-digit', second: '2-digit' });
let content = `
<div class="timeline-item-header">
@@ -945,7 +949,7 @@ async function loadActiveTasks(showErrors = false) {
const result = await response.json().catch(() => ({}));
if (!response.ok) {
throw new Error(result.error || '获取活跃任务失败');
throw new Error(result.error || (typeof window.t === 'function' ? window.t('tasks.loadActiveTasksFailed') : '获取活跃任务失败'));
}
renderActiveTasks(result.tasks || []);
@@ -953,7 +957,8 @@ async function loadActiveTasks(showErrors = false) {
console.error('获取活跃任务失败:', error);
if (showErrors && bar) {
bar.style.display = 'block';
bar.innerHTML = `<div class="active-task-error">无法获取任务状态:${escapeHtml(error.message)}</div>`;
const cannotGetStatus = typeof window.t === 'function' ? window.t('tasks.cannotGetTaskStatus') : '无法获取任务状态:';
bar.innerHTML = `<div class="active-task-error">${escapeHtml(cannotGetStatus)}${escapeHtml(error.message)}</div>`;
}
}
}
@@ -982,8 +987,9 @@ function renderActiveTasks(tasks) {
item.className = 'active-task-item';
const startedTime = task.startedAt ? new Date(task.startedAt) : null;
const taskTimeLocale = (typeof window.__locale === 'string' && window.__locale.startsWith('zh')) ? 'zh-CN' : 'en-US';
const timeText = startedTime && !isNaN(startedTime.getTime())
? startedTime.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', second: '2-digit' })
? startedTime.toLocaleTimeString(taskTimeLocale, { hour: '2-digit', minute: '2-digit', second: '2-digit' })
: '';
const _t = function (k) { return typeof window.t === 'function' ? window.t(k) : k; };