bep40 commited on
Commit
d199be8
·
verified ·
1 Parent(s): 354b82e

Fix match detail UI: add lineups section, restore proper rendering

Browse files
Files changed (1) hide show
  1. static/match_detail.js +22 -43
static/match_detail.js CHANGED
@@ -5,7 +5,6 @@
5
  if(window._mdLoaded) return;
6
  window._mdLoaded = true;
7
 
8
- // Inject styles
9
  if(!document.getElementById('md-css')){
10
  const s=document.createElement('style');
11
  s.id='md-css';
@@ -62,52 +61,39 @@
62
 
63
  function esc(s){return String(s||'').replace(/[&<>"']/g,function(m){return{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]})}
64
 
65
- // === 1. Override openMatch to always set _currentEventId ===
66
  const _origOpenMatch = window.openMatch;
67
  window.openMatch = function(id){
68
  if(id) window._currentEventId = String(id);
69
  if(_origOpenMatch) _origOpenMatch.call(this, id);
70
- // Switch to detail tab
71
  setTimeout(function(){
72
  injectDetailTab();
73
  loadMatchTab('detail');
74
  }, 300);
75
  };
76
 
77
- // === 2. Override loadMatchTab to handle 'detail' tab ===
78
  const _origLoadMatchTab = window.loadMatchTab;
79
  window.loadMatchTab = async function(tab){
80
  if(tab !== 'detail'){
81
  if(_origLoadMatchTab) _origLoadMatchTab.call(this, tab);
82
  return;
83
  }
84
-
85
- // Update tab UI — highlight the Chi tiết tab
86
  document.querySelectorAll('.mo-tab').forEach(function(t){ t.classList.remove('active'); });
87
  document.querySelectorAll('.mo-tab').forEach(function(t){
88
  const txt = t.textContent || '';
89
  if(txt.includes('Chi tiết') || txt.includes('📋')) t.classList.add('active');
90
  });
91
-
92
  const el = document.getElementById('mo-body');
93
  if(!el) return;
94
  el.innerHTML = '<div class="md-no-data"><div style="display:inline-block;width:20px;height:20px;border:2px solid #333;border-top-color:#5cb87a;border-radius:50%;animation:mdspin .8s linear infinite;vertical-align:middle;margin-right:8px"></div>Đang tải chi tiết trận đấu...</div>';
95
-
96
  const eventId = window._currentEventId;
97
  if(!eventId){
98
  el.innerHTML = '<div class="md-err">⚠️ Không tìm thấy mã trận đấu.<br><small>Hãy click vào một trận đấu cụ thể từ danh sách livescore.</small></div>';
99
  return;
100
  }
101
-
102
  try{
103
  const r = await fetch('/api/match/' + eventId + '/detail');
104
  if(!r.ok){
105
- // Handle HTTP errors gracefully
106
- if(r.status === 404){
107
- el.innerHTML = '<div class="md-warn">⚠️ Không tìm thấy dữ liệu trận đấu.<br><small>Event ID: ' + esc(String(eventId)) + '</small><br><small style="color:#888">Trận đấu có thể chưa được cập nhật trên bongda.com.vn</small></div>';
108
- } else {
109
- el.innerHTML = '<div class="md-err">⚠️ Lỗi máy chủ (' + r.status + ').<br><small>Event ID: ' + esc(String(eventId)) + '</small><br><button onclick="window.loadMatchTab(\'detail\')" style="margin-top:8px;background:#0066cc;border:none;color:#fff;padding:6px 14px;border-radius:8px;font-size:11px;cursor:pointer">Thử lại</button></div>';
110
- }
111
  return;
112
  }
113
  const d = await r.json();
@@ -121,13 +107,12 @@
121
  }
122
  };
123
 
124
- // === 3. Render match detail ===
125
  function renderMatchDetail(el, data){
126
  let h = '';
127
  let hasAnyContent = false;
128
-
129
- // 0. Pre-match info card (teams, league, date, stadium)
130
  const info = data.info || {};
 
 
131
  if(info.home_team && info.away_team){
132
  hasAnyContent = true;
133
  h += '<div class="md-pre-match">';
@@ -152,16 +137,12 @@
152
  h += '</div>';
153
  } else if(data.pre_match_html && data.pre_match_html.length > 10){
154
  hasAnyContent = true;
155
- // Fallback: render raw HTML
156
- let clean = data.pre_match_html
157
- .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
158
- .replace(/<iframe[^>]*>[\s\S]*?<\/iframe>/gi, '')
159
- .replace(/<ins[^>]*>[\s\S]*?<\/ins>/gi, '');
160
  h += '<div class="md-sec"><div class="md-sec-title">📋 Thông tin trận đấu</div>';
161
  h += '<div class="md-preview-text">' + clean + '</div></div>';
162
  }
163
 
164
- // 1. H2H Stats comparison (only show if has non-zero data)
165
  if(data.h2h_stats_parsed && Object.keys(data.h2h_stats_parsed).length > 0){
166
  const parsed = data.h2h_stats_parsed;
167
  const hasNonZero = Object.values(parsed).some(s => s.home !== "0" || s.away !== "0");
@@ -185,8 +166,7 @@
185
  if(data.h2h && data.h2h.length > 0){
186
  hasAnyContent = true;
187
  h += '<div class="md-sec"><div class="md-sec-title">🔄 Lịch sử đối đầu</div>';
188
- const h2hList = data.h2h.slice(0, 10);
189
- h2hList.forEach(function(m){
190
  h += '<div class="md-h2h-item">';
191
  h += '<span class="md-h2h-date">'+esc(m.date||'')+'</span>';
192
  if(m.league) h += '<span class="md-h2h-league">'+esc(m.league)+'</span>';
@@ -197,58 +177,60 @@
197
  h += '</span></div>';
198
  });
199
  h += '</div>';
 
 
 
 
200
  }
201
 
202
  // 3. Team form
203
  if((data.home_form && data.home_form.length > 0) || (data.away_form && data.away_form.length > 0)){
204
  hasAnyContent = true;
205
  h += '<div class="md-sec"><div class="md-sec-title">📈 Phong độ gần đây</div>';
206
-
207
  if(data.home_form && data.home_form.length > 0){
208
  h += '<div class="md-form-section">';
209
  h += '<div class="md-form-team-label">🏠 Đội nhà</div>';
210
- data.home_form.slice(0, 5).forEach(function(m){
211
- h += renderFormItem(m);
212
- });
213
  h += '</div>';
214
  }
215
-
216
  if(data.away_form && data.away_form.length > 0){
217
  h += '<div class="md-form-section">';
218
  h += '<div class="md-form-team-label">✈️ Đội khách</div>';
219
- data.away_form.slice(0, 5).forEach(function(m){
220
- h += renderFormItem(m);
221
- });
222
  h += '</div>';
223
  }
224
  h += '</div>';
225
  }
226
 
227
- // 4. Player performance stats
 
 
 
 
 
 
 
228
  if(data.stats_html && data.stats_html.length > 10){
229
  hasAnyContent = true;
230
  h += '<div class="md-sec"><div class="md-sec-title">🌟 Thông số cầu thủ</div>';
231
  h += '<div>' + data.stats_html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,'').replace(/<iframe[^>]*>[\s\S]*?<\/iframe>/gi,'') + '</div></div>';
232
  }
233
 
234
- // 5. Commentaries (live match info)
235
  if(data.commentaries_html && data.commentaries_html.length > 10){
236
  hasAnyContent = true;
237
  h += '<div class="md-sec"><div class="md-sec-title">📢 Diễn biến</div>';
238
  h += '<div class="md-preview-text">' + data.commentaries_html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,'').replace(/<iframe[^>]*>[\s\S]*?<\/iframe>/gi,'') + '</div></div>';
239
  }
240
 
241
- // If no content at all, show appropriate message
242
  if(!h){
243
  if(data.found === false){
244
- h = '<div class="md-warn">⚠️ Không tìm thấy dữ liệu trận đấu.<br><small>Event ID: ' + esc(String(data.event_id||'')) + '</small><br><small style="color:#888;margin-top:4px;display:block">Nguyên nhân có thể:<br>• Mã trận đấu không đúng<br>• Trận đấu chưa được cập nhật trên bongda.com.vn<br>• Dữ liệu chưa có sẵn (trận đấu quá mới hoặc đã kết thúc lâu)</small></div>';
245
  } else {
246
  h = '<div class="md-no-data">⏳ Chưa có chi tiết cho trận đấu này.<br><small style="color:#666">Dữ liệu sẽ cập nhật khi giải khởi tranh hoặc trận đấu bắt đầu.</small></div>';
247
  }
248
  }
249
-
250
  el.innerHTML = h;
251
- // Prevent link navigation inside overlay
252
  el.querySelectorAll('a').forEach(function(a){ a.addEventListener('click', function(e){ e.preventDefault(); }); });
253
  }
254
 
@@ -264,7 +246,6 @@
264
  return h;
265
  }
266
 
267
- // === 4. Inject "Chi tiết" tab into overlay ===
268
  function injectDetailTab(){
269
  const tabs = document.querySelector('.mo-tabs');
270
  if(!tabs || document.querySelector('.mo-tab-detail')) return;
@@ -275,7 +256,6 @@
275
  tabs.insertBefore(d, tabs.firstChild);
276
  }
277
 
278
- // === 5. Intercept clicks in livescore to capture event_id ===
279
  document.addEventListener('click', function(e){
280
  const md = e.target.closest('.match-detail');
281
  if(!md) return;
@@ -287,7 +267,6 @@
287
  }
288
  }, true);
289
 
290
- // Try to inject tab on DOM ready
291
  if(document.readyState==='loading') document.addEventListener('DOMContentLoaded', function(){ setTimeout(injectDetailTab, 1000); });
292
  else setTimeout(injectDetailTab, 1000);
293
  })();
 
5
  if(window._mdLoaded) return;
6
  window._mdLoaded = true;
7
 
 
8
  if(!document.getElementById('md-css')){
9
  const s=document.createElement('style');
10
  s.id='md-css';
 
61
 
62
  function esc(s){return String(s||'').replace(/[&<>"']/g,function(m){return{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]})}
63
 
 
64
  const _origOpenMatch = window.openMatch;
65
  window.openMatch = function(id){
66
  if(id) window._currentEventId = String(id);
67
  if(_origOpenMatch) _origOpenMatch.call(this, id);
 
68
  setTimeout(function(){
69
  injectDetailTab();
70
  loadMatchTab('detail');
71
  }, 300);
72
  };
73
 
 
74
  const _origLoadMatchTab = window.loadMatchTab;
75
  window.loadMatchTab = async function(tab){
76
  if(tab !== 'detail'){
77
  if(_origLoadMatchTab) _origLoadMatchTab.call(this, tab);
78
  return;
79
  }
 
 
80
  document.querySelectorAll('.mo-tab').forEach(function(t){ t.classList.remove('active'); });
81
  document.querySelectorAll('.mo-tab').forEach(function(t){
82
  const txt = t.textContent || '';
83
  if(txt.includes('Chi tiết') || txt.includes('📋')) t.classList.add('active');
84
  });
 
85
  const el = document.getElementById('mo-body');
86
  if(!el) return;
87
  el.innerHTML = '<div class="md-no-data"><div style="display:inline-block;width:20px;height:20px;border:2px solid #333;border-top-color:#5cb87a;border-radius:50%;animation:mdspin .8s linear infinite;vertical-align:middle;margin-right:8px"></div>Đang tải chi tiết trận đấu...</div>';
 
88
  const eventId = window._currentEventId;
89
  if(!eventId){
90
  el.innerHTML = '<div class="md-err">⚠️ Không tìm thấy mã trận đấu.<br><small>Hãy click vào một trận đấu cụ thể từ danh sách livescore.</small></div>';
91
  return;
92
  }
 
93
  try{
94
  const r = await fetch('/api/match/' + eventId + '/detail');
95
  if(!r.ok){
96
+ el.innerHTML = '<div class="md-err">⚠️ Lỗi máy chủ (' + r.status + ').<br><small>Event ID: ' + esc(String(eventId)) + '</small><br><button onclick="window.loadMatchTab(\'detail\')" style="margin-top:8px;background:#0066cc;border:none;color:#fff;padding:6px 14px;border-radius:8px;font-size:11px;cursor:pointer">Thử lại</button></div>';
 
 
 
 
 
97
  return;
98
  }
99
  const d = await r.json();
 
107
  }
108
  };
109
 
 
110
  function renderMatchDetail(el, data){
111
  let h = '';
112
  let hasAnyContent = false;
 
 
113
  const info = data.info || {};
114
+
115
+ // 0. Pre-match info card
116
  if(info.home_team && info.away_team){
117
  hasAnyContent = true;
118
  h += '<div class="md-pre-match">';
 
137
  h += '</div>';
138
  } else if(data.pre_match_html && data.pre_match_html.length > 10){
139
  hasAnyContent = true;
140
+ let clean = data.pre_match_html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '').replace(/<iframe[^>]*>[\s\S]*?<\/iframe>/gi, '').replace(/<ins[^>]*>[\s\S]*?<\/ins>/gi, '');
 
 
 
 
141
  h += '<div class="md-sec"><div class="md-sec-title">📋 Thông tin trận đấu</div>';
142
  h += '<div class="md-preview-text">' + clean + '</div></div>';
143
  }
144
 
145
+ // 1. H2H Stats comparison
146
  if(data.h2h_stats_parsed && Object.keys(data.h2h_stats_parsed).length > 0){
147
  const parsed = data.h2h_stats_parsed;
148
  const hasNonZero = Object.values(parsed).some(s => s.home !== "0" || s.away !== "0");
 
166
  if(data.h2h && data.h2h.length > 0){
167
  hasAnyContent = true;
168
  h += '<div class="md-sec"><div class="md-sec-title">🔄 Lịch sử đối đầu</div>';
169
+ data.h2h.slice(0, 10).forEach(function(m){
 
170
  h += '<div class="md-h2h-item">';
171
  h += '<span class="md-h2h-date">'+esc(m.date||'')+'</span>';
172
  if(m.league) h += '<span class="md-h2h-league">'+esc(m.league)+'</span>';
 
177
  h += '</span></div>';
178
  });
179
  h += '</div>';
180
+ } else if(data.h2h_html && data.h2h_html.length > 10){
181
+ hasAnyContent = true;
182
+ h += '<div class="md-sec"><div class="md-sec-title">🔄 Lịch sử đối đầu</div>';
183
+ h += '<div>' + data.h2h_html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,'').replace(/<iframe[^>]*>[\s\S]*?<\/iframe>/gi,'') + '</div></div>';
184
  }
185
 
186
  // 3. Team form
187
  if((data.home_form && data.home_form.length > 0) || (data.away_form && data.away_form.length > 0)){
188
  hasAnyContent = true;
189
  h += '<div class="md-sec"><div class="md-sec-title">📈 Phong độ gần đây</div>';
 
190
  if(data.home_form && data.home_form.length > 0){
191
  h += '<div class="md-form-section">';
192
  h += '<div class="md-form-team-label">🏠 Đội nhà</div>';
193
+ data.home_form.slice(0, 5).forEach(function(m){ h += renderFormItem(m); });
 
 
194
  h += '</div>';
195
  }
 
196
  if(data.away_form && data.away_form.length > 0){
197
  h += '<div class="md-form-section">';
198
  h += '<div class="md-form-team-label">✈️ Đội khách</div>';
199
+ data.away_form.slice(0, 5).forEach(function(m){ h += renderFormItem(m); });
 
 
200
  h += '</div>';
201
  }
202
  h += '</div>';
203
  }
204
 
205
+ // 4. Lineups
206
+ if(data.lineups_html && data.lineups_html.length > 10){
207
+ hasAnyContent = true;
208
+ h += '<div class="md-sec"><div class="md-sec-title">📋 Đội hình</div>';
209
+ h += '<div>' + data.lineups_html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,'').replace(/<iframe[^>]*>[\s\S]*?<\/iframe>/gi,'') + '</div></div>';
210
+ }
211
+
212
+ // 5. Player performance stats
213
  if(data.stats_html && data.stats_html.length > 10){
214
  hasAnyContent = true;
215
  h += '<div class="md-sec"><div class="md-sec-title">🌟 Thông số cầu thủ</div>';
216
  h += '<div>' + data.stats_html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,'').replace(/<iframe[^>]*>[\s\S]*?<\/iframe>/gi,'') + '</div></div>';
217
  }
218
 
219
+ // 6. Commentaries
220
  if(data.commentaries_html && data.commentaries_html.length > 10){
221
  hasAnyContent = true;
222
  h += '<div class="md-sec"><div class="md-sec-title">📢 Diễn biến</div>';
223
  h += '<div class="md-preview-text">' + data.commentaries_html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,'').replace(/<iframe[^>]*>[\s\S]*?<\/iframe>/gi,'') + '</div></div>';
224
  }
225
 
 
226
  if(!h){
227
  if(data.found === false){
228
+ h = '<div class="md-warn">⚠️ Không tìm thấy dữ liệu trận đấu.<br><small>Event ID: ' + esc(String(data.event_id||'')) + '</small><br><small style="color:#888;margin-top:4px;display:block">Nguyên nhân có thể:<br>• Mã trận đấu không đúng<br>• Trận đấu chưa được cập nhật<br>• Dữ liệu chưa có sẵn</small></div>';
229
  } else {
230
  h = '<div class="md-no-data">⏳ Chưa có chi tiết cho trận đấu này.<br><small style="color:#666">Dữ liệu sẽ cập nhật khi giải khởi tranh hoặc trận đấu bắt đầu.</small></div>';
231
  }
232
  }
 
233
  el.innerHTML = h;
 
234
  el.querySelectorAll('a').forEach(function(a){ a.addEventListener('click', function(e){ e.preventDefault(); }); });
235
  }
236
 
 
246
  return h;
247
  }
248
 
 
249
  function injectDetailTab(){
250
  const tabs = document.querySelector('.mo-tabs');
251
  if(!tabs || document.querySelector('.mo-tab-detail')) return;
 
256
  tabs.insertBefore(d, tabs.firstChild);
257
  }
258
 
 
259
  document.addEventListener('click', function(e){
260
  const md = e.target.closest('.match-detail');
261
  if(!md) return;
 
267
  }
268
  }, true);
269
 
 
270
  if(document.readyState==='loading') document.addEventListener('DOMContentLoaded', function(){ setTimeout(injectDetailTab, 1000); });
271
  else setTimeout(injectDetailTab, 1000);
272
  })();