Discord.py开发:Moderation警报按钮批量触发及后续失效问题求助
问题根源
你当前的代码问题出在两个核心设计错误:
- 所有按钮的
custom_id都是全局重复的固定值,没有和当前对应的违规用户、告警消息做绑定,系统无法区分不同告警消息下的同名按钮 - 采用
wait_for_component在每个on_profanity事件内做阻塞等待,多个并行的等待队列会互相抢占事件,某一个等待触发完成后,其余的等待逻辑就会失效,导致后续按钮点击无响应
修复方案
1. 为每个按钮生成唯一的custom_id
你可以在custom_id中拼接当前违规用户ID、告警消息的唯一标识,保证全局没有重复的按钮ID:
# 生成唯一后缀,用用户id+消息id保证唯一性 suffix = f"{message.author.id}_{message.id}" buttons = [ manage_components.create_button( style=ButtonStyle.red, label="Ban!", custom_id=f"ban_{suffix}" ), manage_components.create_button( style=ButtonStyle.gray, label="Give them a Warning", custom_id=f"warning_{suffix}" ), manage_components.create_button( style=ButtonStyle.green, label="Nope!", custom_id=f"noBan_{suffix}" ), ]
2. 移除事件内的阻塞等待逻辑,改用全局按钮回调
不要在on_profanity里调用wait_for_component,而是单独写一个全局的按钮监听回调,统一处理所有按钮点击事件:
# 全局按钮点击监听 @manage_components.listener() async def on_button_click(button_ctx: ComponentContext): # 拆分custom_id获取动作和绑定的标识 custom_id_parts = button_ctx.custom_id.split("_") if len(custom_id_parts) < 3: # 不是 moderation 相关按钮,直接返回 return action, user_id, msg_id = custom_id_parts[0], custom_id_parts[1], custom_id_parts[2] # 删除原按钮消息避免重复点击 await button_ctx.origin_message.delete() channel = button_ctx.channel guild = button_ctx.guild banned_user = guild.get_member(int(user_id)) if not banned_user: await channel.send("未找到对应违规用户,操作失败") return # 执行对应动作 if action == "ban": await channel.send("The deed has been done.") # 补充ban逻辑即可,或者直接触发你原来的ban事件 elif action == "warning": await channel.send("The warning has been sent!") # 补充给用户加警告角色逻辑即可,或者直接触发原来的warning事件 elif action == "noBan": await channel.send("No action taken")
3. 精简原on_profanity事件逻辑
删除原事件中所有wait_for_component相关的阻塞代码,仅保留发送告警和按钮的逻辑即可:
@bot.event async def on_profanity(message, word): try: guildID = message.guild.id guild = bot.get_guild(guildID) channel = discord.utils.get(guild.text_channels, name="moderation-logs") if not channel: return except: return None embed = discord.Embed(title="Profanity Alert!", description=f"{message.author.name} just said ||{message.content}||. The bad word was: ||{word}||", color=discord.Color.blurple()) await channel.send(embed=embed) # 生成唯一后缀 suffix = f"{message.author.id}_{message.id}" buttons = [ manage_components.create_button( style=ButtonStyle.red, label="Ban!", custom_id=f"ban_{suffix}" ), manage_components.create_button( style=ButtonStyle.gray, label="Give them a Warning", custom_id=f"warning_{suffix}" ), manage_components.create_button( style=ButtonStyle.green, label="Nope!", custom_id=f"noBan_{suffix}" ), ] ActionRow = manage_components.create_actionrow(*buttons) if "warning" in [y.name.lower() for y in message.author.roles]: await channel.send("They have already been warned. Do you wish to ban them?", components=[ActionRow]) else: await channel.send("Do you wish to ban them?", components=[ActionRow])
以上修改完成后,所有按钮ID全局唯一不会串操作,全局回调的方式也不会出现单个按钮点击后其余按钮失效的问题。
内容的提问来源于stack exchange,提问作者Shadrock50
相关产品推荐
相关产品推荐

