Spaces:
Sleeping
Sleeping
| import asyncio | |
| import json | |
| import os | |
| from datetime import datetime | |
| from aiogram import Bot, Dispatcher, types, F | |
| from aiogram.filters import Command | |
| from aiogram.utils.keyboard import ReplyKeyboardBuilder, InlineKeyboardBuilder | |
| from flask import Flask, request, jsonify, render_template_string | |
| import logging | |
| import threading | |
| # Настройка логирования | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) # Используем __name__ для логгера | |
| # Инициализация бота и Flask | |
| BOT_TOKEN = '7734802681:AAGKHGG8O9uNk64JWTHH5yqXzvSxCcoLUdA' | |
| bot = Bot(token=BOT_TOKEN) | |
| dp = Dispatcher() | |
| app = Flask(__name__) | |
| # Путь для хранения данных (товары и заказы) | |
| DATA_FILE = 'data.json' | |
| # Загрузка или создание данных | |
| def load_data(): | |
| try: | |
| if os.path.exists(DATA_FILE): | |
| with open(DATA_FILE, 'r', encoding='utf-8') as f: | |
| return json.load(f) | |
| return {'products': [], 'orders': []} | |
| except Exception as e: | |
| logger.error(f"Ошибка при загрузке данных: {e}") | |
| return {'products': [], 'orders': []} | |
| def save_data(data): | |
| try: | |
| with open(DATA_FILE, 'w', encoding='utf-8') as f: | |
| json.dump(data, f, ensure_ascii=False, indent=4) | |
| except Exception as e: | |
| logger.error(f"Ошибка при сохранении данных: {e}") | |
| data = load_data() | |
| # Клавиатуры | |
| def get_main_keyboard(): | |
| builder = ReplyKeyboardBuilder() | |
| builder.button(text="📋 Меню") | |
| builder.button(text="🛒 Корзина") | |
| builder.button(text="📦 Заказы") | |
| builder.adjust(2) | |
| return builder.as_markup(resize_keyboard=True) | |
| def get_product_keyboard(product_id): | |
| builder = InlineKeyboardBuilder() | |
| builder.button(text="Добавить в корзину", callback_data=f"add_{product_id}") | |
| return builder.as_markup() | |
| # Обработчики для бота | |
| async def cmd_start(message: types.Message): | |
| await message.answer("Привет! Я твой бот-магазин. Выбери действие:", reply_markup=get_main_keyboard()) | |
| async def show_products(message: types.Message): | |
| if not data['products']: | |
| await message.answer("Нет доступных товаров.") | |
| return | |
| for product in data['products']: | |
| await message.answer( | |
| f"🏷 {product['name']} - {product['price']} руб.\nОписание: {product['description']}\n/id: {product['id']}", | |
| reply_markup=get_product_keyboard(product['id']) | |
| ) | |
| async def show_cart(message: types.Message): | |
| user_id = message.from_user.id | |
| cart = next((o for o in data['orders'] if o['user_id'] == user_id and not o['completed']), None) | |
| if not cart or not cart['items']: | |
| await message.answer("Ваша корзина пуста.") | |
| return | |
| total = 0 | |
| response = "Ваша корзина:\n" | |
| for item in cart['items']: | |
| product = next(p for p in data['products'] if p['id'] == item['product_id']) | |
| response += f"🏷 {product['name']} - {product['price']} руб. x {item['quantity']}\n" | |
| total += product['price'] * item['quantity'] | |
| response += f"\nИтого: {total} руб." | |
| builder = InlineKeyboardBuilder() | |
| builder.button(text="Оформить заказ", callback_data=f"complete_{user_id}") | |
| await message.answer(response, reply_markup=builder.as_markup()) | |
| async def add_to_cart(callback_query: types.CallbackQuery): | |
| product_id = int(callback_query.data.split('_')[1]) | |
| product = next((p for p in data['products'] if p['id'] == product_id), None) | |
| if product: | |
| user_id = callback_query.from_user.id | |
| cart = next((o for o in data['orders'] if o['user_id'] == user_id and not o['completed']), None) | |
| if not cart: | |
| cart = {'user_id': user_id, 'items': [], 'completed': False, 'date': datetime.now().isoformat()} | |
| data['orders'].append(cart) | |
| cart_item = next((item for item in cart['items'] if item['product_id'] == product_id), None) | |
| if cart_item: | |
| cart_item['quantity'] += 1 | |
| else: | |
| cart['items'].append({'product_id': product_id, 'quantity': 1}) | |
| save_data(data) | |
| await bot.answer_callback_query(callback_query.id, "Товар добавлен в корзину!") | |
| else: | |
| await bot.answer_callback_query(callback_query.id, "Товар не найден.") | |
| async def complete_order(callback_query: types.CallbackQuery): | |
| user_id = int(callback_query.data.split('_')[1]) | |
| cart = next((o for o in data['orders'] if o['user_id'] == user_id and not o['completed']), None) | |
| if cart: | |
| cart['completed'] = True | |
| save_data(data) | |
| await bot.answer_callback_query(callback_query.id, "Заказ успешно оформлен!") | |
| await bot.send_message(user_id, "Спасибо за заказ! Мы скоро свяжемся с вами.") | |
| else: | |
| await bot.answer_callback_query(callback_query.id, "Корзина пуста или заказ уже оформлен.") | |
| async def show_orders(message: types.Message): | |
| user_id = message.from_user.id | |
| user_orders = [o for o in data['orders'] if o['user_id'] == user_id and o['completed']] | |
| if not user_orders: | |
| await message.answer("У вас нет оформленных заказов.") | |
| return | |
| for order in user_orders: | |
| response = "Ваш заказ:\n" | |
| total = 0 | |
| for item in order['items']: | |
| product = next(p for p in data['products'] if p['id'] == item['product_id']) | |
| response += f"🏷 {product['name']} - {product['price']} руб. x {item['quantity']}\n" | |
| total += product['price'] * item['quantity'] | |
| response += f"\nИтого: {total} руб.\nДата: {order['date']}" | |
| await message.answer(response) | |
| # Админ-панель (Flask) с HTML-шаблоном | |
| admin_html = """ | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Админ-панель</title> | |
| <style> | |
| body { font-family: Arial; background-color: #f0f0f0; margin: 20px; } | |
| .container { max-width: 800px; margin: auto; } | |
| .product { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; background-color: #fff; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>Управление товарами</h1> | |
| <form id="addProductForm"> | |
| <input type="text" name="name" placeholder="Название" required><br> | |
| <input type="number" name="price" placeholder="Цена" required><br> | |
| <textarea name="description" placeholder="Описание"></textarea><br> | |
| <button type="submit">Добавить товар</button> | |
| </form> | |
| <h2>Существующие товары</h2> | |
| {% for product in products %} | |
| <div class="product"> | |
| <b>{{ product.name }}</b> - {{ product.price }}<br>{{ product.description }} | |
| <button onclick="deleteProduct({{ product.id }})">Удалить</button> | |
| </div> | |
| {% endfor %} | |
| <h2>Заказы</h2> | |
| {% for order in orders %} | |
| <div class="product"> | |
| <b>Пользователь:</b> {{ order.user_id }}<br><b>Дата:</b> {{ order.date }} | |
| <ul>{% for item in order.items %} <li>{{ item.quantity }}</li>{% endfor %}</ul></div>{% endfor %} | |
| <script> | |
| // JS для добавления/удаления товаров. | |
| async function deleteProduct(productId) { | |
| const response = await fetch(`/delete_product/${productId}`, { method: 'POST' }); | |
| if (response.ok) window.location.reload(); | |
| } | |
| document.getElementById('addProductForm').onsubmit = async (e) => { | |
| e.preventDefault(); | |
| const formData = new FormData(e.target); | |
| const response = await fetch('/add_product', { method: 'POST', body: formData }); | |
| if (response.ok) window.location.reload(); | |
| }; | |
| </script> | |
| </div></body></html>""" | |
| def admin_panel(): | |
| try: | |
| logger.info(f"Products: {data.get('products')}, Orders: {data.get('orders')}") | |
| return render_template_string(admin_html, products=data.get('products', []), orders=data.get('orders', [])) | |
| except Exception as e: | |
| logger.error(f"Ошибка в шаблоне: {e}") | |
| return "Ошибка сервера. Проверьте логи.", 500 | |
| def add_product(): | |
| try: | |
| logger.info("Adding new product") | |
| name = request.form.get('name') | |
| price = float(request.form.get('price')) | |
| description = request.form.get('description') | |
| # Генерация нового ID для продукта | |
| product_id = max((p['id'] for p in data.get('products', [])), default=0) + 1 | |
| # Добавление продукта в данные и сохранение | |
| data.setdefault('products', []).append({'id': product_id, 'name': name, 'price': price, 'description': description}) | |
| save_data(data) | |
| return jsonify({'status': 'success'}) | |
| except Exception as e: | |
| logger.error(f"Ошибка при добавлении товара: {e}") | |
| return jsonify({'status': 'error', 'message': str(e)}), 500 | |
| def delete_product(product_id): | |
| try: | |
| logger.info(f"Deleting product with id={product_id}") | |
| # Удаление продукта из данных и сохранение | |
| data['products'] = [p for p in data.get('products', []) if p['id'] != product_id] | |
| save_data(data) | |
| return jsonify({'status': 'success'}) | |
| except Exception as e: | |
| logger.error(f"Ошибка при удалении товара: {e}") | |
| return jsonify({'status': 'error', 'message': str(e)}), 500 | |
| # Запуск бота и Flask | |
| async def on_startup(_): | |
| logger.info("Бот запущен!") | |
| def run_flask(): | |
| try: | |
| logger.info("Starting Flask server on port 7860") | |
| # Запуск Flask приложения | |
| app.run(host='0.0.0.0', port=7860) | |
| except Exception as e: | |
| logger.error(f"Ошибка в Flask: {e}") | |
| if __name__ == '__main__': | |
| # Создаем и запускаем поток для Flask | |
| flask_thread = threading.Thread(target=run_flask, daemon=True) | |
| flask_thread.start() | |
| logger.info("Flask thread started") | |
| # Запускаем бота в главном потоке | |
| try: | |
| asyncio.run(dp.start_polling(bot, on_startup=on_startup)) | |
| except KeyboardInterrupt: | |
| logger.info("Stopping bot and Flask") | |
| finally: | |
| flask_thread.join() # Ждем завершения потока Flask при завершении программы | |