Discord机器人慢模式命令拆分:子命令调用问题求助
Discord.js v14 Slowmode子命令调用问题
我正在为个人Discord Bot开发Slowmode命令,想拆分为set(设置)和clear(清除)两个子命令,这是第一次实现子命令,遇到了困难。主要问题是不知道如何调用子命令的选项。
补充说明:
- 使用reconlx的DJS Base Handler,已修改部分代码适配Discord.js(DJS)v14
- 参考过reconlx的Slash Commands指南,但帮助不大
以下是我的源代码:
const { Command } = require("reconlx"); const { EmbedBuilder, ApplicationCommandOptionType, ApplicationCommandType, PermissionsBitField } = require("discord.js"); const ms = require("ms"); module.exports = new Command({ name: "slowmode2", description: "Sets a custom channel slowmode, version 2", userPermissions: PermissionsBitField.Flags.ManageGuild, type: ApplicationCommandType.ChatInput, options: [ { name: "set", description: "Set a channel rate limit", type: ApplicationCommandOptionType.Subcommand, options: [ { name: "rate-limit", description: "Duration of channel slowmode [s|m|h]", type: ApplicationCommandOptionType.String, required: true }, { name: "channel", description: "Channel to rate-limit", type: ApplicationCommandOptionType.Channel, required: false }, ] }, { name: "clear", description: "Clears the rate limit for a specific channel", type: ApplicationCommandOptionType.Subcommand, options: [ { name: "channel", description: "the channel to set the welcome message to.", type: ApplicationCommandOptionType.Channel, required: false }, ] }, ], run: async ({ interaction }) => { const [ subcommand ] = args; if (interaction.options.getSubcommand() === 'set') { const rateLimit = interaction.options.getString('rate-limit'); const rateLimitChannel = interaction.options.getChannel('channel'); } const timeInMs = ms(rateLimit); if (interaction.options.getSubcommand() === 'clear') { const clearChannel = interaction.options.getChannel("channel") } const slowmodeSuccess = new EmbedBuilder() .setColor("#2F3136") .setTitle(`🚅 SLOWING DOWN...`) .addFields( { name: "Slowmode has been enabled for everyone in this channel!", value: `To clear your slowmode, use \`/slowmode clear\``, inline: false }, { name: "Rate Limit", value: `${rateLimit}`, inline: true }, { name: "Channel", value: `${rateLimitChannel}`, inline: true } ) const slowmodeClear = new EmbedBuilder() .setColor("#2F3136") .setTitle(`🏃🏻♂️ SLOWMODE CLEARED!`) .addFields( { name: "Slowmode has been cleared for everyone in this channel!", value: `Everyone may now talk freely at a normal pace!`, inline: false }, { name: "Channel", value: `${clearChannel}`, inline: true } ) const invalidFormat = new EmbedBuilder() .setColor("#2F3136") .setTitle(`❌ ERROR`) .addFields( { name: "Invalid Format!", value: `Please provide your duration in [s|m|h] format!`, inline: true }, ) const error = new EmbedBuilder() .setColor("#2F3136") .setTitle(`❌ ERROR`) .addFields( { name: "Unknown Error: Oops!", value: `Something seems to have gone wrong!`, inline: true }, ) if (subcommand === "set") { if (!timeInMs || timeInMs === false) { interaction.followUp({ embeds: [invalidFormat] }) } else { interaction.channel.setRateLimitPerUser(timeInMs/1000).then( () => { interaction.followUp({ embeds: [slowmodeSuccess] }) }).catch( () => { interaction.followUp({ embeds: [error] }) }) } } if (subcommand === "clear") { interaction.channel.setRateLimitPerUser(false) interaction.followUp({ embeds: [slowmodeClear] }) } } });
问题分析与修复方案
原代码存在几个核心问题:
- 子命令获取错误:
const [ subcommand ] = args;中args未定义,Discord.js v14中需通过interaction.options.getSubcommand()获取子命令名称 - 变量作用域问题:
rateLimit、rateLimitChannel等变量定义在if块内部,外部无法访问,导致Embed和逻辑代码报错 - 频道处理逻辑缺失:未处理用户未指定频道的情况,应默认使用当前交互频道
- 慢模式清除错误:
setRateLimitPerUser(false)无效,需传入0来清除慢模式 - 交互超时风险:未先调用
interaction.deferReply(),长时间处理可能导致交互超时
修正后的完整代码
const { Command } = require("reconlx"); const { EmbedBuilder, ApplicationCommandOptionType, ApplicationCommandType, PermissionsBitField } = require("discord.js"); const ms = require("ms"); module.exports = new Command({ name: "slowmode2", description: "Sets a custom channel slowmode, version 2", userPermissions: PermissionsBitField.Flags.ManageGuild, type: ApplicationCommandType.ChatInput, options: [ { name: "set", description: "Set a channel rate limit", type: ApplicationCommandOptionType.Subcommand, options: [ { name: "rate-limit", description: "Duration of channel slowmode [s|m|h]", type: ApplicationCommandOptionType.String, required: true }, { name: "channel", description: "Channel to rate-limit", type: ApplicationCommandOptionType.Channel, required: false }, ] }, { name: "clear", description: "Clears the rate limit for a specific channel", type: ApplicationCommandOptionType.Subcommand, options: [ { name: "channel", description: "Channel to clear slowmode from", type: ApplicationCommandOptionType.Channel, required: false }, ] }, ], run: async ({ interaction }) => { // 先回复交互避免超时 await interaction.deferReply({ ephemeral: false }); const subcommand = interaction.options.getSubcommand(); if (subcommand === 'set') { const rateLimit = interaction.options.getString('rate-limit'); const targetChannel = interaction.options.getChannel('channel') || interaction.channel; const timeInMs = ms(rateLimit); if (!timeInMs) { const invalidFormat = new EmbedBuilder() .setColor("#2F3136") .setTitle(`❌ ERROR`) .addFields({ name: "Invalid Format!", value: `Please provide your duration in [s|m|h] format!`, inline: true }); return interaction.editReply({ embeds: [invalidFormat] }); } try { await targetChannel.setRateLimitPerUser(timeInMs / 1000); const successEmbed = new EmbedBuilder() .setColor("#2F3136") .setTitle(`🚅 SLOWING DOWN...`) .addFields( { name: "Slowmode enabled!", value: `To clear slowmode, use \`/slowmode2 clear\``, inline: false }, { name: "Rate Limit", value: `${rateLimit}`, inline: true }, { name: "Channel", value: targetChannel.toString(), inline: true } ); await interaction.editReply({ embeds: [successEmbed] }); } catch (err) { const errorEmbed = new EmbedBuilder() .setColor("#2F3136") .setTitle(`❌ ERROR`) .addFields({ name: "Unknown Error", value: `Failed to set slowmode: ${err.message}`, inline: true }); await interaction.editReply({ embeds: [errorEmbed] }); } } else if (subcommand === 'clear') { const targetChannel = interaction.options.getChannel('channel') || interaction.channel; try { await targetChannel.setRateLimitPerUser(0); const clearEmbed = new EmbedBuilder() .setColor("#2F3136") .setTitle(`🏃🏻♂️ SLOWMODE CLEARED!`) .addFields( { name: "Slowmode cleared!", value: `Everyone can now talk freely!`, inline: false }, { name: "Channel", value: targetChannel.toString(), inline: true } ); await interaction.editReply({ embeds: [clearEmbed] }); } catch (err) { const errorEmbed = new EmbedBuilder() .setColor("#2F3136") .setTitle(`❌ ERROR`) .addFields({ name: "Unknown Error", value: `Failed to clear slowmode: ${err.message}`, inline: true }); await interaction.editReply({ embeds: [errorEmbed] }); } } } });
关键修复点说明
- 子命令获取:使用
const subcommand = interaction.options.getSubcommand()正确获取当前触发的子命令 - 变量作用域:将子命令相关逻辑封装在对应的if块内,避免变量访问问题
- 频道默认值:通过
targetChannel = ... || interaction.channel处理用户未指定频道的情况 - 慢模式清除:使用
setRateLimitPerUser(0)替代false,符合Discord.js API要求 - 交互超时处理:先调用
interaction.deferReply(),后续用editReply回复,避免超时 - 错误处理:添加try-catch捕获API调用异常,并在Embed中显示具体错误信息
内容的提问来源于stack exchange,提问作者user19705674
相关产品推荐
相关产品推荐

