You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
661 lines
25 KiB
661 lines
25 KiB
{% extends 'base.html' %}
|
|
|
|
{% block title %}ZFSAFE{% endblock %}
|
|
|
|
<!-- 在此处可添加样式文件 -->
|
|
{% block style_link %}
|
|
<link href="{{ url_for('main.static', filename='css/node_tree.css') }}" rel="stylesheet">
|
|
{% endblock %}
|
|
|
|
<!-- 页面样式块 -->
|
|
{% block style %}
|
|
|
|
/* 查询条件区域:使用 row 分布,输入框占满所在列 */
|
|
.search-section .form-control,
|
|
.search-section .form-select {
|
|
width: 100%;
|
|
}
|
|
/* 查询条件区域,每个条件统一高度且左右间隔均等 */
|
|
.search-section .col {
|
|
padding: 0 5px;
|
|
}
|
|
|
|
/* 表格样式:统一垂直居中 */
|
|
.table thead th, .table tbody td {
|
|
vertical-align: middle;
|
|
text-align: center;
|
|
}
|
|
|
|
/* 分页区域右对齐 */
|
|
.pagination-section {
|
|
text-align: right;
|
|
padding-right: 15px;
|
|
}
|
|
|
|
/* 固定行高,比如 45px,每页 10 行 */
|
|
.fixed-row-height {
|
|
height: 45px;
|
|
overflow: hidden;
|
|
}
|
|
/* 模态框内部最大高度,超出部分滚动 */
|
|
.modal-dialog {
|
|
max-height: calc(100vh+20px);
|
|
}
|
|
.modal-content {
|
|
max-height: calc(100vh+20px);
|
|
}
|
|
.modal-body {
|
|
overflow-y: auto;
|
|
}
|
|
/* 这里设置页码按钮样式(可根据需要调整) */
|
|
.pagination {
|
|
margin: 0;
|
|
}
|
|
.disabled-btn {
|
|
/* 禁用状态样式 */
|
|
background-color: #cccccc; /* 灰色背景 */
|
|
color: #666666; /* 文字颜色变浅 */
|
|
cursor: not-allowed; /* 鼠标显示禁用图标 */
|
|
opacity: 0.7; /* 可选:降低透明度 */
|
|
|
|
/* 禁用点击事件(通过 disabled 属性已实现,此样式仅增强视觉效果) */
|
|
pointer-events: none; /* 可选:彻底阻止鼠标事件 */
|
|
}
|
|
|
|
.offcanvas-backdrop.show {
|
|
z-index: 1055;
|
|
}
|
|
|
|
/* 再把 offcanvas 本身提到更高,超过 modal(modal 是 1055) */
|
|
.offcanvas.show {
|
|
z-index: 1060;
|
|
}
|
|
/* 让所有右侧 offcanvas-end 都变成 60% 宽 */
|
|
.offcanvas.offcanvas-end {
|
|
width: 60% !important;
|
|
max-width: none; /* 取消默认 max-width */
|
|
}
|
|
{% endblock %}
|
|
|
|
<!-- 页面内容块 -->
|
|
{% block content %}
|
|
|
|
<div class="container">
|
|
<!-- 查询条件区域 -->
|
|
<div class="search-section mb-3">
|
|
<form class="row g-3 align-items-center">
|
|
<!-- 每个输入框直接使用 placeholder 显示标题,水平分布 -->
|
|
<div class="col-3">
|
|
<input type="text" class="form-control" id="testTarget" name="target" placeholder="检测目标">
|
|
</div>
|
|
<div class="col-2">
|
|
<select class="form-select" id="riskLevel" name="risk_level">
|
|
<option value="">风险级别</option>
|
|
<option value="0">0</option>
|
|
<option value="1">1</option>
|
|
<option value="2">2</option>
|
|
<option value="3">3</option>
|
|
<option value="4">4</option>
|
|
<option value="5">5</option>
|
|
<option value="6">6</option>
|
|
<option value="7">7</option>
|
|
<option value="8">8</option>
|
|
<option value="9">9</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-2">
|
|
<select class="form-select" id="useModel" name="model">
|
|
<option value="">使用模型</option>
|
|
<option value="1">DeepSeek</option>
|
|
<option value="2">GPT-O3</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-2" >
|
|
<input type="date" id="startTime" class="form-control" name="start_time" placeholder="开始时间">
|
|
</div>
|
|
<div class="col-2">
|
|
<input type="date" id="endTime" class="form-control" name="end_time" placeholder="结束时间">
|
|
</div>
|
|
<div class="col-auto">
|
|
<button type="button" class="btn btn-primary" id="btnQuery">查询</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- 表格区域 -->
|
|
<div class="table-section mb-3">
|
|
<table class="table table-bordered table-hover" id="histasksTable" style="width: 100%; table-layout: fixed;">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th style="width: 60px;">ID</th>
|
|
<th style="width: 20%;">检测目标</th>
|
|
<th style="width: 15%;">开始时间</th>
|
|
<th style="width: 15%;">结束时间</th>
|
|
<th style="width: 15%;">风险等级</th>
|
|
<th style="width: 15%;">使用模型</th>
|
|
<th style="width: 100px;">操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="histasksTbody">
|
|
<!-- 数据由JS动态填充,固定10行一页 -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- 分页控件区域 -->
|
|
<div class="pagination-section mb-3">
|
|
<nav>
|
|
<ul class="pagination pagination-sm justify-content-end" id="histasksPagination">
|
|
<li class="page-item">
|
|
<a class="page-link" href="#" id="prevPage">上一页</a>
|
|
</li>
|
|
<!-- 页码动态生成 -->
|
|
<li class="page-item">
|
|
<a class="page-link" href="#" id="nextPage">下一页</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 模态框:显示 task_manager.html 中的中间 tab 页内容 -->
|
|
<!-- 这里只显示节点树、测试指令、漏洞数据三个 tab 页 -->
|
|
<div class="modal fade" id="viewModal" tabindex="-1" aria-labelledby="viewModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-xl">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="viewModalLabel">任务详情</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="关闭"></button>
|
|
</div>
|
|
<div class="modal-body p-0">
|
|
<!-- 这里仅嵌入中间 tab 页部分 -->
|
|
<div class="tab-wrapper">
|
|
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link active" id="nodeTreeTab" data-bs-toggle="tab" data-bs-target="#nodeTree" type="button" role="tab" aria-controls="nodeTree" aria-selected="true">
|
|
节点树
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="testInstructionsTab" data-bs-toggle="tab" data-bs-target="#testInstructions" type="button" role="tab" aria-controls="testInstructions" aria-selected="false">
|
|
测试指令
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="vulnerabilitiesTab" data-bs-toggle="tab" data-bs-target="#vulnerabilities" type="button" role="tab" aria-controls="vulnerabilities" aria-selected="false">
|
|
漏洞数据
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
<div class="tab-content" id="myTabContent">
|
|
<!-- 节点树 -->
|
|
<div class="tab-pane fade show active p-3 h-100" id="nodeTree" role="tabpanel" aria-labelledby="nodeTreeTab">
|
|
<div class="row h-100">
|
|
<!-- 左侧:节点树区域 -->
|
|
<div class="col-8 h-100">
|
|
<div class="node-tree-area" id="nodeTreeContainer" style="height: 100%; overflow-y: auto; position: relative; background-color: #f8f9fa;">
|
|
<!-- 固定刷新按钮 -->
|
|
<!-- <div class="refresh-container" style="position: absolute; top: 5px; left: 5px; z-index: 100;">-->
|
|
<!-- <button class="tree-refresh btn btn-primary btn-sm" id="btnRefresh" title="刷新节点树">↻</button>-->
|
|
<!-- </div>-->
|
|
<!-- 节点树内容 -->
|
|
<div id="treeContent" class="tree-content" style="padding-top: 40px;">
|
|
<p id="treeLoadingMsg" style="text-align:center;">加载中...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- 右侧:节点信息与操作 -->
|
|
<div class="col-4 h-100">
|
|
<div class="node-info-area mb-3" style="padding: 10px;">
|
|
<h5>节点信息</h5>
|
|
<p><strong>节点名称:</strong> <span id="nodeName">-</span></p>
|
|
<p><strong>测试状态:</strong> <span id="testStatus">-</span></p>
|
|
<p><strong>漏洞类型:</strong> <span id="node_vulType">-</span></p>
|
|
<p><strong>漏洞级别:</strong> <span id="node_vulLevel">-</span></p>
|
|
<p><strong>工作状态:</strong> <span id="node_bwork">-</span></p>
|
|
<p><strong>执行状态:</strong> <span id="node_workstatus">-</span></p>
|
|
</div>
|
|
<div class="node-actions" style="padding: 0 10px 10px;">
|
|
<div class="row mb-2">
|
|
<div class="col-12">
|
|
<button class="btn btn-primary w-100" id="btnViewInstr">查看指令</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- 测试指令 -->
|
|
<div class="tab-pane fade p-3" id="testInstructions" role="tabpanel" aria-labelledby="testInstructionsTab">
|
|
<div class="row search-area mb-2">
|
|
<div class="col-4">
|
|
<input type="text" class="form-control" id="instrNodeName" placeholder="节点名称">
|
|
</div>
|
|
<div class="col-2">
|
|
<button class="btn btn-primary" id="instrSearchBtn">查询</button>
|
|
<button class="btn btn-primary" id="instrExportBtn">导出</button>
|
|
</div>
|
|
</div>
|
|
<table class="table table-bordered table-hover" id="instrTable" style="width: 100%; table-layout: fixed;">
|
|
<colgroup>
|
|
<col style="width: 5%;">
|
|
<col style="width: 15%;">
|
|
<col style="width: 5%;">
|
|
<col style="width: 30%;" class="wrap-cell">
|
|
<col style="width: auto;">
|
|
</colgroup>
|
|
<thead>
|
|
<tr>
|
|
<th>序号</th>
|
|
<th>节点路径</th>
|
|
<th>指序</th>
|
|
<th>执行指令</th>
|
|
<th>执行结果</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- 默认显示10行 -->
|
|
</tbody>
|
|
</table>
|
|
<!-- 分页控件 -->
|
|
<nav>
|
|
<ul class="pagination" id="instrPagination">
|
|
<li class="page-item">
|
|
<a class="page-link" href="#" id="instrPrev">上一页</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="#" id="instrNext">下一页</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
<!-- 漏洞数据 -->
|
|
<div class="tab-pane fade p-3" id="vulnerabilities" role="tabpanel" aria-labelledby="vulnerabilitiesTab">
|
|
<div class="row search-area mb-2">
|
|
<div class="col-3">
|
|
<input type="text" class="form-control" id="vulNodeName" placeholder="节点名称">
|
|
</div>
|
|
<div class="col-3">
|
|
<input type="text" class="form-control" id="vulType" placeholder="漏洞类型">
|
|
</div>
|
|
<div class="col-3">
|
|
<select class="form-select" id="vulLevel">
|
|
<option value="">漏洞级别</option>
|
|
<option value="低危">低危</option>
|
|
<option value="中危">中危</option>
|
|
<option value="高危">高危</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-2">
|
|
<button class="btn btn-primary" id="vulSearchBtn">查询</button>
|
|
<button class="btn btn-primary" id="vulExportBtn">导出</button>
|
|
</div>
|
|
</div>
|
|
<table class="table table-bordered table-hover" id="vulTable">
|
|
<thead>
|
|
<tr>
|
|
<th class="seq-col">序号</th>
|
|
<th>节点路径</th>
|
|
<th>漏洞类型</th>
|
|
<th>漏洞级别</th>
|
|
<th>漏洞说明</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- 默认显示10行 -->
|
|
</tbody>
|
|
</table>
|
|
<!-- 分页控件 -->
|
|
<nav>
|
|
<ul class="pagination" id="vulPagination">
|
|
<li class="page-item">
|
|
<a class="page-link" href="#" id="vulPrev">上一页</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="#" id="vulNext">下一页</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- 模态框 footer -->
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 查看节点执行指令offcanvas --modal 改--->
|
|
<div class="offcanvas offcanvas-end" tabindex="-1" id="instrCanvas" aria-labelledby="instrCanvasLabel">
|
|
<div class="offcanvas-header">
|
|
<!-- 返回按钮 -->
|
|
<!-- <button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="offcanvas">-->
|
|
<!-- ←-->
|
|
<!-- </button>-->
|
|
<h5 class="offcanvas-title" id="instrOffcanvasLabel">测试指令</h5>
|
|
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
|
</div>
|
|
<div class="offcanvas-body">
|
|
<!-- 返回按钮 -->
|
|
<div class="mb-3">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="offcanvas">
|
|
← 返回
|
|
</button>
|
|
</div>
|
|
<!-- 新增一个提示容器 -->
|
|
<!-- <div id="loadingMsg" style="text-align: center; padding: 10px;">请稍后,数据获取中...</div>-->
|
|
<div id="loadingMsg" class="text-center mb-3">请稍后,数据获取中...</div>
|
|
<!-- 页签(已执行、待执行) -->
|
|
<ul class="nav nav-tabs" id="instrTab" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button
|
|
class="nav-link active"
|
|
id="doneInstrTab"
|
|
data-bs-toggle="tab"
|
|
data-bs-target="#doneInstr"
|
|
type="button"
|
|
role="tab"
|
|
aria-controls="doneInstr"
|
|
aria-selected="true"
|
|
>
|
|
已执行
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button
|
|
class="nav-link"
|
|
id="todoInstrTab"
|
|
data-bs-toggle="tab"
|
|
data-bs-target="#todoInstr"
|
|
type="button"
|
|
role="tab"
|
|
aria-controls="todoInstr"
|
|
aria-selected="false"
|
|
>
|
|
待执行
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
<div class="tab-content pt-3" id="instrTabContent">
|
|
<!-- 已执行指令表格 -->
|
|
<div
|
|
class="tab-pane fade show active"
|
|
id="doneInstr"
|
|
role="tabpanel"
|
|
aria-labelledby="doneInstrTab"
|
|
>
|
|
<table class="table table-bordered table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th style="width: 50px;">序号</th>
|
|
<th>执行指令</th>
|
|
<th>执行时间</th>
|
|
<th>执行结果</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="doneInstrTbody">
|
|
<!-- 动态生成,固定 10 行 -->
|
|
</tbody>
|
|
</table>
|
|
<!-- 分页控件 -->
|
|
<nav>
|
|
<ul class="pagination justify-content-end" id="doneInstrPagination">
|
|
<li class="page-item">
|
|
<a class="page-link" href="#" id="doneInstrPrev">上一页</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="#" id="doneInstrNext">下一页</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
<!-- 待执行指令表格 -->
|
|
<div
|
|
class="tab-pane fade"
|
|
id="todoInstr"
|
|
role="tabpanel"
|
|
aria-labelledby="todoInstrTab"
|
|
>
|
|
<table class="table table-bordered table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th style="width: 50px;">序号</th>
|
|
<th>待执行指令</th>
|
|
<th style="width: 80px;">操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="todoInstrTbody">
|
|
<!-- 动态生成,固定 10 行 -->
|
|
</tbody>
|
|
</table>
|
|
<!-- 分页控件 -->
|
|
<nav>
|
|
<ul class="pagination justify-content-end" id="todoInstrPagination">
|
|
<li class="page-item">
|
|
<a class="page-link" href="#" id="todoInstrPrev">上一页</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="#" id="todoInstrNext">下一页</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
<!-- 操作按钮 -->
|
|
<div class="mt-4 d-flex justify-content-end">
|
|
<button type="button" class="btn btn-primary" id="btnExport">导出</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock %}
|
|
|
|
<!-- 页面脚本块 -->
|
|
{% block script %}
|
|
<script src="{{ url_for('main.static', filename='scripts/task_modal.js') }}"></script>
|
|
<script>
|
|
// 全局变量
|
|
let cur_task_id = 0;
|
|
let allHistasks = [];
|
|
let currentPage = 1;
|
|
const pageSize = 10;
|
|
|
|
// 分页渲染函数
|
|
function renderHistasksTable(page) {
|
|
currentPage = page;
|
|
const tbody = document.getElementById("histasksTbody");
|
|
const startIndex = (page - 1) * pageSize;
|
|
const endIndex = startIndex + pageSize;
|
|
const pageData = allHistasks.slice(startIndex, endIndex);
|
|
//select ID,task_target,safe_rank,llm_type,start_time,end_time from task
|
|
tbody.innerHTML = "";
|
|
pageData.forEach((task, i) => {
|
|
const tr = document.createElement("tr");
|
|
// 每个单元格创建时使用 textContent,确保固定行高,如有需要也可增加 class "fixed-row-height"
|
|
const tdId = document.createElement("td");
|
|
tdId.textContent = task[0];
|
|
tr.appendChild(tdId);
|
|
|
|
const tdTarget = document.createElement("td");
|
|
tdTarget.textContent = task[1];
|
|
tr.appendChild(tdTarget);
|
|
|
|
const tdStart = document.createElement("td");
|
|
tdStart.textContent = task[4] || "";
|
|
tr.appendChild(tdStart);
|
|
|
|
const tdEnd = document.createElement("td");
|
|
tdEnd.textContent = task[5] || "";
|
|
tr.appendChild(tdEnd);
|
|
|
|
const tdRisk = document.createElement("td");
|
|
tdRisk.textContent = (task[2] === 0) ? "安全" : "存在风险";
|
|
tr.appendChild(tdRisk);
|
|
|
|
const tdModel = document.createElement("td");
|
|
model_test = ""
|
|
if(task[3]===1){
|
|
model_test="DeepSeek";
|
|
}
|
|
else if(task[3]===2){
|
|
model_test="GPT-O3";
|
|
}
|
|
else{
|
|
model_test="其他模型";
|
|
}
|
|
tdModel.textContent = model_test;
|
|
tr.appendChild(tdModel);
|
|
|
|
const tdAction = document.createElement("td");
|
|
// 查看按钮(点击后弹出 modal)
|
|
const btnView = document.createElement("button");
|
|
btnView.className = "btn btn-outline-info btn-sm";
|
|
btnView.textContent = "查看";
|
|
btnView.onclick = () => openViewModal(task[0]);
|
|
tdAction.appendChild(btnView);
|
|
// 删除按钮(示例)
|
|
const btnDel = document.createElement("button");
|
|
btnDel.className = "btn btn-outline-danger btn-sm ms-1";
|
|
btnDel.textContent = "删除";
|
|
btnDel.onclick = () => confirmDeleteTask(task[0]);
|
|
tdAction.appendChild(btnDel);
|
|
|
|
tr.appendChild(tdAction);
|
|
tbody.appendChild(tr);
|
|
});
|
|
|
|
// 补空行
|
|
for (let i = pageData.length; i < pageSize; i++) {
|
|
const tr = document.createElement("tr");
|
|
for (let j = 0; j < 7; j++) {
|
|
const td = document.createElement("td");
|
|
td.textContent = "\u00A0";
|
|
tr.appendChild(td);
|
|
}
|
|
tbody.appendChild(tr);
|
|
}
|
|
updatePagination();
|
|
}
|
|
|
|
// 更新分页按钮
|
|
function updatePagination() {
|
|
const totalPages = Math.ceil(allHistasks.length / pageSize);
|
|
document.getElementById("prevPage").dataset.page = currentPage > 1 ? currentPage - 1 : 1;
|
|
document.getElementById("nextPage").dataset.page = currentPage < totalPages ? currentPage + 1 : totalPages;
|
|
}
|
|
|
|
// 分页按钮点击事件
|
|
document.getElementById("prevPage").addEventListener("click", function(e) {
|
|
e.preventDefault();
|
|
const page = parseInt(this.dataset.page, 10);
|
|
renderHistasksTable(page);
|
|
});
|
|
document.getElementById("nextPage").addEventListener("click", function(e) {
|
|
e.preventDefault();
|
|
const page = parseInt(this.dataset.page, 10);
|
|
renderHistasksTable(page);
|
|
});
|
|
|
|
// 查询按钮事件,调用 /api/task/histasks 接口获取数据(示例)
|
|
document.getElementById("btnQuery").addEventListener("click", async function() {
|
|
// 此处可拼接获取表单数据条件,示例直接调用接口
|
|
/*
|
|
target_name = data.get("target_name")
|
|
safe_rank = data.get("safe_rank")
|
|
llm_type = data.get("llm_type")
|
|
start_time= data.get("start_time")
|
|
end_time= data.get("end_time")
|
|
* */
|
|
const target_name = document.getElementById("testTarget").value.trim();
|
|
const safe_rank = document.getElementById("riskLevel").value;
|
|
const llm_type = document.getElementById("useModel").value;
|
|
const start_time = document.getElementById("startTime").value;
|
|
const end_time = document.getElementById("endTime").value;
|
|
|
|
try {
|
|
const res = await fetch("/api/task/histasks", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({target_name,safe_rank,llm_type,start_time,end_time})
|
|
});
|
|
if (!res.ok) {
|
|
const errorData = await res.json();
|
|
throw new Error(errorData.error || `HTTP错误 ${res.status}`);
|
|
}
|
|
const data = await res.json();
|
|
allHistasks = data.his_tasks || [];
|
|
renderHistasksTable(1);
|
|
} catch (error) {
|
|
console.error("查询任务记录出错:", error);
|
|
alert("查询失败!");
|
|
}
|
|
});
|
|
|
|
// “查看详情”按钮事件(统一使用模态框显示 task_manager.html)
|
|
async function openViewModal(task_id) {
|
|
cur_task_id = task_id;
|
|
const viewModal = new bootstrap.Modal(document.getElementById("viewModal"), { keyboard: false });
|
|
viewModal.show();
|
|
//查询节点树数据
|
|
loadNodeTree(task_id);
|
|
//查询指令数据
|
|
searchInstructions(1);
|
|
//查询漏洞数据
|
|
searchVulnerabilities(1);
|
|
}
|
|
|
|
// 删除任务的示例函数
|
|
async function confirmDeleteTask(task_id) {
|
|
if (confirm("确认删除任务 " + task_id + " 吗?")) {
|
|
// 发送删除请求...
|
|
try {
|
|
const res = await fetch("/api/task/deltask", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({task_id}),
|
|
});
|
|
if (!res.ok) {
|
|
const errorData = await res.json();
|
|
throw new Error(errorData.error || `HTTP错误 ${res.status}`);
|
|
}
|
|
const data = await res.json();
|
|
bsuccess = data.bsuccess;
|
|
if(bsuccess){
|
|
// 1. 从前端缓存里删除这条任务
|
|
allHistasks = allHistasks.filter(t => t[0] !== task_id);
|
|
|
|
// 2. 重新渲染当前页
|
|
// 注意:如果删除后当前页已经没有任何数据了,可以让 currentPage--
|
|
const totalPages = Math.ceil(allHistasks.length / pageSize) || 1;
|
|
if (currentPage > totalPages) {
|
|
currentPage = totalPages;
|
|
}
|
|
renderHistasksTable(currentPage);
|
|
|
|
// (可选)如果你想做局部删除,而不重画整表,也可以直接:
|
|
// btnEl.closest("tr").remove();
|
|
alert("删除成功")
|
|
}
|
|
else{
|
|
alert("删除失败:",data.error)
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
console.error("删除任务数据异常:", error);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 页面加载时可以自动调用查询接口加载数据
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
// 可自动加载数据,或者等待用户点击查询
|
|
document.getElementById("btnQuery").click();
|
|
//renderHistasksTable(1);
|
|
});
|
|
</script>
|
|
|
|
{% endblock %}
|