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 = '
无效的面值
';
} 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 = '您当前未使用的兑换码已达 ' . $unusedCount . ' 条(上限200条),请先使用后再领取
';
} 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 = '当前面值兑换码距上次领取不足3天,请 ' . $remaining . ' 小时后再领取
';
} 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 = '该面值的可领取兑换码不足,当前仅有 ' . count($available) . ' 个可用
';
$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 = '领取失败,请重试
';
}
}
}
}
}
$totalAvailable = array_sum(array_column($valueOptions, 'cnt'));
?>
兑换码领取
= h($_SESSION['flash_msg']) ?>
= $msg ?>