crud_card.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. from typing import Optional, List, Dict, Any
  2. from mysql.connector.pooling import PooledMySQLConnection
  3. import json
  4. from datetime import datetime
  5. from app.core.config import settings
  6. from app.utils.scheme import CardImageResponse, CardType, SortBy, SortOrder
  7. from app.utils.card_score_calculate import calculate_scores_from_images
  8. def update_card_scores_and_status(db_conn: PooledMySQLConnection, card_id: int):
  9. """
  10. 根据卡牌关联的图片数量和内容,更新cards表中的分数和状态。
  11. - 如果图片满4张,计算并更新 detection_score, modified_score, is_edited。
  12. - 如果图片不足4张,将分数置为NULL,is_edited置为False。
  13. - 自动更新 updated_at 字段。
  14. """
  15. with db_conn.cursor(dictionary=True) as cursor:
  16. # 1. 获取所有关联图片
  17. query_images = f"SELECT * FROM {settings.DB_IMAGE_TABLE_NAME} WHERE card_id = %s"
  18. cursor.execute(query_images, (card_id,))
  19. image_records = cursor.fetchall()
  20. # 将数据库行转换为Pydantic模型,便于处理JSON
  21. images = [CardImageResponse.model_validate(row) for row in image_records]
  22. # 2. 计算分数和状态
  23. scores_data = calculate_scores_from_images(images)
  24. # 3. 更新 cards 表
  25. # 注意: updated_at 会由数据库自动更新
  26. query_update_card = (
  27. f"UPDATE {settings.DB_CARD_TABLE_NAME} SET "
  28. "detection_score = %s, modified_score = %s, is_edited = %s, updated_at = %s "
  29. "WHERE id = %s"
  30. )
  31. params = (
  32. scores_data["detection_score"],
  33. scores_data["modified_score"],
  34. scores_data["is_edited"],
  35. datetime.now(), # 手动更新时间戳以确保触发
  36. card_id,
  37. )
  38. cursor.execute(query_update_card, params)
  39. db_conn.commit()
  40. def get_card_with_details(db_conn: PooledMySQLConnection, card_id: int) -> Optional[Dict[str, Any]]:
  41. """获取单个卡牌的完整信息,包括预计算的分数和所有图片详情。"""
  42. with db_conn.cursor(dictionary=True) as cursor:
  43. # 1. 获取卡牌信息
  44. query_card = f"SELECT * FROM {settings.DB_CARD_TABLE_NAME} WHERE id = %s"
  45. cursor.execute(query_card, (card_id,))
  46. card_data = cursor.fetchone()
  47. if not card_data:
  48. return None
  49. # 2. 获取所有关联的图片信息
  50. query_images = f"SELECT * FROM {settings.DB_IMAGE_TABLE_NAME} WHERE card_id = %s"
  51. cursor.execute(query_images, (card_id,))
  52. image_records = cursor.fetchall()
  53. images = [CardImageResponse.model_validate(row) for row in image_records]
  54. # 3. 获取分数详情 (如果需要)
  55. # 只有当图片满4张时,分数详情才有意义
  56. score_details = calculate_scores_from_images(images)
  57. card_data.update({
  58. "images": images,
  59. "detection_score_detail": score_details["detection_score_detail"],
  60. "modified_score_detail": score_details["modified_score_detail"]
  61. })
  62. return card_data
  63. def get_card_list_with_images(
  64. db_conn: PooledMySQLConnection,
  65. card_name: Optional[str],
  66. card_type: Optional[CardType],
  67. sort_by: SortBy,
  68. sort_order: SortOrder,
  69. skip: int,
  70. limit: int
  71. ) -> List[Dict[str, Any]]:
  72. """获取带筛选和排序功能的卡牌列表,并附带其关联的图片信息。"""
  73. with db_conn.cursor(dictionary=True) as cursor:
  74. # 1. 构建动态查询
  75. query = f"SELECT * FROM {settings.DB_CARD_TABLE_NAME}"
  76. conditions = []
  77. params = []
  78. if card_name:
  79. conditions.append("card_name LIKE %s")
  80. params.append(f"%{card_name}%")
  81. if card_type:
  82. conditions.append("card_type = %s")
  83. params.append(card_type.value)
  84. if conditions:
  85. query += " WHERE " + " AND ".join(conditions)
  86. # 添加排序和分页
  87. query += f" ORDER BY {sort_by.value} {sort_order.value}, id DESC"
  88. query += " LIMIT %s OFFSET %s"
  89. params.extend([limit, skip])
  90. cursor.execute(query, tuple(params))
  91. cards = cursor.fetchall()
  92. if not cards:
  93. return []
  94. # 2. 一次性获取所有相关卡牌的图片 (避免 N+1 查询)
  95. card_ids = [card['id'] for card in cards]
  96. # 使用 IN 子句和占位符
  97. format_strings = ','.join(['%s'] * len(card_ids))
  98. image_query = (
  99. f"SELECT id, card_id, image_type, image_path, detection_image_path, modified_image_path "
  100. f"FROM {settings.DB_IMAGE_TABLE_NAME} WHERE card_id IN ({format_strings})"
  101. )
  102. cursor.execute(image_query, tuple(card_ids))
  103. images = cursor.fetchall()
  104. # 3. 将图片按 card_id 分组
  105. images_by_card_id = {}
  106. for image in images:
  107. cid = image['card_id']
  108. if cid not in images_by_card_id:
  109. images_by_card_id[cid] = []
  110. images_by_card_id[cid].append(image)
  111. # 4. 将图片附加到对应的卡牌上
  112. for card in cards:
  113. card['images'] = images_by_card_id.get(card['id'], [])
  114. return cards