koishi-plugin-maibot 1.7.36 → 1.7.38
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/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +278 -54
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAW,MAAM,QAAQ,CAAA;AAIjD,eAAO,MAAM,IAAI,WAAW,CAAA;AAC5B,eAAO,MAAM,MAAM,UAAe,CAAA;AAElC,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,WAAW,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE;QAClB,OAAO,EAAE,OAAO,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,aAAa,CAAC,EAAE;QACd,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;KACtB,CAAA;IACD,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;QAClB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,YAAY,CAAC,EAAE;QACb,OAAO,EAAE,OAAO,CAAA;QAChB,UAAU,EAAE,MAAM,CAAA;KACnB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAW,MAAM,QAAQ,CAAA;AAIjD,eAAO,MAAM,IAAI,WAAW,CAAA;AAC5B,eAAO,MAAM,MAAM,UAAe,CAAA;AAElC,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,WAAW,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE;QAClB,OAAO,EAAE,OAAO,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,aAAa,CAAC,EAAE;QACd,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;KACtB,CAAA;IACD,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;QAClB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,YAAY,CAAC,EAAE;QACb,OAAO,EAAE,OAAO,CAAA;QAChB,UAAU,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CAsEhC,CAAA;AAymCF,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QA+qJjD"}
|
package/lib/index.js
CHANGED
|
@@ -75,6 +75,8 @@ exports.Config = koishi_1.Schema.object({
|
|
|
75
75
|
enabled: true,
|
|
76
76
|
refIdLabel: 'Ref_ID',
|
|
77
77
|
}),
|
|
78
|
+
errorHelpUrl: koishi_1.Schema.string().default('https://awmc.cc/forums/8/').description('任务出错时引导用户提问的URL(留空则不显示引导信息)'),
|
|
79
|
+
b50PollInterval: koishi_1.Schema.number().default(2000).description('B50任务轮询间隔(毫秒),默认2000毫秒'),
|
|
78
80
|
});
|
|
79
81
|
// 我认识了很多朋友 以下是我认识的好朋友们!
|
|
80
82
|
// Fracture_Hikaritsu
|
|
@@ -556,11 +558,13 @@ class RequestQueue {
|
|
|
556
558
|
function processSGID(input) {
|
|
557
559
|
const trimmed = input.trim();
|
|
558
560
|
// 检查是否为公众号网页地址格式(https://wq.wahlap.net/qrcode/req/)
|
|
559
|
-
const
|
|
561
|
+
const isReqLink = trimmed.includes('https://wq.wahlap.net/qrcode/req/');
|
|
562
|
+
// 检查是否为二维码图片链接格式(https://wq.wahlap.net/qrcode/img/)
|
|
563
|
+
const isImgLink = trimmed.includes('https://wq.wahlap.net/qrcode/img/');
|
|
560
564
|
const isSGID = trimmed.startsWith('SGWCMAID');
|
|
561
565
|
let qrText = trimmed;
|
|
562
566
|
// 如果是网页地址,提取MAID并转换为SGWCMAID格式
|
|
563
|
-
if (
|
|
567
|
+
if (isReqLink) {
|
|
564
568
|
try {
|
|
565
569
|
// 从URL中提取MAID部分:https://wq.wahlap.net/qrcode/req/MAID2601...55.html?...
|
|
566
570
|
// 匹配 /qrcode/req/ 后面的 MAID 开头的内容(到 .html 或 ? 之前)
|
|
@@ -578,6 +582,24 @@ function processSGID(input) {
|
|
|
578
582
|
return null;
|
|
579
583
|
}
|
|
580
584
|
}
|
|
585
|
+
else if (isImgLink) {
|
|
586
|
+
try {
|
|
587
|
+
// 从图片URL中提取MAID部分:https://wq.wahlap.net/qrcode/img/MAID260128205107...png?v
|
|
588
|
+
// 匹配 /qrcode/img/ 后面的 MAID 开头的内容(到 .png 或 ? 之前)
|
|
589
|
+
const match = trimmed.match(/qrcode\/img\/(MAID[^?\.]+)/i);
|
|
590
|
+
if (match && match[1]) {
|
|
591
|
+
const maid = match[1];
|
|
592
|
+
// 在前面加上 SGWC 变成 SGWCMAID...
|
|
593
|
+
qrText = 'SGWC' + maid;
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
catch (error) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
581
603
|
else if (!isSGID) {
|
|
582
604
|
return null;
|
|
583
605
|
}
|
|
@@ -722,10 +744,13 @@ async function getQrText(session, ctx, api, binding, config, timeout = 60000, pr
|
|
|
722
744
|
logger.debug(`收到用户输入: ${trimmed.substring(0, 50)}`);
|
|
723
745
|
let qrText = trimmed;
|
|
724
746
|
// 检查是否为公众号网页地址格式(https://wq.wahlap.net/qrcode/req/)
|
|
725
|
-
const
|
|
747
|
+
const isReqLink = trimmed.includes('https://wq.wahlap.net/qrcode/req/');
|
|
748
|
+
// 检查是否为二维码图片链接格式(https://wq.wahlap.net/qrcode/img/)
|
|
749
|
+
const isImgLink = trimmed.includes('https://wq.wahlap.net/qrcode/img/');
|
|
750
|
+
const isLink = isReqLink || isImgLink;
|
|
726
751
|
const isSGID = trimmed.startsWith('SGWCMAID');
|
|
727
752
|
// 如果是网页地址,提取MAID并转换为SGWCMAID格式
|
|
728
|
-
if (
|
|
753
|
+
if (isReqLink) {
|
|
729
754
|
try {
|
|
730
755
|
// 从URL中提取MAID部分:https://wq.wahlap.net/qrcode/req/MAID2601...55.html?...
|
|
731
756
|
// 匹配 /qrcode/req/ 后面的 MAID 开头的内容(到 .html 或 ? 之前)
|
|
@@ -737,19 +762,41 @@ async function getQrText(session, ctx, api, binding, config, timeout = 60000, pr
|
|
|
737
762
|
logger.info(`从网页地址提取MAID并转换: ${maid.substring(0, 20)}... -> ${qrText.substring(0, 24)}...`);
|
|
738
763
|
}
|
|
739
764
|
else {
|
|
740
|
-
await session.send('⚠️ 无法从网页地址中提取MAID,请发送SGID文本(SGWCMAID
|
|
765
|
+
await session.send('⚠️ 无法从网页地址中提取MAID,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
741
766
|
return { qrText: '', error: '无法从网页地址中提取MAID' };
|
|
742
767
|
}
|
|
743
768
|
}
|
|
744
769
|
catch (error) {
|
|
745
770
|
logger.warn('解析网页地址失败:', error);
|
|
746
|
-
await session.send('⚠️ 网页地址格式错误,请发送SGID文本(SGWCMAID
|
|
771
|
+
await session.send('⚠️ 网页地址格式错误,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
747
772
|
return { qrText: '', error: '网页地址格式错误' };
|
|
748
773
|
}
|
|
749
774
|
}
|
|
775
|
+
else if (isImgLink) {
|
|
776
|
+
try {
|
|
777
|
+
// 从图片URL中提取MAID部分:https://wq.wahlap.net/qrcode/img/MAID260128205107...png?v
|
|
778
|
+
// 匹配 /qrcode/img/ 后面的 MAID 开头的内容(到 .png 或 ? 之前)
|
|
779
|
+
const match = trimmed.match(/qrcode\/img\/(MAID[^?\.]+)/i);
|
|
780
|
+
if (match && match[1]) {
|
|
781
|
+
const maid = match[1];
|
|
782
|
+
// 在前面加上 SGWC 变成 SGWCMAID...
|
|
783
|
+
qrText = 'SGWC' + maid;
|
|
784
|
+
logger.info(`从图片地址提取MAID并转换: ${maid.substring(0, 20)}... -> ${qrText.substring(0, 24)}...`);
|
|
785
|
+
}
|
|
786
|
+
else {
|
|
787
|
+
await session.send('⚠️ 无法从图片地址中提取MAID,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
788
|
+
return { qrText: '', error: '无法从图片地址中提取MAID' };
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
catch (error) {
|
|
792
|
+
logger.warn('解析图片地址失败:', error);
|
|
793
|
+
await session.send('⚠️ 图片地址格式错误,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
794
|
+
return { qrText: '', error: '图片地址格式错误' };
|
|
795
|
+
}
|
|
796
|
+
}
|
|
750
797
|
else if (!isSGID) {
|
|
751
|
-
await session.send('⚠️ 未识别到有效的SGID格式或网页地址,请发送SGID文本(SGWCMAID
|
|
752
|
-
return { qrText: '', error: '无效的二维码格式,必须是SGID
|
|
798
|
+
await session.send('⚠️ 未识别到有效的SGID格式或网页地址,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
799
|
+
return { qrText: '', error: '无效的二维码格式,必须是SGID文本或网页/图片地址' };
|
|
753
800
|
}
|
|
754
801
|
// 验证SGID格式和长度
|
|
755
802
|
if (!qrText.startsWith('SGWCMAID')) {
|
|
@@ -760,7 +807,7 @@ async function getQrText(session, ctx, api, binding, config, timeout = 60000, pr
|
|
|
760
807
|
await session.send('❌ SGID长度错误,应在48-128字符之间');
|
|
761
808
|
return { qrText: '', error: '二维码长度错误,应在48-128字符之间' };
|
|
762
809
|
}
|
|
763
|
-
logger.info(`✅ 接收到${isLink ? '
|
|
810
|
+
logger.info(`✅ 接收到${isLink ? '链接地址(已转换)' : 'SGID'}: ${qrText.substring(0, 50)}...`);
|
|
764
811
|
// 尝试撤回用户发送的消息(如果启用了自动撤回)
|
|
765
812
|
await tryRecallMessage(session, ctx, config);
|
|
766
813
|
await session.send('⏳ 正在处理,请稍候...');
|
|
@@ -855,10 +902,13 @@ async function promptForRebind(session, ctx, api, binding, config, timeout = 600
|
|
|
855
902
|
logger.debug(`收到用户输入: ${trimmed.substring(0, 50)}`);
|
|
856
903
|
let qrCode = trimmed;
|
|
857
904
|
// 检查是否为公众号网页地址格式(https://wq.wahlap.net/qrcode/req/)
|
|
858
|
-
const
|
|
905
|
+
const isReqLink = trimmed.includes('https://wq.wahlap.net/qrcode/req/');
|
|
906
|
+
// 检查是否为二维码图片链接格式(https://wq.wahlap.net/qrcode/img/)
|
|
907
|
+
const isImgLink = trimmed.includes('https://wq.wahlap.net/qrcode/img/');
|
|
908
|
+
const isLink = isReqLink || isImgLink;
|
|
859
909
|
const isSGID = trimmed.startsWith('SGWCMAID');
|
|
860
910
|
// 如果是网页地址,提取MAID并转换为SGWCMAID格式
|
|
861
|
-
if (
|
|
911
|
+
if (isReqLink) {
|
|
862
912
|
try {
|
|
863
913
|
// 从URL中提取MAID部分:https://wq.wahlap.net/qrcode/req/MAID2601...55.html?...
|
|
864
914
|
// 匹配 /qrcode/req/ 后面的 MAID 开头的内容(到 .html 或 ? 之前)
|
|
@@ -870,19 +920,41 @@ async function promptForRebind(session, ctx, api, binding, config, timeout = 600
|
|
|
870
920
|
logger.info(`从网页地址提取MAID并转换: ${maid.substring(0, 20)}... -> ${qrCode.substring(0, 24)}...`);
|
|
871
921
|
}
|
|
872
922
|
else {
|
|
873
|
-
await session.send('⚠️ 无法从网页地址中提取MAID,请发送SGID文本(SGWCMAID
|
|
923
|
+
await session.send('⚠️ 无法从网页地址中提取MAID,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
874
924
|
return { success: false, error: '无法从网页地址中提取MAID', messageId: promptMessageId };
|
|
875
925
|
}
|
|
876
926
|
}
|
|
877
927
|
catch (error) {
|
|
878
928
|
logger.warn('解析网页地址失败:', error);
|
|
879
|
-
await session.send('⚠️ 网页地址格式错误,请发送SGID文本(SGWCMAID
|
|
929
|
+
await session.send('⚠️ 网页地址格式错误,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
880
930
|
return { success: false, error: '网页地址格式错误', messageId: promptMessageId };
|
|
881
931
|
}
|
|
882
932
|
}
|
|
933
|
+
else if (isImgLink) {
|
|
934
|
+
try {
|
|
935
|
+
// 从图片URL中提取MAID部分:https://wq.wahlap.net/qrcode/img/MAID260128205107...png?v
|
|
936
|
+
// 匹配 /qrcode/img/ 后面的 MAID 开头的内容(到 .png 或 ? 之前)
|
|
937
|
+
const match = trimmed.match(/qrcode\/img\/(MAID[^?\.]+)/i);
|
|
938
|
+
if (match && match[1]) {
|
|
939
|
+
const maid = match[1];
|
|
940
|
+
// 在前面加上 SGWC 变成 SGWCMAID...
|
|
941
|
+
qrCode = 'SGWC' + maid;
|
|
942
|
+
logger.info(`从图片地址提取MAID并转换: ${maid.substring(0, 20)}... -> ${qrCode.substring(0, 24)}...`);
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
await session.send('⚠️ 无法从图片地址中提取MAID,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
946
|
+
return { success: false, error: '无法从图片地址中提取MAID', messageId: promptMessageId };
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
catch (error) {
|
|
950
|
+
logger.warn('解析图片地址失败:', error);
|
|
951
|
+
await session.send('⚠️ 图片地址格式错误,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
952
|
+
return { success: false, error: '图片地址格式错误', messageId: promptMessageId };
|
|
953
|
+
}
|
|
954
|
+
}
|
|
883
955
|
else if (!isSGID) {
|
|
884
|
-
await session.send('⚠️ 未识别到有效的SGID格式或网页地址,请发送SGID文本(SGWCMAID
|
|
885
|
-
return { success: false, error: '无效的二维码格式,必须是SGID
|
|
956
|
+
await session.send('⚠️ 未识别到有效的SGID格式或网页地址,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
957
|
+
return { success: false, error: '无效的二维码格式,必须是SGID文本或网页/图片地址', messageId: promptMessageId };
|
|
886
958
|
}
|
|
887
959
|
// 验证SGID格式和长度
|
|
888
960
|
if (!qrCode.startsWith('SGWCMAID')) {
|
|
@@ -893,7 +965,7 @@ async function promptForRebind(session, ctx, api, binding, config, timeout = 600
|
|
|
893
965
|
await session.send('❌ 识别失败:SGID长度错误,应在48-128字符之间');
|
|
894
966
|
return { success: false, error: '二维码长度错误,应在48-128字符之间', messageId: promptMessageId };
|
|
895
967
|
}
|
|
896
|
-
logger.info(`✅ 接收到${isLink ? '
|
|
968
|
+
logger.info(`✅ 接收到${isLink ? '链接地址(已转换)' : 'SGID'}: ${qrCode.substring(0, 50)}...`);
|
|
897
969
|
// 发送识别中反馈
|
|
898
970
|
await session.send('⏳ 正在处理,请稍候...');
|
|
899
971
|
// 使用新API获取用户信息
|
|
@@ -970,6 +1042,104 @@ function apply(ctx, config) {
|
|
|
970
1042
|
const requestQueue = queueConfig.enabled ? new RequestQueue(queueConfig.interval) : null;
|
|
971
1043
|
// 操作记录配置
|
|
972
1044
|
const operationLogConfig = config.operationLog || { enabled: true, refIdLabel: 'Ref_ID' };
|
|
1045
|
+
// 错误帮助URL配置
|
|
1046
|
+
const errorHelpUrl = config.errorHelpUrl || '';
|
|
1047
|
+
/**
|
|
1048
|
+
* 获取上传任务的统计信息(平均处理时长和今日成功率)
|
|
1049
|
+
* @param commandPrefix 命令前缀,用于筛选日志(如 'mai上传B50' 或 'mai上传落雪b50')
|
|
1050
|
+
* @returns 统计信息字符串
|
|
1051
|
+
*/
|
|
1052
|
+
async function getUploadStats(commandPrefix) {
|
|
1053
|
+
try {
|
|
1054
|
+
const today = new Date();
|
|
1055
|
+
today.setHours(0, 0, 0, 0);
|
|
1056
|
+
const todayStart = today.getTime();
|
|
1057
|
+
// 获取今日所有相关操作记录
|
|
1058
|
+
const allLogs = await ctx.database.get('maibot_operation_logs', {});
|
|
1059
|
+
const todayLogs = allLogs.filter(log => {
|
|
1060
|
+
const logTime = new Date(log.createdAt).getTime();
|
|
1061
|
+
return logTime >= todayStart && log.command.startsWith(commandPrefix);
|
|
1062
|
+
});
|
|
1063
|
+
if (todayLogs.length === 0) {
|
|
1064
|
+
return '';
|
|
1065
|
+
}
|
|
1066
|
+
// 统计成功率
|
|
1067
|
+
const taskCompleteLogs = todayLogs.filter(log => log.command.includes('-任务完成'));
|
|
1068
|
+
const successCount = taskCompleteLogs.filter(log => log.status === 'success').length;
|
|
1069
|
+
const failureCount = taskCompleteLogs.filter(log => log.status === 'failure').length;
|
|
1070
|
+
const totalCompleted = successCount + failureCount;
|
|
1071
|
+
// 计算平均处理时长(从任务提交到任务完成)
|
|
1072
|
+
let avgDuration = 0;
|
|
1073
|
+
let durationCount = 0;
|
|
1074
|
+
// 获取所有任务提交记录和对应的完成记录
|
|
1075
|
+
const submitLogs = todayLogs.filter(log => log.command === commandPrefix && log.status === 'success');
|
|
1076
|
+
for (const submitLog of submitLogs) {
|
|
1077
|
+
// 尝试从 apiResponse 中获取 task_id
|
|
1078
|
+
if (!submitLog.apiResponse)
|
|
1079
|
+
continue;
|
|
1080
|
+
try {
|
|
1081
|
+
const response = JSON.parse(submitLog.apiResponse);
|
|
1082
|
+
const taskId = response.task_id;
|
|
1083
|
+
if (!taskId)
|
|
1084
|
+
continue;
|
|
1085
|
+
// 查找对应的完成记录
|
|
1086
|
+
const completeLog = taskCompleteLogs.find(log => {
|
|
1087
|
+
if (!log.apiResponse)
|
|
1088
|
+
return false;
|
|
1089
|
+
try {
|
|
1090
|
+
const completeResponse = JSON.parse(log.apiResponse);
|
|
1091
|
+
return completeResponse.alive_task_id === taskId || String(completeResponse.alive_task_id) === String(taskId);
|
|
1092
|
+
}
|
|
1093
|
+
catch {
|
|
1094
|
+
return false;
|
|
1095
|
+
}
|
|
1096
|
+
});
|
|
1097
|
+
if (completeLog) {
|
|
1098
|
+
const submitTime = new Date(submitLog.createdAt).getTime();
|
|
1099
|
+
const completeTime = new Date(completeLog.createdAt).getTime();
|
|
1100
|
+
const duration = (completeTime - submitTime) / 1000; // 转换为秒
|
|
1101
|
+
if (duration > 0 && duration < 600) { // 排除异常数据(超过10分钟的)
|
|
1102
|
+
avgDuration += duration;
|
|
1103
|
+
durationCount++;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
catch {
|
|
1108
|
+
continue;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
// 计算平均时长
|
|
1112
|
+
if (durationCount > 0) {
|
|
1113
|
+
avgDuration = avgDuration / durationCount;
|
|
1114
|
+
}
|
|
1115
|
+
// 计算成功率
|
|
1116
|
+
const successRate = totalCompleted > 0 ? Math.round((successCount / totalCompleted) * 100) : 0;
|
|
1117
|
+
// 构建统计信息字符串
|
|
1118
|
+
let statsStr = '';
|
|
1119
|
+
if (avgDuration > 0) {
|
|
1120
|
+
statsStr += `平均处理用时 ${avgDuration.toFixed(1)} s`;
|
|
1121
|
+
}
|
|
1122
|
+
if (totalCompleted > 0) {
|
|
1123
|
+
if (statsStr)
|
|
1124
|
+
statsStr += ',';
|
|
1125
|
+
statsStr += `今日成功率 ${successRate}%`;
|
|
1126
|
+
}
|
|
1127
|
+
return statsStr;
|
|
1128
|
+
}
|
|
1129
|
+
catch (error) {
|
|
1130
|
+
logger.warn('获取上传统计信息失败:', error);
|
|
1131
|
+
return '';
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* 获取错误帮助信息(如果配置了帮助URL)
|
|
1136
|
+
*/
|
|
1137
|
+
function getErrorHelpInfo() {
|
|
1138
|
+
if (!errorHelpUrl) {
|
|
1139
|
+
return '';
|
|
1140
|
+
}
|
|
1141
|
+
return `\n\n如有问题,请前往 ${errorHelpUrl} 提问`;
|
|
1142
|
+
}
|
|
973
1143
|
/**
|
|
974
1144
|
* 生成唯一的 ref_id
|
|
975
1145
|
*/
|
|
@@ -1257,9 +1427,10 @@ function apply(ctx, config) {
|
|
|
1257
1427
|
}
|
|
1258
1428
|
const mention = buildMention(session);
|
|
1259
1429
|
const guildId = session.guildId;
|
|
1260
|
-
const
|
|
1261
|
-
const
|
|
1262
|
-
const
|
|
1430
|
+
const pollInterval = config.b50PollInterval || 2000;
|
|
1431
|
+
const maxAttempts = Math.ceil(600000 / pollInterval); // 10分钟超时
|
|
1432
|
+
const interval = pollInterval;
|
|
1433
|
+
const initialDelay = pollInterval; // 首次延迟与轮询间隔相同
|
|
1263
1434
|
let attempts = 0;
|
|
1264
1435
|
const poll = async () => {
|
|
1265
1436
|
attempts += 1;
|
|
@@ -1271,7 +1442,7 @@ function apply(ctx, config) {
|
|
|
1271
1442
|
if (isDone || hasError) {
|
|
1272
1443
|
// 任务完成或出错,发送通知并停止
|
|
1273
1444
|
const statusText = hasError
|
|
1274
|
-
? `❌ 任务失败:${detail.error}`
|
|
1445
|
+
? `❌ 任务失败:${detail.error}${getErrorHelpInfo()}`
|
|
1275
1446
|
: '✅ 任务已完成';
|
|
1276
1447
|
const finishTime = detail.alive_task_end_time
|
|
1277
1448
|
? `\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')}`
|
|
@@ -1301,7 +1472,7 @@ function apply(ctx, config) {
|
|
|
1301
1472
|
status: 'failure',
|
|
1302
1473
|
errorMessage: '任务轮询超时(10分钟)',
|
|
1303
1474
|
});
|
|
1304
|
-
let msg = `${mention} 水鱼B50任务 ${taskId}
|
|
1475
|
+
let msg = `${mention} 水鱼B50任务 ${taskId} 上传失败,请稍后再试一次。${getErrorHelpInfo()}`;
|
|
1305
1476
|
const maintenanceMsg = getMaintenanceMessage(maintenanceNotice);
|
|
1306
1477
|
if (maintenanceMsg) {
|
|
1307
1478
|
msg += `\n${maintenanceMsg}`;
|
|
@@ -1321,7 +1492,7 @@ function apply(ctx, config) {
|
|
|
1321
1492
|
status: 'error',
|
|
1322
1493
|
errorMessage: error instanceof Error ? error.message : '未知错误',
|
|
1323
1494
|
});
|
|
1324
|
-
let msg = `${mention} 水鱼B50任务 ${taskId}
|
|
1495
|
+
let msg = `${mention} 水鱼B50任务 ${taskId} 上传失败,请稍后再试一次。${getErrorHelpInfo()}`;
|
|
1325
1496
|
const maintenanceMsg = getMaintenanceMessage(maintenanceNotice);
|
|
1326
1497
|
if (maintenanceMsg) {
|
|
1327
1498
|
msg += `\n${maintenanceMsg}`;
|
|
@@ -1341,9 +1512,10 @@ function apply(ctx, config) {
|
|
|
1341
1512
|
}
|
|
1342
1513
|
const mention = buildMention(session);
|
|
1343
1514
|
const guildId = session.guildId;
|
|
1344
|
-
const
|
|
1345
|
-
const
|
|
1346
|
-
const
|
|
1515
|
+
const pollInterval = config.b50PollInterval || 2000;
|
|
1516
|
+
const maxAttempts = Math.ceil(600000 / pollInterval); // 10分钟超时
|
|
1517
|
+
const interval = pollInterval;
|
|
1518
|
+
const initialDelay = pollInterval; // 首次延迟与轮询间隔相同
|
|
1347
1519
|
let attempts = 0;
|
|
1348
1520
|
const poll = async () => {
|
|
1349
1521
|
attempts += 1;
|
|
@@ -1355,7 +1527,7 @@ function apply(ctx, config) {
|
|
|
1355
1527
|
if (isDone || hasError) {
|
|
1356
1528
|
// 任务完成或出错,发送通知并停止
|
|
1357
1529
|
const statusText = hasError
|
|
1358
|
-
? `❌ 任务失败:${detail.error}`
|
|
1530
|
+
? `❌ 任务失败:${detail.error}${getErrorHelpInfo()}`
|
|
1359
1531
|
: '✅ 任务已完成';
|
|
1360
1532
|
const finishTime = detail.alive_task_end_time
|
|
1361
1533
|
? `\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')}`
|
|
@@ -1385,7 +1557,7 @@ function apply(ctx, config) {
|
|
|
1385
1557
|
status: 'failure',
|
|
1386
1558
|
errorMessage: '任务轮询超时(10分钟)',
|
|
1387
1559
|
});
|
|
1388
|
-
let msg = `${mention} 落雪B50任务 ${taskId}
|
|
1560
|
+
let msg = `${mention} 落雪B50任务 ${taskId} 上传失败,请稍后再试一次。${getErrorHelpInfo()}`;
|
|
1389
1561
|
const maintenanceMsg = getMaintenanceMessage(maintenanceNotice);
|
|
1390
1562
|
if (maintenanceMsg) {
|
|
1391
1563
|
msg += `\n${maintenanceMsg}`;
|
|
@@ -1405,7 +1577,7 @@ function apply(ctx, config) {
|
|
|
1405
1577
|
status: 'error',
|
|
1406
1578
|
errorMessage: error instanceof Error ? error.message : '未知错误',
|
|
1407
1579
|
});
|
|
1408
|
-
let msg = `${mention} 落雪B50任务 ${taskId}
|
|
1580
|
+
let msg = `${mention} 落雪B50任务 ${taskId} 上传失败,请稍后再试一次。${getErrorHelpInfo()}`;
|
|
1409
1581
|
const maintenanceMsg = getMaintenanceMessage(maintenanceNotice);
|
|
1410
1582
|
if (maintenanceMsg) {
|
|
1411
1583
|
msg += `\n${maintenanceMsg}`;
|
|
@@ -1691,10 +1863,13 @@ function apply(ctx, config) {
|
|
|
1691
1863
|
logger.debug(`收到用户输入: ${trimmed.substring(0, 50)}`);
|
|
1692
1864
|
qrCode = trimmed;
|
|
1693
1865
|
// 检查是否为公众号网页地址格式(https://wq.wahlap.net/qrcode/req/)
|
|
1694
|
-
const
|
|
1866
|
+
const isReqLink = trimmed.includes('https://wq.wahlap.net/qrcode/req/');
|
|
1867
|
+
// 检查是否为二维码图片链接格式(https://wq.wahlap.net/qrcode/img/)
|
|
1868
|
+
const isImgLink = trimmed.includes('https://wq.wahlap.net/qrcode/img/');
|
|
1869
|
+
const isLink = isReqLink || isImgLink;
|
|
1695
1870
|
const isSGID = trimmed.startsWith('SGWCMAID');
|
|
1696
1871
|
// 如果是网页地址,提取MAID并转换为SGWCMAID格式
|
|
1697
|
-
if (
|
|
1872
|
+
if (isReqLink) {
|
|
1698
1873
|
try {
|
|
1699
1874
|
// 从URL中提取MAID部分:https://wq.wahlap.net/qrcode/req/MAID2601...55.html?...
|
|
1700
1875
|
// 匹配 /qrcode/req/ 后面的 MAID 开头的内容(到 .html 或 ? 之前)
|
|
@@ -1706,30 +1881,52 @@ function apply(ctx, config) {
|
|
|
1706
1881
|
logger.info(`从网页地址提取MAID并转换: ${maid.substring(0, 20)}... -> ${qrCode.substring(0, 24)}...`);
|
|
1707
1882
|
}
|
|
1708
1883
|
else {
|
|
1709
|
-
await session.send('⚠️ 无法从网页地址中提取MAID,请发送SGID文本(SGWCMAID
|
|
1884
|
+
await session.send('⚠️ 无法从网页地址中提取MAID,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
1710
1885
|
throw new Error('无法从网页地址中提取MAID');
|
|
1711
1886
|
}
|
|
1712
1887
|
}
|
|
1713
1888
|
catch (error) {
|
|
1714
1889
|
logger.warn('解析网页地址失败:', error);
|
|
1715
|
-
await session.send('⚠️ 网页地址格式错误,请发送SGID文本(SGWCMAID
|
|
1890
|
+
await session.send('⚠️ 网页地址格式错误,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
1716
1891
|
throw new Error('网页地址格式错误');
|
|
1717
1892
|
}
|
|
1718
1893
|
}
|
|
1894
|
+
else if (isImgLink) {
|
|
1895
|
+
try {
|
|
1896
|
+
// 从图片URL中提取MAID部分:https://wq.wahlap.net/qrcode/img/MAID260128205107...png?v
|
|
1897
|
+
// 匹配 /qrcode/img/ 后面的 MAID 开头的内容(到 .png 或 ? 之前)
|
|
1898
|
+
const match = trimmed.match(/qrcode\/img\/(MAID[^?\.]+)/i);
|
|
1899
|
+
if (match && match[1]) {
|
|
1900
|
+
const maid = match[1];
|
|
1901
|
+
// 在前面加上 SGWC 变成 SGWCMAID...
|
|
1902
|
+
qrCode = 'SGWC' + maid;
|
|
1903
|
+
logger.info(`从图片地址提取MAID并转换: ${maid.substring(0, 20)}... -> ${qrCode.substring(0, 24)}...`);
|
|
1904
|
+
}
|
|
1905
|
+
else {
|
|
1906
|
+
await session.send('⚠️ 无法从图片地址中提取MAID,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
1907
|
+
throw new Error('无法从图片地址中提取MAID');
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
catch (error) {
|
|
1911
|
+
logger.warn('解析图片地址失败:', error);
|
|
1912
|
+
await session.send('⚠️ 图片地址格式错误,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
1913
|
+
throw new Error('图片地址格式错误');
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1719
1916
|
else if (!isSGID) {
|
|
1720
|
-
await session.send('⚠️ 未识别到有效的SGID格式或网页地址,请发送SGID文本(SGWCMAID
|
|
1721
|
-
throw new Error('无效的二维码格式,必须是SGID
|
|
1917
|
+
await session.send('⚠️ 未识别到有效的SGID格式或网页地址,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
1918
|
+
throw new Error('无效的二维码格式,必须是SGID文本或网页/图片地址');
|
|
1722
1919
|
}
|
|
1723
1920
|
// 验证SGID格式和长度
|
|
1724
1921
|
if (!qrCode.startsWith('SGWCMAID')) {
|
|
1725
|
-
await session.send('⚠️ 未识别到有效的SGID格式,请发送SGID文本(SGWCMAID
|
|
1922
|
+
await session.send('⚠️ 未识别到有效的SGID格式,请发送SGID文本(SGWCMAID开头)或公众号提供的网页/图片地址');
|
|
1726
1923
|
throw new Error('无效的二维码格式,必须以 SGWCMAID 开头');
|
|
1727
1924
|
}
|
|
1728
1925
|
if (qrCode.length < 48 || qrCode.length > 128) {
|
|
1729
1926
|
await session.send('❌ SGID长度错误,应在48-128字符之间');
|
|
1730
1927
|
throw new Error('二维码长度错误,应在48-128字符之间');
|
|
1731
1928
|
}
|
|
1732
|
-
logger.info(`✅ 接收到${isLink ? '
|
|
1929
|
+
logger.info(`✅ 接收到${isLink ? '链接地址(已转换)' : 'SGID'}: ${qrCode.substring(0, 50)}...`);
|
|
1733
1930
|
// 发送识别中反馈
|
|
1734
1931
|
await session.send('⏳ 正在处理,请稍候...');
|
|
1735
1932
|
}
|
|
@@ -2856,9 +3053,11 @@ function apply(ctx, config) {
|
|
|
2856
3053
|
return '⚠️ 当前账号已有未完成的水鱼B50任务,请稍后再试,无需重复上传。';
|
|
2857
3054
|
}
|
|
2858
3055
|
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
2859
|
-
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
3056
|
+
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}${getErrorHelpInfo()}`;
|
|
2860
3057
|
}
|
|
2861
|
-
const
|
|
3058
|
+
const statsInfo = await getUploadStats('mai上传B50');
|
|
3059
|
+
const statsStr = statsInfo ? `\n${statsInfo}` : '';
|
|
3060
|
+
const successMessage = `✅ B50上传任务已提交!${statsStr}\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
|
|
2862
3061
|
const refId = await logOperation({
|
|
2863
3062
|
command: 'mai上传B50',
|
|
2864
3063
|
session,
|
|
@@ -2941,13 +3140,15 @@ function apply(ctx, config) {
|
|
|
2941
3140
|
return `✅ 重新绑定成功!请重新执行上传操作。`;
|
|
2942
3141
|
}
|
|
2943
3142
|
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
2944
|
-
return `❌ 上传失败:${result.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}`;
|
|
3143
|
+
return `❌ 上传失败:${result.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}${getErrorHelpInfo()}`;
|
|
2945
3144
|
}
|
|
2946
3145
|
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
2947
|
-
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
3146
|
+
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}${getErrorHelpInfo()}`;
|
|
2948
3147
|
}
|
|
2949
3148
|
}
|
|
2950
|
-
const
|
|
3149
|
+
const statsInfo = await getUploadStats('mai上传B50');
|
|
3150
|
+
const statsStr = statsInfo ? `\n${statsInfo}` : '';
|
|
3151
|
+
const successMessage = `✅ B50上传任务已提交!${statsStr}\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
|
|
2951
3152
|
const refId = await logOperation({
|
|
2952
3153
|
command: 'mai上传B50',
|
|
2953
3154
|
session,
|
|
@@ -2971,7 +3172,7 @@ function apply(ctx, config) {
|
|
|
2971
3172
|
if (maintenanceMsg) {
|
|
2972
3173
|
msg += `\n${maintenanceMsg}`;
|
|
2973
3174
|
}
|
|
2974
|
-
msg += `\n\n${maintenanceMessage}`;
|
|
3175
|
+
msg += `\n\n${maintenanceMessage}${getErrorHelpInfo()}`;
|
|
2975
3176
|
return msg;
|
|
2976
3177
|
}
|
|
2977
3178
|
if (error?.response) {
|
|
@@ -3911,9 +4112,11 @@ function apply(ctx, config) {
|
|
|
3911
4112
|
return '⚠️ 当前账号已有未完成的落雪B50任务,请稍后再试,无需重复上传。';
|
|
3912
4113
|
}
|
|
3913
4114
|
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
3914
|
-
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
4115
|
+
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}${getErrorHelpInfo()}`;
|
|
3915
4116
|
}
|
|
3916
|
-
const
|
|
4117
|
+
const statsInfo = await getUploadStats('mai上传落雪b50');
|
|
4118
|
+
const statsStr = statsInfo ? `\n${statsInfo}` : '';
|
|
4119
|
+
const successMessage = `✅ 落雪B50上传任务已提交!${statsStr}\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
|
|
3917
4120
|
const refId = await logOperation({
|
|
3918
4121
|
command: 'mai上传落雪b50',
|
|
3919
4122
|
session,
|
|
@@ -3925,7 +4128,7 @@ function apply(ctx, config) {
|
|
|
3925
4128
|
scheduleLxB50Notification(session, result.task_id, refId);
|
|
3926
4129
|
return appendRefId(successMessage, refId);
|
|
3927
4130
|
}
|
|
3928
|
-
return `❌ 获取二维码失败:${qrTextResult.error}`;
|
|
4131
|
+
return `❌ 获取二维码失败:${qrTextResult.error}${getErrorHelpInfo()}`;
|
|
3929
4132
|
}
|
|
3930
4133
|
// 在调用API前加入队列
|
|
3931
4134
|
await waitForQueue(session);
|
|
@@ -3996,13 +4199,15 @@ function apply(ctx, config) {
|
|
|
3996
4199
|
return `✅ 重新绑定成功!请重新执行上传操作。`;
|
|
3997
4200
|
}
|
|
3998
4201
|
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
3999
|
-
return `❌ 上传失败:${result.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}`;
|
|
4202
|
+
return `❌ 上传失败:${result.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}${getErrorHelpInfo()}`;
|
|
4000
4203
|
}
|
|
4001
4204
|
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
4002
|
-
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
4205
|
+
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}${getErrorHelpInfo()}`;
|
|
4003
4206
|
}
|
|
4004
4207
|
}
|
|
4005
|
-
const
|
|
4208
|
+
const statsInfo = await getUploadStats('mai上传落雪b50');
|
|
4209
|
+
const statsStr = statsInfo ? `\n${statsInfo}` : '';
|
|
4210
|
+
const successMessage = `✅ 落雪B50上传任务已提交!${statsStr}\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
|
|
4006
4211
|
const refId = await logOperation({
|
|
4007
4212
|
command: 'mai上传落雪b50',
|
|
4008
4213
|
session,
|
|
@@ -4025,12 +4230,12 @@ function apply(ctx, config) {
|
|
|
4025
4230
|
if (maintenanceMsg) {
|
|
4026
4231
|
msg += `\n${maintenanceMsg}`;
|
|
4027
4232
|
}
|
|
4028
|
-
msg += `\n\n${maintenanceMessage}`;
|
|
4233
|
+
msg += `\n\n${maintenanceMessage}${getErrorHelpInfo()}`;
|
|
4029
4234
|
return msg;
|
|
4030
4235
|
})()
|
|
4031
4236
|
: (error?.response
|
|
4032
|
-
? `❌ API请求失败: ${error.response.status} ${error.response.statusText}\n\n${maintenanceMessage}`
|
|
4033
|
-
: `❌ 上传失败: ${error?.message || '未知错误'}\n\n${maintenanceMessage}`));
|
|
4237
|
+
? `❌ API请求失败: ${error.response.status} ${error.response.statusText}\n\n${maintenanceMessage}${getErrorHelpInfo()}`
|
|
4238
|
+
: `❌ 上传失败: ${error?.message || '未知错误'}\n\n${maintenanceMessage}${getErrorHelpInfo()}`));
|
|
4034
4239
|
const refId = await logOperation({
|
|
4035
4240
|
command: 'mai上传落雪b50',
|
|
4036
4241
|
session,
|
|
@@ -4998,14 +5203,33 @@ function apply(ctx, config) {
|
|
|
4998
5203
|
}
|
|
4999
5204
|
// 按执行次数排序
|
|
5000
5205
|
const sortedCommands = Object.entries(commandStats).sort((a, b) => b[1].total - a[1].total);
|
|
5206
|
+
// 获取B50平均处理时长统计
|
|
5207
|
+
const pollInterval = config.b50PollInterval || 2000;
|
|
5208
|
+
const fishStats = await getUploadStats('mai上传B50');
|
|
5209
|
+
const lxStats = await getUploadStats('mai上传落雪b50');
|
|
5001
5210
|
let result = `📊 今日命令执行统计\n\n`;
|
|
5002
5211
|
result += `统计时间: ${new Date().toLocaleString('zh-CN')}\n`;
|
|
5003
|
-
result += `总操作数: ${todayLogs.length}\n
|
|
5212
|
+
result += `总操作数: ${todayLogs.length}\n`;
|
|
5213
|
+
result += `轮询间隔: ${pollInterval} ms\n\n`;
|
|
5214
|
+
// B50处理时长统计
|
|
5215
|
+
result += `📈 B50处理统计:\n`;
|
|
5216
|
+
if (fishStats) {
|
|
5217
|
+
result += ` 🐟 水鱼: ${fishStats}\n`;
|
|
5218
|
+
}
|
|
5219
|
+
else {
|
|
5220
|
+
result += ` 🐟 水鱼: 暂无今日数据\n`;
|
|
5221
|
+
}
|
|
5222
|
+
if (lxStats) {
|
|
5223
|
+
result += ` ❄️ 落雪: ${lxStats}\n`;
|
|
5224
|
+
}
|
|
5225
|
+
else {
|
|
5226
|
+
result += ` ❄️ 落雪: 暂无今日数据\n`;
|
|
5227
|
+
}
|
|
5004
5228
|
if (sortedCommands.length === 0) {
|
|
5005
|
-
result +=
|
|
5229
|
+
result += `\nℹ️ 今日暂无操作记录`;
|
|
5006
5230
|
}
|
|
5007
5231
|
else {
|
|
5008
|
-
result +=
|
|
5232
|
+
result += `\n各命令执行情况:\n`;
|
|
5009
5233
|
for (const [command, stats] of sortedCommands) {
|
|
5010
5234
|
result += `\n${command}:\n`;
|
|
5011
5235
|
result += ` 总次数: ${stats.total}\n`;
|