koishi-plugin-rocom 1.0.10 → 1.0.12
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/activities-service.d.ts +72 -0
- package/lib/activities-service.js +293 -0
- package/lib/client.d.ts +32 -1
- package/lib/client.js +102 -6
- package/lib/commands/account.js +44 -0
- package/lib/commands/community.d.ts +12 -0
- package/lib/commands/community.js +323 -0
- package/lib/commands/egg.js +12 -4
- package/lib/commands/merchant.js +135 -22
- package/lib/commands/query.js +112 -21
- package/lib/commands/tools.d.ts +2 -0
- package/lib/commands/tools.js +164 -0
- package/lib/egg-service.d.ts +12 -0
- package/lib/egg-service.js +76 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +5416 -144
- package/lib/render-templates/activities/index.html +77 -0
- package/lib/render-templates/activities/style.css +434 -0
- package/lib/render-templates/student/index.html +95 -0
- package/lib/render-templates/student/style.css +255 -0
- package/lib/render-templates/student-perks/index.html +78 -0
- package/lib/render-templates/student-perks/style.css +238 -0
- package/lib/render-templates/student-state/index.html +52 -0
- package/lib/render-templates/student-state/style.css +157 -0
- package/lib/render-templates/yuanxing-shangren/index.html +85 -28
- package/lib/render.js +17 -5
- package/lib/send-image.d.ts +1 -0
- package/lib/send-image.js +13 -1
- package/lib/subscription-send.js +2 -1
- package/lib/types.d.ts +2 -0
- package/package.json +1 -1
- package/readme.md +4 -8
package/lib/commands/query.js
CHANGED
|
@@ -258,16 +258,28 @@ function normalizeDurationSeconds(value) {
|
|
|
258
258
|
function formatHomeRemaining(targetTs, nowTs = Math.floor(Date.now() / 1000)) {
|
|
259
259
|
if (!targetTs)
|
|
260
260
|
return '未开始';
|
|
261
|
-
|
|
262
|
-
if (remain <= 0)
|
|
261
|
+
if (nowTs >= targetTs)
|
|
263
262
|
return '已完成';
|
|
264
|
-
const
|
|
263
|
+
const remain = Math.max(0, targetTs - nowTs);
|
|
264
|
+
const days = Math.floor(remain / 86400);
|
|
265
|
+
const hours = Math.floor((remain % 86400) / 3600);
|
|
265
266
|
const minutes = Math.floor((remain % 3600) / 60);
|
|
266
|
-
|
|
267
|
-
|
|
267
|
+
const seconds = remain % 60;
|
|
268
|
+
if (days > 0)
|
|
269
|
+
return hours > 0 ? `${days}天${hours}小时` : `${days}天`;
|
|
268
270
|
if (hours > 0)
|
|
269
271
|
return `${hours}小时${minutes}分钟`;
|
|
270
|
-
|
|
272
|
+
if (minutes > 0)
|
|
273
|
+
return `${minutes}分${seconds}秒`;
|
|
274
|
+
return `${seconds}秒`;
|
|
275
|
+
}
|
|
276
|
+
function formatEggRemaining(targetTs, nowTs = Math.floor(Date.now() / 1000)) {
|
|
277
|
+
if (!targetTs || nowTs >= targetTs)
|
|
278
|
+
return '0分钟';
|
|
279
|
+
const remain = Math.max(0, targetTs - nowTs);
|
|
280
|
+
const totalHours = Math.floor(remain / 3600);
|
|
281
|
+
const minutes = Math.floor((remain % 3600) / 60);
|
|
282
|
+
return `${totalHours}小时${minutes}分钟`;
|
|
271
283
|
}
|
|
272
284
|
function homeInfoPayload(res) {
|
|
273
285
|
const payload = res || {};
|
|
@@ -856,31 +868,59 @@ function extractHomePet(raw, index, guard = false) {
|
|
|
856
868
|
const petId = homePet.pet_cfg_id || homePet.pet_id || homePet.pet_base_id || raw.pet_cfg_id || raw.pet_id || raw.id;
|
|
857
869
|
if (['', '0'].includes(String(petId || '0')) && !guard)
|
|
858
870
|
return null;
|
|
859
|
-
const feedInfo = homePet.feed_info && typeof homePet.feed_info === 'object' ? homePet.feed_info : {};
|
|
860
|
-
const beginTime = normalizeEpochSeconds(feedInfo.begin_time);
|
|
861
|
-
const timeCost = normalizeDurationSeconds(feedInfo.time_cost);
|
|
862
|
-
let readyAt = normalizeEpochSeconds(homePet.pet_rip_time || raw.pet_rip_time || raw.rip_time);
|
|
863
|
-
if (!readyAt && beginTime && timeCost)
|
|
864
|
-
readyAt = beginTime + timeCost;
|
|
865
871
|
const nowTs = Math.floor(Date.now() / 1000);
|
|
866
|
-
const
|
|
867
|
-
const
|
|
868
|
-
const
|
|
869
|
-
const
|
|
870
|
-
const
|
|
872
|
+
const hasEgg = Boolean(raw.have_egg);
|
|
873
|
+
const predictedEggTime = normalizeEpochSeconds(raw.predicted_egg_time);
|
|
874
|
+
const eggReady = hasEgg || (predictedEggTime > 0 && nowTs >= predictedEggTime);
|
|
875
|
+
const feedRound = Number(homePet.feed_round || raw.feed_round || 0) || 0;
|
|
876
|
+
const gender = Number(display.gender || raw.gender || 0) || 0;
|
|
877
|
+
const isMale = gender === 1;
|
|
878
|
+
const status = homePet.status ?? raw.status;
|
|
879
|
+
const isGuard = guard || Boolean(raw.is_guard || raw.guard) || ['2', 'guard', '守卫'].includes(String(status).toLowerCase());
|
|
880
|
+
const hasInspiration = feedRound > 0;
|
|
881
|
+
const inspireReady = hasInspiration;
|
|
882
|
+
const statusText = isGuard && !hasInspiration ? '守卫中'
|
|
883
|
+
: (inspireReady ? '可收取灵感'
|
|
884
|
+
: (hasInspiration ? '灵感收集中'
|
|
885
|
+
: '未喂食'));
|
|
886
|
+
const statusClass = isGuard && !hasInspiration ? 'guard'
|
|
887
|
+
: (eggReady ? 'ready'
|
|
888
|
+
: (inspireReady ? 'progress'
|
|
889
|
+
: (hasInspiration ? 'progress'
|
|
890
|
+
: 'idle')));
|
|
891
|
+
let note;
|
|
892
|
+
if (isGuard && String(petId) === '0') {
|
|
893
|
+
note = '家园守卫位';
|
|
894
|
+
}
|
|
895
|
+
else if (eggReady) {
|
|
896
|
+
note = '可收取';
|
|
897
|
+
}
|
|
898
|
+
else if (predictedEggTime > 0) {
|
|
899
|
+
note = `${formatEggRemaining(predictedEggTime, nowTs)}后生蛋`;
|
|
900
|
+
}
|
|
901
|
+
else if (feedRound > 0) {
|
|
902
|
+
note = isMale ? '' : '等待生蛋';
|
|
903
|
+
}
|
|
904
|
+
else if (isGuard) {
|
|
905
|
+
note = '家园守卫位';
|
|
906
|
+
}
|
|
907
|
+
else {
|
|
908
|
+
note = '未喂食';
|
|
909
|
+
}
|
|
871
910
|
return {
|
|
872
911
|
id: String(petId || ''),
|
|
873
912
|
pos: raw.pos || raw.position || index + 1,
|
|
874
913
|
name: String(homePet.name || homePet.pet_name || raw.name || raw.pet_name || `精灵 ${petId || ''}`),
|
|
875
914
|
level: display.level || raw.level || homePet.level || '--',
|
|
876
915
|
iconUrl: homePetIcon(petId, raw.icon_url || raw.pet_img_url || raw.petIcon || ''),
|
|
877
|
-
badge: isGuard ? '守' : '',
|
|
916
|
+
badge: isGuard ? '守' : (hasEgg ? '蛋' : ''),
|
|
878
917
|
isGuard,
|
|
879
918
|
statusText,
|
|
880
919
|
statusClass,
|
|
881
|
-
note
|
|
882
|
-
inspireReady,
|
|
883
|
-
readyAt,
|
|
920
|
+
note,
|
|
921
|
+
inspireReady: eggReady,
|
|
922
|
+
readyAt: predictedEggTime || 0,
|
|
923
|
+
gender,
|
|
884
924
|
};
|
|
885
925
|
}
|
|
886
926
|
function homePetSources(homeInfo) {
|
|
@@ -1011,6 +1051,18 @@ function buildHomeRenderData(deps, res, uid) {
|
|
|
1011
1051
|
if (item)
|
|
1012
1052
|
guardPets.push(item);
|
|
1013
1053
|
});
|
|
1054
|
+
indoorPets.sort((a, b) => {
|
|
1055
|
+
if (a.gender === 2 && b.gender !== 2)
|
|
1056
|
+
return -1;
|
|
1057
|
+
if (a.gender !== 2 && b.gender === 2)
|
|
1058
|
+
return 1;
|
|
1059
|
+
if (a.gender === 2) {
|
|
1060
|
+
const ta = a.readyAt || Number.MAX_SAFE_INTEGER;
|
|
1061
|
+
const tb = b.readyAt || Number.MAX_SAFE_INTEGER;
|
|
1062
|
+
return ta - tb;
|
|
1063
|
+
}
|
|
1064
|
+
return 0;
|
|
1065
|
+
});
|
|
1014
1066
|
const gardenPlots = extractHomePlants(deps, homeInfo);
|
|
1015
1067
|
const createdAt = normalizeEpochSeconds(res?.meta?.created_at);
|
|
1016
1068
|
return {
|
|
@@ -1153,6 +1205,45 @@ function buildFriendshipRenderData(payload, userIds) {
|
|
|
1153
1205
|
copyright: 'Koishi & WeGame Locke Kingdom Plugin',
|
|
1154
1206
|
};
|
|
1155
1207
|
}
|
|
1208
|
+
function buildStudentRenderData(statePayload, perksPayload, area, accountType) {
|
|
1209
|
+
const school = statePayload?.school || statePayload?.school_name || '未返回';
|
|
1210
|
+
const certified = String(statePayload?.certified) === '1';
|
|
1211
|
+
const cards = perksPayload?.cards || [];
|
|
1212
|
+
return {
|
|
1213
|
+
title: '洛克学生',
|
|
1214
|
+
subtitle: `大区:${area} 账号类型:${accountTypeText(accountType)}`,
|
|
1215
|
+
heroTitle: '学生信息总览',
|
|
1216
|
+
heroValue: certified ? '已通过' : '未认证',
|
|
1217
|
+
heroSubvalue: school,
|
|
1218
|
+
summaryCards: [
|
|
1219
|
+
{ label: '认证状态', value: certified ? '已认证' : '未认证' },
|
|
1220
|
+
{ label: '学校', value: school },
|
|
1221
|
+
{ label: '奖励数量', value: String(cards.length) },
|
|
1222
|
+
],
|
|
1223
|
+
stateItems: [
|
|
1224
|
+
{ label: '学生认证', value: certified ? '是' : '否' },
|
|
1225
|
+
{ label: '游戏内认证', value: String(statePayload?.game_certified) === '1' ? '是' : '否' },
|
|
1226
|
+
{ label: '学校', value: school },
|
|
1227
|
+
{ label: '上游状态', value: statePayload?.result?.error_message || 'WG_COMM_SUCC' },
|
|
1228
|
+
{ label: '上游错误码', value: stringifyInspectValue(statePayload?.result?.error_code || 0) },
|
|
1229
|
+
],
|
|
1230
|
+
perkCards: cards.map((card) => ({
|
|
1231
|
+
name: card.name || `奖励 #${card.id || '-'}`,
|
|
1232
|
+
count: card.count || 0,
|
|
1233
|
+
desc: card.desc || '暂无说明',
|
|
1234
|
+
icon: card.icon || '',
|
|
1235
|
+
id: stringifyInspectValue(card.id),
|
|
1236
|
+
stateText: `状态码 ${stringifyInspectValue(card.state)}`,
|
|
1237
|
+
})),
|
|
1238
|
+
detailItems: Object.entries(perksPayload || {})
|
|
1239
|
+
.filter(([key, value]) => !['cards', 'result'].includes(key) && (value === null || typeof value !== 'object'))
|
|
1240
|
+
.map(([key, value]) => ({ label: key.replace(/_/g, ' '), value: stringifyInspectValue(value) })),
|
|
1241
|
+
stateResult: statePayload?.result?.error_message || 'WG_COMM_SUCC',
|
|
1242
|
+
perksResult: perksPayload?.result?.error_message || 'WG_COMM_SUCC',
|
|
1243
|
+
commandHint: '洛克.学生 [area] [account_type]',
|
|
1244
|
+
copyright: 'Koishi & WeGame Locke Kingdom Plugin',
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1156
1247
|
function sessionTarget(session) {
|
|
1157
1248
|
return {
|
|
1158
1249
|
platform: session?.platform || session?.bot?.platform || '',
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.register = register;
|
|
4
|
+
const koishi_1 = require("koishi");
|
|
5
|
+
const activities_service_1 = require("../activities-service");
|
|
6
|
+
const send_image_1 = require("../send-image");
|
|
7
|
+
const logger = new koishi_1.Logger('rocom-tools');
|
|
8
|
+
const activitiesService = new activities_service_1.ActivitiesService();
|
|
9
|
+
function trimText(value) {
|
|
10
|
+
return String(value ?? '').trim();
|
|
11
|
+
}
|
|
12
|
+
function stripHtml(value) {
|
|
13
|
+
return trimText(value)
|
|
14
|
+
.replace(/<br\s*\/?>/gi, '\n')
|
|
15
|
+
.replace(/<\/p>/gi, '\n')
|
|
16
|
+
.replace(/<[^>]+>/g, '')
|
|
17
|
+
.replace(/ /g, ' ')
|
|
18
|
+
.replace(/&/g, '&')
|
|
19
|
+
.replace(/</g, '<')
|
|
20
|
+
.replace(/>/g, '>')
|
|
21
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
22
|
+
.trim();
|
|
23
|
+
}
|
|
24
|
+
function formatDate(value) {
|
|
25
|
+
const text = trimText(value);
|
|
26
|
+
if (!text)
|
|
27
|
+
return '未知时间';
|
|
28
|
+
const numeric = Number(text);
|
|
29
|
+
const date = Number.isFinite(numeric)
|
|
30
|
+
? new Date(numeric > 10000000000 ? numeric : numeric * 1000)
|
|
31
|
+
: new Date(text);
|
|
32
|
+
if (Number.isNaN(date.getTime()))
|
|
33
|
+
return text;
|
|
34
|
+
const pad = (num) => String(num).padStart(2, '0');
|
|
35
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
36
|
+
}
|
|
37
|
+
function pageNumber(value, defaultValue = 1) {
|
|
38
|
+
const num = Number(value);
|
|
39
|
+
if (!Number.isFinite(num) || num < 1)
|
|
40
|
+
return defaultValue;
|
|
41
|
+
return Math.min(50, Math.floor(num));
|
|
42
|
+
}
|
|
43
|
+
function firstArray(payload, keys) {
|
|
44
|
+
if (!payload || typeof payload !== 'object')
|
|
45
|
+
return [];
|
|
46
|
+
for (const key of keys) {
|
|
47
|
+
if (Array.isArray(payload[key]))
|
|
48
|
+
return payload[key];
|
|
49
|
+
}
|
|
50
|
+
if (payload.data && typeof payload.data === 'object')
|
|
51
|
+
return firstArray(payload.data, keys);
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
function announcementId(item) {
|
|
55
|
+
return trimText(item?.thread_id || item?.id);
|
|
56
|
+
}
|
|
57
|
+
function buildAnnouncementListText(data, page) {
|
|
58
|
+
const list = firstArray(data, ['list', 'items']);
|
|
59
|
+
if (!list.length)
|
|
60
|
+
return page > 1 ? '该页没有更多公告。' : '当前没有公告数据。';
|
|
61
|
+
const lines = ['洛克公告'];
|
|
62
|
+
for (const [index, item] of list.entries()) {
|
|
63
|
+
const title = trimText(item?.title) || '未命名公告';
|
|
64
|
+
const summary = trimText(item?.summary);
|
|
65
|
+
const id = announcementId(item);
|
|
66
|
+
const stick = Number(item?.isStick) === 1 ? '[置顶]' : '';
|
|
67
|
+
lines.push(`${index + 1}. ${stick}${title}${id ? ` #${id}` : ''}`);
|
|
68
|
+
if (summary)
|
|
69
|
+
lines.push(` ${summary.length > 70 ? `${summary.slice(0, 67)}...` : summary}`);
|
|
70
|
+
lines.push(` ${formatDate(item?.publishAt || item?.published_at || item?.createdAt)}`);
|
|
71
|
+
}
|
|
72
|
+
const current = Number(data?.page) || page;
|
|
73
|
+
if (data?.has_more || data?.next_page) {
|
|
74
|
+
lines.push(`当前第 ${current} 页,下一页:洛克.公告 ${data.next_page || current + 1}`);
|
|
75
|
+
}
|
|
76
|
+
lines.push('详情:洛克.公告详情 <公告ID>');
|
|
77
|
+
return lines.join('\n');
|
|
78
|
+
}
|
|
79
|
+
function buildAnnouncementDetailText(data) {
|
|
80
|
+
const item = data?.detail || data?.announcement || data;
|
|
81
|
+
if (!item || typeof item !== 'object')
|
|
82
|
+
return '公告详情为空。';
|
|
83
|
+
const title = trimText(item?.title) || '未命名公告';
|
|
84
|
+
const id = announcementId(item);
|
|
85
|
+
const summary = trimText(item?.summary);
|
|
86
|
+
const content = stripHtml(item?.content?.text || item?.text || item?.content);
|
|
87
|
+
const lines = [
|
|
88
|
+
`公告详情${id ? ` #${id}` : ''}`,
|
|
89
|
+
title,
|
|
90
|
+
`发布时间:${formatDate(item?.publishAt || item?.published_at || item?.createdAt)}`,
|
|
91
|
+
];
|
|
92
|
+
if (summary)
|
|
93
|
+
lines.push(`摘要:${summary}`);
|
|
94
|
+
if (content) {
|
|
95
|
+
lines.push('');
|
|
96
|
+
lines.push(content.length > 900 ? `${content.slice(0, 900)}...` : content);
|
|
97
|
+
}
|
|
98
|
+
const images = Array.isArray(item?.content?.indexes)
|
|
99
|
+
? item.content.indexes.flatMap((entry) => Array.isArray(entry?.imageUrl) ? entry.imageUrl : [])
|
|
100
|
+
: [];
|
|
101
|
+
if (images.length) {
|
|
102
|
+
lines.push('');
|
|
103
|
+
lines.push(`图片资源:${images.slice(0, 3).join('\n')}`);
|
|
104
|
+
}
|
|
105
|
+
return lines.join('\n');
|
|
106
|
+
}
|
|
107
|
+
function register(deps) {
|
|
108
|
+
const { ctx, client, config, renderer } = deps;
|
|
109
|
+
ctx.command('洛克').subcommand('.日历 [mode:string]', '查看洛克活动日历')
|
|
110
|
+
.alias('洛克日历')
|
|
111
|
+
.action(async ({ session }, mode = '') => {
|
|
112
|
+
const refresh = ['刷新', 'refresh', 'true', '1'].includes(String(mode || '').toLowerCase());
|
|
113
|
+
const data = await client.getActivitiesInfo(ctx, refresh, session?.userId || '');
|
|
114
|
+
if (!data)
|
|
115
|
+
return `活动日历查询失败:${client.getLastErrorBrief()}`;
|
|
116
|
+
const fallback = activitiesService.buildFallbackText(data);
|
|
117
|
+
if (!session?.send)
|
|
118
|
+
return fallback;
|
|
119
|
+
const image = await renderer.renderHtml(ctx, 'activities', activitiesService.buildRenderData(data));
|
|
120
|
+
await (0, send_image_1.sendImageWithFallback)(session, image, fallback, 'activities:calendar', config);
|
|
121
|
+
});
|
|
122
|
+
ctx.command('洛克').subcommand('.公告 [page:number]', '查看洛克公告列表')
|
|
123
|
+
.alias('洛克公告')
|
|
124
|
+
.action(async ({ session }, page = 1) => {
|
|
125
|
+
const currentPage = pageNumber(page);
|
|
126
|
+
const data = await client.getAnnouncementList(ctx, { category_id: 99, page: currentPage, limit: 10 }, session?.userId || '');
|
|
127
|
+
if (!data)
|
|
128
|
+
return `公告列表查询失败:${client.getLastErrorBrief()}`;
|
|
129
|
+
return buildAnnouncementListText(data, currentPage);
|
|
130
|
+
});
|
|
131
|
+
ctx.command('洛克').subcommand('.最新公告', '查看最新洛克公告')
|
|
132
|
+
.alias('洛克最新公告')
|
|
133
|
+
.action(async ({ session }) => {
|
|
134
|
+
const data = await client.getLatestAnnouncement(ctx, { category_id: 99 }, session?.userId || '');
|
|
135
|
+
if (!data)
|
|
136
|
+
return `最新公告查询失败:${client.getLastErrorBrief()}`;
|
|
137
|
+
return buildAnnouncementDetailText(data);
|
|
138
|
+
});
|
|
139
|
+
ctx.command('洛克').subcommand('.公告详情 <threadId:string>', '查看公告详情')
|
|
140
|
+
.alias('洛克公告详情')
|
|
141
|
+
.action(async ({ session }, threadId) => {
|
|
142
|
+
const id = trimText(threadId);
|
|
143
|
+
if (!/^\d+$/.test(id))
|
|
144
|
+
return '请提供公告 ID。用法:洛克.公告详情 <公告ID>';
|
|
145
|
+
const data = await client.getAnnouncementDetail(ctx, id, session?.userId || '');
|
|
146
|
+
if (!data)
|
|
147
|
+
return `公告详情查询失败:${client.getLastErrorBrief()}`;
|
|
148
|
+
return buildAnnouncementDetailText(data);
|
|
149
|
+
});
|
|
150
|
+
ctx.command('洛克').subcommand('.同步配置', '手动同步 RoCom 远端配置')
|
|
151
|
+
.alias('洛克同步配置')
|
|
152
|
+
.action(async ({ session }) => {
|
|
153
|
+
if (!config.adminUserIds.includes(session?.userId || ''))
|
|
154
|
+
return '此指令仅限管理员使用。';
|
|
155
|
+
const data = await client.syncConfig(ctx, session?.userId || '');
|
|
156
|
+
if (!data)
|
|
157
|
+
return `同步配置失败:${client.getLastErrorBrief()}`;
|
|
158
|
+
logger.info(`manual config sync requested by ${session?.userId || 'unknown'}`);
|
|
159
|
+
const skipped = Array.isArray(data?.skipped_resources) ? data.skipped_resources.length : 0;
|
|
160
|
+
return skipped
|
|
161
|
+
? `配置同步完成,但有 ${skipped} 个资源跳过。`
|
|
162
|
+
: '配置同步完成。';
|
|
163
|
+
});
|
|
164
|
+
}
|
package/lib/egg-service.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ export declare class EggService {
|
|
|
27
27
|
private rangeMatchScore;
|
|
28
28
|
private formatPetCard;
|
|
29
29
|
private formatSizeApiCard;
|
|
30
|
+
private formatEggSearchCard;
|
|
31
|
+
private formatEggSearchTextLine;
|
|
30
32
|
private mergeCardsByName;
|
|
31
33
|
private mergeSizeCard;
|
|
32
34
|
private minValue;
|
|
@@ -47,6 +49,7 @@ export declare class EggService {
|
|
|
47
49
|
range: any[];
|
|
48
50
|
}, heightDisplay?: string): string;
|
|
49
51
|
buildSizeSearchTextFromApi(height?: number, weight?: number, results?: any, heightDisplay?: string): string;
|
|
52
|
+
buildEggSearchText(heightMeters?: number, weight?: number, results?: any, heightDisplay?: string): string;
|
|
50
53
|
buildSearchText(pet: any): string;
|
|
51
54
|
buildCandidatesText(keyword: string, candidates: any[]): string;
|
|
52
55
|
buildWantPetText(pet: any): string;
|
|
@@ -225,5 +228,14 @@ export declare class EggService {
|
|
|
225
228
|
commandHint: string;
|
|
226
229
|
copyright: string;
|
|
227
230
|
};
|
|
231
|
+
buildEggSearchData(heightMeters?: number, weight?: number, results?: any, heightDisplay?: string): {
|
|
232
|
+
query_label: string;
|
|
233
|
+
perfect_matches: any;
|
|
234
|
+
range_matches: any[];
|
|
235
|
+
total_count: any;
|
|
236
|
+
has_results: boolean;
|
|
237
|
+
commandHint: string;
|
|
238
|
+
copyright: string;
|
|
239
|
+
};
|
|
228
240
|
private buildEggDetails;
|
|
229
241
|
}
|
package/lib/egg-service.js
CHANGED
|
@@ -306,6 +306,42 @@ class EggService {
|
|
|
306
306
|
match_info_label: this.formatMatchSummary(probability, matchCount),
|
|
307
307
|
};
|
|
308
308
|
}
|
|
309
|
+
formatEggSearchCard(item) {
|
|
310
|
+
const eggGroups = Array.isArray(item?.egg_groups)
|
|
311
|
+
? item.egg_groups
|
|
312
|
+
.map((group) => group?.official_name || group?.display_name || `蛋组${group?.group_id}`)
|
|
313
|
+
.filter(Boolean)
|
|
314
|
+
: [];
|
|
315
|
+
const heightRange = Array.isArray(item?.height_range_m) ? item.height_range_m : [];
|
|
316
|
+
const weightRange = Array.isArray(item?.weight_range_kg) ? item.weight_range_kg : [];
|
|
317
|
+
const typeLabel = Array.isArray(item?.unit_type) && item.unit_type.length
|
|
318
|
+
? item.unit_type.join(' / ')
|
|
319
|
+
: '未知';
|
|
320
|
+
return {
|
|
321
|
+
id: item?.id || '-',
|
|
322
|
+
name: item?.name || '未知精灵',
|
|
323
|
+
icon: item?.pet_icon_url || petIconUrl(item?.id),
|
|
324
|
+
image: item?.pet_img_url || petImageUrl(item?.id),
|
|
325
|
+
type_label: typeLabel,
|
|
326
|
+
egg_group_ids: Array.isArray(item?.egg_groups)
|
|
327
|
+
? item.egg_groups.map((group) => Number(group?.group_id)).filter((value) => Number.isFinite(value))
|
|
328
|
+
: [],
|
|
329
|
+
egg_groups_label: eggGroups.length ? eggGroups.join(' / ') : '暂无蛋组数据',
|
|
330
|
+
height_min: num(heightRange[0]),
|
|
331
|
+
height_max: num(heightRange[1]),
|
|
332
|
+
height_label: fmtRange(num(heightRange[0]), num(heightRange[1]), 'm'),
|
|
333
|
+
weight_min: num(weightRange[0]),
|
|
334
|
+
weight_max: num(weightRange[1]),
|
|
335
|
+
weight_label: fmtRange(num(weightRange[0]), num(weightRange[1]), 'kg'),
|
|
336
|
+
probability: null,
|
|
337
|
+
match_count: null,
|
|
338
|
+
match_info_label: '',
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
formatEggSearchTextLine(item) {
|
|
342
|
+
const card = this.formatEggSearchCard(item);
|
|
343
|
+
return `${card.name} (#${card.id}) — ${card.height_label} / ${card.weight_label} · ${card.egg_groups_label}`;
|
|
344
|
+
}
|
|
309
345
|
mergeCardsByName(perfect, ranged) {
|
|
310
346
|
const perfectMap = new Map();
|
|
311
347
|
const rangedMap = new Map();
|
|
@@ -482,6 +518,26 @@ class EggService {
|
|
|
482
518
|
}
|
|
483
519
|
return lines.join('\n');
|
|
484
520
|
}
|
|
521
|
+
buildEggSearchText(heightMeters, weight, results, heightDisplay) {
|
|
522
|
+
const cond = [];
|
|
523
|
+
if (heightMeters != null)
|
|
524
|
+
cond.push(`身高=${heightDisplay || `${formatNumber(heightMeters)}m`}`);
|
|
525
|
+
if (weight != null)
|
|
526
|
+
cond.push(`体重=${weight}kg`);
|
|
527
|
+
const condStr = cond.join(' + ') || '当前条件';
|
|
528
|
+
const items = Array.isArray(results?.items) ? results.items : [];
|
|
529
|
+
if (!items.length)
|
|
530
|
+
return `❌ 未找到符合 ${condStr} 的精灵。`;
|
|
531
|
+
const total = results?.total ?? items.length;
|
|
532
|
+
const lines = [`✅ 符合 ${condStr} 的精灵(共 ${total} 只):`];
|
|
533
|
+
items.slice(0, 10).forEach((item, index) => {
|
|
534
|
+
lines.push(` ${index + 1}. ${this.formatEggSearchTextLine(item)}`);
|
|
535
|
+
});
|
|
536
|
+
if (results?.has_more) {
|
|
537
|
+
lines.push(` ... 还有更多结果,可尝试更精确的尺寸或等待后续分页支持。`);
|
|
538
|
+
}
|
|
539
|
+
return lines.join('\n');
|
|
540
|
+
}
|
|
485
541
|
buildSearchText(pet) {
|
|
486
542
|
const egs = this.getEggGroups(pet);
|
|
487
543
|
const compat = this.getCompatiblePets(pet);
|
|
@@ -669,6 +725,26 @@ class EggService {
|
|
|
669
725
|
copyright: 'Koishi & WeGame 洛克王国插件',
|
|
670
726
|
};
|
|
671
727
|
}
|
|
728
|
+
buildEggSearchData(heightMeters, weight, results, heightDisplay) {
|
|
729
|
+
const conditions = [];
|
|
730
|
+
if (heightMeters != null)
|
|
731
|
+
conditions.push(`身高 ${heightDisplay || `${formatNumber(heightMeters)} m`}`);
|
|
732
|
+
if (weight != null)
|
|
733
|
+
conditions.push(`体重 ${weight} kg`);
|
|
734
|
+
const cards = (Array.isArray(results?.items) ? results.items : []).map((item) => this.formatEggSearchCard(item));
|
|
735
|
+
const pageNo = num(results?.page_no);
|
|
736
|
+
const totalPages = num(results?.total_pages);
|
|
737
|
+
const pageLabel = pageNo && totalPages ? ` · 第 ${pageNo}/${totalPages} 页` : '';
|
|
738
|
+
return {
|
|
739
|
+
query_label: `${conditions.join(' / ') || '孵蛋反查'}${pageLabel}`,
|
|
740
|
+
perfect_matches: cards,
|
|
741
|
+
range_matches: [],
|
|
742
|
+
total_count: results?.total ?? cards.length,
|
|
743
|
+
has_results: cards.length > 0,
|
|
744
|
+
commandHint: '洛克查蛋 <精灵名> | 洛克查蛋 0.18m 1.5kg | 洛克配种 <父体> <母体>',
|
|
745
|
+
copyright: 'Koishi & WeGame 洛克王国插件',
|
|
746
|
+
};
|
|
747
|
+
}
|
|
672
748
|
buildEggDetails(breeding) {
|
|
673
749
|
if (!breeding)
|
|
674
750
|
return { has_data: false };
|
package/lib/index.d.ts
CHANGED
|
@@ -13,7 +13,9 @@ export interface Config {
|
|
|
13
13
|
merchantSubscriptionEnabled: boolean;
|
|
14
14
|
merchantSubscriptionItems: string[];
|
|
15
15
|
merchantPrivateSubscriptionEnabled: boolean;
|
|
16
|
+
merchantCheckMode: 'interval' | 'times';
|
|
16
17
|
merchantCheckInterval: number;
|
|
18
|
+
merchantCheckTimes: string[];
|
|
17
19
|
homeSubscriptionEnabled: boolean;
|
|
18
20
|
homeSubscriptionIntervalMinutes: number;
|
|
19
21
|
imageCompressionEnabled: boolean;
|