migrate_add_background_images.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. """
  2. 数据库迁移脚本:创建背景图片相关表并初始化数据
  3. 运行: python migrate_add_background_images.py
  4. """
  5. import asyncio
  6. import sys
  7. from typing import Any
  8. import aiomysql
  9. from config import settings
  10. async def migrate_create_background_images_tables() -> bool:
  11. """创建背景图片相关表并初始化数据"""
  12. try:
  13. conn: aiomysql.Connection = await aiomysql.connect(
  14. host=settings.MYSQL_HOST,
  15. port=settings.MYSQL_PORT,
  16. user=settings.MYSQL_USER,
  17. password=settings.MYSQL_PASSWORD,
  18. db=settings.MYSQL_DATABASE,
  19. charset="utf8mb4",
  20. )
  21. async with conn.cursor() as cursor:
  22. # 1. 检查并创建 background_images 表
  23. await cursor.execute(
  24. """
  25. SELECT COUNT(*) FROM information_schema.tables
  26. WHERE table_schema = %s AND table_name = 'background_images'
  27. """,
  28. (settings.MYSQL_DATABASE,),
  29. )
  30. exists_row: Any = await cursor.fetchone()
  31. bg_images_exists = bool(exists_row and exists_row[0] > 0)
  32. if not bg_images_exists:
  33. print("🔄 创建 background_images 表...")
  34. await cursor.execute(
  35. """
  36. CREATE TABLE background_images (
  37. id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
  38. image_id VARCHAR(64) NOT NULL UNIQUE COMMENT '背景图片唯一标识',
  39. image_name VARCHAR(100) NOT NULL COMMENT '背景图片名称',
  40. image_url VARCHAR(500) NOT NULL COMMENT '背景图片URL',
  41. thumbnail_url VARCHAR(500) NULL COMMENT '缩略图URL',
  42. unlock_type ENUM('default', 'level', 'purchase', 'mission') NOT NULL DEFAULT 'default' COMMENT '解锁类型',
  43. unlock_level INT NULL COMMENT '解锁所需等级(unlock_type=level时)',
  44. unlock_mission_type VARCHAR(64) NULL COMMENT '解锁所需任务类型(unlock_type=mission时)',
  45. display_order INT NOT NULL DEFAULT 0 COMMENT '显示顺序',
  46. is_active TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
  47. description VARCHAR(255) NULL COMMENT '背景图片描述',
  48. metadata JSON NULL COMMENT '扩展配置',
  49. created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  50. updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  51. INDEX idx_image_id (image_id),
  52. INDEX idx_unlock_type (unlock_type),
  53. INDEX idx_display_order (display_order)
  54. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='背景图片配置表';
  55. """
  56. )
  57. print("✅ background_images 表创建完成")
  58. else:
  59. print("✅ background_images 表已存在")
  60. # 2. 检查并创建 user_background_images 表
  61. await cursor.execute(
  62. """
  63. SELECT COUNT(*) FROM information_schema.tables
  64. WHERE table_schema = %s AND table_name = 'user_background_images'
  65. """,
  66. (settings.MYSQL_DATABASE,),
  67. )
  68. exists_row = await cursor.fetchone()
  69. user_bg_images_exists = bool(exists_row and exists_row[0] > 0)
  70. if not user_bg_images_exists:
  71. print("🔄 创建 user_background_images 表...")
  72. await cursor.execute(
  73. """
  74. CREATE TABLE user_background_images (
  75. id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
  76. user_id VARCHAR(64) NOT NULL COMMENT '用户ID',
  77. image_id VARCHAR(64) NOT NULL COMMENT '背景图片ID',
  78. obtained_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '获得时间',
  79. obtained_type ENUM('default', 'level_up', 'purchase', 'mission', 'gift') NOT NULL DEFAULT 'default' COMMENT '获得方式',
  80. obtained_source VARCHAR(64) NULL COMMENT '获得来源(任务类型、等级等)',
  81. metadata JSON NULL COMMENT '扩展信息',
  82. created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  83. UNIQUE KEY uk_user_background_image (user_id, image_id),
  84. INDEX idx_user_id (user_id),
  85. INDEX idx_image_id (image_id),
  86. INDEX idx_user_obtained (user_id, obtained_at)
  87. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户背景图片关联表';
  88. """
  89. )
  90. print("✅ user_background_images 表创建完成")
  91. else:
  92. print("✅ user_background_images 表已存在")
  93. # 3. 检查并添加 users 表的 current_background_image_id 字段
  94. await cursor.execute(
  95. """
  96. SELECT COUNT(*) FROM information_schema.columns
  97. WHERE table_schema = %s
  98. AND table_name = 'users'
  99. AND column_name = 'current_background_image_id'
  100. """,
  101. (settings.MYSQL_DATABASE,),
  102. )
  103. exists_row = await cursor.fetchone()
  104. column_exists = bool(exists_row and exists_row[0] > 0)
  105. if not column_exists:
  106. print("🔄 为 users 表添加 current_background_image_id 字段...")
  107. await cursor.execute(
  108. """
  109. ALTER TABLE users
  110. ADD COLUMN current_background_image_id VARCHAR(64) NULL COMMENT '当前使用的背景图片ID'
  111. AFTER last_active_at
  112. """
  113. )
  114. print("✅ current_background_image_id 字段添加完成")
  115. else:
  116. print("✅ current_background_image_id 字段已存在")
  117. await conn.commit()
  118. # 4. 初始化背景图片数据
  119. print("🔄 初始化背景图片数据...")
  120. # 检查默认背景图片是否存在
  121. await cursor.execute(
  122. "SELECT COUNT(*) FROM background_images WHERE image_id = 'default'"
  123. )
  124. default_exists = (await cursor.fetchone())[0] > 0
  125. if not default_exists:
  126. await cursor.execute(
  127. """
  128. INSERT INTO background_images
  129. (image_id, image_name, image_url, unlock_type, display_order, description)
  130. VALUES
  131. ('default', '默认背景', 'https://assets.lyrria.com/init.jpg', 'default', 1, '默认背景图片')
  132. """
  133. )
  134. print("✅ 默认背景图片已添加")
  135. else:
  136. print("✅ 默认背景图片已存在")
  137. # 检查新年背景图片是否存在
  138. await cursor.execute(
  139. "SELECT COUNT(*) FROM background_images WHERE image_id = 'happynewyear'"
  140. )
  141. newyear_exists = (await cursor.fetchone())[0] > 0
  142. if not newyear_exists:
  143. await cursor.execute(
  144. """
  145. INSERT INTO background_images
  146. (image_id, image_name, image_url, unlock_type, display_order, description)
  147. VALUES
  148. ('happynewyear', '新年背景', 'https://assets.lyrria.com/bg-happynewyear.png', 'default', 2, '新年背景图片')
  149. """
  150. )
  151. print("✅ 新年背景图片已添加")
  152. else:
  153. print("✅ 新年背景图片已存在")
  154. await conn.commit()
  155. # 5. 为所有现有用户设置默认背景图片
  156. print("🔄 为现有用户设置默认背景图片...")
  157. # 更新所有用户的 current_background_image_id 为 'default'(如果为 NULL)
  158. await cursor.execute(
  159. """
  160. UPDATE users
  161. SET current_background_image_id = 'default'
  162. WHERE current_background_image_id IS NULL
  163. """
  164. )
  165. updated_users = cursor.rowcount
  166. print(f"✅ 已为 {updated_users} 个用户设置默认背景图片")
  167. # 6. 为所有现有用户添加默认背景图片到已获得列表
  168. print("🔄 为现有用户添加默认背景图片到已获得列表...")
  169. await cursor.execute(
  170. """
  171. INSERT IGNORE INTO user_background_images
  172. (user_id, image_id, obtained_type, obtained_source)
  173. SELECT user_id, 'default', 'default', 'system_init'
  174. FROM users
  175. """
  176. )
  177. added_records = cursor.rowcount
  178. print(f"✅ 已为 {added_records} 个用户添加默认背景图片到已获得列表")
  179. await conn.commit()
  180. print("✅ 迁移完成")
  181. await conn.ensure_closed()
  182. return True
  183. except Exception as exc: # noqa: BLE001
  184. import traceback
  185. print(f"❌ 迁移失败: {exc}")
  186. traceback.print_exc()
  187. return False
  188. if __name__ == "__main__":
  189. if len(sys.argv) > 1 and sys.argv[1] == "--force":
  190. confirm = "y"
  191. else:
  192. confirm = input("\n是否继续创建背景图片相关表并初始化数据? (y/n): ")
  193. if confirm.lower() != "y":
  194. sys.exit(0)
  195. ok = asyncio.run(migrate_create_background_images_tables())
  196. if not ok:
  197. sys.exit(1)