184 lines
11 KiB
HTML
184 lines
11 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ player.username }}{% endblock %}
|
|
{% block page_title %}<i class="bi bi-person-fill me-2"></i>{{ player.username }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- Spieler-Info Karte -->
|
|
<div class="row g-3 mb-4">
|
|
<div class="col-12 col-md-4">
|
|
<div class="card h-100">
|
|
<div class="card-body text-center py-4">
|
|
<img src="https://minotar.net/avatar/{{ player.username }}/80"
|
|
class="rounded mb-3" alt="{{ player.username }}"
|
|
onerror="this.onerror=null;this.src='data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'80\' height=\'80\' viewBox=\'0 0 80 80\'%3E%3Crect width=\'80\' height=\'80\' rx=\'8\' fill=\'%23374151\'/%3E%3Ctext x=\'50%25\' y=\'54%25\' text-anchor=\'middle\' dominant-baseline=\'middle\' font-size=\'36\' font-family=\'monospace\' fill=\'%239ca3af\'%3E%3F%3C/text%3E%3C/svg%3E'">
|
|
<h5 class="fw-bold mb-1">{{ player.username }}</h5>
|
|
{% if player.is_op %}
|
|
<span class="badge bg-warning text-dark mb-2"><i class="bi bi-shield-fill"></i> OP</span>
|
|
{% endif %}
|
|
<table class="table table-sm mt-2 text-start">
|
|
<tr><th>UUID</th><td class="small text-break">{{ player.uuid }}</td></tr>
|
|
<tr><th>IP</th><td class="small">{{ player.ip_address or '—' }}</td></tr>
|
|
<tr><th>Locale</th><td class="small">{{ player.locale or '—' }}</td></tr>
|
|
<tr><th>Playtime</th><td>{{ player.total_playtime_sec | fmt_duration }}</td></tr>
|
|
<tr><th>Since</th><td class="small">{{ player.first_seen | fmt_dt }}</td></tr>
|
|
<tr><th>Last Seen</th><td class="small">{{ player.last_seen | fmt_dt }}</td></tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-8">
|
|
<!-- Tabs -->
|
|
<ul class="nav nav-tabs mb-3" id="playerTabs">
|
|
<li class="nav-item"><a class="nav-link active" data-bs-toggle="tab" href="#tab-sessions">Sessions ({{ sessions|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-chat">Chat ({{ chat|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-cmds">Commands ({{ commands|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-deaths">Deaths ({{ deaths|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-tp">Teleports ({{ teleports|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-stats">Stats ({{ stats|length }})</a></li>
|
|
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#tab-proxy">Proxy ({{ proxy_events|length }})</a></li>
|
|
</ul>
|
|
|
|
<div class="tab-content">
|
|
<!-- Sessions -->
|
|
<div class="tab-pane fade show active" id="tab-sessions">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Login</th><th>Logout</th><th>Duration</th><th>Server</th><th>IP</th></tr></thead>
|
|
<tbody>
|
|
{% for s in sessions %}
|
|
<tr>
|
|
<td class="small text-nowrap">{{ s.login_time | fmt_dt }}</td>
|
|
<td class="small text-nowrap">{{ s.logout_time | fmt_dt }}</td>
|
|
<td class="small">{{ s.duration_sec | fmt_duration }}</td>
|
|
<td><span class="badge bg-secondary">{{ s.server_name or '—' }}</span></td>
|
|
<td class="small text-muted">{{ s.ip_address or '—' }}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="5" class="text-center text-muted">No sessions</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Chat -->
|
|
<div class="tab-pane fade" id="tab-chat">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>Server</th><th>Message</th></tr></thead>
|
|
<tbody>
|
|
{% for c in chat %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ c.timestamp | fmt_dt }}</td>
|
|
<td><span class="badge bg-secondary">{{ c.server_name or '—' }}</span></td>
|
|
<td class="small">{{ c.message }}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="3" class="text-center text-muted">No chat messages</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Commands -->
|
|
<div class="tab-pane fade" id="tab-cmds">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>Server</th><th>Command</th><th>Position</th></tr></thead>
|
|
<tbody>
|
|
{% for c in commands %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ c.timestamp | fmt_dt }}</td>
|
|
<td><span class="badge bg-secondary">{{ c.server_name or '—' }}</span></td>
|
|
<td class="small font-monospace">{{ c.command }}</td>
|
|
<td class="small text-muted">{{ c.world or '' }} {% if c.x %}({{ c.x|round(1) }}, {{ c.y|round(1) }}, {{ c.z|round(1) }}){% endif %}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="4" class="text-center text-muted">No commands</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tode -->
|
|
<div class="tab-pane fade" id="tab-deaths">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>Cause</th><th>Killer</th><th>Level</th><th>World</th></tr></thead>
|
|
<tbody>
|
|
{% for d in deaths %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ d.timestamp | fmt_dt }}</td>
|
|
<td><span class="badge bg-danger">{{ d.cause or '—' }}</span></td>
|
|
<td class="small">{{ d.killer_name or '—' }}</td>
|
|
<td class="small">{{ d.exp_level }}</td>
|
|
<td class="small text-muted">{{ d.world }}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="5" class="text-center text-muted">No deaths</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Teleports -->
|
|
<div class="tab-pane fade" id="tab-tp">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>From</th><th>To</th><th>Cause</th></tr></thead>
|
|
<tbody>
|
|
{% for t in teleports %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ t.timestamp | fmt_dt }}</td>
|
|
<td class="small">{{ t.from_world }} ({{ t.from_x|round(0)|int }}, {{ t.from_y|round(0)|int }}, {{ t.from_z|round(0)|int }})</td>
|
|
<td class="small">{{ t.to_world }} ({{ t.to_x|round(0)|int }}, {{ t.to_y|round(0)|int }}, {{ t.to_z|round(0)|int }})</td>
|
|
<td><span class="badge bg-info text-dark">{{ t.cause or '—' }}</span></td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="4" class="text-center text-muted">No teleports</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stats -->
|
|
<div class="tab-pane fade" id="tab-stats">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>Type</th><th>Old</th><th>New</th></tr></thead>
|
|
<tbody>
|
|
{% for s in stats %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ s.timestamp | fmt_dt }}</td>
|
|
<td><span class="badge bg-secondary">{{ s.event_type }}</span></td>
|
|
<td class="small">{{ s.old_value or '—' }}</td>
|
|
<td class="small">{{ s.new_value or '—' }}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="4" class="text-center text-muted">No stats</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Proxy-Events -->
|
|
<div class="tab-pane fade" id="tab-proxy">
|
|
<div class="table-responsive" style="max-height:400px; overflow-y:auto;">
|
|
<table class="table table-sm table-hover">
|
|
<thead class="table-dark sticky-top"><tr><th>Time</th><th>Type</th><th>From</th><th>To</th></tr></thead>
|
|
<tbody>
|
|
{% for e in proxy_events %}
|
|
<tr>
|
|
<td class="small text-nowrap text-muted">{{ e.timestamp | fmt_dt }}</td>
|
|
<td><span class="badge bg-primary">{{ e.event_type }}</span></td>
|
|
<td class="small">{{ e.from_server or '—' }}</td>
|
|
<td class="small">{{ e.to_server or '—' }}</td>
|
|
</tr>
|
|
{% else %}<tr><td colspan="4" class="text-center text-muted">No proxy events</td></tr>{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div><!-- /tab-content -->
|
|
</div>
|
|
</div>
|
|
|
|
<a href="{{ url_for('players') }}" class="btn btn-outline-secondary">
|
|
<i class="bi bi-arrow-left me-1"></i>Back to Overview
|
|
</a>
|
|
{% endblock %}
|