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
相关产品推荐
相关产品推荐

