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

如何设置仅特定角色可点击的Discord按钮?

解决Discord按钮角色权限限制问题

问题原因

@commands.has_role装饰器仅适用于discord.py的命令(Command)对象,无法直接作用于discord.ui.Button的回调方法,因此你的装饰器不会生效,需要在按钮回调函数内部手动检查用户角色权限。

解决方案

在每个按钮的回调逻辑开头添加角色检查步骤,若用户没有对应角色则直接反馈并终止执行;同时修正原代码中类变量存储时间导致的多用户数据冲突问题,改用实例变量。

修改后的完整代码:

import discord
from discord import ui
from discord.ext import commands
import datetime
import pytz
import time
from datetime import timedelta

class SimpleView(discord.ui.View):
    def __init__(self):
         self.start_time = None  # 改用实例变量,避免多用户数据冲突
         self.stop_time = None
         super().__init__(timeout=None)

    @discord.ui.button(label="𝑬𝑵𝑻𝑹𝑨𝑻𝑨⬆️", style=discord.ButtonStyle.green, custom_id="1")
    async def entrata(self, interaction: discord.Interaction, button: discord.ui.Button):
            # 检查用户是否拥有指定角色
            required_role = discord.utils.get(interaction.guild.roles, name="🙍‍♂️ FUORI SERVIZIO")
            if required_role not in interaction.user.roles:
                await interaction.response.send_message("你没有权限点击这个按钮!", ephemeral=True)
                return

            orario_it = datetime.datetime.now(pytz.timezone('Europe/Rome'))
            orario = orario_it.strftime('%H:%M')
            data = orario_it.strftime('%Y-%m-%d')  # 补充原代码未定义的data变量

            self.start_time = time.time()

            channel = interaction.guild.get_channel(1214495527924928522)           
            embed=discord.Embed(color=0x23a559)
            embed.set_thumbnail(url="https://shft.cl/img/c/cdn.discordapp.com-101395680655364460.webp")
            embed.add_field(name="⬆️𝑬𝑵𝑻𝑹𝑨𝑻𝑨⬆️", value="", inline=False)
            embed.add_field(name="NOME:", value=f"{interaction.user.mention}", inline=True)
            embed.add_field(name="", value="", inline=True)
            embed.add_field(name="", value="", inline=False)
            embed.add_field(name="", value="", inline=False)
            embed.add_field(name="DATA:", value=f"{data}", inline=True)
            embed.add_field(name="ORARIO:", value=f"{orario}", inline=True)
            embed.set_footer(text="ARMERIA200")
            await channel.send(embed=embed)
            await interaction.response.send_message(f"***SEI ENTRATO IN SERVIZIO ALLE: {orario}.***", ephemeral=True)

    @discord.ui.button(label="𝑼𝑺𝑪𝑰𝑻𝑨⬇️", style=discord.ButtonStyle.red, custom_id="2")
    async def uscita(self, interaction: discord.Interaction, button: discord.ui.Button):
            # 检查用户是否拥有指定角色
            required_role = discord.utils.get(interaction.guild.roles, name="🙋‍♂️ IN SERVIZIO")
            if required_role not in interaction.user.roles:
                await interaction.response.send_message("你没有权限点击这个按钮!", ephemeral=True)
                return

            # 防止未记录入职就点击离职的情况
            if self.start_time is None:
                await interaction.response.send_message("你还没有记录入职时间!", ephemeral=True)
                return

            orario_it = datetime.datetime.now(pytz.timezone('Europe/Rome'))
            orario = orario_it.strftime('%H:%M')
            data = orario_it.strftime('%Y-%m-%d')

            self.stop_time = time.time()
            elapsed_time = self.stop_time - self.start_time
            time_d = timedelta(seconds=int(elapsed_time))

            channel = interaction.guild.get_channel(1215061241270374400)           
            embed=discord.Embed(color=0xda373c)
            embed.set_thumbnail(url="https://shft.cl/img/c/cdn.discordapp.com-101395680655364460.webp")
            embed.add_field(name="⬇️𝑼𝑺𝑪𝑰𝑻𝑨⬇️", value="", inline=False)
            embed.add_field(name="NOME:", value=f"{interaction.user.mention}", inline=True)
            embed.add_field(name="", value="", inline=True)
            embed.add_field(name="", value="", inline=False)
            embed.add_field(name="", value="", inline=False)
            embed.add_field(name="DATA:", value=f"{data}", inline=True)
            embed.add_field(name="ORARIO:", value=f"{orario}", inline=True)
            embed.add_field(name="TEMPO IN SERVIZIO:", value=f"{time_d}", inline=True)
            embed.set_footer(text="ARMERIA200")
            await channel.send(embed=embed)
            await interaction.response.send_message(f"***SEI USCITO DI SERVIZIO ALLE: {orario}, DOPO: {time_d}***", ephemeral=True)

关键修改说明

  • 移除无效的@commands.has_role装饰器,改用discord.utils.get获取目标角色,手动检查用户角色列表。
  • 将SimpleView.start_time和SimpleView.stop_time改为实例变量self.start_time和self.stop_time,避免多用户使用时数据互相覆盖。
  • 补充原代码中未定义的data变量,使用当前日期赋值。
  • 为离职按钮添加入职时间非空检查,避免逻辑错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 11:36:17