如何设置仅特定角色可点击的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
相关产品推荐
相关产品推荐

