Bladeren bron

refactor(参数处理): 重构参数类型处理逻辑,统一使用Receive类型

重构了参数类型处理逻辑,将原有的ParamType枚举替换为Receive类型,以增强代码的一致性和可维护性。同时更新了相关插件的参数装饰器和解析逻辑,确保参数类型检查更加严格和准确。
枫林 3 maanden geleden
bovenliggende
commit
55a8b880a1

+ 4 - 12
src/interface/plugin.ts

@@ -1,3 +1,5 @@
+import { Receive } from "node-napcat-ts";
+
 // 更新 Plugin 接口
 export interface Plugin {
     id: string;
@@ -44,21 +46,11 @@ export interface Command {
 // 参数元数据接口
 export interface ParamMetadata {
     name: string; // 参数名称
-    type: ParamType; // 参数类型
+    type: "text" | "image" | "reply" | "poke" | "at" | "file" | "dice" | "rps" | "face" | "video" | "record" | "forward" | "json" | "markdown"; // 参数类型
     index: number; // 参数索引
-    defaultValue?: any; // 默认值
+    defaultValue?: Receive[keyof Receive]; // 默认值
     optional: boolean; // 是否可选
 }
-// 参数类型枚举
-export const ParamType = {
-    String: "string" as const,
-    Number: "number" as const,
-    Boolean: "boolean" as const,
-    Rest: "rest" as const
-} as const;
-// 从对象值中获取类型
-export type ParamType = typeof ParamType[keyof typeof ParamType];
-
 // 添加模板配置接口
 export interface TemplateConfig {
     enabled: boolean;

+ 44 - 26
src/lib/Plugins.ts

@@ -14,7 +14,7 @@ import * as fs from 'fs'
 import * as path from 'path'
 // 获取指令前缀
 import { Botconfig as config, economy, load, PermissionConfig, saveConfig } from './config.js'
-import { ImageSegment, ReplySegment, TextSegment } from "node-napcat-ts/dist/Structs.js";
+import { ImageSegment, Receive, ReplySegment, TextSegment } from "node-napcat-ts/dist/Structs.js";
 import { fileURLToPath } from 'node:url';
 import { qqBot } from "../app.js";
 import { IsPermission } from "./Permission.js";
@@ -596,17 +596,49 @@ export async function cost( context: PrivateFriendMessage | PrivateGroupMessage
 // 修改参数解析函数
 async function parseCommandParams(message: string, context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage, command: Command,easycmd:boolean): Promise<any[]> {
     const cmdArgs = message.split(/\s+/).filter(Boolean);
-
     // 移除命令前缀和命令名
     const parts = message.split(/\s+/);
     let cmdIndex = 2;
     if (easycmd) {
         cmdIndex = 1;
     }
-    const paramArgs = parts.slice(cmdIndex); 
+    const paramArgs: Receive[keyof Receive][] = [];
+    parts.slice(cmdIndex).forEach((part) => {
+        if (part !== '') {
+            const Args: Receive["text"] ={
+                type: 'text',
+                data: {
+                    text: part
+                }
+            }
+            paramArgs.push(Args)
+        }
+    }); 
+    // 插入其他类别的消息
+    for(let i = 0;i<context.message.length;i++){
+        if(i !== 0){
+            const msg= context.message[i]
+            if (msg.type === 'text') {
+                const parts = msg.data.text.split(/\s+/);
+                parts.forEach((part) => {
+                    if (part!== '') {
+                        const Args: Receive["text"] ={
+                            type: 'text',
+                            data: {
+                                text: part
+                            }
+                        }
+                        paramArgs.push(Args)
+                    }
+                });
+            }else{
+                paramArgs.push(context.message[i])
+            }
+            
+        }
+    }
 
-    // 调试日志
-    botlogger.info('DEBUG - 命令参数:' + JSON.stringify({ paramArgs }));
+    botlogger.info('DEBUG - 命令参数:' + JSON.stringify(paramArgs));
 
     const params: any[] = [];
     const param = paramMetadata.get(command.pluginId + "." + command.fnName);
@@ -627,28 +659,14 @@ async function parseCommandParams(message: string, context: PrivateFriendMessage
             if (!optional && !paramArgs[index]) {
                 throw new Error(`参数 <${name}> 是必需的,${msg}`);
             }
-            switch (type) {
-                case "string":
-                    params[index] = paramArgs[index] || '';
-                    break;
-                case "number":
-                    params[index] = Number(paramArgs[index]) || 0;
-                    if (isNaN(params[index])) {
-                        throw new Error(`参数 ${name} 必须是数字,${msg}`);
-                    }
-                    break;
-                case "boolean":
-                    params[index] = paramArgs[index] === 'true';
-                    if (optional && paramArgs[index] === undefined) {
-                        params[index] = false;
-                    }
-                    break;
-                case "rest":
-                    params[index] = paramArgs.slice(index);
-                    break;
-                default:
-                    throw new Error(`未知参数类型: ${type},${msg}`);
+            // 检查参数类型
+            let msgtype = paramArgs[index].type
+            if (type === msgtype) {
+                params[index] = paramArgs[index];
+            }else{
+                throw new Error(`参数 <${name}> 类型错误,${msg}`);
             }
+
             if (optional && paramArgs[index] === undefined) {
                 params[index] = paramData.defaultValue;
             }

+ 3 - 2
src/lib/decorators.ts

@@ -4,9 +4,10 @@ import botlogger from './logger.js';
 import { Botconfig as config } from './config.js'
 const CMD_PREFIX = config?.cmd?.prefix ?? '#';
 import { fileURLToPath } from 'node:url';
-import { Command, CommandConfig, ParamMetadata, ParamType, PluginConfig } from '../interface/plugin.js';
+import { Command, CommandConfig, ParamMetadata, PluginConfig } from '../interface/plugin.js';
 import { Plugin } from '../interface/plugin.js';
 import { EconomyCommands } from '../interface/economy.js';
+import { Receive } from 'node-napcat-ts/dist/Structs.js';
 
 
 
@@ -20,7 +21,7 @@ export const commandList: Plugin[] = [];
 
 // 修改参数装饰器
 //默认值
-export function param(name: string, type: ParamType = ParamType.String, defaultValue?:any, optional: boolean = false): ParameterDecorator {
+export function param(name: string, type: "text" | "image" | "reply" | "poke" | "at" | "file" | "dice" | "rps" | "face" | "video" | "record" | "forward" | "json" | "markdown", defaultValue?:Receive[keyof Receive], optional: boolean = false): ParameterDecorator {
 
     return function (target: any, propertyKey: string | symbol | undefined, parameterIndex: number): void {
         const actualPropertyKey = propertyKey!;

+ 4 - 5
src/plugins/PluginsFile.ts

@@ -2,12 +2,11 @@ import { param, plugins, runcod } from '../lib/decorators.js';
 import path from 'path';
 import 'reflect-metadata';
 import { fileURLToPath } from 'node:url';
-import { GroupMessage, PrivateFriendMessage, PrivateGroupMessage } from 'node-napcat-ts';
+import { GroupMessage, PrivateFriendMessage, PrivateGroupMessage, Receive } from 'node-napcat-ts';
 import botlogger from '../lib/logger.js';
 import * as fs from 'fs'
 import { qqBot } from '../app.js';
-import { ParamType } from '../interface/plugin.js';
-import { load, PermissionConfig, saveConfig } from '../lib/config.js';
+import { load, saveConfig } from '../lib/config.js';
 import { download } from '../lib/download.js';
 import { IsAdmin } from '../lib/Permission.js';
 
@@ -108,7 +107,7 @@ export class PluginsFile {
     }
     @runcod(["download", "下载插件"], "下载插件")
     async download(
-        @param("插件名称", ParamType.String) pluName: string,
+        @param("插件名称", 'text') pluName: Receive["text"],
         context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
     ): Promise<any> {
         const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -125,7 +124,7 @@ export class PluginsFile {
 
             // 根据文件名查找具体插件
             const targetFile = foundFiles.find((file: string) =>
-                path.parse(file).name.toLowerCase() === pluName.toLowerCase()
+                path.parse(file).name.toLowerCase() === pluName.data.text.toLowerCase()
             );
 
             if (!targetFile) {

+ 11 - 11
src/plugins/ecomony.ts

@@ -3,8 +3,8 @@ import { param, plugins, runcod } from "../lib/decorators.js";
 import { GroupMessage, PrivateFriendMessage, PrivateGroupMessage } from "node-napcat-ts/dist/Interfaces.js";
 import path from "path";
 import { fileURLToPath } from "url";
-import { ParamType } from "../interface/plugin.js";
 import { IsAdmin } from "../lib/Permission.js";
+import { Receive } from "node-napcat-ts";
 
 @plugins({
     name: "经济系统", //插件名称,用于显示在菜单中
@@ -56,9 +56,9 @@ export class ecomony {
 
     @runcod(["add", "增加"], "增加金币")
     async addecomony(
-        @param("QQ号", ParamType.Number,) userid: string,
-        @param("数量", ParamType.Number) amount: number,
-        @param("原因", ParamType.String,'管理员增加',true) reason: string,
+        @param("QQ号", 'at',) userid: Receive["at"],
+        @param("数量", 'text') amount: Receive["text"],
+        @param("原因", 'text',{type:'text',data:{text:"管理员增加"}},true) reason: Receive["text"],
         context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
     ) {
         const __dirname = path.dirname(fileURLToPath(import.meta.url)); //获取当前文件的目录名
@@ -82,8 +82,8 @@ export class ecomony {
                     }
                 }
             }
-            addCoins(context.sender.user_id.toString(),amount,reason)
-            const newcoins = (await getUserData(userid)).economy.coins
+            addCoins(context.sender.user_id.toString(),Number(amount.data.text),reason.data.text)
+            const newcoins = (await getUserData(userid.data.qq)).economy.coins
             return {
                 msgtype: 'success',
                 ecomsg: `增加成功! 金币 +${amount}, 当前数量: ${newcoins}`,
@@ -139,9 +139,9 @@ export class ecomony {
 
     @runcod(["reduce", "减少"], "减少金币")
     async reduceecomony(
-        @param("QQ号", ParamType.Number,) userid: string,
-        @param("数量", ParamType.Number) amount: number,
-        @param("原因", ParamType.String,'管理员减少',true) reason: string,
+        @param("QQ号", 'at',) userid: Receive["at"],
+        @param("数量", 'text') amount: Receive["text"],
+        @param("原因", 'text',{type:'text',data:{text:"管理员增加"}},true) reason: Receive["text"],
         context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
     ){
         const __dirname = path.dirname(fileURLToPath(import.meta.url)); //获取当前文件的目录名
@@ -165,8 +165,8 @@ export class ecomony {
                     }
                 }
             }
-            removeCoins(context.sender.user_id.toString(),-amount,reason)
-            const newcoins = (await getUserData(userid)).economy.coins
+            removeCoins(context.sender.user_id.toString(),-amount,reason.data.text)
+            const newcoins = (await getUserData(userid.data.qq)).economy.coins
             return {
                 msgtype:'success',
                 ecomsg: `减少成功! 金币 -${amount}, 当前数量: ${newcoins}`,

+ 7 - 8
src/plugins/log.ts

@@ -2,11 +2,10 @@ import { param, plugins, runcod } from '../lib/decorators.js';
 import path from 'path';
 import 'reflect-metadata';
 import { fileURLToPath } from 'node:url';
-import { GroupMessage, PrivateFriendMessage, PrivateGroupMessage } from 'node-napcat-ts';
+import { GroupMessage, PrivateFriendMessage, PrivateGroupMessage, Receive } from 'node-napcat-ts';
 import botlogger from '../lib/logger.js';
 import fs from 'fs/promises';
 import { qqBot } from '../app.js';
-import { ParamType } from '../interface/plugin.js';
 @plugins({
     name: "log日志管理", //插件名称,用于显示在菜单中
     version: "1.0.0", //插件版本号,用于显示在菜单中
@@ -34,15 +33,15 @@ export class Botlog {
                 foundFiles[index] = path.parse(file).name;
             })
             return `找到插件文件:${foundFiles.join(', ')}`;
-        } catch (error) {
-            botlogger.error('文件查找失败:', error);
+        } catch (error:any) {
+            botlogger.error('文件查找失败:' + error.message);
             return '插件查找服务暂不可用';
         }
     }
 
     @runcod(["downloadlog", "getlog"], "下载日志")
     async getBotlogbyfile(
-        @param("日志名称", ParamType.String) logName: string,
+        @param("日志名称", 'text') logName: Receive["text"],
         context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
     ): Promise<any> {
         // pluName += ".ts"
@@ -57,7 +56,7 @@ export class Botlog {
 
             // 根据文件名查找具体插件
             const targetFile = foundFiles.find((file: string) =>
-                path.parse(file).name.toLowerCase() === logName.toLowerCase()
+                path.parse(file).name.toLowerCase() === logName.data.text.toLowerCase()
             );
 
             if (!targetFile) {
@@ -86,8 +85,8 @@ export class Botlog {
             }
 
             return '上传成功';
-        } catch (error) {
-            botlogger.error('文件查找失败:', error);
+        } catch (error:any) {
+            botlogger.error('文件查找失败:' + error.message);
             return '插件查找服务暂不可用';
         }
     }

+ 20 - 19
src/plugins/prop.ts

@@ -1,5 +1,4 @@
 import botlogger from "../lib/logger.js";
-import { ParamType } from "../interface/plugin.js";
 import { param, plugins, runcod } from "../lib/decorators.js";
 import { addProp, getuserProp, Props, reduceProp } from "../lib/prop.js";
 import { GroupMessage, PrivateFriendMessage, PrivateGroupMessage } from "node-napcat-ts";
@@ -7,6 +6,7 @@ import { removeCoins } from "../lib/economy.js";
 import path from "path";
 import { fileURLToPath } from "url";
 import { Prop } from "../interface/prop.js";
+import { Receive } from 'node-napcat-ts/dist/Structs.js';
 
 @plugins({
     easycmd: true,//是否启用简易命令,启用将将命令注册为<命令名称>,不启用将注册为#<插件名称> <命令名称>
@@ -22,41 +22,42 @@ import { Prop } from "../interface/prop.js";
 export class Propplu {
     @runcod(["use", "使用道具"],"使用道具" )
     async useprop(
-        @param("道具Id", ParamType.String) propId: string,
-        @param("QQ", ParamType.Number) userId: string,
-        @param("数量", ParamType.Number, 1, true) Num: number,
-        @param("道具参数",ParamType.String,"",true) propparam:string,
+        @param("道具Id","text") propId: Receive["text"],
+        @param("QQ", "at") userId: Receive["at"],
+        @param("数量", "text", {type:'text',data:{text:"1"}}, true) Num: Receive["text"],
+        @param("道具参数","text",{type:'text',data:{text:""}},true) propparam:Receive["text"],
         context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
     ): Promise<any> {
         const userProp = await getuserProp(context?.sender?.user_id.toString()??"0") || [];
-        let findprop = userProp.find((prop) => prop.propId == propId);
+        let findprop = userProp.find((prop) => prop.propId == propId?.data?.text);
         if (!findprop) {
             return this.tl(`你没有${propId}道具`,'error',`你没有${propId}道具`)
         }
-        if (findprop.Num < Num) {
+        
+        if (findprop.Num < Number(Num?.data?.text)) {
             return this.tl(`道具数量不足`,'error',`道具数量不足`)
         }
         Props.forEach((prop) => {
-            if (prop.propId === propId) {
-                if(prop.maxuse<Num){
+            if (prop.propId === propId?.data?.text) {
+                if(prop.maxuse<Number(Num?.data?.text)){
                     return this.tl(`该道具允许最大使用数量为${prop.maxuse}超过最大使用数量`,'error',`该道具允许最大使用数量为${prop.maxuse}超过最大使用数量`)
                 }
             }    
         });
         try {
-            for (let i = 0; i < Num; i++) {
+            for (let i = 0; i < Number(Num?.data?.text); i++) {
                 let fn;
                 let classConstructor;
                 let propid=''
                 Props.forEach((prop) => {
-                    if (prop.propId==propId) {
+                    if (prop.propId==propId?.data?.text) {
                         fn = prop.fn;
                         classConstructor = prop.classConstructor
                         propid= prop.propId
                     }
                 })
                 if (await reduceProp(context?.sender?.user_id.toString()??"0", propid, 1)){
-                    const result = (fn as any).call(classConstructor, userId, propparam,context);
+                    const result = (fn as any).call(classConstructor, userId.data.qq, propparam,context);
                     if (result) {
                         return result;
                     }
@@ -138,19 +139,19 @@ export class Propplu {
     }
     @runcod(["buy","买"],"购买道具")
     async buyprop(
-        @param("道具Id", ParamType.String) propId: string,
-        @param("数量", ParamType.Number, 1, true) Num: number,
+        @param("道具Id", 'text') propId:  Receive["text"],
+        @param("数量", 'text', {type:'text',data:{text:"1"}}, true) Num:  Receive["text"],
         context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
     ){
-        if(Num<=0){
+        if(Number(Num?.data?.text)<=0){
             return this.tl('道具数量不能小于0','error','道具数量不能小于0')
         }
         let res = ''
         Props.forEach(async (prop) => {
-            if(prop.propId===propId){
-                removeCoins(context?.sender?.user_id?.toString(),prop?.price??0 * Num,`购买道具${prop?.propName??'未知'}`)
-                addProp(context?.sender?.user_id?.toString(),prop?.propId,Num)
-                res = `购买${prop.propName}成功!消费${prop.price * Num}!`
+            if(prop.propId===propId?.data?.text){
+                removeCoins(context?.sender?.user_id?.toString(),prop?.price??0 * Number(Num?.data?.text),`购买道具${prop?.propName??'未知'}`)
+                addProp(context?.sender?.user_id?.toString(),prop?.propId,Number(Num?.data?.text))
+                res = `购买${prop.propName}成功!消费${prop.price * Number(Num?.data?.text)}!`
             }
         })
         return this.tl(res,'success',res)

+ 8 - 6
src/plugins/test.ts

@@ -7,10 +7,10 @@ import 'reflect-metadata';
 import { fileURLToPath } from 'node:url';
 import { qqBot } from '../app.js';
 import botlogger from '../lib/logger.js';
-import { ParamType } from '../interface/plugin.js';
 import { prop } from '../lib/prop.js';
 import * as fs from 'fs'
 import { GroupMessage, PrivateFriendMessage, PrivateGroupMessage } from 'node-napcat-ts/dist/Interfaces.js';
+import { Receive } from 'node-napcat-ts';
 async function convertImageToBase64(filePath: string): Promise<string> {
     try {
       const fileData = await fs.promises.readFile(filePath);
@@ -53,8 +53,9 @@ export class test {
         "参数实例" //命令描述,用于显示在默认菜单中
     )//命令装饰器,用于注册命令
     async param(
-        @param("参数1", ParamType.String) param1: string,//参数装饰器,用于解析参数
-        @param("参数2", ParamType.Number,999,true) param2: number,//参数装饰器,用于解析参数
+        @param("参数1", 'text') param1: Receive["text"],//参数装饰器,用于解析参数
+        @param("参数2", 'text',{type: 'text',data: {text: '未输入数字'}},true) param2: Receive["text"],//参数装饰器,用于解析参数
+        @param("参数3", 'at') param3: Receive["at"],//参数装饰器,用于解析参数
     ): Promise<any> {
         if (!param1 || !param2) {
             return "请输入正确的参数格式: #test param <字符串> <数字>";//返回错误信息,用于显示在菜单中
@@ -64,6 +65,7 @@ export class test {
         return {
             param1,//参数1,用于显示在菜单中
             param2,//参数2,用于显示在菜单中
+            param3,//参数3,用于显示在菜单中
             template: { // 模板配置,用于发送图片内容
                 enabled: true,//是否启用模板,启用将发送图片内容
                 sendText: false,//是否发送文本,启用将发送文本内容,如果都启用则发送两条消息
@@ -105,15 +107,15 @@ export class test {
     )
     async test(
         userId:string,
-        propparam:string,
+        propparam: Receive["text"],
         context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage
     ): Promise<any>{
-        debugger
+        debugger;
         if (context?.message_type === 'group') {
             await qqBot.set_group_special_title({
                 group_id:Number(context.group_id),
                 user_id:Number(userId),
-                special_title:propparam
+                special_title:propparam.data.text,
             })
         }
         return `操作成功!`

+ 5 - 0
src/resources/test/param.html

@@ -1,5 +1,10 @@
 <span>
     模版生图演示
+    <br>
     参数1(字符串): {{param1}}
+    <br>
     参数2(数字): {{param2}}
+    <br>
+    参数3(at): {{param3}}
+    <br>
 </span>