Files
2026-08-14 10:55:06 +08:00

144 lines
7.2 KiB
PHP
Raw Permalink 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
// 商品详情 + 加入购物车
require __DIR__ . '/includes/init.php';
$pageTitle = __('product.detail');
$id = (int) ($_GET['id'] ?? 0);
$stmt = db()->prepare('SELECT * FROM ' . tn('products') . ' WHERE id = ? AND status = 1');
$stmt->execute([$id]);
$product = $stmt->fetch();
if (!$product) {
header('Location: index.php');
exit;
}
// 当前登录用户是否已购买该商品,并取最新发货 / 商品信息
$hasBought = false;
$purchase = null;
if ($user = currentUser()) {
$bstmt = db()->prepare(
'SELECT 1 FROM ' . tn('orders') . ' o
INNER JOIN ' . tn('order_items') . ' oi ON oi.order_id = o.id
WHERE o.user_id = ? AND oi.product_id = ? AND o.status IN ("paid","shipped","completed") LIMIT 1'
);
$bstmt->execute([$user['id'], $id]);
$hasBought = (bool) $bstmt->fetchColumn();
$pstmt = db()->prepare(
'SELECT d.* FROM ' . tn('order_deliveries') . ' d
INNER JOIN ' . tn('orders') . ' o ON o.id = d.order_id
INNER JOIN ' . tn('order_items') . ' oi ON oi.order_id = o.id
WHERE o.user_id = ? AND oi.product_id = ? AND o.status IN ("paid","shipped","completed")
ORDER BY d.id DESC LIMIT 1'
);
$pstmt->execute([$user['id'], $id]);
$purchase = $pstmt->fetch();
}
$err = $ok = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add'])) {
verifyCsrf();
$qty = max(1, (int) ($_POST['qty'] ?? 1));
if ($product['stock'] <= 0) {
$err = __('product_page.err_out_of_stock');
} elseif ($qty > $product['stock']) {
$err = str_replace('{max}', $product['stock'], __('product_page.err_low_stock'));
} else {
if (!isset($_SESSION['cart'])) $_SESSION['cart'] = [];
$cur = (int) ($_SESSION['cart'][$id] ?? 0);
$_SESSION['cart'][$id] = $cur + $qty;
header('Location: cart.php');
exit;
}
}
require 'includes/header.php';
?>
<section class="section">
<a href="index.php" class="back-link"><i class="fas fa-arrow-left"></i> <?= __('product_page.back_list') ?></a>
<div class="product-detail">
<div class="pd-media">
<?php if (!empty($product['image'])): ?>
<img src="<?= h($product['image']) ?>" alt="<?= h($product['name']) ?>">
<?php else: ?>
<i class="fas <?= h($product['icon']) ?>"></i>
<?php endif; ?>
</div>
<div class="pd-info">
<span class="pc-cat"><?= h($product['category']) ?></span>
<h1 class="pd-name"><?= h($product['name']) ?></h1>
<?php if (!empty($product['points_price'])): ?>
<div class="pd-price"><?= __('product_page.points_price_label') ?><strong><?= (int) $product['points_price'] ?></strong><?= __('product_page.points_suffix') ?></div>
<?php else: ?>
<div class="pd-price"><?= __('product_page.cash_price_label') ?></div>
<?php endif; ?>
<div class="pd-stock"><?= __('product_page.stock_label') ?><?= (int) $product['stock'] ?><?= __('product_page.stock_unit') ?></div>
<?php if (!empty($product['period_days'])): ?>
<div class="pd-period"><i class="fas fa-clock"></i> <?= __('product_page.period_label') ?><?= periodLabel($product['period_days']) ?></div>
<?php endif; ?>
<p class="pd-desc"><?= nl2br(h($product['description'] ?? '')) ?></p>
<?php if ($err): ?><p class="form-err"><?= h($err) ?></p><?php endif; ?>
<?php if ($product['stock'] > 0): ?>
<form method="post" action="" class="pd-buy">
<?= csrfField() ?>
<label><?= __('product_page.qty_label') ?>
<input type="number" name="qty" value="1" min="1" max="<?= (int)$product['stock'] ?>" class="qty-input">
</label>
<button type="submit" name="add" class="btn btn-primary"><i class="fas fa-cart-plus"></i> <?= __('product_page.add_cart_btn') ?></button>
</form>
<?php else: ?>
<p class="sold-out"><?= __('product_page.sold_out') ?></p>
<?php endif; ?>
</div>
</div>
</section>
<?php if ($hasBought): ?>
<section class="section">
<div class="pd-purchased">
<div class="pp-head">
<i class="fas fa-check-circle"></i>
<span class="pp-title"><?= __('product_page.purchased_title') ?></span>
<button type="button" class="btn btn-ghost btn-sm" id="ppToggle"><?= __('product_page.purchased_toggle') ?></button>
</div>
<div class="pp-detail" id="ppDetail" style="display:none;">
<?php if ($purchase): ?>
<div class="od-line"><?= __('status') ?><span class="badge-<?= !empty($purchase['activated']) ? 'on' : 'off' ?>"><?= !empty($purchase['activated']) ? __('product_page.purchased_activated') : __('product_page.purchased_not_activated') ?></span></div>
<?php if ($purchase['product_info'] !== ''): ?>
<div class="od-line od-info-block"><?= __('product_page.purchased_product_info') ?><?= nl2br(h($purchase['product_info'])) ?></div>
<?php endif; ?>
<?php if ($purchase['server_ip'] !== '' || $purchase['conn_addr'] !== '' || $purchase['login_user'] !== '' || $purchase['login_pass'] !== ''): ?>
<div class="od-line"><?= __('product_page.server_ip') ?><?= h($purchase['server_ip']) ?: __('product_page.none_value') ?></div>
<div class="od-line"><?= __('product_page.conn_addr') ?><?= h($purchase['conn_addr']) ?: __('product_page.none_value') ?></div>
<div class="od-line"><?= __('product_page.login_user') ?><?= h($purchase['login_user']) ?: __('product_page.none_value') ?></div>
<div class="od-line"><?= __('product_page.login_pass') ?>
<span class="secret" data-secret="<?= h($purchase['login_pass']) ?>"><?= $purchase['login_pass'] !== '' ? str_repeat('●', max(6, mb_strlen($purchase['login_pass']))) : __('product_page.none_value') ?></span>
<?php if ($purchase['login_pass'] !== ''): ?><button type="button" class="mini-btn reveal-btn"><?= __('product_page.reveal_btn') ?></button><?php endif; ?>
</div>
<?php endif; ?>
<?php if ($purchase['remark'] !== ''): ?>
<div class="od-line"><?= __('product_page.remark_label') ?><?= nl2br(h($purchase['remark'])) ?></div>
<?php endif; ?>
<?php else: ?>
<p class="muted"><?= __('product_page.pending_delivery') ?></p>
<?php endif; ?>
</div>
</div>
</section>
<script>
(function () {
var btn = document.getElementById('ppToggle');
var box = document.getElementById('ppDetail');
if (!btn || !box) return;
btn.addEventListener('click', function () {
var open = box.style.display === 'none';
box.style.display = open ? 'block' : 'none';
btn.textContent = open ? '<?= __('product_page.purchased_toggle_close') ?>' : '<?= __('product_page.purchased_toggle') ?>';
});
})();
</script>
<?php endif; ?>
<?php require 'includes/footer.php'; ?>