feat: 完善前端页面 - 新增数据分析、素材库、创作任务、平台配置页面
- 新增 metrics.html: 数据分析页面 (Dashboard, 趋势图, 平台对比, 选题推荐) - 新增 assets.html: 素材库页面 (上传/管理/预览/标签) - 新增 tasks.html: 创作任务页面 (任务列表/进度/详情) - 新增 platforms.html: 平台配置页面 (知乎/微信/小红书格式规则) - 更新导航组件: 添加新页面入口, 适配 H5 底部导航 - 修复 calendar.html: 使用本地 Vue/ElementPlus 资源 - 修复 assets.py: db.func.count -> sqlalchemy.func.count - 新增 test_api_unit.py: 后端 API 单元测试 - 新增 test_frontend.sh: 前端页面完整性测试 PC/H5 双端适配, 所有页面统一使用 navbar + navigation 组件
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python3
|
||||
"""后端 API 单元测试"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
BASE_URL = "http://localhost:8001"
|
||||
|
||||
try:
|
||||
import requests
|
||||
except ImportError:
|
||||
os.system("pip install requests -q")
|
||||
import requests
|
||||
|
||||
def get_token():
|
||||
resp = requests.post(f"{BASE_URL}/api/auth/login", json={"username": "admin", "password": "admin123"})
|
||||
if resp.status_code == 200:
|
||||
return resp.json()["token"]
|
||||
return None
|
||||
|
||||
def headers(token):
|
||||
return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
|
||||
def test(name, fn):
|
||||
print(f"\n🔹 {name}")
|
||||
try:
|
||||
fn()
|
||||
print(f" ✅ PASS")
|
||||
return True
|
||||
except AssertionError as e:
|
||||
print(f" ❌ FAIL: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f" ❌ ERROR: {e}")
|
||||
return False
|
||||
|
||||
class TestMetricsAPI:
|
||||
def __init__(self, token):
|
||||
self.token = token
|
||||
|
||||
def run(self):
|
||||
r = requests.get(f"{BASE_URL}/api/metrics/dashboard", headers=headers(self.token))
|
||||
assert r.status_code == 200, f"Expected 200, got {r.status_code}"
|
||||
data = r.json()
|
||||
assert "total_topics" in data
|
||||
print(f" - 选题总数: {data.get('total_topics', 0)}")
|
||||
return True
|
||||
|
||||
class TestAssetsAPI:
|
||||
def __init__(self, token):
|
||||
self.token = token
|
||||
|
||||
def run(self):
|
||||
r = requests.get(f"{BASE_URL}/api/assets", headers=headers(self.token))
|
||||
assert r.status_code == 200, f"Expected 200, got {r.status_code}"
|
||||
print(f" - 素材列表获取成功")
|
||||
|
||||
r = requests.get(f"{BASE_URL}/api/assets/tags", headers=headers(self.token))
|
||||
assert r.status_code == 200
|
||||
print(f" - 标签列表获取成功")
|
||||
|
||||
r = requests.get(f"{BASE_URL}/api/assets/counts", headers=headers(self.token))
|
||||
assert r.status_code == 200
|
||||
print(f" - 素材统计获取成功")
|
||||
return True
|
||||
|
||||
class TestTasksAPI:
|
||||
def __init__(self, token):
|
||||
self.token = token
|
||||
|
||||
def run(self):
|
||||
r = requests.get(f"{BASE_URL}/api/tasks", headers=headers(self.token))
|
||||
assert r.status_code == 200, f"Expected 200, got {r.status_code}"
|
||||
print(f" - 任务列表获取成功")
|
||||
|
||||
r = requests.get(f"{BASE_URL}/api/tasks/active", headers=headers(self.token))
|
||||
assert r.status_code == 200
|
||||
print(f" - 活跃任务获取成功")
|
||||
return True
|
||||
|
||||
class TestPlatformConfigAPI:
|
||||
def __init__(self, token):
|
||||
self.token = token
|
||||
|
||||
def run(self):
|
||||
r = requests.get(f"{BASE_URL}/api/platform-config", headers=headers(self.token))
|
||||
assert r.status_code == 200, f"Expected 200, got {r.status_code}"
|
||||
data = r.json()
|
||||
print(f" - 平台配置列表: {len(data)} 个平台")
|
||||
return True
|
||||
|
||||
class TestTopicConfigAPI:
|
||||
def __init__(self, token):
|
||||
self.token = token
|
||||
|
||||
def run(self):
|
||||
r = requests.get(f"{BASE_URL}/api/topic-config/fields", headers=headers(self.token))
|
||||
assert r.status_code == 200, f"Expected 200, got {r.status_code}"
|
||||
data = r.json()
|
||||
print(f" - 领域配置: {len(data)} 个")
|
||||
return True
|
||||
|
||||
class TestCalendarAPI:
|
||||
def __init__(self, token):
|
||||
self.token = token
|
||||
|
||||
def run(self):
|
||||
now = time.localtime()
|
||||
year, month = now.tm_year, now.tm_mon
|
||||
r = requests.get(f"{BASE_URL}/api/calendar?year={year}&month={month}", headers=headers(self.token))
|
||||
assert r.status_code == 200, f"Expected 200, got {r.status_code}"
|
||||
print(f" - 内容日历获取成功")
|
||||
return True
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("宇之然平台 - 后端 API 单元测试")
|
||||
print("=" * 60)
|
||||
|
||||
token = get_token()
|
||||
if not token:
|
||||
print("\n❌ 登录失败,无法获取 token")
|
||||
return 1
|
||||
|
||||
print(f"\n🔑 登录成功")
|
||||
|
||||
results = []
|
||||
results.append(test("数据分析 API", TestMetricsAPI(token).run))
|
||||
results.append(test("素材库 API", TestAssetsAPI(token).run))
|
||||
results.append(test("创作任务 API", TestTasksAPI(token).run))
|
||||
results.append(test("平台配置 API", TestPlatformConfigAPI(token).run))
|
||||
results.append(test("选题配置 API", TestTopicConfigAPI(token).run))
|
||||
results.append(test("内容日历 API", TestCalendarAPI(token).run))
|
||||
|
||||
passed = sum(results)
|
||||
total = len(results)
|
||||
print("\n" + "=" * 60)
|
||||
print(f"测试结果: {passed}/{total} 通过")
|
||||
print("=" * 60)
|
||||
return 0 if passed == total else 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user