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:
lt
2026-05-08 23:35:26 +08:00
parent cf5103bbca
commit 526278589b
9 changed files with 1430 additions and 4 deletions
+146
View File
@@ -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())