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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 20:15:05