koishi-plugin-ets2-tools-tmp 3.0.5 → 3.1.0

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.
@@ -0,0 +1,581 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>积分排行榜</title>
6
+ <style>
7
+ @font-face {
8
+ font-family: 'segui-emj';
9
+ src: url('./package/SEGUIEMJ.TTF');
10
+ font-weight: normal;
11
+ font-style: normal;
12
+ }
13
+
14
+ * {
15
+ box-sizing: border-box;
16
+ }
17
+
18
+ body {
19
+ font-family: 'segui-emj', 'Microsoft YaHei', 'PingFang SC', sans-serif;
20
+ margin: 0;
21
+ padding: 0;
22
+ background-color: #000;
23
+ }
24
+
25
+ #container {
26
+ width: 520px;
27
+ background: linear-gradient(160deg, #1a0b2e 0%, #16213e 35%, #0f3460 70%, #1a0b2e 100%);
28
+ padding: 0 0 20px 0;
29
+ position: relative;
30
+ overflow: hidden;
31
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
32
+ }
33
+
34
+ /* 装饰性背景光晕 */
35
+ #container::before {
36
+ content: '';
37
+ position: absolute;
38
+ top: -100px;
39
+ left: -100px;
40
+ width: 300px;
41
+ height: 300px;
42
+ background: radial-gradient(circle, rgba(255, 215, 0, 0.15) 0%, transparent 70%);
43
+ pointer-events: none;
44
+ }
45
+
46
+ #container::after {
47
+ content: '';
48
+ position: absolute;
49
+ bottom: -100px;
50
+ right: -100px;
51
+ width: 300px;
52
+ height: 300px;
53
+ background: radial-gradient(circle, rgba(138, 43, 226, 0.15) 0%, transparent 70%);
54
+ pointer-events: none;
55
+ }
56
+
57
+ .header {
58
+ padding: 28px 24px 20px;
59
+ text-align: center;
60
+ position: relative;
61
+ z-index: 1;
62
+ }
63
+
64
+ .header-icon {
65
+ font-size: 36px;
66
+ margin-bottom: 8px;
67
+ filter: drop-shadow(0 0 12px rgba(255, 215, 0, 0.6));
68
+ }
69
+
70
+ .header-title {
71
+ color: transparent;
72
+ background: linear-gradient(135deg, #ffd700 0%, #ffaa00 50%, #ff6b35 100%);
73
+ -webkit-background-clip: text;
74
+ background-clip: text;
75
+ font-size: 26px;
76
+ font-weight: 800;
77
+ letter-spacing: 3px;
78
+ text-shadow: 0 2px 8px rgba(255, 215, 0, 0.3);
79
+ margin: 0;
80
+ }
81
+
82
+ .header-subtitle {
83
+ color: #a8b2c8;
84
+ font-size: 12px;
85
+ margin-top: 6px;
86
+ letter-spacing: 1px;
87
+ }
88
+
89
+ .header-decoration {
90
+ width: 80px;
91
+ height: 2px;
92
+ background: linear-gradient(90deg, transparent, #ffd700, transparent);
93
+ margin: 12px auto 0;
94
+ }
95
+
96
+ /* 前三名特殊区域 */
97
+ .top3-container {
98
+ padding: 8px 20px 20px;
99
+ display: flex;
100
+ justify-content: center;
101
+ align-items: flex-end;
102
+ gap: 12px;
103
+ position: relative;
104
+ z-index: 1;
105
+ }
106
+
107
+ .top3-item {
108
+ flex: 1;
109
+ max-width: 145px;
110
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.02) 100%);
111
+ border-radius: 12px;
112
+ padding: 16px 8px 12px;
113
+ text-align: center;
114
+ position: relative;
115
+ backdrop-filter: blur(10px);
116
+ border: 1px solid rgba(255, 255, 255, 0.1);
117
+ }
118
+
119
+ .top3-item.rank-1 {
120
+ background: linear-gradient(180deg, rgba(255, 215, 0, 0.25) 0%, rgba(255, 165, 0, 0.1) 100%);
121
+ border-color: rgba(255, 215, 0, 0.5);
122
+ box-shadow: 0 0 24px rgba(255, 215, 0, 0.4), inset 0 0 12px rgba(255, 215, 0, 0.1);
123
+ transform: translateY(-12px);
124
+ order: 2;
125
+ }
126
+
127
+ .top3-item.rank-2 {
128
+ background: linear-gradient(180deg, rgba(192, 192, 192, 0.2) 0%, rgba(150, 150, 150, 0.08) 100%);
129
+ border-color: rgba(192, 192, 192, 0.4);
130
+ box-shadow: 0 0 16px rgba(192, 192, 192, 0.3);
131
+ order: 1;
132
+ }
133
+
134
+ .top3-item.rank-3 {
135
+ background: linear-gradient(180deg, rgba(205, 127, 50, 0.2) 0%, rgba(160, 100, 40, 0.08) 100%);
136
+ border-color: rgba(205, 127, 50, 0.4);
137
+ box-shadow: 0 0 16px rgba(205, 127, 50, 0.3);
138
+ order: 3;
139
+ }
140
+
141
+ .crown {
142
+ font-size: 22px;
143
+ margin-bottom: 4px;
144
+ filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5));
145
+ }
146
+
147
+ .rank-1 .crown { font-size: 28px; }
148
+
149
+ .top3-rank-num {
150
+ font-size: 32px;
151
+ font-weight: 900;
152
+ color: #ffffff;
153
+ margin: 4px 0;
154
+ text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
155
+ line-height: 1;
156
+ }
157
+
158
+ .rank-1 .top3-rank-num { color: #ffd700; text-shadow: 0 0 12px rgba(255, 215, 0, 0.8); }
159
+ .rank-2 .top3-rank-num { color: #e0e0e0; text-shadow: 0 0 8px rgba(192, 192, 192, 0.6); }
160
+ .rank-3 .top3-rank-num { color: #cd7f32; text-shadow: 0 0 8px rgba(205, 127, 50, 0.6); }
161
+
162
+ .top3-avatar {
163
+ width: 56px;
164
+ height: 56px;
165
+ border-radius: 50%;
166
+ margin: 8px auto;
167
+ display: block;
168
+ border: 2px solid rgba(255, 255, 255, 0.3);
169
+ object-fit: cover;
170
+ background: rgba(0, 0, 0, 0.3);
171
+ }
172
+
173
+ .rank-1 .top3-avatar { width: 64px; height: 64px; border-color: rgba(255, 215, 0, 0.6); }
174
+
175
+ .top3-name {
176
+ color: #ffffff;
177
+ font-size: 13px;
178
+ font-weight: 700;
179
+ margin: 6px 0 2px;
180
+ white-space: nowrap;
181
+ overflow: hidden;
182
+ text-overflow: ellipsis;
183
+ text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
184
+ }
185
+
186
+ .top3-teamid {
187
+ color: #a8b2c8;
188
+ font-size: 10px;
189
+ margin-bottom: 4px;
190
+ }
191
+
192
+ .top3-teamid span {
193
+ color: #ffd700;
194
+ font-weight: 600;
195
+ }
196
+
197
+ .top3-points {
198
+ color: #ffd700;
199
+ font-size: 14px;
200
+ font-weight: 800;
201
+ text-shadow: 0 0 6px rgba(255, 215, 0, 0.4);
202
+ }
203
+
204
+ .rank-2 .top3-points { color: #e0e0e0; text-shadow: 0 0 6px rgba(192, 192, 192, 0.4); }
205
+ .rank-3 .top3-points { color: #cd7f32; text-shadow: 0 0 6px rgba(205, 127, 50, 0.4); }
206
+
207
+ .top3-points-label {
208
+ color: #888;
209
+ font-size: 10px;
210
+ margin-left: 2px;
211
+ }
212
+
213
+ /* 第4-10名列表 */
214
+ .rank-list {
215
+ padding: 0 20px;
216
+ position: relative;
217
+ z-index: 1;
218
+ }
219
+
220
+ .rank-list-title {
221
+ color: #a8b2c8;
222
+ font-size: 12px;
223
+ text-align: center;
224
+ margin: 16px 0 12px;
225
+ letter-spacing: 2px;
226
+ position: relative;
227
+ }
228
+
229
+ .rank-list-title::before,
230
+ .rank-list-title::after {
231
+ content: '';
232
+ position: absolute;
233
+ top: 50%;
234
+ width: 60px;
235
+ height: 1px;
236
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
237
+ }
238
+
239
+ .rank-list-title::before { left: 80px; }
240
+ .rank-list-title::after { right: 80px; }
241
+
242
+ .rank-item {
243
+ display: flex;
244
+ align-items: center;
245
+ padding: 10px 14px;
246
+ margin-bottom: 6px;
247
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
248
+ border-radius: 8px;
249
+ border: 1px solid rgba(255, 255, 255, 0.06);
250
+ transition: all 0.3s ease;
251
+ }
252
+
253
+ .rank-item:hover {
254
+ background: rgba(255, 255, 255, 0.08);
255
+ border-color: rgba(255, 255, 255, 0.15);
256
+ }
257
+
258
+ .rank-num {
259
+ width: 36px;
260
+ height: 36px;
261
+ border-radius: 50%;
262
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05));
263
+ display: flex;
264
+ align-items: center;
265
+ justify-content: center;
266
+ color: #ffffff;
267
+ font-size: 14px;
268
+ font-weight: 700;
269
+ margin-right: 12px;
270
+ border: 1px solid rgba(255, 255, 255, 0.1);
271
+ flex-shrink: 0;
272
+ }
273
+
274
+ .rank-avatar {
275
+ width: 36px;
276
+ height: 36px;
277
+ border-radius: 50%;
278
+ margin-right: 12px;
279
+ border: 1px solid rgba(255, 255, 255, 0.15);
280
+ object-fit: cover;
281
+ background: rgba(0, 0, 0, 0.3);
282
+ flex-shrink: 0;
283
+ }
284
+
285
+ .rank-info {
286
+ flex: 1;
287
+ min-width: 0;
288
+ }
289
+
290
+ .rank-name {
291
+ color: #ffffff;
292
+ font-size: 14px;
293
+ font-weight: 600;
294
+ white-space: nowrap;
295
+ overflow: hidden;
296
+ text-overflow: ellipsis;
297
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
298
+ }
299
+
300
+ .rank-tmpid {
301
+ color: #666;
302
+ font-size: 10px;
303
+ margin-top: 2px;
304
+ }
305
+
306
+ .rank-tmpid .team-id {
307
+ color: #ffd700;
308
+ font-weight: 600;
309
+ margin-left: 6px;
310
+ }
311
+
312
+ .rank-points {
313
+ color: #ffd700;
314
+ font-size: 16px;
315
+ font-weight: 800;
316
+ text-shadow: 0 0 6px rgba(255, 215, 0, 0.3);
317
+ white-space: nowrap;
318
+ flex-shrink: 0;
319
+ }
320
+
321
+ .rank-points-label {
322
+ color: #888;
323
+ font-size: 10px;
324
+ margin-left: 2px;
325
+ }
326
+
327
+ /* 底部信息 */
328
+ .footer {
329
+ margin-top: 20px;
330
+ padding: 12px 20px 0;
331
+ text-align: center;
332
+ border-top: 1px solid rgba(255, 255, 255, 0.06);
333
+ position: relative;
334
+ z-index: 1;
335
+ }
336
+
337
+ .footer-total {
338
+ color: #a8b2c8;
339
+ font-size: 11px;
340
+ margin-bottom: 4px;
341
+ }
342
+
343
+ .footer-total span {
344
+ color: #ffd700;
345
+ font-weight: 700;
346
+ }
347
+
348
+ .footer-update {
349
+ color: #555;
350
+ font-size: 10px;
351
+ }
352
+
353
+ /* 当前用户排名区域 */
354
+ .current-player-section {
355
+ margin: 16px 20px 0;
356
+ padding: 14px 16px;
357
+ background: linear-gradient(90deg, rgba(255, 215, 0, 0.15) 0%, rgba(255, 165, 0, 0.08) 100%);
358
+ border-radius: 10px;
359
+ border: 1px solid rgba(255, 215, 0, 0.3);
360
+ box-shadow: 0 0 12px rgba(255, 215, 0, 0.15);
361
+ position: relative;
362
+ z-index: 1;
363
+ }
364
+
365
+ .current-player-title {
366
+ color: #ffd700;
367
+ font-size: 12px;
368
+ text-align: center;
369
+ margin-bottom: 10px;
370
+ letter-spacing: 2px;
371
+ font-weight: 600;
372
+ }
373
+
374
+ .current-player-content {
375
+ display: flex;
376
+ align-items: center;
377
+ gap: 12px;
378
+ }
379
+
380
+ .current-player-rank {
381
+ width: 44px;
382
+ height: 44px;
383
+ border-radius: 50%;
384
+ background: linear-gradient(135deg, #ffd700, #ff8c00);
385
+ display: flex;
386
+ align-items: center;
387
+ justify-content: center;
388
+ color: #1a0b2e;
389
+ font-size: 16px;
390
+ font-weight: 800;
391
+ flex-shrink: 0;
392
+ box-shadow: 0 0 10px rgba(255, 215, 0, 0.4);
393
+ }
394
+
395
+ .current-player-info {
396
+ flex: 1;
397
+ min-width: 0;
398
+ }
399
+
400
+ .current-player-name {
401
+ color: #ffffff;
402
+ font-size: 14px;
403
+ font-weight: 700;
404
+ white-space: nowrap;
405
+ overflow: hidden;
406
+ text-overflow: ellipsis;
407
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
408
+ }
409
+
410
+ .current-player-meta {
411
+ color: #a8b2c8;
412
+ font-size: 11px;
413
+ margin-top: 3px;
414
+ }
415
+
416
+ .current-player-meta .team-id {
417
+ color: #ffd700;
418
+ margin-left: 6px;
419
+ }
420
+
421
+ .current-player-points {
422
+ color: #ffd700;
423
+ font-size: 18px;
424
+ font-weight: 800;
425
+ text-shadow: 0 0 8px rgba(255, 215, 0, 0.4);
426
+ white-space: nowrap;
427
+ flex-shrink: 0;
428
+ }
429
+
430
+ .current-player-points-label {
431
+ color: #888;
432
+ font-size: 11px;
433
+ margin-left: 2px;
434
+ }
435
+ </style>
436
+ </head>
437
+ <body>
438
+ <div id="container">
439
+ <div class="header">
440
+ <div class="header-icon">🏆</div>
441
+ <h1 class="header-title">积 分 排 行 榜</h1>
442
+ <div class="header-subtitle">POINTS LEADERBOARD</div>
443
+ <div class="header-decoration"></div>
444
+ </div>
445
+
446
+ <!-- 前三名展示 -->
447
+ <div class="top3-container" id="top3"></div>
448
+
449
+ <!-- 第4-10名列表 -->
450
+ <div class="rank-list" id="rankList" style="display:none;">
451
+ <div class="rank-list-title">— 其他排名 —</div>
452
+ <div id="rankListContent"></div>
453
+ </div>
454
+
455
+ <!-- 当前用户排名 -->
456
+ <div class="current-player-section" id="currentPlayerSection" style="display:none;">
457
+ <div class="current-player-title">— 你的排名 —</div>
458
+ <div class="current-player-content" id="currentPlayerContent"></div>
459
+ </div>
460
+
461
+ <!-- 底部信息 -->
462
+ <div class="footer">
463
+ <div class="footer-total">总成员数: <span id="totalCount">0</span> 人</div>
464
+ <div class="footer-update">数据更新时间: <span id="updateTime">-</span></div>
465
+ </div>
466
+ </div>
467
+
468
+ <script>
469
+ function escapeHtml(text) {
470
+ if (!text) return '';
471
+ const map = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
472
+ return String(text).replace(/[&<>"']/g, m => map[m]);
473
+ }
474
+
475
+ function createAvatarHtml(player, sizeClass) {
476
+ if (!player.avatarUrl) {
477
+ return `<div class="${sizeClass}" style="display:flex; align-items:center; justify-content:center; color:#888;">${escapeHtml(player.tmpName.charAt(0))}</div>`;
478
+ }
479
+ return `<img class="${sizeClass}" src="${escapeHtml(player.avatarUrl)}" onerror="this.onerror=null; this.src=''; this.style.display='none'; this.parentElement.querySelector('.avatar-fallback').style.display='flex';">
480
+ <div class="${sizeClass} avatar-fallback" style="display:none; align-items:center; justify-content:center; color:#888;">${escapeHtml(player.tmpName.charAt(0))}</div>`;
481
+ }
482
+
483
+ function createTop3Item(player) {
484
+ const item = document.createElement('div');
485
+ const rankClass = `rank-${player.rank}`;
486
+ item.className = `top3-item ${rankClass}`;
487
+
488
+ const crowns = { 1: '👑', 2: '🥈', 3: '🥉' };
489
+
490
+ item.innerHTML = `
491
+ <div class="crown">${crowns[player.rank]}</div>
492
+ <div class="top3-rank-num">${player.rank}</div>
493
+ <div class="avatar-wrapper">${createAvatarHtml(player, 'top3-avatar')}</div>
494
+ <div class="top3-name">${escapeHtml(player.tmpName)}</div>
495
+ <div class="top3-teamid">车队编号: <span>#${escapeHtml(player.teamId)}</span></div>
496
+ <div class="top3-points">${player.rewardPoints.toLocaleString()}<span class="top3-points-label">分</span></div>
497
+ `;
498
+ return item;
499
+ }
500
+
501
+ function createRankItem(player) {
502
+ const item = document.createElement('div');
503
+ item.className = 'rank-item';
504
+
505
+ item.innerHTML = `
506
+ <div class="rank-num">${player.rank}</div>
507
+ <div class="avatar-wrapper">${createAvatarHtml(player, 'rank-avatar')}</div>
508
+ <div class="rank-info">
509
+ <div class="rank-name">${escapeHtml(player.tmpName)}</div>
510
+ <div class="rank-tmpid">TMP: ${escapeHtml(player.tmpId)}<span class="team-id">车队 #${escapeHtml(player.teamId)}</span></div>
511
+ </div>
512
+ <div class="rank-points">${player.rewardPoints.toLocaleString()}<span class="rank-points-label">分</span></div>
513
+ `;
514
+ return item;
515
+ }
516
+
517
+ function createCurrentPlayerItem(player) {
518
+ const content = document.createElement('div');
519
+ content.className = 'current-player-content';
520
+
521
+ content.innerHTML = `
522
+ <div class="current-player-rank">#${player.rank}</div>
523
+ <div class="current-player-info">
524
+ <div class="current-player-name">${escapeHtml(player.tmpName)}</div>
525
+ <div class="current-player-meta">TMP: ${escapeHtml(player.tmpId)}<span class="team-id">车队 #${escapeHtml(player.teamId)}</span></div>
526
+ </div>
527
+ <div class="current-player-points">${player.rewardPoints.toLocaleString()}<span class="current-player-points-label">分</span></div>
528
+ `;
529
+ return content;
530
+ }
531
+
532
+ function setData(data) {
533
+ if (!data || !data.top10 || !Array.isArray(data.top10)) {
534
+ console.error('数据无效');
535
+ return;
536
+ }
537
+
538
+ const top3Container = document.getElementById('top3');
539
+ const rankList = document.getElementById('rankList');
540
+ const rankListContent = document.getElementById('rankListContent');
541
+ const currentPlayerSection = document.getElementById('currentPlayerSection');
542
+ const currentPlayerContent = document.getElementById('currentPlayerContent');
543
+ const totalCountEl = document.getElementById('totalCount');
544
+ const updateTimeEl = document.getElementById('updateTime');
545
+
546
+ top3Container.innerHTML = '';
547
+ rankListContent.innerHTML = '';
548
+ currentPlayerContent.innerHTML = '';
549
+
550
+ // 渲染前三名
551
+ const top3 = data.top10.slice(0, 3);
552
+ top3.forEach(player => {
553
+ top3Container.appendChild(createTop3Item(player));
554
+ });
555
+
556
+ // 渲染第4-10名
557
+ const rest = data.top10.slice(3);
558
+ if (rest.length > 0) {
559
+ rankList.style.display = 'block';
560
+ rest.forEach(player => {
561
+ rankListContent.appendChild(createRankItem(player));
562
+ });
563
+ } else {
564
+ rankList.style.display = 'none';
565
+ }
566
+
567
+ // 渲染当前用户排名(仅在找到用户数据时显示)
568
+ if (data.currentPlayer && data.currentPlayer.rank) {
569
+ currentPlayerSection.style.display = 'block';
570
+ currentPlayerContent.appendChild(createCurrentPlayerItem(data.currentPlayer));
571
+ } else {
572
+ currentPlayerSection.style.display = 'none';
573
+ }
574
+
575
+ // 底部信息
576
+ if (totalCountEl) totalCountEl.textContent = (data.totalCount || 0).toLocaleString();
577
+ if (updateTimeEl) updateTimeEl.textContent = data.updateTime || '-';
578
+ }
579
+ </script>
580
+ </body>
581
+ </html>