You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js点击按钮后如何向模态框提交者私发Embed消息

问题根源

你现有代码无法实现需求的核心问题有3个:

  • 存储提交人信息的author是模态框提交逻辑内的局部变量,管理员点击审核按钮时无法访问该变量
  • 审核按钮的自定义ID为固定值,无法关联对应申请的提交用户,多份申请提交后无法区分每条审核消息对应的申请人
  • 审核按钮的交互判断写在模态框提交的判断分支后,模态框提交事件触发时会直接执行if (!interaction.isModalSubmit()) return;返回,根本不会走到后续的按钮判断逻辑
实现方案

不需要额外引入数据库存储申请对应关系,直接把申请人ID编码到审核按钮的customId中即可,Discord按钮的customId支持最长100个字符,存储用户ID完全足够。按钮触发时直接从customId中解析出申请人ID,就能定位到对应用户发送私信。

关键修改点

  • 合并所有interactionCreate事件监听,不要重复注册多个监听,把按钮交互、模态框提交的逻辑都放在同一个监听内处理
  • 生成审核消息的按钮时,把申请人ID拼接到按钮customId后缀
  • 审核按钮触发时,从customId拆分出申请人ID,拉取用户对象后发送对应结果的私信
  • 交互触发后必须在3秒内返回响应,避免Discord报交互失效,管理员操作后返回仅自己可见的临时提示即可
  • 操作完成后禁用审核消息上的按钮,避免重复点击触发多次通知

修改后完整可运行代码

client.on("messageCreate", (message) => {
    if(message.content == "!bando"){
        const bando = new MessageEmbed()
        .setColor("#037bfc")
        .setTitle("MODULO BANDO STAFF")
        .setDescription(`Se vorresti diventare staff, segui le regole\n del bando in <#995108403330416753> e poi premi il bottone qua sotto`)
        .setTimestamp()
        .setFooter({ text: "Developed by @Wrld#0095", iconURL: "https://cdn.discordapp.com/attachments/987458307092545568/995114362748547183/logo-wrld.gif"})

        const row = new MessageActionRow()
            .addComponents(
                new MessageButton()
                    .setCustomId('bando')
                    .setLabel('Modulo bando')
                    .setStyle('PRIMARY')
                    .setEmoji('📝'),
            );

        message.channel.send({embeds: [bando], components: [row]})
    }
})

client.on('interactionCreate', async interaction => {
    // 处理打开申请模态框的按钮
    if (interaction.isButton() && interaction.customId === 'bando') {
        const modal = new Modal()
            .setCustomId('modalBando')
            .setTitle('MODULO BANDO');
        
        const nome = new TextInputComponent()
            .setCustomId('nome')
            .setLabel("Nome")
            .setStyle('SHORT');
        const eta = new TextInputComponent()
            .setCustomId('eta')
            .setLabel("Età")
            .setStyle('SHORT');
        const motivo = new TextInputComponent()
            .setCustomId('motivo')
            .setLabel("Perchè vorresti diventare staff?")
            .setStyle('PARAGRAPH');
        const mansione = new TextInputComponent()
            .setCustomId('mansione')
            .setLabel("Che ruolo vorresti ricoprire?")
            .setStyle('SHORT');
        
        const firstActionRow = new MessageActionRow().addComponents(nome);
        const secondActionRow = new MessageActionRow().addComponents(eta);
        const thirdActionRow = new MessageActionRow().addComponents(motivo);
        const fourthActionRow = new MessageActionRow().addComponents(mansione);
        modal.addComponents(firstActionRow, secondActionRow, thirdActionRow, fourthActionRow);

        await interaction.showModal(modal);
        return;
    }

    // 处理模态框提交
    if (interaction.isModalSubmit() && interaction.customId === 'modalBando') {
        const applicant = interaction.user;
        // 给申请人发提交成功通知
        const bandoInviato = new MessageEmbed()
        .setColor("#037bfc")
        .setTitle("MODULO BANDO STAFF")
        .setDescription(`Salve, il suo bando è stato inviato.\n Presto le comunicheremo l'esito.`)
        .setTimestamp()
        .setFooter({ text: "Developed by @Wrld#0095", iconURL: "https://cdn.discordapp.com/attachments/987458307092545568/995114362748547183/logo-wrld.gif"})
        await applicant.send({ embeds: [bandoInviato]});
        
        const nome = interaction.fields.getTextInputValue('nome');
        const eta = interaction.fields.getTextInputValue('eta');
        const motivo = interaction.fields.getTextInputValue('motivo');
        const mansione = interaction.fields.getTextInputValue('mansione');
        const logBando = interaction.guild.channels.cache.get("995105468341026866");
        const bandoLog = new MessageEmbed()
            .setColor("#037bfc")
            .setTitle("MODULO BANDO STAFF")
            .setDescription(`Bando eseguito da ${interaction.user.tag}`)
            .addFields(
                { name: 'Nome', value: nome, inline: false },
                { name: 'Età', value: eta, inline: false },
                { name: 'Perchè vorresti diventare staff?', value: motivo, inline: false },
                { name: 'Che ruolo vorresti ricoprire?', value: mansione, inline: false },
            )
            .setTimestamp()
            .setFooter({ text: "Developed by @Wrld#0095", iconURL: "https://cdn.discordapp.com/attachments/987458307092545568/995114362748547183/logo-wrld.gif"})

        // 按钮customId拼接申请人ID,用于后续审核时定位用户
        const esitoBando = new MessageActionRow()
            .addComponents(
                new MessageButton()
                    .setCustomId(`accettato_${applicant.id}`)
                    .setLabel('Accetta')
                    .setStyle('SUCCESS')
                    .setEmoji('✔'),
                    new MessageButton()
                    .setCustomId(`rifiutato_${applicant.id}`)
                    .setLabel('Rifiuta')
                    .setStyle('DANGER')
                    .setEmoji('❌'),
            );
        await logBando.send({ embeds: [bandoLog], components: [esitoBando]});
        // 响应模态框提交
        await interaction.reply({ content: '你的申请已提交,请等待审核结果', ephemeral: true });
        return;
    }

    // 处理审核通过按钮
    if (interaction.isButton() && interaction.customId.startsWith('accettato_')) {
        const applicantId = interaction.customId.split('_')[1];
        const applicant = await client.users.fetch(applicantId);
        
        const accettato = new MessageEmbed()
        .setColor("#037bfc")
        .setTitle("BANDO ACCETTATO")
        .setDescription(`Salve, il suo bando è stato accettato.\n Apra un <#995105177403142174>e comunica gli orari disponibili\n per effettuare il colloquio.`)
        .setTimestamp()
        .setFooter({ text: "Developed by @Wrld#0095", iconURL: "https://cdn.discordapp.com/attachments/987458307092545568/995114362748547183/logo-wrld.gif"})
        
        try {
            await applicant.send({ embeds: [accettato]});
            await interaction.reply({ content: '已通过该申请,结果已私信通知申请人', ephemeral: true });
        } catch (err) {
            await interaction.reply({ content: '操作失败,该用户关闭了服务器私信,无法通知结果', ephemeral: true });
        }

        // 禁用按钮避免重复操作
        const disabledRow = new MessageActionRow()
            .addComponents(
                new MessageButton()
                    .setCustomId('accettato_disabled')
                    .setLabel('已通过')
                    .setStyle('SUCCESS')
                    .setEmoji('✔')
                    .setDisabled(true),
                new MessageButton()
                    .setCustomId('rifiutato_disabled')
                    .setLabel('Rifiuta')
                    .setStyle('DANGER')
                    .setEmoji('❌')
                    .setDisabled(true),
            );
        await interaction.message.edit({ components: [disabledRow] });
        return;
    }

    // 处理审核拒绝按钮
    if (interaction.isButton() && interaction.customId.startsWith('rifiutato_')) {
        const applicantId = interaction.customId.split('_')[1];
        const applicant = await client.users.fetch(applicantId);

        const rifiutato = new MessageEmbed()
        .setColor("#037bfc")
        .setTitle("BANDO RIFIUTATO")
        .setDescription(`Salve, il suo bando è stato rifiutato.\n Ritenta alle prossime candidature.`)
        .setTimestamp()
        .setFooter({ text: "Developed by @Wrld#0095", iconURL: "https://cdn.discordapp.com/attachments/987458307092545568/995114362748547183/logo-wrld.gif"})
        
        try {
            await applicant.send({ embeds: [rifiutato]});
            await interaction.reply({ content: '已拒绝该申请,结果已私信通知申请人', ephemeral: true });
        } catch (err) {
            await interaction.reply({ content: '操作失败,该用户关闭了服务器私信,无法通知结果', ephemeral: true });
        }

        // 禁用按钮避免重复操作
        const disabledRow = new MessageActionRow()
            .addComponents(
                new MessageButton()
                    .setCustomId('accettato_disabled')
                    .setLabel('Accetta')
                    .setStyle('SUCCESS')
                    .setEmoji('✔')
                    .setDisabled(true),
                new MessageButton()
                    .setCustomId('rifiutato_disabled')
                    .setLabel('已拒绝')
                    .setStyle('DANGER')
                    .setEmoji('❌')
                    .setDisabled(true),
            );
        await interaction.message.edit({ components: [disabledRow] });
        return;
    }
})

额外说明

  • 代码里加了try/catch捕获私信发送失败的场景,避免用户关闭私信时机器人直接报错崩溃
  • 所有交互都做了提前return,避免逻辑穿透走到其他判断分支
  • 管理员操作后的提示设置了ephemeral: true,只有操作的管理员能看到提示,不会污染审核频道的内容

内容的提问来源于stack exchange,提问作者Angelo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 05:15:31