Telegram Bot管理员点击按钮后用户未收到响应问题
问题排查与修复方案
核心问题分析
- 全局变量
user_id的竞态冲突:当多个用户提交付款截图时,全局user_id会被最后提交的用户ID覆盖,导致管理员处理早期用户的请求时,反馈消息会发给错误的用户。 - 回调处理器的优先级问题:两个
@bot.callback_query_handler(func=lambda call: True)装饰器的函数按注册顺序执行,第一个处理器会先捕获所有回调请求(包括管理员的「Подтвердить/Отклонить」操作),未处理的请求无法正确传递到第二个处理器。 - 冗余代码干扰:
handler_photo函数中重复判断content_type == 'photo',属于无效代码。
修复后的完整代码
from telebot import types import telebot token = 'token' bot = telebot.TeleBot(token) admin_id = 12345678 @bot.message_handler(commands=['start']) def start(message): if message.chat.id == admin_id: bot.send_message(message.chat.id, "Привет, администратор!") else: m1 = f'Привет, {message.from_user.first_name}. В этом боте можно оплатить участие в викторине. Нажми кнопку, чтобы получить реквизиты.' markup = types.InlineKeyboardMarkup() markup.add(types.InlineKeyboardButton('Получить реквизиты', callback_data='yes')) bot.send_message(message.chat.id, m1, reply_markup=markup) # 仅处理「Получить реквизиты」的回调请求 @bot.callback_query_handler(func=lambda call: call.data == 'yes') def callback_query_handler(call): chat_id = call.message.chat.id m2 = 'Реквизиты для оплаты: 5555 5555 4444 4444. ' \ 'После оплаты прикрепите скриншот оплаты для проверки.' bot.send_message(chat_id, m2) @bot.message_handler(content_types=['text', 'photo', 'audio', 'video', 'document', 'location', 'contact', 'sticker', 'poll']) def handler_photo(message): content_type = message.content_type chat_id = message.chat.id if message.from_user.id != admin_id: if content_type == 'photo': m3 = 'Спасибо, фотография получена. Нам необходимо немного времени, чтобы проверить оплату' bot.send_message(chat_id, m3) user_id = message.from_user.id photo_file_id = message.photo[-1].file_id markup = types.InlineKeyboardMarkup(row_width=2) # 将用户ID嵌入回调数据,避免全局变量冲突 approve_button = types.InlineKeyboardButton('Подтвердить', callback_data=f'approve_{user_id}') reject_button = types.InlineKeyboardButton('Отклонить', callback_data=f'reject_{user_id}') markup.add(approve_button, reject_button) bot.send_photo(chat_id=admin_id, photo=photo_file_id, reply_markup=markup) else: m4 = 'Пожалуйста, прикрепите скриншот оплаты в виде фотографии. Спасибо!' bot.send_message(chat_id, m4) # 仅处理管理员的审批/驳回回调 @bot.callback_query_handler(func=lambda call: call.data.startswith('approve_') or call.data.startswith('reject_')) def handle_callback_query(call): # 从回调数据中解析目标用户ID action, user_id = call.data.split('_') user_id = int(user_id) if action == 'approve': m5 = 'Ваша оплата принята! Ссылка на канал: https://t.me/' bot.send_message(chat_id=user_id, text=m5) elif action == 'reject': m6 = 'Оплата не была подтверджена. Отправьте квитанцию повторно или свяжитесь с поддержкой.' bot.send_message(chat_id=user_id, text=m6) bot.answer_callback_query(callback_query_id=call.id) bot.polling(none_stop=True, interval=0)
关键修改说明
- 移除全局
user_id:将用户ID直接嵌入按钮的callback_data中(格式为approve_用户ID/reject_用户ID),确保管理员处理请求时能精准定位到提交截图的用户。 - 拆分回调处理器:
- 第一个回调处理器仅响应用户点击「Получить реквизиты」的操作,避免拦截管理员的审批回调。
- 第二个回调处理器仅处理包含
approve_或reject_前缀的请求,逻辑边界清晰。
- 清理冗余代码:删除
handler_photo中重复的content_type == 'photo'判断,简化逻辑。
内容的提问来源于stack exchange,提问作者IRF
相关产品推荐
相关产品推荐

