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

使用discord.js v12开发统计用户持有指定角色时长的机器人如何实现?

问题核心原因

你当前代码的错误主要有两点:

  • message.member.roles.cache.has(role.id) 方法返回的是布尔值(true/false),直接用它做除法运算时,布尔值会被隐式转换为数字1/0,自然不可能得到正确的时长结果
  • 你没有存储用户获得「🚀On Duty」角色的时间戳,没有计算时长的基准值,且原有时间单位转换公式完全错误
修复方案

你需要新增一个存储结构记录用户的上岗时间戳,离岗时用当前时间减去开始时间得到总时长,再转换为天/时/分/秒格式即可。
首先在你命令处理逻辑的外层(比如机器人启动代码的顶部)声明存储结构:

// 存储用户上岗时间戳,key为用户ID,value为毫秒级时间戳
const dutyStartTimes = new Map();
const DUTY_ROLE_NAME = '🚀On Duty';

修改后的命令逻辑如下:

if(command === 'on') {
    const role = message.guild.roles.cache.find(role => role.name === DUTY_ROLE_NAME);
    // 避免重复上岗
    if (message.member.roles.cache.has(role.id)) {
        return message.reply('你已经处于上岗状态,无需重复执行命令').then(msg => msg.delete({timeout: 3000}));
    }
    message.member.roles.add(role).then(() => {
        // 记录上岗时间
        dutyStartTimes.set(message.author.id, Date.now());
        message.author.send('你已进入上岗状态');
        message.react('<:tick:902920026489749564>');
    }).catch(err => console.error('添加角色失败:', err));
} else if(command == 'off'){
    const role = message.guild.roles.cache.find(role => role.name === DUTY_ROLE_NAME);
    // 避免未上岗直接离岗
    if (!message.member.roles.cache.has(role.id) || !dutyStartTimes.has(message.author.id)) {
        return message.reply('你当前没有处于上岗状态,无法执行离岗命令').then(msg => msg.delete({timeout: 3000}));
    }
    // 计算在岗时长
    const startTime = dutyStartTimes.get(message.author.id);
    const totalMs = Date.now() - startTime;
    const days = Math.floor(totalMs / (1000 * 60 * 60 * 24));
    const hours = Math.floor((totalMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
    const minutes = Math.floor((totalMs % (1000 * 60 * 60)) / (1000 * 60));
    const seconds = Math.floor((totalMs % (1000 * 60)) / 1000);
    
    // 移除角色、清理存储记录
    message.member.roles.remove(role).then(() => {
        dutyStartTimes.delete(message.author.id);
        // 发送webhook日志
        const wc = new WebhookClient('MyWebhookId', 'myWebhookUrl');
        const log = new Discord.MessageEmbed()
        .setTitle('上岗日志')
        .setDescription(`用户: <@${message.author.id}>
天数: **${days}**
小时: **${hours}**
分钟: **${minutes}**
秒数: **${seconds}**`)
        .setTimestamp()
        .setColor('#fa0505');
        wc.send({
            username : message.author.tag,
            avatarURL : message.author.displayAvatarURL({ dynamic : true }),
            embeds : [log]
        });
        message.react('<:tick:902920026489749564>');
    }).catch(err => console.error('移除角色失败:', err));
}
额外说明
  • 上述代码使用内存Map存储时间戳,重启机器人后数据会丢失,如果需要持久化存储可以接入quick.db、mongoose等数据库存储用户的上岗时间
  • 代码新增了异常校验逻辑,避免用户重复执行上岗、未上岗直接执行离岗的异常场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 03:06:01