Add files via upload

This commit is contained in:
公明
2026-04-28 10:23:24 +08:00
committed by GitHub
parent dfaf0bc77f
commit 47922c2083
8 changed files with 94 additions and 8 deletions
+13 -1
View File
@@ -8970,7 +8970,7 @@ header {
/* 任务管理 · 队列卡片:单行主网格 + 进度列内统计,降低高度 */
.batch-queue-item__inner--grid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(128px, auto) minmax(88px, 14%) 44px;
grid-template-columns: minmax(0, 1fr) minmax(128px, auto) minmax(88px, 14%) minmax(40px, max-content);
grid-template-rows: auto;
grid-template-areas: "lead cluster progress actions";
column-gap: 22px;
@@ -9051,6 +9051,12 @@ header {
justify-self: end;
align-self: center;
padding-left: 6px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
justify-content: flex-end;
gap: 6px;
}
.batch-queue-item__idline--lead {
@@ -9137,6 +9143,12 @@ header {
}
.batch-queue-icon-btn:hover {
color: var(--accent-color, #0066ff);
border-color: rgba(0, 102, 255, 0.35);
background: rgba(0, 102, 255, 0.08);
}
.batch-queue-icon-btn--danger:hover {
color: var(--error-color, #dc3545);
border-color: rgba(220, 53, 69, 0.35);
background: rgba(220, 53, 69, 0.06);
+3
View File
@@ -303,6 +303,8 @@
"clearHistory": "Clear history",
"cancelTask": "Cancel task",
"viewConversation": "View conversation",
"viewVulnerabilities": "View vulnerabilities",
"viewVulnerabilitiesQueueTitle": "View vulnerabilities: open management filtered to this queue",
"retryTask": "Retry",
"conversationIdLabel": "Conversation ID",
"statusPending": "Pending",
@@ -1702,6 +1704,7 @@
},
"contextMenu": {
"viewAttackChain": "View attack chain",
"viewVulnerabilities": "View vulnerabilities",
"downloadMarkdown": "Download Markdown",
"downloadMarkdownSummary": "Summary",
"downloadMarkdownFull": "Full",
+3
View File
@@ -303,6 +303,8 @@
"clearHistory": "清空历史",
"cancelTask": "取消任务",
"viewConversation": "查看对话",
"viewVulnerabilities": "查看漏洞",
"viewVulnerabilitiesQueueTitle": "查看漏洞:打开漏洞管理并筛选本队列",
"retryTask": "重试",
"conversationIdLabel": "对话ID",
"statusPending": "待执行",
@@ -1702,6 +1704,7 @@
},
"contextMenu": {
"viewAttackChain": "查看攻击链",
"viewVulnerabilities": "查看漏洞",
"downloadMarkdown": "下载 Markdown",
"downloadMarkdownSummary": "简版",
"downloadMarkdownFull": "完整版",
+11
View File
@@ -6121,6 +6121,17 @@ async function downloadConversationMarkdownFromContext(includeToolDetails = fals
closeContextMenu();
}
// 从上下文菜单跳转到漏洞管理,并按当前对话 ID 筛选
function navigateToVulnerabilitiesForContextConversation() {
const convId = contextMenuConversationId;
if (!convId) {
closeContextMenu();
return;
}
closeContextMenu();
window.location.hash = 'vulnerabilities?conversation_id=' + encodeURIComponent(convId);
}
// 从上下文菜单删除对话
function deleteConversationFromContext() {
const convId = contextMenuConversationId;
+5 -5
View File
@@ -1,19 +1,19 @@
// 页面路由管理
let currentPage = 'dashboard';
/** 仅当停留在 chat 时保留 ?conversation= 等查询串,其它页面只使用 pageId */
/** chat、漏洞管理页在切换时保留当前 hash 上的查询串(如 ?conversation= / ?conversation_id= */
function buildHashForPage(pageId) {
if (pageId !== 'chat') {
if (pageId !== 'chat' && pageId !== 'vulnerabilities') {
return pageId;
}
const full = window.location.hash.slice(1);
const parts = full.split('?');
const curPage = parts[0];
const q = parts.length > 1 ? parts.slice(1).join('?') : '';
if (curPage === 'chat' && q) {
return 'chat?' + q;
if (curPage === pageId && q) {
return pageId + '?' + q;
}
return 'chat';
return pageId;
}
let chatConversationFromHashSeq = 0;
+16 -2
View File
@@ -531,6 +531,7 @@ function renderTaskItem(task, statusMap, isHistory = false) {
${isHistory && completedText ? completedText : timeText}
</span>
${canCancel ? `<button class="btn-secondary btn-small" onclick="cancelTask('${task.conversationId}', this)">` + _t('tasks.cancelTask') + `</button>` : ''}
${task.conversationId ? `<button class="btn-secondary btn-small" onclick="navigateToVulnerabilitiesFromTasksPage('conversation', '${task.conversationId}')">` + _t('tasks.viewVulnerabilities') + `</button>` : ''}
${task.conversationId ? `<button class="btn-secondary btn-small" onclick="viewConversation('${task.conversationId}')">` + _t('tasks.viewConversation') + `</button>` : ''}
</div>
</div>
@@ -708,6 +709,17 @@ function viewConversation(conversationId) {
}
}
// 跳转漏洞管理并按对话 ID 或批量队列 ID 筛选(队列 ID 走 task_id,与列表筛选项一致)
function navigateToVulnerabilitiesFromTasksPage(kind, id) {
if (!id) return;
const enc = encodeURIComponent(id);
if (kind === 'queue') {
window.location.hash = 'vulnerabilities?task_id=' + enc;
} else if (kind === 'conversation') {
window.location.hash = 'vulnerabilities?conversation_id=' + enc;
}
}
// 刷新任务列表
async function refreshTasks() {
await loadTasks();
@@ -1134,6 +1146,8 @@ function renderBatchQueues() {
const progress = stats.total > 0 ? Math.round((stats.completed + stats.failed + stats.cancelled) / stats.total * 100) : 0;
// 允许删除待执行、已完成或已取消状态的队列
const canDelete = queue.status === 'pending' || queue.status === 'completed' || queue.status === 'cancelled';
// 操作列常驻「查看漏洞」,不再使用 --no-actions 隐藏整列(否则无法从运行中队列跳转漏洞页)
const noActionsClass = '';
const loadedRoles = batchQueuesState.loadedRoles || [];
const roleIcon = getRoleIconForDisplay(queue.role, loadedRoles);
@@ -1157,7 +1171,6 @@ function renderBatchQueues() {
: `<h4 class="batch-queue-card-title batch-queue-card-title--muted">${escapeHtml(_t('tasks.batchQueueUntitled'))}</h4>`;
const doneCount = stats.completed + stats.failed + stats.cancelled;
const noActionsClass = canDelete ? '' : ' batch-queue-item--no-actions';
return `
<div class="batch-queue-item batch-queue-item--compact${cardMod}${noActionsClass}" data-queue-id="${queue.id}" onclick="showBatchQueueDetail('${queue.id}')">
<div class="batch-queue-item__inner batch-queue-item__inner--grid">
@@ -1182,7 +1195,8 @@ function renderBatchQueues() {
</div>
</div>
<div class="batch-queue-item__actions-col" onclick="event.stopPropagation();">
${canDelete ? `<button type="button" class="batch-queue-icon-btn" onclick="deleteBatchQueueFromList('${queue.id}')" title="${escapeHtml(_t('tasks.deleteQueue'))}" aria-label="${escapeHtml(_t('tasks.deleteQueue'))}"><svg class="batch-queue-icon-btn__svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M10 11v6"/><path d="M14 11v6"/></svg></button>` : ''}
<button type="button" class="batch-queue-icon-btn" onclick="navigateToVulnerabilitiesFromTasksPage('queue', '${queue.id}')" title="${escapeHtml(_t('tasks.viewVulnerabilitiesQueueTitle'))}" aria-label="${escapeHtml(_t('tasks.viewVulnerabilitiesQueueTitle'))}"><svg class="batch-queue-icon-btn__svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 12l2 2 4-4"/></svg></button>
${canDelete ? `<button type="button" class="batch-queue-icon-btn batch-queue-icon-btn--danger" onclick="deleteBatchQueueFromList('${queue.id}')" title="${escapeHtml(_t('tasks.deleteQueue'))}" aria-label="${escapeHtml(_t('tasks.deleteQueue'))}"><svg class="batch-queue-icon-btn__svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M10 11v6"/><path d="M14 11v6"/></svg></button>` : ''}
</div>
</div>
</div>
+36
View File
@@ -61,10 +61,43 @@ let vulnerabilityPagination = {
totalPages: 1
};
// 从地址栏 #vulnerabilities?conversation_id= / ?task_id= 同步筛选(对话菜单、任务管理联动)
function syncVulnerabilityFiltersFromLocationHash() {
const hash = window.location.hash.slice(1);
const hashParts = hash.split('?');
if (hashParts[0] !== 'vulnerabilities' || hashParts.length < 2) {
return;
}
const params = new URLSearchParams(hashParts.slice(1).join('?'));
const cid = (params.get('conversation_id') || '').trim();
const tid = (params.get('task_id') || '').trim();
if (!cid && !tid) {
return;
}
vulnerabilityFilters.conversation_id = '';
vulnerabilityFilters.task_id = '';
const convEl = document.getElementById('vulnerability-conversation-filter');
const taskEl = document.getElementById('vulnerability-task-filter');
if (convEl) convEl.value = '';
if (taskEl) taskEl.value = '';
if (cid) {
vulnerabilityFilters.conversation_id = cid;
if (convEl) convEl.value = cid;
}
if (tid) {
vulnerabilityFilters.task_id = tid;
if (taskEl) taskEl.value = tid;
}
vulnerabilityPagination.currentPage = 1;
}
// 初始化漏洞管理页面
function initVulnerabilityPage() {
// 从localStorage加载每页条数设置
vulnerabilityPagination.pageSize = getVulnerabilityPageSize();
syncVulnerabilityFiltersFromLocationHash();
loadVulnerabilityStats();
loadVulnerabilities();
}
@@ -82,6 +115,9 @@ async function loadVulnerabilityStats() {
if (vulnerabilityFilters.conversation_id) {
params.append('conversation_id', vulnerabilityFilters.conversation_id);
}
if (vulnerabilityFilters.task_id) {
params.append('task_id', vulnerabilityFilters.task_id);
}
const response = await apiFetch(`/api/vulnerabilities/stats?${params.toString()}`);
if (!response.ok) {
+7
View File
@@ -2424,6 +2424,13 @@
</div>
</div>
</div>
<div class="context-menu-item" onclick="navigateToVulnerabilitiesForContextConversation()">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 12l2 2 4-4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span data-i18n="contextMenu.viewVulnerabilities">查看漏洞</span>
</div>
<div class="context-menu-divider"></div>
<div class="context-menu-item" onclick="renameConversation()">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">