#!/usr/bin/env python3 """查询每个U的单元强化里具体有多少个单点任务 - 完整版(含所有Unit,含A1)""" import os, json import pymysql from collections import defaultdict conn = pymysql.connect( host='bj-cdb-dh2fkqa0.sql.tencentcdb.com', port=27751, user='read_only', password=os.environ.get('MYSQL_ONLINE_PASSWORD', ''), database='vala', charset='utf8mb4' ) cur = conn.cursor() # 1. 获取所有 season_package cur.execute(""" SELECT id, level, season_of_year, season_of_quarter, cn_name FROM vala_game_season_package WHERE deleted_at IS NULL AND is_hide = 0 ORDER BY level, season_of_year, season_of_quarter """) seasons = {} for row in cur.fetchall(): sp_id, level, sy, sq, cn_name = row seasons[sp_id] = {'level': level, 'season_of_year': sy, 'season_of_quarter': sq, 'cn_name': cn_name} # 2. 获取所有 game_info (unit) cur.execute(""" SELECT id, season_package_id, cn_name, `index` FROM vala_game_info WHERE deleted_at IS NULL AND is_hide = 0 ORDER BY season_package_id, `index` """) units = {} for row in cur.fetchall(): gi_id, sp_id, cn_name, idx = row if sp_id in seasons: s = seasons[sp_id] level_display = s['level'].replace('A1', 'L1').replace('A2', 'L2') units[gi_id] = { 'season_package_id': sp_id, 'level': level_display, 'season_of_quarter': s['season_of_quarter'], 'cn_name': cn_name, 'index': idx, 'season_cn_name': s['cn_name'] } # 3. 获取所有 chapter cur.execute(""" SELECT id, game_id, cn_name, `index` FROM vala_game_chapter WHERE deleted_at IS NULL ORDER BY game_id, `index` """) chapters = {} for row in cur.fetchall(): ch_id, gi_id, cn_name, idx = row if gi_id in units: chapters[ch_id] = {'game_id': gi_id, 'cn_name': cn_name, 'index': idx} # 4. 获取所有 section 的 component_config cur.execute(""" SELECT chapter_id, component_config FROM vala_game_chapter_section WHERE deleted_at IS NULL AND component_config IS NOT NULL """) unit_reinforcement = defaultdict(lambda: {'单点任务': 0, '场景对话': 0, '场景时间线': 0, '其他': 0, '总计': 0}) for row in cur.fetchall(): chapter_id, config_json = row if chapter_id not in chapters: continue try: configs = json.loads(config_json) except: continue for comp in configs: comp_type = comp.get('componentType', -1) sub_type = comp.get('subComponentType', -1) if comp_type != 3: continue gi_id = chapters[chapter_id]['game_id'] u = units[gi_id] level = u['level'] sq = u['season_of_quarter'] season_label = f"S{sq}" unit_label = f"U{u['index']:02d}" if u['index'] is not None else "U??" unit_key = f"{level}-{season_label}-{unit_label}" unit_reinforcement[unit_key]['总计'] += 1 if sub_type == 4: unit_reinforcement[unit_key]['单点任务'] += 1 elif sub_type == 6: unit_reinforcement[unit_key]['场景对话'] += 1 elif sub_type == 7: unit_reinforcement[unit_key]['场景时间线'] += 1 else: unit_reinforcement[unit_key]['其他'] += 1 # 5. 构建所有 unit_key 列表(含无强化任务的 Unit) all_unit_keys = [] for gi_id, u in units.items(): level = u['level'] sq = u['season_of_quarter'] season_label = f"S{sq}" unit_label = f"U{u['index']:02d}" if u['index'] is not None else "U??" uk = f"{level}-{season_label}-{unit_label}" all_unit_keys.append((uk, u['cn_name'], u['season_cn_name'])) # 6. 输出 print(f"\n{'Unit':<22} {'单元名称':<18} {'所属季':<12} {'单点任务':>8} {'场景对话':>8} {'场景时间线':>10} {'其他':>6} {'总计':>6}") print("-" * 100) for uk, unit_cn, season_cn in all_unit_keys: d = unit_reinforcement.get(uk, {'单点任务': 0, '场景对话': 0, '场景时间线': 0, '其他': 0, '总计': 0}) if d['总计'] == 0: continue # 跳过无强化任务的 print(f"{uk:<22} {unit_cn:<18} {season_cn:<12} {d['单点任务']:>8} {d['场景对话']:>8} {d['场景时间线']:>10} {d['其他']:>6} {d['总计']:>6}") # 7. 按 Level 汇总 print("\n" + "=" * 100) print("按 Level 汇总") print("=" * 100) level_summary = defaultdict(lambda: {'单点任务': 0, '场景对话': 0, '场景时间线': 0, '其他': 0, '总计': 0, 'units': 0}) for uk, unit_cn, season_cn in all_unit_keys: d = unit_reinforcement.get(uk, {'单点任务': 0, '场景对话': 0, '场景时间线': 0, '其他': 0, '总计': 0}) level = uk.split('-')[0] for k in d: level_summary[level][k] += d[k] if d['总计'] > 0: level_summary[level]['units'] += 1 for level in sorted(level_summary.keys()): d = level_summary[level] print(f"{level}: 有强化任务的Unit={d['units']}个, 单点任务={d['单点任务']}, 场景对话={d['场景对话']}, 场景时间线={d['场景时间线']}, 其他={d['其他']}, 总计={d['总计']}") cur.close() conn.close()