在帮助嵌入中显示子命令。 Discord.js v14

问题描述 投票:0回答:1

无论我尝试什么,我都无法显示子命令。它只是显示这个

有趣的命令 /fun:有趣的命令!

今天13:07

示例 fun.js

我尝试在互联网上搜索,询问 chapgtp 等等。尝试查看文档但仍然一无所获。

我尝试更新这两个文件以使其正常工作,没有任何错误,只是 help.js 无法调用甚至无法查看子命令。

这是我每次得到的输出 https://prnt.sc/weeO16P8DIDE

const { SlashCommandBuilder } = require('@discordjs/builders');
const { EmbedBuilder } = require('discord.js');
const axios = require('axios');
const he = require('he'); // Importing the 'he' library for HTML decoding

module.exports = {
    data: new SlashCommandBuilder()
        .setName('fun')
        .setDescription('Fun commands to play with!')
        .addSubcommand(subcommands =>
            subcommands
                .setName('8ball')
                .setDescription('Ask the magic 8-ball a question.')
                .addStringOption(option => option.setName('question').setDescription('Your yes/no question').setRequired(true)))
        .addSubcommand(subcommands =>
            subcommands
                .setName('av')
                .setDescription('Displays the avatar of the specified user.')
                .addUserOption(option =>
                    option.setName('user')
                        .setDescription('The user whose avatar to display')
                        .setRequired(false)))
        .addSubcommand(subcommand =>
            subcommand
                .setName('coinflip')
                .setDescription('Flip a coin and get heads or tails.'))
        .addSubcommand(subcommand =>
            subcommand
                .setName('fact')
                .setDescription('Provides a random interesting fact using an API.'))
        .addSubcommand(subcommand =>
            subcommand
                .setName('joke')
                .setDescription('Fetch a random joke.'))
        .addSubcommand(subcommand =>
            subcommand
                .setName('meme')
                .setDescription('Fetch a random meme from Reddit.'))
        .addSubcommand(subcommand =>
            subcommand
                .setName('roll')
                .setDescription('Rolls a six-sided die.'))
        .addSubcommand(subcommand =>
            subcommand
                .setName('trivia')
                .setDescription('Start a trivia game.')),
    category: 'fun',
    async execute(interaction) {
        const subcommand = interaction.options.getSubcommand();

        switch (subcommand) {
            case '8ball':
                const answers = ['Yes', 'No', 'Maybe', 'Definitely', 'Ask again later'];
                const randomAnswer = answers[Math.floor(Math.random() * answers.length)];
                await interaction.reply(randomAnswer);
                break;

            case 'av':
                await interaction.deferReply();
                const user = interaction.options.getUser('user') || interaction.user;
                const avatarEmbed = new EmbedBuilder()
                    .setTitle(`${user.username}'s avatar`)
                    .setColor(0x333333)
                    .setImage(user.displayAvatarURL({ dynamic: true, size: 2048 }));
                await interaction.followUp({ embeds: [avatarEmbed] });
                break;

            case 'coinflip':
                const result = Math.random() < 0.5 ? 'Heads' : 'Tails';
                await interaction.reply(`The coin landed on: ${result}`);
                break;

            case 'fact':
                await interaction.deferReply();
                try {
                    const factResponse = await axios.get('https://uselessfacts.jsph.pl/random.json');
                    const fact = factResponse.data.text;
                    const factEmbed = new EmbedBuilder()
                        .setTitle('🔍 Random Fact')
                        .setColor(0x333333)
                        .setDescription(fact);
                    await interaction.followUp({ embeds: [factEmbed] });
                } catch (error) {
                    console.error(error);
                    await interaction.followUp({ content: 'Sorry, I couldn\'t fetch a fact at the moment.' });
                }
                break;

            case 'joke':
                try {
                    const jokeResponse = await axios.get('https://official-joke-api.appspot.com/random_joke');
                    await interaction.reply(`${jokeResponse.data.setup} - ${jokeResponse.data.punchline}`);
                } catch (error) {
                    await interaction.reply('Error fetching joke.');
                }
                break;

            case 'meme':
                try {
                    const memeResponse = await axios.get('https://meme-api.com/gimme'); // Replace with actual meme API
                    await interaction.reply({ content: memeResponse.data.url });
                } catch (error) {
                    await interaction.reply('Error fetching meme.');
                }
                break;

            case 'roll':
                await interaction.deferReply();
                const roll = Math.floor(Math.random() * 6) + 1;
                const rollEmbed = new EmbedBuilder()
                    .setTitle('🎲 You rolled!')
                    .setColor(0x333333)
                    .setDescription(`You rolled a **${roll}**.`);
                await interaction.followUp({ embeds: [rollEmbed] });
                break;

            case 'trivia':
                try {
                    const triviaResponse = await axios.get('https://opentdb.com/api.php?amount=1&type=multiple');
                    const question = he.decode(triviaResponse.data.results[0].question);
                    const correctAnswer = he.decode(triviaResponse.data.results[0].correct_answer);
                    const incorrectAnswers = triviaResponse.data.results[0].incorrect_answers.map(he.decode);
                    const answers = [correctAnswer, ...incorrectAnswers].sort(() => Math.random() - 0.5);
                    const answersString = answers.map((answer, index) => `${index + 1}. ${answer}`).join('\n');
                    await interaction.reply(`Trivia: ${question}\n\nOptions:\n${answersString}`);

                    const filter = response => {
                        return !isNaN(response.content) && response.author.id === interaction.user.id && response.content > 0 && response.content <= answers.length;
                    };

                    const collector = interaction.channel.createMessageCollector({ filter, time: 15000 });

                    collector.on('collect', m => {
                        const answerIndex = parseInt(m.content) - 1;
                        const userAnswer = answers[answerIndex];
                        const correctAnswerIndex = answers.indexOf(correctAnswer);

                        if (userAnswer === answers[correctAnswerIndex]) {
                            interaction.followUp(`Correct! 🎉 The answer is: ${correctAnswer}`);
                        } else {
                            interaction.followUp(`Wrong answer! The correct answer was: ${correctAnswer}`);
                        }
                        collector.stop();
                    });

                    collector.on('end', collected => {
                        if (collected.size === 0) {
                            interaction.followUp('Time is up! No one answered.');
                        }
                    });

                } catch (error) {
                    console.error('Error fetching trivia:', error);
                    await interaction.reply('Error fetching trivia. Please try again later.');
                }
                break;
        }
    },
};

#help.js

const { SlashCommandBuilder } = require('@discordjs/builders');

module.exports = {
    data: new SlashCommandBuilder()
        .setName('help')
        .setDescription('Displays a list of available commands or information about a specific command.')
        .addStringOption(option =>
            option.setName('command')
                .setDescription('The command you want help with')),
    category: 'utility',

    async execute(interaction) {
        const { commands } = interaction.client;

        // Define categorizedCommands, including the game category
        const categorizedCommands = {
            fun: [],
            moderation: [],
            utility: [],
            roleManagement: [],
            music: [],
            game: [],
            chatbot: [],
            giveaway: [],
        };

        // Categorize commands
        commands.forEach(command => {
            if (command.category && categorizedCommands[command.category]) {
                categorizedCommands[command.category].push(command);
            } else {
                console.warn(`Command ${command.data.name} is missing a valid category or category does not exist.`);
            }
        });

        const commandName = interaction.options.getString('command');

        if (!commandName) {
            const categories = Object.keys(categorizedCommands);

            // Create the initial embed
            const helpEmbed = new EmbedBuilder()
                .setColor('#5865F2')  // Discord's blurple color
                .setTitle('📜 Command List')
                .setDescription('Select a category to view its commands:')
                .setThumbnail(interaction.client.user.displayAvatarURL())
                .setTimestamp();  // Adds a timestamp at the bottom

            // Function to update the embed with the current category
            const updateEmbed = (category) => {
                const commandList = categorizedCommands[category]
                    .map(command => {
                        // Prepare the command and subcommand display
                        let commandDisplay = `**/${command.data.name}**: ${command.data.description}`;
                        
                        // Check if the command has subcommands
                        if (command.data.options && command.data.options.length > 0) {
                            const subcommandsDisplay = command.data.options
                                .filter(option => option.type === 1) // Subcommand type
                                .map(subcommand => `  - **/${command.data.name} ${subcommand.name}**: ${subcommand.description}`)
                                .join('\n');
                            commandDisplay += `\n${subcommandsDisplay}`; // Append subcommands to command
                            return commandDisplay;}
                        
                        
                    })
                    .join('\n') || 'No commands available.';

                helpEmbed.setTitle(`📋 Commands in ${category.charAt(0).toUpperCase() + category.slice(1)}`)
                    .setDescription(commandList);
            };

            // Set the initial category to the first one
            const initialCategory = categories[0];
            updateEmbed(initialCategory);  // Update for the initial category

            // Create a select menu for categories
            const selectMenu = new StringSelectMenuBuilder()
                .setCustomId('categorySelect')
                .setPlaceholder('Select a category')
                .addOptions(
                    categories.slice(0, 25).map(category => ({ // Limit to 25 options for safety
                        label: category.charAt(0).toUpperCase() + category.slice(1),
                        value: category,
                    }))
                );

            const row = new ActionRowBuilder().addComponents(selectMenu);

            const message = await interaction.reply({ embeds: [helpEmbed], components: [row], fetchReply: true });

            // Create a message component collector for select interactions
            const collector = message.createMessageComponentCollector({ time: 60000 });

            collector.on('collect', async i => {
                // Check if the select menu is used
                if (i.customId === 'categorySelect') {
                    updateEmbed(i.values[0]);  // Update the embed for the selected category
                    await i.update({ embeds: [helpEmbed] });  // Update the message with the new embed
                }
            });

            collector.on('end', () => {
                message.edit({ components: [] });  // Remove the select menu after the collector ends
            });

        } else {
            const command = commands.get(commandName.toLowerCase());

            if (!command) {
                return interaction.reply("❌ That's not a valid command!");
            }

            // Create the embed for a specific command
            const helpEmbed = new EmbedBuilder()
                .setColor('#5865F2')
                .setTitle(`❓ Help: /${command.data.name}`)
                .setDescription(`**Description**: ${command.data.description}`)
                .setThumbnail(interaction.client.user.displayAvatarURL());

            if (command.data.aliases) {
                helpEmbed.addFields({ name: '🔀 Aliases', value: command.data.aliases.join(', ') });
            }
            if (command.data.example) {
                helpEmbed.addFields({ name: '💡 Example', value: `\`${command.data.example}\`` });
            }
            if (command.data.options && command.data.options.length > 0) {
                const subcommandsList = command.data.options
                    .filter(option => option.type === 1) // type 1 indicates a subcommand
                    .map(subcommand => `**/${command.data.name} ${subcommand.name}**: ${subcommand.description}`)
                    .join('\n') || 'No subcommands available.';

                helpEmbed.addFields({ name: '📜 Subcommands', value: subcommandsList });
            }

            return interaction.reply({ embeds: [helpEmbed] });
        }
    },
};```

I have tried directly calling the subcommands then tried calling option type 1 as shown above, but still the output is 

[![help command output](https://i.sstatic.net/LIJUZSdr.png)](https://i.sstatic.net/LIJUZSdr.png)


  [1]: https://i.sstatic.net/fdJc16ta.png
javascript discord.js
1个回答
0
投票

以下代码返回命令的选项,如果选项是子命令,则返回子命令及其下选项的名称和描述,如果选项不是子命令,则返回名称、类型和描述的选项。

    console.log(
      interaction.client.commands.get("help")
        ?.data.options.map((option) =>
          option instanceof SlashCommandSubcommandBuilder
            ? {
                name: option.name,
                description: option.description,
                subcommandsOptions: option.options.map((subcommandoption) => ({
                  name: subcommandoption.name,
                  type: subcommandoption.type,
                  description: subcommandoption.description,
                })),
              }
            : { name: option.name, description: option.description }
        )
    );
© www.soinside.com 2019 - 2024. All rights reserved.