AnlaAnla пре 2 недеља
родитељ
комит
e54a206102
6 измењених фајлова са 155 додато и 4 уклоњено
  1. 65 0
      Test/auto_img_insert.py
  2. 42 2
      app/api/cards.py
  3. 42 0
      app/api/formate_xy.py
  4. 2 2
      app/core/database_loader.py
  5. 2 0
      app/crud/crud_card.py
  6. 2 0
      app/utils/scheme.py

+ 65 - 0
Test/auto_img_insert.py

@@ -0,0 +1,65 @@
+import os
+import requests
+
+
+def auto_import(data, target_url):
+    # 2. 准备文件数据
+    files = []
+    opened_files = []  # 记录已打开的文件柄,便于最后关闭
+    IMAGE_PATHS = data.get("local_paths")
+    try:
+        for field_name, path in IMAGE_PATHS.items():
+            if path and os.path.exists(path):
+                # 以二进制方式打开文件
+                f = open(path, "rb")
+                opened_files.append(f)
+
+                # Request 的 files 格式: ("表单字段名", ("文件名", 文件对象, "MIME类型"))
+                files.append((
+                    field_name,
+                    (os.path.basename(path), f, "image/jpeg")
+                ))
+            else:
+                print(f"[Warning] 图片不存在或未配置跳过: {path}")
+
+        if not files:
+            print("没有找到任何可上传的图片文件,请检查 IMAGE_PATHS 路径。")
+            return
+
+        print(f"开始请求 API: {target_url} ...")
+
+        # 3. 发起 multipart/form-data 请求
+        response = requests.post(target_url, data=data, files=files)
+
+        # 4. 打印结果
+        print(f"Status Code: {response.status_code}")
+        try:
+            print("Response JSON:", response.json())
+        except Exception:
+            print("Response Text:", response.text)
+
+    finally:
+        # 确保所有文件句柄都被关闭
+        for f in opened_files:
+            f.close()
+
+
+if __name__ == '__main__':
+    target_url = f"http://192.168.77.249:7755/api/import/process_and_import"
+    request_data = {
+        "card_name": "测试2345",
+        "cardNo": "fsg453",
+        "card_type": "pokemon",
+        "is_reflect_card": True,
+        "strict_mode": False,  # 若为 True 则必须凑齐上面定义的4张主图
+        "local_paths": {
+            "front_ring": r"C:\Code\ML\Image\Card\testimg\1_front_ring_0_1.jpg",
+            "front_coaxial": r"C:\Code\ML\Image\Card\testimg\1_front_coaxial_1_0.jpg",
+            "back_ring": r"C:\Code\ML\Image\Card\testimg\1_back_ring_0_1.jpg",
+            "back_coaxial": r"C:\Code\ML\Image\Card\testimg\1_back_coaxial_1_0.jpg",
+            "front_gray": None,
+            "back_gray": None
+        }
+    }
+
+    auto_import(request_data, target_url)

+ 42 - 2
app/api/cards.py

@@ -110,6 +110,7 @@ def get_next_card_details(card_id: int, db_conn: PooledMySQLConnection = db_depe
         if isinstance(e, HTTPException): raise e
         raise HTTPException(status_code=500, detail="服务器内部错误,查询数据库失败。")
 
+
 @router.get("/card_list_filter", response_model=CardListResponseWrapper, summary="获取卡牌列表和总数")
 def card_list_filter(
         card_id: Optional[int] = Query(None, description="筛选:卡牌ID"),
@@ -117,6 +118,8 @@ def card_list_filter(
         card_name: Optional[str] = Query(None, description="筛选:卡牌名称"),
         card_type: Optional[CardType] = Query(None, description="筛选:卡牌类型"),
         is_edited: Optional[bool] = Query(None, description="筛选:是否已编辑"),
+        review_state: Optional[int] = Query(None, ge=1, le=4,
+                                            description="筛选:审核状态(1待复检, 2已复检, 3审核未通过, 4审核通过)"),
 
         min_detection_score: Optional[float] = Query(None, ge=0, le=10),
         max_detection_score: Optional[float] = Query(None, ge=0, le=10),
@@ -140,12 +143,12 @@ def card_list_filter(
     结构: { "data": { "total": 100, "list": [...] } }
     """
     if page_num is not None:
-        skip = (page_num-1) * limit
+        skip = (page_num - 1) * limit
 
     try:
         result = crud_card.get_card_list_and_count(
             db_conn,
-            card_id, cardNo, card_name, card_type, is_edited,
+            card_id, cardNo, card_name, card_type, is_edited, review_state,
             min_detection_score, max_detection_score,
             min_modified_score, max_modified_score,
             created_start, created_end,
@@ -212,3 +215,40 @@ def delete_card(id: int, db_conn: PooledMySQLConnection = db_dependency):
         logger.error(f"删除卡牌失败 ({id}): {e}")
         if isinstance(e, HTTPException): raise e
         raise HTTPException(status_code=500, detail="删除卡牌失败。")
+
+
+@router.put("/review_state/{id}", status_code=200, summary="修改卡牌的审核状态")
+def update_review_state(
+        id: int,
+        review_state: int = Query(..., ge=1, le=4, description="审核状态 (1待复检, 2已复检, 3审核未通过, 4审核通过)"),
+        db_conn: PooledMySQLConnection = db_dependency
+):
+    """
+    修改某张卡牌的审核状态。
+
+    review_state 参数说明:
+    - 1: 待复检 (默认状态)
+    - 2: 已复检
+    - 3: 审核未通过
+    - 4: 审核通过
+    """
+    try:
+        with db_conn.cursor() as cursor:
+            # 更新指定 card_id 的 review_state 字段
+            query_update = f"UPDATE {settings.DB_CARD_TABLE_NAME} SET review_state = %s WHERE id = %s"
+            cursor.execute(query_update, (review_state, id))
+
+            if cursor.rowcount == 0:
+                raise HTTPException(status_code=404, detail=f"ID为 {id} 的卡牌未找到。")
+
+            db_conn.commit()
+            logger.info(f"卡牌 ID {id} 的审核状态已成功修改为 {review_state}。")
+
+            return {"message": f"成功修改卡牌 ID {id} 的审核状态为 {review_state}"}
+
+    except Exception as e:
+        db_conn.rollback()
+        logger.error(f"修改卡牌 {id} 审核状态失败: {e}")
+        if isinstance(e, HTTPException):
+            raise e
+        raise HTTPException(status_code=500, detail="修改审核状态失败,数据库操作错误。")

+ 42 - 0
app/api/formate_xy.py

@@ -205,6 +205,27 @@ async def update_image_modified_json(
         except Exception as score_update_e:
             logger.error(f"更新卡牌 {card_id_to_update} 分数失败: {score_update_e}")
 
+        # 更新卡牌审核状态
+        try:
+            with db_conn.cursor() as cursor:
+                review_state = 2
+                # 更新指定 card_id 的 review_state 字段
+                query_update = f"UPDATE {settings.DB_CARD_TABLE_NAME} SET review_state = %s WHERE id = %s"
+                cursor.execute(query_update, (review_state, card_id_to_update))
+
+                if cursor.rowcount == 0:
+                    raise HTTPException(status_code=404, detail=f"ID为 {card_id_to_update} 的卡牌未找到。")
+
+                db_conn.commit()
+                logger.info(f"卡牌 ID {card_id_to_update} 的审核状态已成功修改为 {review_state}。")
+
+        except Exception as e:
+            db_conn.rollback()
+            logger.error(f"修改卡牌 {id} 审核状态失败: {e}")
+            if isinstance(e, HTTPException):
+                raise e
+            raise HTTPException(status_code=500, detail="修改审核状态失败,数据库操作错误。")
+
         return {
             "detail": f"成功更新图片ID {id} 的JSON数据",
             "image_type": image_type,
@@ -358,6 +379,27 @@ async def update_gray_image_json(
         except Exception as e:
             logger.error(f"更新卡牌 {card_id} 分数状态失败: {e}")
 
+        # 更新卡牌审核状态
+        try:
+            with db_conn.cursor() as cursor:
+                review_state = 2
+                # 更新指定 card_id 的 review_state 字段
+                query_update = f"UPDATE {settings.DB_CARD_TABLE_NAME} SET review_state = %s WHERE id = %s"
+                cursor.execute(query_update, (review_state, card_id))
+
+                if cursor.rowcount == 0:
+                    raise HTTPException(status_code=404, detail=f"ID为 {card_id} 的卡牌未找到。")
+
+                db_conn.commit()
+                logger.info(f"卡牌 ID {card_id} 的审核状态已成功修改为 {review_state}。")
+
+        except Exception as e:
+            db_conn.rollback()
+            logger.error(f"修改卡牌 {id} 审核状态失败: {e}")
+            if isinstance(e, HTTPException):
+                raise e
+            raise HTTPException(status_code=500, detail="修改审核状态失败,数据库操作错误。")
+
         return {
             "detail": f"成功应用灰度图修改到 {target_ring_type}",
             "target_ring_id": ring_image_id,

+ 2 - 2
app/core/database_loader.py

@@ -33,6 +33,7 @@ def init_database():
             "  `detection_score` DECIMAL(4, 2) NULL,"
             "  `modified_score` DECIMAL(4, 2) NULL,"
             "  `is_edited` BOOLEAN NOT NULL DEFAULT FALSE,"
+            "  `review_state` TINYINT NOT NULL DEFAULT 1 COMMENT '审核状态(1待复检, 2已复检, 3审核未通过, 4审核通过)',"
             "  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,"
             "  `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
             ") ENGINE=InnoDB COMMENT='存储实体卡牌的核心信息'"
@@ -40,7 +41,6 @@ def init_database():
         cursor.execute(cards_table)
         logger.info(f"数据表 '{settings.DB_CARD_TABLE_NAME}' 已准备就绪。")
 
-
         # 2. 创建 card_images 表 (主要计算图)
         card_images_table = (
             f"CREATE TABLE IF NOT EXISTS `{settings.DB_IMAGE_TABLE_NAME}` ("
@@ -124,4 +124,4 @@ def get_db_connection():
         logger.error(f"获取数据库连接失败: {err}")
     finally:
         if db_conn and db_conn.is_connected():
-            db_conn.close()
+            db_conn.close()

+ 2 - 0
app/crud/crud_card.py

@@ -306,6 +306,7 @@ def get_card_list_and_count(
         card_name: Optional[str],
         card_type: Optional[CardType],
         is_edited: Optional[bool],
+        review_state: Optional[int],
         min_detect_score: Optional[float],
         max_detect_score: Optional[float],
         min_mod_score: Optional[float],
@@ -328,6 +329,7 @@ def get_card_list_and_count(
         if card_name: conditions.append("card_name LIKE %s"); params.append(f"%{card_name}%")
         if card_type: conditions.append("card_type = %s"); params.append(card_type.value)
         if is_edited is not None: conditions.append("is_edited = %s"); params.append(is_edited)
+        if review_state is not None: conditions.append("review_state = %s"); params.append(review_state)
         if min_detect_score is not None: conditions.append("detection_score >= %s"); params.append(min_detect_score)
         if max_detect_score is not None: conditions.append("detection_score <= %s"); params.append(max_detect_score)
         if min_mod_score is not None: conditions.append("modified_score >= %s"); params.append(min_mod_score)

+ 2 - 0
app/utils/scheme.py

@@ -98,6 +98,7 @@ class CardDetailResponse(BaseModel):
     updated_at: datetime
     card_type: str
     is_edited: bool
+    review_state: int = 1
     detection_score: Optional[float] = None
     modified_score: Optional[float] = None
     detection_score_detail: Optional[Dict[str, Any]] = None
@@ -148,6 +149,7 @@ class CardListDetailResponse(BaseModel):
     detection_score: Optional[float] = None
     modified_score: Optional[float] = None
     is_edited: bool
+    review_state: int = 1
     created_at: datetime
     updated_at: datetime
     image_path_list: Dict[str, Optional[str]] = {}