1.3.1: Removed unused scripts.
This commit is contained in:
@@ -98,6 +98,49 @@ 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(clutch_1v1) as c1, SUM(clutch_1v2) as c2, SUM(clutch_1v3) as c3, SUM(clutch_1v4) as c4, SUM(clutch_1v5) as c5,
|
||||
SUM(kill_2) as k2, SUM(kill_3) as k3, SUM(kill_4) as k4, SUM(kill_5) as k5,
|
||||
SUM(many_assists_cnt2) as a2, SUM(many_assists_cnt3) as a3, SUM(many_assists_cnt4) as a4, SUM(many_assists_cnt5) as a5,
|
||||
COUNT(*) as matches,
|
||||
SUM(round_total) as total_rounds
|
||||
FROM fact_match_players
|
||||
WHERE 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 {}
|
||||
|
||||
# Ensure basic stats fallback if features missing or incomplete
|
||||
basic = StatsService.get_player_basic_stats(steam_id)
|
||||
|
||||
@@ -157,7 +200,16 @@ def detail(steam_id):
|
||||
})
|
||||
map_stats_list.sort(key=lambda x: x['matches'], reverse=True)
|
||||
|
||||
return render_template('players/profile.html', player=player, features=features, comments=comments, metadata=metadata, history=history, distribution=distribution, map_stats=map_stats_list)
|
||||
return render_template('players/profile.html',
|
||||
player=player,
|
||||
features=features,
|
||||
comments=comments,
|
||||
metadata=metadata,
|
||||
history=history,
|
||||
distribution=distribution,
|
||||
map_stats=map_stats_list,
|
||||
l2_stats=l2_stats,
|
||||
side_stats=side_stats)
|
||||
|
||||
@bp.route('/comment/<int:comment_id>/like', methods=['POST'])
|
||||
def like_comment(comment_id):
|
||||
|
||||
@@ -295,9 +295,7 @@ class FeatureService:
|
||||
SUM(first_death) as sum_fd,
|
||||
SUM(clutch_1v1) as sum_1v1,
|
||||
SUM(clutch_1v2) as sum_1v2,
|
||||
SUM(clutch_1v3) as sum_1v3,
|
||||
SUM(clutch_1v4) as sum_1v4,
|
||||
SUM(clutch_1v5) as sum_1v5,
|
||||
SUM(clutch_1v3) + SUM(clutch_1v4) + SUM(clutch_1v5) as sum_1v3p,
|
||||
SUM(kill_2) as sum_2k,
|
||||
SUM(kill_3) as sum_3k,
|
||||
SUM(kill_4) as sum_4k,
|
||||
@@ -342,15 +340,6 @@ class FeatureService:
|
||||
df['basic_avg_kill_3'] = df['sum_3k'] / df['matches_played']
|
||||
df['basic_avg_kill_4'] = df['sum_4k'] / df['matches_played']
|
||||
df['basic_avg_kill_5'] = df['sum_5k'] / df['matches_played']
|
||||
|
||||
# New Metrics
|
||||
df['basic_multi_kill_rate'] = (df['sum_2k'] + df['sum_3k'] + df['sum_4k'] + df['sum_5k']) / df['rounds_played'].replace(0, 1)
|
||||
df['basic_total_1v1'] = df['sum_1v1']
|
||||
df['basic_total_1v2'] = df['sum_1v2']
|
||||
df['basic_total_1v3'] = df['sum_1v3']
|
||||
df['basic_total_1v4'] = df['sum_1v4']
|
||||
df['basic_total_1v5'] = df['sum_1v5']
|
||||
|
||||
df['basic_avg_assisted_kill'] = df['sum_assist'] / df['matches_played']
|
||||
df['basic_avg_perfect_kill'] = df['sum_perfect'] / df['matches_played']
|
||||
df['basic_avg_revenge_kill'] = df['sum_revenge'] / df['matches_played']
|
||||
|
||||
@@ -147,11 +147,11 @@
|
||||
<span>📊</span> 详细数据面板 (Detailed Stats)
|
||||
</h3>
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-y-6 gap-x-4">
|
||||
{% macro detail_item(label, value, key, format_str='{:.2f}', sublabel=None) %}
|
||||
{% macro detail_item(label, value, key, format_str='{:.2f}', sublabel=None, count_label=None) %}
|
||||
{% set dist = distribution[key] if distribution else None %}
|
||||
<div class="flex flex-col group relative">
|
||||
<div class="flex flex-col group relative h-full">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<span class="text-xs font-bold text-gray-400 uppercase tracking-wider">{{ label }}</span>
|
||||
<span class="text-xs font-bold text-gray-400 uppercase tracking-wider truncate" title="{{ label }}">{{ label }}</span>
|
||||
{% if dist %}
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-bold
|
||||
{% if dist.rank == 1 %}bg-yellow-50 text-yellow-700 border border-yellow-100
|
||||
@@ -186,6 +186,13 @@
|
||||
<span>H:{{ format_str.format(dist.max) }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Count Label (Bottom Right) -->
|
||||
{% if count_label is not none %}
|
||||
<div class="absolute bottom-0 right-0 text-[10px] font-bold text-gray-400 font-mono">
|
||||
{{ count_label }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -222,16 +229,8 @@
|
||||
{{ detail_item('3K Rounds (三杀)', features['basic_avg_kill_3'], 'basic_avg_kill_3') }}
|
||||
{{ detail_item('4K Rounds (四杀)', features['basic_avg_kill_4'], 'basic_avg_kill_4') }}
|
||||
{{ detail_item('5K Rounds (五杀)', features['basic_avg_kill_5'], 'basic_avg_kill_5') }}
|
||||
{{ detail_item('Multi-Kill % (多杀率)', features['basic_multi_kill_rate'], 'basic_multi_kill_rate', '{:.1%}') }}
|
||||
|
||||
<!-- Row 6: Clutch -->
|
||||
{{ detail_item('1v1 Wins (1v1胜)', features['basic_total_1v1'], 'basic_total_1v1', '{:.0f}') }}
|
||||
{{ detail_item('1v2 Wins (1v2胜)', features['basic_total_1v2'], 'basic_total_1v2', '{:.0f}') }}
|
||||
{{ detail_item('1v3 Wins (1v3胜)', features['basic_total_1v3'], 'basic_total_1v3', '{:.0f}') }}
|
||||
{{ detail_item('1v4 Wins (1v4胜)', features['basic_total_1v4'], 'basic_total_1v4', '{:.0f}') }}
|
||||
{{ detail_item('1v5 Wins (1v5胜)', features['basic_total_1v5'], 'basic_total_1v5', '{:.0f}') }}
|
||||
|
||||
<!-- Row 7: Special -->
|
||||
<!-- Row 6: Special -->
|
||||
{{ detail_item('Perfect Kills (无伤杀)', features['basic_avg_perfect_kill'], 'basic_avg_perfect_kill') }}
|
||||
{{ detail_item('Revenge Kills (复仇杀)', features['basic_avg_revenge_kill'], 'basic_avg_revenge_kill') }}
|
||||
</div>
|
||||
@@ -296,15 +295,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Group 5: SPECIAL (Clutch & Multi) -->
|
||||
<div>
|
||||
<h4 class="text-xs font-black text-gray-400 uppercase tracking-widest mb-4 border-b border-gray-100 dark:border-slate-700 pb-2">
|
||||
SPECIAL (Clutch & Multi)
|
||||
</h4>
|
||||
{% set rounds = l2_stats.get('total_rounds', 0) or 1 %}
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-y-6 gap-x-4">
|
||||
{{ detail_item('1v1 Win%', (l2_stats.get('c1', 0) or 0) / rounds, 'l2_c1', '{:.1%}', count_label=l2_stats.get('c1', 0)) }}
|
||||
{{ detail_item('1v2 Win%', (l2_stats.get('c2', 0) or 0) / rounds, 'l2_c2', '{:.1%}', count_label=l2_stats.get('c2', 0)) }}
|
||||
{{ detail_item('1v3 Win%', (l2_stats.get('c3', 0) or 0) / rounds, 'l2_c3', '{:.1%}', count_label=l2_stats.get('c3', 0)) }}
|
||||
{{ detail_item('1v4 Win%', (l2_stats.get('c4', 0) or 0) / rounds, 'l2_c4', '{:.1%}', count_label=l2_stats.get('c4', 0)) }}
|
||||
{{ detail_item('1v5 Win%', (l2_stats.get('c5', 0) or 0) / rounds, 'l2_c5', '{:.1%}', count_label=l2_stats.get('c5', 0)) }}
|
||||
|
||||
{% set mk_count = (l2_stats.get('k2', 0) or 0) + (l2_stats.get('k3', 0) or 0) + (l2_stats.get('k4', 0) or 0) + (l2_stats.get('k5', 0) or 0) %}
|
||||
{% set ma_count = (l2_stats.get('a2', 0) or 0) + (l2_stats.get('a3', 0) or 0) + (l2_stats.get('a4', 0) or 0) + (l2_stats.get('a5', 0) or 0) %}
|
||||
|
||||
{{ detail_item('Multi-Kill Rate', mk_count / rounds, 'l2_mk', '{:.1%}', count_label=mk_count) }}
|
||||
{{ detail_item('Multi-Assist Rate', ma_count / rounds, 'l2_ma', '{:.1%}', count_label=ma_count) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Group 4: SIDE (T/CT Preference) -->
|
||||
<div>
|
||||
<h4 class="text-xs font-black text-gray-400 uppercase tracking-widest mb-4 border-b border-gray-100 dark:border-slate-700 pb-2">
|
||||
SIDE (T/CT Preference)
|
||||
</h4>
|
||||
|
||||
{% macro vs_item(label, t_key, ct_key, format_str='{:.2f}') %}
|
||||
{% set t_val = features[t_key] or 0 %}
|
||||
{% set ct_val = features[ct_key] or 0 %}
|
||||
{% macro vs_item_val(label, t_val, ct_val, format_str='{:.2f}') %}
|
||||
{% set diff = ct_val - t_val %}
|
||||
|
||||
{# Dynamic Sizing #}
|
||||
@@ -367,6 +385,10 @@
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro vs_item(label, t_key, ct_key, format_str='{:.2f}') %}
|
||||
{{ vs_item_val(label, features[t_key] or 0, features[ct_key] or 0, format_str) }}
|
||||
{% endmacro %}
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{{ vs_item('Rating (Rating/KD)', 'side_rating_t', 'side_rating_ct') }}
|
||||
{{ vs_item('KD Ratio', 'side_kd_t', 'side_kd_ct') }}
|
||||
@@ -375,8 +397,23 @@
|
||||
{{ vs_item('First Death Rate (首死率)', 'side_first_death_rate_t', 'side_first_death_rate_ct', '{:.1%}') }}
|
||||
{{ vs_item('KAST (贡献率)', 'side_kast_t', 'side_kast_ct', '{:.1%}') }}
|
||||
{{ vs_item('RWS (Round Win Share)', 'side_rws_t', 'side_rws_ct') }}
|
||||
{{ vs_item('Multi-Kill Rate (多杀率)', 'side_multikill_rate_t', 'side_multikill_rate_ct', '{:.1%}') }}
|
||||
{{ vs_item('Headshot Rate (爆头率)', 'side_headshot_rate_t', 'side_headshot_rate_ct', '{:.1%}') }}
|
||||
|
||||
{# New Comparisons #}
|
||||
{% set t_rounds = side_stats.get('T', {}).get('rounds', 0) or 1 %}
|
||||
{% set ct_rounds = side_stats.get('CT', {}).get('rounds', 0) or 1 %}
|
||||
|
||||
{% set t_clutch = (side_stats.get('T', {}).get('total_clutch', 0) or 0) / t_rounds %}
|
||||
{% set ct_clutch = (side_stats.get('CT', {}).get('total_clutch', 0) or 0) / ct_rounds %}
|
||||
{{ vs_item_val('Clutch Win Rate (残局率)', t_clutch, ct_clutch, '{:.1%}') }}
|
||||
|
||||
{% set t_mk = (side_stats.get('T', {}).get('total_multikill', 0) or 0) / t_rounds %}
|
||||
{% set ct_mk = (side_stats.get('CT', {}).get('total_multikill', 0) or 0) / ct_rounds %}
|
||||
{{ vs_item_val('Multi-Kill Rate (多杀率)', t_mk, ct_mk, '{:.1%}') }}
|
||||
|
||||
{% set t_ma = (side_stats.get('T', {}).get('total_multiassist', 0) or 0) / t_rounds %}
|
||||
{% set ct_ma = (side_stats.get('CT', {}).get('total_multiassist', 0) or 0) / ct_rounds %}
|
||||
{{ vs_item_val('Multi-Assist Rate (多助攻)', t_ma, ct_ma, '{:.1%}') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user