koishi-plugin-rocom 1.0.7 → 1.0.9
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/LICENSE +661 -0
- package/lib/client.js +8 -1
- package/lib/commands/account.d.ts +1 -1
- package/lib/commands/account.js +42 -7
- package/lib/commands/query.js +0 -9
- package/lib/index.js +1 -1
- package/lib/render-templates/player-search/index.html +68 -60
- package/lib/render-templates/player-search/style.css +300 -192
- package/package.json +1 -1
- package/readme.md +1 -1
package/lib/client.js
CHANGED
|
@@ -99,6 +99,9 @@ class RocomClient {
|
|
|
99
99
|
if (/缺少\s*API\s*Key|API\s*Key.*required|missing\s+api\s*key/i.test(message)) {
|
|
100
100
|
return true;
|
|
101
101
|
}
|
|
102
|
+
if (/请提供有效的认证凭证|有效的?认证凭证|valid\s+credentials?\s+required|X-API-Key|Authorization\s*:\s*Bearer|X-Anonymous-Token/i.test(message)) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
102
105
|
if (/HTTP\s*(401|403)/i.test(message)) {
|
|
103
106
|
return true;
|
|
104
107
|
}
|
|
@@ -280,7 +283,11 @@ class RocomClient {
|
|
|
280
283
|
const status = Number(response?.status ?? response?.statusCode ?? 200);
|
|
281
284
|
const body = response?.data !== undefined ? response.data : response;
|
|
282
285
|
if (body?.code !== undefined && body.code !== 0) {
|
|
283
|
-
|
|
286
|
+
const rawMessage = body.message || body.msg || '接口返回异常';
|
|
287
|
+
const message = !acceptedStatuses.includes(status)
|
|
288
|
+
? `HTTP ${status}: ${rawMessage}`
|
|
289
|
+
: rawMessage;
|
|
290
|
+
this.setLastError(message);
|
|
284
291
|
if (!options.silentFailureDetails) {
|
|
285
292
|
this.logRequestFailureDetails(method, path, headers, options.params, options.json, body);
|
|
286
293
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PluginDeps } from '../types';
|
|
2
2
|
export declare function getPrimaryToken(deps: PluginDeps, userId: string): Promise<string>;
|
|
3
3
|
export declare function notLoggedInHint(): string;
|
|
4
|
-
export declare function saveBindingWithRoleInfo(deps: PluginDeps, session: any, fwToken: string, loginType: string, userId: string): Promise<void>;
|
|
4
|
+
export declare function saveBindingWithRoleInfo(deps: PluginDeps, session: any, fwToken: string, loginType: string, userId: string, preMessageIds?: string[]): Promise<void>;
|
|
5
5
|
export declare function register(deps: PluginDeps): void;
|
package/lib/commands/account.js
CHANGED
|
@@ -7,6 +7,21 @@ exports.register = register;
|
|
|
7
7
|
const koishi_1 = require("koishi");
|
|
8
8
|
const role_token_1 = require("../role-token");
|
|
9
9
|
const send_image_1 = require("../send-image");
|
|
10
|
+
const logger = new koishi_1.Logger('rocom-account');
|
|
11
|
+
async function recallMessages(session, messageIds) {
|
|
12
|
+
if (!session?.bot?.deleteMessage || !session.channelId)
|
|
13
|
+
return;
|
|
14
|
+
for (const id of messageIds) {
|
|
15
|
+
if (!id)
|
|
16
|
+
continue;
|
|
17
|
+
try {
|
|
18
|
+
await session.bot.deleteMessage(session.channelId, id);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
logger.warn(`撤回消息 ${id} 失败:${err}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
10
25
|
async function getPrimaryToken(deps, userId) {
|
|
11
26
|
const token = await (0, role_token_1.getRoleToken)(deps.ctx, userId);
|
|
12
27
|
return token?.fwt || '';
|
|
@@ -29,16 +44,29 @@ function formatLoginType(loginType) {
|
|
|
29
44
|
};
|
|
30
45
|
return typeMap[loginType] || loginType || '未知';
|
|
31
46
|
}
|
|
32
|
-
async function saveBindingWithRoleInfo(deps, session, fwToken, loginType, userId) {
|
|
47
|
+
async function saveBindingWithRoleInfo(deps, session, fwToken, loginType, userId, preMessageIds = []) {
|
|
33
48
|
const { ctx, client, userMgr } = deps;
|
|
34
|
-
|
|
49
|
+
const intermediateMessageIds = [...preMessageIds];
|
|
50
|
+
const sendIntermediate = async (content) => {
|
|
51
|
+
const result = await session.send(content);
|
|
52
|
+
if (Array.isArray(result)) {
|
|
53
|
+
for (const id of result) {
|
|
54
|
+
if (id)
|
|
55
|
+
intermediateMessageIds.push(String(id));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else if (result) {
|
|
59
|
+
intermediateMessageIds.push(String(result));
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
await sendIntermediate('登录成功,正在调用绑定接口...');
|
|
35
63
|
const bindRes = await client.createBinding(ctx, fwToken, userId);
|
|
36
64
|
const bindingId = String(bindRes?.binding?.id || fwToken || '').trim();
|
|
37
65
|
if (!bindRes?.binding || !bindingId) {
|
|
38
66
|
await session.send('绑定接口调用失败,请稍后重试。');
|
|
39
67
|
return;
|
|
40
68
|
}
|
|
41
|
-
await
|
|
69
|
+
await sendIntermediate('绑定成功,正在获取角色信息...');
|
|
42
70
|
const roleRes = await client.getRole(ctx, fwToken, undefined, userId);
|
|
43
71
|
if (!roleRes?.role) {
|
|
44
72
|
await session.send('绑定成功,但获取角色信息失败,请尝试重新登录。');
|
|
@@ -61,6 +89,7 @@ async function saveBindingWithRoleInfo(deps, session, fwToken, loginType, userId
|
|
|
61
89
|
roleId: binding.role_id,
|
|
62
90
|
loginType,
|
|
63
91
|
});
|
|
92
|
+
await recallMessages(session, intermediateMessageIds);
|
|
64
93
|
await session.send(`绑定成功!当前账号:${binding.nickname} (ID: ${binding.role_id})`);
|
|
65
94
|
}
|
|
66
95
|
function register(deps) {
|
|
@@ -75,7 +104,10 @@ function register(deps) {
|
|
|
75
104
|
const fwToken = qrData.frameworkToken;
|
|
76
105
|
const qrB64 = qrData.qr_image;
|
|
77
106
|
const imgData = qrB64.includes(',') ? qrB64.split(',')[1] : qrB64;
|
|
78
|
-
await session.send((0, koishi_1.h)('message', {}, koishi_1.h.at(userId), koishi_1.h.text('\n请使用 QQ 扫描二维码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n'), koishi_1.h.image(`data:image/png;base64,${imgData}`)));
|
|
107
|
+
const qrSendResult = await session.send((0, koishi_1.h)('message', {}, koishi_1.h.at(userId), koishi_1.h.text('\n请使用 QQ 扫描二维码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n'), koishi_1.h.image(`data:image/png;base64,${imgData}`)));
|
|
108
|
+
const qrMessageIds = Array.isArray(qrSendResult)
|
|
109
|
+
? qrSendResult.filter(Boolean).map(String)
|
|
110
|
+
: qrSendResult ? [String(qrSendResult)] : [];
|
|
79
111
|
const startTime = Date.now();
|
|
80
112
|
while (Date.now() - startTime < 115000) {
|
|
81
113
|
await new Promise(r => setTimeout(r, 3000));
|
|
@@ -83,7 +115,7 @@ function register(deps) {
|
|
|
83
115
|
if (!status)
|
|
84
116
|
continue;
|
|
85
117
|
if (status.status === 'done') {
|
|
86
|
-
await saveBindingWithRoleInfo(deps, session, fwToken, 'qq', userId);
|
|
118
|
+
await saveBindingWithRoleInfo(deps, session, fwToken, 'qq', userId, qrMessageIds);
|
|
87
119
|
return;
|
|
88
120
|
}
|
|
89
121
|
if (['expired', 'failed', 'canceled'].includes(status.status))
|
|
@@ -100,7 +132,10 @@ function register(deps) {
|
|
|
100
132
|
return '获取微信登录链接失败。';
|
|
101
133
|
const fwToken = qrData.frameworkToken;
|
|
102
134
|
const qrUrl = qrData.qr_image;
|
|
103
|
-
await session.send(`请使用微信打开以下链接扫码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n${qrUrl}`);
|
|
135
|
+
const qrSendResult = await session.send(`请使用微信打开以下链接扫码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n${qrUrl}`);
|
|
136
|
+
const qrMessageIds = Array.isArray(qrSendResult)
|
|
137
|
+
? qrSendResult.filter(Boolean).map(String)
|
|
138
|
+
: qrSendResult ? [String(qrSendResult)] : [];
|
|
104
139
|
const startTime = Date.now();
|
|
105
140
|
while (Date.now() - startTime < 115000) {
|
|
106
141
|
await new Promise(r => setTimeout(r, 3000));
|
|
@@ -108,7 +143,7 @@ function register(deps) {
|
|
|
108
143
|
if (!status)
|
|
109
144
|
continue;
|
|
110
145
|
if (status.status === 'done') {
|
|
111
|
-
await saveBindingWithRoleInfo(deps, session, fwToken, 'wechat', userId);
|
|
146
|
+
await saveBindingWithRoleInfo(deps, session, fwToken, 'wechat', userId, qrMessageIds);
|
|
112
147
|
return;
|
|
113
148
|
}
|
|
114
149
|
if (['expired', 'failed'].includes(status.status))
|
package/lib/commands/query.js
CHANGED
|
@@ -1058,12 +1058,6 @@ function buildPlayerSearchRenderData(payload, uid) {
|
|
|
1058
1058
|
['舒适度', playerField(parsed, 'home_comfort_level')],
|
|
1059
1059
|
['访客数量', playerField(parsed, 'visitor_num')],
|
|
1060
1060
|
]),
|
|
1061
|
-
pack('名片信息', [
|
|
1062
|
-
['名片皮肤', playerField(parsed, 'card_skin_selected')],
|
|
1063
|
-
['名片头像', playerField(parsed, 'card_icon_selected')],
|
|
1064
|
-
['首标签', playerField(parsed, 'card_label_first_selected')],
|
|
1065
|
-
['尾标签', playerField(parsed, 'card_label_last_selected')],
|
|
1066
|
-
]),
|
|
1067
1061
|
].filter(Boolean);
|
|
1068
1062
|
const summaryCards = [
|
|
1069
1063
|
{ label: '等级', value: parsed.level },
|
|
@@ -1076,7 +1070,6 @@ function buildPlayerSearchRenderData(payload, uid) {
|
|
|
1076
1070
|
const signature = parsed.signature && parsed.signature !== '未设置' ? parsed.signature : '';
|
|
1077
1071
|
return {
|
|
1078
1072
|
title: '洛克玩家',
|
|
1079
|
-
subtitle: parsed.title,
|
|
1080
1073
|
heroTitle: '玩家信息',
|
|
1081
1074
|
heroValue: parsed.nickname,
|
|
1082
1075
|
heroSubvalue: `UID ${parsed.uid}`,
|
|
@@ -1334,7 +1327,6 @@ function register(deps) {
|
|
|
1334
1327
|
if (!fwToken)
|
|
1335
1328
|
return (0, account_1.notLoggedInHint)();
|
|
1336
1329
|
const userIdentifier = session.userId;
|
|
1337
|
-
await session.send('正在获取洛克王国数据...');
|
|
1338
1330
|
const [roleRes, evalRes, sumRes, collRes, boRes, blRes] = await Promise.all([
|
|
1339
1331
|
client.getRole(ctx, fwToken, undefined, userIdentifier),
|
|
1340
1332
|
client.getEvaluation(ctx, fwToken, userIdentifier),
|
|
@@ -1781,7 +1773,6 @@ function register(deps) {
|
|
|
1781
1773
|
return '请提供 UID,或先绑定账号后再使用 洛克.刷新面板。';
|
|
1782
1774
|
if (!/^\d+$/.test(targetUid))
|
|
1783
1775
|
return '请输入正确的 UID 格式。';
|
|
1784
|
-
await session?.send?.(`正在刷新 UID ${targetUid} 的精灵面板,请稍候...`);
|
|
1785
1776
|
const record = await refreshPanelPets(deps, targetUid, session?.userId || '');
|
|
1786
1777
|
if (!record)
|
|
1787
1778
|
return panelRefreshErrorHint(client);
|
package/lib/index.js
CHANGED
|
@@ -96,7 +96,7 @@ function buildMenuFallbackText() {
|
|
|
96
96
|
exports.Config = koishi_1.Schema.intersect([
|
|
97
97
|
koishi_1.Schema.object({
|
|
98
98
|
apiBaseUrl: koishi_1.Schema.string().default('https://wegame.shallow.ink').description('API 基础地址'),
|
|
99
|
-
wegameApiKey: koishi_1.Schema.string().default('').description('WeGame API Key'),
|
|
99
|
+
wegameApiKey: koishi_1.Schema.string().default('').description('WeGame API Key(获取 key 查看 Github:https://github.com/Entropy-Increase-Team/koishi-plugin-rocom )'),
|
|
100
100
|
qqLoginDebugMode: koishi_1.Schema.boolean().default(false).description('QQ 扫码登录调试模式,仅调试时开启'),
|
|
101
101
|
adminUserIds: koishi_1.Schema.array(String).default([]).description('管理员用户 ID 列表'),
|
|
102
102
|
autoRefreshEnabled: koishi_1.Schema.boolean().default(false).description('启用自动刷新凭证'),
|
|
@@ -1,60 +1,68 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=
|
|
6
|
-
<link rel="stylesheet" href="{{_res_path}}render/player-search/style.css">
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<div class="player-search-page player-page">
|
|
10
|
-
<div class="page-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<div class="
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
{{
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
{{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
</
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=1280, initial-scale=1">
|
|
6
|
+
<link rel="stylesheet" href="{{_res_path}}render/player-search/style.css">
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div class="player-search-page player-page">
|
|
10
|
+
<div class="page-bg"></div>
|
|
11
|
+
|
|
12
|
+
<header class="page-header">
|
|
13
|
+
<div class="page-title">{{title}}</div>
|
|
14
|
+
<div class="page-title-ghost">ROCOM PLAYER</div>
|
|
15
|
+
</header>
|
|
16
|
+
|
|
17
|
+
<section class="profile-strip">
|
|
18
|
+
<div class="profile-main">
|
|
19
|
+
<div class="profile-name-row">
|
|
20
|
+
<span class="player-name">{{heroValue}}</span>
|
|
21
|
+
<span class="uid-pill">{{heroSubvalue}}</span>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</section>
|
|
25
|
+
|
|
26
|
+
<section class="summary-strip">
|
|
27
|
+
{{each summaryCards item}}
|
|
28
|
+
<div class="summary-item">
|
|
29
|
+
<div class="summary-label">{{item.label}}</div>
|
|
30
|
+
<div class="summary-value">{{item.value}}</div>
|
|
31
|
+
</div>
|
|
32
|
+
{{/each}}
|
|
33
|
+
</section>
|
|
34
|
+
|
|
35
|
+
{{if showSignature}}
|
|
36
|
+
<section class="signature-strip">
|
|
37
|
+
<div class="signature-label">个性签名</div>
|
|
38
|
+
<div class="signature-text">{{signature}}</div>
|
|
39
|
+
</section>
|
|
40
|
+
{{/if}}
|
|
41
|
+
|
|
42
|
+
<main class="content-grid">
|
|
43
|
+
{{each sections section}}
|
|
44
|
+
<section class="panel">
|
|
45
|
+
<div class="panel-head">
|
|
46
|
+
<h2>{{section.title}}</h2>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="detail-list">
|
|
49
|
+
{{each section["items"] item}}
|
|
50
|
+
<div class="detail-row">
|
|
51
|
+
<span class="detail-label">{{item.label}}</span>
|
|
52
|
+
<span class="detail-value">{{item.value}}</span>
|
|
53
|
+
</div>
|
|
54
|
+
{{/each}}
|
|
55
|
+
</div>
|
|
56
|
+
</section>
|
|
57
|
+
{{/each}}
|
|
58
|
+
</main>
|
|
59
|
+
|
|
60
|
+
<footer class="page-footer">
|
|
61
|
+
{{if commandHint}}
|
|
62
|
+
<div class="command-hint">用法:{{commandHint}}</div>
|
|
63
|
+
{{/if}}
|
|
64
|
+
<div class="copyright">{{copyright}}</div>
|
|
65
|
+
</footer>
|
|
66
|
+
</div>
|
|
67
|
+
</body>
|
|
68
|
+
</html>
|