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.
 
 
 
 

447 lines
15 KiB

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));
//双击任务列表节点读取数据
searchInstructions();
searchVulnerabilities();
// renderTableRows(document.querySelector("#instrTable tbody"), []);
// renderTableRows(document.querySelector("#vulTable tbody"), []);
});
//----------------------左侧任务列表-----------------------
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 = "<p>加载任务列表失败!</p>";
}
}
//选中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);
}
//--------------------任务基本信息区域--------------------
//单选按钮--测试模式修改
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);
}
}
//修改了涉及到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-------------------
// 复用:根据返回的数据数组渲染表格 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 < 10; i++) {
const tr = document.createElement("tr");
for (let j = 0; j < tbody.parentElement.querySelectorAll("th").length; j++) {
const td = document.createElement("td");
td.innerHTML = "&nbsp;";
tr.appendChild(td);
}
tbody.appendChild(tr);
}
}
// 查询测试指令
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();
// data.instrs 数组中包含查询结果
renderTableRows(document.querySelector("#instrTable tbody"), data.instrs || []);
// 此处可更新分页控件(示例只简单绑定上一页下一页)
document.getElementById("instrPrev").dataset.page = page > 1 ? page - 1 : 1;
document.getElementById("instrNext").dataset.page = page + 1;
} catch (error) {
console.error("获取测试指令失败:", error);
}
}
// 查询漏洞数据
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();
renderTableRows(document.querySelector("#vulTable tbody"), data.vuls || []);
document.getElementById("vulPrev").dataset.page = page > 1 ? page - 1 : 1;
document.getElementById("vulNext").dataset.page = page + 1;
} catch (error) {
console.error("获取漏洞数据失败:", error);
}
}
// 绑定测试指令查询按钮事件
document.getElementById("instrSearchBtn").addEventListener("click", () => {
searchInstructions();
});
// 绑定测试指令分页点击事件
document.getElementById("instrPrev").addEventListener("click", (e) => {
e.preventDefault();
searchInstructions(parseInt(e.target.dataset.page));
});
document.getElementById("instrNext").addEventListener("click", (e) => {
e.preventDefault();
searchInstructions(parseInt(e.target.dataset.page));
});
// 绑定漏洞数据查询按钮事件
document.getElementById("vulSearchBtn").addEventListener("click", () => {
searchVulnerabilities();
});
// 绑定漏洞数据分页点击事件
document.getElementById("vulPrev").addEventListener("click", (e) => {
e.preventDefault();
searchVulnerabilities(parseInt(e.target.dataset.page));
});
document.getElementById("vulNext").addEventListener("click", (e) => {
e.preventDefault();
searchVulnerabilities(parseInt(e.target.dataset.page));
});