185 lines
6.1 KiB
Python
185 lines
6.1 KiB
Python
# app/routers/home_experts.py
|
||
# 已迁移到新栏目体系(columns/articles),post_id 语义现在指向 Article.id
|
||
from typing import List, Union, Optional
|
||
from fastapi import APIRouter, Depends, HTTPException
|
||
from pydantic import BaseModel
|
||
from sqlalchemy.orm import Session
|
||
|
||
from app.database import get_db
|
||
from app.models.home_expert import HomeExpert
|
||
from app.models.article import Article
|
||
from app.models.admin import Admin
|
||
from app.auth import get_current_admin
|
||
|
||
router = APIRouter()
|
||
|
||
|
||
# Schemas
|
||
class HomeExpertCreate(BaseModel):
|
||
post_id: int # 语义:article.id
|
||
sort_order: int = 0
|
||
is_enabled: bool = True
|
||
|
||
|
||
class HomeExpertUpdate(BaseModel):
|
||
post_id: Optional[int] = None
|
||
sort_order: Optional[int] = None
|
||
is_enabled: Optional[bool] = None
|
||
|
||
|
||
class HomeExpertResponse(BaseModel):
|
||
code: int = 200
|
||
data: Union[dict, list] = None
|
||
message: str = "success"
|
||
|
||
|
||
# Helper
|
||
|
||
def expert_to_dict(expert: HomeExpert, article: Article = None) -> dict:
|
||
"""转换为字典。保持对外字段名 `post` 不变,避免破坏前端展示。"""
|
||
result = {
|
||
"id": expert.id,
|
||
"post_id": expert.post_id,
|
||
"sort_order": expert.sort_order,
|
||
"is_enabled": expert.is_enabled,
|
||
}
|
||
if article:
|
||
result["post"] = {
|
||
"id": article.id,
|
||
"title": article.title,
|
||
"slug": article.slug,
|
||
"summary": article.summary,
|
||
"cover_image": article.cover_image,
|
||
"column_id": article.column_id,
|
||
# 兼容老字段名
|
||
"category_id": article.column_id,
|
||
}
|
||
return result
|
||
|
||
|
||
# Public routes
|
||
@router.get("/home-experts", response_model=HomeExpertResponse)
|
||
def get_public_experts(
|
||
limit: int = 6,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""访客端:获取启用的专家团队(关联已发布的文章)"""
|
||
experts = db.query(HomeExpert).filter(
|
||
HomeExpert.is_enabled == True
|
||
).order_by(HomeExpert.sort_order.asc()).limit(limit).all()
|
||
|
||
result = []
|
||
for expert in experts:
|
||
article = db.query(Article).filter(
|
||
Article.id == expert.post_id,
|
||
Article.status == "published"
|
||
).first()
|
||
if article:
|
||
result.append(expert_to_dict(expert, article))
|
||
return HomeExpertResponse(data=result)
|
||
|
||
|
||
# Admin routes
|
||
@router.get("/admin/home-experts", response_model=HomeExpertResponse)
|
||
def get_admin_experts(
|
||
db: Session = Depends(get_db),
|
||
current_admin: Admin = Depends(get_current_admin)
|
||
):
|
||
"""后台:获取所有专家团队(含文章信息)"""
|
||
experts = db.query(HomeExpert).order_by(HomeExpert.sort_order.asc()).all()
|
||
result = []
|
||
for expert in experts:
|
||
article = db.query(Article).filter(Article.id == expert.post_id).first()
|
||
result.append(expert_to_dict(expert, article))
|
||
return HomeExpertResponse(data=result)
|
||
|
||
|
||
@router.get("/admin/home-experts/available-posts", response_model=HomeExpertResponse)
|
||
def get_available_posts(
|
||
keyword: Optional[str] = None,
|
||
db: Session = Depends(get_db),
|
||
current_admin: Admin = Depends(get_current_admin)
|
||
):
|
||
"""后台:获取可选的已发布文章列表(供挑选作为专家)"""
|
||
query = db.query(Article).filter(Article.status == "published")
|
||
|
||
if keyword:
|
||
query = query.filter(Article.title.contains(keyword))
|
||
|
||
articles = query.order_by(Article.created_at.desc()).limit(50).all()
|
||
return HomeExpertResponse(data=[
|
||
{
|
||
"id": a.id,
|
||
"title": a.title,
|
||
"slug": a.slug,
|
||
"summary": a.summary,
|
||
"cover_image": a.cover_image,
|
||
"column_id": a.column_id,
|
||
"created_at": a.created_at.isoformat() if a.created_at else None,
|
||
}
|
||
for a in articles
|
||
])
|
||
|
||
|
||
@router.post("/admin/home-experts", response_model=HomeExpertResponse)
|
||
def create_expert(
|
||
request: HomeExpertCreate,
|
||
db: Session = Depends(get_db),
|
||
current_admin: Admin = Depends(get_current_admin)
|
||
):
|
||
"""添加一篇文章为专家团队成员"""
|
||
article = db.query(Article).filter(Article.id == request.post_id).first()
|
||
if not article:
|
||
raise HTTPException(status_code=404, detail="资讯不存在")
|
||
|
||
existing = db.query(HomeExpert).filter(HomeExpert.post_id == request.post_id).first()
|
||
if existing:
|
||
raise HTTPException(status_code=400, detail="该资讯已添加到专家团队")
|
||
|
||
expert = HomeExpert(
|
||
post_id=request.post_id,
|
||
sort_order=request.sort_order,
|
||
is_enabled=request.is_enabled,
|
||
)
|
||
db.add(expert)
|
||
db.commit()
|
||
db.refresh(expert)
|
||
return HomeExpertResponse(message="添加成功", data=expert_to_dict(expert, article))
|
||
|
||
|
||
@router.put("/admin/home-experts/{expert_id}", response_model=HomeExpertResponse)
|
||
def update_expert(
|
||
expert_id: int,
|
||
request: HomeExpertUpdate,
|
||
db: Session = Depends(get_db),
|
||
current_admin: Admin = Depends(get_current_admin)
|
||
):
|
||
"""更新专家团队条目"""
|
||
expert = db.query(HomeExpert).filter(HomeExpert.id == expert_id).first()
|
||
if not expert:
|
||
raise HTTPException(status_code=404, detail="专家不存在")
|
||
|
||
for field, value in request.dict(exclude_unset=True).items():
|
||
setattr(expert, field, value)
|
||
|
||
db.commit()
|
||
db.refresh(expert)
|
||
article = db.query(Article).filter(Article.id == expert.post_id).first()
|
||
return HomeExpertResponse(message="更新成功", data=expert_to_dict(expert, article))
|
||
|
||
|
||
@router.delete("/admin/home-experts/{expert_id}", response_model=HomeExpertResponse)
|
||
def delete_expert(
|
||
expert_id: int,
|
||
db: Session = Depends(get_db),
|
||
current_admin: Admin = Depends(get_current_admin)
|
||
):
|
||
"""从首页专家团队移除(不删除原文章)"""
|
||
expert = db.query(HomeExpert).filter(HomeExpert.id == expert_id).first()
|
||
if not expert:
|
||
raise HTTPException(status_code=404, detail="专家不存在")
|
||
|
||
db.delete(expert)
|
||
db.commit()
|
||
return HomeExpertResponse(message="移除成功")
|