120 lines
6.0 KiB
PHP
Executable File
120 lines
6.0 KiB
PHP
Executable File
<?php
|
||
require_once __DIR__ . '/includes/auth.php';
|
||
require_once __DIR__ . '/includes/functions.php';
|
||
requireLogin();
|
||
|
||
$pageTitle = '兑换码领取';
|
||
require __DIR__ . '/includes/header.php';
|
||
|
||
$msg = '';
|
||
$pid = getCurrentProductId();
|
||
|
||
// 获取所有面值及对应可领取数量
|
||
$stmt = $pdo->prepare("SELECT value, COUNT(*) AS cnt FROM redemption_codes WHERE status = 1 AND (expired_at IS NULL OR expired_at > NOW()) AND product_id = ? GROUP BY value ORDER BY value ASC");
|
||
$stmt->execute([$pid]);
|
||
$valueOptions = $stmt->fetchAll();
|
||
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
if (!verifyCsrf($_POST['csrf_token'] ?? '')) { die('CSRF token无效'); }
|
||
$codeValue = trim($_POST['code_value'] ?? '');
|
||
$quantity = max(1, min(100, (int)($_POST['quantity'] ?? 1)));
|
||
|
||
// 校验面值是否有效
|
||
$validValues = array_map(fn($v) => $v['value'], $valueOptions);
|
||
if (!in_array($codeValue, $validValues, true)) {
|
||
$msg = '<div class="alert alert-danger">无效的面值</div>';
|
||
} else {
|
||
// 检查当前用户未使用兑换码数量
|
||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM claim_records WHERE user_id = ? AND product_id = ? AND status = 1");
|
||
$stmt->execute([getCurrentUserId(), $pid]);
|
||
$unusedCount = (int)$stmt->fetchColumn();
|
||
if ($unusedCount >= 200) {
|
||
$msg = '<div class="alert alert-danger">您当前未使用的兑换码已达 ' . $unusedCount . ' 条(上限200条),请先使用后再领取</div>';
|
||
} else {
|
||
// 检查频繁领取(同面值距上一次领取不足3天)
|
||
$stmt = $pdo->prepare("SELECT MAX(claimed_at) FROM claim_records WHERE user_id = ? AND product_id = ? AND value = ?");
|
||
$stmt->execute([getCurrentUserId(), $pid, $codeValue]);
|
||
$lastClaim = $stmt->fetchColumn();
|
||
if ($lastClaim && strtotime($lastClaim) > strtotime('-3 days')) {
|
||
$remaining = ceil((strtotime($lastClaim) + 3 * 86400 - time()) / 3600);
|
||
$msg = '<div class="alert alert-danger">当前面值兑换码距上次领取不足3天,请 ' . $remaining . ' 小时后再领取</div>';
|
||
} else {
|
||
$pdo->beginTransaction();
|
||
try {
|
||
// 查找指定面值的可领取兑换码
|
||
$stmt = $pdo->prepare('SELECT * FROM redemption_codes WHERE value = ? AND status = 1 AND (expired_at IS NULL OR expired_at > NOW()) AND product_id = ? ORDER BY id ASC LIMIT ? FOR UPDATE');
|
||
$stmt->execute([$codeValue, $pid, $quantity]);
|
||
$available = $stmt->fetchAll();
|
||
|
||
if (count($available) < $quantity) {
|
||
$msg = '<div class="alert alert-danger">该面值的可领取兑换码不足,当前仅有 ' . count($available) . ' 个可用</div>';
|
||
$pdo->rollBack();
|
||
} else {
|
||
$claimed = 0;
|
||
foreach ($available as $code) {
|
||
$stmt = $pdo->prepare('UPDATE redemption_codes SET status = 2, claim_user_id = ?, claimed_at = NOW() WHERE id = ?');
|
||
$stmt->execute([getCurrentUserId(), $code['id']]);
|
||
|
||
$stmt = $pdo->prepare('INSERT INTO claim_records (product_id, created_at, user_id, code_name, batch_no, code_type, code, value, status, expired_at, price_tier1, price_tier2, claim_user, claimed_at) VALUES (?, NOW(), ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, NOW())');
|
||
$stmt->execute([
|
||
$code['product_id'],
|
||
getCurrentUserId(),
|
||
$code['name'],
|
||
$code['batch_no'],
|
||
$code['type'],
|
||
$code['code'],
|
||
$code['value'],
|
||
$code['expired_at'],
|
||
$code['price_tier1'],
|
||
$code['price_tier2'],
|
||
getCurrentUsername()
|
||
]);
|
||
$claimed++;
|
||
}
|
||
$pdo->commit();
|
||
$_SESSION['flash_msg'] = '成功领取 ' . $claimed . ' 个兑换码!';
|
||
$_SESSION['flash_type'] = 'success';
|
||
redirect('claim_code.php');
|
||
}
|
||
} catch (Exception $e) {
|
||
$pdo->rollBack();
|
||
$msg = '<div class="alert alert-danger">领取失败,请重试</div>';
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
$totalAvailable = array_sum(array_column($valueOptions, 'cnt'));
|
||
?>
|
||
<div class="card">
|
||
<h2>兑换码领取</h2>
|
||
<?php if (isset($_SESSION['flash_msg'])): ?>
|
||
<div class="alert alert-<?= h($_SESSION['flash_type'] ?? 'success') ?>"><?= h($_SESSION['flash_msg']) ?></div>
|
||
<?php unset($_SESSION['flash_msg'], $_SESSION['flash_type']); ?>
|
||
<?php endif; ?>
|
||
<?= $msg ?>
|
||
<form method="post">
|
||
<input type="hidden" name="csrf_token" value="<?= csrfToken() ?>">
|
||
<div class="form-group">
|
||
<label>兑换码面值</label>
|
||
<select name="code_value" class="form-control" required>
|
||
<option value="">-- 请选择面值 --</option>
|
||
<?php foreach ($valueOptions as $opt): ?>
|
||
<option value="<?= h($opt['value']) ?>" <?= (isset($_POST['code_value']) && $_POST['code_value'] === $opt['value']) ? 'selected' : '' ?>>
|
||
<?= h($opt['value']) ?>(剩余 <?= $opt['cnt'] ?> 个)
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>领取数量</label>
|
||
<input type="number" name="quantity" class="form-control" value="1" min="1" max="100" required>
|
||
<div style="font-size:12px;color:#999;margin-top:4px;">当前共计可领取: <?= $totalAvailable ?> 个,单次最多100个</div>
|
||
</div>
|
||
<button type="submit" class="btn btn-success" onclick="return confirm('确认领取?')">立即领取</button>
|
||
<button type="button" class="btn btn-default" onclick="history.back()" style="margin-left:8px;">取消</button>
|
||
</form>
|
||
</div>
|
||
<?php require __DIR__ . '/includes/footer.php'; ?>
|