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

Discord.js V12中消息反应用户user.id与user.name获取失败及积分功能实现问题咨询

解决Discord.js v12中messageReactionAdd事件的guild未定义错误及逻辑问题

核心错误原因

你的messageReactionAdd事件处理函数参数写错了!在Discord.js v12中,messageReactionAdd事件的回调参数是**(reaction, user)**,而不是(message, reaction, user)。这直接导致你函数里的message参数是undefined,后续调用reaction.message.guild自然会触发Cannot read property 'guild' of undefined错误。

其他需要修正的问题

除了参数错误,还有几个逻辑和语法问题需要调整:

1. SQLite语句语法错误

你的client.setdayCount语句里,VALUES部分的@dayCount和@guild之间缺少逗号,会导致SQL执行失败:

-- 错误写法
INSERT OR REPLACE INTO Table (id, dayCount, guild) VALUES (@id, @dayCount @guild);
-- 修正后
INSERT OR REPLACE INTO Table (id, dayCount, guild) VALUES (@id, @dayCount, @guild);

2. 表情判断逻辑错误

你当前的表情判断写法完全不符合JavaScript逻辑:if (lastMessage.reactions.cache.emojis === "1️⃣" || "2️⃣"...) 永远会返回true,因为非空字符串都是真值。正确的做法是检查用户添加的反应表情是否在目标列表中:

const validEmojis = ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣"];
if (validEmojis.includes(reaction.emoji.name)) {
  // 后续逻辑
}

3. Member获取方式与逻辑问题

  • 在v12中,获取服务器成员推荐使用members.fetch()方法,而不是直接member(user.id);
  • 需要排除机器人用户,避免给机器人加分;
  • 你直接给character(member对象)添加setdayCount属性是不合理的,应该先从数据库查询用户当前积分,再计算更新后的值。

4. 消息获取逻辑优化

你当前获取固定消息的方式是取频道最后一条消息,这可能不是你要的固定消息。如果是固定消息,建议直接存储该消息的ID,通过ID直接获取会更可靠。

修正后的完整代码

const config = require('./config.json');

// 修正SQL语句,增加guild查询条件避免跨服务器数据混淆
client.getdayCount = DB.prepare("SELECT dayCount from Table WHERE id = ? AND guild = ?;");
client.setdayCount = DB.prepare("INSERT OR REPLACE INTO Table (id, dayCount, guild) VALUES (@id, @dayCount, @guild);");

// 修正事件参数
client.on('messageReactionAdd', addRole);
client.on('messageReactionRemove', removeRole);

async function addRole(reaction, user) {
    // 排除机器人用户,避免无效操作
    if (user.bot) return;

    // 处理部分消息(未完全加载的消息)
    if (reaction.message.partial) {
        try {
            await reaction.message.fetch();
        } catch (err) {
            console.error('获取消息失败:', err);
            return;
        }
    }

    // 验证反应的表情是否为指定的1-7表情
    const validEmojis = ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣"];
    if (!validEmojis.includes(reaction.emoji.name)) return;

    try {
        const targetChannel = client.channels.cache.get(config.channelID);
        if (!targetChannel) {
            console.error('目标频道未找到');
            return;
        }

        // 这里暂时保留你取最后一条消息的逻辑,建议替换为固定消息ID直接获取
        const messages = await targetChannel.messages.fetch({ limit: 1 });
        const targetMessage = messages.first();
        // 确保用户反应的是目标消息
        if (reaction.message.id !== targetMessage.id) return;

        const guild = reaction.message.guild;
        if (!guild) {
            console.error('反应不在服务器内');
            return;
        }

        // 获取用户的服务器成员对象
        const member = await guild.members.fetch(user.id);
        if (!member) return;

        // 查询用户当前积分,不存在则默认为0
        const existingRecord = client.getdayCount.get(user.id, guild.id);
        const newCount = existingRecord ? existingRecord.dayCount + 1 : 1;

        // 更新数据库
        client.setdayCount.run({
            id: user.id,
            dayCount: newCount,
            guild: guild.id
        });

        console.log(`给${user.tag}增加1分,当前积分: ${newCount}`);
    } catch (err) {
        console.error('加分逻辑出错:', err);
    }
}

// 移除反应的扣分逻辑
async function removeRole(reaction, user) {
    if (user.bot) return;
    if (reaction.message.partial) {
        try {
            await reaction.message.fetch();
        } catch (err) {
            console.error('获取消息失败:', err);
            return;
        }
    }

    const validEmojis = ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣"];
    if (!validEmojis.includes(reaction.emoji.name)) return;

    try {
        const targetChannel = client.channels.cache.get(config.channelID);
        if (!targetChannel) return;

        const messages = await targetChannel.messages.fetch({ limit: 1 });
        const targetMessage = messages.first();
        if (reaction.message.id !== targetMessage.id) return;

        const guild = reaction.message.guild;
        if (!guild) return;

        // 查询用户当前积分,不存在则直接返回
        const existingRecord = client.getdayCount.get(user.id, guild.id);
        if (!existingRecord) return;

        // 扣分后避免出现负数积分
        const newCount = Math.max(0, existingRecord.dayCount - 1);
        client.setdayCount.run({
            id: user.id,
            dayCount: newCount,
            guild: guild.id
        });

        console.log(`给${user.tag}扣除1分,当前积分: ${newCount}`);
    } catch (err) {
        console.error('扣分逻辑出错:', err);
    }
}

关键修改点总结

  1. 修正了messageReactionAdd事件的回调参数,从(message, reaction, user)改为(reaction, user);
  2. 修复了SQL语句中的语法错误,并增加了guild查询条件避免跨服务器数据混淆;
  3. 优化了表情判断逻辑,使用数组includes方法验证表情;
  4. 添加了机器人用户过滤,避免无效操作;
  5. 调整了数据库查询和更新逻辑,正确获取并计算用户积分;
  6. 增加了错误处理和日志输出,方便调试;
  7. 编写了完整的removeRole逻辑,实现取消反应扣分的功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 13:57:31