Files
web_work/public/product.php
kirill.khorkov 29b9aaac50 Исправление багов авторизации, корзины и админки
- Исправлено выпадающее меню профиля (hover-баг с margin-top)
- Исправлена авторизация: правильные пути к API (api/auth.php)
- Исправлены ссылки на админку (admin/index.php вместо admin_panel.php)
- Исправлены пути API корзины в catalog.php и checkout.php
- Добавлена форма добавления/редактирования товаров в админке
- Исправлены кнопки +/- в корзине (улучшена обработка AJAX)
- Исправлена регистрация: правильные пути и обработка boolean в PostgreSQL
- Добавлена миграция для назначения прав админа пользователю admin@mail.ru
- Удален тестовый блок 'Быстрый вход' для неавторизованных пользователей
- Улучшена обработка ошибок во всех API-эндпоинтах
2025-12-16 02:58:44 +03:00

492 lines
18 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// product_page.php
session_start();
require_once __DIR__ . '/../config/database.php';
// Проверка авторизации
if (!isset($_SESSION['isLoggedIn']) || $_SESSION['isLoggedIn'] !== true) {
header('Location: login.php?error=auth_required&redirect=' . urlencode($_SERVER['REQUEST_URI']));
exit();
}
if (!isset($_GET['id'])) {
header('Location: catalog.php');
exit();
}
$product_id = intval($_GET['id']);
$db = Database::getInstance()->getConnection();
try {
// Получаем информацию о товаре
$productStmt = $db->prepare("
SELECT
p.*,
c.name as category_name,
c.slug as category_slug
FROM products p
LEFT JOIN categories c ON p.category_id = c.category_id
WHERE p.product_id = ? AND p.is_available = TRUE
");
$productStmt->execute([$product_id]);
$product = $productStmt->fetch();
if (!$product) {
header('Location: catalog.php?error=product_not_found');
exit();
}
// Получаем похожие товары
$similarStmt = $db->prepare("
SELECT * FROM products
WHERE category_id = ?
AND product_id != ?
AND is_available = TRUE
ORDER BY RANDOM()
LIMIT 3
");
$similarStmt->execute([$product['category_id'], $product_id]);
$similarProducts = $similarStmt->fetchAll();
// Получаем отзывы (если есть отдельная таблица reviews)
$reviewsStmt = $db->prepare("
SELECT rating, comment, created_at
FROM reviews
WHERE product_id = ?
ORDER BY created_at DESC
LIMIT 5
");
$reviewsStmt->execute([$product_id]);
$reviews = $reviewsStmt->fetchAll();
} catch (PDOException $e) {
die("Ошибка базы данных: " . $e->getMessage());
}
// HTML код страницы товара
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AETERNA - <?= htmlspecialchars($product['name']) ?></title>
<link rel="stylesheet/less" type="text/css" href="style_for_cite.less">
<script src="https://cdn.jsdelivr.net/npm/less"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<style>
.product-attributes {
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
}
.attribute-row {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #ddd;
}
.attribute-label {
font-weight: bold;
color: #453227;
}
.attribute-value {
color: #617365;
}
.stock-status {
font-weight: bold;
padding: 5px 10px;
border-radius: 4px;
display: inline-block;
}
.in-stock {
background: #d4edda;
color: #155724;
}
.low-stock {
background: #fff3cd;
color: #856404;
}
.out-of-stock {
background: #f8d7da;
color: #721c24;
}
</style>
</head>
<body>
<header class="header">
<div class="header__top">
<div class="container header__top-content">
<div class="logo">AETERNA</div>
<div class="search-catalog">
<div class="catalog-dropdown">
Все категории <span>&#9660;</span>
<div class="catalog-dropdown__menu">
<ul>
<li><a href="#">Диваны</a></li>
<li><a href="#">Кровати</a></li>
<li><a href="#">Шкафы</a></li>
<li><a href="#">Стулья</a></li>
<li><a href="#">Столы</a></li>
</ul>
</div>
</div>
<div class="search-box">
<input type="text" placeholder="Поиск товаров">
<span class="search-icon"><i class="fas fa-search"></i></span>
</div>
</div>
<div class="header__icons--top">
<a href="checkout.php" class="icon"><i class="fas fa-shopping-cart"></i></a>
<a href="register.php" class="icon"><i class="far fa-user"></i></a>
</div>
</div>
</div>
<div class="header__bottom">
<div class="container header__bottom-content">
<div class="catalog-menu">
<a href="/catalog.php" class="catalog-link active-catalog">
<div class="catalog-icon">
<span class="line"></span>
<span class="line"></span>
<span class="line"></span>
</div>
<span class="catalog-lines">☰</span>
Каталог
</a>
</div>
<nav class="nav">
<ul class="nav-list">
<li><a href="cite_mebel.php">Главная</a></li>
<li><a href="services.php">Услуги</a></li>
<li><a href="delivery.php">Доставка и оплата</a></li>
<li><a href="warranty.php">Гарантия</a></li>
<li><a href="#footer">Контакты</a></li>
</ul>
</nav>
<div class="header-phone">+7(912)999-12-23</div>
</div>
</div>
</header>
<main class="container">
<div class="breadcrumbs">
<a href="cite_mebel.php">Главная</a> •
<a href="/catalog.php">Каталог</a> •
<?php if ($product['category_name']): ?>
<a href="/catalog.php?category=<?= $product['category_id'] ?>">
<?= htmlspecialchars($product['category_name']) ?>
</a> •
<?php endif; ?>
<span><?= htmlspecialchars($product['name']) ?></span>
</div>
<div class="product__section">
<div class="product__gallery">
<div class="product__main-image">
<img src="<?= htmlspecialchars($product['image_url'] ?? 'img1/default.jpg') ?>"
alt="<?= htmlspecialchars($product['name']) ?>"
id="mainImage">
</div>
</div>
<div class="product__info">
<h1><?= htmlspecialchars($product['name']) ?></h1>
<div class="product__rating">
<div class="stars">
<?php
$rating = $product['rating'] ?? 0;
$fullStars = floor($rating);
$hasHalfStar = $rating - $fullStars >= 0.5;
for ($i = 1; $i <= 5; $i++) {
if ($i <= $fullStars) {
echo '<span class="star filled">★</span>';
} elseif ($i == $fullStars + 1 && $hasHalfStar) {
echo '<span class="star half">★</span>';
} else {
echo '<span class="star">☆</span>';
}
}
?>
</div>
<span class="rating-value"><?= number_format($rating, 1) ?></span>
<span class="reviews-count">(<?= $product['review_count'] ?> отзывов)</span>
</div>
<div class="product__price">
<span class="current-price">
<?= number_format($product['price'], 0, '', ' ') ?> ₽
</span>
<?php if ($product['old_price'] && $product['old_price'] > $product['price']): ?>
<span class="old-price">
<?= number_format($product['old_price'], 0, '', ' ') ?> ₽
</span>
<span class="discount-badge">
-<?= round(($product['old_price'] - $product['price']) / $product['old_price'] * 100) ?>%
</span>
<?php endif; ?>
</div>
<div class="stock-status <?php
if ($product['stock_quantity'] > 10) echo 'in-stock';
elseif ($product['stock_quantity'] > 0) echo 'low-stock';
else echo 'out-of-stock';
?>">
<?php
if ($product['stock_quantity'] > 10) {
echo '<i class="fas fa-check-circle"></i> В наличии';
} elseif ($product['stock_quantity'] > 0) {
echo '<i class="fas fa-exclamation-circle"></i> Осталось мало: ' . $product['stock_quantity'] . ' шт.';
} else {
echo '<i class="fas fa-times-circle"></i> Нет в наличии';
}
?>
</div>
<div class="product-attributes">
<div class="attribute-row">
<span class="attribute-label">Артикул:</span>
<span class="attribute-value"><?= $product['sku'] ?? 'N/A' ?></span>
</div>
<div class="attribute-row">
<span class="attribute-label">Категория:</span>
<span class="attribute-value"><?= htmlspecialchars($product['category_name'] ?? 'Без категории') ?></span>
</div>
<div class="attribute-row">
<span class="attribute-label">На складе:</span>
<span class="attribute-value"><?= $product['stock_quantity'] ?> шт.</span>
</div>
</div>
<p class="product__description">
<?= nl2br(htmlspecialchars($product['description'] ?? 'Описание отсутствует')) ?>
</p>
<?php if ($product['stock_quantity'] > 0): ?>
<div class="product__purchase">
<div class="product__quantity">
<button class="product__qty-btn minus">-</button>
<input type="number" class="product__qty-value" value="1" min="1" max="<?= $product['stock_quantity'] ?>">
<button class="product__qty-btn plus">+</button>
</div>
<div class="product__actions">
<button class="btn primary-btn" onclick="addToCart(<?= $product['product_id'] ?>)">
<i class="fas fa-shopping-cart"></i> В корзину
</button>
<button class="btn secondary-btn" onclick="buyNow(<?= $product['product_id'] ?>)">
<i class="fas fa-bolt"></i> Купить сейчас
</button>
</div>
</div>
<?php else: ?>
<div class="product__actions">
<button class="btn secondary-btn" onclick="notifyWhenAvailable(<?= $product['product_id'] ?>)">
<i class="fas fa-bell"></i> Уведомить о поступлении
</button>
</div>
<?php endif; ?>
<?php if (isset($_SESSION['isAdmin']) && $_SESSION['isAdmin']): ?>
<div class="admin-actions" style="margin-top: 20px;">
<a href="admin_panel.php?action=edit&id=<?= $product['product_id'] ?>"
class="btn btn-warning">
<i class="fas fa-edit"></i> Редактировать
</a>
<button onclick="deleteProduct(<?= $product['product_id'] ?>)"
class="btn btn-danger">
<i class="fas fa-trash"></i> Удалить
</button>
</div>
<?php endif; ?>
</div>
</div>
<?php if (!empty($similarProducts)): ?>
<section class="similar-products">
<h2>Похожие товары</h2>
<div class="products-grid">
<?php foreach ($similarProducts as $similar): ?>
<div class="product-card">
<div class="product-image">
<img src="<?= htmlspecialchars($similar['image_url'] ?? 'img2/default.jpg') ?>"
alt="<?= htmlspecialchars($similar['name']) ?>">
</div>
<div class="product-info">
<h3><?= htmlspecialchars($similar['name']) ?></h3>
<p class="product-price">
<?= number_format($similar['price'], 0, '', ' ') ?> ₽
</p>
<a href="product_page.php?id=<?= $similar['product_id'] ?>"
class="btn btn-primary">
Подробнее
</a>
</div>
</div>
<?php endforeach; ?>
</div>
</section>
<?php endif; ?>
</main>
<footer class="footer" id="footer">
<div class="container footer__content">
<div class="footer__col footer--logo">
<div class="logo">AETERNA</div>
</div>
<div class="footer__col">
<h5>ПОКУПАТЕЛЮ</h5>
<ul>
<li><a href="/catalog.php">Каталог</a></li>
<li><a href="services.php">Услуги</a></li>
</ul>
</div>
<div class="footer__col">
<h5>ПОМОЩЬ</h5>
<ul>
<li><a href="delivery.php">Доставка и оплата</a></li>
<li><a href="warranty.php">Гарантия и возврат</a></li>
<li><a href="cite_mebel.php#faq">Ответы на вопросы</a></li>
<li><a href="#footer">Контакты</a></li>
</ul>
</div>
<div class="footer__col">
<h5>КОНТАКТЫ</h5>
<p>aeterna@mail.ru</p>
<p>+7(912)999-12-23</p>
<div class="social-icons">
<span class="icon"><i class="fab fa-telegram"></i></span>
<span class="icon"><i class="fab fa-instagram"></i></span>
<span class="icon"><i class="fab fa-vk"></i></span>
</div>
</div>
<div class="footer__col">
<h5>ПРИНИМАЕМ К ОПЛАТЕ</h5>
<div class="payment-icons">
<span class="pay-icon"><i class="fab fa-cc-visa"></i></span>
<span class="pay-icon"><i class="fab fa-cc-mastercard"></i></span>
</div>
</div>
</div>
<div class="copyright">
<p>© 2025 AETERNA. Все права защищены.</p>
</div>
</footer>
<script>
$(document).ready(function() {
// Управление количеством
$('.product__qty-btn.plus').click(function() {
const $input = $('.product__qty-value');
let value = parseInt($input.val());
let max = parseInt($input.attr('max'));
if (value < max) {
$input.val(value + 1);
}
});
$('.product__qty-btn.minus').click(function() {
const $input = $('.product__qty-value');
let value = parseInt($input.val());
if (value > 1) {
$input.val(value - 1);
}
});
// Добавление в корзину
window.addToCart = function(productId) {
const quantity = $('.product__qty-value').val();
$.ajax({
url: 'add_to_cart.php',
method: 'POST',
data: {
product_id: productId,
quantity: quantity
},
success: function(response) {
try {
const result = JSON.parse(response);
if (result.success) {
alert('Товар добавлен в корзину!');
// Обновляем счетчик в шапке
$('.cart-count').text(result.cart_count);
} else {
alert('Ошибка: ' + result.message);
}
} catch(e) {
alert('Товар добавлен в корзину!');
}
}
});
};
// Покупка сейчас
window.buyNow = function(productId) {
const quantity = $('.product__qty-value').val();
$.ajax({
url: 'add_to_cart.php',
method: 'POST',
data: {
product_id: productId,
quantity: quantity
},
success: function() {
window.location.href = 'checkout.php';
}
});
};
// Уведомление о поступлении
window.notifyWhenAvailable = function(productId) {
const email = prompt('Введите ваш email для уведомления:');
if (email) {
$.ajax({
url: 'notify_available.php',
method: 'POST',
data: {
product_id: productId,
email: email
},
success: function(response) {
alert('Вы будете уведомлены о поступлении товара!');
}
});
}
};
// Удаление товара (админ)
window.deleteProduct = function(productId) {
if (confirm('Вы уверены, что хотите удалить этот товар?')) {
$.ajax({
url: 'catalog_admin_action.php',
method: 'POST',
data: {
action: 'delete',
product_id: productId
},
success: function() {
window.location.href = 'catalog.php';
}
});
}
};
});
</script>
</body>
</html>