Skip to main content
Glama
test-plans.js12.3 kB
/** * 测试计划管理页面JavaScript */ class TestPlanManager { constructor() { this.plans = []; this.currentPlan = null; this.taskCounter = 0; this.init(); } init() { this.loadPlans(); this.bindEvents(); } bindEvents() { // 模态框关闭事件 document.querySelectorAll('.close').forEach(closeBtn => { closeBtn.addEventListener('click', (e) => { e.target.closest('.modal').style.display = 'none'; }); }); // 点击模态框外部关闭 window.addEventListener('click', (e) => { if (e.target.classList.contains('modal')) { e.target.style.display = 'none'; } }); // 创建计划表单提交 document.getElementById('createPlanForm').addEventListener('submit', (e) => { e.preventDefault(); this.createPlan(); }); } async loadPlans() { try { const response = await fetch('/api/plans'); if (response.ok) { this.plans = await response.json(); this.renderPlans(); } else { Utils.showNotification('加载测试计划失败', 'error'); } } catch (error) { console.error('加载测试计划错误:', error); Utils.showNotification('加载测试计划失败', 'error'); } } renderPlans() { const plansList = document.getElementById('plansList'); if (this.plans.length === 0) { plansList.innerHTML = ` <div class="empty-state"> <p>暂无测试计划</p> <button class="btn-primary" onclick="showCreatePlanModal()">创建第一个计划</button> </div> `; return; } plansList.innerHTML = this.plans.map(plan => ` <div class="plan-card" data-plan-id="${plan.id}"> <div class="plan-header"> <h3>${plan.name}</h3> <div class="plan-actions"> <button class="btn-secondary" onclick="testPlanManager.viewPlan('${plan.id}')">查看</button> <button class="btn-secondary" onclick="testPlanManager.editPlan('${plan.id}')">编辑</button> <button class="btn-danger" onclick="testPlanManager.deletePlan('${plan.id}')">删除</button> </div> </div> <div class="plan-info"> <span class="task-count">任务数: ${plan.tasks ? plan.tasks.length : 0}</span> <span class="created-time">创建时间: ${Utils.formatTimestamp(plan.created_at)}</span> </div> </div> `).join(''); } showCreatePlanModal() { this.taskCounter = 0; document.getElementById('createPlanForm').reset(); document.getElementById('tasksList').innerHTML = ''; document.getElementById('createPlanModal').style.display = 'block'; } closeCreatePlanModal() { document.getElementById('createPlanModal').style.display = 'none'; } addTask() { this.taskCounter++; const tasksList = document.getElementById('tasksList'); const taskHtml = ` <div class="task-item" data-task-id="${this.taskCounter}"> <div class="task-header"> <h4>任务 ${this.taskCounter}</h4> <button type="button" class="btn-danger btn-small" onclick="testPlanManager.removeTask(${this.taskCounter})">删除</button> </div> <div class="task-form"> <div class="form-group"> <label>任务名称 *</label> <input type="text" name="taskName_${this.taskCounter}" required placeholder="输入任务名称"> </div> <div class="form-group"> <label>请求URL *</label> <input type="url" name="taskUrl_${this.taskCounter}" required placeholder="https://api.example.com/endpoint"> </div> <div class="form-group"> <label>请求方法</label> <select name="taskMethod_${this.taskCounter}"> <option value="GET">GET</option> <option value="POST">POST</option> <option value="PUT">PUT</option> <option value="DELETE">DELETE</option> </select> </div> <div class="form-group"> <label>请求头 (JSON格式)</label> <textarea name="taskHeaders_${this.taskCounter}" placeholder='{"Content-Type": "application/json"}'></textarea> </div> <div class="form-group"> <label>查询参数 (JSON格式)</label> <textarea name="taskQuery_${this.taskCounter}" placeholder='{"page": "1", "limit": "10"}'></textarea> </div> <div class="form-group"> <label>请求体 (JSON格式)</label> <textarea name="taskBody_${this.taskCounter}" placeholder='{"name": "test", "value": "example"}'></textarea> </div> </div> </div> `; tasksList.insertAdjacentHTML('beforeend', taskHtml); } removeTask(taskId) { const taskElement = document.querySelector(`[data-task-id="${taskId}"]`); if (taskElement) { taskElement.remove(); } } async createPlan() { const formData = new FormData(document.getElementById('createPlanForm')); const planName = formData.get('planName'); if (!planName) { Utils.showNotification('请输入计划名称', 'error'); return; } // 收集任务数据 const tasks = []; const taskItems = document.querySelectorAll('.task-item'); for (const taskItem of taskItems) { const taskId = taskItem.dataset.taskId; const taskData = { name: formData.get(`taskName_${taskId}`), url: formData.get(`taskUrl_${taskId}`), method: formData.get(`taskMethod_${taskId}`) || 'GET', headers: formData.get(`taskHeaders_${taskId}`) || '{}', query: formData.get(`taskQuery_${taskId}`) || '{}', body: formData.get(`taskBody_${taskId}`) || '{}' }; // 验证必填字段 if (!taskData.name || !taskData.url) { Utils.showNotification(`任务 ${taskId} 的名称和URL不能为空`, 'error'); return; } // 验证JSON格式 try { JSON.parse(taskData.headers); JSON.parse(taskData.query); JSON.parse(taskData.body); } catch (error) { Utils.showNotification(`任务 ${taskId} 的JSON格式不正确`, 'error'); return; } tasks.push(taskData); } if (tasks.length === 0) { Utils.showNotification('请至少添加一个任务', 'error'); return; } try { Utils.setLoading(true); const response = await fetch('/api/plans', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: planName, tasks: tasks }) }); const result = await response.json(); if (response.ok) { Utils.showNotification('测试计划创建成功', 'success'); this.closeCreatePlanModal(); this.loadPlans(); } else { Utils.showNotification(result.message || '创建测试计划失败', 'error'); } } catch (error) { console.error('创建测试计划错误:', error); Utils.showNotification('创建测试计划失败', 'error'); } finally { Utils.setLoading(false); } } async viewPlan(planId) { try { const response = await fetch(`/api/plans/${planId}`); if (response.ok) { const plan = await response.json(); this.showPlanDetails(plan); } else { Utils.showNotification('获取计划详情失败', 'error'); } } catch (error) { console.error('获取计划详情错误:', error); Utils.showNotification('获取计划详情失败', 'error'); } } showPlanDetails(plan) { document.getElementById('planDetailsTitle').textContent = `计划详情 - ${plan.name}`; const tasksHtml = plan.tasks ? plan.tasks.map((task, index) => ` <div class="task-detail"> <h4>任务 ${index + 1}: ${task.name}</h4> <div class="task-info"> <p><strong>URL:</strong> ${task.url}</p> <p><strong>方法:</strong> ${task.method}</p> <p><strong>请求头:</strong> <code>${task.headers}</code></p> <p><strong>查询参数:</strong> <code>${task.query}</code></p> <p><strong>请求体:</strong> <code>${task.body}</code></p> </div> </div> `).join('') : '<p>暂无任务</p>'; document.getElementById('planDetailsContent').innerHTML = ` <div class="plan-details"> <div class="plan-meta"> <p><strong>计划ID:</strong> ${plan.id}</p> <p><strong>创建时间:</strong> ${Utils.formatTimestamp(plan.created_at)}</p> <p><strong>任务数量:</strong> ${plan.tasks ? plan.tasks.length : 0}</p> </div> <div class="tasks-details"> <h3>任务列表</h3> ${tasksHtml} </div> </div> `; document.getElementById('planDetailsModal').style.display = 'block'; } async deletePlan(planId) { if (!confirm('确定要删除这个测试计划吗?此操作不可恢复。')) { return; } try { Utils.setLoading(true); const response = await fetch(`/api/plans/${planId}`, { method: 'DELETE' }); const result = await response.json(); if (response.ok) { Utils.showNotification('测试计划删除成功', 'success'); this.loadPlans(); } else { Utils.showNotification(result.message || '删除测试计划失败', 'error'); } } catch (error) { console.error('删除测试计划错误:', error); Utils.showNotification('删除测试计划失败', 'error'); } finally { Utils.setLoading(false); } } editPlan(planId) { // 跳转到编辑页面或打开编辑模态框 Utils.showNotification('编辑功能开发中...', 'info'); } } // 全局函数 function showCreatePlanModal() { testPlanManager.showCreatePlanModal(); } function closeCreatePlanModal() { testPlanManager.closeCreatePlanModal(); } function addTask() { testPlanManager.addTask(); } // 初始化 let testPlanManager; document.addEventListener('DOMContentLoaded', () => { testPlanManager = new TestPlanManager(); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/FactrueSolin/api-test-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server