koishi-plugin-rocom 1.0.18 → 1.0.19
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.
- package/lib/announcement-service.d.ts +21 -0
- package/lib/announcement-service.js +63 -0
- package/lib/async-control.d.ts +3 -0
- package/lib/async-control.js +48 -0
- package/lib/client.d.ts +48 -7
- package/lib/client.js +244 -125
- package/lib/commands/egg.js +66 -4
- package/lib/commands/merchant.js +144 -146
- package/lib/commands/query.js +148 -117
- package/lib/commands/ranking.d.ts +2 -0
- package/lib/commands/ranking.js +31 -0
- package/lib/commands/share-code.d.ts +2 -0
- package/lib/commands/share-code.js +66 -0
- package/lib/commands/tools.js +47 -59
- package/lib/egg-service.d.ts +82 -8
- package/lib/egg-service.js +235 -19
- package/lib/img//345/274/202/350/211/262.png +0 -0
- package/lib/img//347/202/253/345/275/251.png +0 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +16 -3
- package/lib/merchant-clock.d.ts +22 -0
- package/lib/merchant-clock.js +95 -0
- package/lib/merchant-service.d.ts +24 -0
- package/lib/merchant-service.js +148 -0
- package/lib/permissions.d.ts +16 -0
- package/lib/permissions.js +66 -0
- package/lib/pet-data-service.js +7 -9
- package/lib/pet-size.d.ts +13 -0
- package/lib/pet-size.js +54 -0
- package/lib/player-service.d.ts +37 -0
- package/lib/player-service.js +201 -0
- package/lib/ranking-service.d.ts +46 -0
- package/lib/ranking-service.js +137 -0
- package/lib/render-templates/announcement/detail.html +8 -0
- package/lib/render-templates/announcement/list.html +5 -0
- package/lib/render-templates/announcement/style.css +1 -0
- package/lib/render-templates/pet-ranking/index.html +99 -0
- package/lib/render-templates/pet-ranking/style.css +338 -0
- package/lib/render-templates/player-search/index.html +7 -0
- package/lib/render-templates/searcheggs/index.html +1 -1
- package/lib/render-templates/searcheggs/size.html +70 -68
- package/lib/render-templates/share-code-team/index.html +105 -0
- package/lib/render-templates/share-code-team/style.css +345 -0
- package/lib/render.d.ts +15 -2
- package/lib/render.js +120 -37
- package/lib/send-image.d.ts +1 -1
- package/lib/send-image.js +12 -1
- package/lib/share-code-service.d.ts +32 -0
- package/lib/share-code-service.js +184 -0
- package/lib/subscription-runner.d.ts +6 -0
- package/lib/subscription-runner.js +21 -0
- package/lib/subscription-send.d.ts +4 -2
- package/lib/subscription-send.js +45 -20
- package/lib/types.d.ts +5 -0
- package/lib/user.d.ts +5 -0
- package/package.json +4 -1
- package/readme.md +145 -124
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RANKING_META = void 0;
|
|
4
|
+
exports.parseRankingArgs = parseRankingArgs;
|
|
5
|
+
exports.formatRankingTime = formatRankingTime;
|
|
6
|
+
exports.buildRankingView = buildRankingView;
|
|
7
|
+
exports.buildRankingText = buildRankingText;
|
|
8
|
+
const client_1 = require("./client");
|
|
9
|
+
exports.RANKING_META = {
|
|
10
|
+
shining: {
|
|
11
|
+
title: '异色精灵排行榜',
|
|
12
|
+
subtitle: '按异色精灵收集数排名',
|
|
13
|
+
label: '异色',
|
|
14
|
+
otherLabel: '炫彩',
|
|
15
|
+
countField: 'collected_shining_pet_count',
|
|
16
|
+
otherCountField: 'collected_glass_pet_count',
|
|
17
|
+
theme: 'shining',
|
|
18
|
+
},
|
|
19
|
+
glass: {
|
|
20
|
+
title: '炫彩精灵排行榜',
|
|
21
|
+
subtitle: '按炫彩精灵收集数排名',
|
|
22
|
+
label: '炫彩',
|
|
23
|
+
otherLabel: '异色',
|
|
24
|
+
countField: 'collected_glass_pet_count',
|
|
25
|
+
otherCountField: 'collected_shining_pet_count',
|
|
26
|
+
theme: 'glass',
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
// 单参数 1–50 视为数量;其他纯数字视为 UID;两参数分别为 UID/数量。
|
|
30
|
+
function parseRankingArgs(text, primaryUid = '') {
|
|
31
|
+
const parts = String(text || '').trim().split(/\s+/).filter(Boolean);
|
|
32
|
+
if (parts.length > 2)
|
|
33
|
+
throw new Error('用法:排行榜 [UID] [数量]');
|
|
34
|
+
let uid = '';
|
|
35
|
+
let limit = 10;
|
|
36
|
+
if (parts.length === 1) {
|
|
37
|
+
const value = parts[0];
|
|
38
|
+
if (/^\d+$/.test(value) && Number(value) >= 1 && Number(value) <= 50) {
|
|
39
|
+
limit = Number(value);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
uid = value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else if (parts.length === 2) {
|
|
46
|
+
uid = parts[0];
|
|
47
|
+
if (!/^\d+$/.test(parts[1]))
|
|
48
|
+
throw new Error('数量必须是 1–50 的整数');
|
|
49
|
+
limit = Number(parts[1]);
|
|
50
|
+
}
|
|
51
|
+
if (uid && !/^\d+$/.test(uid))
|
|
52
|
+
throw new Error('UID 只能包含数字');
|
|
53
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 50) {
|
|
54
|
+
throw new Error('数量必须是 1–50 的整数');
|
|
55
|
+
}
|
|
56
|
+
return { uid: uid || primaryUid, limit };
|
|
57
|
+
}
|
|
58
|
+
function toInt(value, fallback = 0) {
|
|
59
|
+
const n = Number(value);
|
|
60
|
+
return Number.isFinite(n) ? Math.trunc(n) : fallback;
|
|
61
|
+
}
|
|
62
|
+
// 无时区的时间字符串按 +08:00 解释(与上游一致)。
|
|
63
|
+
function formatRankingTime(value) {
|
|
64
|
+
const text = String(value ?? '').trim();
|
|
65
|
+
if (!text)
|
|
66
|
+
return '未知';
|
|
67
|
+
const normalized = /^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/.test(text) && !/(Z|[+-]\d{2}:?\d{2})$/.test(text)
|
|
68
|
+
? `${text.replace(' ', 'T')}+08:00`
|
|
69
|
+
: text.replace('Z', '+00:00');
|
|
70
|
+
const date = new Date(normalized);
|
|
71
|
+
if (Number.isNaN(date.getTime()))
|
|
72
|
+
return text;
|
|
73
|
+
const shifted = new Date(date.getTime() + 8 * 3600_000);
|
|
74
|
+
const pad = (v) => String(v).padStart(2, '0');
|
|
75
|
+
return `${pad(shifted.getUTCMonth() + 1)}-${pad(shifted.getUTCDate())} ${pad(shifted.getUTCHours())}:${pad(shifted.getUTCMinutes())}`;
|
|
76
|
+
}
|
|
77
|
+
function avatarUrl(baseUrl, cardIcon) {
|
|
78
|
+
const iconId = String(cardIcon ?? '').trim();
|
|
79
|
+
if (!iconId)
|
|
80
|
+
return '';
|
|
81
|
+
return `${String(baseUrl || '').replace(/\/$/, '')}/api/v1/resources/wiki/assets/profile/avatar/${iconId}.png`;
|
|
82
|
+
}
|
|
83
|
+
function normalizeItem(item, meta, baseUrl) {
|
|
84
|
+
const rank = toInt(item?.rank);
|
|
85
|
+
return {
|
|
86
|
+
rank,
|
|
87
|
+
podiumClass: rank >= 1 && rank <= 3 ? `podium-${rank}` : '',
|
|
88
|
+
playerName: String(item?.player_name || '未记录名称'),
|
|
89
|
+
avatar: avatarUrl(baseUrl, item?.card_icon_selected),
|
|
90
|
+
signature: String(item?.card_signature || '暂无签名'),
|
|
91
|
+
primaryCount: toInt(item?.[meta.countField]),
|
|
92
|
+
secondaryCount: toInt(item?.[meta.otherCountField]),
|
|
93
|
+
sampleCount: toInt(item?.sample_count),
|
|
94
|
+
lastSeen: formatRankingTime(item?.last_seen_at),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function buildRankingView(payload, rankType, baseUrl, requestedUid = '', now = new Date()) {
|
|
98
|
+
const meta = exports.RANKING_META[rankType] || exports.RANKING_META.shining;
|
|
99
|
+
const data = (0, client_1.isObject)(payload) ? payload : {};
|
|
100
|
+
const items = (Array.isArray(data.items) ? data.items : [])
|
|
101
|
+
.filter(item => (0, client_1.isObject)(item))
|
|
102
|
+
.map(item => normalizeItem(item, meta, baseUrl));
|
|
103
|
+
let current = null;
|
|
104
|
+
if ((0, client_1.isObject)(data.current)) {
|
|
105
|
+
current = normalizeItem(data.current, meta, baseUrl);
|
|
106
|
+
current.uid = String(data.current.uid || requestedUid || '');
|
|
107
|
+
current.titleText = '该玩家名次';
|
|
108
|
+
}
|
|
109
|
+
const pad = (v) => String(v).padStart(2, '0');
|
|
110
|
+
const updatedAt = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}`;
|
|
111
|
+
return {
|
|
112
|
+
...meta,
|
|
113
|
+
total: toInt(data.total),
|
|
114
|
+
items,
|
|
115
|
+
current,
|
|
116
|
+
requestedUid: String(requestedUid || ''),
|
|
117
|
+
shownCount: items.length,
|
|
118
|
+
updatedAt,
|
|
119
|
+
commandHint: `/${meta.label}排行榜 [UID] [数量] · 数量支持 1-50`,
|
|
120
|
+
copyright: 'Koishi & WeGame 洛克王国插件',
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function buildRankingText(data) {
|
|
124
|
+
const lines = [`${data.title || '精灵排行榜'}(共 ${data.total || 0} 名)`];
|
|
125
|
+
for (const item of data.items || []) {
|
|
126
|
+
lines.push(`#${item.rank} ${item.playerName}:${data.label} ${item.primaryCount},${data.otherLabel} ${item.secondaryCount}`);
|
|
127
|
+
}
|
|
128
|
+
if (data.current) {
|
|
129
|
+
lines.push(`该玩家名次:#${data.current.rank} ${data.current.playerName},${data.label} ${data.current.primaryCount}`);
|
|
130
|
+
}
|
|
131
|
+
else if (data.requestedUid) {
|
|
132
|
+
lines.push(`UID ${data.requestedUid} 暂无排行榜记录。`);
|
|
133
|
+
}
|
|
134
|
+
if (!data.items?.length && !data.current)
|
|
135
|
+
lines.push('当前排行榜暂无记录。');
|
|
136
|
+
return lines.join('\n');
|
|
137
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN"><head><meta charset="utf-8"><link rel="stylesheet" href="{{_res_path}}render-templates/announcement/style.css"></head>
|
|
3
|
+
<body><main class="announcement-detail-page">
|
|
4
|
+
<header><span>洛克王国 · 公告 {{id}}</span><h1>{{title}}</h1><p>{{publishedAt}}</p></header>
|
|
5
|
+
{{each blocks entry}}<section>{{if entry.text}}<p class="content">{{entry.text}}</p>{{/if}}{{if entry.image}}<img src="{{entry.image}}" alt="公告图片" onerror="this.style.display='none'">{{/if}}</section>{{/each}}
|
|
6
|
+
{{if !blocks.length}}<p>暂无正文</p>{{/if}}
|
|
7
|
+
<footer>{{commandHint}}<br>{{copyright}}</footer>
|
|
8
|
+
</main></body></html>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN"><head><meta charset="utf-8"><link rel="stylesheet" href="{{_res_path}}render-templates/announcement/style.css"></head>
|
|
3
|
+
<body><main class="announcement-list-page"><header><span>洛克王国 · 第 {{page}} 页</span><h1>{{title}}</h1></header>
|
|
4
|
+
{{each items item}}<article><h2>{{item.title}}</h2><p>{{item.summary}}</p><small>#{{item.id}} · {{item.publishedAt}}</small></article>{{/each}}
|
|
5
|
+
{{if !items.length}}<p>当前页暂无公告</p>{{/if}}<footer>{{commandHint}}<br>{{copyright}}</footer></main></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@font-face{font-family:Rocom;src:url('../../ttf/HYWenHei-85W-1.ttf')}*{box-sizing:border-box}body{margin:0;background:#eee7d9;color:#473828;font-family:Rocom,'Microsoft YaHei',sans-serif}.announcement-detail-page,.announcement-list-page{width:1080px;padding:48px;background:#faf5e9}header{border-bottom:3px solid #bc914a;padding-bottom:22px}h1{font-size:38px;line-height:1.5}h2{font-size:27px}p{font-size:23px;line-height:1.8;overflow-wrap:anywhere}header span,small{color:#947346;font-size:18px}.content{white-space:pre-wrap}section img{display:block;width:auto;max-width:100%;height:auto;margin:20px auto}article{padding:20px 0;border-bottom:1px solid #dac9ad}footer{font-size:18px;line-height:1.8;margin-top:36px;color:#947346}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=1080, initial-scale=1">
|
|
6
|
+
<title>{{title}}</title>
|
|
7
|
+
<link rel="stylesheet" href="{{_res_path}}render/pet-ranking/style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<section class="pet-ranking-page theme-{{theme}}">
|
|
11
|
+
<header class="ranking-header">
|
|
12
|
+
<div class="title-icon">
|
|
13
|
+
{{if theme == "shining"}}
|
|
14
|
+
<img src="{{_res_path}}img/异色.png" alt="">
|
|
15
|
+
{{else}}
|
|
16
|
+
<img src="{{_res_path}}img/炫彩.png" alt="">
|
|
17
|
+
{{/if}}
|
|
18
|
+
</div>
|
|
19
|
+
<div class="title-copy">
|
|
20
|
+
<h1>{{title}}</h1>
|
|
21
|
+
<p>{{subtitle}} · 当前收录 {{total}} 名玩家</p>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="header-stat">
|
|
24
|
+
<span>TOP</span>
|
|
25
|
+
<strong>{{shownCount}}</strong>
|
|
26
|
+
</div>
|
|
27
|
+
</header>
|
|
28
|
+
|
|
29
|
+
{{if current}}
|
|
30
|
+
<section class="current-rank">
|
|
31
|
+
<div class="current-label">{{current.titleText || '该玩家名次'}}</div>
|
|
32
|
+
<div class="current-rank-value">#{{current.rank}}</div>
|
|
33
|
+
<div class="avatar-shell current-avatar">
|
|
34
|
+
<img class="avatar-fallback" src="{{_res_path}}img/头像黑色圆底.png" alt="">
|
|
35
|
+
{{if current.avatar}}
|
|
36
|
+
<img class="avatar-image" src="{{current.avatar}}" alt="" onerror="this.style.display='none'">
|
|
37
|
+
{{/if}}
|
|
38
|
+
</div>
|
|
39
|
+
<div class="current-player">
|
|
40
|
+
<strong>{{current.playerName}}</strong>
|
|
41
|
+
<span>UID {{current.uid}}</span>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="current-count">
|
|
44
|
+
<strong>{{current.primaryCount}}</strong>
|
|
45
|
+
<span>{{label}}精灵</span>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="current-count secondary">
|
|
48
|
+
<strong>{{current.secondaryCount}}</strong>
|
|
49
|
+
<span>{{otherLabel}}精灵</span>
|
|
50
|
+
</div>
|
|
51
|
+
</section>
|
|
52
|
+
{{else if requestedUid}}
|
|
53
|
+
<section class="current-rank current-empty">
|
|
54
|
+
<div class="current-label">该玩家名次</div>
|
|
55
|
+
<div class="empty-copy">UID {{requestedUid}} 暂无排行榜记录</div>
|
|
56
|
+
</section>
|
|
57
|
+
{{/if}}
|
|
58
|
+
|
|
59
|
+
<main class="ranking-list">
|
|
60
|
+
<div class="ranking-columns">
|
|
61
|
+
<span>名次 / 玩家</span>
|
|
62
|
+
<span>收集统计</span>
|
|
63
|
+
</div>
|
|
64
|
+
{{each items item}}
|
|
65
|
+
<article class="ranking-row {{item.podiumClass}}">
|
|
66
|
+
<div class="rank-number">{{item.rank}}</div>
|
|
67
|
+
<div class="avatar-shell">
|
|
68
|
+
<img class="avatar-fallback" src="{{_res_path}}img/头像黑色圆底.png" alt="">
|
|
69
|
+
{{if item.avatar}}
|
|
70
|
+
<img class="avatar-image" src="{{item.avatar}}" alt="" onerror="this.style.display='none'">
|
|
71
|
+
{{/if}}
|
|
72
|
+
</div>
|
|
73
|
+
<div class="player-copy">
|
|
74
|
+
<div class="player-name">{{item.playerName}}</div>
|
|
75
|
+
<div class="player-signature">{{item.signature}}</div>
|
|
76
|
+
<div class="player-meta">更新 {{item.lastSeen}} · 样本 {{item.sampleCount}}</div>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="count-block primary-count">
|
|
79
|
+
<strong>{{item.primaryCount}}</strong>
|
|
80
|
+
<span>{{label}}</span>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="count-block secondary-count">
|
|
83
|
+
<strong>{{item.secondaryCount}}</strong>
|
|
84
|
+
<span>{{otherLabel}}</span>
|
|
85
|
+
</div>
|
|
86
|
+
</article>
|
|
87
|
+
{{/each}}
|
|
88
|
+
{{if !items.length && !current}}
|
|
89
|
+
<div class="ranking-empty">当前排行榜暂无记录。</div>
|
|
90
|
+
{{/if}}
|
|
91
|
+
</main>
|
|
92
|
+
|
|
93
|
+
<footer class="ranking-footer">
|
|
94
|
+
<span>{{commandHint}}</span>
|
|
95
|
+
<span>{{updatedAt}} · {{copyright}}</span>
|
|
96
|
+
</footer>
|
|
97
|
+
</section>
|
|
98
|
+
</body>
|
|
99
|
+
</html>
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
@font-face {
|
|
2
|
+
font-family: "rocom-ranking";
|
|
3
|
+
src: url("../../ttf/HYWenHei-85W-1.ttf") format("truetype");
|
|
4
|
+
font-display: swap;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
:root {
|
|
8
|
+
--ink: #292621;
|
|
9
|
+
--muted: #80786c;
|
|
10
|
+
--paper: rgba(249, 245, 235, 0.96);
|
|
11
|
+
--row: rgba(255, 255, 255, 0.76);
|
|
12
|
+
--line: rgba(58, 49, 38, 0.12);
|
|
13
|
+
--accent: #a85c79;
|
|
14
|
+
--accent-soft: #f1dce6;
|
|
15
|
+
--secondary: #4e8274;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
html,
|
|
19
|
+
body {
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 24px;
|
|
22
|
+
background: url("../../img/bg.C8CUoi7I.jpg") no-repeat center top;
|
|
23
|
+
background-size: cover;
|
|
24
|
+
font-family: "rocom-ranking", "Microsoft YaHei", sans-serif;
|
|
25
|
+
letter-spacing: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.pet-ranking-page {
|
|
29
|
+
width: 1000px;
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
padding: 34px 38px 28px;
|
|
32
|
+
margin: 0 auto;
|
|
33
|
+
color: var(--ink);
|
|
34
|
+
background: var(--paper);
|
|
35
|
+
border: 1px solid rgba(255, 255, 255, 0.7);
|
|
36
|
+
border-radius: 8px;
|
|
37
|
+
box-shadow: 0 18px 46px rgba(31, 24, 17, 0.18);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.theme-glass {
|
|
41
|
+
--accent: #3f8f92;
|
|
42
|
+
--accent-soft: #d7ece9;
|
|
43
|
+
--secondary: #a45c79;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.ranking-header {
|
|
47
|
+
min-height: 88px;
|
|
48
|
+
display: grid;
|
|
49
|
+
grid-template-columns: 72px 1fr 110px;
|
|
50
|
+
gap: 18px;
|
|
51
|
+
align-items: center;
|
|
52
|
+
padding-bottom: 24px;
|
|
53
|
+
border-bottom: 2px solid var(--accent);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.title-icon {
|
|
57
|
+
width: 68px;
|
|
58
|
+
height: 68px;
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
background: var(--accent-soft);
|
|
63
|
+
border: 1px solid rgba(38, 31, 26, 0.08);
|
|
64
|
+
border-radius: 8px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.title-icon img {
|
|
68
|
+
width: 58px;
|
|
69
|
+
height: 58px;
|
|
70
|
+
object-fit: contain;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.title-copy h1 {
|
|
74
|
+
margin: 0;
|
|
75
|
+
font-size: 38px;
|
|
76
|
+
line-height: 1.15;
|
|
77
|
+
color: var(--ink);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.title-copy p {
|
|
81
|
+
margin: 8px 0 0;
|
|
82
|
+
font-size: 17px;
|
|
83
|
+
line-height: 1.35;
|
|
84
|
+
color: var(--muted);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.header-stat {
|
|
88
|
+
height: 64px;
|
|
89
|
+
display: flex;
|
|
90
|
+
flex-direction: column;
|
|
91
|
+
align-items: flex-end;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
color: var(--accent);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.header-stat span {
|
|
97
|
+
font-size: 14px;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.header-stat strong {
|
|
101
|
+
margin-top: 2px;
|
|
102
|
+
font-size: 34px;
|
|
103
|
+
line-height: 1;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.current-rank {
|
|
107
|
+
min-height: 88px;
|
|
108
|
+
display: grid;
|
|
109
|
+
grid-template-columns: 92px 72px 58px 1fr 118px 118px;
|
|
110
|
+
gap: 14px;
|
|
111
|
+
align-items: center;
|
|
112
|
+
margin: 22px 0;
|
|
113
|
+
padding: 16px 20px;
|
|
114
|
+
box-sizing: border-box;
|
|
115
|
+
background: var(--accent-soft);
|
|
116
|
+
border-left: 5px solid var(--accent);
|
|
117
|
+
border-radius: 6px;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.current-label {
|
|
121
|
+
font-size: 16px;
|
|
122
|
+
color: var(--muted);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.current-rank-value {
|
|
126
|
+
font-size: 28px;
|
|
127
|
+
color: var(--accent);
|
|
128
|
+
font-weight: 700;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.current-player {
|
|
132
|
+
min-width: 0;
|
|
133
|
+
display: flex;
|
|
134
|
+
flex-direction: column;
|
|
135
|
+
gap: 4px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.current-player strong {
|
|
139
|
+
overflow-wrap: anywhere;
|
|
140
|
+
font-size: 22px;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.current-player span {
|
|
144
|
+
font-size: 13px;
|
|
145
|
+
color: var(--muted);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.current-count {
|
|
149
|
+
display: flex;
|
|
150
|
+
flex-direction: column;
|
|
151
|
+
align-items: flex-end;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.current-count strong {
|
|
155
|
+
font-size: 28px;
|
|
156
|
+
color: var(--accent);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.current-count span {
|
|
160
|
+
font-size: 13px;
|
|
161
|
+
color: var(--muted);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.current-count.secondary strong {
|
|
165
|
+
color: var(--secondary);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.current-empty {
|
|
169
|
+
grid-template-columns: 92px 1fr;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.empty-copy {
|
|
173
|
+
font-size: 18px;
|
|
174
|
+
color: var(--muted);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.ranking-columns {
|
|
178
|
+
height: 32px;
|
|
179
|
+
display: flex;
|
|
180
|
+
align-items: center;
|
|
181
|
+
justify-content: space-between;
|
|
182
|
+
padding: 0 18px 0 106px;
|
|
183
|
+
color: var(--muted);
|
|
184
|
+
font-size: 13px;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.ranking-list {
|
|
188
|
+
display: flex;
|
|
189
|
+
flex-direction: column;
|
|
190
|
+
gap: 9px;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.ranking-row {
|
|
194
|
+
min-height: 92px;
|
|
195
|
+
display: grid;
|
|
196
|
+
grid-template-columns: 58px 64px 1fr 110px 92px;
|
|
197
|
+
gap: 14px;
|
|
198
|
+
align-items: center;
|
|
199
|
+
padding: 12px 18px;
|
|
200
|
+
box-sizing: border-box;
|
|
201
|
+
background: var(--row);
|
|
202
|
+
border: 1px solid var(--line);
|
|
203
|
+
border-radius: 6px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.ranking-row.podium-1,
|
|
207
|
+
.ranking-row.podium-2,
|
|
208
|
+
.ranking-row.podium-3 {
|
|
209
|
+
border-left: 5px solid var(--accent);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.rank-number {
|
|
213
|
+
width: 42px;
|
|
214
|
+
height: 42px;
|
|
215
|
+
display: flex;
|
|
216
|
+
align-items: center;
|
|
217
|
+
justify-content: center;
|
|
218
|
+
border-radius: 50%;
|
|
219
|
+
background: #ece7dc;
|
|
220
|
+
color: #686055;
|
|
221
|
+
font-size: 18px;
|
|
222
|
+
font-weight: 700;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.podium-1 .rank-number {
|
|
226
|
+
background: #e2bd58;
|
|
227
|
+
color: #3d2c0d;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.podium-2 .rank-number {
|
|
231
|
+
background: #c8c9cb;
|
|
232
|
+
color: #34373a;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.podium-3 .rank-number {
|
|
236
|
+
background: #c88f62;
|
|
237
|
+
color: #3f2818;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.avatar-shell {
|
|
241
|
+
position: relative;
|
|
242
|
+
width: 58px;
|
|
243
|
+
height: 58px;
|
|
244
|
+
overflow: hidden;
|
|
245
|
+
flex: 0 0 58px;
|
|
246
|
+
background: #e8e1d6;
|
|
247
|
+
border: 1px solid var(--line);
|
|
248
|
+
border-radius: 50%;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.current-avatar {
|
|
252
|
+
width: 52px;
|
|
253
|
+
height: 52px;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.avatar-fallback,
|
|
257
|
+
.avatar-image {
|
|
258
|
+
position: absolute;
|
|
259
|
+
inset: 0;
|
|
260
|
+
width: 100%;
|
|
261
|
+
height: 100%;
|
|
262
|
+
object-fit: cover;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.avatar-image {
|
|
266
|
+
z-index: 1;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.player-copy {
|
|
270
|
+
min-width: 0;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.player-name {
|
|
274
|
+
overflow-wrap: anywhere;
|
|
275
|
+
font-size: 20px;
|
|
276
|
+
line-height: 1.2;
|
|
277
|
+
font-weight: 700;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.player-signature {
|
|
281
|
+
margin-top: 4px;
|
|
282
|
+
overflow: hidden;
|
|
283
|
+
text-overflow: ellipsis;
|
|
284
|
+
white-space: nowrap;
|
|
285
|
+
font-size: 14px;
|
|
286
|
+
color: #655f56;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.player-meta {
|
|
290
|
+
margin-top: 5px;
|
|
291
|
+
font-size: 12px;
|
|
292
|
+
color: var(--muted);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.count-block {
|
|
296
|
+
display: flex;
|
|
297
|
+
flex-direction: column;
|
|
298
|
+
align-items: flex-end;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.count-block strong {
|
|
302
|
+
font-size: 28px;
|
|
303
|
+
line-height: 1;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.count-block span {
|
|
307
|
+
margin-top: 5px;
|
|
308
|
+
font-size: 12px;
|
|
309
|
+
color: var(--muted);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.primary-count strong {
|
|
313
|
+
color: var(--accent);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.secondary-count strong {
|
|
317
|
+
color: var(--secondary);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.ranking-empty {
|
|
321
|
+
padding: 24px;
|
|
322
|
+
text-align: center;
|
|
323
|
+
color: var(--muted);
|
|
324
|
+
background: var(--row);
|
|
325
|
+
border: 1px dashed var(--line);
|
|
326
|
+
border-radius: 6px;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.ranking-footer {
|
|
330
|
+
display: flex;
|
|
331
|
+
justify-content: space-between;
|
|
332
|
+
gap: 24px;
|
|
333
|
+
margin-top: 22px;
|
|
334
|
+
padding-top: 18px;
|
|
335
|
+
border-top: 1px solid var(--line);
|
|
336
|
+
font-size: 13px;
|
|
337
|
+
color: var(--muted);
|
|
338
|
+
}
|
|
@@ -39,6 +39,13 @@
|
|
|
39
39
|
</section>
|
|
40
40
|
{{/if}}
|
|
41
41
|
|
|
42
|
+
{{if collectedShining !== undefined || collectedGlass !== undefined}}
|
|
43
|
+
<section class="summary-strip">
|
|
44
|
+
<div class="summary-item">异色收集:{{collectedShining || '0'}}</div>
|
|
45
|
+
<div class="summary-item">炫彩收集:{{collectedGlass || '0'}}</div>
|
|
46
|
+
</section>
|
|
47
|
+
{{/if}}
|
|
48
|
+
{{if cardImageUrl}}<section class="signature-strip"><img src="{{cardImageUrl}}" style="max-width:100%;height:auto" onerror="this.style.display='none'" alt="名片"></section>{{/if}}
|
|
42
49
|
<main class="content-grid">
|
|
43
50
|
{{each sections section}}
|
|
44
51
|
<section class="panel">
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
<div class="info-value">{{total_stats}}</div>
|
|
77
77
|
</div>
|
|
78
78
|
<div class="info-item">
|
|
79
|
-
<div class="info-label"
|
|
79
|
+
<div class="info-label">{{if compatible_total_known === false}}当前预览数{{else}}可配种数{{/if}}</div>
|
|
80
80
|
<div class="info-value">{{total_compatible}}</div>
|
|
81
81
|
</div>
|
|
82
82
|
<div class="info-item">
|