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

Discord机器人验证系统错误触发私信通知问题求助

Discord机器人验证系统错误触发私信通知问题求助

嘿,我明白你遇到的麻烦了——已经验证过的用户触发任何其他交互(比如Code2里的找队友按钮)都会收到机器人的“已验证”私信,这确实很烦人。让我帮你分析下问题所在,再给你解决方案:

问题根源分析

你的Code1里犯了两个关键错误:

  1. 重复注册全局交互监听器:每次运行sendverifizierung命令时,都会给client添加3个新的interactionCreate监听器。这些监听器会一直驻留在机器人进程中,只要有任何交互触发,所有这些监听器都会执行,导致重复触发逻辑。
  2. 未过滤交互类型:第一个监听器没有判断当前交互是否属于验证系统的组件(比如验证按钮、规则选择菜单),只要用户拥有成员角色707275842295955530,任何交互都会触发这条私信,不管是验证按钮还是找队友按钮。

解决方案

我们需要把验证相关的交互逻辑合并成一个独立的监听器,并且只处理验证系统的组件,同时避免重复注册监听器:

步骤1:重构Code1的交互逻辑

把所有验证相关的交互处理移到模块顶层(不要放在run方法里),这样只会注册一次监听器,并且只处理验证相关的组件:

const Discord = require('discord.js')
const Command = require('../../structures/CommandClass');
const { stripIndents } = require('common-tags');
const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, TextInputStyle, StringSelectMenuBuilder, Events, ModalBuilder, TextInputBuilder } = require('discord.js');

// 用Map存储用户昵称,比全局对象更安全,避免内存泄漏
module.exports = class verifiy extends Command {
  constructor(client) {
    super(client, {
      data: new SlashCommandBuilder()
        .setName('sendverifizierung')
        .setDescription('Sende das Verifizierungs Embed')
        .setDefaultMemberPermissions(PermissionFlagsBits.BanMembers)
        .setDMPermission(false),
    });

    // 初始化昵称缓存(如果客户端没有的话)
    if (!client.nicknameCache) {
      client.nicknameCache = new Map();
    }

    // 只注册一次验证交互监听器
    client.on('interactionCreate', async interaction => {
      const memberRoleId = '707275842295955530';
      // 只处理验证系统相关的交互,过滤掉其他组件
      const validVerificationCustomIds = ['buttonanfrageverify', 'rulesmenü', 'rolemenü', 'ninput'];
      if (!validVerificationCustomIds.includes(interaction.customId)) return;

      const member = await interaction.member.fetch();
      // 检查用户是否已验证,仅在验证交互触发时判断
      if (member.roles.cache.has(memberRoleId)) {
        await member.send('**Du bist bereits auf YANKEEUNIT91 COMMUNITY verifiziert!**');
        return interaction.deferUpdate();
      }

      // 处理验证按钮点击
      if (interaction.isButton() && interaction.customId === 'buttonanfrageverify') {
        const rulesmenü = new ActionRowBuilder()
          .addComponents(
            new StringSelectMenuBuilder()
              .setCustomId('rulesmenü')
              .setPlaceholder('Antwort auswählen')
              .addOptions(
                { label: 'Ja, gelesen und einverstanden.', value: 'ja' },
                { label: 'Nein, nicht gelsesen und nicht einverstanden.', value: 'nein' }
              )
          );
        await interaction.reply({ content:'**Hast du die Regeln gelesen, und bist du damit einverstanden?**', components: [rulesmenü], ephemeral: true });
      }

      // 处理规则选择菜单
      else if (interaction.isStringSelectMenu() && interaction.customId === 'rulesmenü') {
        const selected = interaction.values[0];
        const modalsv = new ModalBuilder()
          .setCustomId('ninput')
          .setTitle('YANKEEUNIT91 COMMUNITY')
          .addComponents(
            new ActionRowBuilder().addComponents(
              new TextInputBuilder()
                .setCustomId('nameinput')
                .setLabel("Server Nickname")
                .setPlaceholder('Keine Sonderzeichen!')
                .setStyle(TextInputStyle.Short)
                .setMinLength(2)
                .setMaxLength(32)
                .setRequired(true)
            )
          );

        if (selected === 'ja') {
          await interaction.showModal(modalsv);
        } else if (selected === 'nein') {
          await interaction.update({ content:'**Lese dir die Regeln erneut durch! Solltest du nicht mit denn Regeln einverstanden sein, bitten wir dich denn Server zu verlassen.**', components: [], ephemeral: true });
        }
      }

      // 处理昵称模态框提交
      else if (interaction.isModalSubmit() && interaction.customId === 'ninput') {
        const rolemenü = new ActionRowBuilder()
          .addComponents(
            new StringSelectMenuBuilder()
              .setCustomId('rolemenü')
              .setPlaceholder('Rolle auswählen')
              .addOptions(
                { label: 'YU91 Glocke', description: 'Erhalte extra Benachrichtigungen über Yankeeunit91.', value: 'glocke' },
                { label: 'Gaming News', description: 'Erhalte extra Benachrichtigungen für Neue Infos über z.B Spiele etc.', value: 'news' },
                { label: 'Keine', description: 'Erhalte keine Rolle.', value: 'keine' }
              )
          );
        await interaction.update({ content:'**Wähle eine Role für die du dich interresierst!**', components: [rolemenü], ephemeral: true });
        
        // 存储处理后的昵称到缓存
        const nickname = interaction.fields.getTextInputValue('nameinput').replace(/[^a-zA-Z0-9 ]/g, 'X');
        client.nicknameCache.set(interaction.user.id, nickname);
      }

      // 处理角色选择菜单
      else if (interaction.isStringSelectMenu() && interaction.customId === 'rolemenü') {
        const selected = interaction.values[0];
        const glocke = interaction.guild.roles.cache.get('884820297977573386');
        const news = interaction.guild.roles.cache.get('1032524990274351134');
        const memberrole = interaction.guild.roles.cache.get(memberRoleId);
        const nickname = client.nicknameCache.get(interaction.user.id);
        let failsafe = false;

        switch(selected) {
          case 'glocke':
            await interaction.update({ content:'**Du hast die \`YU91 Glocke\` erhalten. Willkommen in der YANKEEUNIT91 COMMUNITY!**', components: [], ephemeral: true });
            await member.roles.add(glocke);
            break;
          case 'news':
            await interaction.update({ content:'**Du hast die \`Gaming News\` erhalten. Willkommen in der YANKEEUNIT91 COMMUNITY!**', components: [], ephemeral: true });
            await member.roles.add(news);
            break;
          case 'keine':
            await interaction.update({ content:'**Willkommen in der YANKEEUNIT91 COMMUNITY!**', components: [], ephemeral: true });
            break;
        }

        await interaction.member.setNickname(nickname).catch(e => (failsafe = true));
        await member.roles.add(memberrole);
        // 移除缓存的昵称,释放内存
        client.nicknameCache.delete(interaction.user.id);
      }
    });
  }

  async run(client, interaction) {
    let member = await interaction.member.fetch();
    const verifiychannelID = '1052951990331773019';
    const verifiychannel = member.guild.channels.cache.get(verifiychannelID);

    const verifeembed = new EmbedBuilder()
      .setTitle(`Verifizieren dich!`)
      .setColor('#00ff0c')
      .setDescription(stripIndents`Durch das verifizieren erhälst du zugriff auf die YANKEEUNIT91 COMMUNITY!`)
      .setFooter({ text: 'YANKEEUNIT91 COMMUNITY'})
      .setTimestamp();

    const buttonva = new ActionRowBuilder()
      .addComponents(
        new ButtonBuilder()
          .setCustomId('buttonanfrageverify')
          .setEmoji('✅')
          .setLabel('Verifizieren')
          .setStyle(ButtonStyle.Success),
      );

    verifiychannel.send({ embeds: [verifeembed], components: [buttonva] });
    await interaction.reply({ content: 'Verifizierungs Embed wurde versendet!', ephemeral: true });
  }
};

步骤2:修复核心逻辑

  • 现在监听器只会处理验证系统的组件(通过validVerificationCustomIds数组过滤),其他交互(比如Code2的找队友按钮)会直接跳过角色检查。
  • 用Map存储用户昵称替代全局对象,避免内存泄漏和意外覆盖。
  • 监听器只在模块初始化时注册一次,不会重复添加导致逻辑重复触发。

这样修改后,只有用户触发验证相关的按钮/菜单时,才会检查是否已验证并发送私信,其他交互完全不受影响。

备注:内容来源于stack exchange,提问作者Marc-Anthony

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 14:42:52