|
@@ -1,5 +1,6 @@
|
|
|
import requests
|
|
import requests
|
|
|
import json
|
|
import json
|
|
|
|
|
+from enum import Enum
|
|
|
|
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, Body
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, Body
|
|
|
from fastapi.concurrency import run_in_threadpool
|
|
from fastapi.concurrency import run_in_threadpool
|
|
@@ -21,6 +22,12 @@ router = APIRouter()
|
|
|
db_dependency = Depends(get_db_connection)
|
|
db_dependency = Depends(get_db_connection)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+class QueryMode(str, Enum):
|
|
|
|
|
+ current = "current"
|
|
|
|
|
+ next = "next"
|
|
|
|
|
+ prev = "prev"
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
def _process_images_to_xy_format(card_data: dict):
|
|
def _process_images_to_xy_format(card_data: dict):
|
|
|
"""
|
|
"""
|
|
|
内部辅助函数:遍历卡牌数据中的图片,将 JSON 格式转换为前端需要的 XY 格式。
|
|
内部辅助函数:遍历卡牌数据中的图片,将 JSON 格式转换为前端需要的 XY 格式。
|
|
@@ -46,98 +53,58 @@ def _process_images_to_xy_format(card_data: dict):
|
|
|
return card_data
|
|
return card_data
|
|
|
|
|
|
|
|
|
|
|
|
|
-@router.get("/query", response_model=CardDetailResponse, summary="获取指定卡牌的详细信息(格式化xy)")
|
|
|
|
|
-def get_card_details(card_id: int, db_conn: PooledMySQLConnection = db_dependency):
|
|
|
|
|
- """
|
|
|
|
|
- 获取卡牌元数据以及所有与之关联的图片信息。
|
|
|
|
|
- 【特殊处理】:会将 json 中的 points 坐标转换为 [{"id":..., "x":..., "y":...}] 格式。
|
|
|
|
|
|
|
+@router.get("/query", response_model=CardDetailResponse, summary="获取卡牌详细信息(格式化xy), 支持前后翻页")
|
|
|
|
|
+def get_card_details(
|
|
|
|
|
+ card_id: int = Query(..., description="基准卡牌ID"),
|
|
|
|
|
+ mode: QueryMode = Query(QueryMode.current, description="查询模式: current(当前), next(下一个), prev(上一个)"),
|
|
|
|
|
+ db_conn: PooledMySQLConnection = db_dependency
|
|
|
|
|
+):
|
|
|
"""
|
|
"""
|
|
|
- # 1. 获取原始数据
|
|
|
|
|
- card_data = crud_card.get_card_with_details(db_conn, card_id)
|
|
|
|
|
-
|
|
|
|
|
- if not card_data:
|
|
|
|
|
- raise HTTPException(status_code=404, detail=f"ID为 {card_id} 的卡牌未找到。")
|
|
|
|
|
-
|
|
|
|
|
- # 2. 转换格式 (提取为公共函数)
|
|
|
|
|
- _process_images_to_xy_format(card_data)
|
|
|
|
|
-
|
|
|
|
|
- # 3. 验证并返回
|
|
|
|
|
- return CardDetailResponse.model_validate(card_data)
|
|
|
|
|
-
|
|
|
|
|
|
|
+ 获取卡牌元数据以及所有与之关联的图片信息,并将坐标转换为 xy 格式。
|
|
|
|
|
|
|
|
-@router.get("/query_next", response_model=CardDetailResponse, summary="获取下一个卡牌的详细信息(格式化xy)")
|
|
|
|
|
-def get_next_card_details(card_id: int, db_conn: PooledMySQLConnection = db_dependency):
|
|
|
|
|
- """
|
|
|
|
|
- 获取指定ID的下一张卡牌的信息,并格式化为xy坐标结构。
|
|
|
|
|
|
|
+ - **current**: 查询 card_id 对应的卡牌。
|
|
|
|
|
+ - **next**: 查询 ID 比 card_id 大的第一张卡牌。
|
|
|
|
|
+ - **prev**: 查询 ID 比 card_id 小的第一张卡牌。
|
|
|
"""
|
|
"""
|
|
|
- try:
|
|
|
|
|
- with db_conn.cursor(dictionary=True) as cursor:
|
|
|
|
|
- # 1. 查询下一个ID (ID > current ORDER BY ID ASC)
|
|
|
|
|
- query_next = (
|
|
|
|
|
- f"SELECT id FROM {settings.DB_CARD_TABLE_NAME} "
|
|
|
|
|
- f"WHERE id > %s ORDER BY id ASC LIMIT 1"
|
|
|
|
|
- )
|
|
|
|
|
- cursor.execute(query_next, (card_id,))
|
|
|
|
|
- row = cursor.fetchone()
|
|
|
|
|
-
|
|
|
|
|
- if not row:
|
|
|
|
|
- # 保持与 cards.py 一致的行为,没有下一张时返回 200 或 404 视业务需求定,这里参考 cards.py 逻辑
|
|
|
|
|
- raise HTTPException(status_code=200, detail=f"没有下一张")
|
|
|
|
|
-
|
|
|
|
|
- next_card_id = row['id']
|
|
|
|
|
-
|
|
|
|
|
- # 2. 获取数据
|
|
|
|
|
- card_data = crud_card.get_card_with_details(db_conn, next_card_id)
|
|
|
|
|
- if not card_data:
|
|
|
|
|
- raise HTTPException(status_code=404, detail=f"下一个卡牌ID {next_card_id} 数据异常。")
|
|
|
|
|
-
|
|
|
|
|
- # 3. 转换格式
|
|
|
|
|
- _process_images_to_xy_format(card_data)
|
|
|
|
|
-
|
|
|
|
|
- return CardDetailResponse.model_validate(card_data)
|
|
|
|
|
|
|
+ target_id = card_id
|
|
|
|
|
|
|
|
- except HTTPException:
|
|
|
|
|
- raise
|
|
|
|
|
- except Exception as e:
|
|
|
|
|
- logger.error(f"查询下一个卡牌(xy)失败 (基准ID: {card_id}): {e}")
|
|
|
|
|
- raise HTTPException(status_code=500, detail="查询失败")
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-@router.get("/query_prev", response_model=CardDetailResponse, summary="获取上一个卡牌的详细信息(格式化xy)")
|
|
|
|
|
-def get_prev_card_details(card_id: int, db_conn: PooledMySQLConnection = db_dependency):
|
|
|
|
|
- """
|
|
|
|
|
- 获取指定ID的上一张卡牌的信息,并格式化为xy坐标结构。
|
|
|
|
|
- """
|
|
|
|
|
- try:
|
|
|
|
|
- with db_conn.cursor(dictionary=True) as cursor:
|
|
|
|
|
- # 1. 查询上一个ID (ID < current ORDER BY ID DESC)
|
|
|
|
|
- query_prev = (
|
|
|
|
|
- f"SELECT id FROM {settings.DB_CARD_TABLE_NAME} "
|
|
|
|
|
- f"WHERE id < %s ORDER BY id DESC LIMIT 1"
|
|
|
|
|
- )
|
|
|
|
|
- cursor.execute(query_prev, (card_id,))
|
|
|
|
|
- row = cursor.fetchone()
|
|
|
|
|
-
|
|
|
|
|
- if not row:
|
|
|
|
|
- raise HTTPException(status_code=200, detail=f"没有上一张")
|
|
|
|
|
-
|
|
|
|
|
- prev_card_id = row['id']
|
|
|
|
|
|
|
+ # 1. 如果是查询上一个或下一个,先计算目标ID
|
|
|
|
|
+ if mode != QueryMode.current:
|
|
|
|
|
+ try:
|
|
|
|
|
+ with db_conn.cursor(dictionary=True) as cursor:
|
|
|
|
|
+ if mode == QueryMode.next:
|
|
|
|
|
+ query = (f"SELECT id FROM {settings.DB_CARD_TABLE_NAME} "
|
|
|
|
|
+ f"WHERE id > %s ORDER BY id ASC LIMIT 1")
|
|
|
|
|
+ else: # mode == QueryMode.prev
|
|
|
|
|
+ query = (f"SELECT id FROM {settings.DB_CARD_TABLE_NAME} "
|
|
|
|
|
+ f"WHERE id < %s ORDER BY id DESC LIMIT 1")
|
|
|
|
|
+
|
|
|
|
|
+ cursor.execute(query, (card_id,))
|
|
|
|
|
+ row = cursor.fetchone()
|
|
|
|
|
+
|
|
|
|
|
+ if not row:
|
|
|
|
|
+ # 按照项目习惯,找不到上/下一个时返回 200 + 提示信息,或根据需求改为 404
|
|
|
|
|
+ msg = "没有下一张" if mode == QueryMode.next else "没有上一张"
|
|
|
|
|
+ raise HTTPException(status_code=200, detail=msg)
|
|
|
|
|
+
|
|
|
|
|
+ target_id = row['id']
|
|
|
|
|
+ except HTTPException:
|
|
|
|
|
+ raise
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"查询卡牌ID失败 (Mode: {mode}, BaseID: {card_id}): {e}")
|
|
|
|
|
+ raise HTTPException(status_code=500, detail="数据库查询失败")
|
|
|
|
|
|
|
|
- # 2. 获取数据
|
|
|
|
|
- card_data = crud_card.get_card_with_details(db_conn, prev_card_id)
|
|
|
|
|
- if not card_data:
|
|
|
|
|
- raise HTTPException(status_code=404, detail=f"上一个卡牌ID {prev_card_id} 数据异常。")
|
|
|
|
|
|
|
+ # 2. 获取目标卡牌的详细数据 (Dict 格式)
|
|
|
|
|
+ card_data = crud_card.get_card_with_details(db_conn, target_id)
|
|
|
|
|
|
|
|
- # 3. 转换格式
|
|
|
|
|
- _process_images_to_xy_format(card_data)
|
|
|
|
|
|
|
+ if not card_data:
|
|
|
|
|
+ raise HTTPException(status_code=404, detail=f"ID为 {target_id} 的卡牌未找到。")
|
|
|
|
|
|
|
|
- return CardDetailResponse.model_validate(card_data)
|
|
|
|
|
|
|
+ # 3. 遍历图片,转换格式 (使用抽取出的辅助函数)
|
|
|
|
|
+ _process_images_to_xy_format(card_data)
|
|
|
|
|
|
|
|
- except HTTPException:
|
|
|
|
|
- raise
|
|
|
|
|
- except Exception as e:
|
|
|
|
|
- logger.error(f"查询上一个卡牌(xy)失败 (基准ID: {card_id}): {e}")
|
|
|
|
|
- raise HTTPException(status_code=500, detail="查询失败")
|
|
|
|
|
|
|
+ # 4. 验证并返回
|
|
|
|
|
+ return CardDetailResponse.model_validate(card_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.put("/update/json/{id}", status_code=200, summary="接收xy格式, 还原后重计算分数并保存")
|
|
@router.put("/update/json/{id}", status_code=200, summary="接收xy格式, 还原后重计算分数并保存")
|
|
@@ -232,4 +199,4 @@ async def update_image_modified_json(
|
|
|
raise HTTPException(status_code=500, detail=f"更新JSON数据失败: {e}")
|
|
raise HTTPException(status_code=500, detail=f"更新JSON数据失败: {e}")
|
|
|
finally:
|
|
finally:
|
|
|
if cursor:
|
|
if cursor:
|
|
|
- cursor.close()
|
|
|
|
|
|
|
+ cursor.close()
|