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 = ""; // 遍历数据行,生成