Browse Source
a.增加了批量添加目标,重新调整了任务的启停; b.增加了数据过滤功能,过滤提交到llm的目标信息; c.增加了对通以qwen3模型的对接; d.https有短数据包不及时发送到前端的问题,暂时调回http; e.其他的一些bug和工具迭代。master
1 changed files with 659 additions and 0 deletions
@ -0,0 +1,659 @@ |
|||
// 全局变量,用于保存当前选中的节点数据
|
|||
let selectedNodeData = null; |
|||
|
|||
/** |
|||
* 根据节点数据递归生成树形结构(返回 <li> 元素) |
|||
* 假设节点数据格式: |
|||
* { |
|||
* "node_name":node.name, |
|||
* "node_path":node.path, |
|||
* "node_status":node.status, |
|||
* "node_bwork":node.bwork, |
|||
* "node_vultype":node.vul_type, |
|||
* "node_vulgrade":node.vul_grade, |
|||
* children: [ { ... }, { ... } ] |
|||
* } |
|||
*/ |
|||
function generateTreeHTML(nodeData) { |
|||
const li = document.createElement("li"); |
|||
const nodeSpan = document.createElement("span"); |
|||
nodeSpan.className = "tree-node"; |
|||
//设置data属性
|
|||
nodeSpan.setAttribute("data-node_name", nodeData.node_name); |
|||
nodeSpan.setAttribute("data-node_path", nodeData.node_path); |
|||
nodeSpan.setAttribute("data-node_status", nodeData.node_status); |
|||
nodeSpan.setAttribute("data-node_bwork", nodeData.node_bwork); |
|||
nodeSpan.setAttribute("data-node_vultype", nodeData.node_vultype); |
|||
nodeSpan.setAttribute("data-node_vulgrade", nodeData.node_vulgrade || ""); |
|||
nodeSpan.setAttribute("data-node_workstatus",nodeData.node_workstatus); |
|||
if(nodeData.node_workstatus ===0){ |
|||
nodeSpan.classList.add("no-work"); |
|||
}else { |
|||
nodeSpan.classList.remove("no-work"); |
|||
} |
|||
// 根据漏洞级别添加样式
|
|||
if (nodeData.node_vulgrade) { |
|||
nodeSpan.classList.remove("no-work"); |
|||
if (nodeData.node_vulgrade === "低危") { |
|||
nodeSpan.classList.add("vul-low"); |
|||
} else if (nodeData.node_vulgrade === "中危") { |
|||
nodeSpan.classList.add("vul-medium"); |
|||
} else if (nodeData.node_vulgrade === "高危") { |
|||
nodeSpan.classList.add("vul-high"); |
|||
} |
|||
} |
|||
// 创建容器用于存放切换图标与文本
|
|||
const container = document.createElement("div"); |
|||
container.className = "node-container"; |
|||
// 如果有子节点,则添加切换图标
|
|||
if (nodeData.children && nodeData.children.length > 0) { |
|||
const toggleIcon = document.createElement("span"); |
|||
toggleIcon.className = "toggle-icon"; |
|||
toggleIcon.textContent = "-"; // 默认展开时显示“-”
|
|||
container.appendChild(toggleIcon); |
|||
} |
|||
//节点文本
|
|||
const textSpan = document.createElement("span"); |
|||
textSpan.className = "node-text"; |
|||
textSpan.textContent = nodeData.node_name; |
|||
container.appendChild(textSpan); |
|||
nodeSpan.appendChild(container); |
|||
li.appendChild(nodeSpan); |
|||
//如果存在子节点,递归生成子节点列表
|
|||
if (nodeData.children && nodeData.children.length > 0) { |
|||
const ul = document.createElement("ul"); |
|||
nodeData.children.forEach((child) => { |
|||
ul.appendChild(generateTreeHTML(child)); |
|||
}); |
|||
li.appendChild(ul); |
|||
} |
|||
return li; |
|||
} |
|||
|
|||
// 绑定所有节点的点击事件
|
|||
function bindTreeNodeEvents() { |
|||
document.querySelectorAll(".tree-node").forEach((el) => { |
|||
el.addEventListener("click", (event) => { |
|||
// 阻止事件冒泡,避免点击时展开折叠影响
|
|||
event.stopPropagation(); |
|||
// 清除之前选中的节点样式
|
|||
document |
|||
.querySelectorAll(".tree-node.selected") |
|||
.forEach((node) => node.classList.remove("selected")); |
|||
// 当前节点标记为选中
|
|||
el.classList.add("selected"); |
|||
// 读取 data 属性更新右侧显示
|
|||
const nodeName = el.getAttribute("data-node_name"); |
|||
const status = el.getAttribute("data-node_status"); |
|||
const nodepath = el.getAttribute("data-node_path"); |
|||
const nodebwork = el.getAttribute("data-node_bwork"); |
|||
const vulType = el.getAttribute("data-node_vultype"); |
|||
const vulLevel = el.getAttribute("data-node_vulgrade"); |
|||
const workstatus = el.getAttribute("data-node_workstatus"); |
|||
//selectedNodeData = { nodeName, status, vulType, vulLevel,nodepath,nodebwork };
|
|||
// 示例中默认填充
|
|||
selectedNodeData = { |
|||
node_name: nodeName, |
|||
node_path: nodepath, |
|||
status: status, |
|||
node_bwork: nodebwork, |
|||
vul_type: vulType, |
|||
vul_grade: vulLevel || "-", |
|||
workstatus: workstatus |
|||
}; |
|||
//刷新界面内容
|
|||
update_select_node_data_show(nodeName,status,vulType,vulLevel,workstatus,nodebwork) |
|||
}); |
|||
// 双击事件:展开/收缩子节点区域
|
|||
el.addEventListener("dblclick", (event) => { |
|||
event.stopPropagation(); |
|||
// 找到该节点下的 <ul> 子节点列表
|
|||
const parentLi = el.parentElement; |
|||
const childUl = parentLi.querySelector("ul"); |
|||
if (childUl) { |
|||
// 切换 collapsed 类,控制 display
|
|||
childUl.classList.toggle("collapsed"); |
|||
// 更新切换图标
|
|||
const toggleIcon = el.querySelector(".toggle-icon"); |
|||
if (toggleIcon) { |
|||
toggleIcon.textContent = childUl.classList.contains("collapsed") |
|||
? "+" |
|||
: "-"; |
|||
} |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
// 动态加载节点树数据
|
|||
async function loadNodeTree(task_id) { |
|||
// 清空选中状态
|
|||
selectedNodeData = null; |
|||
//刷新界面内容
|
|||
update_select_node_data_show("-","-","-","-","-",false) |
|||
try { |
|||
const res = await fetch("/api/task/gethistree", { |
|||
method: "POST", |
|||
headers: { "Content-Type": "application/json" }, |
|||
body: JSON.stringify({ task_id }), //task_id:task_id
|
|||
}); |
|||
if (!res.ok) { |
|||
const errorData = await res.json(); |
|||
throw new Error(errorData.error || `HTTP错误 ${res.status}`); |
|||
} |
|||
const data = await res.json(); |
|||
const treeData = data.tree; |
|||
if (!treeData) { |
|||
document.getElementById("treeContent").innerHTML = |
|||
"<p>无节点数据</p>"; |
|||
return; |
|||
} |
|||
|
|||
// 创建一个 <ul> 作为树的根容器
|
|||
const ul = document.createElement("ul"); |
|||
ul.className = "tree-root-ul"; |
|||
ul.appendChild(generateTreeHTML(treeData)); |
|||
// 替换节点树容器的内容
|
|||
const container = document.getElementById("treeContent"); |
|||
container.innerHTML = ""; |
|||
container.appendChild(ul); |
|||
// 绑定节点点击事件
|
|||
bindTreeNodeEvents(); |
|||
} catch (error) { |
|||
console.error("加载节点树失败:", error); |
|||
document.getElementById("treeContent").innerHTML = "<p>加载节点树失败</p>"; |
|||
} |
|||
} |
|||
|
|||
function getWorkStatus_Str(workstatus){ |
|||
strworkstatus = "" |
|||
switch (workstatus){ |
|||
case 0: |
|||
strworkstatus = "无待执行任务"; |
|||
break; |
|||
case 1: |
|||
strworkstatus = "待执行指令中"; |
|||
break; |
|||
case 2: |
|||
strworkstatus = "指令执行中"; |
|||
break; |
|||
case 3: |
|||
strworkstatus = "待提交llm中"; |
|||
break; |
|||
case 4: |
|||
strworkstatus = "提交llm中"; |
|||
break; |
|||
default: |
|||
strworkstatus = "-" |
|||
} |
|||
return strworkstatus |
|||
} |
|||
|
|||
//根据web端过来的数据,更新节点的工作状态
|
|||
function updateTreeNode(node_path, node_workstatus) { |
|||
// 根据 node_path 查找对应节点(假设每个 .tree-node 上设置了 data-node_path 属性)
|
|||
const nodeEl = document.querySelector(`.tree-node[data-node_path="${node_path}"]`); |
|||
if (nodeEl) { |
|||
// 更新 DOM 属性(属性值均为字符串)
|
|||
nodeEl.setAttribute("data-node_workstatus", node_workstatus); |
|||
//判断是否需要更新界面
|
|||
if(selectedNodeData){ |
|||
if(node_path === selectedNodeData.node_path){ //只有是当前选中节点才更新数据
|
|||
selectedNodeData.workstatus = node_workstatus; |
|||
strnew = getWorkStatus_Str(node_workstatus); |
|||
document.getElementById("node_workstatus").textContent = strnew; |
|||
} |
|||
} |
|||
} else { |
|||
console.warn(`未找到节点 ${node_path}`); |
|||
} |
|||
} |
|||
|
|||
//刷新节点的数据显示
|
|||
function update_select_node_data_show(nodeName,testStatus,vulType,vulLevel,workStatus,nodebwork){ |
|||
document.getElementById("nodeName").textContent = nodeName; |
|||
document.getElementById("testStatus").textContent = testStatus; |
|||
document.getElementById("node_vulType").textContent = vulType; |
|||
document.getElementById("node_vulLevel").textContent = vulLevel; |
|||
str_workStatus = getWorkStatus_Str(Number(workStatus)); |
|||
document.getElementById("node_workstatus").textContent = str_workStatus; |
|||
if(nodebwork==="true"){ |
|||
document.getElementById("node_bwork").textContent = "执行中"; |
|||
}else { |
|||
document.getElementById("node_bwork").textContent = "暂停中"; |
|||
} |
|||
setNodeBtnStatus(); |
|||
} |
|||
|
|||
//节点按钮的状态控制
|
|||
function setNodeBtnStatus(){ |
|||
const btn_VI = document.getElementById("btnViewInstr"); |
|||
if(!selectedNodeData){ |
|||
//没有选择node,按钮全部置不可用
|
|||
btn_VI.disabled = true; |
|||
btn_VI.classList.add("disabled-btn"); |
|||
} |
|||
else{ |
|||
btn_VI.disabled = false; |
|||
btn_VI.classList.remove("disabled-btn"); |
|||
} |
|||
} |
|||
|
|||
// // 刷新按钮事件绑定
|
|||
// document.getElementById("btnRefresh").addEventListener("click", () => {
|
|||
// // 重新加载节点树数据
|
|||
// loadNodeTree(cur_task_id);
|
|||
// });
|
|||
|
|||
// 按钮事件:当未选中节点时提示
|
|||
function checkSelectedNode() { |
|||
if (!selectedNodeData) { |
|||
alert("请先选择节点"); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
//----------------------查看节点--指令modal----------------------------
|
|||
let doneInstrs = []; // 已执行指令的所有数据
|
|||
let todoInstrs = []; // 待执行指令的所有数据
|
|||
let donePage = 1; // 已执行指令当前页
|
|||
let todoPage = 1; // 待执行指令当前页
|
|||
|
|||
document.getElementById("btnViewInstr").addEventListener("click", () => { |
|||
if (!checkSelectedNode()) return; |
|||
openInstrModal() |
|||
}); |
|||
// 打开对话框函数
|
|||
function openInstrModal() { |
|||
const instrCanvas = new bootstrap.Offcanvas(document.getElementById('instrCanvas')); |
|||
instrCanvas.show(); |
|||
|
|||
// const modalEl = document.getElementById("instrModal");
|
|||
// // 假设用 Bootstrap 5 的 Modal 组件
|
|||
// const instrModal = new bootstrap.Modal(modalEl, {keyboard: false});
|
|||
// 显示对话框
|
|||
//instrModal.show();
|
|||
|
|||
// 在打开 modal 时,先更新提示内容,将 loadingMsg 显示“请稍后,数据获取中…”
|
|||
const loadingMsg = document.getElementById("loadingMsg"); |
|||
if (loadingMsg) { |
|||
loadingMsg.textContent = "请稍后,数据获取中..."; |
|||
} |
|||
|
|||
// 加载指令数据
|
|||
loadInstrData(); |
|||
} |
|||
|
|||
// 调用后端接口,获取指令数据
|
|||
async function loadInstrData() { |
|||
task_id = cur_task_id; |
|||
node_path = selectedNodeData.node_path; |
|||
try { |
|||
const res = await fetch("/api/task/hisnodegetinstr", { |
|||
method: "POST", |
|||
headers: { "Content-Type": "application/json" }, |
|||
body: JSON.stringify({task_id,node_path}), |
|||
}); |
|||
if (!res.ok) { |
|||
const errorData = await res.json(); |
|||
throw new Error(errorData.error || `HTTP错误 ${res.status}`); |
|||
} |
|||
const data = await res.json(); |
|||
// 数据获取成功后,清除加载提示
|
|||
const loadingMsg = document.getElementById("loadingMsg"); |
|||
if (loadingMsg) { |
|||
loadingMsg.style.display = "none"; // 或者清空其 innerHTML
|
|||
} |
|||
doneInstrs = data.doneInstrs || []; |
|||
//todoInstrs = data.todoInstrs || [];
|
|||
donePage = 1; |
|||
todoPage = 1; |
|||
renderDoneInstrTable(donePage); |
|||
//renderTodoInstrTable(todoPage);
|
|||
} catch (error) { |
|||
console.error("加载指令数据异常:", error); |
|||
} |
|||
} |
|||
|
|||
// 渲染已执行指令表格
|
|||
function renderDoneInstrTable(page) { |
|||
const tbody = document.getElementById("doneInstrTbody"); |
|||
// 计算起始索引
|
|||
const startIndex = (page - 1) * pageSize; |
|||
const endIndex = startIndex + pageSize; |
|||
const pageData = doneInstrs.slice(startIndex, endIndex); |
|||
//select instruction,start_time,result from task_result where task_id=%s and node_path=%s;
|
|||
tbody.innerHTML = ""; |
|||
// 插入行
|
|||
pageData.forEach((item, i) => { |
|||
const tr = document.createElement("tr"); |
|||
|
|||
// 第一列:序号
|
|||
const tdIndex = document.createElement("td"); |
|||
tdIndex.textContent = startIndex + i + 1; |
|||
tr.appendChild(tdIndex); |
|||
|
|||
// 第二列:指令内容
|
|||
const tdInstr = document.createElement("td"); |
|||
tdInstr.textContent = item[0]; |
|||
tr.appendChild(tdInstr); |
|||
|
|||
// 第三列:开始时间(如果没有则显示空字符串)
|
|||
const tdStartTime = document.createElement("td"); |
|||
tdStartTime.textContent = item[1] || ""; |
|||
tr.appendChild(tdStartTime); |
|||
|
|||
// 第四列:执行结果
|
|||
const tdResult = document.createElement("td"); |
|||
tdResult.textContent = item[2] || ""; |
|||
tr.appendChild(tdResult); |
|||
|
|||
tbody.appendChild(tr); |
|||
}); |
|||
|
|||
// 若不足 10 行,补空行
|
|||
for (let i = pageData.length; i < pageSize; i++) { |
|||
const tr = document.createElement("tr"); |
|||
tr.innerHTML = ` |
|||
<td> </td> |
|||
<td> </td> |
|||
<td> </td> |
|||
<td> </td> |
|||
`;
|
|||
tbody.appendChild(tr); |
|||
} |
|||
} |
|||
|
|||
// 渲染待执行指令表格
|
|||
function renderTodoInstrTable(page) { |
|||
const tbody = document.getElementById("todoInstrTbody"); |
|||
const startIndex = (page - 1) * pageSize; |
|||
const endIndex = startIndex + pageSize; |
|||
const pageData = todoInstrs.slice(startIndex, endIndex); |
|||
|
|||
tbody.innerHTML = ""; |
|||
pageData.forEach((item, i) => { |
|||
const tr = document.createElement("tr"); |
|||
const idx = startIndex + i + 1; |
|||
// 第一列:序号
|
|||
const tdIndex = document.createElement("td"); |
|||
tdIndex.textContent = idx; |
|||
tr.appendChild(tdIndex); |
|||
|
|||
// 第二列:指令文本内容(直接使用 textContent)
|
|||
const tdItem = document.createElement("td"); |
|||
tdItem.textContent = item; // 使用 textContent 避免 HTML 解析
|
|||
tr.appendChild(tdItem); |
|||
|
|||
// 第三列:复制和删除按钮
|
|||
const tdAction = document.createElement("td"); |
|||
// const btn_cp = document.createElement("button");
|
|||
// btn_cp.className = "btn btn-primary btn-sm";
|
|||
// btn_cp.textContent = "复制";
|
|||
// btn_cp.style.marginRight = "2px"; // 设置间隔
|
|||
// btn_cp.onclick = () => confirmCopyTodoInstr(idx - 1);
|
|||
// tdAction.appendChild(btn_cp);
|
|||
const btn = document.createElement("button"); |
|||
btn.className = "btn btn-danger btn-sm"; |
|||
btn.textContent = "删除"; |
|||
btn.onclick = () => confirmDeleteTodoInstr(idx - 1); |
|||
tdAction.appendChild(btn); |
|||
tr.appendChild(tdAction); |
|||
|
|||
tbody.appendChild(tr); |
|||
}); |
|||
|
|||
// 补空行
|
|||
for (let i = pageData.length; i < pageSize; i++) { |
|||
const tr = document.createElement("tr"); |
|||
tr.innerHTML = ` |
|||
<td> </td> |
|||
<td> </td> |
|||
<td> </td> |
|||
`;
|
|||
tbody.appendChild(tr); |
|||
} |
|||
} |
|||
|
|||
// 分页事件
|
|||
document.getElementById("doneInstrPrev").addEventListener("click", (e) => { |
|||
e.preventDefault(); |
|||
if (donePage > 1) { |
|||
donePage--; |
|||
renderDoneInstrTable(donePage); |
|||
} |
|||
}); |
|||
document.getElementById("doneInstrNext").addEventListener("click", (e) => { |
|||
e.preventDefault(); |
|||
const maxPage = Math.ceil(doneInstrs.length / pageSize); |
|||
if (donePage < maxPage) { |
|||
donePage++; |
|||
renderDoneInstrTable(donePage); |
|||
} |
|||
}); |
|||
document.getElementById("todoInstrPrev").addEventListener("click", (e) => { |
|||
e.preventDefault(); |
|||
if (todoPage > 1) { |
|||
todoPage--; |
|||
renderTodoInstrTable(todoPage); |
|||
} |
|||
}); |
|||
document.getElementById("todoInstrNext").addEventListener("click", (e) => { |
|||
e.preventDefault(); |
|||
const maxPage = Math.ceil(todoInstrs.length / pageSize); |
|||
if (todoPage < maxPage) { |
|||
todoPage++; |
|||
renderTodoInstrTable(todoPage); |
|||
} |
|||
}); |
|||
|
|||
// 导出当前页数据
|
|||
document.getElementById("btnExport").addEventListener("click", () => { |
|||
// 判断当前是哪个 Tab
|
|||
const activeTab = document.querySelector("#instrTab button.nav-link.active"); |
|||
if (activeTab.id === "doneInstrTab") { |
|||
exportCurrentPage(doneInstrs, donePage, ["序号", "执行指令", "执行时间", "执行结果"]); |
|||
} else { |
|||
exportCurrentPage(todoInstrs, todoPage, ["序号", "待执行指令"]); |
|||
} |
|||
}); |
|||
|
|||
function exportCurrentPage(dataArr, page, headerArr) { |
|||
const startIndex = (page - 1) * pageSize; |
|||
const endIndex = startIndex + pageSize; |
|||
const pageData = dataArr.slice(startIndex, endIndex); |
|||
|
|||
// 在 CSV 的开头加上 BOM,用于 Excel 识别 UTF-8 编码
|
|||
let csvContent = "\uFEFF" + headerArr.join(",") + "\n"; |
|||
pageData.forEach((item, i) => { |
|||
const rowIndex = startIndex + i + 1; |
|||
if (headerArr.length === 4) { |
|||
// 已执行:序号,执行指令,执行时间,执行结果
|
|||
csvContent += rowIndex + "," + |
|||
(item.command || "") + "," + |
|||
(item.execTime || "") + "," + |
|||
(item.result || "") + "\n"; |
|||
} else { |
|||
// 待执行:序号,待执行指令
|
|||
csvContent += rowIndex + "," + (item.command || "") + "\n"; |
|||
} |
|||
}); |
|||
// 如果不足 pageSize 行,补足空行(根据列数进行适当补全)
|
|||
for (let i = pageData.length; i < pageSize; i++) { |
|||
// 根据 headerArr.length 来设置空行的格式
|
|||
if (headerArr.length === 4) { |
|||
csvContent += ",,,\n"; |
|||
} else { |
|||
csvContent += ",\n"; |
|||
} |
|||
} |
|||
|
|||
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" }); |
|||
const url = URL.createObjectURL(blob); |
|||
const link = document.createElement("a"); |
|||
link.href = url; |
|||
link.download = "指令导出.csv"; |
|||
link.click(); |
|||
URL.revokeObjectURL(url); |
|||
} |
|||
|
|||
//------------------测试数据和漏洞数据tab-------------------
|
|||
// 复用:根据返回的数据数组渲染表格 tbody,保证固定 10 行
|
|||
function renderTableRows(tbody, rowsData) { |
|||
tbody.innerHTML = ""; |
|||
// 遍历数据行,生成 <tr>
|
|||
rowsData.forEach((row, index) => { |
|||
const tr = document.createElement("tr"); |
|||
// 这里假设 row 为对象,包含各个字段;下标从1开始显示序号
|
|||
for (const cellData of Object.values(row)) { |
|||
const td = document.createElement("td"); |
|||
td.textContent = cellData; |
|||
tr.appendChild(td); |
|||
} |
|||
tbody.appendChild(tr); |
|||
}); |
|||
// 补足空行
|
|||
const rowCount = rowsData.length; |
|||
for (let i = rowCount; i < pageSize; i++) { |
|||
const tr = document.createElement("tr"); |
|||
for (let j = 0; j < tbody.parentElement.querySelectorAll("th").length; j++) { |
|||
const td = document.createElement("td"); |
|||
td.innerHTML = " "; |
|||
tr.appendChild(td); |
|||
} |
|||
tbody.appendChild(tr); |
|||
} |
|||
} |
|||
|
|||
//--------------------------测试指令-------------------------------
|
|||
let allInstrs = []; |
|||
let currentInstrPage = 1; |
|||
function renderInstrPage(page) { |
|||
currentInstrPage = page; |
|||
const start = (page - 1) * pageSize; |
|||
const end = start + pageSize; |
|||
const pageData = allInstrs.slice(start, end); |
|||
|
|||
const tbody = document.querySelector("#instrTable tbody"); |
|||
renderTableRows(tbody, pageData); |
|||
|
|||
// 更新分页按钮
|
|||
document.getElementById("instrPrev").dataset.page = page > 1 ? page - 1 : 1; |
|||
document.getElementById("instrNext").dataset.page = (end < allInstrs.length) ? page + 1 : page; |
|||
} |
|||
|
|||
// 查询测试指令
|
|||
async function searchInstructions(page = 1) { |
|||
if(cur_task_id === 0){ |
|||
return; |
|||
} |
|||
const nodeName = document.getElementById("instrNodeName").value.trim(); |
|||
try { |
|||
const res = await fetch("/api/task/getinstr", { |
|||
method: "POST", |
|||
headers: { |
|||
"Content-Type": "application/json", |
|||
}, |
|||
body: JSON.stringify({ |
|||
cur_task_id, |
|||
nodeName |
|||
}), |
|||
}); |
|||
if (!res.ok) { |
|||
const errorData = await res.json(); |
|||
throw new Error(errorData.error || `HTTP错误 ${res.status}`); |
|||
} |
|||
const data = await res.json(); |
|||
allInstrs = data.instrs; |
|||
renderInstrPage(1); //显示第一页数据
|
|||
} catch (error) { |
|||
console.error("获取测试指令失败:", error); |
|||
} |
|||
} |
|||
|
|||
//导出测试指令数据
|
|||
async function ExportInstructions(){ |
|||
alert("导出指令功能实现中。。。") |
|||
} |
|||
|
|||
// 绑定测试指令查询按钮事件
|
|||
document.getElementById("instrSearchBtn").addEventListener("click", () => { |
|||
searchInstructions(); |
|||
}); |
|||
// 绑定测试指令分页点击事件
|
|||
document.getElementById("instrPrev").addEventListener("click", (e) => { |
|||
const page = parseInt(e.target.dataset.page, 10); |
|||
renderInstrPage(page); |
|||
}); |
|||
document.getElementById("instrNext").addEventListener("click", (e) => { |
|||
const page = parseInt(e.target.dataset.page, 10); |
|||
renderInstrPage(page);; |
|||
}); |
|||
|
|||
//------------------漏洞数据---------------------------------
|
|||
let allVuls = []; |
|||
let currentVulPage = 1; |
|||
function renderVulPage(page) { |
|||
currentVulPage = page; |
|||
const start = (page - 1) * pageSize; |
|||
const end = start + pageSize; |
|||
const pageData = allVuls.slice(start, end); |
|||
|
|||
const tbody = document.querySelector("#vulTable tbody"); |
|||
renderTableRows(tbody, pageData); |
|||
|
|||
// 更新分页按钮
|
|||
document.getElementById("vulPrev").dataset.page = page > 1 ? page - 1 : 1; |
|||
document.getElementById("vulNext").dataset.page = (end < allVuls.length) ? page + 1 : page; |
|||
} |
|||
|
|||
// 查询漏洞数据
|
|||
async function searchVulnerabilities(page = 1) { |
|||
if(cur_task_id === 0){return;} |
|||
const nodeName = document.getElementById("vulNodeName").value.trim(); |
|||
const vulType = document.getElementById("vulType").value.trim(); |
|||
const vulLevel = document.getElementById("vulLevel").value; |
|||
try { |
|||
const res = await fetch("/api/task/getvul", { |
|||
method: "POST", |
|||
headers: { |
|||
"Content-Type": "application/json", |
|||
}, |
|||
body: JSON.stringify({ |
|||
cur_task_id, |
|||
nodeName, |
|||
vulType, |
|||
vulLevel |
|||
}), |
|||
}); |
|||
if (!res.ok) { |
|||
const errorData = await res.json(); |
|||
throw new Error(errorData.error || `HTTP错误 ${res.status}`); |
|||
} |
|||
const data = await res.json(); |
|||
allVuls = data.vuls; |
|||
renderVulPage(1) |
|||
} catch (error) { |
|||
console.error("获取漏洞数据失败:", error); |
|||
} |
|||
} |
|||
|
|||
//导出漏洞数据
|
|||
async function ExportVuls(){ |
|||
alert("导出漏洞功能实现中。。。") |
|||
} |
|||
|
|||
// 绑定漏洞数据查询按钮事件
|
|||
document.getElementById("vulSearchBtn").addEventListener("click", () => { |
|||
searchVulnerabilities(); |
|||
}); |
|||
// 绑定漏洞数据分页点击事件
|
|||
document.getElementById("vulPrev").addEventListener("click", (e) => { |
|||
const page = parseInt(e.target.dataset.page, 10); |
|||
renderVulPage(page); |
|||
}); |
|||
document.getElementById("vulNext").addEventListener("click", (e) => { |
|||
const page = parseInt(e.target.dataset.page, 10); |
|||
renderVulPage(page); |
|||
}); |
Loading…
Reference in new issue