bep40 commited on
Commit
d503020
·
verified ·
1 Parent(s): 00cd61f

Fix: World Cup section + EPG timezone + CSS

Browse files
Files changed (1) hide show
  1. static/app_v2.js +134 -14
static/app_v2.js CHANGED
@@ -29,11 +29,12 @@ async function loadHome(){
29
  loadHotTopics();
30
 
31
  // Fetch all data with timeout - không để 1 API chậm treo cả trang
32
- const [featuredData, wallData, hlLeagues, aiData] = await Promise.allSettled([
33
  _fetchWithTimeout('/api/livescore/featured', 5000),
34
  _fetchWithTimeout('/api/wall', 5000),
35
- _fetchWithTimeout('/api/highlights/leagues', 15000), // Tăng timeout cho highlights
36
  _fetchWithTimeout('/api/genk_ai', 8000),
 
37
  ]).then(results => results.map(r => r.status === 'fulfilled' ? r.value : null));
38
 
39
  if(featuredData && featuredData.home){
@@ -44,29 +45,148 @@ async function loadHome(){
44
  }
45
 
46
  _wallPosts = (wallData && wallData.posts) || [];
47
- // Đảm bảo _hlLeagueData luôn là object, không bao giờ null
48
  _hlLeagueData = (hlLeagues && typeof hlLeagues === 'object') ? hlLeagues : {};
 
49
 
50
  _renderWallIn(afterEl);
51
  _renderHLIn(afterEl);
 
 
 
 
 
 
52
  if(aiData && aiData.length) _renderSlidesIn('ai-articles','Ứng dụng AI','🤖',aiData,afterEl);
 
 
 
 
 
 
 
 
53
 
54
- // Load World Cup highlights riêng nếu chưa có trong hlLeagues
55
- if(!_hlLeagueData['world-cup'] || !_hlLeagueData['world-cup'].length){
56
- _loadWorldCupHighlights(afterEl);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
58
  }
59
 
60
- // Load World Cup highlights riêng biệt - không block trang chủ
61
- async function _loadWorldCupHighlights(afterEl){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  try{
63
- const wcData = await _fetchWithTimeout('/api/highlights/world-cup', 12000);
64
- if(wcData && wcData.length > 0){
65
- _hlLeagueData['world-cup'] = wcData;
66
- _renderSlidesIn('world-cup', 'World Cup 2026', '🌍', wcData, afterEl);
67
- }
68
  }catch(e){
69
- console.log('WC highlights load failed:', e.message);
70
  }
71
  }
72
 
 
29
  loadHotTopics();
30
 
31
  // Fetch all data with timeout - không để 1 API chậm treo cả trang
32
+ const [featuredData, wallData, hlLeagues, aiData, wcData] = await Promise.allSettled([
33
  _fetchWithTimeout('/api/livescore/featured', 5000),
34
  _fetchWithTimeout('/api/wall', 5000),
35
+ _fetchWithTimeout('/api/highlights/leagues', 15000),
36
  _fetchWithTimeout('/api/genk_ai', 8000),
37
+ _fetchWithTimeout('/api/wc2026', 12000), // World Cup data
38
  ]).then(results => results.map(r => r.status === 'fulfilled' ? r.value : null));
39
 
40
  if(featuredData && featuredData.home){
 
45
  }
46
 
47
  _wallPosts = (wallData && wallData.posts) || [];
 
48
  _hlLeagueData = (hlLeagues && typeof hlLeagues === 'object') ? hlLeagues : {};
49
+ _wcData = wcData || {}; // Store World Cup data globally
50
 
51
  _renderWallIn(afterEl);
52
  _renderHLIn(afterEl);
53
+
54
+ // Render World Cup section nếu có dữ liệu
55
+ if(_wcData && Object.keys(_wcData).length > 0){
56
+ _renderWorldCupSection(afterEl);
57
+ }
58
+
59
  if(aiData && aiData.length) _renderSlidesIn('ai-articles','Ứng dụng AI','🤖',aiData,afterEl);
60
+ }
61
+
62
+ // ===== WORLD CUP 2026 SECTION =====
63
+ function _renderWorldCupSection(afterEl){
64
+ const wc = _wcData;
65
+ const wrap = document.createElement('div');
66
+ wrap.className = 'wc-section';
67
+ wrap.id = 'wc-section';
68
 
69
+ let h = '<div class="wc-header"><span class="wc-title">🌍 World Cup 2026</span></div>';
70
+ h += '<div class="wc-tabs"><span class="wc-tab active" onclick="switchWCTab(\'news\',this)">📰 Tin tức</span><span class="wc-tab" onclick="switchWCTab(\'fixtures\',this)">📅 Lịch thi đấu</span><span class="wc-tab" onclick="switchWCTab(\'standings\',this)">🏆 Bảng xếp hạng</span><span class="wc-tab" onclick="switchWCTab(\'stats\',this)">📊 Thống kê</span><span class="wc-tab" onclick="switchWCTab(\'highlights\',this)">🎬 Highlight</span></div>';
71
+ h += '<div id="wc-tab-content" class="wc-tab-content"></div>';
72
+
73
+ wrap.innerHTML = h;
74
+ afterEl.parentNode.insertBefore(wrap, afterEl);
75
+
76
+ // Mặc định hiển thị tin tức
77
+ _renderWCTabContent('news');
78
+ }
79
+
80
+ function switchWCTab(tab, el){
81
+ document.querySelectorAll('.wc-tab').forEach(t => t.classList.remove('active'));
82
+ if(el) el.classList.add('active');
83
+ _renderWCTabContent(tab);
84
+ }
85
+
86
+ function _renderWCTabContent(tab){
87
+ const contentEl = document.getElementById('wc-tab-content');
88
+ if(!contentEl) return;
89
+
90
+ if(tab === 'news'){
91
+ _renderWCNews(contentEl);
92
+ } else if(tab === 'fixtures'){
93
+ _renderWCFixtures(contentEl);
94
+ } else if(tab === 'standings'){
95
+ _renderWCStandings(contentEl);
96
+ } else if(tab === 'stats'){
97
+ _renderWCStats(contentEl);
98
+ } else if(tab === 'highlights'){
99
+ _renderWCHighlights(contentEl);
100
  }
101
  }
102
 
103
+ function _renderWCNews(el){
104
+ const news = _wcData.news || [];
105
+ if(!news.length){
106
+ el.innerHTML = '<div class="loading">Đang tải tin tức...</div>';
107
+ // Fetch news nếu chưa có
108
+ _fetchWCTabData('news');
109
+ return;
110
+ }
111
+ let h = '<div class="wc-news-list">';
112
+ news.slice(0, 15).forEach(item => {
113
+ h += `<div class="wc-news-item" onclick="readArticle('${esc(item.link)}')">`;
114
+ if(item.img) h += `<div class="wc-news-img"><img src="${esc(item.img)}" loading="lazy" onerror="this.style.display='none'"></div>`;
115
+ h += `<div class="wc-news-text"><div class="wc-news-title">${esc(item.title)}</div><div class="wc-news-source">${esc(item.source||'')}</div></div></div>`;
116
+ });
117
+ h += '</div>';
118
+ el.innerHTML = h;
119
+ }
120
+
121
+ function _renderWCFixtures(el){
122
+ const fixtures = _wcData.fixtures || {};
123
+ const matches = fixtures.matches || [];
124
+ if(!matches.length){
125
+ el.innerHTML = '<div class="loading">Đang tải lịch thi đấu...</div>';
126
+ _fetchWCTabData('fixtures');
127
+ return;
128
+ }
129
+ let h = '<div class="wc-fixtures-list">';
130
+ matches.slice(0, 20).forEach(m => {
131
+ const statusClass = m.status === 'live' ? 'wc-live' : (m.status === 'finished' ? 'wc-finished' : 'wc-upcoming');
132
+ const score = m.score || 'vs';
133
+ h += `<div class="wc-match-item">`;
134
+ h += `<div class="wc-match-date">${esc(m.date_vn||m.date_utc||'')}</div>`;
135
+ h += `<div class="wc-match-teams"><span class="wc-team">${esc(m.home||'')}</span><span class="wc-score ${statusClass}">${esc(score)}</span><span class="wc-team">${esc(m.away||'')}</span></div>`;
136
+ if(m.location) h += `<div class="wc-match-location">📍 ${esc(m.location)}</div>`;
137
+ h += `</div>`;
138
+ });
139
+ h += '</div>';
140
+ el.innerHTML = h;
141
+ }
142
+
143
+ function _renderWCStandings(el){
144
+ const standings = _wcData.standings || {};
145
+ const html = standings.html || '';
146
+ if(!html){
147
+ el.innerHTML = '<div class="loading">Đang tải bảng xếp hạng...</div>';
148
+ _fetchWCTabData('standings');
149
+ return;
150
+ }
151
+ el.innerHTML = '<div class="wc-standings-table">' + html + '</div>';
152
+ }
153
+
154
+ function _renderWCStats(el){
155
+ const stats = _wcData.stats || {};
156
+ const html = stats.html || '';
157
+ if(!html){
158
+ el.innerHTML = '<div class="loading">Đang tải thống kê...</div>';
159
+ _fetchWCTabData('stats');
160
+ return;
161
+ }
162
+ el.innerHTML = '<div class="wc-stats-table">' + html + '</div>';
163
+ }
164
+
165
+ function _renderWCHighlights(el){
166
+ const highlights = _hlLeagueData['world-cup'] || [];
167
+ if(!highlights.length){
168
+ el.innerHTML = '<div class="loading">Đang tải highlights...</div>';
169
+ _fetchWCTabData('highlights');
170
+ return;
171
+ }
172
+ let h = '<div class="wc-highlights-grid">';
173
+ highlights.slice(0, 12).forEach((item, i) => {
174
+ h += `<div class="wc-hl-item" onclick="openHighlightFeed('world-cup',${i})">`;
175
+ h += `<div class="wc-hl-thumb">${item.img ? `<img src="${esc(item.img)}" loading="lazy">` : ''}<div class="card-play">▶</div></div>`;
176
+ h += `<div class="wc-hl-title">${esc(item.title)}</div></div>`;
177
+ });
178
+ h += '</div>';
179
+ el.innerHTML = h;
180
+ }
181
+
182
+ async function _fetchWCTabData(tab){
183
  try{
184
+ const data = await _fetchWithTimeout(`/api/wc2026/${tab}`, 10000);
185
+ if(!_wcData) _wcData = {};
186
+ _wcData[tab] = data;
187
+ _renderWCTabContent(tab);
 
188
  }catch(e){
189
+ console.log(`WC ${tab} fetch failed:`, e.message);
190
  }
191
  }
192