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()