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

如何让Discord机器人检测单反应槽满8次用户反应后触发指定操作

Discord活动报名机器人功能实现方案

前置调整说明

  • 必须补充GUILD_MESSAGE_REACTIONS权限,否则机器人无法检测用户的表情反应
  • 原cron表达式为每秒触发,已修改为每周五18点触发的配置,可按需调整时间
  • 反应监听器配置了7天的有效期,完全满足数天的反应累计需求
  • 请提前替换代码中的NOTIFY_CHANNEL_ID为你的目标通知频道ID

完整修改后代码

const { Client, Intents } = require('discord.js');
const cron = require('cron');

// 配置项
const NOTIFY_CHANNEL_ID = '替换为你的通知频道ID';
const ACTIVE_DAYS = 7; // 报名有效时长,单位天
const MIN_PARTICIPANTS = 8; // 成团最低人数
const CRON_SCHEDULE = '0 0 18 * * 5'; // 每周五18点发送报名消息,从左到右参数:秒、分、时、日、月、周

const client = new Client({ 
  intents: [
    Intents.FLAGS.GUILDS, 
    Intents.FLAGS.GUILD_MESSAGES,
    Intents.FLAGS.GUILD_MESSAGE_REACTIONS // 新增反应监听权限
  ] 
});

let currentMtgFormat = "VOW";

Date.prototype.addDays = function(days) {
    var date = new Date(this.valueOf());
    date.setDate(date.getDate() + days);
    return date;
}

function getTimestampSeconds(daysFromToday) {
    let ms= new Date().addDays(daysFromToday);
    let sec= Math.floor((ms/1000));
    return sec;
};

// 生成报名消息
function generateSignupMsg() {
  let mondayDate = "<t:" + getTimestampSeconds(3) + ":D>";
  let mondayDateShort = "<t:" + getTimestampSeconds(3) + ":d>";
  let tuesdayDate = "<t:" + getTimestampSeconds(4) + ":D>";
  let wednesdayDate = "<t:" + getTimestampSeconds(5) + ":D>";
  let thursdayDate = "<t:" + getTimestampSeconds(6) + ":D>";
  let fridayDate = "<t:" + getTimestampSeconds(7) + ":D>";
  let saturdayDate = "<t:" + getTimestampSeconds(8) + ":D>";
  let sundayDate = "<t:" + getTimestampSeconds(9) + ":D>";
  let sundayDateShort = "<t:" + getTimestampSeconds(9) + ":d>";

  return "**- Ouverture des inscriptions pour la semaine du " + mondayDateShort + " au " + sundayDateShort + "  -**\n\nPour vous inscrire réagissez à ce poste avec vos jours de disponibilité : \n\n:regional_indicator_l: : Lundi " + mondayDate + " (20h) - Draft " + currentMtgFormat + "\n:regional_indicator_m: : Mardi " + tuesdayDate + " (20h) - Draft " + currentMtgFormat + "\n:regional_indicator_w: : Mercredi " + wednesdayDate + " (20h) - Draft " + currentMtgFormat + "\n:regional_indicator_j: : Jeudi " + thursdayDate + " (20h) - Draft " + currentMtgFormat + "\n:regional_indicator_v: : Vendredi " + fridayDate + " (20h30) - Draft " + currentMtgFormat + "\n:regional_indicator_s: : Samedi " + saturdayDate + " (20h30) - Draft " + currentMtgFormat + "\n:regional_indicator_d: : Dimanche " + sundayDate + " (20h) - Draft " + currentMtgFormat + "\n:alarm_clock:  : Dimanche " + sundayDate + " : Draft Asynchrone (21h) - " + currentMtgFormat + "\n\nDès lors qu'une personne est le 8ème inscrit sur un créneau (ou 16ème pour un éventuel 2ème draft au même horaire), cette dernière DOIT lancer le message de Check-in dans le salon approprié selon le modèle indiqué dans <#911268701528002590> (ou prévenir un modérateur).\n\nLes joueurs inscrits supplémentaires (mais en nombre insuffisant pour constituer une POD) sont considérés comme prioritaires sur les remplacements éventuels (absence de check-in, désistement de dernière minute etc...).";
}

client.once('ready', () => {
    console.log('IM SUPER READY YEA!')
})

let scheduledPodsMessage = new cron.CronJob(CRON_SCHEDULE, async () => {
    const channel = client.channels.cache.get("910686979828633611");
    const guild = client.guilds.cache.get("910603170336624640");
    const notifyChannel = client.channels.cache.get(NOTIFY_CHANNEL_ID);
    if (!channel || !guild || !notifyChannel) return console.error('频道/服务器不存在');

    // 发送报名消息
    const sentMessage = await channel.send(generateSignupMsg());
    // 预置表情
    const emojis = [
      guild.emojis.cache.get('911267403072167966'),
      guild.emojis.cache.get('911267403046998016'),
      guild.emojis.cache.get('911267403084730418'),
      guild.emojis.cache.get('911267403046985738'),
      guild.emojis.cache.get('911268283901177876'),
      guild.emojis.cache.get('911267403034415114'),
      guild.emojis.cache.get('911267403109912606'),
      '⏰'
    ];
    for (const emoji of emojis) {
      await sentMessage.react(emoji);
    }

    // 反应过滤器:排除机器人,仅监听预置表情
    const filter = (reaction, user) => {
      return !user.bot && emojis.some(e => e.id ? e.id === reaction.emoji.id : e === reaction.emoji.name);
    };

    // 开启7天的反应监听
    const reactionCollector = sentMessage.createReactionCollector({
      filter,
      time: ACTIVE_DAYS * 24 * 60 * 60 * 1000,
      dispose: true // 支持用户取消反应的计数更新
    });

    // 监听新增反应
    reactionCollector.on('collect', async (reaction, user) => {
      // 获取当前表情的所有非机器人用户
      const users = await reaction.users.fetch();
      const validUsers = users.filter(u => !u.bot);
      
      // 人数达到成团标准
      if (validUsers.size >= MIN_PARTICIPANTS) {
        // 取前8个用户
        const notifyUsers = validUsers.first(MIN_PARTICIPANTS);
        // 发送通知
        await notifyChannel.send(`⏰ 活动场次成团!本次参与成员:${notifyUsers.map(u => `<@${u.id}>`).join(' ')}`);
        // 删除这8个用户的对应反应
        for (const u of notifyUsers) {
          await reaction.users.remove(u.id);
        }
      }
    });

    console.log('报名消息已发送,反应监听已开启')
}, null, true);

scheduledPodsMessage.start()

client.login('你的机器人Token');

功能匹配说明

  • 自动统计每个表情的非机器人反应数量,达到8人自动触发通知
  • 通知自动@所有成团用户,发送到指定频道
  • 通知发送后自动删除对应8人的反应,剩余用户继续累计可触发下一场成团通知
  • 监听有效期默认7天,可通过ACTIVE_DAYS参数灵活调整,满足长周期累计需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 19:45:06