UI优化完善初版

This commit is contained in:
lt
2026-05-01 06:48:21 +08:00
parent e1ba31afda
commit cfb60d7aae
12228 changed files with 1358947 additions and 2593 deletions
+8 -6
View File
@@ -1,14 +1,18 @@
from fastapi import APIRouter, HTTPException, Query
from fastapi import APIRouter, HTTPException, Query, Depends
from pathlib import Path
import os
from datetime import datetime, date
from ..database import get_db
from ..models import User
from .auth import get_current_user
router = APIRouter(prefix="/api/articles", tags=["articles"])
PROJECT_ROOT = Path('/root/openclaw-workspace/projects/yu-zhi-ran')
@router.get("/drafts")
def list_drafts(publish_date: str = None):
def list_drafts(publish_date: str = None, current_user: User = Depends(get_current_user)):
"""列出指定日期的草稿文件(三平台)"""
if not publish_date:
publish_date = date.today().isoformat()
@@ -28,21 +32,19 @@ def list_drafts(publish_date: str = None):
return {"date": publish_date, "files": result}
@router.get("/{topic_id}/preview")
def preview_article(topic_id: str, platform: str = "zhihu", publish_date: str = None):
def preview_article(topic_id: str, platform: str = "zhihu", publish_date: str = None, current_user: User = Depends(get_current_user)):
"""预览某选题的HTML内容"""
if not publish_date:
publish_date = date.today().isoformat()
filename = f"{platform}_{topic_id}_{platform}.html"
file_path = PROJECT_ROOT / "automation" / "data" / "releases" / publish_date / platform / filename
# DEBUG
print(f"[DEBUG] file_path={file_path}, exists={file_path.exists()}")
if not file_path.exists():
raise HTTPException(status_code=404, detail=f"Article not found: {file_path}")
content = file_path.read_text(encoding='utf-8')
return {"topic_id": topic_id, "platform": platform, "html": content}
@router.get("/optimization-report")
def get_optimization_report(publish_date: str = None):
def get_optimization_report(publish_date: str = None, current_user: User = Depends(get_current_user)):
"""获取合规优化报告"""
if not publish_date:
publish_date = date.today().isoformat()
+6
View File
@@ -146,6 +146,12 @@ def get_current_user(request: Request, db: Session = Depends(get_db)) -> User:
token = auth_header.split(" ")[1]
user = verify_token(token, db)
return user
def get_current_admin(current_user: User = Depends(get_current_user)) -> User:
"""依赖项:验证管理员权限"""
if current_user.role != "admin":
raise HTTPException(status_code=403, detail="需要管理员权限")
return current_user
@router.get("/me")
def get_me(
request: Request,
@@ -0,0 +1,71 @@
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.orm import Session
from pathlib import Path
import subprocess
from ..database import get_db
from ..models import User
from .auth import get_current_admin
router = APIRouter(prefix="/api", tags=["optimizer_logs"])
PROJECT_ROOT = Path(__file__).parent.parent.parent.parent.parent
@router.post("/optimizer/run")
def run_optimizer(
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin)
):
"""
触发合规优化器运行(管理员)
"""
try:
body = request.json()
except Exception:
raise HTTPException(status_code=400, detail="Invalid JSON")
topic_id = body.get("topic_id")
if not topic_id:
raise HTTPException(status_code=400, detail="topic_id is required")
script_path = PROJECT_ROOT / "automation" / "scripts" / "compliance_optimizer.py"
if not script_path.exists():
raise HTTPException(status_code=500, detail="Optimizer script not found")
try:
result = subprocess.run(
["python", str(script_path), "--topic-id", topic_id],
capture_output=True,
text=True,
timeout=600,
cwd=PROJECT_ROOT
)
if result.returncode != 0:
raise HTTPException(status_code=500, detail=f"Optimizer failed: {result.stderr}")
return {"ok": True, "message": "Optimization completed", "output": result.stdout}
except subprocess.TimeoutExpired:
raise HTTPException(status_code=500, detail="Optimizer timed out")
@router.get("/logs")
def get_logs(
request: Request,
type: str = None, # creator, optimizer, collector
date: str = None, # YYYY-MM-DD
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin)
):
"""
读取系统日志文件内容(管理员)
"""
if not type or not date:
raise HTTPException(status_code=400, detail="type and date parameters are required")
logs_dir = PROJECT_ROOT / "automation" / "logs"
filename = f"{type}_{date}.log"
log_path = logs_dir / filename
if not log_path.exists():
# 日志文件不存在返回空内容
return {"type": type, "date": date, "content": ""}
try:
content = log_path.read_text(encoding="utf-8")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to read log: {str(e)}")
return {"type": type, "date": date, "content": content}
+8 -20
View File
@@ -5,13 +5,13 @@ from pydantic import BaseModel
from datetime import datetime
from typing import Optional
from app.database import get_db
from app.models import Topic, PublishRecord, User
from ..database import get_db
from ..models import Topic, PublishRecord, User
from sqlalchemy.orm import Session
from .auth import verify_token
from .auth import get_current_admin
from ..core.audit_logger import audit_log
router = APIRouter()
router = APIRouter(prefix="/api/publishing", tags=["publishing"])
class PublishRequest(BaseModel):
topic_id: str
@@ -21,26 +21,14 @@ class PublishResponse(BaseModel):
topic_id: str
message: str
def get_current_user(request: Request, db: Session = Depends(get_db)) -> User:
"""获取当前登录用户(可选,未登录也允许,但记录为 anonymous)"""
auth_header = request.headers.get("Authorization")
if not auth_header or not auth_header.startswith("Bearer "):
return None
token = auth_header.split(" ")[1]
try:
from .auth import verify_token
return verify_token(token, db)
except Exception:
return None
@router.post("/api/publishing/create", response_model=PublishResponse)
@router.post("/create", response_model=PublishResponse)
async def create_publish_record(
req: PublishRequest,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
current_user: User = Depends(get_current_admin)
):
"""标记选题为已发布,并创建发布记录"""
"""标记选题为已发布,并创建发布记录(管理员)"""
try:
# 查找选题
topic = db.query(Topic).filter(Topic.id == req.topic_id).first()
@@ -56,7 +44,7 @@ async def create_publish_record(
topic.published_at = datetime.now().date() # 设置发布时间为今天
# 创建发布记录
operator = current_user.username if current_user else 'anonymous'
operator = current_user.username
record = PublishRecord(
topic_id=req.topic_id,
platform='all',
+9 -9
View File
@@ -29,12 +29,12 @@ def get_status(db: Session = Depends(get_db)):
by_status_result = db.query(Topic.status, func.count()).group_by(Topic.status).all()
by_status = {status: count for status, count in by_status_result}
# 确保返回所有状态
# 确保返回所有状态(数据库存中文,返回前端需要英文)
status_map = {
'pending': by_status.get('pending', 0),
'review': by_status.get('review', 0),
'ready': by_status.get('ready', 0),
'published': by_status.get('published', 0)
'pending': by_status.get('待处理', 0),
'review': by_status.get('待审查', 0),
'ready': by_status.get('待发布', 0),
'published': by_status.get('已发布', 0)
}
# 计算今日新增
@@ -46,10 +46,10 @@ def get_status(db: Session = Depends(get_db)):
return {
"stats": {
"total": total,
"pending": status_map['待处理'],
"review": status_map['待审查'],
"ready": status_map['待发布'],
"published": status_map['已发布'],
"pending": status_map['pending'],
"review": status_map['review'],
"ready": status_map['ready'],
"published": status_map['published'],
"today": today_count
}
}
+3 -2
View File
@@ -9,7 +9,7 @@ from pathlib import Path
from .database import engine, get_db, init_db
from .models import Base
from .api import topics, system, articles, publishing, auth, admin, audit
from .api import topics, system, articles, publishing, auth, admin, audit, optimizer_logs
from .initial_data import import_initial_data
app = FastAPI(title="宇之然内容创作平台", version="0.1.0")
@@ -37,9 +37,10 @@ app.include_router(publishing.router)
app.include_router(auth.router)
app.include_router(admin.router)
app.include_router(audit.router)
app.include_router(optimizer_logs.router)
# 挂载前端
FRONTEND_DIR = Path(__file__).parent.parent / "static"
FRONTEND_DIR = Path(__file__).parent.parent.parent / "frontend"
if FRONTEND_DIR.exists() and (FRONTEND_DIR / "index.html").exists():
app.mount("/", StaticFiles(directory=str(FRONTEND_DIR), html=True), name="frontend")
logger.info(f"Frontend mounted at / from {FRONTEND_DIR}")