/* webtest-agent 前端逻辑 */ const $ = s => document.querySelector(s); const API = ''; async function refreshHealth() { try { const r = await fetch(API + '/health'); const d = await r.json(); $('#health').textContent = `服务正常 | 模型: ${d.llm_model} | 运行中任务: ${d.concurrent}`; $('#health').classList.add('ok'); } catch (e) { $('#health').textContent = '服务异常'; $('#health').classList.remove('ok'); } } const STATUS_MAP = { queued: '排队中', running: '测试中', finished: '已完成', stopped: '已停止' }; const RESULT_MAP = { pending: '待定', pass: '✅ 通过', fail: '❌ 失败', error: '⚠️ 错误', stopped: '⏹️ 停止' }; function esc(s) { return String(s ?? '').replace(/[&<>"']/g, c => ( {'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); } async function loadTasks() { try { const r = await fetch(API + '/api/tasks'); const d = await r.json(); const tb = $('#task-table tbody'); if (!d.tasks.length) { tb.innerHTML = '暂无任务,先发起一个吧'; return; } tb.innerHTML = d.tasks.map(t => { const ops = t.status === 'running' || t.status === 'queued' ? ` ` : ''; const report = t.status === 'finished' ? `查看报告` : '—'; return ` ${esc(t.id)} ${esc(t.url)}
${esc(t.goal)}
${STATUS_MAP[t.status] || esc(t.status)} ${RESULT_MAP[t.result] || esc(t.result)} ${t.steps || 0} ${esc(t.created)} ${ops}${report} `; }).join(''); } catch (e) { $('#task-table tbody').innerHTML = '加载失败'; } } async function stopTask(tid) { if (!confirm('确定停止该任务?')) return; await fetch(API + `/api/tasks/${tid}/stop`, { method: 'POST' }); setTimeout(loadTasks, 500); } function openReport(tid) { $('#report-frame').src = API + `/api/tasks/${tid}/report`; $('#modal-title').textContent = `测试报告 - ${tid}`; $('#report-modal').classList.remove('hidden'); } $('#modal-close').onclick = () => $('#report-modal').classList.add('hidden'); $('#report-modal').onclick = e => { if (e.target === $('#report-modal')) $('#report-modal').classList.add('hidden'); }; $('#submit').onclick = async () => { const url = $('#url').value.trim(); const goal = $('#goal').value.trim(); if (!url || !goal) { alert('请填写网址和测试目标'); return; } const btn = $('#submit'); btn.disabled = true; btn.textContent = '提交中...'; try { const r = await fetch(API + '/api/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url, goal, max_steps: parseInt($('#max_steps').value) || 30, timeout: parseInt($('#timeout').value) || 600 }) }); const d = await r.json(); if (d.error) { alert('提交失败: ' + d.error); } else { $('#goal').value = ''; loadTasks(); // 轮询直到该任务结束 pollTask(d.task_id); } } catch (e) { alert('提交失败: ' + e); } finally { btn.disabled = false; btn.textContent = '🚀 开始测试'; } }; function pollTask(tid, count = 0) { if (count > 400) return; setTimeout(async () => { try { const r = await fetch(API + `/api/tasks/${tid}`); const t = await r.json(); loadTasks(); if (t.status === 'finished' || t.status === 'stopped') return; pollTask(tid, count + 1); } catch (e) { /* ignore */ } }, 3000); } $('#refresh').onclick = loadTasks; refreshHealth(); loadTasks(); setInterval(refreshHealth, 30000); setInterval(loadTasks, 5000);