feat: 当月热门笑话 + 统计面板,删除首页清除筛选按钮
- 后端新增 GET /api/jokes/hot-monthly(当月浏览量 top 10) - 后端新增 GET /api/jokes/stats(公开统计:总数/审核/待审/浏览等) - 右侧栏热门改为当月热门笑话 - 右侧栏新增网站统计区(笑话总数/已审核/待审核/总浏览) - 首页删除清除筛选按钮
This commit is contained in:
+61
-20
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
import random
|
||||
from datetime import datetime
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy import func, text
|
||||
@@ -161,26 +162,6 @@ def list_jokes(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{joke_id}", response_model=JokeResponse)
|
||||
def get_joke(joke_id: int, db: Session = Depends(get_db)):
|
||||
"""获取单条笑话详情"""
|
||||
# 只返回已审核通过的笑话
|
||||
joke = db.query(Joke).filter(
|
||||
Joke.id == joke_id,
|
||||
Joke.status == "approved"
|
||||
).first()
|
||||
if not joke:
|
||||
raise HTTPException(status_code=404, detail="笑话不存在")
|
||||
# 使用原子更新避免并发竞态
|
||||
db.query(Joke).filter(Joke.id == joke_id).update({Joke.view_count: Joke.view_count + 1})
|
||||
db.commit()
|
||||
# 重新查询获取更新后的数据
|
||||
db.refresh(joke)
|
||||
# 批量加载类型和人群名称
|
||||
type_map, crowd_map = _batch_load_categories(db, [joke])
|
||||
return joke_to_response(joke, type_map, crowd_map)
|
||||
|
||||
|
||||
@router.get("/random", response_model=JokeResponse)
|
||||
def get_random_joke(db: Session = Depends(get_db)):
|
||||
"""随机获取一条已审核通过的笑话"""
|
||||
@@ -208,6 +189,66 @@ def get_random_joke(db: Session = Depends(get_db)):
|
||||
return joke_to_response(joke, type_map, crowd_map)
|
||||
|
||||
|
||||
@router.get("/hot-monthly")
|
||||
def hot_monthly_jokes(db: Session = Depends(get_db)):
|
||||
"""当月热门笑话:本月浏览量最高的前 10 条"""
|
||||
now = datetime.now()
|
||||
start_of_month = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||
jokes = (
|
||||
db.query(Joke)
|
||||
.filter(
|
||||
Joke.status == "approved",
|
||||
Joke.created_at >= start_of_month,
|
||||
)
|
||||
.order_by(Joke.view_count.desc())
|
||||
.limit(10)
|
||||
.all()
|
||||
)
|
||||
type_map, crowd_map = _batch_load_categories(db, jokes)
|
||||
return [joke_to_response(j, type_map, crowd_map) for j in jokes]
|
||||
|
||||
|
||||
@router.get("/stats")
|
||||
def public_stats(db: Session = Depends(get_db)):
|
||||
"""公开统计数据:笑话总数、审核/待审/拒绝数量、总浏览/赞/踩"""
|
||||
total = db.query(Joke).count()
|
||||
approved = db.query(Joke).filter(Joke.status == "approved").count()
|
||||
pending = db.query(Joke).filter(Joke.status == "pending").count()
|
||||
rejected = db.query(Joke).filter(Joke.status == "rejected").count()
|
||||
total_views = db.query(Joke).with_entities(func.sum(Joke.view_count)).scalar() or 0
|
||||
total_likes = db.query(Joke).with_entities(func.sum(Joke.like_count)).scalar() or 0
|
||||
total_dislikes = db.query(Joke).with_entities(func.sum(Joke.dislike_count)).scalar() or 0
|
||||
return {
|
||||
"total_jokes": total,
|
||||
"approved_jokes": approved,
|
||||
"pending_jokes": pending,
|
||||
"rejected_jokes": rejected,
|
||||
"total_views": total_views,
|
||||
"total_likes": total_likes,
|
||||
"total_dislikes": total_dislikes,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{joke_id}", response_model=JokeResponse)
|
||||
def get_joke(joke_id: int, db: Session = Depends(get_db)):
|
||||
"""获取单条笑话详情"""
|
||||
# 只返回已审核通过的笑话
|
||||
joke = db.query(Joke).filter(
|
||||
Joke.id == joke_id,
|
||||
Joke.status == "approved"
|
||||
).first()
|
||||
if not joke:
|
||||
raise HTTPException(status_code=404, detail="笑话不存在")
|
||||
# 使用原子更新避免并发竞态
|
||||
db.query(Joke).filter(Joke.id == joke_id).update({Joke.view_count: Joke.view_count + 1})
|
||||
db.commit()
|
||||
# 重新查询获取更新后的数据
|
||||
db.refresh(joke)
|
||||
# 批量加载类型和人群名称
|
||||
type_map, crowd_map = _batch_load_categories(db, [joke])
|
||||
return joke_to_response(joke, type_map, crowd_map)
|
||||
|
||||
|
||||
def _vote_joke(joke_id: int, field: str, db: Session):
|
||||
"""通用投票逻辑:点赞或点踩(仅允许已审核通过的笑话)"""
|
||||
joke = db.query(Joke).filter(
|
||||
|
||||
Reference in New Issue
Block a user