let task_list = [] let cur_task = null //当前选择的task--用于修改缓存时使用 let cur_task_id = 0 //当前选择的cur_task_id let ws = null // 页面卸载时断开连接 window.addEventListener("beforeunload", function() { if (ws) { ws.close(); ws =null; } task_list = [] cur_task = null; cur_task_id = 0; }); // 页面加载完成后调用接口获取任务列表数据 document.addEventListener("DOMContentLoaded", async () => { //建立wbsocket initWebSocket() //获取左侧任务列表 getTasklist(); //当前选中的数据要清空 cur_task = null; cur_task_id = 0; //任务基本信息界面初始化 document.getElementById("detailTestTarget").textContent = "-"; document.getElementById("detailTestStatus").textContent = "-"; document.getElementById("detailSafeStatus").textContent = '-'; //单选按钮 set_radio_selection('testMode', 'auto'); setSetpBtnStatus(); //节点树界面初始化 update_select_node_data_show("-","-","-","-","-",false) //单选按钮点击事件 ------ 是不是更规范的编程方式,应该把控件事件的添加都放页面加载完成后处理 const autoRadio = document.getElementById("autoMode"); const manualRadio = document.getElementById("manualMode"); autoRadio.addEventListener("click", () => updateTestMode(1)); manualRadio.addEventListener("click", () => updateTestMode(0)); //tab页点击刷新数据 document.getElementById("testInstructionsTab").addEventListener("click",()=>searchInstructions()); document.getElementById("vulnerabilitiesTab").addEventListener("click",()=>searchVulnerabilities()); //指令和漏洞数据的导出按钮点击事件 document.getElementById("instrExportBtn").addEventListener("click",()=>ExportInstructions()); document.getElementById("vulExportBtn").addEventListener("click",()=>ExportVuls()); }); //----------------------左侧任务列表----------------------- function getstrsafeR(safeRank){ if(safeRank === 0){ safeR = "安全"; } else{ safeR = "存在风险"; } return safeR; } function getstrTaskS(taskStatus){ if(taskStatus === 0){ taskS = "暂停中"; }else if(taskStatus === 1){ taskS = "执行中"; }else { taskS = "已完成"; } return taskS; } async function getTasklist(){ try { const res = await fetch("/api/task/getlist"); if (!res.ok) { const errorData = await res.json(); throw new Error(errorData.error || `HTTP错误 ${res.status}`); } const data = await res.json(); task_list = data.tasks const taskList = document.getElementById("taskList"); taskList.innerHTML = ""; // 清空“加载中”提示 // 遍历任务数组,生成任务项 task_list.forEach((task) => { const taskItem = document.createElement("div"); taskItem.dataset.taskID =task.taskID //在taskItem添加数据属性,这是关联数据的第二种方法,selectedEl.dataset.taskId; 感觉比cur_task更好 taskItem.className = "task-item"; // 第一行:测试目标 const targetDiv = document.createElement("div"); targetDiv.className = "task-target"; targetDiv.textContent = task.testTarget; taskItem.appendChild(targetDiv); // 第二行:测试状态,带缩进 const statusDiv = document.createElement("div"); statusDiv.className = "task-status"; let safeR = getstrsafeR(task.safeRank); let taskS = getstrTaskS(task.taskStatus); statusDiv.textContent = `${taskS}-${safeR}`; taskItem.appendChild(statusDiv); // 可绑定点击事件:点击任务项更新右侧详情 taskItem.addEventListener("click", () => { // 取消所有任务项的选中状态 document.querySelectorAll(".task-item.selected").forEach(item => { item.classList.remove("selected"); }); // 给当前点击的任务项添加选中状态 taskItem.classList.add("selected"); //执行业务代码 --参数当前选中task的数据 cur_task = task; selected_task_item() }); taskList.appendChild(taskItem); }); } catch (error) { console.error("加载任务列表出错:", error); document.getElementById("taskList").innerHTML = "

加载任务列表失败!

"; } } //选中tasklist--更新界面数据 function selected_task_item(){ if(cur_task_id === cur_task.taskID) return; cur_task_id = cur_task.taskID; //按钮状态更新 actionButton = document.getElementById("actionButton"); if(cur_task.taskStatus === 0){ actionButton.textContent = "继续"; }else if(cur_task.taskStatus === 1){ actionButton.textContent = "暂停"; }else { } //基本信息 let safeR = getstrsafeR(cur_task.safeRank); let taskS = getstrTaskS(cur_task.taskStatus); document.getElementById("detailTestTarget").textContent = cur_task.testTarget; document.getElementById("detailTestStatus").textContent = taskS; document.getElementById("detailSafeStatus").textContent = safeR; //单选按钮 if(cur_task.workType === 0){ //人工 set_radio_selection('testMode', 'manual'); }else { //1-自动 set_radio_selection('testMode', 'auto'); } //更新单步按钮 setSetpBtnStatus() //加载任务其他信息--node_tree.js loadNodeTree(cur_task_id); //加载测试指令和漏洞数据 searchInstructions(); searchVulnerabilities(); // renderTableRows(document.querySelector("#instrTable tbody"), []); // renderTableRows(document.querySelector("#vulTable tbody"), []); } //--------------------任务基本信息区域-------------------- //单选按钮--测试模式修改 async function updateTestMode(mode){ //0-人工,1-自动 if(cur_task){ if(cur_task.workType !== mode){ if(cur_task.taskStatus === 1){ alert("执行状态,不允许修改测试模式!"); if( cur_task.workType === 0){ //人工 set_radio_selection('testMode', 'manual'); }else { //1-自动 set_radio_selection('testMode', 'auto'); } } else {//不是执行状态,可以修改测试模式 try { const res = await fetch("/api/task/taskworktype", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ cur_task_id,mode }), //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(); bsuccess = data.bsuccess; if(bsuccess){ cur_task.workType = mode; //更新前端缓存 //更新单步按钮状态 setSetpBtnStatus() }else { alert("修改测试模失败!") if( cur_task.workType === 0){ //人工 修改失败还原单选按钮点击状态 set_radio_selection('testMode', 'manual'); }else { //1-自动 set_radio_selection('testMode', 'auto'); } } } catch (error) { console.error("控制任务状态异常:", error); alert("控制任务状态异常:",error); if( cur_task.workType === 0){ //人工 修改失败还原单选按钮点击状态 set_radio_selection('testMode', 'manual'); }else { //1-自动 set_radio_selection('testMode', 'auto'); } } } } } } //点击暂停/继续按钮 document.getElementById("actionButton").addEventListener("click",() => { controlTask(); }); async function controlTask(){ if(cur_task_id === 0){ alert("请先选择一个任务!") return } try { const res = await fetch("/api/task/taskcontrol", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ cur_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(); newstatus = data.newstatus; //更新页面 if(newstatus === 0){ document.getElementById("detailTestStatus").textContent = "暂停中"; actionButton.textContent = "继续"; }else if(newstatus === 1){ document.getElementById("detailTestStatus").textContent = "执行中"; actionButton.textContent = "暂停"; }else { document.getElementById("detailTestStatus").textContent = "已完成"; actionButton.textContent = "已完成"; } cur_task.taskStatus = newstatus; //光有个cur_taks也可以 setSetpBtnStatus(); //更新task_list的显示 updateTaskList(); } catch (error) { console.error("控制任务状态异常:", error); alert("控制任务状态异常:",error); } } //结束任务-brun-false document.getElementById("btnTaskOver").addEventListener("click",()=>{ overTask(); }) async function overTask(){ if(cur_task_id === 0){ alert("请先选择一个任务!") return } try { if (confirm('确定要结束此任务吗?')){ const res = await fetch("/api/task/taskover", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ cur_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(); bsuccess = data.bsuccess; error = data.error; if(bsuccess){ //更新页面 task_list = [] cur_task = null //当前选择的task--用于修改缓存时使用 cur_task_id = 0 //当前选择的cur_task_id //重新获取任务list getTasklist(); }else { alert("结束任务失败:",error); } } } catch (error) { alert("结束任务失败:",error); } } //修改了涉及到tasklist的展示内容,修改tasklist显示 function updateTaskList(){ //更新数据 const selectedEl = document.querySelector(".task-item.selected"); if (selectedEl) { let safeR = getstrsafeR(cur_task.safeRank); let taskS = getstrTaskS(cur_task.taskStatus); const statusDiv = selectedEl.querySelector(".task-status"); statusDiv.textContent = `${taskS}-${safeR}`; } } //设置单步按钮的可点击状态状态 function setSetpBtnStatus(){ if(cur_task){ task_status = cur_task.taskStatus; work_type = cur_task.workType; }else { task_status = 0; work_type = 0; } btn_TaskStep = document.getElementById("one_step"); btn_NodeStep = document.getElementById("btnNodeStep"); if(task_status===1 && work_type===0){ //执行中且是人工模式 btn_TaskStep.disabled= false; btn_TaskStep.classList.remove("disabled-btn"); //node-step if (selectedNodeData) { if(selectedNodeData.node_bwork){ //有选中node,且节点为工作状态 btn_NodeStep.disabled= false; btn_NodeStep.classList.remove("disabled-btn"); } else { btn_NodeStep.disabled = true; btn_NodeStep.classList.add("disabled-btn"); //css会去重 } } }else{ //其他情况都是不可用状态 btn_TaskStep.disabled = true; // 添加 disabled 属性 btn_TaskStep.classList.add("disabled-btn"); // 添加自定义样式 if (selectedNodeData) { btn_NodeStep.disabled = true; btn_NodeStep.classList.add("disabled-btn"); //css会去重 } } } //单步按钮--任务单步 document.getElementById("one_step").addEventListener("click",() => { if(cur_task_id===0){ return } one_step_task(); }); async function one_step_task(){ try { const res = await fetch("/api/task/taskstep", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ cur_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 bsuccess = data.bsuccess; if(bsuccess){ alert("该任务已提交单步工作,请稍候查看执行结果!") } else{ error = data.erroe; alert("该任务单步失败!",error) } }catch (error) { alert("该节点单步失败,请联系管理员!", error); } } //------------------测试数据和漏洞数据tab------------------- const pageSize = 10; // 复用:根据返回的数据数组渲染表格 tbody,保证固定 10 行 function renderTableRows(tbody, rowsData) { tbody.innerHTML = ""; // 遍历数据行,生成 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); });