mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-05-17 13:43:31 +02:00
Add files via upload
This commit is contained in:
+28
-3
@@ -857,10 +857,35 @@
|
||||
background: var(--c2-surface);
|
||||
border-radius: var(--c2-radius);
|
||||
border: 1px solid var(--c2-border);
|
||||
overflow: hidden;
|
||||
overflow-x: auto;
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
.c2-task-table { width: 100%; border-collapse: collapse; }
|
||||
/* 操作列:仅占按钮宽度,避免 100% 表格把余白摊到最右列 */
|
||||
.c2-task-table th.c2-task-table-col-actions,
|
||||
.c2-task-table td.c2-task-table-col-actions {
|
||||
width: 1%;
|
||||
white-space: nowrap;
|
||||
text-align: right;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.c2-task-table-actions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 6px;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.c2-task-table-actions .btn-small,
|
||||
.c2-task-table-actions .btn-sm {
|
||||
min-height: 30px;
|
||||
min-width: 52px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.c2-task-table { width: 100%; border-collapse: collapse; table-layout: auto; }
|
||||
|
||||
.c2-task-table th {
|
||||
text-align: left;
|
||||
@@ -1261,7 +1286,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
z-index: 10050;
|
||||
padding: 24px;
|
||||
animation: c2-fade-in 0.15s ease-out;
|
||||
}
|
||||
|
||||
@@ -6209,7 +6209,9 @@ header {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.btn-small {
|
||||
/* btn-sm 与 btn-small 等价(C2 / WebShell 等模块使用 btn-sm 别名) */
|
||||
.btn-small,
|
||||
.btn-sm {
|
||||
padding: 6px 14px;
|
||||
font-size: 0.8125rem;
|
||||
border-radius: 6px;
|
||||
@@ -6222,7 +6224,23 @@ header {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn-small:hover {
|
||||
/* 小号按钮统一尺寸,避免 .btn-danger 默认大 padding 导致同行按钮高低不齐 */
|
||||
.btn-primary.btn-small,
|
||||
.btn-primary.btn-sm,
|
||||
.btn-secondary.btn-small,
|
||||
.btn-secondary.btn-sm,
|
||||
.btn-danger.btn-small,
|
||||
.btn-danger.btn-sm,
|
||||
.btn-ghost.btn-small,
|
||||
.btn-ghost.btn-sm {
|
||||
padding: 6px 14px;
|
||||
font-size: 0.8125rem;
|
||||
border-radius: 6px;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.btn-small:hover,
|
||||
.btn-sm:hover {
|
||||
background: var(--bg-tertiary);
|
||||
border-color: var(--accent-color);
|
||||
color: var(--accent-color);
|
||||
@@ -6230,13 +6248,19 @@ header {
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.btn-small.btn-danger {
|
||||
.btn-small.btn-danger,
|
||||
.btn-sm.btn-danger,
|
||||
.btn-danger.btn-small,
|
||||
.btn-danger.btn-sm {
|
||||
background: rgba(220, 53, 69, 0.08);
|
||||
border-color: rgba(220, 53, 69, 0.3);
|
||||
color: var(--error-color);
|
||||
}
|
||||
|
||||
.btn-small.btn-danger:hover {
|
||||
.btn-small.btn-danger:hover,
|
||||
.btn-sm.btn-danger:hover,
|
||||
.btn-danger.btn-small:hover,
|
||||
.btn-danger.btn-sm:hover {
|
||||
background: rgba(220, 53, 69, 0.15);
|
||||
border-color: var(--error-color);
|
||||
color: #c82333;
|
||||
|
||||
+48
-20
@@ -151,6 +151,25 @@
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
/** 任务列表操作按钮(查看/取消/删除)— 事件委托 */
|
||||
function bindC2TaskActionDelegation() {
|
||||
if (document.documentElement.dataset.c2TaskActionsBound === '1') return;
|
||||
document.documentElement.dataset.c2TaskActionsBound = '1';
|
||||
document.addEventListener('click', function(e) {
|
||||
const btn = e.target.closest('[data-c2-task-action]');
|
||||
if (!btn) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const action = btn.getAttribute('data-c2-task-action');
|
||||
const id = btn.getAttribute('data-task-id');
|
||||
if (!id) return;
|
||||
if (action === 'view') C2.viewTask(id);
|
||||
else if (action === 'cancel') C2.cancelTask(id);
|
||||
else if (action === 'delete') C2.deleteTaskById(id);
|
||||
});
|
||||
}
|
||||
bindC2TaskActionDelegation();
|
||||
|
||||
/** 监听器表单:Malleable Profile 下拉选项 HTML(value / 文本已转义) */
|
||||
function listenerProfileSelectHtml(selectedProfileId) {
|
||||
const sel = selectedProfileId ? String(selectedProfileId) : '';
|
||||
@@ -1293,14 +1312,17 @@
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = tasks.map(t => `
|
||||
container.innerHTML = tasks.map(t => {
|
||||
const rawId = t.id || '';
|
||||
return `
|
||||
<div class="c2-task-item-compact">
|
||||
<span class="c2-task-status-dot ${t.status}"></span>
|
||||
<span class="c2-task-type">${t.taskType}</span>
|
||||
<span class="c2-task-status-dot ${escapeHtml(t.status || '')}"></span>
|
||||
<span class="c2-task-type">${escapeHtml(t.taskType || '')}</span>
|
||||
<span class="c2-task-meta">${escapeHtml(taskStatusLabel(t.status))} | ${formatDuration(t.durationMs)}</span>
|
||||
<button class="btn-ghost btn-sm" onclick="C2.viewTask('${t.id}')">${escapeHtml(c2t('c2.tasks.view'))}</button>
|
||||
<button type="button" class="btn-secondary btn-small" data-c2-task-action="view" data-task-id="${escapeHtml(rawId)}">${escapeHtml(c2t('c2.tasks.view'))}</button>
|
||||
</div>
|
||||
`).join('');
|
||||
`;
|
||||
}).join('');
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1334,13 +1356,12 @@
|
||||
<th>${escapeHtml(c2t('c2.tasks.colStatus'))}</th>
|
||||
<th>${escapeHtml(c2t('c2.tasks.colDuration'))}</th>
|
||||
<th>${escapeHtml(c2t('c2.tasks.colCreated'))}</th>
|
||||
<th>${escapeHtml(c2t('c2.tasks.colActions'))}</th>
|
||||
<th class="c2-task-table-col-actions">${escapeHtml(c2t('c2.tasks.colActions'))}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${C2.tasks.map(t => {
|
||||
const rawId = t.id || '';
|
||||
const idJson = JSON.stringify(rawId);
|
||||
const shortTaskId = rawId.length > 14 ? escapeHtml(rawId.substring(0, 12)) + '\u2026' : escapeHtml(rawId);
|
||||
const sid = t.sessionId ? escapeHtml(String(t.sessionId).substring(0, 8)) + '\u2026' : '-';
|
||||
return `
|
||||
@@ -1356,12 +1377,14 @@
|
||||
<td><span class="c2-status-badge ${escapeHtml(t.status || '')}">${escapeHtml(taskStatusLabel(t.status))}</span></td>
|
||||
<td>${formatDuration(t.durationMs)}</td>
|
||||
<td>${formatTime(t.createdAt)}</td>
|
||||
<td>
|
||||
<button type="button" class="btn-ghost btn-sm" onclick="C2.viewTask(${idJson})">${escapeHtml(c2t('c2.tasks.view'))}</button>
|
||||
<td class="c2-task-table-col-actions">
|
||||
<div class="c2-task-table-actions">
|
||||
<button type="button" class="btn-secondary btn-small" data-c2-task-action="view" data-task-id="${escapeHtml(rawId)}">${escapeHtml(c2t('c2.tasks.view'))}</button>
|
||||
${t.status === 'queued' || t.status === 'sent'
|
||||
? `<button type="button" class="btn-danger btn-sm" onclick="C2.cancelTask(${idJson})">${escapeHtml(c2t('c2.tasks.cancelBtn'))}</button>`
|
||||
? `<button type="button" class="btn-danger btn-small" data-c2-task-action="cancel" data-task-id="${escapeHtml(rawId)}">${escapeHtml(c2t('c2.tasks.cancelBtn'))}</button>`
|
||||
: ''}
|
||||
<button type="button" class="btn-secondary btn-sm c2-task-row-delete" onclick="C2.deleteTaskById(${idJson})" title="${delTitle}" aria-label="${delTitle}">${escapeHtml(c2t('c2.tasks.deleteBtn'))}</button>
|
||||
<button type="button" class="btn-danger btn-small" data-c2-task-action="delete" data-task-id="${escapeHtml(rawId)}" title="${delTitle}" aria-label="${delTitle}">${escapeHtml(c2t('c2.tasks.deleteBtn'))}</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
@@ -1387,10 +1410,10 @@
|
||||
</div>
|
||||
<div class="c2-modal-body">
|
||||
<div class="c2-task-detail">
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelId'))}:</strong> ${t.id}</div>
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelSession'))}:</strong> ${t.sessionId}</div>
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelType'))}:</strong> ${t.taskType}</div>
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelStatus'))}:</strong> <span class="c2-status-badge ${t.status}">${escapeHtml(taskStatusLabel(t.status))}</span></div>
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelId'))}:</strong> ${escapeHtml(t.id || '')}</div>
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelSession'))}:</strong> ${escapeHtml(t.sessionId || '')}</div>
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelType'))}:</strong> ${escapeHtml(t.taskType || '')}</div>
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelStatus'))}:</strong> <span class="c2-status-badge ${escapeHtml(t.status || '')}">${escapeHtml(taskStatusLabel(t.status))}</span></div>
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelCreated'))}:</strong> ${formatTime(t.createdAt)}</div>
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelSent'))}:</strong> ${formatTime(t.sentAt)}</div>
|
||||
<div><strong>${escapeHtml(c2t('c2.tasks.labelCompleted'))}:</strong> ${formatTime(t.completedAt)}</div>
|
||||
@@ -1416,19 +1439,24 @@
|
||||
renderTaskModal(local);
|
||||
return;
|
||||
}
|
||||
apiRequest('GET', `${API_BASE}/tasks/${id}`).then(data => {
|
||||
apiRequest('GET', `${API_BASE}/tasks/${encodeURIComponent(id)}`).then(data => {
|
||||
if (data.error) {
|
||||
showToast(String(data.error), 'error');
|
||||
return;
|
||||
}
|
||||
if (data.task) renderTaskModal(data.task);
|
||||
});
|
||||
else showToast(c2t('c2.tasks.emptyAll'), 'warn');
|
||||
}).catch(err => showToast(err.message || String(err), 'error'));
|
||||
};
|
||||
|
||||
C2.cancelTask = function(id) {
|
||||
apiRequest('POST', `${API_BASE}/tasks/${id}/cancel`, {}).then(data => {
|
||||
if (data.error) showToast(data.error, 'error');
|
||||
apiRequest('POST', `${API_BASE}/tasks/${encodeURIComponent(id)}/cancel`, {}).then(data => {
|
||||
if (data.error) showToast(String(data.error), 'error');
|
||||
else {
|
||||
showToast(c2t('c2.tasks.toastCancelled'), 'success');
|
||||
C2.loadTasks(C2.tasksPage || 1);
|
||||
}
|
||||
});
|
||||
}).catch(err => showToast(err.message || String(err), 'error'));
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user