From f96783f9cf64bf173f4bb337e21a476376360b80 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Tue, 10 Feb 2026 11:55:54 +0000 Subject: [PATCH] xiufu --- ajax_handler.php | 513 +++++++++++++++++++++++------------------------ dashboard.php | 88 +++++--- 2 files changed, 314 insertions(+), 287 deletions(-) diff --git a/ajax_handler.php b/ajax_handler.php index dd14cad..f401b45 100644 --- a/ajax_handler.php +++ b/ajax_handler.php @@ -11,10 +11,11 @@ $api = new LubanSMS(); $action = $_GET['action'] ?? ''; -header('Content-Type: application/json'); +header('Content-Type: application/json; charset=utf-8'); +// Basic Auth check if (!isset($_SESSION['user_id']) && $action !== 'login') { - echo json_encode(['code' => 401, 'msg' => 'Unauthorized']); + echo json_encode(['code' => 401, 'msg' => '未登录或登录已过期']); exit; } @@ -27,8 +28,9 @@ function check_trc20_payment($address, $target_amount, $order_time) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_TIMEOUT, 10); - curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); + curl_setopt($ch, CURLOPT_TIMEOUT, 15); + curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $response = curl_exec($ch); curl_close($ch); @@ -43,301 +45,294 @@ function check_trc20_payment($address, $target_amount, $order_time) { $tx_time = (int)($tx['block_ts'] / 1000); $order_ts = strtotime($order_time); - // Match amount (with small tolerance for floating point) and time (must be after order) - if (abs($amount - $target_amount) < 0.001 && $tx_time > $order_ts) { + if (abs($amount - $target_amount) < 0.01 && $tx_time > $order_ts) { return $tx['transaction_id']; } } return false; } -switch ($action) { - case 'get_balance': - $stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ?"); - $stmt->execute([$_SESSION['user_id']]); - $balance = $stmt->fetchColumn(); - echo json_encode(['code' => 0, 'balance' => number_format($balance, 2)]); - break; +try { + switch ($action) { + case 'get_balance': + $stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $balance = $stmt->fetchColumn(); + echo json_encode(['code' => 0, 'balance' => number_format((float)$balance, 2)]); + break; - case 'get_countries': - $res = $api->getCountries(); - if ($res && (int)$res['code'] === 0) { - $data = $res['msg'] ?? $res['data'] ?? []; - echo json_encode(['code' => 0, 'data' => $data]); - } else { - echo json_encode($res ?: ['code' => 500, 'msg' => 'Unknown API error']); - } - break; + case 'get_countries': + $res = $api->getCountries(); + if ($res && (int)$res['code'] === 0) { + $data = $res['msg'] ?? $res['data'] ?? []; + echo json_encode(['code' => 0, 'data' => $data], JSON_UNESCAPED_UNICODE); + } else { + echo json_encode($res ?: ['code' => 500, 'msg' => 'API接口响应异常'], JSON_UNESCAPED_UNICODE); + } + break; - case 'get_services': - $country = $_GET['country'] ?? ''; - $service = $_GET['service'] ?? ''; - $res = $api->getServices($country, $service); - - if ($res && (int)$res['code'] === 0) { - $data = $res['msg'] ?? $res['data'] ?? []; - foreach ($data as &$item) { - if (isset($item['cost'])) { - $item['cost'] = round((float)$item['cost'] * PRICE_MULTIPLIER, 2); + case 'get_services': + $country = $_GET['country'] ?? ''; + $service = $_GET['service'] ?? ''; + $res = $api->getServices($country, $service); + + if ($res && (int)$res['code'] === 0) { + $data = $res['msg'] ?? $res['data'] ?? []; + if (!is_array($data)) $data = []; + foreach ($data as &$item) { + if (isset($item['cost'])) { + $item['cost'] = round((float)$item['cost'] * PRICE_MULTIPLIER, 2); + } } + echo json_encode(['code' => 0, 'data' => $data], JSON_UNESCAPED_UNICODE); + } else { + echo json_encode($res ?: ['code' => 500, 'msg' => '获取项目列表失败'], JSON_UNESCAPED_UNICODE); } - echo json_encode(['code' => 0, 'data' => $data]); - } else { - echo json_encode($res ?: ['code' => 500, 'msg' => 'Unknown API error']); - } - break; - - case 'get_number': - $service_id = $_GET['service_id'] ?? ''; - $country_name = $_GET['country_name'] ?? '未知国家'; - $service_name = $_GET['service_name'] ?? '未知项目'; - $price = (float)($_GET['price'] ?? 0); - - if (!$service_id) { - echo json_encode(['code' => 400, 'msg' => 'Service ID is required']); break; - } - $stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ?"); - $stmt->execute([$_SESSION['user_id']]); - $balance = $stmt->fetchColumn(); + case 'get_number': + $service_id = $_GET['service_id'] ?? ''; + $country_name = $_GET['country_name'] ?? '未知国家'; + $service_name = $_GET['service_name'] ?? '未知项目'; + $price = (float)($_GET['price'] ?? 0); - if ($balance < $price) { - echo json_encode(['code' => 400, 'msg' => '余额不足,请先充值']); - break; - } - - $res = $api->getNumber($service_id); - if ($res && (int)$res['code'] === 0) { - $pdo->beginTransaction(); - try { - $stmt = $pdo->prepare("UPDATE users SET balance = balance - ? WHERE id = ?"); - $stmt->execute([$price, $_SESSION['user_id']]); - - $stmt = $pdo->prepare("INSERT INTO sms_orders (user_id, request_id, number, service_name, country_name, cost, status, expire_at) VALUES (?, ?, ?, ?, ?, ?, 'pending', DATE_ADD(NOW(), INTERVAL 10 MINUTE))"); - $stmt->execute([$_SESSION['user_id'], $res['request_id'], $res['number'], $service_name, $country_name, $price]); - $pdo->commit(); - echo json_encode($res); - } catch (Exception $e) { - $pdo->rollBack(); - echo json_encode(['code' => 500, 'msg' => 'Database error: ' . $e->getMessage()]); + if (!$service_id) { + echo json_encode(['code' => 400, 'msg' => 'Service ID is required']); + break; } - } else { - echo json_encode($res ?: ['code' => 500, 'msg' => 'API Error']); - } - break; - case 'check_sms': - $request_id = $_GET['request_id'] ?? ''; - if (!$request_id) { - echo json_encode(['code' => 400, 'msg' => 'Request ID is required']); + $stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $balance = (float)$stmt->fetchColumn(); + + if ($balance < $price) { + echo json_encode(['code' => 400, 'msg' => '余额不足,请先充值']); + break; + } + + $res = $api->getNumber($service_id); + if ($res && (int)$res['code'] === 0) { + $pdo->beginTransaction(); + try { + $stmt = $pdo->prepare("UPDATE users SET balance = balance - ? WHERE id = ?"); + $stmt->execute([$price, $_SESSION['user_id']]); + + $stmt = $pdo->prepare("INSERT INTO sms_orders (user_id, request_id, number, service_name, country_name, cost, status, expire_at) VALUES (?, ?, ?, ?, ?, ?, 'pending', DATE_ADD(NOW(), INTERVAL 10 MINUTE))"); + $stmt->execute([$_SESSION['user_id'], $res['request_id'], $res['number'], $service_name, $country_name, $price]); + $pdo->commit(); + echo json_encode($res, JSON_UNESCAPED_UNICODE); + } catch (Exception $e) { + $pdo->rollBack(); + echo json_encode(['code' => 500, 'msg' => '数据库事务错误'], JSON_UNESCAPED_UNICODE); + } + } else { + echo json_encode($res ?: ['code' => 500, 'msg' => 'API获取号码失败'], JSON_UNESCAPED_UNICODE); + } break; - } - $res = $api->getSms($request_id); - if ($res && (int)$res['code'] === 0 && ($res['msg'] ?? '') == 'success') { - $stmt = $pdo->prepare("UPDATE sms_orders SET sms_content = ?, status = 'received' WHERE request_id = ?"); - $stmt->execute([$res['sms_code'], $request_id]); - } - echo json_encode($res ?: ['code' => 500, 'msg' => 'API Error']); - break; + case 'check_sms': + $request_id = $_GET['request_id'] ?? ''; + if (!$request_id) { + echo json_encode(['code' => 400, 'msg' => 'Request ID is required']); + break; + } - case 'release_number': - $request_id = $_GET['request_id'] ?? ''; - - $stmt = $pdo->prepare("SELECT created_at, status FROM sms_orders WHERE request_id = ? AND user_id = ?"); - $stmt->execute([$request_id, $_SESSION['user_id']]); - $order = $stmt->fetch(); - - if (!$order) { - echo json_encode(['code' => 404, 'msg' => 'Order not found']); + $res = $api->getSms($request_id); + if ($res && (int)$res['code'] === 0 && (string)($res['msg'] ?? '') === 'success') { + $stmt = $pdo->prepare("UPDATE sms_orders SET sms_content = ?, status = 'received' WHERE request_id = ?"); + $stmt->execute([$res['sms_code'], $request_id]); + } + echo json_encode($res ?: ['code' => 500, 'msg' => 'API Error'], JSON_UNESCAPED_UNICODE); break; - } - - if ($order['status'] !== 'pending') { - echo json_encode(['code' => 400, 'msg' => 'Invalid order status']); + + case 'release_number': + $request_id = $_GET['request_id'] ?? ''; + + $stmt = $pdo->prepare("SELECT created_at, status FROM sms_orders WHERE request_id = ? AND user_id = ?"); + $stmt->execute([$request_id, $_SESSION['user_id']]); + $order = $stmt->fetch(); + + if (!$order) { + echo json_encode(['code' => 404, 'msg' => '未找到该订单']); + break; + } + + if ($order['status'] !== 'pending') { + echo json_encode(['code' => 400, 'msg' => '订单状态不符合释放条件']); + break; + } + + $createdAt = strtotime($order['created_at']); + if (time() - $createdAt < 120) { + echo json_encode(['code' => 400, 'msg' => '获取号码不足2分钟,暂时无法手动释放。']); + break; + } + + $res = $api->setStatus($request_id, 'reject'); + if ($res && (int)$res['code'] === 0) { + $stmt = $pdo->prepare("UPDATE sms_orders SET status = 'canceled' WHERE request_id = ?"); + $stmt->execute([$request_id]); + } + echo json_encode($res ?: ['code' => 500, 'msg' => 'API释放失败'], JSON_UNESCAPED_UNICODE); break; - } - $createdAt = strtotime($order['created_at']); - if (time() - $createdAt < 120) { - echo json_encode(['code' => 400, 'msg' => '获取号码不足2分钟,暂时无法手动释放。']); + case 'get_active_orders': + // Auto expire old orders + $stmt = $pdo->prepare("UPDATE sms_orders SET status = 'expired' WHERE status = 'pending' AND expire_at < NOW()"); + $stmt->execute(); + + $stmt = $pdo->prepare("SELECT * FROM sms_orders WHERE user_id = ? AND status = 'pending' ORDER BY created_at DESC"); + $stmt->execute([$_SESSION['user_id']]); + echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()], JSON_UNESCAPED_UNICODE); break; - } - $res = $api->setStatus($request_id, 'reject'); - if ($res && (int)$res['code'] === 0) { - $stmt = $pdo->prepare("UPDATE sms_orders SET status = 'canceled' WHERE request_id = ?"); - $stmt->execute([$request_id]); - } - echo json_encode($res ?: ['code' => 500, 'msg' => 'API Error']); - break; + case 'create_recharge': + $amount = (float)($_POST['amount'] ?? 0); + if ($amount < 10) { + echo json_encode(['code' => 400, 'msg' => '最低充值金额为 10 USDT']); + break; + } + + $base = floor($amount); + $random_decimal = rand(1, 99) / 100; + $final_amount = $base + $random_decimal; - case 'get_active_orders': - $stmt = $pdo->prepare("UPDATE sms_orders SET status = 'expired' WHERE status = 'pending' AND expire_at < NOW()"); - $stmt->execute(); - - $stmt = $pdo->prepare("SELECT * FROM sms_orders WHERE user_id = ? AND status = 'pending' ORDER BY created_at DESC"); - $stmt->execute([$_SESSION['user_id']]); - echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()]); - break; - - case 'create_recharge': - $amount = (float)($_POST['amount'] ?? 0); - if ($amount < 10) { - echo json_encode(['code' => 400, 'msg' => '最低充值金额为 10 USDT']); + $stmt = $pdo->prepare("INSERT INTO recharges (user_id, amount, txid, status) VALUES (?, ?, 'Auto-Detect', 'pending')"); + $stmt->execute([$_SESSION['user_id'], $final_amount]); + echo json_encode(['code' => 0, 'recharge_id' => $pdo->lastInsertId(), 'amount' => $final_amount], JSON_UNESCAPED_UNICODE); break; - } - - $base = floor($amount); - $random_decimal = rand(1, 99) / 100; - $final_amount = $base + $random_decimal; - $stmt = $pdo->prepare("INSERT INTO recharges (user_id, amount, txid, status) VALUES (?, ?, 'Auto-Detect', 'pending')"); - $stmt->execute([$_SESSION['user_id'], $final_amount]); - echo json_encode(['code' => 0, 'recharge_id' => $pdo->lastInsertId(), 'amount' => $final_amount]); - break; + case 'check_recharge_status': + $recharge_id = $_GET['recharge_id'] ?? ''; + if (!$recharge_id) { + echo json_encode(['code' => 400, 'msg' => 'Recharge ID is required']); + break; + } + + $stmt = $pdo->prepare("SELECT * FROM recharges WHERE id = ? AND user_id = ?"); + $stmt->execute([$recharge_id, $_SESSION['user_id']]); + $recharge = $stmt->fetch(); + + if (!$recharge) { + echo json_encode(['code' => 404, 'msg' => '未找到充值订单']); + break; + } - case 'check_recharge_status': - $recharge_id = $_GET['recharge_id'] ?? ''; - if (!$recharge_id) { - echo json_encode(['code' => 400, 'msg' => 'Recharge ID is required']); - break; - } - - $stmt = $pdo->prepare("SELECT * FROM recharges WHERE id = ? AND user_id = ?"); - $stmt->execute([$recharge_id, $_SESSION['user_id']]); - $recharge = $stmt->fetch(); - - if (!$recharge) { - echo json_encode(['code' => 404, 'msg' => 'Order not found']); - break; - } - - if ($recharge['status'] === 'completed') { - echo json_encode(['code' => 0, 'status' => 'completed']); - exit; - } - - // Try Auto-Detection - $settings = $pdo->query("SELECT setting_key, setting_value FROM settings")->fetchAll(PDO::FETCH_KEY_PAIR); - $trc20_address = $settings['usdt_trc20_address'] ?? ''; - - $txid = check_trc20_payment($trc20_address, $recharge['amount'], $recharge['created_at']); - if ($txid) { - $pdo->beginTransaction(); - try { - $stmt = $pdo->prepare("UPDATE recharges SET status = 'completed', txid = ? WHERE id = ?"); - $stmt->execute([$txid, $recharge_id]); - $stmt = $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?"); - $stmt->execute([$recharge['amount'], $recharge['user_id']]); - $pdo->commit(); + if ($recharge['status'] === 'completed') { echo json_encode(['code' => 0, 'status' => 'completed']); - } catch (Exception $e) { - $pdo->rollBack(); - echo json_encode(['code' => 500, 'msg' => 'Detection error']); + exit; } - } else { - echo json_encode(['code' => 0, 'status' => 'pending']); - } - break; - // --- Chat Actions --- - case 'send_message': - $message = trim($_POST['message'] ?? ''); - $target_user_id = $_POST['user_id'] ?? $_SESSION['user_id']; - - if (!$message) { - echo json_encode(['code' => 400, 'msg' => 'Message is empty']); + // Try Auto-Detection + $settings = $pdo->query("SELECT setting_key, setting_value FROM settings")->fetchAll(PDO::FETCH_KEY_PAIR); + $trc20_address = $settings['usdt_trc20_address'] ?? ''; + + $txid = check_trc20_payment($trc20_address, $recharge['amount'], $recharge['created_at']); + if ($txid) { + $pdo->beginTransaction(); + try { + $stmt = $pdo->prepare("UPDATE recharges SET status = 'completed', txid = ? WHERE id = ?"); + $stmt->execute([$txid, $recharge_id]); + $stmt = $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?"); + $stmt->execute([$recharge['amount'], $recharge['user_id']]); + $pdo->commit(); + echo json_encode(['code' => 0, 'status' => 'completed']); + } catch (Exception $e) { + $pdo->rollBack(); + echo json_encode(['code' => 500, 'msg' => '自动入账失败'], JSON_UNESCAPED_UNICODE); + } + } else { + echo json_encode(['code' => 0, 'status' => 'pending']); + } break; - } - $sender = 'user'; - // Check if current user is admin - $stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?"); - $stmt->execute([$_SESSION['user_id']]); - $currentUser = $stmt->fetch(); - if ($currentUser['role'] === 'admin') { - $sender = 'admin'; - } + case 'send_message': + $message = trim($_POST['message'] ?? ''); + $target_user_id = $_POST['user_id'] ?? $_SESSION['user_id']; + + if (!$message) { + echo json_encode(['code' => 400, 'msg' => '消息内容不能为空']); + break; + } - $stmt = $pdo->prepare("INSERT INTO support_messages (user_id, sender, message, is_read) VALUES (?, ?, ?, 0)"); - $stmt->execute([$target_user_id, $sender, $message]); - echo json_encode(['code' => 0, 'msg' => 'Sent']); - break; + // Check sender role + $stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $role = $stmt->fetchColumn(); + $sender = ($role === 'admin') ? 'admin' : 'user'; - case 'get_messages': - $target_user_id = $_GET['user_id'] ?? $_SESSION['user_id']; - - // Security: non-admins can only see their own messages - $stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?"); - $stmt->execute([$_SESSION['user_id']]); - $currentUser = $stmt->fetch(); - - $isAdmin = ($currentUser['role'] === 'admin'); - if (!$isAdmin && $target_user_id != $_SESSION['user_id']) { - echo json_encode(['code' => 403, 'msg' => 'Forbidden']); + $stmt = $pdo->prepare("INSERT INTO support_messages (user_id, sender, message, is_read) VALUES (?, ?, ?, 0)"); + $stmt->execute([$target_user_id, $sender, $message]); + echo json_encode(['code' => 0, 'msg' => '已发送'], JSON_UNESCAPED_UNICODE); break; - } - // Mark as read logic - if ($isAdmin && $target_user_id != $_SESSION['user_id']) { - // Admin is reading user messages - $stmt = $pdo->prepare("UPDATE support_messages SET is_read = 1 WHERE user_id = ? AND sender = 'user'"); + case 'get_messages': + $target_user_id = $_GET['user_id'] ?? $_SESSION['user_id']; + + $stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $currentUserRole = $stmt->fetchColumn(); + + $isAdmin = ($currentUserRole === 'admin'); + if (!$isAdmin && (int)$target_user_id !== (int)$_SESSION['user_id']) { + echo json_encode(['code' => 403, 'msg' => '无权查看他人消息']); + break; + } + + // Mark as read + if ($isAdmin && (int)$target_user_id !== (int)$_SESSION['user_id']) { + $stmt = $pdo->prepare("UPDATE support_messages SET is_read = 1 WHERE user_id = ? AND sender = 'user'"); + $stmt->execute([$target_user_id]); + } else if (!$isAdmin) { + $stmt = $pdo->prepare("UPDATE support_messages SET is_read = 1 WHERE user_id = ? AND sender = 'admin'"); + $stmt->execute([$_SESSION['user_id']]); + } + + $stmt = $pdo->prepare("SELECT * FROM support_messages WHERE user_id = ? ORDER BY created_at ASC"); $stmt->execute([$target_user_id]); - } else if (!$isAdmin && $target_user_id == $_SESSION['user_id']) { - // User is reading admin messages - $stmt = $pdo->prepare("UPDATE support_messages SET is_read = 1 WHERE user_id = ? AND sender = 'admin'"); - $stmt->execute([$target_user_id]); - } - - $stmt = $pdo->prepare("SELECT * FROM support_messages WHERE user_id = ? ORDER BY created_at ASC"); - $stmt->execute([$target_user_id]); - echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()]); - break; - - case 'get_chat_users': - // Admin only - $stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?"); - $stmt->execute([$_SESSION['user_id']]); - $currentUser = $stmt->fetch(); - if ($currentUser['role'] !== 'admin') { - echo json_encode(['code' => 403, 'msg' => 'Forbidden']); + echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()], JSON_UNESCAPED_UNICODE); break; - } - $stmt = $pdo->query(" - SELECT u.id, u.username, m.message as last_message, m.created_at as last_time, - (SELECT COUNT(*) FROM support_messages WHERE user_id = u.id AND sender = 'user' AND is_read = 0) as unread_count - FROM users u - JOIN ( - SELECT user_id, MAX(created_at) as max_time - FROM support_messages - GROUP BY user_id - ) last_msg ON u.id = last_msg.user_id - JOIN support_messages m ON m.user_id = u.id AND m.created_at = last_msg.max_time - ORDER BY m.created_at DESC - "); - echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()]); - break; + case 'get_chat_users': + $stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?"); + $stmt->execute([$_SESSION['user_id']]); + if ($stmt->fetchColumn() !== 'admin') { + echo json_encode(['code' => 403, 'msg' => 'Forbidden']); + break; + } - case 'check_new_messages': - // Admin only - $stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?"); - $stmt->execute([$_SESSION['user_id']]); - $currentUser = $stmt->fetch(); - if ($currentUser['role'] !== 'admin') { - echo json_encode(['code' => 403, 'msg' => 'Forbidden']); + $stmt = $pdo->query(" + SELECT u.id, u.username, m.message as last_message, m.created_at as last_time, + (SELECT COUNT(*) FROM support_messages WHERE user_id = u.id AND sender = 'user' AND is_read = 0) as unread_count + FROM users u + JOIN ( + SELECT user_id, MAX(created_at) as max_time + FROM support_messages + GROUP BY user_id + ) last_msg ON u.id = last_msg.user_id + JOIN support_messages m ON m.user_id = u.id AND m.created_at = last_msg.max_time + ORDER BY m.created_at DESC + "); + echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()], JSON_UNESCAPED_UNICODE); break; - } - $stmt = $pdo->query("SELECT COUNT(*) FROM support_messages WHERE sender = 'user' AND is_read = 0"); - $count = $stmt->fetchColumn(); - - echo json_encode(['code' => 0, 'unread_total' => $count]); - break; + case 'check_new_messages': + $stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?"); + $stmt->execute([$_SESSION['user_id']]); + if ($stmt->fetchColumn() !== 'admin') { + echo json_encode(['code' => 403, 'msg' => 'Forbidden']); + break; + } - default: - echo json_encode(['code' => 404, 'msg' => 'Action not found']); - break; -} + $stmt = $pdo->query("SELECT COUNT(*) FROM support_messages WHERE sender = 'user' AND is_read = 0"); + $count = $stmt->fetchColumn(); + echo json_encode(['code' => 0, 'unread_total' => $count]); + break; + + default: + echo json_encode(['code' => 404, 'msg' => '未知请求']); + break; + } +} catch (Exception $e) { + echo json_encode(['code' => 500, 'msg' => '系统处理异常: ' . $e->getMessage()], JSON_UNESCAPED_UNICODE); +} \ No newline at end of file diff --git a/dashboard.php b/dashboard.php index f926439..9470fb9 100644 --- a/dashboard.php +++ b/dashboard.php @@ -98,6 +98,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; margin-bottom: 2rem; box-shadow: var(--shadow-sm); border: 1px solid var(--border-color); + position: relative; } .search-grid { @@ -122,6 +123,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; justify-content: space-between; cursor: pointer; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + user-select: none; } .custom-select-trigger:hover { border-color: var(--primary); @@ -145,7 +147,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; overflow-y: auto; animation: dropdownFade 0.2s ease-out; } - .dropdown-menu-custom.show { display: block; } + .dropdown-menu-custom.show { display: block !important; } @keyframes dropdownFade { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } .list-item { @@ -253,7 +255,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
ACCOUNT BALANCE
-
$
+
$
@@ -266,7 +268,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
- +
@@ -289,7 +291,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
-
+
搜索或选择国家...
@@ -297,13 +299,15 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
-
+
+
正在加载国家列表...
+
-
+
搜索社交平台项目...
@@ -376,31 +380,38 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; }); async function loadCountries() { + const listContainer = document.getElementById('countriesList'); try { const res = await fetch(`${apiHandler}?action=get_countries`); const data = await res.json(); if (data.code === 0) { allCountries = Array.isArray(data.data) ? data.data : []; renderCountries(); + } else if (data.code === 401) { + window.location.href = 'index.php'; } else { - document.getElementById('countriesList').innerHTML = '
加载国家列表失败
'; + listContainer.innerHTML = `
加载失败: ${data.msg || '未知API错误'}
`; } } catch (e) { - document.getElementById('countriesList').innerHTML = '
连接服务器失败
'; + listContainer.innerHTML = '
网络连接超时,请刷新页面
'; } } - function toggleDropdown(id) { + function toggleDropdown(id, event) { + if (event) event.stopPropagation(); const d = document.getElementById(id); - const show = d.classList.contains('show'); + const isShow = d.classList.contains('show'); hideAllDropdowns(); - if (!show) { + if (!isShow) { d.classList.add('show'); const input = d.querySelector('input'); if (input) setTimeout(() => input.focus(), 50); } } - function hideAllDropdowns() { document.querySelectorAll('.dropdown-menu-custom').forEach(d => d.classList.remove('show')); } + + function hideAllDropdowns() { + document.querySelectorAll('.dropdown-menu-custom').forEach(d => d.classList.remove('show')); + } function renderCountries(filter = '') { const container = document.getElementById('countriesList'); @@ -408,7 +419,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; container.innerHTML = ''; if (!Array.isArray(allCountries) || allCountries.length === 0) { - container.innerHTML = '
暂无可用国家
'; + container.innerHTML = '
暂无可用国家数据
'; return; } @@ -418,7 +429,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; ) : allCountries; if (filtered.length === 0) { - container.innerHTML = '
未找到匹配国家
'; + container.innerHTML = '
未找到匹配的国家
'; return; } @@ -426,7 +437,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; const div = document.createElement('div'); div.className = 'list-item'; div.innerHTML = `
${c.name_zh || '未知'}${c.name_en || ''}
`; - div.onclick = () => { selectCountry(c); }; + div.onclick = (e) => { e.stopPropagation(); selectCountry(c); }; container.appendChild(div); }); } @@ -437,7 +448,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; container.innerHTML = ''; if (!Array.isArray(services) || services.length === 0) { - container.innerHTML = '
暂无项目
'; + container.innerHTML = '
暂无搜索结果
'; return; } @@ -445,7 +456,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; const div = document.createElement('div'); div.className = 'list-item'; div.innerHTML = `${s.name}`; - div.onclick = () => { selectService(s); }; + div.onclick = (e) => { e.stopPropagation(); selectService(s); }; container.appendChild(div); }); } @@ -454,8 +465,10 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; function handleServiceInput() { const q = document.getElementById('serviceSearch').value; + const listContainer = document.getElementById('servicesList'); if (searchTimeout) clearTimeout(searchTimeout); if (!q) { renderServices(popularServices); return; } + searchTimeout = setTimeout(async () => { try { const res = await fetch(`${apiHandler}?action=get_services&service=${encodeURIComponent(q)}`); @@ -471,9 +484,13 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; } }); renderServices(unique); + } else if (data.code === 401) { + window.location.href = 'index.php'; } - } catch (e) {} - }, 300); + } catch (e) { + console.error("Search error", e); + } + }, 400); } function selectCountry(c) { @@ -509,7 +526,10 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; if (data.code === 0) { body.innerHTML = ''; const services = Array.isArray(data.data) ? data.data : []; - if (!services.length) { body.innerHTML = '
该地区暂无此服务,请尝试其他国家
'; return; } + if (!services.length) { + body.innerHTML = '
该地区暂无此服务,请尝试其他国家或项目
'; + return; + } services.forEach(s => { const item = document.createElement('div'); item.className = 'quotation-item'; @@ -533,24 +553,37 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; body.appendChild(item); }); document.getElementById('lastUpdated').textContent = 'UPDATED: ' + new Date().toLocaleTimeString(); + } else if (data.code === 401) { + window.location.href = 'index.php'; } else { - body.innerHTML = `
加载行情失败: ${data.msg || '未知错误'}
`; + body.innerHTML = `
加载行情失败: ${data.msg || '未知接口错误'}
`; } - } catch (e) { body.innerHTML = '
行情数据连接失败
'; } + } catch (e) { body.innerHTML = '
行情数据连接失败,请检查网络
'; } } async function getNumber(sid, sname, price, btn) { if (!confirm(`确认扣费 $${price} 购买 ${sname} 号码?`)) return; - btn.disabled = true; btn.innerHTML = ''; + const originalText = btn.innerHTML; + btn.disabled = true; + btn.innerHTML = ''; + try { const cname = currentCountry ? currentCountry.name_zh : '全球'; const res = await fetch(`${apiHandler}?action=get_number&service_id=${sid}&service_name=${encodeURIComponent(sname)}&country_name=${encodeURIComponent(cname)}&price=${price}`); const data = await res.json(); if (data.code === 0) { loadActiveOrders(); updateBalance(); window.scrollTo({top: 0, behavior: 'smooth'}); - } else { alert(data.msg || '库存不足或接口超时'); } - } catch (e) {} - btn.disabled = false; btn.innerHTML = '获取号码'; + } else if (data.code === 401) { + window.location.href = 'index.php'; + } else { + alert(data.msg || '库存不足或接口超时'); + } + } catch (e) { + alert('获取号码失败,请重试'); + } finally { + btn.disabled = false; + btn.innerHTML = originalText; + } } async function updateBalance() { @@ -614,7 +647,6 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; if (el) el.innerHTML = `${data.sms_code}`; clearInterval(activePolls[rid]); delete activePolls[rid]; showSmsModal(data.sms_code); } else if (data.code === 400 || (data.code !== 0 && data.code !== 500)) { - // Stop polling on permanent errors (but not network errors) clearInterval(activePolls[rid]); delete activePolls[rid]; loadActiveOrders(); } } catch (e) {} @@ -654,4 +686,4 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!'; } - + \ No newline at end of file