3.0.0 : Reconstructed Database System.

This commit is contained in:
2026-01-29 02:21:44 +08:00
parent 1642adb00e
commit 04ee957af6
69 changed files with 10258 additions and 6546 deletions

View File

@@ -98,50 +98,8 @@ def detail(steam_id):
return "Player not found", 404
features = FeatureService.get_player_features(steam_id)
# --- New: Fetch Detailed Stats from L2 (Clutch, Multi-Kill, Multi-Assist) ---
sql_l2 = """
SELECT
SUM(p.clutch_1v1) as c1, SUM(p.clutch_1v2) as c2, SUM(p.clutch_1v3) as c3, SUM(p.clutch_1v4) as c4, SUM(p.clutch_1v5) as c5,
SUM(a.attempt_1v1) as att1, SUM(a.attempt_1v2) as att2, SUM(a.attempt_1v3) as att3, SUM(a.attempt_1v4) as att4, SUM(a.attempt_1v5) as att5,
SUM(p.kill_2) as k2, SUM(p.kill_3) as k3, SUM(p.kill_4) as k4, SUM(p.kill_5) as k5,
SUM(p.many_assists_cnt2) as a2, SUM(p.many_assists_cnt3) as a3, SUM(p.many_assists_cnt4) as a4, SUM(p.many_assists_cnt5) as a5,
COUNT(*) as matches,
SUM(p.round_total) as total_rounds
FROM fact_match_players p
LEFT JOIN fact_match_clutch_attempts a ON p.match_id = a.match_id AND p.steam_id_64 = a.steam_id_64
WHERE p.steam_id_64 = ?
"""
l2_stats = query_db('l2', sql_l2, [steam_id], one=True)
l2_stats = dict(l2_stats) if l2_stats else {}
# Fetch T/CT splits for comparison
# Note: We use SUM(clutch...) as Total Clutch Wins. We don't have attempts, so 'Win Rate' is effectively Wins/Rounds or just Wins count.
# User asked for 'Win Rate', but without attempts data, we'll provide Rate per Round or just Count.
# Let's provide Rate per Round for Multi-Kill/Assist, and maybe just Count for Clutch?
# User said: "总残局胜率...分t和ct在下方加入对比".
# Since we found clutch == end in DB, we treat it as Wins. We can't calc Win %.
# We will display "Clutch Wins / Round" or just "Clutch Wins".
sql_side = """
SELECT
'T' as side,
SUM(clutch_1v1+clutch_1v2+clutch_1v3+clutch_1v4+clutch_1v5) as total_clutch,
SUM(kill_2+kill_3+kill_4+kill_5) as total_multikill,
SUM(many_assists_cnt2+many_assists_cnt3+many_assists_cnt4+many_assists_cnt5) as total_multiassist,
SUM(round_total) as rounds
FROM fact_match_players_t WHERE steam_id_64 = ?
UNION ALL
SELECT
'CT' as side,
SUM(clutch_1v1+clutch_1v2+clutch_1v3+clutch_1v4+clutch_1v5) as total_clutch,
SUM(kill_2+kill_3+kill_4+kill_5) as total_multikill,
SUM(many_assists_cnt2+many_assists_cnt3+many_assists_cnt4+many_assists_cnt5) as total_multiassist,
SUM(round_total) as rounds
FROM fact_match_players_ct WHERE steam_id_64 = ?
"""
side_rows = query_db('l2', sql_side, [steam_id, steam_id])
side_stats = {row['side']: dict(row) for row in side_rows} if side_rows else {}
l2_stats = {}
side_stats = {}
# Ensure basic stats fallback if features missing or incomplete
basic = StatsService.get_player_basic_stats(steam_id)
@@ -167,6 +125,47 @@ def detail(steam_id):
if 'basic_avg_adr' not in features or features['basic_avg_adr'] is None:
features['basic_avg_adr'] = basic.get('adr', 0) if basic else 0
try:
matches = int(features.get("matches_played") or 0)
except Exception:
matches = 0
try:
total_rounds = int(features.get("total_rounds") or 0)
except Exception:
total_rounds = 0
def _f(key, default=0.0):
v = features.get(key)
if v is None:
return default
try:
return float(v)
except Exception:
return default
l2_stats = {
"matches": matches,
"total_rounds": total_rounds,
"c1": int(_f("tac_clutch_1v1_wins", 0)),
"att1": int(_f("tac_clutch_1v1_attempts", 0)),
"c2": int(_f("tac_clutch_1v2_wins", 0)),
"att2": int(_f("tac_clutch_1v2_attempts", 0)),
"c3": int(_f("tac_clutch_1v3_plus_wins", 0)),
"att3": int(_f("tac_clutch_1v3_plus_attempts", 0)),
"c4": 0,
"att4": 0,
"c5": 0,
"att5": 0,
"k2": int(round(_f("tac_avg_2k", 0) * max(matches, 0))),
"k3": int(round(_f("tac_avg_3k", 0) * max(matches, 0))),
"k4": int(round(_f("tac_avg_4k", 0) * max(matches, 0))),
"k5": int(round(_f("tac_avg_5k", 0) * max(matches, 0))),
"a2": 0,
"a3": 0,
"a4": 0,
"a5": 0,
}
comments = WebService.get_comments('player', steam_id)
metadata = WebService.get_player_metadata(steam_id)
@@ -203,7 +202,7 @@ def detail(steam_id):
map_stats_list.sort(key=lambda x: x['matches'], reverse=True)
# --- New: Recent Performance Stats ---
recent_stats = StatsService.get_recent_performance_stats(steam_id)
# recent_stats = StatsService.get_recent_performance_stats(steam_id)
return render_template('players/profile.html',
player=player,
@@ -214,8 +213,7 @@ def detail(steam_id):
distribution=distribution,
map_stats=map_stats_list,
l2_stats=l2_stats,
side_stats=side_stats,
recent_stats=recent_stats)
side_stats=side_stats)
@bp.route('/comment/<int:comment_id>/like', methods=['POST'])
def like_comment(comment_id):
@@ -234,7 +232,7 @@ def charts_data(steam_id):
radar_dist = FeatureService.get_roster_features_distribution(steam_id)
if features:
# Dimensions: STA, BAT, HPS, PTL, T/CT, UTIL
# Dimensions: AIM, DEFENSE, UTILITY, CLUTCH, ECONOMY, PACE (6 Dimensions)
# Use calculated scores (0-100 scale)
# Helper to get score safely
@@ -243,14 +241,14 @@ def charts_data(steam_id):
return float(val) if val else 0
radar_data = {
'STA': get_score('score_sta'),
'BAT': get_score('score_bat'),
'HPS': get_score('score_hps'),
'PTL': get_score('score_ptl'),
'SIDE': get_score('score_tct'),
'UTIL': get_score('score_util'),
'ECO': get_score('score_eco'),
'PACE': get_score('score_pace')
'AIM': get_score('score_aim'),
'DEFENSE': get_score('score_defense'),
'UTILITY': get_score('score_utility'),
'CLUTCH': get_score('score_clutch'),
'ECONOMY': get_score('score_economy'),
'PACE': get_score('score_pace'),
'PISTOL': get_score('score_pistol'),
'STABILITY': get_score('score_stability')
}
trend_labels = []