Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -11,7 +11,7 @@ import threading
|
|
| 11 |
|
| 12 |
# Настройка логирования
|
| 13 |
logging.basicConfig(level=logging.INFO)
|
| 14 |
-
logger = logging.getLogger(__name__)
|
| 15 |
|
| 16 |
# Инициализация бота и Flask
|
| 17 |
BOT_TOKEN = '7734802681:AAGKHGG8O9uNk64JWTHH5yqXzvSxCcoLUdA'
|
|
@@ -67,10 +67,8 @@ async def show_products(message: types.Message):
|
|
| 67 |
await message.answer("Нет доступных товаров.")
|
| 68 |
return
|
| 69 |
for product in data['products']:
|
| 70 |
-
await message.answer(
|
| 71 |
-
|
| 72 |
-
reply_markup=get_product_keyboard(product['id'])
|
| 73 |
-
)
|
| 74 |
|
| 75 |
@dp.message(F.text == "🛒 Корзина")
|
| 76 |
async def show_cart(message: types.Message):
|
|
@@ -100,11 +98,7 @@ async def add_to_cart(callback_query: types.CallbackQuery):
|
|
| 100 |
if not cart:
|
| 101 |
cart = {'user_id': user_id, 'items': [], 'completed': False, 'date': datetime.now().isoformat()}
|
| 102 |
data['orders'].append(cart)
|
| 103 |
-
|
| 104 |
-
if cart_item:
|
| 105 |
-
cart_item['quantity'] += 1
|
| 106 |
-
else:
|
| 107 |
-
cart['items'].append({'product_id': product_id, 'quantity': 1})
|
| 108 |
save_data(data)
|
| 109 |
await bot.answer_callback_query(callback_query.id, "Товар добавлен в корзину!")
|
| 110 |
else:
|
|
@@ -139,81 +133,100 @@ async def show_orders(message: types.Message):
|
|
| 139 |
response += f"\nИтого: {total} руб.\nДата: {order['date']}"
|
| 140 |
await message.answer(response)
|
| 141 |
|
| 142 |
-
# Админ-панель (Flask) с HTML
|
| 143 |
admin_html = """
|
| 144 |
<!DOCTYPE html>
|
| 145 |
<html>
|
| 146 |
<head>
|
| 147 |
-
<title>Админ-панель</title>
|
| 148 |
-
<style>
|
| 149 |
-
body { font-family: Arial; background-color: #f0f0f0;
|
| 150 |
-
.container { max-width: 800px; margin: auto; }
|
| 151 |
-
.product { border: 1px solid #ccc; padding:
|
| 152 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
</head>
|
| 154 |
<body>
|
| 155 |
-
<div class="container">
|
| 156 |
-
<h1>Управление товарами</h1>
|
| 157 |
-
<form id="addProductForm">
|
| 158 |
-
<input type="text" name="name" placeholder="Название" required><br>
|
| 159 |
-
<input type="number" name="price" placeholder="Цена" required><br>
|
| 160 |
-
<textarea name="description" placeholder="Описание"></textarea><br>
|
| 161 |
-
<button type="submit">Добавить товар</button>
|
| 162 |
-
</form>
|
| 163 |
-
<h2>Существующие товары</h2>
|
| 164 |
-
{%
|
| 165 |
-
|
| 166 |
-
<
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
{
|
| 170 |
-
|
| 171 |
-
{%
|
| 172 |
-
|
| 173 |
-
<
|
| 174 |
-
|
| 175 |
-
<
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
}
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
}
|
| 187 |
-
|
| 188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
@app.route('/')
|
| 191 |
def admin_panel():
|
| 192 |
try:
|
| 193 |
-
logger.info(
|
| 194 |
-
return render_template_string(admin_html, products=data
|
| 195 |
except Exception as e:
|
| 196 |
logger.error(f"Ошибка в шаблоне: {e}")
|
| 197 |
-
return "Ошибка сервера.
|
| 198 |
|
| 199 |
@app.route('/add_product', methods=['POST'])
|
| 200 |
def add_product():
|
| 201 |
try:
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
data.setdefault('products', []).append({'id': product_id, 'name': name, 'price': price, 'description': description})
|
| 212 |
-
|
| 213 |
-
save_data(data)
|
| 214 |
-
|
| 215 |
-
return jsonify({'status': 'success'})
|
| 216 |
-
|
| 217 |
except Exception as e:
|
| 218 |
logger.error(f"Ошибка при добавлении товара: {e}")
|
| 219 |
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
@@ -222,14 +235,9 @@ def add_product():
|
|
| 222 |
def delete_product(product_id):
|
| 223 |
try:
|
| 224 |
logger.info(f"Deleting product with id={product_id}")
|
| 225 |
-
|
| 226 |
-
# Удаление продукта из данных и сохранение
|
| 227 |
-
data['products'] = [p for p in data.get('products', []) if p['id'] != product_id]
|
| 228 |
-
|
| 229 |
save_data(data)
|
| 230 |
-
|
| 231 |
return jsonify({'status': 'success'})
|
| 232 |
-
|
| 233 |
except Exception as e:
|
| 234 |
logger.error(f"Ошибка при удалении товара: {e}")
|
| 235 |
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
@@ -241,15 +249,12 @@ async def on_startup(_):
|
|
| 241 |
def run_flask():
|
| 242 |
try:
|
| 243 |
logger.info("Starting Flask server on port 7860")
|
| 244 |
-
|
| 245 |
-
# Запуск Flask приложения
|
| 246 |
app.run(host='0.0.0.0', port=7860)
|
| 247 |
-
|
| 248 |
except Exception as e:
|
| 249 |
logger.error(f"Ошибка в Flask: {e}")
|
| 250 |
|
| 251 |
if __name__ == '__main__':
|
| 252 |
-
#
|
| 253 |
flask_thread = threading.Thread(target=run_flask, daemon=True)
|
| 254 |
flask_thread.start()
|
| 255 |
logger.info("Flask thread started")
|
|
@@ -260,4 +265,4 @@ if __name__ == '__main__':
|
|
| 260 |
except KeyboardInterrupt:
|
| 261 |
logger.info("Stopping bot and Flask")
|
| 262 |
finally:
|
| 263 |
-
flask_thread.join() #
|
|
|
|
| 11 |
|
| 12 |
# Настройка логирования
|
| 13 |
logging.basicConfig(level=logging.INFO)
|
| 14 |
+
logger = logging.getLogger(__name__)
|
| 15 |
|
| 16 |
# Инициализация бота и Flask
|
| 17 |
BOT_TOKEN = '7734802681:AAGKHGG8O9uNk64JWTHH5yqXzvSxCcoLUdA'
|
|
|
|
| 67 |
await message.answer("Нет доступных товаров.")
|
| 68 |
return
|
| 69 |
for product in data['products']:
|
| 70 |
+
await message.answer(f"🏷 {product['name']} - {product['price']} руб.\nОписание: {product['description']}\n/id: {product['id']}",
|
| 71 |
+
reply_markup=get_product_keyboard(product['id']))
|
|
|
|
|
|
|
| 72 |
|
| 73 |
@dp.message(F.text == "🛒 Корзина")
|
| 74 |
async def show_cart(message: types.Message):
|
|
|
|
| 98 |
if not cart:
|
| 99 |
cart = {'user_id': user_id, 'items': [], 'completed': False, 'date': datetime.now().isoformat()}
|
| 100 |
data['orders'].append(cart)
|
| 101 |
+
cart['items'].append({'product_id': product_id, 'quantity': 1})
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
save_data(data)
|
| 103 |
await bot.answer_callback_query(callback_query.id, "Товар добавлен в корзину!")
|
| 104 |
else:
|
|
|
|
| 133 |
response += f"\nИтого: {total} руб.\nДата: {order['date']}"
|
| 134 |
await message.answer(response)
|
| 135 |
|
| 136 |
+
# Админ-панель (Flask) с HTML, CSS и JavaScript в строке
|
| 137 |
admin_html = """
|
| 138 |
<!DOCTYPE html>
|
| 139 |
<html>
|
| 140 |
<head>
|
| 141 |
+
<title>Админ-панель</title>
|
| 142 |
+
<style>
|
| 143 |
+
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f0f0f0; }
|
| 144 |
+
.container { max-width: 800px; margin: 0 auto; }
|
| 145 |
+
.product { border: 1px solid #ccc; padding: 15px; margin: 10px 0; background-color: #fff; border-radius: 5px; }
|
| 146 |
+
form { background-color: #fff; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
|
| 147 |
+
input, textarea { width: 100%; margin: 5px 0; padding: 8px; }
|
| 148 |
+
button { background-color: #4CAF50; color: white; padding: 10px 15px; border: none; border-radius: 5px; cursor: pointer; }
|
| 149 |
+
button:hover { background-color: #45a049; }
|
| 150 |
+
</style>
|
| 151 |
</head>
|
| 152 |
<body>
|
| 153 |
+
<div class="container">
|
| 154 |
+
<h1>Управление товарами</h1>
|
| 155 |
+
<form id="addProductForm">
|
| 156 |
+
<input type="text" name="name" placeholder="Название" required><br>
|
| 157 |
+
<input type="number" name="price" placeholder="Цена" step="0.01" required><br>
|
| 158 |
+
<textarea name="description" placeholder="Описание" required></textarea><br>
|
| 159 |
+
<button type="submit">Добавить товар</button>
|
| 160 |
+
</form>
|
| 161 |
+
<h2>Существующие товары</h2>
|
| 162 |
+
{% if products %}
|
| 163 |
+
{% for product in products %}
|
| 164 |
+
<div class="product">
|
| 165 |
+
{{ product.name }} - {{ product.price }} руб.<br>
|
| 166 |
+
{{ product.description }}<br>
|
| 167 |
+
<button onclick="deleteProduct({{ product.id }})">Удалить</button>
|
| 168 |
+
</div>
|
| 169 |
+
{% endfor %}
|
| 170 |
+
{% else %}
|
| 171 |
+
<p>Нет товаров.</p>
|
| 172 |
+
{% endif %}
|
| 173 |
+
<h2>Заказы</h2>
|
| 174 |
+
{% if orders %}
|
| 175 |
+
{% for order in orders %}
|
| 176 |
+
<div class="product">
|
| 177 |
+
Пользователь: {{ order.user_id }}<br>
|
| 178 |
+
Дата: {{ order.date }}<br>
|
| 179 |
+
Товары:
|
| 180 |
+
{% for item in order.items %}
|
| 181 |
+
{% for product in products %}
|
| 182 |
+
{% if product.id == item.product_id %}
|
| 183 |
+
{{ item.quantity }} x {{ product.name }}<br>
|
| 184 |
+
{% endif %}
|
| 185 |
+
{% endfor %}
|
| 186 |
+
{% endfor %}
|
| 187 |
+
</div>
|
| 188 |
+
{% endfor %}
|
| 189 |
+
{% else %}
|
| 190 |
+
<p>Нет заказов.</p>
|
| 191 |
+
{% endif %}
|
| 192 |
+
</div>
|
| 193 |
+
<script>
|
| 194 |
+
document.getElementById('addProductForm').onsubmit = async (e) => {
|
| 195 |
+
e.preventDefault();
|
| 196 |
+
const formData = new FormData(e.target);
|
| 197 |
+
const response = await fetch('/add_product', { method: 'POST', body: formData });
|
| 198 |
+
if (response.ok) window.location.reload();
|
| 199 |
+
};
|
| 200 |
+
async function deleteProduct(productId) {
|
| 201 |
+
const response = await fetch(`/delete_product/${productId}`, { method: 'POST' });
|
| 202 |
+
if (response.ok) window.location.reload();
|
| 203 |
+
}
|
| 204 |
+
</script>
|
| 205 |
+
</body>
|
| 206 |
+
</html>
|
| 207 |
+
"""
|
| 208 |
|
| 209 |
@app.route('/')
|
| 210 |
def admin_panel():
|
| 211 |
try:
|
| 212 |
+
logger.info("Rendering admin panel with products and orders")
|
| 213 |
+
return render_template_string(admin_html, products=data['products'], orders=data['orders'])
|
| 214 |
except Exception as e:
|
| 215 |
logger.error(f"Ошибка в шаблоне: {e}")
|
| 216 |
+
return "Ошибка сервера. Проверь логи.", 500
|
| 217 |
|
| 218 |
@app.route('/add_product', methods=['POST'])
|
| 219 |
def add_product():
|
| 220 |
try:
|
| 221 |
+
if request.method == 'POST':
|
| 222 |
+
logger.info("Adding new product")
|
| 223 |
+
name = request.form['name']
|
| 224 |
+
price = float(request.form['price'])
|
| 225 |
+
description = request.form['description']
|
| 226 |
+
product_id = max((p['id'] for p in data['products']), default=0) + 1
|
| 227 |
+
data['products'].append({'id': product_id, 'name': name, 'price': price, 'description': description})
|
| 228 |
+
save_data(data)
|
| 229 |
+
return jsonify({'status': 'success'})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
except Exception as e:
|
| 231 |
logger.error(f"Ошибка при добавлении товара: {e}")
|
| 232 |
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
|
|
| 235 |
def delete_product(product_id):
|
| 236 |
try:
|
| 237 |
logger.info(f"Deleting product with id={product_id}")
|
| 238 |
+
data['products'] = [p for p in data['products'] if p['id'] != product_id]
|
|
|
|
|
|
|
|
|
|
| 239 |
save_data(data)
|
|
|
|
| 240 |
return jsonify({'status': 'success'})
|
|
|
|
| 241 |
except Exception as e:
|
| 242 |
logger.error(f"Ошибка при удалении товара: {e}")
|
| 243 |
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
|
|
| 249 |
def run_flask():
|
| 250 |
try:
|
| 251 |
logger.info("Starting Flask server on port 7860")
|
|
|
|
|
|
|
| 252 |
app.run(host='0.0.0.0', port=7860)
|
|
|
|
| 253 |
except Exception as e:
|
| 254 |
logger.error(f"Ошибка в Flask: {e}")
|
| 255 |
|
| 256 |
if __name__ == '__main__':
|
| 257 |
+
# Создаём и запускаем поток для Flask
|
| 258 |
flask_thread = threading.Thread(target=run_flask, daemon=True)
|
| 259 |
flask_thread.start()
|
| 260 |
logger.info("Flask thread started")
|
|
|
|
| 265 |
except KeyboardInterrupt:
|
| 266 |
logger.info("Stopping bot and Flask")
|
| 267 |
finally:
|
| 268 |
+
flask_thread.join() # Ждём завершения потока Flask при завершении программы
|