From b5932a95b270ebe79bc212926f0815a3d95f9ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A5=80=E6=A2=A6?= <3501646051@qq.com> Date: Tue, 27 Jan 2026 23:15:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=AE=A1=E7=90=86=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E5=90=8E=E7=AB=AF=E4=BC=98=E5=8C=96=EF=BC=9A=E6=8F=90?= =?UTF-8?q?=E5=8D=87=E8=BF=9B=E5=BA=A6=E6=9B=B4=E6=96=B0=E9=A2=91=E7=8E=87?= =?UTF-8?q?=E5=92=8C=E7=8A=B6=E6=80=81=E8=AF=A6=E7=BB=86=E7=A8=8B=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 提高爬取阶段进度更新频率:从每10个改为每5个代理更新一次 2. 提高验证阶段进度更新频率:从每5个改为每验证1个代理就更新一次 3. 添加进度百分比计算所需字段:在progress消息中添加current和total字段 4. 增强状态信息详细程度: - 添加connecting状态:正在连接插件源 - 添加starting状态:正在启动爬虫 - 添加crawling_start状态:开始爬取代理 - 添加validating_start状态:开始验证代理 - 在进度消息中添加message字段,显示更详细的进度描述 这些改进可以让前端显示更实时、更详细的任务进度和状态信息 --- frontend/src/api/index.js | 25 +- frontend/src/main.js | 5 +- frontend/src/views/ProxyList.vue | 81 ++-- frontend/src/views/Settings.vue | 29 +- tasks_manager.py | 31 +- test_results.json | 724 +++++++++++++++++++++++++++++++ 6 files changed, 844 insertions(+), 51 deletions(-) create mode 100644 test_results.json diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 4cc81b9..ac7f684 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -6,6 +6,19 @@ const api = axios.create({ timeout: 30000 }) +api.interceptors.request.use( + config => { + const apiKey = localStorage.getItem('api_key') + if (apiKey) { + config.headers['X-API-Key'] = apiKey + } + return config + }, + error => { + return Promise.reject(error) + } +) + api.interceptors.response.use( response => response.data, error => { @@ -20,14 +33,22 @@ export const statsAPI = { } export const proxiesAPI = { - getProxies: (params) => api.post('/api/proxies', params), + getProxies: (params) => { + const cleanedParams = {} + Object.keys(params).forEach(key => { + if (params[key] !== null && params[key] !== undefined && params[key] !== '') { + cleanedParams[key] = params[key] + } + }) + return api.post('/api/proxies', cleanedParams) + }, getRandomProxy: () => api.get('/api/proxies/random'), getProxyDetail: (ip, port) => api.get(`/api/proxies/${ip}/${port}`), deleteProxy: (ip, port) => api.delete(`/api/proxies/${ip}/${port}`), batchDeleteProxies: (proxies) => api.post('/api/proxies/batch-delete', { proxies }), cleanInvalidProxies: () => api.delete('/api/proxies/clean-invalid'), exportProxies: (format, protocol) => api.get(`/api/proxies/export/${format}`, { - params: { protocol }, + params: protocol ? { protocol } : {}, responseType: 'blob' }) } diff --git a/frontend/src/main.js b/frontend/src/main.js index 3a4b343..e12fc1e 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -1,6 +1,7 @@ import { createApp } from 'vue' import { createPinia } from 'pinia' import ElementPlus from 'element-plus' +import zhCn from 'element-plus/es/locale/lang/zh-cn' import 'element-plus/dist/index.css' import router from './router' import './style.css' @@ -12,6 +13,8 @@ const pinia = createPinia() app.use(pinia) app.use(router) -app.use(ElementPlus) +app.use(ElementPlus, { + locale: zhCn, +}) app.mount('#app') diff --git a/frontend/src/views/ProxyList.vue b/frontend/src/views/ProxyList.vue index c1a4d94..575e3ed 100644 --- a/frontend/src/views/ProxyList.vue +++ b/frontend/src/views/ProxyList.vue @@ -5,7 +5,7 @@ - + @@ -14,24 +14,14 @@ - + - + - - - 🔍 - 搜索 - - - 🔄 - 重置 - - @@ -40,19 +30,24 @@
代理详情
- - 批量删除 - - - 导出 - - + + + 批量删除 + + + + 导出 + + + + +
@@ -76,15 +71,14 @@ + + + - + + +
用于执行管理操作的API Key
+
+ @@ -92,6 +103,7 @@ import PageHeader from '../components/PageHeader.vue' const loading = ref(false) const saving = ref(false) const settings = reactive({ + api_key: '', db_path: '', crawl_timeout: 30, validation_timeout: 10, @@ -109,6 +121,7 @@ async function fetchSettings() { const data = await response.json() Object.assign(settings, data) } + settings.api_key = localStorage.getItem('api_key') || '' } finally { loading.value = false } @@ -117,12 +130,19 @@ async function fetchSettings() { async function handleSave() { saving.value = true try { + if (settings.api_key) { + localStorage.setItem('api_key', settings.api_key) + } else { + localStorage.removeItem('api_key') + } + + const { api_key, ...settingsToSend } = settings const response = await fetch('http://localhost:8923/api/settings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(settings) + body: JSON.stringify(settingsToSend) }) if (response.ok) { @@ -171,6 +191,13 @@ onMounted(() => { color: var(--text-secondary); } +.setting-hint { + margin-top: 8px; + font-size: 12px; + color: var(--text-secondary); + line-height: 1.4; +} + .btn-icon { font-size: 20px; margin-right: 8px; diff --git a/tasks_manager.py b/tasks_manager.py index 172a7d2..569f071 100644 --- a/tasks_manager.py +++ b/tasks_manager.py @@ -22,6 +22,7 @@ class TasksManager: 'current_url': None, 'plugins': [] } + self.estimated_total = 1000 def set_callbacks(self, progress_callback: Optional[Callable] = None, status_callback: Optional[Callable] = None): self.progress_callback = progress_callback @@ -34,6 +35,10 @@ class TasksManager: if 'found' in data and 'verified' in data: data['success_rate'] = round((data['verified'] / data['found'] * 100), 2) if data['found'] > 0 else 0 + if 'found' in data: + data['current'] = data['found'] + self.stats['total_verified'] + data['total'] = self.estimated_total + await self.progress_callback(data) async def _notify_status(self, status: str, message: str): @@ -45,7 +50,7 @@ class TasksManager: }) async def run_crawler(self): - await self._notify_status('crawling', '开始爬取代理啦~') + await self._notify_status('crawling_start', '开始爬取代理啦~') manager = PluginManager() count = 0 @@ -59,11 +64,13 @@ class TasksManager: count += 1 self.stats['total_found'] = count - if count % 10 == 0: + if count % 5 == 0: await self._notify_progress({ 'type': 'crawling', 'found': count, - 'verified': self.stats['total_verified'] + 'verified': self.stats['total_verified'], + 'current_proxy': f"{ip}:{port}", + 'message': f'正在爬取:已发现 {count} 个代理' }) if self.stop_requested: @@ -73,7 +80,7 @@ class TasksManager: logger.info(f"爬虫抓取阶段完成,共发现 {count} 个潜在代理。") async def run_validator(self, db: SQLiteManager, validator: ProxyValidator): - await self._notify_status('validating', '开始验证代理啦~') + await self._notify_status('validating_start', '开始验证代理啦~') verified_count = 0 while True: @@ -91,13 +98,13 @@ class TasksManager: verified_count += 1 self.stats['total_verified'] = verified_count - if verified_count % 5 == 0: - await self._notify_progress({ - 'type': 'validating', - 'found': self.stats['total_found'], - 'verified': verified_count, - 'current_proxy': f"{ip}:{port}" - }) + await self._notify_progress({ + 'type': 'validating', + 'found': self.stats['total_found'], + 'verified': verified_count, + 'current_proxy': f"{ip}:{port}", + 'message': f'正在验证:已验证 {verified_count} 个代理' + }) else: logger.info(f"验证失败: {ip}:{port} ({protocol})") except Exception as e: @@ -126,6 +133,8 @@ class TasksManager: 'plugins': [] } + await self._notify_status('connecting', '正在连接插件源...') + await self._notify_status('starting', '正在启动爬虫...') await self._notify_status('running', '任务开始啦~') async with ProxyValidator(max_concurrency=200) as validator: diff --git a/test_results.json b/test_results.json new file mode 100644 index 0000000..ae99e39 --- /dev/null +++ b/test_results.json @@ -0,0 +1,724 @@ +{ + "summary": { + "total_tests": 29, + "passed_tests": 29, + "failed_tests": 0, + "pass_rate": 100.0, + "timestamp": "2026-01-27T23:11:59.292107" + }, + "results": [ + { + "test_name": "GET / - 根路径访问", + "passed": true, + "message": "根路径返回正常", + "timestamp": "2026-01-27T23:11:21.092484", + "response_data": { + "message": "欢迎使用代理池API~", + "status": "running", + "data": null + } + }, + { + "test_name": "GET /health - 健康检查", + "passed": true, + "message": "服务健康状态正常", + "timestamp": "2026-01-27T23:11:23.104732", + "response_data": { + "status": "healthy", + "timestamp": "2026-01-27T23:11:23.104732", + "database": "connected", + "version": "1.0.0" + } + }, + { + "test_name": "GET /api/stats - 统计信息", + "passed": true, + "message": "成功获取统计信息,总数: 220", + "timestamp": "2026-01-27T23:11:25.116587", + "response_data": { + "code": 200, + "message": "获取统计信息成功啦~", + "data": { + "total": 220, + "available": 220, + "avg_score": 10.0, + "http_count": 147, + "https_count": 0, + "socks4_count": 73, + "socks5_count": 0, + "today_new": 220 + } + } + }, + { + "test_name": "GET /api/stats - 字段完整性", + "passed": true, + "message": "所有必需字段都存在", + "timestamp": "2026-01-27T23:11:25.116587", + "response_data": null + }, + { + "test_name": "POST /api/proxies - 基本分页查询", + "passed": true, + "message": "成功获取代理列表,共 220 条", + "timestamp": "2026-01-27T23:11:27.126629", + "response_data": { + "code": 200, + "message": "获取代理列表成功啦~", + "data": { + "list": [ + { + "ip": "120.26.68.107", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:23.000Z" + }, + { + "ip": "169.61.46.13", + "port": 7563, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:23.000Z" + }, + { + "ip": "35.209.198.222", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:21.000Z" + }, + { + "ip": "34.81.160.132", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:21.000Z" + }, + { + "ip": "176.126.164.213", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:19.000Z" + }, + { + "ip": "8.220.136.174", + "port": 5060, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:15.000Z" + }, + { + "ip": "47.86.53.59", + "port": 8080, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:14.000Z" + }, + { + "ip": "40.177.106.156", + "port": 8080, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:10.000Z" + }, + { + "ip": "47.56.110.204", + "port": 8989, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:10.000Z" + }, + { + "ip": "193.53.127.169", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:09.000Z" + }, + { + "ip": "163.172.167.48", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:08.000Z" + }, + { + "ip": "36.67.136.27", + "port": 5678, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:08.000Z" + }, + { + "ip": "162.223.90.144", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:08.000Z" + }, + { + "ip": "104.197.218.238", + "port": 8080, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:59.000Z" + }, + { + "ip": "211.230.49.122", + "port": 3128, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:54.000Z" + }, + { + "ip": "159.195.84.83", + "port": 443, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:53.000Z" + }, + { + "ip": "172.237.73.24", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:52.000Z" + }, + { + "ip": "81.169.213.169", + "port": 8888, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:47.000Z" + }, + { + "ip": "8.220.141.8", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:46.000Z" + }, + { + "ip": "31.28.4.192", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:45.000Z" + } + ], + "total": 220, + "page": 1, + "page_size": 20 + } + } + }, + { + "test_name": "POST /api/proxies - 基本分页查询 - 字段完整性", + "passed": true, + "message": "代理数据字段完整", + "timestamp": "2026-01-27T23:11:27.126629", + "response_data": null + }, + { + "test_name": "POST /api/proxies - 带协议筛选", + "passed": true, + "message": "成功获取代理列表,共 147 条", + "timestamp": "2026-01-27T23:11:29.137101", + "response_data": { + "code": 200, + "message": "获取代理列表成功啦~", + "data": { + "list": [ + { + "ip": "47.89.159.212", + "port": 1080, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:10:27.000Z" + }, + { + "ip": "200.59.186.177", + "port": 999, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:10:26.000Z" + }, + { + "ip": "34.76.142.148", + "port": 80, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:10:22.000Z" + }, + { + "ip": "101.47.16.15", + "port": 7890, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:10:22.000Z" + }, + { + "ip": "212.114.194.72", + "port": 80, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:10:21.000Z" + }, + { + "ip": "8.213.156.191", + "port": 221, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:10:21.000Z" + }, + { + "ip": "191.101.1.116", + "port": 80, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:10:20.000Z" + }, + { + "ip": "51.141.175.118", + "port": 80, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:10:19.000Z" + }, + { + "ip": "213.73.25.230", + "port": 8080, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:10:19.000Z" + }, + { + "ip": "50.203.147.152", + "port": 80, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:10:17.000Z" + } + ], + "total": 147, + "page": 1, + "page_size": 10 + } + } + }, + { + "test_name": "POST /api/proxies - 带协议筛选 - 字段完整性", + "passed": true, + "message": "代理数据字段完整", + "timestamp": "2026-01-27T23:11:29.137101", + "response_data": null + }, + { + "test_name": "POST /api/proxies - 带分数筛选", + "passed": true, + "message": "成功获取代理列表,共 0 条", + "timestamp": "2026-01-27T23:11:31.148007", + "response_data": { + "code": 200, + "message": "获取代理列表成功啦~", + "data": { + "list": [], + "total": 0, + "page": 1, + "page_size": 10 + } + } + }, + { + "test_name": "POST /api/proxies - 带分数筛选 - 空列表", + "passed": true, + "message": "代理列表为空(可能数据库无数据)", + "timestamp": "2026-01-27T23:11:31.148007", + "response_data": { + "code": 200, + "message": "获取代理列表成功啦~", + "data": { + "list": [], + "total": 0, + "page": 1, + "page_size": 10 + } + } + }, + { + "test_name": "POST /api/proxies - 带排序", + "passed": true, + "message": "成功获取代理列表,共 221 条", + "timestamp": "2026-01-27T23:11:33.159151", + "response_data": { + "code": 200, + "message": "获取代理列表成功啦~", + "data": { + "list": [ + { + "ip": "212.114.194.75", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:28.000Z" + }, + { + "ip": "35.209.198.222", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:21.000Z" + }, + { + "ip": "40.177.106.156", + "port": 8080, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:10.000Z" + }, + { + "ip": "163.172.167.48", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:11:08.000Z" + }, + { + "ip": "159.195.84.83", + "port": 443, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:53.000Z" + }, + { + "ip": "31.28.4.192", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:45.000Z" + }, + { + "ip": "108.170.12.10", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:44.000Z" + }, + { + "ip": "35.180.127.14", + "port": 1001, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:42.000Z" + }, + { + "ip": "139.162.200.213", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:42.000Z" + }, + { + "ip": "154.90.48.76", + "port": 80, + "protocol": "socks4", + "score": 10, + "last_check": "2026-01-27T15:10:38.000Z" + } + ], + "total": 221, + "page": 1, + "page_size": 10 + } + } + }, + { + "test_name": "POST /api/proxies - 带排序 - 字段完整性", + "passed": true, + "message": "代理数据字段完整", + "timestamp": "2026-01-27T23:11:33.159151", + "response_data": null + }, + { + "test_name": "POST /api/proxies - 参数验证测试 - 无效协议", + "passed": true, + "message": "参数验证失败,符合预期", + "timestamp": "2026-01-27T23:11:35.168328", + "response_data": { + "detail": [ + { + "type": "value_error", + "loc": [ + "body", + "protocol" + ], + "msg": "Value error, 协议类型必须是 http, https, socks4 或 socks5", + "input": "invalid", + "ctx": { + "error": {} + }, + "url": "https://errors.pydantic.dev/2.12/v/value_error" + } + ] + } + }, + { + "test_name": "POST /api/proxies - 参数验证测试 - page为0", + "passed": true, + "message": "参数验证失败,符合预期", + "timestamp": "2026-01-27T23:11:37.176455", + "response_data": { + "detail": [ + { + "type": "greater_than_equal", + "loc": [ + "body", + "page" + ], + "msg": "Input should be greater than or equal to 1", + "input": 0, + "ctx": { + "ge": 1 + }, + "url": "https://errors.pydantic.dev/2.12/v/greater_than_equal" + } + ] + } + }, + { + "test_name": "POST /api/proxies - 参数验证测试 - page_size超过100", + "passed": true, + "message": "参数验证失败,符合预期", + "timestamp": "2026-01-27T23:11:39.186465", + "response_data": { + "detail": [ + { + "type": "less_than_equal", + "loc": [ + "body", + "page_size" + ], + "msg": "Input should be less than or equal to 100", + "input": 101, + "ctx": { + "le": 100 + }, + "url": "https://errors.pydantic.dev/2.12/v/less_than_equal" + } + ] + } + }, + { + "test_name": "GET /api/proxies/random - 获取随机代理", + "passed": true, + "message": "成功获取随机代理: 176.126.103.194:44214", + "timestamp": "2026-01-27T23:11:41.196335", + "response_data": { + "code": 200, + "message": "获取随机代理成功啦~", + "data": { + "ip": "176.126.103.194", + "port": 44214, + "protocol": "http", + "score": 10, + "last_check": "2026-01-27T15:08:12.000Z" + } + } + }, + { + "test_name": "GET /api/proxies/有效代理", + "passed": true, + "message": "代理不存在(符合预期)", + "timestamp": "2026-01-27T23:11:43.202256", + "response_data": { + "code": 404, + "message": "代理不存在呢~", + "data": null + } + }, + { + "test_name": "GET /api/proxies/不存在的代理", + "passed": true, + "message": "代理不存在(符合预期)", + "timestamp": "2026-01-27T23:11:45.210946", + "response_data": { + "code": 404, + "message": "代理不存在呢~", + "data": null + } + }, + { + "test_name": "GET /api/proxies/export/csv - 导出CSV格式", + "passed": true, + "message": "成功导出CSV格式,内容长度: 552", + "timestamp": "2026-01-27T23:11:47.221104", + "response_data": { + "content_length": 552 + } + }, + { + "test_name": "GET /api/proxies/export/csv - CSV格式验证", + "passed": true, + "message": "CSV格式正确,包含表头", + "timestamp": "2026-01-27T23:11:47.221104", + "response_data": null + }, + { + "test_name": "GET /api/proxies/export/txt - 导出TXT格式", + "passed": true, + "message": "成功导出TXT格式,内容长度: 184", + "timestamp": "2026-01-27T23:11:49.226991", + "response_data": { + "content_length": 184 + } + }, + { + "test_name": "GET /api/proxies/export/txt - TXT格式验证", + "passed": true, + "message": "TXT格式正确", + "timestamp": "2026-01-27T23:11:49.228522", + "response_data": null + }, + { + "test_name": "GET /api/proxies/export/json - 导出JSON格式", + "passed": true, + "message": "成功导出JSON格式,内容长度: 1260", + "timestamp": "2026-01-27T23:11:51.242429", + "response_data": { + "content_length": 1260 + } + }, + { + "test_name": "GET /api/proxies/export/json - JSON格式验证", + "passed": true, + "message": "JSON格式正确", + "timestamp": "2026-01-27T23:11:51.244593", + "response_data": null + }, + { + "test_name": "GET /api/proxies/export/invalid - 无效格式测试", + "passed": true, + "message": "正确返回400错误", + "timestamp": "2026-01-27T23:11:53.258979", + "response_data": null + }, + { + "test_name": "GET /api/crawler/status - 获取爬虫状态", + "passed": true, + "message": "爬虫状态: 运行中", + "timestamp": "2026-01-27T23:11:55.270148", + "response_data": { + "code": 200, + "message": "获取爬虫状态成功啦~", + "data": { + "running": true, + "stats": { + "total_found": 5524, + "total_verified": 4, + "start_time": "2026-01-27T23:06:12.013714", + "current_url": null, + "plugins": [ + "IP3366", + "89免费代理", + "快代理", + "ProxyListDownload", + "SpeedX代理源", + "云代理" + ] + } + } + } + }, + { + "test_name": "GET /api/scheduler - 获取定时任务状态", + "passed": true, + "message": "定时任务状态: 未启用", + "timestamp": "2026-01-27T23:11:57.282485", + "response_data": { + "code": 200, + "message": "获取定时任务状态成功啦~", + "data": { + "enabled": false, + "interval_minutes": 60 + } + } + }, + { + "test_name": "GET /api/plugins - 获取插件列表", + "passed": true, + "message": "成功获取插件列表,共 6 个插件", + "timestamp": "2026-01-27T23:11:59.290536", + "response_data": { + "code": 200, + "message": "获取插件列表成功啦~", + "data": { + "plugins": [ + { + "id": "IP3366", + "name": "IP3366", + "enabled": true, + "description": "从IP3366网站爬取代理", + "last_run": null, + "success_count": 0, + "failure_count": 0 + }, + { + "id": "89免费代理", + "name": "89免费代理", + "enabled": true, + "description": "从89免费代理网站爬取代理", + "last_run": null, + "success_count": 0, + "failure_count": 0 + }, + { + "id": "快代理", + "name": "快代理", + "enabled": true, + "description": "从快代理网站爬取代理", + "last_run": null, + "success_count": 0, + "failure_count": 0 + }, + { + "id": "ProxyListDownload", + "name": "ProxyListDownload", + "enabled": true, + "description": "从ProxyListDownload网站爬取代理", + "last_run": null, + "success_count": 0, + "failure_count": 0 + }, + { + "id": "SpeedX代理源", + "name": "SpeedX代理源", + "enabled": true, + "description": "从SpeedX代理源网站爬取代理", + "last_run": null, + "success_count": 0, + "failure_count": 0 + }, + { + "id": "云代理", + "name": "云代理", + "enabled": true, + "description": "从云代理网站爬取代理", + "last_run": null, + "success_count": 0, + "failure_count": 0 + } + ] + } + } + }, + { + "test_name": "GET /api/plugins - 插件字段完整性", + "passed": true, + "message": "插件数据字段完整", + "timestamp": "2026-01-27T23:11:59.290536", + "response_data": null + } + ] +} \ No newline at end of file