bep40 commited on
Commit
fefdab2
·
verified ·
1 Parent(s): 62c6bbe

Upload static/match_detail_v6.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. static/match_detail_v6.js +212 -0
static/match_detail_v6.js ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // === VNEWS — Match Detail UI (v6-final)
2
+ (function(){
3
+ if(window._mdLoadedV6) return;
4
+ window._mdLoadedV6 = true;
5
+
6
+ if(!document.getElementById('mdv6-css')){
7
+ const s=document.createElement('style');
8
+ s.id='mdv6-css';
9
+ s.textContent=`
10
+ .mdv6-sec{margin-bottom:14px}
11
+ .mdv6-sec-title{font-size:12px;font-weight:800;color:#5cb87a;margin-bottom:6px;padding-bottom:4px;border-bottom:1px solid #2a2a2a}
12
+ .mdv6-header{background:linear-gradient(135deg,#1a2a1f,#0d1117);border:1px solid #2d8659;border-radius:10px;padding:12px;text-align:center;margin-bottom:12px}
13
+ .mdv6-teams{display:flex;align-items:center;justify-content:center;gap:12px}
14
+ .mdv6-team{display:flex;flex-direction:column;align-items:center;gap:4px;flex:1}
15
+ .mdv6-team img{width:44px;height:44px;object-fit:contain;background:#111;border-radius:50%;padding:4px;border:2px solid #333}
16
+ .mdv6-vs .mdv6-score{font-size:26px;font-weight:900;color:#f0c040}
17
+ .mdv6-vs .mdv6-status{font-size:9px;font-weight:700;padding:2px 10px;border-radius:4px}
18
+ .mdv6-vs .mdv6-status.finished{background:#2d8659;color:#a8ffb8}
19
+ .mdv6-vs .mdv6-status.live{background:#c0392b;color:#fff;animation:mdv6pulse 1.5s infinite}
20
+ .mdv6-tabs{display:flex;gap:4px;margin-bottom:10px}
21
+ .mdv6-tab-btn{flex:1;padding:9px;border:none;border-radius:6px;font-size:11px;font-weight:700;cursor:pointer}
22
+ .mdv6-tab-btn.active{background:#2d8659;color:#fff}
23
+ .mdv6-tab-btn:not(.active){background:#1a1a1a;color:#888}
24
+ .mdv6-tab-content{display:none}
25
+ .mdv6-tab-content.active{display:block}
26
+ .mdv6-timeline{}
27
+ .mdv6-period{font-size:11px;font-weight:800;color:#5cb87a;padding:6px 0;border-bottom:1px solid #2a2a2a;margin-bottom:2px}
28
+ .mdv6-ev{display:flex;align-items:flex-start;gap:8px;padding:7px 0;border-bottom:1px solid #1a1a1a}
29
+ .mdv6-ev-time{font-size:11px;font-weight:800;color:#f0c040;min-width:40px;text-align:center}
30
+ .mdv6-ev-icon{width:20px;height:20px;display:flex;align-items:center;justify-content:center}
31
+ .mdv6-ev-body{flex:1}
32
+ .mdv6-ev-team{font-size:8px;font-weight:800;padding:1px 5px;border-radius:3px;margin-right:4px}
33
+ .mdv6-ev-team.home{background:#1a3a2a;color:#5cb87a}
34
+ .mdv6-ev-team.away{background:#3a2a1a;color:#e85d04}
35
+ .mdv6-ev-title{font-size:12px;color:#fff;font-weight:700}
36
+ .mdv6-ev-detail{font-size:11px;color:#999;margin-top:3px}
37
+ .mdv6-stat-row{display:flex;align-items:center;gap:8px;padding:5px 0;font-size:11px;border-bottom:1px solid #1a1a1a}
38
+ .mdv6-stat-home{width:36px;text-align:right;color:#5cb87a;font-weight:700}
39
+ .mdv6-stat-label{flex:1;text-align:center;color:#999;font-size:10px}
40
+ .mdv6-stat-away{width:36px;text-align:left;color:#e85d04;font-weight:700}
41
+ .mdv6-pred{background:linear-gradient(135deg,#1a2a1f,#0d1117);border:1px solid #2d8659;border-radius:10px;padding:10px;margin-bottom:12px}
42
+ .mdv6-pred-title{font-size:9px;color:#5cb87a;font-weight:700;text-align:center;margin-bottom:8px}
43
+ .mdv6-pred-teams{display:flex;align-items:center;justify-content:center;gap:8px}
44
+ .mdv6-pred-vs{font-size:14px;font-weight:800;color:#f0c040}
45
+ .mdv6-recent-row{display:flex;align-items:center;gap:8px;padding:6px 8px;background:#111;border-radius:6px;margin-bottom:3px;font-size:11px}
46
+ .mdv6-recent-date{font-size:9px;color:#888;min-width:55px}
47
+ .mdv6-recent-score{font-size:11px;font-weight:800;color:#f0c040;min-width:36px;text-align:center}
48
+ .mdv6-no-data{text-align:center;color:#666;padding:16px 8px;font-size:12px}
49
+ .mdv6-warn{color:#f0c040;font-size:12px;padding:8px;background:#2a2a1a;border-radius:6px}
50
+ .mdv6-source{font-size:9px;color:#5cb87a;text-align:center;padding:3px;background:#1a2a1f;border-radius:4px;margin-bottom:8px}
51
+ @keyframes mdv6spin{to{transform:rotate(360deg)}}
52
+ @keyframes mdv6pulse{0%,100%{opacity:1}50%{opacity:.5}}
53
+ `;
54
+ document.head.appendChild(s);
55
+ }
56
+
57
+ function esc(s){const d=document.createElement('div');d.textContent=s||'';return d.innerHTML;}
58
+
59
+ // Hook: override loadMatchTab to use fast endpoint
60
+ window._origLoadMatchTab = window.loadMatchTab;
61
+ window.loadMatchTab = async function(tab){
62
+ if(tab!=='detail'){
63
+ if(window._origLoadMatchTab) return window._origLoadMatchTab.call(this, tab);
64
+ return;
65
+ }
66
+ document.querySelectorAll('.mo-tab').forEach(t=>t.classList.remove('active'));
67
+ const el=document.getElementById('mo-body');
68
+ if(!el)return;
69
+ el.innerHTML='<div class="mdv6-no-data"><div style="display:inline-block;width:20px;height:20px;border:2px solid #333;border-top-color:#5cb87a;border-radius:50%;animation:mdv6spin .8s linear infinite"></div><div style="margin-top:8px">Đang tải...</div></div>';
70
+
71
+ const eventId=window._currentEventId;
72
+ let matchUrl = window._currentMatchUrl;
73
+ if(!eventId){el.innerHTML='<div class="mdv6-warn">⚠️ Không tìm thấy mã trận đấu.</div>';return;}
74
+
75
+ // Auto-fetch slug if missing (for featured matches clicked without URL)
76
+ if(!matchUrl && eventId){
77
+ try{
78
+ matchUrl = 'https://bongda.com.vn/tran-dau/' + eventId;
79
+ // Store for next time
80
+ window._currentMatchUrl = matchUrl;
81
+ }catch(e){}
82
+ }
83
+
84
+ try{
85
+ const url = '/api/match/' + eventId + '/detail' + (matchUrl ? '?url=' + encodeURIComponent(matchUrl) : '');
86
+ const r = await fetch(url, {signal: AbortSignal.timeout(25000)});
87
+ const data = await r.json();
88
+ if(data.found && data.info && data.info.home_team){
89
+ el.innerHTML = '<div class="mdv6-source">📡 Dữ liệu server-side nhanh</div>';
90
+ renderMatchDetail(el, data);
91
+ }else{
92
+ el.innerHTML = '<div class="mdv6-warn">⚠️ Không thể tải dữ liệu.<br>Event ID: ' + esc(String(eventId)) + '<br><a href="https://bongda.com.vn/tran-dau/' + eventId + '" target="_blank">Xem trên bongda.com.vn</a></div>';
93
+ }
94
+ }catch(e){
95
+ el.innerHTML = '<div class="mdv6-warn">⚠️ Lỗi: ' + esc(e.message) + '</div>';
96
+ }
97
+ };
98
+
99
+ function renderMatchDetail(el, data){
100
+ const info=data.info||{};
101
+ let h='';
102
+
103
+ h+='<div class="mdv6-header"><div class="mdv6-teams">';
104
+ h+='<div class="mdv6-team">';
105
+ if(info.home_logo)h+='<img src="' + esc(info.home_logo) + '" alt="' + esc(info.home_team) + '">';
106
+ h+='<span>' + esc(info.home_team) + '</span></div>';
107
+ h+='<div class="mdv6-vs">';
108
+ if(info.score)h+='<span class="mdv6-score">' + esc(info.score) + '</span>';
109
+ if(info.status_label){
110
+ const sl=info.status_label;let cls='finished';
111
+ if(sl==='LIVE'||sl==='H1'||sl==='H2')cls='live';
112
+ h+='<span class="mdv6-status ' + cls + '">' + esc(sl) + '</span>';
113
+ }
114
+ h+='</div><div class="mdv6-team">';
115
+ if(info.away_logo)h+='<img src="' + esc(info.away_logo) + '" alt="' + esc(info.away_team) + '">';
116
+ h+='<span>' + esc(info.away_team) + '</span></div></div></div>';
117
+
118
+ const hasEvents=data.events&&data.events.length>0;
119
+ const hasStats=data.h2h_stats_parsed||data.prediction||data.recent_matches;
120
+
121
+ if(hasStats||hasEvents){
122
+ h+='<div class="mdv6-tabs">';
123
+ if(hasStats)h+='<button class="mdv6-tab-btn active" onclick="window._mdv6ShowTab(\'stats\',this)">📊 Thống kê</button>';
124
+ if(hasEvents)h+='<button class="mdv6-tab-btn" onclick="window._mdv6ShowTab(\'events\',this)">📢 Diễn biến</button>';
125
+ h+='</div>';
126
+ }
127
+
128
+ if(hasStats){
129
+ h+='<div id="mdv6-tab-stats" class="mdv6-tab-content" style="display:' + (hasEvents?'none':'block') + '">';
130
+ if(data.h2h_stats_parsed){
131
+ h+='<div class="mdv6-sec"><div class="mdv6-sec-title">📊 Tỷ lệ đối đầu</div>';
132
+ for(const label in data.h2h_stats_parsed){
133
+ const sv=data.h2h_stats_parsed[label];
134
+ h+='<div class="mdv6-stat-row"><span class="mdv6-stat-home">' + esc(sv.home) + '</span><span class="mdv6-stat-label">' + esc(label) + '</span><span class="mdv6-stat-away">' + esc(sv.away) + '</span></div>';
135
+ }
136
+ h+='</div>';
137
+ }
138
+ if(data.prediction){
139
+ h+='<div class="mdv6-pred"><div class="mdv6-pred-title">🎯 Dự đoán</div><div class="mdv6-pred-teams">';
140
+ h+='<span>' + esc(data.prediction.home_name || '') + '</span><span class="mdv6-pred-vs">' + esc(data.prediction.result || 'VS') + '</span><span>' + esc(data.prediction.away_name || '') + '</span></div></div>';
141
+ }
142
+ if(data.recent_matches){
143
+ h+='<div class="mdv6-sec"><div class="mdv6-sec-title">📋 Kết quả gần nhất</div>';
144
+ data.recent_matches.slice(0,6).forEach(m=>{
145
+ h+='<div class="mdv6-recent-row"><span class="mdv6-recent-date">' + esc(m.date) + '</span><span>' + esc(m.home) + '</span><span class="mdv6-recent-score">' + esc(m.score) + '</span><span>' + esc(m.away) + '</span></div>';
146
+ });
147
+ h+='</div>';
148
+ }
149
+ h+='</div>';
150
+ }
151
+
152
+ if(hasEvents){
153
+ h+='<div id="mdv6-tab-events" class="mdv6-tab-content" style="display:' + (hasStats?'none':'block') + '">';
154
+ h+='<div class="mdv6-sec"><div class="mdv6-sec-title">📢 Diễn biến trận đấu</div><div class="mdv6-timeline">';
155
+ let lastPeriod='';
156
+ data.events.forEach(ev=>{
157
+ if(ev.period&&ev.period!==lastPeriod){
158
+ h+='<div class="mdv6-period">' + esc(ev.period) + '</div>';
159
+ lastPeriod=ev.period;
160
+ }
161
+ const isHome=ev.team==='home';
162
+ const badge=isHome?'<span class="mdv6-ev-team home">HOME</span>':'<span class="mdv6-ev-team away">AWAY</span>';
163
+ let icon='', title='', detail='';
164
+
165
+ if(ev.type==='goal'){icon='⚽';title='BÀN THẮNG';detail=esc(ev.players);}
166
+ else if(ev.type==='redcard'){icon='🟥';title='THỺ ĐỎ';detail=esc(ev.players);}
167
+ else if(ev.type==='yellowcard'){icon='🟨';title='THỺ VÀNG';detail=esc(ev.players);}
168
+ else if(ev.type==='substitution'){icon='↔️';title='THAY ĐỔI';detail=esc(ev.players);}
169
+ else{icon='•';detail=esc(ev.players);}
170
+
171
+ h+='<div class="mdv6-ev"><span class="mdv6-ev-time">' + esc(ev.time||'') + '</span><span class="mdv6-ev-icon">' + icon + '</span><div class="mdv6-ev-body">' + badge + ' <span class="mdv6-ev-title">' + title + '</span>';
172
+ if(detail)h+='<div class="mdv6-ev-detail">' + detail + '</div>';
173
+ h+='</div></div>';
174
+ });
175
+ h+='</div></div>';
176
+ }
177
+
178
+ el.innerHTML=h;
179
+
180
+ window._mdv6ShowTab=(tab,btn)=>{
181
+ document.querySelectorAll('.mdv6-tab-btn').forEach(b=>{b.classList.remove('active');b.style.background='#1a1a1a';b.style.color='#888';});
182
+ if(btn){btn.classList.add('active');btn.style.background='#2d8659';btn.style.color='#fff';}
183
+ const stats=document.getElementById('mdv6-tab-stats');
184
+ const events=document.getElementById('mdv6-tab-events');
185
+ if(stats)stats.style.display=tab==='stats'?'block':'none';
186
+ if(events)events.style.display=tab==='events'?'block':'none';
187
+ };
188
+ }
189
+
190
+ // Auto-extract match ID/slug on click
191
+ document.addEventListener('click',e=>{
192
+ const md=e.target.closest('.match-detail, .match-item');
193
+ if(!md)return;
194
+ const link=md.querySelector('a[href*="tran-dau"]');
195
+ if(link){
196
+ const href=link.getAttribute('href')||'';
197
+ const m=href.match(/\/tran-dau\/(\d+)\/(?:centre|preview)\/(.+)/);
198
+ if(m){
199
+ window._currentEventId=m[1];
200
+ window._currentSlug=m[2];
201
+ window._currentMatchUrl='https://bongda.com.vn' + href;
202
+ }else{
203
+ const m2=href.match(/\/tran-dau\/(\d+)/);
204
+ if(m2){
205
+ window._currentEventId=m2[1];
206
+ window._currentMatchUrl='https://bongda.com.vn' + href;
207
+ }
208
+ }
209
+ }
210
+ },true);
211
+
212
+ })();