koishi-plugin-maibot 1.7.32 → 1.7.34
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 +201 -0
- package/lib/database.d.ts +15 -0
- package/lib/database.d.ts.map +1 -1
- package/lib/database.js +20 -0
- package/lib/database.js.map +1 -1
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +605 -218
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -67,6 +67,13 @@ exports.Config = koishi_1.Schema.object({
|
|
|
67
67
|
interval: 10000,
|
|
68
68
|
message: '你正在排队,前面还有 {queuePosition} 人。预计等待 {queueEST} 秒。',
|
|
69
69
|
}),
|
|
70
|
+
operationLog: koishi_1.Schema.object({
|
|
71
|
+
enabled: koishi_1.Schema.boolean().default(true).description('操作记录开关,开启后记录所有操作'),
|
|
72
|
+
refIdLabel: koishi_1.Schema.string().default('Ref_ID').description('Ref_ID 显示标签(可自定义),默认 "Ref_ID"'),
|
|
73
|
+
}).description('操作记录配置').default({
|
|
74
|
+
enabled: true,
|
|
75
|
+
refIdLabel: 'Ref_ID',
|
|
76
|
+
}),
|
|
70
77
|
});
|
|
71
78
|
// 我认识了很多朋友 以下是我认识的好朋友们!
|
|
72
79
|
// Fracture_Hikaritsu
|
|
@@ -959,6 +966,54 @@ function apply(ctx, config) {
|
|
|
959
966
|
// 初始化队列系统
|
|
960
967
|
const queueConfig = config.queue || { enabled: false, interval: 10000, message: '你正在排队,前面还有 {queuePosition} 人。预计等待 {queueEST} 秒。' };
|
|
961
968
|
const requestQueue = queueConfig.enabled ? new RequestQueue(queueConfig.interval) : null;
|
|
969
|
+
// 操作记录配置
|
|
970
|
+
const operationLogConfig = config.operationLog || { enabled: true, refIdLabel: 'Ref_ID' };
|
|
971
|
+
/**
|
|
972
|
+
* 生成唯一的 ref_id
|
|
973
|
+
*/
|
|
974
|
+
function generateRefId() {
|
|
975
|
+
const timestamp = Date.now().toString(36);
|
|
976
|
+
const random = Math.random().toString(36).substring(2, 9);
|
|
977
|
+
return `${timestamp}-${random}`.toUpperCase();
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* 记录操作日志
|
|
981
|
+
*/
|
|
982
|
+
async function logOperation(params) {
|
|
983
|
+
if (!operationLogConfig.enabled) {
|
|
984
|
+
return '';
|
|
985
|
+
}
|
|
986
|
+
const refId = generateRefId();
|
|
987
|
+
try {
|
|
988
|
+
await ctx.database.create('maibot_operation_logs', {
|
|
989
|
+
refId,
|
|
990
|
+
command: params.command,
|
|
991
|
+
userId: params.session.userId || '',
|
|
992
|
+
targetUserId: params.targetUserId,
|
|
993
|
+
guildId: params.session.guildId || undefined,
|
|
994
|
+
channelId: params.session.channelId || undefined,
|
|
995
|
+
status: params.status,
|
|
996
|
+
result: params.result,
|
|
997
|
+
errorMessage: params.errorMessage,
|
|
998
|
+
apiResponse: params.apiResponse ? JSON.stringify(params.apiResponse) : undefined,
|
|
999
|
+
createdAt: new Date(),
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
catch (error) {
|
|
1003
|
+
logger.warn(`记录操作日志失败: ${error?.message || '未知错误'}`);
|
|
1004
|
+
}
|
|
1005
|
+
return refId;
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* 在结果消息中添加 Ref_ID
|
|
1009
|
+
*/
|
|
1010
|
+
function appendRefId(message, refId) {
|
|
1011
|
+
if (!refId || !operationLogConfig.enabled) {
|
|
1012
|
+
return message;
|
|
1013
|
+
}
|
|
1014
|
+
const label = operationLogConfig.refIdLabel || 'Ref_ID';
|
|
1015
|
+
return `${message}\n${label}: ${refId}`;
|
|
1016
|
+
}
|
|
962
1017
|
/**
|
|
963
1018
|
* 在API调用前加入队列并等待
|
|
964
1019
|
* 这个函数应该在获取到SGID后、调用API前使用
|
|
@@ -1191,7 +1246,7 @@ function apply(ctx, config) {
|
|
|
1191
1246
|
logger.debug(`getTargetBinding: 成功获取目标用户 ${targetUserIdRaw} 的绑定`);
|
|
1192
1247
|
return { binding: bindings[0], isProxy: true, error: null };
|
|
1193
1248
|
}
|
|
1194
|
-
const scheduleB50Notification = (session, taskId) => {
|
|
1249
|
+
const scheduleB50Notification = (session, taskId, initialRefId) => {
|
|
1195
1250
|
const bot = session.bot;
|
|
1196
1251
|
const channelId = session.channelId;
|
|
1197
1252
|
if (!bot || !channelId) {
|
|
@@ -1219,7 +1274,17 @@ function apply(ctx, config) {
|
|
|
1219
1274
|
const finishTime = detail.alive_task_end_time
|
|
1220
1275
|
? `\n完成时间: ${new Date((typeof detail.alive_task_end_time === 'number' ? detail.alive_task_end_time : parseInt(String(detail.alive_task_end_time))) * 1000).toLocaleString('zh-CN')}`
|
|
1221
1276
|
: '';
|
|
1222
|
-
|
|
1277
|
+
// 记录任务完成/失败的操作日志
|
|
1278
|
+
const taskRefId = await logOperation({
|
|
1279
|
+
command: 'mai上传B50-任务完成',
|
|
1280
|
+
session,
|
|
1281
|
+
status: hasError ? 'failure' : 'success',
|
|
1282
|
+
result: `${statusText}${finishTime}`,
|
|
1283
|
+
errorMessage: hasError ? detail.error || '未知错误' : undefined,
|
|
1284
|
+
apiResponse: detail,
|
|
1285
|
+
});
|
|
1286
|
+
const finalMessage = `${mention} 水鱼B50任务 ${taskId} 状态更新\n${statusText}${finishTime}`;
|
|
1287
|
+
await bot.sendMessage(channelId, appendRefId(finalMessage, taskRefId), guildId);
|
|
1223
1288
|
return;
|
|
1224
1289
|
}
|
|
1225
1290
|
// 如果还没完成且没出错,继续轮询(在超时范围内)
|
|
@@ -1227,12 +1292,19 @@ function apply(ctx, config) {
|
|
|
1227
1292
|
ctx.setTimeout(poll, interval);
|
|
1228
1293
|
return;
|
|
1229
1294
|
}
|
|
1295
|
+
// 超时情况
|
|
1296
|
+
const timeoutRefId = await logOperation({
|
|
1297
|
+
command: 'mai上传B50-任务超时',
|
|
1298
|
+
session,
|
|
1299
|
+
status: 'failure',
|
|
1300
|
+
errorMessage: '任务轮询超时(10分钟)',
|
|
1301
|
+
});
|
|
1230
1302
|
let msg = `${mention} 水鱼B50任务 ${taskId} 上传失败,请稍后再试一次。`;
|
|
1231
1303
|
const maintenanceMsg = getMaintenanceMessage(maintenanceNotice);
|
|
1232
1304
|
if (maintenanceMsg) {
|
|
1233
1305
|
msg += `\n${maintenanceMsg}`;
|
|
1234
1306
|
}
|
|
1235
|
-
await bot.sendMessage(channelId, msg, guildId);
|
|
1307
|
+
await bot.sendMessage(channelId, appendRefId(msg, timeoutRefId), guildId);
|
|
1236
1308
|
}
|
|
1237
1309
|
catch (error) {
|
|
1238
1310
|
logger.warn('轮询B50任务状态失败', error);
|
|
@@ -1240,18 +1312,25 @@ function apply(ctx, config) {
|
|
|
1240
1312
|
ctx.setTimeout(poll, interval);
|
|
1241
1313
|
return;
|
|
1242
1314
|
}
|
|
1315
|
+
// 轮询异常情况
|
|
1316
|
+
const errorRefId = await logOperation({
|
|
1317
|
+
command: 'mai上传B50-轮询异常',
|
|
1318
|
+
session,
|
|
1319
|
+
status: 'error',
|
|
1320
|
+
errorMessage: error instanceof Error ? error.message : '未知错误',
|
|
1321
|
+
});
|
|
1243
1322
|
let msg = `${mention} 水鱼B50任务 ${taskId} 上传失败,请稍后再试一次。`;
|
|
1244
1323
|
const maintenanceMsg = getMaintenanceMessage(maintenanceNotice);
|
|
1245
1324
|
if (maintenanceMsg) {
|
|
1246
1325
|
msg += `\n${maintenanceMsg}`;
|
|
1247
1326
|
}
|
|
1248
|
-
await bot.sendMessage(channelId, msg, guildId);
|
|
1327
|
+
await bot.sendMessage(channelId, appendRefId(msg, errorRefId), guildId);
|
|
1249
1328
|
}
|
|
1250
1329
|
};
|
|
1251
1330
|
// 首次延迟3秒后开始检查,之后每5秒轮询一次
|
|
1252
1331
|
ctx.setTimeout(poll, initialDelay);
|
|
1253
1332
|
};
|
|
1254
|
-
const scheduleLxB50Notification = (session, taskId) => {
|
|
1333
|
+
const scheduleLxB50Notification = (session, taskId, initialRefId) => {
|
|
1255
1334
|
const bot = session.bot;
|
|
1256
1335
|
const channelId = session.channelId;
|
|
1257
1336
|
if (!bot || !channelId) {
|
|
@@ -1279,7 +1358,17 @@ function apply(ctx, config) {
|
|
|
1279
1358
|
const finishTime = detail.alive_task_end_time
|
|
1280
1359
|
? `\n完成时间: ${new Date((typeof detail.alive_task_end_time === 'number' ? detail.alive_task_end_time : parseInt(String(detail.alive_task_end_time))) * 1000).toLocaleString('zh-CN')}`
|
|
1281
1360
|
: '';
|
|
1282
|
-
|
|
1361
|
+
// 记录任务完成/失败的操作日志
|
|
1362
|
+
const taskRefId = await logOperation({
|
|
1363
|
+
command: 'mai上传落雪b50-任务完成',
|
|
1364
|
+
session,
|
|
1365
|
+
status: hasError ? 'failure' : 'success',
|
|
1366
|
+
result: `${statusText}${finishTime}`,
|
|
1367
|
+
errorMessage: hasError ? detail.error || '未知错误' : undefined,
|
|
1368
|
+
apiResponse: detail,
|
|
1369
|
+
});
|
|
1370
|
+
const finalMessage = `${mention} 落雪B50任务 ${taskId} 状态更新\n${statusText}${finishTime}`;
|
|
1371
|
+
await bot.sendMessage(channelId, appendRefId(finalMessage, taskRefId), guildId);
|
|
1283
1372
|
return;
|
|
1284
1373
|
}
|
|
1285
1374
|
// 如果还没完成且没出错,继续轮询(在超时范围内)
|
|
@@ -1287,12 +1376,19 @@ function apply(ctx, config) {
|
|
|
1287
1376
|
ctx.setTimeout(poll, interval);
|
|
1288
1377
|
return;
|
|
1289
1378
|
}
|
|
1379
|
+
// 超时情况
|
|
1380
|
+
const timeoutRefId = await logOperation({
|
|
1381
|
+
command: 'mai上传落雪b50-任务超时',
|
|
1382
|
+
session,
|
|
1383
|
+
status: 'failure',
|
|
1384
|
+
errorMessage: '任务轮询超时(10分钟)',
|
|
1385
|
+
});
|
|
1290
1386
|
let msg = `${mention} 落雪B50任务 ${taskId} 上传失败,请稍后再试一次。`;
|
|
1291
1387
|
const maintenanceMsg = getMaintenanceMessage(maintenanceNotice);
|
|
1292
1388
|
if (maintenanceMsg) {
|
|
1293
1389
|
msg += `\n${maintenanceMsg}`;
|
|
1294
1390
|
}
|
|
1295
|
-
await bot.sendMessage(channelId, msg, guildId);
|
|
1391
|
+
await bot.sendMessage(channelId, appendRefId(msg, timeoutRefId), guildId);
|
|
1296
1392
|
}
|
|
1297
1393
|
catch (error) {
|
|
1298
1394
|
logger.warn('轮询落雪B50任务状态失败', error);
|
|
@@ -1300,12 +1396,19 @@ function apply(ctx, config) {
|
|
|
1300
1396
|
ctx.setTimeout(poll, interval);
|
|
1301
1397
|
return;
|
|
1302
1398
|
}
|
|
1399
|
+
// 轮询异常情况
|
|
1400
|
+
const errorRefId = await logOperation({
|
|
1401
|
+
command: 'mai上传落雪b50-轮询异常',
|
|
1402
|
+
session,
|
|
1403
|
+
status: 'error',
|
|
1404
|
+
errorMessage: error instanceof Error ? error.message : '未知错误',
|
|
1405
|
+
});
|
|
1303
1406
|
let msg = `${mention} 落雪B50任务 ${taskId} 上传失败,请稍后再试一次。`;
|
|
1304
1407
|
const maintenanceMsg = getMaintenanceMessage(maintenanceNotice);
|
|
1305
1408
|
if (maintenanceMsg) {
|
|
1306
1409
|
msg += `\n${maintenanceMsg}`;
|
|
1307
1410
|
}
|
|
1308
|
-
await bot.sendMessage(channelId, msg, guildId);
|
|
1411
|
+
await bot.sendMessage(channelId, appendRefId(msg, errorRefId), guildId);
|
|
1309
1412
|
}
|
|
1310
1413
|
};
|
|
1311
1414
|
// 首次延迟2秒后开始检查,之后每1秒轮询一次
|
|
@@ -1669,11 +1772,27 @@ function apply(ctx, config) {
|
|
|
1669
1772
|
}
|
|
1670
1773
|
catch (error) {
|
|
1671
1774
|
ctx.logger('maibot').error('获取用户预览信息失败:', error);
|
|
1672
|
-
|
|
1775
|
+
const errorMessage = `❌ 绑定失败:无法从二维码获取用户信息\n错误信息: ${error?.message || '未知错误'}`;
|
|
1776
|
+
const refId = await logOperation({
|
|
1777
|
+
command: 'mai绑定',
|
|
1778
|
+
session,
|
|
1779
|
+
status: 'error',
|
|
1780
|
+
errorMessage: error?.message || '未知错误',
|
|
1781
|
+
apiResponse: error?.response?.data,
|
|
1782
|
+
});
|
|
1783
|
+
return appendRefId(errorMessage, refId);
|
|
1673
1784
|
}
|
|
1674
1785
|
// 检查是否获取成功
|
|
1675
1786
|
if (previewResult.UserID === -1 || (typeof previewResult.UserID === 'string' && previewResult.UserID === '-1')) {
|
|
1676
|
-
|
|
1787
|
+
const errorMessage = `❌ 绑定失败:无效或过期的二维码`;
|
|
1788
|
+
const refId = await logOperation({
|
|
1789
|
+
command: 'mai绑定',
|
|
1790
|
+
session,
|
|
1791
|
+
status: 'failure',
|
|
1792
|
+
errorMessage: '无效或过期的二维码',
|
|
1793
|
+
apiResponse: previewResult,
|
|
1794
|
+
});
|
|
1795
|
+
return appendRefId(errorMessage, refId);
|
|
1677
1796
|
}
|
|
1678
1797
|
// UserID在新API中是加密的字符串
|
|
1679
1798
|
const maiUid = String(previewResult.UserID);
|
|
@@ -1690,21 +1809,34 @@ function apply(ctx, config) {
|
|
|
1690
1809
|
lastQrCode: qrCode, // 保存为缓存
|
|
1691
1810
|
lastQrCodeTime: new Date(), // 保存时间戳
|
|
1692
1811
|
});
|
|
1693
|
-
|
|
1812
|
+
const successMessage = `✅ 绑定成功!\n` +
|
|
1694
1813
|
(userName ? `用户名: ${userName}\n` : '') +
|
|
1695
1814
|
(rating ? `Rating: ${rating}\n` : '') +
|
|
1696
1815
|
`绑定时间: ${new Date().toLocaleString('zh-CN')}\n\n` +
|
|
1697
1816
|
`⚠️ 为了确保账户安全,请手动撤回群内包含SGID的消息`;
|
|
1817
|
+
const refId = await logOperation({
|
|
1818
|
+
command: 'mai绑定',
|
|
1819
|
+
session,
|
|
1820
|
+
status: 'success',
|
|
1821
|
+
result: successMessage,
|
|
1822
|
+
});
|
|
1823
|
+
return appendRefId(successMessage, refId);
|
|
1698
1824
|
}
|
|
1699
1825
|
catch (error) {
|
|
1700
1826
|
ctx.logger('maibot').error('绑定失败:', error);
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1827
|
+
const errorMessage = maintenanceMode
|
|
1828
|
+
? maintenanceMessage
|
|
1829
|
+
: (error?.response
|
|
1830
|
+
? `❌ API请求失败: ${error.response.status} ${error.response.statusText}\n\n${maintenanceMessage}`
|
|
1831
|
+
: `❌ 绑定失败: ${error?.message || '未知错误'}\n\n${maintenanceMessage}`);
|
|
1832
|
+
const refId = await logOperation({
|
|
1833
|
+
command: 'mai绑定',
|
|
1834
|
+
session,
|
|
1835
|
+
status: 'error',
|
|
1836
|
+
errorMessage: error?.message || '未知错误',
|
|
1837
|
+
apiResponse: error?.response?.data,
|
|
1838
|
+
});
|
|
1839
|
+
return appendRefId(errorMessage, refId);
|
|
1708
1840
|
}
|
|
1709
1841
|
});
|
|
1710
1842
|
/**
|
|
@@ -1776,10 +1908,14 @@ function apply(ctx, config) {
|
|
|
1776
1908
|
statusInfo += `\n⚠️ 无法获取最新状态:${qrTextResult.error}`;
|
|
1777
1909
|
}
|
|
1778
1910
|
else {
|
|
1779
|
-
// 在调用API
|
|
1911
|
+
// 在调用API前加入队列(只调用一次)
|
|
1780
1912
|
await waitForQueue(session);
|
|
1781
1913
|
try {
|
|
1782
|
-
|
|
1914
|
+
// 同时获取 preview 和 getCharge(并行执行,避免重复排队)
|
|
1915
|
+
const [preview, chargeResult] = await Promise.all([
|
|
1916
|
+
api.getPreview(machineInfo.clientId, qrTextResult.qrText),
|
|
1917
|
+
api.getCharge(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText)
|
|
1918
|
+
]);
|
|
1783
1919
|
// 更新数据库中的用户名和Rating
|
|
1784
1920
|
await ctx.database.set('maibot_bindings', { userId }, {
|
|
1785
1921
|
userName: preview.UserName,
|
|
@@ -1822,6 +1958,9 @@ function apply(ctx, config) {
|
|
|
1822
1958
|
(versionInfo ? versionInfo : '') +
|
|
1823
1959
|
`登录状态: ${preview.IsLogin === true ? '已登录' : '未登录'}\n` +
|
|
1824
1960
|
`封禁状态: ${preview.BanState === 0 ? '正常' : '已封禁'}\n`;
|
|
1961
|
+
// 保存 chargeResult 供后续使用
|
|
1962
|
+
qrTextResultForCharge = { ...qrTextResult };
|
|
1963
|
+
qrTextResultForCharge.chargeResult = chargeResult;
|
|
1825
1964
|
}
|
|
1826
1965
|
catch (error) {
|
|
1827
1966
|
logger.warn('获取用户预览信息失败:', error);
|
|
@@ -1876,9 +2015,17 @@ function apply(ctx, config) {
|
|
|
1876
2015
|
// 显示票券信息(使用新的getCharge API)
|
|
1877
2016
|
try {
|
|
1878
2017
|
if (qrTextResultForCharge && !qrTextResultForCharge.error) {
|
|
1879
|
-
//
|
|
1880
|
-
|
|
1881
|
-
|
|
2018
|
+
// 如果已经在上面获取了 chargeResult,直接使用;否则重新获取
|
|
2019
|
+
let chargeResult;
|
|
2020
|
+
if (qrTextResultForCharge.chargeResult) {
|
|
2021
|
+
// 已经在上面并行获取了,直接使用
|
|
2022
|
+
chargeResult = qrTextResultForCharge.chargeResult;
|
|
2023
|
+
}
|
|
2024
|
+
else {
|
|
2025
|
+
// 如果上面获取失败,这里重新获取(需要排队)
|
|
2026
|
+
await waitForQueue(session);
|
|
2027
|
+
chargeResult = await api.getCharge(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResultForCharge.qrText);
|
|
2028
|
+
}
|
|
1882
2029
|
if (chargeResult.ChargeStatus && chargeResult.userChargeList) {
|
|
1883
2030
|
const now = new Date();
|
|
1884
2031
|
const validTickets = [];
|
|
@@ -1937,10 +2084,26 @@ function apply(ctx, config) {
|
|
|
1937
2084
|
logger.warn('获取票券信息失败:', error);
|
|
1938
2085
|
statusInfo += `\n\n🎫 票券情况: 获取失败(${error?.message || '未知错误'})`;
|
|
1939
2086
|
}
|
|
1940
|
-
|
|
2087
|
+
const refId = await logOperation({
|
|
2088
|
+
command: 'mai状态',
|
|
2089
|
+
session,
|
|
2090
|
+
targetUserId,
|
|
2091
|
+
status: 'success',
|
|
2092
|
+
result: statusInfo,
|
|
2093
|
+
});
|
|
2094
|
+
return appendRefId(statusInfo, refId);
|
|
1941
2095
|
}
|
|
1942
2096
|
catch (error) {
|
|
1943
2097
|
ctx.logger('maibot').error('查询状态失败:', error);
|
|
2098
|
+
const errorMessage = `❌ 查询状态失败: ${error?.message || '未知错误'}`;
|
|
2099
|
+
const refId = await logOperation({
|
|
2100
|
+
command: 'mai状态',
|
|
2101
|
+
session,
|
|
2102
|
+
targetUserId,
|
|
2103
|
+
status: 'error',
|
|
2104
|
+
errorMessage: error?.message || '未知错误',
|
|
2105
|
+
});
|
|
2106
|
+
return appendRefId(errorMessage, refId);
|
|
1944
2107
|
if (maintenanceMode) {
|
|
1945
2108
|
return maintenanceMessage;
|
|
1946
2109
|
}
|
|
@@ -2487,17 +2650,32 @@ function apply(ctx, config) {
|
|
|
2487
2650
|
return '❌ 发票失败:服务器返回未成功,请确认是否已在短时间内多次执行发票指令或稍后再试或点击获取二维码刷新账号后再试。';
|
|
2488
2651
|
}
|
|
2489
2652
|
}
|
|
2490
|
-
|
|
2653
|
+
const successMessage = `✅ 已发放 ${multiple} 倍票\n请稍等几分钟在游戏内确认`;
|
|
2654
|
+
const refId = await logOperation({
|
|
2655
|
+
command: 'mai发票',
|
|
2656
|
+
session,
|
|
2657
|
+
targetUserId,
|
|
2658
|
+
status: 'success',
|
|
2659
|
+
result: successMessage,
|
|
2660
|
+
});
|
|
2661
|
+
return appendRefId(successMessage, refId);
|
|
2491
2662
|
}
|
|
2492
2663
|
catch (error) {
|
|
2493
2664
|
logger.error('发票失败:', error);
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2665
|
+
const errorMessage = maintenanceMode
|
|
2666
|
+
? maintenanceMessage
|
|
2667
|
+
: (error?.response
|
|
2668
|
+
? `❌ API请求失败: ${error.response.status} ${error.response.statusText}\n\n${maintenanceMessage}`
|
|
2669
|
+
: `❌ 发票失败: ${error?.message || '未知错误'}\n\n${maintenanceMessage}`);
|
|
2670
|
+
const refId = await logOperation({
|
|
2671
|
+
command: 'mai发票',
|
|
2672
|
+
session,
|
|
2673
|
+
targetUserId,
|
|
2674
|
+
status: 'error',
|
|
2675
|
+
errorMessage: error?.message || '未知错误',
|
|
2676
|
+
apiResponse: error?.response?.data,
|
|
2677
|
+
});
|
|
2678
|
+
return appendRefId(errorMessage, refId);
|
|
2501
2679
|
}
|
|
2502
2680
|
});
|
|
2503
2681
|
/**
|
|
@@ -2678,8 +2856,17 @@ function apply(ctx, config) {
|
|
|
2678
2856
|
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
2679
2857
|
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
2680
2858
|
}
|
|
2681
|
-
|
|
2682
|
-
|
|
2859
|
+
const successMessage = `✅ B50上传任务已提交!\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
|
|
2860
|
+
const refId = await logOperation({
|
|
2861
|
+
command: 'mai上传B50',
|
|
2862
|
+
session,
|
|
2863
|
+
targetUserId,
|
|
2864
|
+
status: 'success',
|
|
2865
|
+
result: successMessage,
|
|
2866
|
+
apiResponse: result,
|
|
2867
|
+
});
|
|
2868
|
+
scheduleB50Notification(session, result.task_id, refId);
|
|
2869
|
+
return appendRefId(successMessage, refId);
|
|
2683
2870
|
}
|
|
2684
2871
|
return `❌ 获取二维码失败:${qrTextResult.error}`;
|
|
2685
2872
|
}
|
|
@@ -2758,8 +2945,17 @@ function apply(ctx, config) {
|
|
|
2758
2945
|
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
2759
2946
|
}
|
|
2760
2947
|
}
|
|
2761
|
-
|
|
2762
|
-
|
|
2948
|
+
const successMessage = `✅ B50上传任务已提交!\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
|
|
2949
|
+
const refId = await logOperation({
|
|
2950
|
+
command: 'mai上传B50',
|
|
2951
|
+
session,
|
|
2952
|
+
targetUserId,
|
|
2953
|
+
status: 'success',
|
|
2954
|
+
result: successMessage,
|
|
2955
|
+
apiResponse: result,
|
|
2956
|
+
});
|
|
2957
|
+
scheduleB50Notification(session, result.task_id, refId);
|
|
2958
|
+
return appendRefId(successMessage, refId);
|
|
2763
2959
|
}
|
|
2764
2960
|
catch (error) {
|
|
2765
2961
|
ctx.logger('maibot').error('上传B50失败:', error);
|
|
@@ -2864,157 +3060,166 @@ function apply(ctx, config) {
|
|
|
2864
3060
|
return `❌ 获取二维码失败:${qrTextResult.error}`;
|
|
2865
3061
|
}
|
|
2866
3062
|
const results = [];
|
|
2867
|
-
//
|
|
2868
|
-
|
|
2869
|
-
|
|
3063
|
+
// 先上传水鱼B50,等待完成后再上传落雪(串行执行,避免同时登录)
|
|
3064
|
+
try {
|
|
3065
|
+
await waitForQueue(session);
|
|
3066
|
+
let fishResult = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText, fishToken);
|
|
3067
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
3068
|
+
if (qrTextResult.fromCache && !fishResult.UploadStatus && (fishResult.msg?.includes('二维码') || fishResult.msg?.includes('qr_text') || fishResult.msg?.includes('无效'))) {
|
|
3069
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
3070
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
3071
|
+
if (retryQrText.error) {
|
|
3072
|
+
const taskIdInfo = fishResult.task_id ? `\n任务ID: ${fishResult.task_id}` : '';
|
|
3073
|
+
return `🐟 水鱼: ❌ 上传失败:${fishResult.msg || '未知错误'}\n获取新二维码失败:${retryQrText.error}${taskIdInfo}`;
|
|
3074
|
+
}
|
|
3075
|
+
// 在调用API前加入队列
|
|
2870
3076
|
await waitForQueue(session);
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
if (retryQrText.error) {
|
|
2877
|
-
const taskIdInfo = fishResult.task_id ? `\n任务ID: ${fishResult.task_id}` : '';
|
|
2878
|
-
results.push(`🐟 水鱼: ❌ 上传失败:${fishResult.msg || '未知错误'}\n获取新二维码失败:${retryQrText.error}${taskIdInfo}`);
|
|
2879
|
-
return null;
|
|
2880
|
-
}
|
|
2881
|
-
// 在调用API前加入队列
|
|
2882
|
-
await waitForQueue(session);
|
|
2883
|
-
fishResult = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, fishToken);
|
|
3077
|
+
fishResult = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, fishToken);
|
|
3078
|
+
}
|
|
3079
|
+
if (!fishResult.UploadStatus) {
|
|
3080
|
+
if (fishResult.msg === '该账号下存在未完成的任务') {
|
|
3081
|
+
results.push('🐟 水鱼: ⚠️ 当前账号已有未完成的B50任务,请稍后再试,无需重复上传。');
|
|
2884
3082
|
}
|
|
2885
|
-
if (
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
return
|
|
2889
|
-
}
|
|
2890
|
-
if (fishResult.msg?.includes('二维码') || fishResult.msg?.includes('qr_text') || fishResult.msg?.includes('无效')) {
|
|
2891
|
-
const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
|
|
2892
|
-
if (rebindResult.success && rebindResult.newBinding) {
|
|
2893
|
-
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
2894
|
-
}
|
|
2895
|
-
const taskIdInfo = fishResult.task_id ? `\n任务ID: ${fishResult.task_id}` : '';
|
|
2896
|
-
return `❌ 水鱼上传失败:${fishResult.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}`;
|
|
3083
|
+
else if (fishResult.msg?.includes('二维码') || fishResult.msg?.includes('qr_text') || fishResult.msg?.includes('无效')) {
|
|
3084
|
+
const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
|
|
3085
|
+
if (rebindResult.success && rebindResult.newBinding) {
|
|
3086
|
+
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
2897
3087
|
}
|
|
3088
|
+
const taskIdInfo = fishResult.task_id ? `\n任务ID: ${fishResult.task_id}` : '';
|
|
3089
|
+
return `❌ 水鱼上传失败:${fishResult.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}`;
|
|
3090
|
+
}
|
|
3091
|
+
else {
|
|
2898
3092
|
const taskIdInfo = fishResult.task_id ? `\n任务ID: ${fishResult.task_id}` : '';
|
|
2899
3093
|
results.push(`🐟 水鱼: ❌ 上传失败:${fishResult.msg || '未知错误'}${taskIdInfo}`);
|
|
2900
|
-
return null;
|
|
2901
3094
|
}
|
|
2902
|
-
scheduleB50Notification(session, fishResult.task_id);
|
|
2903
|
-
results.push(`🐟 水鱼: ✅ B50任务已提交!\n任务ID: ${fishResult.task_id}\n请耐心等待任务完成,预计1-10分钟`);
|
|
2904
|
-
return null;
|
|
2905
3095
|
}
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
3096
|
+
else {
|
|
3097
|
+
const successMessage = `🐟 水鱼: ✅ B50任务已提交!\n任务ID: ${fishResult.task_id}\n请耐心等待任务完成,预计1-10分钟`;
|
|
3098
|
+
const refId = await logOperation({
|
|
3099
|
+
command: 'maiua-水鱼B50',
|
|
3100
|
+
session,
|
|
3101
|
+
targetUserId: actualTargetUserId,
|
|
3102
|
+
status: 'success',
|
|
3103
|
+
result: successMessage,
|
|
3104
|
+
apiResponse: fishResult,
|
|
3105
|
+
});
|
|
3106
|
+
scheduleB50Notification(session, fishResult.task_id, refId);
|
|
3107
|
+
results.push(appendRefId(successMessage, refId));
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
catch (error) {
|
|
3111
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
3112
|
+
if (qrTextResult.fromCache) {
|
|
3113
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
3114
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
3115
|
+
if (retryQrText.error) {
|
|
3116
|
+
return `🐟 水鱼: ❌ 获取二维码失败:${retryQrText.error}`;
|
|
3117
|
+
}
|
|
3118
|
+
// 在调用API前加入队列
|
|
3119
|
+
await waitForQueue(session);
|
|
3120
|
+
try {
|
|
3121
|
+
const fishResult = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, fishToken);
|
|
3122
|
+
if (!fishResult.UploadStatus) {
|
|
3123
|
+
if (fishResult.msg === '该账号下存在未完成的任务') {
|
|
3124
|
+
results.push('🐟 水鱼: ⚠️ 当前账号已有未完成的B50任务,请稍后再试,无需重复上传。');
|
|
3125
|
+
}
|
|
3126
|
+
else {
|
|
2924
3127
|
const taskIdInfo = fishResult.task_id ? `\n任务ID: ${fishResult.task_id}` : '';
|
|
2925
|
-
|
|
2926
|
-
return null;
|
|
3128
|
+
return `🐟 水鱼: ❌ 上传失败:${fishResult.msg || '未知错误'}${taskIdInfo}`;
|
|
2927
3129
|
}
|
|
3130
|
+
}
|
|
3131
|
+
else {
|
|
2928
3132
|
scheduleB50Notification(session, fishResult.task_id);
|
|
2929
3133
|
results.push(`🐟 水鱼: ✅ B50任务已提交!\n任务ID: ${fishResult.task_id}\n请耐心等待任务完成,预计1-10分钟`);
|
|
2930
|
-
return null;
|
|
2931
|
-
}
|
|
2932
|
-
catch (retryError) {
|
|
2933
|
-
const failureResult = await handleApiFailure(session, ctx, api, binding, config, retryError, rebindTimeout);
|
|
2934
|
-
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
2935
|
-
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
2936
|
-
}
|
|
2937
|
-
if (retryError?.code === 'ECONNABORTED' || String(retryError?.message || '').includes('timeout')) {
|
|
2938
|
-
results.push('🐟 水鱼: ❌ 上传超时,请稍后再试一次。');
|
|
2939
|
-
return null;
|
|
2940
|
-
}
|
|
2941
|
-
if (retryError?.response) {
|
|
2942
|
-
results.push(`🐟 水鱼: ❌ API请求失败: ${retryError.response.status} ${retryError.response.statusText}`);
|
|
2943
|
-
return null;
|
|
2944
|
-
}
|
|
2945
|
-
results.push(`🐟 水鱼: ❌ 上传失败: ${retryError?.message || '未知错误'}`);
|
|
2946
|
-
return null;
|
|
2947
3134
|
}
|
|
2948
3135
|
}
|
|
2949
|
-
|
|
2950
|
-
const failureResult = await handleApiFailure(session, ctx, api, binding, config,
|
|
3136
|
+
catch (retryError) {
|
|
3137
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, retryError, rebindTimeout);
|
|
2951
3138
|
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
2952
3139
|
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
2953
3140
|
}
|
|
2954
|
-
if (
|
|
2955
|
-
|
|
2956
|
-
return null;
|
|
3141
|
+
if (retryError?.code === 'ECONNABORTED' || String(retryError?.message || '').includes('timeout')) {
|
|
3142
|
+
return '🐟 水鱼: ❌ 上传超时,请稍后再试一次。';
|
|
2957
3143
|
}
|
|
2958
|
-
if (
|
|
2959
|
-
|
|
2960
|
-
return null;
|
|
3144
|
+
if (retryError?.response) {
|
|
3145
|
+
return `🐟 水鱼: ❌ API请求失败: ${retryError.response.status} ${retryError.response.statusText}`;
|
|
2961
3146
|
}
|
|
2962
|
-
|
|
2963
|
-
return null;
|
|
3147
|
+
return `🐟 水鱼: ❌ 上传失败: ${retryError?.message || '未知错误'}`;
|
|
2964
3148
|
}
|
|
2965
3149
|
}
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
3150
|
+
else {
|
|
3151
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
|
|
3152
|
+
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
3153
|
+
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
3154
|
+
}
|
|
3155
|
+
if (error?.code === 'ECONNABORTED' || String(error?.message || '').includes('timeout')) {
|
|
3156
|
+
return '🐟 水鱼: ❌ 上传超时,请稍后再试一次。';
|
|
3157
|
+
}
|
|
3158
|
+
if (error?.response) {
|
|
3159
|
+
return `🐟 水鱼: ❌ API请求失败: ${error.response.status} ${error.response.statusText}`;
|
|
3160
|
+
}
|
|
3161
|
+
return `🐟 水鱼: ❌ 上传失败: ${error?.message || '未知错误'}`;
|
|
3162
|
+
}
|
|
2969
3163
|
}
|
|
3164
|
+
// 等待水鱼上传完成后再上传落雪(避免同时登录导致失败)
|
|
2970
3165
|
// 上传落雪B50
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
}
|
|
3166
|
+
try {
|
|
3167
|
+
await waitForQueue(session);
|
|
3168
|
+
let lxResult = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText, finalLxnsCode);
|
|
3169
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
3170
|
+
if (qrTextResult.fromCache && !lxResult.UploadStatus && (lxResult.msg?.includes('二维码') || lxResult.msg?.includes('qr_text') || lxResult.msg?.includes('无效'))) {
|
|
3171
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
3172
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
3173
|
+
if (retryQrText.error) {
|
|
3174
|
+
const taskIdInfo = lxResult.task_id ? `\n任务ID: ${lxResult.task_id}` : '';
|
|
3175
|
+
results.push(`❄️ 落雪: ❌ 上传失败:${lxResult.msg || '未知错误'}\n获取新二维码失败:${retryQrText.error}${taskIdInfo}`);
|
|
3176
|
+
}
|
|
3177
|
+
else {
|
|
2984
3178
|
// 在调用API前加入队列
|
|
2985
3179
|
await waitForQueue(session);
|
|
2986
3180
|
lxResult = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, finalLxnsCode);
|
|
2987
3181
|
}
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
}
|
|
2998
|
-
const taskIdInfo = lxResult.task_id ? `\n任务ID: ${lxResult.task_id}` : '';
|
|
2999
|
-
return `❌ 落雪上传失败:${lxResult.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}`;
|
|
3182
|
+
}
|
|
3183
|
+
if (!lxResult.UploadStatus) {
|
|
3184
|
+
if (lxResult.msg === '该账号下存在未完成的任务') {
|
|
3185
|
+
results.push('❄️ 落雪: ⚠️ 当前账号已有未完成的B50任务,请稍后再试,无需重复上传。');
|
|
3186
|
+
}
|
|
3187
|
+
else if (lxResult.msg?.includes('二维码') || lxResult.msg?.includes('qr_text') || lxResult.msg?.includes('无效')) {
|
|
3188
|
+
const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
|
|
3189
|
+
if (rebindResult.success && rebindResult.newBinding) {
|
|
3190
|
+
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
3000
3191
|
}
|
|
3192
|
+
const taskIdInfo = lxResult.task_id ? `\n任务ID: ${lxResult.task_id}` : '';
|
|
3193
|
+
return `❌ 落雪上传失败:${lxResult.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}`;
|
|
3194
|
+
}
|
|
3195
|
+
else {
|
|
3001
3196
|
const taskIdInfo = lxResult.task_id ? `\n任务ID: ${lxResult.task_id}` : '';
|
|
3002
3197
|
results.push(`❄️ 落雪: ❌ 上传失败:${lxResult.msg || '未知错误'}${taskIdInfo}`);
|
|
3003
|
-
return null;
|
|
3004
3198
|
}
|
|
3005
|
-
scheduleLxB50Notification(session, lxResult.task_id);
|
|
3006
|
-
results.push(`❄️ 落雪: ✅ B50任务已提交!\n任务ID: ${lxResult.task_id}\n请耐心等待任务完成,预计1-10分钟`);
|
|
3007
|
-
return null;
|
|
3008
3199
|
}
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3200
|
+
else {
|
|
3201
|
+
const successMessage = `❄️ 落雪: ✅ B50任务已提交!\n任务ID: ${lxResult.task_id}\n请耐心等待任务完成,预计1-10分钟`;
|
|
3202
|
+
const refId = await logOperation({
|
|
3203
|
+
command: 'maiua-落雪B50',
|
|
3204
|
+
session,
|
|
3205
|
+
targetUserId: actualTargetUserId,
|
|
3206
|
+
status: 'success',
|
|
3207
|
+
result: successMessage,
|
|
3208
|
+
apiResponse: lxResult,
|
|
3209
|
+
});
|
|
3210
|
+
scheduleLxB50Notification(session, lxResult.task_id, refId);
|
|
3211
|
+
results.push(appendRefId(successMessage, refId));
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
catch (error) {
|
|
3215
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
3216
|
+
if (qrTextResult.fromCache) {
|
|
3217
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
3218
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
3219
|
+
if (retryQrText.error) {
|
|
3220
|
+
results.push(`❄️ 落雪: ❌ 获取二维码失败:${retryQrText.error}`);
|
|
3221
|
+
}
|
|
3222
|
+
else {
|
|
3018
3223
|
// 在调用API前加入队列
|
|
3019
3224
|
await waitForQueue(session);
|
|
3020
3225
|
try {
|
|
@@ -3022,15 +3227,25 @@ function apply(ctx, config) {
|
|
|
3022
3227
|
if (!lxResult.UploadStatus) {
|
|
3023
3228
|
if (lxResult.msg === '该账号下存在未完成的任务') {
|
|
3024
3229
|
results.push('❄️ 落雪: ⚠️ 当前账号已有未完成的B50任务,请稍后再试,无需重复上传。');
|
|
3025
|
-
return null;
|
|
3026
3230
|
}
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3231
|
+
else {
|
|
3232
|
+
const taskIdInfo = lxResult.task_id ? `\n任务ID: ${lxResult.task_id}` : '';
|
|
3233
|
+
results.push(`❄️ 落雪: ❌ 上传失败:${lxResult.msg || '未知错误'}${taskIdInfo}`);
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
else {
|
|
3237
|
+
const successMessage = `❄️ 落雪: ✅ B50任务已提交!\n任务ID: ${lxResult.task_id}\n请耐心等待任务完成,预计1-10分钟`;
|
|
3238
|
+
const refId = await logOperation({
|
|
3239
|
+
command: 'maiua-落雪B50',
|
|
3240
|
+
session,
|
|
3241
|
+
targetUserId: actualTargetUserId,
|
|
3242
|
+
status: 'success',
|
|
3243
|
+
result: successMessage,
|
|
3244
|
+
apiResponse: lxResult,
|
|
3245
|
+
});
|
|
3246
|
+
scheduleLxB50Notification(session, lxResult.task_id, refId);
|
|
3247
|
+
results.push(appendRefId(successMessage, refId));
|
|
3030
3248
|
}
|
|
3031
|
-
scheduleLxB50Notification(session, lxResult.task_id);
|
|
3032
|
-
results.push(`❄️ 落雪: ✅ B50任务已提交!\n任务ID: ${lxResult.task_id}\n请耐心等待任务完成,预计1-10分钟`);
|
|
3033
|
-
return null;
|
|
3034
3249
|
}
|
|
3035
3250
|
catch (retryError) {
|
|
3036
3251
|
const failureResult = await handleApiFailure(session, ctx, api, binding, config, retryError, rebindTimeout);
|
|
@@ -3039,36 +3254,31 @@ function apply(ctx, config) {
|
|
|
3039
3254
|
}
|
|
3040
3255
|
if (retryError?.code === 'ECONNABORTED' || String(retryError?.message || '').includes('timeout')) {
|
|
3041
3256
|
results.push('❄️ 落雪: ❌ 上传超时,请稍后再试一次。');
|
|
3042
|
-
return null;
|
|
3043
3257
|
}
|
|
3044
|
-
if (retryError?.response) {
|
|
3258
|
+
else if (retryError?.response) {
|
|
3045
3259
|
results.push(`❄️ 落雪: ❌ API请求失败: ${retryError.response.status} ${retryError.response.statusText}`);
|
|
3046
|
-
return null;
|
|
3047
3260
|
}
|
|
3048
|
-
|
|
3049
|
-
|
|
3261
|
+
else {
|
|
3262
|
+
results.push(`❄️ 落雪: ❌ 上传失败: ${retryError?.message || '未知错误'}`);
|
|
3263
|
+
}
|
|
3050
3264
|
}
|
|
3051
3265
|
}
|
|
3266
|
+
}
|
|
3267
|
+
else {
|
|
3268
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
|
|
3269
|
+
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
3270
|
+
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
3271
|
+
}
|
|
3272
|
+
if (error?.code === 'ECONNABORTED' || String(error?.message || '').includes('timeout')) {
|
|
3273
|
+
results.push('❄️ 落雪: ❌ 上传超时,请稍后再试一次。');
|
|
3274
|
+
}
|
|
3275
|
+
else if (error?.response) {
|
|
3276
|
+
results.push(`❄️ 落雪: ❌ API请求失败: ${error.response.status} ${error.response.statusText}`);
|
|
3277
|
+
}
|
|
3052
3278
|
else {
|
|
3053
|
-
const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
|
|
3054
|
-
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
3055
|
-
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
3056
|
-
}
|
|
3057
|
-
if (error?.code === 'ECONNABORTED' || String(error?.message || '').includes('timeout')) {
|
|
3058
|
-
results.push('❄️ 落雪: ❌ 上传超时,请稍后再试一次。');
|
|
3059
|
-
return null;
|
|
3060
|
-
}
|
|
3061
|
-
if (error?.response) {
|
|
3062
|
-
results.push(`❄️ 落雪: ❌ API请求失败: ${error.response.status} ${error.response.statusText}`);
|
|
3063
|
-
return null;
|
|
3064
|
-
}
|
|
3065
3279
|
results.push(`❄️ 落雪: ❌ 上传失败: ${error?.message || '未知错误'}`);
|
|
3066
|
-
return null;
|
|
3067
3280
|
}
|
|
3068
3281
|
}
|
|
3069
|
-
})();
|
|
3070
|
-
if (lxnsAbort) {
|
|
3071
|
-
return lxnsAbort;
|
|
3072
3282
|
}
|
|
3073
3283
|
if (results.length === 0) {
|
|
3074
3284
|
return `⚠️ 未能发起上传请求${proxyTip}`;
|
|
@@ -3613,11 +3823,11 @@ function apply(ctx, config) {
|
|
|
3613
3823
|
if (!whitelistCheck.allowed) {
|
|
3614
3824
|
return whitelistCheck.message || '本群暂时没有被授权使用本Bot的功能,请添加官方群聊1072033605。';
|
|
3615
3825
|
}
|
|
3826
|
+
// 解析参数:第一个参数可能是SGID/URL或落雪代码
|
|
3827
|
+
let qrCode;
|
|
3828
|
+
let lxnsCode;
|
|
3829
|
+
let actualTargetUserId = targetUserId;
|
|
3616
3830
|
try {
|
|
3617
|
-
// 解析参数:第一个参数可能是SGID/URL或落雪代码
|
|
3618
|
-
let qrCode;
|
|
3619
|
-
let lxnsCode;
|
|
3620
|
-
let actualTargetUserId = targetUserId;
|
|
3621
3831
|
// 检查第一个参数是否是SGID或URL
|
|
3622
3832
|
if (qrCodeOrLxnsCode) {
|
|
3623
3833
|
const processed = processSGID(qrCodeOrLxnsCode);
|
|
@@ -3701,8 +3911,17 @@ function apply(ctx, config) {
|
|
|
3701
3911
|
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
3702
3912
|
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
3703
3913
|
}
|
|
3704
|
-
|
|
3705
|
-
|
|
3914
|
+
const successMessage = `✅ 落雪B50上传任务已提交!\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
|
|
3915
|
+
const refId = await logOperation({
|
|
3916
|
+
command: 'mai上传落雪b50',
|
|
3917
|
+
session,
|
|
3918
|
+
targetUserId: actualTargetUserId,
|
|
3919
|
+
status: 'success',
|
|
3920
|
+
result: successMessage,
|
|
3921
|
+
apiResponse: result,
|
|
3922
|
+
});
|
|
3923
|
+
scheduleLxB50Notification(session, result.task_id, refId);
|
|
3924
|
+
return appendRefId(successMessage, refId);
|
|
3706
3925
|
}
|
|
3707
3926
|
return `❌ 获取二维码失败:${qrTextResult.error}`;
|
|
3708
3927
|
}
|
|
@@ -3781,28 +4000,44 @@ function apply(ctx, config) {
|
|
|
3781
4000
|
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
3782
4001
|
}
|
|
3783
4002
|
}
|
|
3784
|
-
|
|
3785
|
-
|
|
4003
|
+
const successMessage = `✅ 落雪B50上传任务已提交!\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
|
|
4004
|
+
const refId = await logOperation({
|
|
4005
|
+
command: 'mai上传落雪b50',
|
|
4006
|
+
session,
|
|
4007
|
+
targetUserId: actualTargetUserId || undefined,
|
|
4008
|
+
status: 'success',
|
|
4009
|
+
result: successMessage,
|
|
4010
|
+
apiResponse: result,
|
|
4011
|
+
});
|
|
4012
|
+
scheduleLxB50Notification(session, result.task_id, refId);
|
|
4013
|
+
return appendRefId(successMessage, refId);
|
|
3786
4014
|
}
|
|
3787
4015
|
catch (error) {
|
|
3788
4016
|
ctx.logger('maibot').error('上传落雪B50失败:', error);
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
4017
|
+
const errorMessage = maintenanceMode
|
|
4018
|
+
? maintenanceMessage
|
|
4019
|
+
: (error?.code === 'ECONNABORTED' || String(error?.message || '').includes('timeout')
|
|
4020
|
+
? (() => {
|
|
4021
|
+
let msg = '落雪B50任务 上传失败,请稍后再试一次。';
|
|
4022
|
+
const maintenanceMsg = getMaintenanceMessage(maintenanceNotice);
|
|
4023
|
+
if (maintenanceMsg) {
|
|
4024
|
+
msg += `\n${maintenanceMsg}`;
|
|
4025
|
+
}
|
|
4026
|
+
msg += `\n\n${maintenanceMessage}`;
|
|
4027
|
+
return msg;
|
|
4028
|
+
})()
|
|
4029
|
+
: (error?.response
|
|
4030
|
+
? `❌ API请求失败: ${error.response.status} ${error.response.statusText}\n\n${maintenanceMessage}`
|
|
4031
|
+
: `❌ 上传失败: ${error?.message || '未知错误'}\n\n${maintenanceMessage}`));
|
|
4032
|
+
const refId = await logOperation({
|
|
4033
|
+
command: 'mai上传落雪b50',
|
|
4034
|
+
session,
|
|
4035
|
+
targetUserId: (typeof actualTargetUserId !== 'undefined' ? actualTargetUserId : targetUserId) || undefined,
|
|
4036
|
+
status: 'error',
|
|
4037
|
+
errorMessage: error?.message || '未知错误',
|
|
4038
|
+
apiResponse: error?.response?.data,
|
|
4039
|
+
});
|
|
4040
|
+
return appendRefId(errorMessage, refId);
|
|
3806
4041
|
}
|
|
3807
4042
|
});
|
|
3808
4043
|
// 查询落雪B50任务状态功能已暂时取消
|
|
@@ -4628,16 +4863,168 @@ function apply(ctx, config) {
|
|
|
4628
4863
|
resultMessage = `ℹ️ 没有需要更新的用户\n所有用户都未开启锁定模式和保护模式`
|
|
4629
4864
|
}
|
|
4630
4865
|
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
})
|
|
4866
|
+
const refId = await logOperation({
|
|
4867
|
+
command: 'mai管理员一键关闭',
|
|
4868
|
+
session,
|
|
4869
|
+
status: 'success',
|
|
4870
|
+
result: resultMessage,
|
|
4871
|
+
})
|
|
4872
|
+
|
|
4873
|
+
return appendRefId(resultMessage, refId)
|
|
4874
|
+
} catch (error: any) {
|
|
4875
|
+
logger.error('管理员一键关闭操作失败:', error)
|
|
4876
|
+
const errorMessage = maintenanceMode
|
|
4877
|
+
? maintenanceMessage
|
|
4878
|
+
: `❌ 操作失败: ${error?.message || '未知错误'}\n\n${maintenanceMessage}`
|
|
4879
|
+
|
|
4880
|
+
const refId = await logOperation({
|
|
4881
|
+
command: 'mai管理员一键关闭',
|
|
4882
|
+
session,
|
|
4883
|
+
status: 'error',
|
|
4884
|
+
errorMessage: error?.message || '未知错误',
|
|
4885
|
+
})
|
|
4886
|
+
|
|
4887
|
+
return appendRefId(errorMessage, refId)
|
|
4888
|
+
}
|
|
4889
|
+
})
|
|
4640
4890
|
|
|
4891
|
+
/**
|
|
4892
|
+
* 管理员查询操作记录(通过 ref_id)
|
|
4893
|
+
* 用法: /mai管理员查询操作 <ref_id>
|
|
4894
|
+
*/
|
|
4895
|
+
ctx.command('mai管理员查询操作 <refId:text>', '通过 Ref_ID 查询操作详细信息(需要auth等级3以上)')
|
|
4896
|
+
.userFields(['authority'])
|
|
4897
|
+
.action(async ({ session }, refId) => {
|
|
4898
|
+
if (!session) {
|
|
4899
|
+
return '❌ 无法获取会话信息';
|
|
4900
|
+
}
|
|
4901
|
+
if ((session.user?.authority ?? 0) < 3) {
|
|
4902
|
+
return '❌ 权限不足,需要auth等级3以上才能执行此操作';
|
|
4903
|
+
}
|
|
4904
|
+
try {
|
|
4905
|
+
const logs = await ctx.database.get('maibot_operation_logs', { refId: refId.trim() });
|
|
4906
|
+
if (logs.length === 0) {
|
|
4907
|
+
return `❌ 未找到 Ref_ID 为 "${refId}" 的操作记录`;
|
|
4908
|
+
}
|
|
4909
|
+
const log = logs[0];
|
|
4910
|
+
const statusText = {
|
|
4911
|
+
success: '✅ 成功',
|
|
4912
|
+
failure: '❌ 失败',
|
|
4913
|
+
error: '⚠️ 错误',
|
|
4914
|
+
}[log.status] || log.status;
|
|
4915
|
+
let result = `📋 操作记录详情\n\n`;
|
|
4916
|
+
result += `Ref_ID: ${log.refId}\n`;
|
|
4917
|
+
result += `命令: ${log.command}\n`;
|
|
4918
|
+
result += `操作人: ${log.userId}\n`;
|
|
4919
|
+
if (log.targetUserId) {
|
|
4920
|
+
result += `目标用户: ${log.targetUserId}\n`;
|
|
4921
|
+
}
|
|
4922
|
+
result += `状态: ${statusText}\n`;
|
|
4923
|
+
result += `操作时间: ${new Date(log.createdAt).toLocaleString('zh-CN')}\n`;
|
|
4924
|
+
if (log.guildId) {
|
|
4925
|
+
result += `群组ID: ${log.guildId}\n`;
|
|
4926
|
+
}
|
|
4927
|
+
if (log.channelId) {
|
|
4928
|
+
result += `频道ID: ${log.channelId}\n`;
|
|
4929
|
+
}
|
|
4930
|
+
if (log.result) {
|
|
4931
|
+
result += `\n操作结果:\n${log.result}\n`;
|
|
4932
|
+
}
|
|
4933
|
+
if (log.errorMessage) {
|
|
4934
|
+
result += `\n错误信息:\n${log.errorMessage}\n`;
|
|
4935
|
+
}
|
|
4936
|
+
if (log.apiResponse) {
|
|
4937
|
+
try {
|
|
4938
|
+
const apiResp = JSON.parse(log.apiResponse);
|
|
4939
|
+
result += `\nAPI响应:\n${JSON.stringify(apiResp, null, 2)}\n`;
|
|
4940
|
+
}
|
|
4941
|
+
catch {
|
|
4942
|
+
result += `\nAPI响应:\n${log.apiResponse}\n`;
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
return result;
|
|
4946
|
+
}
|
|
4947
|
+
catch (error) {
|
|
4948
|
+
logger.error('查询操作记录失败:', error);
|
|
4949
|
+
return `❌ 查询失败: ${error?.message || '未知错误'}`;
|
|
4950
|
+
}
|
|
4951
|
+
});
|
|
4952
|
+
/**
|
|
4953
|
+
* 管理员查看今日命令统计
|
|
4954
|
+
* 用法: /mai管理员统计
|
|
4955
|
+
*/
|
|
4956
|
+
ctx.command('mai管理员统计', '查看今日各指令执行次数统计(需要auth等级3以上)')
|
|
4957
|
+
.userFields(['authority'])
|
|
4958
|
+
.action(async ({ session }) => {
|
|
4959
|
+
if (!session) {
|
|
4960
|
+
return '❌ 无法获取会话信息';
|
|
4961
|
+
}
|
|
4962
|
+
if ((session.user?.authority ?? 0) < 3) {
|
|
4963
|
+
return '❌ 权限不足,需要auth等级3以上才能执行此操作';
|
|
4964
|
+
}
|
|
4965
|
+
try {
|
|
4966
|
+
const today = new Date();
|
|
4967
|
+
today.setHours(0, 0, 0, 0);
|
|
4968
|
+
const todayStart = today.getTime();
|
|
4969
|
+
// 获取今日所有操作记录
|
|
4970
|
+
const allLogs = await ctx.database.get('maibot_operation_logs', {});
|
|
4971
|
+
const todayLogs = allLogs.filter(log => new Date(log.createdAt).getTime() >= todayStart);
|
|
4972
|
+
// 统计各命令执行次数
|
|
4973
|
+
// 将任务完成/失败等子命令合并到主命令中
|
|
4974
|
+
const commandStats = {};
|
|
4975
|
+
// 命令名称映射:将子命令合并到主命令
|
|
4976
|
+
const commandMapping = {
|
|
4977
|
+
'mai上传B50-任务完成': 'mai上传B50',
|
|
4978
|
+
'mai上传B50-任务超时': 'mai上传B50',
|
|
4979
|
+
'mai上传B50-轮询异常': 'mai上传B50',
|
|
4980
|
+
'mai上传落雪b50-任务完成': 'mai上传落雪b50',
|
|
4981
|
+
'mai上传落雪b50-任务超时': 'mai上传落雪b50',
|
|
4982
|
+
'mai上传落雪b50-轮询异常': 'mai上传落雪b50',
|
|
4983
|
+
'maiua-水鱼B50': 'maiua',
|
|
4984
|
+
'maiua-落雪B50': 'maiua',
|
|
4985
|
+
};
|
|
4986
|
+
for (const log of todayLogs) {
|
|
4987
|
+
// 使用映射后的命令名称,如果没有映射则使用原命令名称
|
|
4988
|
+
const commandName = commandMapping[log.command] || log.command;
|
|
4989
|
+
if (!commandStats[commandName]) {
|
|
4990
|
+
commandStats[commandName] = { total: 0, success: 0, failure: 0, error: 0 };
|
|
4991
|
+
}
|
|
4992
|
+
commandStats[commandName].total++;
|
|
4993
|
+
if (log.status === 'success') {
|
|
4994
|
+
commandStats[commandName].success++;
|
|
4995
|
+
}
|
|
4996
|
+
else if (log.status === 'failure') {
|
|
4997
|
+
commandStats[commandName].failure++;
|
|
4998
|
+
}
|
|
4999
|
+
else if (log.status === 'error') {
|
|
5000
|
+
commandStats[commandName].error++;
|
|
5001
|
+
}
|
|
5002
|
+
}
|
|
5003
|
+
// 按执行次数排序
|
|
5004
|
+
const sortedCommands = Object.entries(commandStats).sort((a, b) => b[1].total - a[1].total);
|
|
5005
|
+
let result = `📊 今日命令执行统计\n\n`;
|
|
5006
|
+
result += `统计时间: ${new Date().toLocaleString('zh-CN')}\n`;
|
|
5007
|
+
result += `总操作数: ${todayLogs.length}\n\n`;
|
|
5008
|
+
if (sortedCommands.length === 0) {
|
|
5009
|
+
result += `ℹ️ 今日暂无操作记录`;
|
|
5010
|
+
}
|
|
5011
|
+
else {
|
|
5012
|
+
result += `各命令执行情况:\n`;
|
|
5013
|
+
for (const [command, stats] of sortedCommands) {
|
|
5014
|
+
result += `\n${command}:\n`;
|
|
5015
|
+
result += ` 总次数: ${stats.total}\n`;
|
|
5016
|
+
result += ` 成功: ${stats.success}\n`;
|
|
5017
|
+
result += ` 失败: ${stats.failure}\n`;
|
|
5018
|
+
result += ` 错误: ${stats.error}\n`;
|
|
5019
|
+
}
|
|
5020
|
+
}
|
|
5021
|
+
return result;
|
|
5022
|
+
}
|
|
5023
|
+
catch (error) {
|
|
5024
|
+
logger.error('查询统计失败:', error);
|
|
5025
|
+
return `❌ 查询失败: ${error?.message || '未知错误'}`;
|
|
5026
|
+
}
|
|
5027
|
+
});
|
|
4641
5028
|
/**
|
|
4642
5029
|
* 管理员关闭/开启登录播报功能(全局开关)
|
|
4643
5030
|
* 用法: /mai管理员关闭登录播报 [on|off]
|