214 lines
6.3 KiB
TypeScript
214 lines
6.3 KiB
TypeScript
|
|
import request from '@/utils/request';
|
|||
|
|
|
|||
|
|
// @/api/scanCenter.ts
|
|||
|
|
/**
|
|||
|
|
* 获取历史检测记录
|
|||
|
|
* @param params 分页和筛选参数 { page, size, status }
|
|||
|
|
* @returns 历史记录列表
|
|||
|
|
*/
|
|||
|
|
export function getScanHistory(params: { page: number; size: number; status?: string }): Promise<any> {
|
|||
|
|
return new Promise(resolve => {
|
|||
|
|
setTimeout(() => {
|
|||
|
|
// 模拟历史记录数据
|
|||
|
|
const mockRecords = [
|
|||
|
|
{
|
|||
|
|
taskId: 'scan_1689234567890',
|
|||
|
|
target: 'https://example.com',
|
|||
|
|
type: 'url',
|
|||
|
|
status: 'completed',
|
|||
|
|
riskLevel: '高危',
|
|||
|
|
startTime: '2024-07-13T09:23:45',
|
|||
|
|
completeTime: '2024-07-13T09:25:12',
|
|||
|
|
duration: 87000,
|
|||
|
|
riskStats: { critical: 1, high: 3, medium: 2, low: 5 }
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
taskId: 'scan_1689231234567',
|
|||
|
|
target: 'app-release.apk',
|
|||
|
|
type: 'file',
|
|||
|
|
status: 'completed',
|
|||
|
|
riskLevel: '中危',
|
|||
|
|
startTime: '2024-07-12T15:42:18',
|
|||
|
|
completeTime: '2024-07-12T15:47:33',
|
|||
|
|
duration: 315000,
|
|||
|
|
riskStats: { critical: 0, high: 0, medium: 2, low: 1 }
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
taskId: 'scan_1689228901234',
|
|||
|
|
target: 'SBOM内容',
|
|||
|
|
type: 'sbom',
|
|||
|
|
status: 'failed',
|
|||
|
|
riskLevel: '-',
|
|||
|
|
startTime: '2024-07-12T14:15:30',
|
|||
|
|
completeTime: '2024-07-12T14:16:05',
|
|||
|
|
duration: 35000,
|
|||
|
|
errorMsg: '格式解析错误:缺少必填字段"version"'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
taskId: 'scan_1689225678901',
|
|||
|
|
target: 'https://test-api.com/v1',
|
|||
|
|
type: 'url',
|
|||
|
|
status: 'completed',
|
|||
|
|
riskLevel: '低危',
|
|||
|
|
startTime: '2024-07-12T10:08:22',
|
|||
|
|
completeTime: '2024-07-12T10:09:45',
|
|||
|
|
duration: 83000,
|
|||
|
|
riskStats: { critical: 0, high: 0, medium: 0, low: 2 }
|
|||
|
|
}
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 筛选逻辑
|
|||
|
|
let filtered = mockRecords;
|
|||
|
|
if (params.status && params.status !== 'all') {
|
|||
|
|
filtered = filtered.filter(item => item.status === params.status);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 分页逻辑
|
|||
|
|
const total = filtered.length;
|
|||
|
|
const start = (params.page - 1) * params.size;
|
|||
|
|
const records = filtered.slice(start, start + params.size);
|
|||
|
|
|
|||
|
|
resolve({
|
|||
|
|
code: 200,
|
|||
|
|
message: 'success',
|
|||
|
|
data: {
|
|||
|
|
total,
|
|||
|
|
records,
|
|||
|
|
page: params.page,
|
|||
|
|
size: params.size,
|
|||
|
|
pages: Math.ceil(total / params.size)
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}, 300);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 实际接口调用(注释掉,使用模拟数据)
|
|||
|
|
// return request({
|
|||
|
|
// url: `/scan/history`,
|
|||
|
|
// method: 'get',
|
|||
|
|
// params
|
|||
|
|
// });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 提交检测任务
|
|||
|
|
* @param data 任务数据 { type, target, file?, content? }
|
|||
|
|
* @returns 任务信息
|
|||
|
|
*/
|
|||
|
|
export function submitScanTask(data: {
|
|||
|
|
type: 'file' | 'url' | 'sbom';
|
|||
|
|
target: string;
|
|||
|
|
file?: FormData;
|
|||
|
|
content?: string;
|
|||
|
|
}): Promise<any> {
|
|||
|
|
return new Promise(resolve => {
|
|||
|
|
setTimeout(() => {
|
|||
|
|
// 生成唯一任务ID
|
|||
|
|
const taskId = `scan_${Date.now()}`;
|
|||
|
|
const now = new Date().toISOString();
|
|||
|
|
|
|||
|
|
resolve({
|
|||
|
|
code: 200,
|
|||
|
|
message: '任务提交成功',
|
|||
|
|
data: {
|
|||
|
|
taskId,
|
|||
|
|
type: data.type,
|
|||
|
|
target: data.target,
|
|||
|
|
status: 'pending', // 初始状态:等待中
|
|||
|
|
progress: 0,
|
|||
|
|
startTime: now,
|
|||
|
|
estimatedCompleteTime: new Date(Date.now() + 300000).toISOString(), // 预计5分钟后完成
|
|||
|
|
currentStep: '等待调度'
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}, 500);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 实际接口调用(注释掉,使用模拟数据)
|
|||
|
|
// return request({
|
|||
|
|
// url: `/scan/submit`,
|
|||
|
|
// method: 'post',
|
|||
|
|
// data
|
|||
|
|
// });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取检测任务状态
|
|||
|
|
* @param taskId 任务ID
|
|||
|
|
* @returns 任务当前状态信息
|
|||
|
|
*/
|
|||
|
|
export function getScanStatus(taskId: string): Promise<any> {
|
|||
|
|
return new Promise(resolve => {
|
|||
|
|
setTimeout(() => {
|
|||
|
|
// 解析任务ID中的时间戳(模拟任务创建时间)
|
|||
|
|
const createTime = parseInt(taskId.split('_')[1] || Date.now().toString());
|
|||
|
|
const now = Date.now();
|
|||
|
|
const elapsed = now - createTime;
|
|||
|
|
|
|||
|
|
// 模拟状态流转
|
|||
|
|
let status: string, progress: number, currentStep: string, completeTime: string | null = null;
|
|||
|
|
|
|||
|
|
if (elapsed < 3000) { // 前3秒:等待中
|
|||
|
|
status = 'pending';
|
|||
|
|
progress = 0;
|
|||
|
|
currentStep = '等待调度';
|
|||
|
|
} else if (elapsed < 15000) { // 3-15秒:检测中(进度递增)
|
|||
|
|
status = 'scanning';
|
|||
|
|
progress = Math.min(Math.floor((elapsed - 3000) / 12000 * 100), 90);
|
|||
|
|
currentStep = progress < 30 ? '初始化检测环境' :
|
|||
|
|
progress < 60 ? '执行漏洞扫描' : '生成初步报告';
|
|||
|
|
} else { // 15秒后:完成(80%概率)或失败(20%概率)
|
|||
|
|
const isSuccess = Math.random() > 0.2;
|
|||
|
|
status = isSuccess ? 'completed' : 'failed';
|
|||
|
|
progress = 100;
|
|||
|
|
completeTime = new Date().toISOString();
|
|||
|
|
|
|||
|
|
if (isSuccess) {
|
|||
|
|
currentStep = '检测完成';
|
|||
|
|
} else {
|
|||
|
|
currentStep = '检测失败';
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 模拟风险统计(仅当任务完成时)
|
|||
|
|
const riskStats = status === 'completed'
|
|||
|
|
? {
|
|||
|
|
critical: Math.floor(Math.random() * 2),
|
|||
|
|
high: Math.floor(Math.random() * 3),
|
|||
|
|
medium: Math.floor(Math.random() * 5),
|
|||
|
|
low: Math.floor(Math.random() * 8)
|
|||
|
|
}
|
|||
|
|
: null;
|
|||
|
|
|
|||
|
|
// 模拟错误信息(仅当任务失败时)
|
|||
|
|
const errorMsg = status === 'failed'
|
|||
|
|
? ['网络连接超时', '目标资源不可访问', '检测引擎异常'][Math.floor(Math.random() * 3)]
|
|||
|
|
: null;
|
|||
|
|
|
|||
|
|
resolve({
|
|||
|
|
code: 200,
|
|||
|
|
message: 'success',
|
|||
|
|
data: {
|
|||
|
|
taskId,
|
|||
|
|
status,
|
|||
|
|
progress,
|
|||
|
|
currentStep,
|
|||
|
|
startTime: new Date(createTime).toISOString(),
|
|||
|
|
estimatedCompleteTime: new Date(createTime + 300000).toISOString(),
|
|||
|
|
completeTime,
|
|||
|
|
riskStats,
|
|||
|
|
errorMsg,
|
|||
|
|
totalChecks: status === 'completed' ? 20 + Math.floor(Math.random() * 30) : null,
|
|||
|
|
completedChecks: status === 'scanning' ? Math.floor(progress / 100 * 40) : null
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}, 300);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 实际接口调用(注释掉,使用模拟数据)
|
|||
|
|
// return request({
|
|||
|
|
// url: `/scan/status/${taskId}`,
|
|||
|
|
// method: 'get'
|
|||
|
|
// });
|
|||
|
|
}
|