135 lines
7.8 KiB
PHP
135 lines
7.8 KiB
PHP
<?php /* gamelog viewer — log รวม 7 มินิเกม + LobbyA/B (อ่านจาก log.php) */ ?>
|
|
<!DOCTYPE html>
|
|
<html lang="th">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Game Log · Justice</title>
|
|
<style>
|
|
:root { --bg:#0a0e1a; --panel:#121a2e; --line:#23304d; --txt:#cfe0ff; --dim:#7f93bd; --acc:#37e0ff; }
|
|
* { box-sizing:border-box; }
|
|
body { margin:0; background:var(--bg); color:var(--txt); font:14px/1.5 "Kanit",system-ui,sans-serif; }
|
|
header { position:sticky; top:0; z-index:5; background:linear-gradient(180deg,#0d1426,#0a0e1a); border-bottom:1px solid var(--line); padding:10px 14px; }
|
|
h1 { margin:0 0 8px; font-size:18px; letter-spacing:.5px; color:#fff; }
|
|
h1 small { color:var(--dim); font-size:12px; font-weight:400; }
|
|
.tabs { display:flex; flex-wrap:wrap; gap:6px; }
|
|
.tab { cursor:pointer; padding:5px 11px; border-radius:8px; border:1px solid var(--line); background:#0f1730; color:var(--dim); font-size:13px; user-select:none; }
|
|
.tab:hover { border-color:var(--acc); color:var(--txt); }
|
|
.tab.active { background:var(--acc); color:#05101f; border-color:var(--acc); font-weight:700; }
|
|
.tab .n { opacity:.7; font-size:11px; margin-left:4px; }
|
|
.bar { display:flex; align-items:center; gap:12px; margin-top:8px; font-size:12px; color:var(--dim); flex-wrap:wrap; }
|
|
.bar label { cursor:pointer; }
|
|
.bar input[type=text]{ background:#0f1730; border:1px solid var(--line); color:var(--txt); border-radius:7px; padding:5px 9px; min-width:160px; }
|
|
.btn { cursor:pointer; padding:5px 11px; border-radius:8px; border:1px solid var(--line); background:#0f1730; color:var(--txt); font-size:12px; }
|
|
.btn:hover { border-color:var(--acc); }
|
|
.btn.danger:hover { border-color:#ff5b6e; color:#ff8a97; }
|
|
#wrap { padding:6px 8px 60px; }
|
|
table { width:100%; border-collapse:collapse; }
|
|
th,td { text-align:left; padding:5px 9px; border-bottom:1px solid #182238; vertical-align:top; }
|
|
th { position:sticky; top:0; color:var(--dim); font-weight:600; font-size:12px; background:var(--bg); }
|
|
td.t { color:var(--dim); white-space:nowrap; font-variant-numeric:tabular-nums; font-size:12px; }
|
|
td.cat span { display:inline-block; padding:1px 8px; border-radius:6px; font-size:12px; font-weight:700; }
|
|
td.room { color:var(--dim); font-size:12px; max-width:130px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
td.who { color:#bcd; font-size:13px; }
|
|
td.ev { font-weight:600; }
|
|
td.detail { color:var(--dim); font-size:12px; word-break:break-word; }
|
|
tr.src-client td.ev::after { content:" ·c"; color:#6a7da6; font-size:10px; font-weight:400; }
|
|
.empty { text-align:center; color:var(--dim); padding:40px; }
|
|
/* cat colors */
|
|
.c-LobbyA{background:#1d3a5f;color:#9fd4ff} .c-LobbyB{background:#2a2f63;color:#c4c2ff}
|
|
.c-MG1{background:#7a2540;color:#ffc0d4} .c-MG2{background:#2a5f3a;color:#bfffd0}
|
|
.c-MG3{background:#5f4a1d;color:#ffe6a0} .c-MG4{background:#1d5f5a;color:#a0fff2}
|
|
.c-MG5{background:#3a2a5f;color:#d6c0ff} .c-MG6{background:#5f1d3a;color:#ffb0c8}
|
|
.c-MG7{background:#5f3a1d;color:#ffd0a0} .cother{background:#2a3550;color:#9fb0d0}
|
|
.ev-leave td.ev, .ev-disconnect td.ev{color:#ff8a97} .ev-join td.ev{color:#7ee787}
|
|
.ev-bot-takeover td.ev,.ev-ghost-prune td.ev{color:#ffd166} .ev-error td.ev{color:#ff5b6e}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<h1>🎮 Game Log <small>— 7 มินิเกม + LobbyA / LobbyB · srv1361159</small></h1>
|
|
<div style="margin:0 0 8px;font-size:12px;color:#9fb0d0">
|
|
🔎 ค้นหา <b>TC154 / TC156 / TC157 / TC144 / TC158</b> (หรือ ev: preplay-lock · story-gate · vote-gate · lobbyb-gate · mg4-warp)
|
|
→ ดูว่าฟีเจอร์ทำงานไหม แล้วอัปเดตผลที่ <a href="/testcase/" style="color:#37e0ff" target="_blank">/testcase/</a>
|
|
· เสียง (TC159-164) = ฟังเอง ไม่มีใน log
|
|
</div>
|
|
<div class="tabs" id="tabs"></div>
|
|
<div class="bar">
|
|
<label><input type="checkbox" id="auto" checked> auto-refresh 3s</label>
|
|
<input type="text" id="search" placeholder="ค้นหา (ชื่อ/ห้อง/event/detail)">
|
|
<span id="status"></span>
|
|
<span style="flex:1"></span>
|
|
<button class="btn" id="reload">รีโหลด</button>
|
|
<button class="btn danger" id="clear">ล้าง log</button>
|
|
</div>
|
|
</header>
|
|
<div id="wrap"><div class="empty">กำลังโหลด...</div></div>
|
|
|
|
<script>
|
|
var CATS = ['ALL','LobbyA','LobbyB','MG1','MG2','MG3','MG4','MG5','MG6','MG7','อื่นๆ'];
|
|
var curCat = 'ALL';
|
|
var rows = [];
|
|
var counts = {};
|
|
|
|
function catClass(c){ var m={'LobbyA':'c-LobbyA','LobbyB':'c-LobbyB','MG1':'c-MG1','MG2':'c-MG2','MG3':'c-MG3','MG4':'c-MG4','MG5':'c-MG5','MG6':'c-MG6','MG7':'c-MG7'}; return m[c]||'cother'; }
|
|
function fmtTime(ms){ var d=new Date(ms); function p(n){return (n<10?'0':'')+n;} return p(d.getHours())+':'+p(d.getMinutes())+':'+p(d.getSeconds()); }
|
|
function esc(s){ return String(s==null?'':s).replace(/[&<>]/g,function(c){return{'&':'&','<':'<','>':'>'}[c];}); }
|
|
|
|
function renderTabs(){
|
|
var t=document.getElementById('tabs'); t.innerHTML='';
|
|
CATS.forEach(function(c){
|
|
var d=document.createElement('div'); d.className='tab'+(c===curCat?' active':'');
|
|
var n=counts[c]!=null?('<span class="n">'+counts[c]+'</span>'):'';
|
|
d.innerHTML=esc(c)+n;
|
|
d.onclick=function(){ curCat=c; renderTabs(); render(); load(); };
|
|
t.appendChild(d);
|
|
});
|
|
}
|
|
function render(){
|
|
var wrap=document.getElementById('wrap');
|
|
var q=(document.getElementById('search').value||'').toLowerCase().trim();
|
|
var list=rows.filter(function(r){
|
|
if(!q) return true;
|
|
return ((r.who||'')+' '+(r.room||'')+' '+(r.ev||'')+' '+(r.detail||'')).toLowerCase().indexOf(q)>=0;
|
|
});
|
|
if(!list.length){ wrap.innerHTML='<div class="empty">ยังไม่มี log'+(curCat!=='ALL'?(' ใน '+esc(curCat)):'')+'</div>'; return; }
|
|
var h='<table><thead><tr><th>เวลา</th><th>หมวด</th><th>ห้อง</th><th>ใคร</th><th>event</th><th>รายละเอียด</th></tr></thead><tbody>';
|
|
list.forEach(function(r){
|
|
h+='<tr class="src-'+esc(r.src||'')+' ev-'+esc((r.ev||'').replace(/[^a-z-]/gi,''))+'">'+
|
|
'<td class="t">'+fmtTime(r.t)+'</td>'+
|
|
'<td class="cat"><span class="'+catClass(r.cat)+'">'+esc(r.cat)+'</span></td>'+
|
|
'<td class="room" title="'+esc(r.room)+'">'+esc(r.room)+'</td>'+
|
|
'<td class="who">'+esc(r.who)+'</td>'+
|
|
'<td class="ev">'+esc(r.ev)+'</td>'+
|
|
'<td class="detail">'+esc(r.detail)+'</td></tr>';
|
|
});
|
|
h+='</tbody></table>';
|
|
wrap.innerHTML=h;
|
|
}
|
|
function load(){
|
|
fetch('log.php?cat='+encodeURIComponent(curCat)+'&limit=800&_='+Date.now())
|
|
.then(function(r){return r.json();})
|
|
.then(function(j){
|
|
rows = (j&&j.logs)||[];
|
|
document.getElementById('status').textContent = (rows.length)+' รายการ · '+new Date().toLocaleTimeString('th-TH');
|
|
render();
|
|
}).catch(function(){ document.getElementById('status').textContent='โหลดไม่ได้'; });
|
|
// counts ทุกหมวด (จาก ALL)
|
|
fetch('log.php?cat=ALL&limit=2000&_c='+Date.now()).then(function(r){return r.json();}).then(function(j){
|
|
counts={ALL:0}; CATS.forEach(function(c){counts[c]=0;});
|
|
((j&&j.logs)||[]).forEach(function(r){ counts.ALL++; if(counts[r.cat]!=null) counts[r.cat]++; else counts['อื่นๆ']++; });
|
|
renderTabs();
|
|
}).catch(function(){});
|
|
}
|
|
document.getElementById('reload').onclick=load;
|
|
document.getElementById('search').oninput=render;
|
|
document.getElementById('clear').onclick=function(){
|
|
if(!confirm('ล้าง log ทั้งหมด?')) return;
|
|
fetch('log.php?action=clear').then(function(){ load(); });
|
|
};
|
|
renderTabs(); load();
|
|
setInterval(function(){ if(document.getElementById('auto').checked) load(); }, 3000);
|
|
</script>
|
|
</body>
|
|
</html>
|