koishi-plugin-ets2-tools-tmp 3.1.1 → 3.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
2
+ <html lang="zh-CN">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <title>Mileage Leaderboard</title>
@@ -10,354 +10,555 @@
10
10
  font-weight: normal;
11
11
  font-style: normal;
12
12
  }
13
+
14
+ * { margin: 0; padding: 0; box-sizing: border-box; }
15
+
13
16
  body {
14
- font-family: 'segui-emj', sans-serif;
15
- margin: 0;
16
- padding: 0;
17
- background-color: #000;
17
+ font-family: 'segui-emj', 'Segoe UI', -apple-system, sans-serif;
18
+ background: #0a0a0a;
19
+ -webkit-font-smoothing: antialiased;
18
20
  }
19
21
 
20
22
  #container {
21
- width: 340px;
22
- background: linear-gradient(135deg, #1f2f54, #0f2c2a);
23
+ width: 520px;
24
+ background: #0d0d0d;
25
+ padding-bottom: 20px;
23
26
  overflow: hidden;
24
- padding-bottom: 12px;
25
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
27
+ position: relative;
26
28
  }
27
29
 
30
+ /* Racing stripe background */
31
+ .racing-stripes {
32
+ position: absolute;
33
+ top: 0;
34
+ left: 0;
35
+ right: 0;
36
+ height: 6px;
37
+ background: repeating-linear-gradient(
38
+ 90deg,
39
+ #ff6b00 0px, #ff6b00 20px,
40
+ #0d0d0d 20px, #0d0d0d 40px
41
+ );
42
+ z-index: 10;
43
+ }
44
+
45
+ /* Carbon fiber texture overlay */
46
+ .carbon-texture {
47
+ position: absolute;
48
+ inset: 0;
49
+ background:
50
+ radial-gradient(circle at 2px 2px, rgba(255,255,255,0.015) 1px, transparent 0) 0 0 / 4px 4px;
51
+ pointer-events: none;
52
+ z-index: 0;
53
+ }
54
+
55
+ /* Neon glow accents */
56
+ .neon-line-left {
57
+ position: absolute;
58
+ left: 0;
59
+ top: 80px;
60
+ bottom: 40px;
61
+ width: 2px;
62
+ background: linear-gradient(180deg, transparent, #ff6b00, #ff3d00, #ff6b00, transparent);
63
+ box-shadow: 0 0 8px rgba(255, 107, 0, 0.4), 0 0 20px rgba(255, 61, 0, 0.15);
64
+ z-index: 1;
65
+ }
66
+
67
+ .neon-line-right {
68
+ position: absolute;
69
+ right: 0;
70
+ top: 120px;
71
+ bottom: 80px;
72
+ width: 2px;
73
+ background: linear-gradient(180deg, transparent, #ff3d00, #ff6b00, #ff3d00, transparent);
74
+ box-shadow: 0 0 8px rgba(255, 61, 0, 0.4), 0 0 20px rgba(255, 107, 0, 0.15);
75
+ z-index: 1;
76
+ }
77
+
78
+ /* ===== HEADER ===== */
28
79
  .header {
29
- height: 45px;
30
- background-color: rgba(0, 0, 0, .1);
80
+ padding: 30px 24px 18px;
81
+ text-align: center;
82
+ position: relative;
83
+ z-index: 2;
84
+ }
85
+
86
+ .header-icon {
87
+ font-size: 42px;
88
+ display: block;
89
+ margin-bottom: 6px;
90
+ filter: drop-shadow(0 0 12px rgba(255, 107, 0, 0.5));
91
+ }
92
+
93
+ .header .title {
94
+ font-size: 24px;
95
+ font-weight: 900;
96
+ color: #ffffff;
97
+ letter-spacing: 3px;
98
+ text-transform: uppercase;
99
+ }
100
+
101
+ .header .title-accent {
102
+ display: inline-block;
103
+ width: 60px;
104
+ height: 3px;
105
+ background: linear-gradient(90deg, transparent, #ff6b00, transparent);
106
+ margin: 10px auto 0;
107
+ border-radius: 2px;
108
+ box-shadow: 0 0 10px rgba(255, 107, 0, 0.5);
109
+ }
110
+
111
+ .header .subtitle {
112
+ font-size: 11px;
113
+ color: #555;
114
+ margin-top: 8px;
115
+ letter-spacing: 2px;
116
+ text-transform: uppercase;
117
+ }
118
+
119
+ /* ===== TOP 1 HERO ===== */
120
+ .hero {
121
+ margin: 16px 20px;
122
+ padding: 20px;
123
+ background: linear-gradient(135deg, rgba(255, 107, 0, 0.1) 0%, rgba(255, 61, 0, 0.05) 100%);
124
+ border: 1px solid rgba(255, 107, 0, 0.2);
125
+ border-radius: 16px;
126
+ position: relative;
127
+ z-index: 2;
31
128
  display: flex;
32
129
  align-items: center;
33
- justify-content: center;
34
- padding: 0 20px;
35
- box-shadow: 0 0 16px rgba(0, 0, 0, .4);
130
+ gap: 16px;
131
+ box-shadow: 0 4px 24px rgba(255, 107, 0, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.03);
36
132
  }
37
133
 
38
- .header .title {
39
- color: #b0c7ff;
40
- font-size: 16px;
41
- font-weight: 600;
42
- text-align: center;
134
+ .hero::before {
135
+ content: '';
136
+ position: absolute;
137
+ top: 0;
138
+ left: 20px;
139
+ right: 20px;
140
+ height: 1px;
141
+ background: linear-gradient(90deg, transparent, rgba(255, 107, 0, 0.3), transparent);
43
142
  }
44
143
 
45
- .leaderboard-container {
46
- padding: 12px 16px 0 16px;
144
+ .hero-crown {
145
+ font-size: 36px;
146
+ filter: drop-shadow(0 0 8px rgba(255, 215, 0, 0.5));
147
+ flex-shrink: 0;
47
148
  }
48
149
 
49
- .leaderboard-item {
50
- background-color: rgba(0, 0, 0, 0.25);
51
- margin-bottom: 4px;
52
- border-radius: 6px;
150
+ .hero-info {
151
+ flex: 1;
152
+ min-width: 0;
153
+ }
154
+
155
+ .hero-name {
156
+ font-size: 18px;
157
+ font-weight: 800;
158
+ color: #ff6b00;
159
+ white-space: nowrap;
53
160
  overflow: hidden;
54
- border: 1px solid rgba(255, 255, 255, 0.1);
161
+ text-overflow: ellipsis;
162
+ text-shadow: 0 0 12px rgba(255, 107, 0, 0.3);
55
163
  }
56
164
 
57
- .leaderboard-item.top3 {
58
- background: linear-gradient(135deg, rgba(255, 215, 0, 0.2), rgba(255, 215, 0, 0.1));
59
- border-color: rgba(255, 215, 0, 0.3);
60
- box-shadow: 0 2px 8px rgba(255, 215, 0, 0.2);
165
+ .hero-rank {
166
+ font-size: 11px;
167
+ color: #888;
168
+ letter-spacing: 1px;
169
+ margin-top: 2px;
61
170
  }
62
171
 
63
- .leaderboard-item.current-player {
64
- background: linear-gradient(135deg, rgba(92, 227, 92, 0.3), rgba(92, 227, 92, 0.15));
65
- border: 1px solid rgba(92, 227, 92, 0.6);
66
- box-shadow: 0 2px 10px rgba(92, 227, 92, 0.3);
172
+ .hero-distance {
173
+ font-size: 20px;
174
+ font-weight: 900;
175
+ color: #fff;
176
+ flex-shrink: 0;
177
+ letter-spacing: 0.5px;
178
+ }
179
+
180
+ .hero-distance-unit {
181
+ font-size: 12px;
182
+ font-weight: 400;
183
+ color: #666;
184
+ margin-left: 4px;
67
185
  }
68
186
 
69
- .item-content {
187
+ /* ===== 2ND & 3RD PODIUM ===== */
188
+ .podium-row {
70
189
  display: flex;
71
- align-items: center;
72
- padding: 8px 14px;
190
+ gap: 10px;
191
+ margin: 12px 20px;
192
+ position: relative;
193
+ z-index: 2;
73
194
  }
74
195
 
75
- .rank {
76
- width: 32px;
77
- color: #ffffff;
78
- font-size: 15px;
79
- font-weight: bold;
80
- text-align: center;
81
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
196
+ .podium-card {
197
+ flex: 1;
198
+ padding: 14px;
199
+ background: rgba(255, 255, 255, 0.03);
200
+ border: 1px solid rgba(255, 255, 255, 0.06);
201
+ border-radius: 12px;
202
+ display: flex;
203
+ align-items: center;
204
+ gap: 10px;
205
+ position: relative;
206
+ overflow: hidden;
82
207
  }
83
208
 
84
- .current-player .rank {
85
- min-width: 48px;
86
- flex-shrink: 0;
209
+ .podium-card::before {
210
+ content: '';
211
+ position: absolute;
212
+ top: 0;
213
+ left: 0;
214
+ right: 0;
215
+ height: 1px;
216
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.06), transparent);
87
217
  }
88
218
 
89
- .rank.top1 {
90
- color: #ffd700;
91
- text-shadow: 0 0 8px rgba(255, 215, 0, 0.6);
219
+ .podium-card.second {
220
+ border-color: rgba(192, 192, 192, 0.15);
221
+ background: linear-gradient(135deg, rgba(192, 192, 192, 0.06), rgba(192, 192, 192, 0.02));
92
222
  }
93
223
 
94
- .rank.top2 {
95
- color: #c0c0c0;
96
- text-shadow: 0 0 6px rgba(192, 192, 192, 0.5);
224
+ .podium-card.third {
225
+ border-color: rgba(205, 127, 50, 0.15);
226
+ background: linear-gradient(135deg, rgba(205, 127, 50, 0.06), rgba(205, 127, 50, 0.02));
97
227
  }
98
228
 
99
- .rank.top3 {
100
- color: #cd7f32;
101
- text-shadow: 0 0 6px rgba(205, 127, 50, 0.5);
229
+ .podium-medal {
230
+ font-size: 22px;
231
+ flex-shrink: 0;
102
232
  }
103
233
 
104
- .player-info {
234
+ .podium-card-info {
105
235
  flex: 1;
106
- padding: 0 10px;
107
236
  min-width: 0;
108
237
  }
109
238
 
110
- .player-name {
111
- color: #ffffff;
239
+ .podium-card-name {
112
240
  font-size: 13px;
113
- font-weight: 600;
241
+ font-weight: 700;
242
+ color: #ddd;
114
243
  white-space: nowrap;
115
244
  overflow: hidden;
116
245
  text-overflow: ellipsis;
117
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
118
- max-width: 160px;
119
246
  }
120
247
 
121
- .current-player .player-name {
122
- max-width: 144px;
248
+ .podium-card.second .podium-card-name { color: #c0c0c0; }
249
+ .podium-card.third .podium-card-name { color: #cd7f32; }
250
+
251
+ .podium-card-dist {
252
+ font-size: 14px;
253
+ font-weight: 800;
254
+ color: #aaa;
255
+ flex-shrink: 0;
123
256
  }
124
257
 
258
+ .podium-card.second .podium-card-dist { color: #c0c0c0; }
259
+ .podium-card.third .podium-card-dist { color: #cd7f32; }
125
260
 
126
- .mileage-value {
127
- color: #ffffff;
261
+ /* ===== RANK LIST (4-10) ===== */
262
+ .rank-list {
263
+ margin: 8px 20px 0;
264
+ position: relative;
265
+ z-index: 2;
266
+ }
267
+
268
+ .rank-item {
269
+ display: flex;
270
+ align-items: center;
271
+ padding: 10px 14px;
272
+ margin-bottom: 4px;
273
+ background: rgba(255, 255, 255, 0.02);
274
+ border-left: 3px solid rgba(255, 107, 0, 0.3);
275
+ border-radius: 0 8px 8px 0;
276
+ position: relative;
277
+ }
278
+
279
+ .rank-item::before {
280
+ content: '';
281
+ position: absolute;
282
+ left: -3px;
283
+ top: 50%;
284
+ transform: translateY(-50%);
285
+ width: 3px;
286
+ height: 0;
287
+ background: #ff6b00;
288
+ border-radius: 2px;
289
+ box-shadow: 0 0 6px rgba(255, 107, 0, 0.5);
290
+ transition: height 0.2s;
291
+ }
292
+
293
+ .rank-number {
294
+ width: 26px;
295
+ font-size: 14px;
296
+ font-weight: 900;
297
+ color: #444;
298
+ flex-shrink: 0;
299
+ text-align: center;
300
+ margin-right: 12px;
301
+ }
302
+
303
+ .rank-bar {
304
+ flex: 1;
305
+ height: 4px;
306
+ background: rgba(255, 255, 255, 0.04);
307
+ border-radius: 2px;
308
+ overflow: hidden;
309
+ margin-right: 12px;
310
+ position: relative;
311
+ }
312
+
313
+ .rank-bar-fill {
314
+ height: 100%;
315
+ background: linear-gradient(90deg, #ff6b00, #ff3d00);
316
+ border-radius: 2px;
317
+ box-shadow: 0 0 6px rgba(255, 107, 0, 0.3);
318
+ }
319
+
320
+ .rank-name {
128
321
  font-size: 13px;
129
- font-weight: 700;
130
- text-align: right;
322
+ font-weight: 600;
323
+ color: #bbb;
324
+ flex-shrink: 0;
325
+ width: 120px;
131
326
  white-space: nowrap;
132
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
133
- min-width: 65px;
327
+ overflow: hidden;
328
+ text-overflow: ellipsis;
329
+ margin-right: 12px;
330
+ }
331
+
332
+ .rank-distance {
333
+ font-size: 13px;
334
+ font-weight: 800;
335
+ color: #888;
336
+ flex-shrink: 0;
337
+ text-align: right;
338
+ min-width: 70px;
134
339
  }
135
340
 
341
+ /* ===== DIVIDER ===== */
136
342
  .divider {
137
343
  height: 1px;
138
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
139
- margin: 12px 16px;
344
+ margin: 16px 40px;
345
+ background: linear-gradient(90deg, transparent, rgba(255, 107, 0, 0.3), transparent);
346
+ position: relative;
347
+ z-index: 2;
140
348
  }
141
349
 
142
- .current-player-container {
143
- padding: 0 16px;
350
+ /* ===== CURRENT PLAYER ===== */
351
+ .current-section {
352
+ margin: 0 20px;
353
+ position: relative;
354
+ z-index: 2;
144
355
  }
145
356
 
146
- .current-player-title {
147
- color: #aaaaaa;
148
- font-size: 12px;
357
+ .current-title {
358
+ font-size: 10px;
359
+ font-weight: 700;
360
+ color: #555;
361
+ text-transform: uppercase;
362
+ letter-spacing: 2px;
149
363
  text-align: center;
150
364
  margin-bottom: 8px;
151
365
  }
152
366
 
153
- .footer-note {
154
- color: #666666;
367
+ .current-card {
368
+ display: flex;
369
+ align-items: center;
370
+ padding: 12px 16px;
371
+ background: linear-gradient(135deg, rgba(0, 200, 83, 0.1) 0%, rgba(0, 200, 83, 0.03) 100%);
372
+ border: 1px solid rgba(0, 200, 83, 0.2);
373
+ border-left: 3px solid #00c853;
374
+ border-radius: 0 12px 12px 0;
375
+ box-shadow: 0 2px 12px rgba(0, 200, 83, 0.08);
376
+ }
377
+
378
+ .current-rank {
379
+ font-size: 18px;
380
+ font-weight: 900;
381
+ color: #00c853;
382
+ flex-shrink: 0;
383
+ margin-right: 12px;
384
+ min-width: 40px;
385
+ text-shadow: 0 0 8px rgba(0, 200, 83, 0.3);
386
+ }
387
+
388
+ .current-name {
389
+ font-size: 14px;
390
+ font-weight: 700;
391
+ color: #00c853;
392
+ flex: 1;
393
+ min-width: 0;
394
+ white-space: nowrap;
395
+ overflow: hidden;
396
+ text-overflow: ellipsis;
397
+ }
398
+
399
+ .current-distance {
400
+ font-size: 15px;
401
+ font-weight: 800;
402
+ color: #00c853;
403
+ flex-shrink: 0;
404
+ text-shadow: 0 0 6px rgba(0, 200, 83, 0.3);
405
+ }
406
+
407
+ /* ===== FOOTER ===== */
408
+ .footer {
155
409
  font-size: 10px;
410
+ color: #333;
156
411
  text-align: center;
157
- margin-top: 12px;
158
- padding: 0 16px;
159
- opacity: 0.8;
412
+ margin-top: 16px;
413
+ padding: 0 24px;
414
+ position: relative;
415
+ z-index: 2;
416
+ letter-spacing: 0.5px;
160
417
  }
161
418
  </style>
162
419
  </head>
163
420
  <body>
164
421
  <div id="container">
422
+ <div class="racing-stripes"></div>
423
+ <div class="carbon-texture"></div>
424
+ <div class="neon-line-left"></div>
425
+ <div class="neon-line-right"></div>
426
+
165
427
  <div class="header">
166
- <div class="title">🚗 行驶里程排行榜</div>
428
+ <span class="header-icon">🏁</span>
429
+ <div class="title" id="header-title">里程排行榜</div>
430
+ <div class="title-accent"></div>
431
+ <div class="subtitle" id="header-subtitle">MILEAGE RANKING</div>
167
432
  </div>
168
433
 
169
- <div class="leaderboard-container">
170
- <!-- 排行榜前10名 -->
171
- <div id="top-rankings"></div>
172
- </div>
434
+ <!-- #1 Hero -->
435
+ <div id="hero" class="hero" style="display:none;"></div>
436
+
437
+ <!-- #2 & #3 Podium -->
438
+ <div id="podium-row" class="podium-row" style="display:none;"></div>
173
439
 
174
- <div class="divider"></div>
440
+ <!-- #4-10 Rank List -->
441
+ <div id="rank-list" class="rank-list"></div>
175
442
 
176
- <div class="current-player-container">
177
- <div class="current-player-title">你的排名</div>
443
+ <div id="divider" class="divider" style="display:none;"></div>
444
+
445
+ <!-- Current Player -->
446
+ <div id="current-section" class="current-section" style="display:none;">
447
+ <div class="current-title">你的排名</div>
178
448
  <div id="current-player"></div>
179
449
  </div>
180
450
 
181
- <div class="footer-note" id="footer-note">
182
- * 数据统计说明
183
- </div>
451
+ <div id="footer" class="footer"></div>
184
452
  </div>
185
453
 
186
454
  <script>
187
- function createLeaderboardItem(rank, playerName, mileage, isCurrentPlayer = false, isTop3 = false) {
188
- const item = document.createElement('div');
189
- item.className = `leaderboard-item${isTop3 ? ' top3' : ''}${isCurrentPlayer ? ' current-player' : ''}`;
190
-
191
- let rankClass = '';
192
- if (rank === 1) rankClass = 'top1';
193
- else if (rank === 2) rankClass = 'top2';
194
- else if (rank === 3) rankClass = 'top3';
195
-
196
- item.innerHTML = `
197
- <div class="item-content">
198
- <div class="rank ${rankClass}">#${rank}</div>
199
- <div class="player-info">
200
- <div class="player-name">${playerName}</div>
201
- </div>
202
- <div class="mileage-value">${formatMileage(mileage)}</div>
203
- </div>
204
- `;
205
-
206
- return item;
207
- }
208
-
209
455
  function formatMileage(mileage) {
210
456
  const meters = parseInt(mileage);
211
- if (isNaN(meters) || meters < 0) return '0 km';
212
-
457
+ if (isNaN(meters) || meters < 0) return { value: '0', unit: 'km' };
213
458
  const km = meters / 1000;
214
-
215
459
  if (km >= 1000000) {
216
- const value = (km / 1000000).toFixed(2);
217
- return value.endsWith('.00') ? Math.floor(km / 1000000) + 'M km' : value + 'M km';
460
+ const v = (km / 1000000).toFixed(2);
461
+ return { value: v.endsWith('.00') ? Math.floor(km / 1000000) + '' : v, unit: 'M km' };
218
462
  } else if (km >= 1000) {
219
- const value = (km / 1000).toFixed(2);
220
- return value.endsWith('.00') ? Math.floor(km / 1000) + 'K km' : value + 'K km';
463
+ const v = (km / 1000).toFixed(2);
464
+ return { value: v.endsWith('.00') ? Math.floor(km / 1000) + '' : v, unit: 'K km' };
221
465
  } else if (km >= 1) {
222
- return Math.floor(km).toLocaleString() + ' km';
466
+ return { value: Math.floor(km).toLocaleString(), unit: 'km' };
223
467
  } else {
224
- return meters.toLocaleString() + ' m';
468
+ return { value: meters.toLocaleString(), unit: 'm' };
225
469
  }
226
470
  }
227
471
 
228
- // 新增:处理来自后端的动态数据
229
- function setData(apiData) {
230
- if (!apiData) {
231
- console.error('数据无效');
232
- return;
233
- }
234
-
235
- // 设置标题和底部脚注
236
- const titleElement = document.querySelector('.header .title');
237
- const footerElement = document.getElementById('footer-note');
238
-
239
- if (titleElement) {
240
- const titles = {
241
- 1: '- 总行驶里程排行榜 -',
242
- 2: '- 今日行驶里程排行榜 -'
243
- };
244
- const footerNotes = {
245
- 1: '* 数据自 2025年8月23日 20:00 开始统计',
246
- 2: '* 每日 0:00 重置统计'
247
- };
248
-
249
- titleElement.textContent = titles[apiData.rankingType] || '🚗 行驶里程排行榜';
250
- if (footerElement) {
251
- footerElement.textContent = footerNotes[apiData.rankingType] || '* 数据统计说明';
252
- }
253
- }
254
-
255
- const topRankings = document.getElementById('top-rankings');
256
- const currentPlayerContainer = document.getElementById('current-player');
257
-
258
- // 清空现有内容
259
- topRankings.innerHTML = '';
260
- currentPlayerContainer.innerHTML = '';
261
-
262
- // 渲染前10名排行榜
263
- if (apiData.mileageRankingList && Array.isArray(apiData.mileageRankingList)) {
264
- apiData.mileageRankingList.slice(0, 10).forEach((player) => {
265
- if (player && player.tmpName && typeof player.distance !== 'undefined' && typeof player.ranking !== 'undefined') {
266
- const isTop3 = player.ranking <= 3;
267
- const item = createLeaderboardItem(player.ranking, player.tmpName, player.distance, false, isTop3);
268
- topRankings.appendChild(item);
269
- }
270
- });
271
- }
472
+ function fmtDist(mileage) {
473
+ const r = formatMileage(mileage);
474
+ return r.value + ' ' + r.unit;
475
+ }
272
476
 
273
- // 渲染当前玩家排名
274
- if (apiData.playerMileageRanking && apiData.playerMileageRanking.tmpName && typeof apiData.playerMileageRanking.ranking !== 'undefined') {
275
- const currentItem = createLeaderboardItem(
276
- apiData.playerMileageRanking.ranking,
277
- apiData.playerMileageRanking.tmpName,
278
- apiData.playerMileageRanking.distance,
279
- true,
280
- false
281
- );
282
- currentPlayerContainer.appendChild(currentItem);
283
- } else {
284
- // 如果没有当前玩家数据,隐藏该部分
285
- const divider = document.querySelector('.divider');
286
- const currentPlayerSection = document.querySelector('.current-player-container');
287
- if (divider) divider.style.display = 'none';
288
- if (currentPlayerSection) currentPlayerSection.style.display = 'none';
289
- }
477
+ function avatarHtml(url, name) {
478
+ const fb = (name || '?').charAt(0).toUpperCase();
479
+ return `<div style="position:relative;width:100%;height:100%;">
480
+ <img src="${url || ''}" style="width:100%;height:100%;object-fit:cover;border-radius:50%;"
481
+ onerror="this.style.display='none';this.nextElementSibling.style.display='flex';">
482
+ <div style="display:none;position:absolute;inset:0;border-radius:50%;background:linear-gradient(135deg,#ff6b00,#ff3d00);align-items:center;justify-content:center;font-size:18px;font-weight:800;color:#fff;">${fb}</div>
483
+ </div>`;
290
484
  }
291
485
 
292
- function init(data) {
293
- if (!data) {
294
- console.error('数据无效');
295
- return;
486
+ function setData(apiData) {
487
+ if (!apiData) return;
488
+
489
+ const titles = { 1: '总里程排行榜', 2: '今日里程排行榜' };
490
+ const subs = { 1: 'ALL-TIME MILEAGE RANKING', 2: 'TODAY\'S MILEAGE RANKING' };
491
+ const footers = { 1: '* 数据自 2025年8月23日 20:00 开始统计', 2: '* 每日 0:00 重置统计' };
492
+
493
+ document.getElementById('header-title').textContent = titles[apiData.rankingType] || '里程排行榜';
494
+ document.getElementById('header-subtitle').textContent = subs[apiData.rankingType] || 'MILEAGE RANKING';
495
+ document.getElementById('footer').textContent = footers[apiData.rankingType] || '';
496
+
497
+ const list = (apiData.mileageRankingList || []).slice(0, 10);
498
+ const maxDist = list.length > 0 ? Math.max(...list.map(p => parseInt(p.distance) || 0)) : 1;
499
+
500
+ // #1 Hero
501
+ if (list[0]) {
502
+ const p = list[0];
503
+ const d = formatMileage(p.distance);
504
+ document.getElementById('hero').style.display = '';
505
+ document.getElementById('hero').innerHTML = `
506
+ <div class="hero-crown">👑</div>
507
+ <div class="hero-info">
508
+ <div class="hero-name">${p.tmpName || '未知'}</div>
509
+ <div class="hero-rank">#1 LEADER</div>
510
+ </div>
511
+ <div class="hero-distance">${d.value}<span class="hero-distance-unit">${d.unit}</span></div>`;
296
512
  }
297
513
 
298
- const topRankings = document.getElementById('top-rankings');
299
- const currentPlayerContainer = document.getElementById('current-player');
300
-
301
- // 清空现有内容
302
- topRankings.innerHTML = '';
303
- currentPlayerContainer.innerHTML = '';
304
-
305
- // 渲染前10名排行榜
306
- if (data.topRankings && Array.isArray(data.topRankings)) {
307
- data.topRankings.slice(0, 10).forEach((player, index) => {
308
- if (player && player.name && typeof player.mileage !== 'undefined') {
309
- const rank = index + 1;
310
- const isTop3 = rank <= 3;
311
- const item = createLeaderboardItem(rank, player.name, player.mileage, false, isTop3);
312
- topRankings.appendChild(item);
313
- }
514
+ // #2 & #3
515
+ if (list[1] || list[2]) {
516
+ document.getElementById('podium-row').style.display = '';
517
+ let html = '';
518
+ [list[1], list[2]].forEach((p, i) => {
519
+ if (!p) return;
520
+ const cls = i === 0 ? 'second' : 'third';
521
+ const medal = i === 0 ? '🥈' : '🥉';
522
+ html += `
523
+ <div class="podium-card ${cls}">
524
+ <div class="podium-medal">${medal}</div>
525
+ <div class="podium-card-info">
526
+ <div class="podium-card-name">${p.tmpName || '未知'}</div>
527
+ </div>
528
+ <div class="podium-card-dist">${fmtDist(p.distance)}</div>
529
+ </div>`;
314
530
  });
531
+ document.getElementById('podium-row').innerHTML = html;
315
532
  }
316
533
 
317
- // 渲染当前玩家排名
318
- if (data.currentPlayer && data.currentPlayer.name && typeof data.currentPlayer.rank !== 'undefined') {
319
- const currentItem = createLeaderboardItem(
320
- data.currentPlayer.rank,
321
- data.currentPlayer.name,
322
- data.currentPlayer.mileage,
323
- true,
324
- false
325
- );
326
- currentPlayerContainer.appendChild(currentItem);
327
- } else {
328
- // 如果没有当前玩家数据,隐藏该部分
329
- const divider = document.querySelector('.divider');
330
- const currentPlayerSection = document.querySelector('.current-player-container');
331
- if (divider) divider.style.display = 'none';
332
- if (currentPlayerSection) currentPlayerSection.style.display = 'none';
534
+ // #4-10 with progress bar
535
+ const rankList = document.getElementById('rank-list');
536
+ rankList.innerHTML = '';
537
+ for (let i = 3; i < list.length; i++) {
538
+ const p = list[i];
539
+ const pct = Math.max(5, ((parseInt(p.distance) || 0) / maxDist) * 100);
540
+ rankList.innerHTML += `
541
+ <div class="rank-item">
542
+ <div class="rank-number">${p.ranking}</div>
543
+ <div class="rank-name">${p.tmpName || '未知'}</div>
544
+ <div class="rank-bar"><div class="rank-bar-fill" style="width:${pct}%"></div></div>
545
+ <div class="rank-distance">${fmtDist(p.distance)}</div>
546
+ </div>`;
333
547
  }
334
- }
335
548
 
336
- // 示例数据 - 实际使用时将被外部数据替换
337
- const sampleData = {
338
- topRankings: [
339
- { name: "Afo780", mileage: 347167 },
340
- { name: "lαdу ναlєяijα", mileage: 331177 },
341
- { name: "Stefan Z", mileage: 330658 },
342
- { name: "YorkshireSlacka", mileage: 328871 },
343
- { name: "Sun [PL]", mileage: 327208 },
344
- { name: "joewales96 LAG", mileage: 324952 },
345
- { name: "Turbo_Express", mileage: 320211 },
346
- { name: "gapcio9933", mileage: 319599 },
347
- { name: "R8 anderson", mileage: 319004 },
348
- { name: "lorddarki85", mileage: 317788 }
349
- ],
350
- currentPlayer: {
351
- rank: 3365,
352
- name: "ZyRoX Drum",
353
- mileage: 59515
549
+ // Current Player
550
+ const cp = apiData.playerMileageRanking;
551
+ if (cp && cp.tmpName && typeof cp.ranking !== 'undefined') {
552
+ document.getElementById('divider').style.display = '';
553
+ document.getElementById('current-section').style.display = '';
554
+ document.getElementById('current-player').innerHTML = `
555
+ <div class="current-card">
556
+ <div class="current-rank">#${cp.ranking}</div>
557
+ <div class="current-name">${cp.tmpName}</div>
558
+ <div class="current-distance">${fmtDist(cp.distance)}</div>
559
+ </div>`;
354
560
  }
355
- };
356
-
357
- // 页面加载时初始化示例数据
358
- document.addEventListener('DOMContentLoaded', function() {
359
- init(sampleData);
360
- });
561
+ }
361
562
  </script>
362
563
  </body>
363
564
  </html>