koishi-plugin-ets2-tools-tmp 3.1.6 → 3.1.8
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/api/truckersMpApi.js +1 -1
- package/lib/api/truckersMpMapApi.js +1 -1
- package/lib/api/truckyAppApi.js +1 -1
- package/lib/command/tmpQuery/tmpQueryImg.js +1 -1
- package/lib/command/tmpVtcOnline/tmpVtcOnline.js +13 -0
- package/lib/command/tmpVtcOnline/tmpVtcOnlineImg.js +47 -0
- package/lib/command/tmpVtcOnline/tmpVtcOnlineText.js +22 -0
- package/lib/index.js +15 -0
- package/lib/resource/tmpVtcOnline.html +313 -0
- package/package.json +1 -1
package/lib/api/truckersMpApi.js
CHANGED
package/lib/api/truckyAppApi.js
CHANGED
|
@@ -165,7 +165,7 @@ module.exports = async (ctx, cfg, session, tmpId) => {
|
|
|
165
165
|
const steamApiKey = cfg.steamApi?.key;
|
|
166
166
|
if (steamApiKey) {
|
|
167
167
|
const steamId = playerInfo.data.steamId;
|
|
168
|
-
const url = `https://
|
|
168
|
+
const url = `https://evmapi.114512.xyz/proxy/steam/IPlayerService/GetOwnedGames/v1?key=${steamApiKey}&steamid=${steamId}&appids_filter[0]=227300&appids_filter[1]=270880&include_played_free_games=1`;
|
|
169
169
|
const response = await ctx.http.get(url);
|
|
170
170
|
if (response.response && response.response.game_count > 0) {
|
|
171
171
|
for (const game of response.response.games) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const tmpVtcOnlineText = require('./tmpVtcOnlineText');
|
|
2
|
+
const tmpVtcOnlineImg = require('./tmpVtcOnlineImg');
|
|
3
|
+
|
|
4
|
+
module.exports = async (ctx, cfg) => {
|
|
5
|
+
switch (cfg.tmpVtcOnline?.type) {
|
|
6
|
+
case 1:
|
|
7
|
+
return await tmpVtcOnlineText(ctx, cfg);
|
|
8
|
+
case 2:
|
|
9
|
+
return await tmpVtcOnlineImg(ctx, cfg);
|
|
10
|
+
default:
|
|
11
|
+
return '指令配置错误';
|
|
12
|
+
}
|
|
13
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const { segment } = require('koishi');
|
|
2
|
+
const { resolve } = require('path');
|
|
3
|
+
const common = require('../../util/common');
|
|
4
|
+
|
|
5
|
+
module.exports = async (ctx, cfg) => {
|
|
6
|
+
const vtcId = cfg.tmpActivityService?.api?.vtcId;
|
|
7
|
+
if (!vtcId) {
|
|
8
|
+
return '请先在活动查询配置中填写 VTC ID';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let result;
|
|
12
|
+
try {
|
|
13
|
+
result = await ctx.http.get(`https://www.cnly.top/api/player_online/api?vtcId=${encodeURIComponent(vtcId)}`);
|
|
14
|
+
} catch {
|
|
15
|
+
return '查询车队在线成员失败,请稍后重试';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!result || result.code !== 200 || !Array.isArray(result.data)) {
|
|
19
|
+
return '查询车队在线成员失败,请稍后重试';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const members = result.data;
|
|
23
|
+
const onlineMembers = members.filter(item => item.isOnline);
|
|
24
|
+
|
|
25
|
+
const rows = [];
|
|
26
|
+
for (let i = 0; i < onlineMembers.length; i += 3) {
|
|
27
|
+
rows.push(onlineMembers.slice(i, i + 3));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let page;
|
|
31
|
+
try {
|
|
32
|
+
page = await ctx.puppeteer.page();
|
|
33
|
+
await page.setViewport({ width: 800, height: 1200, deviceScaleFactor: 1.5 });
|
|
34
|
+
await page.goto(`file:///${resolve(__dirname, '../../resource/tmpVtcOnline.html')}`);
|
|
35
|
+
await page.evaluate(`setData(${JSON.stringify({ members, onlineMembers, rows })})`);
|
|
36
|
+
await common.sleep(100);
|
|
37
|
+
await page.waitForNetworkIdle();
|
|
38
|
+
const element = await page.$('#container');
|
|
39
|
+
return segment.image(await element.screenshot({ encoding: 'binary' }), 'image/jpg');
|
|
40
|
+
} catch {
|
|
41
|
+
return '渲染异常,请重试';
|
|
42
|
+
} finally {
|
|
43
|
+
if (page) {
|
|
44
|
+
await page.close();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module.exports = async (ctx, cfg) => {
|
|
2
|
+
const vtcId = cfg.tmpActivityService?.api?.vtcId;
|
|
3
|
+
if (!vtcId) {
|
|
4
|
+
return '请先在活动查询配置中填写 VTC ID';
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let result;
|
|
8
|
+
try {
|
|
9
|
+
result = await ctx.http.get(`https://www.cnly.top/api/player_online/api?vtcId=${encodeURIComponent(vtcId)}`);
|
|
10
|
+
} catch {
|
|
11
|
+
return '查询车队在线成员失败,请稍后重试';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!result || result.code !== 200 || !Array.isArray(result.data)) {
|
|
15
|
+
return '查询车队在线成员失败,请稍后重试';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const onlineMembers = result.data.filter(item => item.isOnline);
|
|
19
|
+
const lines = onlineMembers.map(item => `${item.name} - ${item.serverName || '未知服务器'}`);
|
|
20
|
+
|
|
21
|
+
return `车队在线成员(${onlineMembers.length}/${result.data.length})\n${lines.length ? lines.join('\n') : '当前没有成员在线'}`;
|
|
22
|
+
};
|
package/lib/index.js
CHANGED
|
@@ -23,6 +23,7 @@ const commands = {
|
|
|
23
23
|
addMember: require('./command/ets-app/addMember/addMemberV2'),
|
|
24
24
|
pointRanking: require('./command/ets-app/pointRanking/pointRanking'),
|
|
25
25
|
tmpVtc: require('./command/tmpVtc'),
|
|
26
|
+
tmpVtcOnline: require('./command/tmpVtcOnline/tmpVtcOnline'),
|
|
26
27
|
tmpFootprint: require('./command/tmpFootprint')
|
|
27
28
|
};
|
|
28
29
|
const { ActivityService } = require('./command/tmpActivityService');
|
|
@@ -78,6 +79,7 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
78
79
|
tmpMileageRanking: koishi_1.Schema.boolean().default(true).description('是否启用里程排行榜'),
|
|
79
80
|
pointRanking: koishi_1.Schema.boolean().default(false).description('是否启用积分排行榜'),
|
|
80
81
|
tmpVtc: koishi_1.Schema.boolean().default(true).description('是否启用VTC查询'),
|
|
82
|
+
tmpVtcOnline: koishi_1.Schema.boolean().default(false).description('是否启用车队在线成员查询功能'),
|
|
81
83
|
tmpFootprint: koishi_1.Schema.boolean().default(true).description('是否启用足迹查询'),
|
|
82
84
|
mainSettings: koishi_1.Schema.boolean().default(false).description('是否启用车队平台积分查询功能'),
|
|
83
85
|
resetPassword: koishi_1.Schema.boolean().default(false).description('是否启用车队平台重置密码功能'),
|
|
@@ -113,6 +115,12 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
113
115
|
koishi_1.Schema.const(2).description('图片')
|
|
114
116
|
]).default(1).description('服务器信息展示方式'),
|
|
115
117
|
}).description('服务器查询配置'),
|
|
118
|
+
tmpVtcOnline: koishi_1.Schema.object({
|
|
119
|
+
type: koishi_1.Schema.union([
|
|
120
|
+
koishi_1.Schema.const(1).description('文字'),
|
|
121
|
+
koishi_1.Schema.const(2).description('图片')
|
|
122
|
+
]).default(1).description('车队在线成员展示方式')
|
|
123
|
+
}).description('车队在线成员查询'),
|
|
116
124
|
|
|
117
125
|
tmpVersionCheck: koishi_1.Schema.object({
|
|
118
126
|
checkInterval: koishi_1.Schema.number().description("版本检查间隔(分钟)").default(30),
|
|
@@ -224,6 +232,7 @@ function logDisabledCommands(ctx, cfg) {
|
|
|
224
232
|
{ key: 'tmpMileageRanking', label: '里程排行榜/今日里程排行榜' },
|
|
225
233
|
{ key: 'pointRanking', label: '积分排行榜' },
|
|
226
234
|
{ key: 'tmpVtc', label: 'vtc查询' },
|
|
235
|
+
{ key: 'tmpVtcOnline', label: '车队在线成员' },
|
|
227
236
|
{ key: 'tmpFootprint', label: '足迹查询' },
|
|
228
237
|
{ key: 'resetPassword', label: '重置密码' },
|
|
229
238
|
{ key: 'mainSettings', label: '查询积分' },
|
|
@@ -309,6 +318,12 @@ function registerBaseCommands(ctx, cfg) {
|
|
|
309
318
|
.action(async ({ session }, vtcid) => await commands.tmpVtc(ctx, cfg, session, vtcid));
|
|
310
319
|
}
|
|
311
320
|
|
|
321
|
+
if (cfg.commands?.tmpVtcOnline) {
|
|
322
|
+
ctx.command('车队在线成员')
|
|
323
|
+
.usage('查询车队在线成员列表')
|
|
324
|
+
.action(async () => await commands.tmpVtcOnline(ctx, cfg));
|
|
325
|
+
}
|
|
326
|
+
|
|
312
327
|
if (cfg.commands?.tmpFootprint) {
|
|
313
328
|
ctx.command('近七日足迹 [tmpId:string]')
|
|
314
329
|
.usage("查询ETS服务器今日足迹")
|
|
@@ -0,0 +1,313 @@
|
|
|
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
|
+
html,
|
|
19
|
+
body {
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
body {
|
|
25
|
+
font-family: 'segui-emj', 'Microsoft YaHei', 'Segoe UI', sans-serif;
|
|
26
|
+
color: #f8fbff;
|
|
27
|
+
background: #050711;
|
|
28
|
+
-webkit-font-smoothing: antialiased;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#container {
|
|
32
|
+
width: 760px;
|
|
33
|
+
min-height: 220px;
|
|
34
|
+
padding: 18px;
|
|
35
|
+
position: relative;
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
background:
|
|
38
|
+
radial-gradient(circle at 8% -8%, rgba(34, 211, 238, 0.24), transparent 30%),
|
|
39
|
+
radial-gradient(circle at 100% 0%, rgba(129, 140, 248, 0.22), transparent 33%),
|
|
40
|
+
radial-gradient(circle at 86% 100%, rgba(217, 70, 239, 0.12), transparent 28%),
|
|
41
|
+
linear-gradient(145deg, #0b1020 0%, #070a16 48%, #0c1021 100%);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#container::before {
|
|
45
|
+
content: '';
|
|
46
|
+
position: absolute;
|
|
47
|
+
inset: 0;
|
|
48
|
+
pointer-events: none;
|
|
49
|
+
opacity: 0.32;
|
|
50
|
+
background-image:
|
|
51
|
+
linear-gradient(rgba(148, 163, 184, 0.035) 1px, transparent 1px),
|
|
52
|
+
linear-gradient(90deg, rgba(148, 163, 184, 0.035) 1px, transparent 1px);
|
|
53
|
+
background-size: 26px 26px;
|
|
54
|
+
mask-image: linear-gradient(to bottom, black, transparent 85%);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#container::after {
|
|
58
|
+
content: '';
|
|
59
|
+
position: absolute;
|
|
60
|
+
top: -120px;
|
|
61
|
+
left: 24%;
|
|
62
|
+
width: 360px;
|
|
63
|
+
height: 180px;
|
|
64
|
+
pointer-events: none;
|
|
65
|
+
background: rgba(56, 189, 248, 0.10);
|
|
66
|
+
filter: blur(70px);
|
|
67
|
+
transform: rotate(-8deg);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.content {
|
|
71
|
+
position: relative;
|
|
72
|
+
z-index: 1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.header {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
gap: 14px;
|
|
79
|
+
padding: 17px 18px;
|
|
80
|
+
border: 1px solid rgba(148, 163, 184, 0.16);
|
|
81
|
+
border-radius: 20px;
|
|
82
|
+
background: linear-gradient(135deg, rgba(255, 255, 255, 0.105), rgba(255, 255, 255, 0.035));
|
|
83
|
+
box-shadow:
|
|
84
|
+
0 18px 42px rgba(0, 0, 0, 0.30),
|
|
85
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.12),
|
|
86
|
+
inset 0 -1px 0 rgba(0, 0, 0, 0.18);
|
|
87
|
+
backdrop-filter: blur(24px) saturate(1.25);
|
|
88
|
+
-webkit-backdrop-filter: blur(24px) saturate(1.25);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.header-mark {
|
|
92
|
+
width: 46px;
|
|
93
|
+
height: 46px;
|
|
94
|
+
flex: 0 0 46px;
|
|
95
|
+
display: grid;
|
|
96
|
+
place-items: center;
|
|
97
|
+
border: 1px solid rgba(103, 232, 249, 0.35);
|
|
98
|
+
border-radius: 15px;
|
|
99
|
+
color: #67e8f9;
|
|
100
|
+
font-size: 23px;
|
|
101
|
+
background: linear-gradient(145deg, rgba(34, 211, 238, 0.24), rgba(99, 102, 241, 0.14));
|
|
102
|
+
box-shadow: 0 0 24px rgba(34, 211, 238, 0.16), inset 0 1px 0 rgba(255, 255, 255, 0.18);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.header-copy {
|
|
106
|
+
min-width: 0;
|
|
107
|
+
flex: 1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.eyebrow {
|
|
111
|
+
color: #67e8f9;
|
|
112
|
+
font-size: 10px;
|
|
113
|
+
font-weight: 800;
|
|
114
|
+
letter-spacing: 2.6px;
|
|
115
|
+
text-transform: uppercase;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.title {
|
|
119
|
+
margin-top: 4px;
|
|
120
|
+
color: #f8fafc;
|
|
121
|
+
font-size: 23px;
|
|
122
|
+
font-weight: 900;
|
|
123
|
+
letter-spacing: 2px;
|
|
124
|
+
text-shadow: 0 0 20px rgba(125, 211, 252, 0.22);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.subtitle {
|
|
128
|
+
margin-top: 5px;
|
|
129
|
+
color: #94a3b8;
|
|
130
|
+
font-size: 11px;
|
|
131
|
+
letter-spacing: 0.3px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.section-heading {
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
gap: 9px;
|
|
138
|
+
margin: 16px 2px 10px;
|
|
139
|
+
color: #cbd5e1;
|
|
140
|
+
font-size: 11px;
|
|
141
|
+
font-weight: 800;
|
|
142
|
+
letter-spacing: 1.8px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.section-heading::after {
|
|
146
|
+
content: '';
|
|
147
|
+
flex: 1;
|
|
148
|
+
height: 1px;
|
|
149
|
+
background: linear-gradient(90deg, rgba(103, 232, 249, 0.32), transparent);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.section-heading::before {
|
|
153
|
+
content: '';
|
|
154
|
+
width: 7px;
|
|
155
|
+
height: 7px;
|
|
156
|
+
border-radius: 50%;
|
|
157
|
+
background: #67e8f9;
|
|
158
|
+
box-shadow: 0 0 10px rgba(103, 232, 249, 0.75);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.grid {
|
|
162
|
+
display: flex;
|
|
163
|
+
flex-direction: column;
|
|
164
|
+
gap: 10px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.row {
|
|
168
|
+
display: grid;
|
|
169
|
+
grid-template-columns: repeat(3, 1fr);
|
|
170
|
+
gap: 10px;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.card {
|
|
174
|
+
min-height: 0;
|
|
175
|
+
padding: 12px 14px;
|
|
176
|
+
position: relative;
|
|
177
|
+
overflow: hidden;
|
|
178
|
+
border: 1px solid rgba(52, 211, 153, 0.28);
|
|
179
|
+
border-radius: 17px;
|
|
180
|
+
background: linear-gradient(145deg, rgba(16, 185, 129, 0.13), rgba(255, 255, 255, 0.045) 52%, rgba(99, 102, 241, 0.07));
|
|
181
|
+
box-shadow:
|
|
182
|
+
0 10px 25px rgba(0, 0, 0, 0.22),
|
|
183
|
+
0 0 18px rgba(52, 211, 153, 0.08),
|
|
184
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.12);
|
|
185
|
+
backdrop-filter: blur(16px) saturate(1.2);
|
|
186
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.2);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.card::before {
|
|
190
|
+
content: '';
|
|
191
|
+
position: absolute;
|
|
192
|
+
inset: 0;
|
|
193
|
+
pointer-events: none;
|
|
194
|
+
background: linear-gradient(135deg, rgba(255, 255, 255, 0.12), transparent 45%);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.card::after {
|
|
198
|
+
content: '';
|
|
199
|
+
position: absolute;
|
|
200
|
+
right: -28px;
|
|
201
|
+
bottom: -38px;
|
|
202
|
+
width: 110px;
|
|
203
|
+
height: 90px;
|
|
204
|
+
border-radius: 50%;
|
|
205
|
+
pointer-events: none;
|
|
206
|
+
background: rgba(52, 211, 153, 0.13);
|
|
207
|
+
filter: blur(25px);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.name,
|
|
211
|
+
.server {
|
|
212
|
+
position: relative;
|
|
213
|
+
z-index: 1;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.member-info {
|
|
217
|
+
display: flex;
|
|
218
|
+
align-items: center;
|
|
219
|
+
gap: 8px;
|
|
220
|
+
position: relative;
|
|
221
|
+
z-index: 1;
|
|
222
|
+
min-width: 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.name {
|
|
226
|
+
min-width: 0;
|
|
227
|
+
flex: 1;
|
|
228
|
+
color: #f8fafc;
|
|
229
|
+
font-size: 14px;
|
|
230
|
+
font-weight: 800;
|
|
231
|
+
line-height: 1.42;
|
|
232
|
+
overflow: hidden;
|
|
233
|
+
text-overflow: ellipsis;
|
|
234
|
+
white-space: nowrap;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.server {
|
|
238
|
+
display: flex;
|
|
239
|
+
align-items: center;
|
|
240
|
+
gap: 5px;
|
|
241
|
+
flex: 0 1 auto;
|
|
242
|
+
max-width: 45%;
|
|
243
|
+
min-width: 0;
|
|
244
|
+
overflow: hidden;
|
|
245
|
+
color: #cbd5e1;
|
|
246
|
+
font-size: 10px;
|
|
247
|
+
white-space: nowrap;
|
|
248
|
+
text-overflow: ellipsis;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.server-icon {
|
|
252
|
+
color: #67e8f9;
|
|
253
|
+
font-size: 12px;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.empty {
|
|
257
|
+
padding: 28px 20px;
|
|
258
|
+
border: 1px dashed rgba(148, 163, 184, 0.24);
|
|
259
|
+
border-radius: 17px;
|
|
260
|
+
color: #94a3b8;
|
|
261
|
+
text-align: center;
|
|
262
|
+
font-size: 13px;
|
|
263
|
+
background: rgba(255, 255, 255, 0.03);
|
|
264
|
+
}
|
|
265
|
+
</style>
|
|
266
|
+
</head>
|
|
267
|
+
<body>
|
|
268
|
+
<div id="container">
|
|
269
|
+
<div class="content">
|
|
270
|
+
<div class="header">
|
|
271
|
+
<div class="header-mark">🚚</div>
|
|
272
|
+
<div class="header-copy">
|
|
273
|
+
<div class="eyebrow">VTC LIVE MONITOR</div>
|
|
274
|
+
<div class="title">车队在线成员</div>
|
|
275
|
+
<div class="subtitle" id="subtitle"></div>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
<div class="section-heading">在线成员</div>
|
|
280
|
+
<div class="grid" id="grid"></div>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
<script>
|
|
285
|
+
function setData(data) {
|
|
286
|
+
const members = data.members || [];
|
|
287
|
+
const onlineMembers = data.onlineMembers || [];
|
|
288
|
+
const rows = data.rows || [];
|
|
289
|
+
|
|
290
|
+
document.getElementById('subtitle').textContent = `在线 ${onlineMembers.length} / ${members.length}`;
|
|
291
|
+
|
|
292
|
+
const grid = document.getElementById('grid');
|
|
293
|
+
if (!onlineMembers.length) {
|
|
294
|
+
grid.innerHTML = '<div class="empty">当前没有成员在线</div>';
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
grid.innerHTML = rows.map((row) => `
|
|
299
|
+
<div class="row">
|
|
300
|
+
${row.map((item) => `
|
|
301
|
+
<div class="card">
|
|
302
|
+
<div class="member-info">
|
|
303
|
+
<div class="name">${item.name}</div>
|
|
304
|
+
<div class="server"><span class="server-icon">◈</span>${item.serverName || '未知服务器'}</div>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
`).join('')}
|
|
308
|
+
</div>
|
|
309
|
+
`).join('');
|
|
310
|
+
}
|
|
311
|
+
</script>
|
|
312
|
+
</body>
|
|
313
|
+
</html>
|