table_game/backend/app/routers/user_game.py
2025-03-10 08:35:19 +08:00

427 lines
13 KiB
Python

from fastapi import APIRouter, HTTPException, Depends
from typing import List, Optional
from pydantic import BaseModel, Field
from ..utils.jwt_handler import verify_token
from ..services.admin_game_service import get_connection
router = APIRouter()
class GameListRequest(BaseModel):
game_type: int
class GameListResponseForUser(BaseModel):
game_id: int
game_name: str
photo_url: str
game_type: int
tags: List[str]
class GameSearchRequest(BaseModel):
search_name: str
class GameDetailResponse(BaseModel):
game_id: int
game_name: str
photo_url: str
game_type: int
description: str
duration: str
difficulty_level: int
recommended_players: str
remaining_quantity: int
tags: List[str]
long_description: str
class GameDetailRequest(BaseModel):
game_id: int
class TagResponse(BaseModel):
tag_id: int
tag_name: str
class TagGameRequest(BaseModel):
tag_ids: List[int]
class GameReviewCreate(BaseModel):
token: str
game_id: int
rating: int = Field(..., gt=0, le=10)
comment: Optional[str] = None
class GameReviewResponse(BaseModel):
user_name: str
rating: int
comment: Optional[str] = None
created_at: str
class GameReviewsResponse(BaseModel):
support_count: int
oppose_count: int
reviews: List[GameReviewResponse]
class GetUserRatingRequest(BaseModel):
token: str
game_id: int
class GetUserRatingResponse(BaseModel):
rating: int
class UpdateUserRatingRequest(BaseModel):
token: str
game_id: int
good: int
async def get_current_user(token: str):
try:
payload = verify_token(token)
return payload
except ValueError as e:
raise HTTPException(status_code=401, detail=str(e))
@router.post("/search", response_model=List[GameListResponseForUser])
def search_games(request: GameSearchRequest):
"""搜索游戏"""
connection = get_connection()
cursor = connection.cursor(dictionary=True)
try:
cursor.execute("""
SELECT g.*, GROUP_CONCAT(t.tag_name) as tags
FROM games g
LEFT JOIN game_tags gt ON g.game_id = gt.game_id
LEFT JOIN tags t ON gt.tag_id = t.tag_id
WHERE g.game_name LIKE %s AND is_available = 1 # 移除 game_type 条件
GROUP BY g.game_id
""", (f"%{request.search_name}%",)) # 参数减少为一个
return [parse_game_with_tags(row) for row in cursor.fetchall()]
finally:
cursor.close()
connection.close()
@router.post("/detail", response_model=GameDetailResponse)
def get_game_detail(request: GameDetailRequest):
"""获取游戏详情"""
connection = get_connection()
cursor = connection.cursor(dictionary=True)
try:
cursor.execute("""
SELECT g.*,
(g.quantity - COALESCE((
SELECT SUM(quantity)
FROM orders
WHERE game_id = g.game_id
AND order_status IN ('in_progress')
), 0)) as remaining_quantity,
GROUP_CONCAT(t.tag_name) as tags
FROM games g
LEFT JOIN game_tags gt ON g.game_id = gt.game_id
LEFT JOIN tags t ON gt.tag_id = t.tag_id
WHERE g.game_id = %s
GROUP BY g.game_id
""", (request.game_id,))
row = cursor.fetchone()
return parse_game_detail(row)
finally:
cursor.close()
connection.close()
def parse_game_with_tags(row):
return {
"game_id": row["game_id"],
"game_name": row["game_name"],
"photo_url": row["photo_url"] or "",
"game_type": row["game_type"],
"tags": row["tags"].split(',') if row["tags"] else []
}
def parse_game_detail(row):
return {
"game_id": row["game_id"],
"game_name": row["game_name"],
"photo_url": row["photo_url"] or "",
"game_type": row["game_type"],
"description": row["description"],
"duration": row["duration"],
"long_description": row["long_description"] or "",
"difficulty_level": row["difficulty_level"],
"recommended_players": f"{row['min_players']}-{row['max_players']}",
"remaining_quantity": row["remaining_quantity"],
"tags": row["tags"].split(',') if row["tags"] else []
}
@router.get("/tags", response_model=List[TagResponse])
def get_all_tags():
"""获取所有标签"""
connection = get_connection()
cursor = connection.cursor(dictionary=True)
try:
cursor.execute("SELECT tag_id, tag_name FROM tags")
return [{"tag_id": row["tag_id"], "tag_name": row["tag_name"]} for row in cursor.fetchall()]
finally:
cursor.close()
connection.close()
@router.post("/by_tag", response_model=List[GameListResponseForUser])
def get_games_by_tag(request: TagGameRequest):
"""根据多个标签获取游戏列表(空列表时返回所有游戏)"""
connection = get_connection()
cursor = connection.cursor(dictionary=True)
try:
base_query = """
SELECT g.*, GROUP_CONCAT(t.tag_name) as tags
FROM games g
LEFT JOIN game_tags gt ON g.game_id = gt.game_id
LEFT JOIN tags t ON gt.tag_id = t.tag_id
WHERE is_available = 1
"""
# 动态构建查询条件
params = []
if request.tag_ids:
in_params = ', '.join(['%s'] * len(request.tag_ids))
base_query += f" AND gt.tag_id IN ({in_params})"
params.extend(request.tag_ids)
base_query += " GROUP BY g.game_id HAVING COUNT(DISTINCT gt.tag_id) = %s"
params.append(len(request.tag_ids))
else:
base_query += " GROUP BY g.game_id"
cursor.execute(base_query, tuple(params))
return [parse_game_with_tags(row) for row in cursor.fetchall()]
finally:
cursor.close()
connection.close()
# 在路由部分添加新接口
@router.post("/review")
def create_game_review(request: GameReviewCreate):
"""提交游戏评价"""
connection = get_connection()
cursor = connection.cursor(dictionary=True)
try:
payload = verify_token(request.token)
cursor.execute("SELECT user_id FROM users WHERE phone_number = %s", (payload["sub"],))
user = cursor.fetchone()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
user_id = user['user_id']
# 修正参数为元组格式
cursor.execute("""
INSERT INTO player_reviews
(user_id, game_id, rating, comment)
VALUES (%s, %s, %s, %s)
""",(user_id, request.game_id, request.rating, request.comment)) # 用单个元组包裹参数
connection.commit()
return {"message": "评价提交成功"}
finally:
cursor.close()
connection.close()
@router.post("/reviews", response_model=GameReviewsResponse)
def get_game_reviews(request: GameDetailRequest):
"""获取游戏评价"""
connection = get_connection()
cursor = connection.cursor(dictionary=True)
try:
# 获取拉数和踩数
cursor.execute("""
SELECT
SUM(CASE WHEN rating = 1 THEN 1 ELSE 0 END) as support_count,
SUM(CASE WHEN rating = 0 THEN 1 ELSE 0 END) as oppose_count
FROM user_game_rating
WHERE game_id = %s
""", (request.game_id,))
count_result = cursor.fetchone()
support_count = int(count_result['support_count']) if count_result and count_result['support_count'] else 0
oppose_count = int(count_result['oppose_count']) if count_result and count_result['oppose_count'] else 0
# 获取有评论的评价列表
cursor.execute("""
SELECT
u.username,
pr.rating,
pr.comment,
pr.created_at
FROM player_reviews pr
JOIN users u ON pr.user_id = u.user_id
WHERE pr.game_id = %s AND pr.comment IS NOT NULL
GROUP BY pr.review_id
""", (request.game_id,))
results = cursor.fetchall()
# 处理返回结果
reviews = [{
"user_name": row['username'],
"rating": row['rating'],
"comment": row['comment'],
"created_at": str(row['created_at'])
} for row in results]
return {
"support_count": support_count,
"oppose_count": oppose_count,
"reviews": reviews
}
finally:
cursor.close()
connection.close()
@router.post("/user-rating", response_model=GetUserRatingResponse)
def get_user_rating(request: GetUserRatingRequest):
"""获取用户对游戏的拉踩状态"""
connection = get_connection()
cursor = connection.cursor(dictionary=True)
try:
payload = verify_token(request.token)
cursor.execute("SELECT user_id FROM users WHERE phone_number = %s", (payload["sub"],))
user = cursor.fetchone()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
user_id = user['user_id']
# 查询用户对游戏的拉踩状态
cursor.execute("""
SELECT rating
FROM user_game_rating
WHERE user_id = %s AND game_id = %s
""", (user_id, request.game_id))
rating_result = cursor.fetchone()
if rating_result:
rating = rating_result['rating']
else:
rating = 3
return {"rating": rating}
finally:
cursor.close()
connection.close()
@router.post("/update-user-rating")
def update_user_rating(request: UpdateUserRatingRequest):
"""更新用户对游戏的拉踩记录"""
connection = get_connection()
cursor = connection.cursor(dictionary=True)
try:
payload = verify_token(request.token)
cursor.execute("SELECT user_id FROM users WHERE phone_number = %s", (payload["sub"],))
user = cursor.fetchone()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
user_id = user['user_id']
# 检查是否已有记录
cursor.execute("""
SELECT id
FROM user_game_rating
WHERE user_id = %s AND game_id = %s
""", (user_id, request.game_id))
record = cursor.fetchone()
if record:
if request.good == 3:
# 删除记录
cursor.execute("""
DELETE FROM user_game_rating
WHERE user_id = %s AND game_id = %s
""", (user['user_id'], request.game_id))
else:
# 更新记录
cursor.execute("""
UPDATE user_game_rating
SET rating = %s
WHERE user_id = %s AND game_id = %s
""", (request.good, user['user_id'], request.game_id))
else:
if request.good != 3:
# 插入新记录
cursor.execute("""
INSERT INTO user_game_rating (user_id, game_id, rating)
VALUES (%s, %s, %s)
""", (user['user_id'], request.game_id, request.good))
connection.commit()
return {"message": "拉踩记录更新成功"}
finally:
cursor.close()
connection.close()
class MessageCreate(BaseModel):
token: str
message: str
class MessageResponse(BaseModel):
message_id: int
username: str
message_content: str
created_at: str
@router.post("/messages")
def create_message(request: MessageCreate):
"""创建用户留言"""
connection = get_connection()
cursor = connection.cursor(dictionary=True)
try:
payload = verify_token(request.token)
cursor.execute("SELECT user_id FROM users WHERE phone_number = %s", (payload["sub"],))
user = cursor.fetchone()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
user_id = user['user_id']
# 插入留言
cursor.execute(
"""INSERT INTO player_messages
(user_id, message_content)
VALUES (%s, %s)""",
(user_id, request.message)
)
connection.commit()
return {"message": "留言提交成功"}
finally:
cursor.close()
connection.close()
@router.get("/messages", response_model=list[MessageResponse])
def get_messages():
"""获取最新10条留言"""
connection = get_connection()
cursor = connection.cursor(dictionary=True)
try:
cursor.execute("""
SELECT m.message_id, u.username, m.message_content, m.created_at
FROM player_messages m
JOIN users u ON m.user_id = u.user_id
ORDER BY m.created_at DESC
LIMIT 10
""")
return cursor.fetchall()
finally:
cursor.close()
connection.close()