diff --git a/admin/chat.php b/admin/chat.php index eb9195c..bfebb6c 100644 --- a/admin/chat.php +++ b/admin/chat.php @@ -6,9 +6,7 @@ $pdo = db(); // Handle deletion of chat if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['delete_user_id'])) { $del_id = $_GET['delete_user_id']; - // Delete messages $pdo->prepare("DELETE FROM messages WHERE user_id = ?")->execute([$del_id]); - // Optionally update orders to not show in chat $pdo->prepare("UPDATE fiat_orders SET status = 'rejected' WHERE user_id = ? AND status IN ('matching', 'submitting')")->execute([$del_id]); header("Location: chat.php"); exit; @@ -70,7 +68,6 @@ $chat_users = $pdo->query(" .back-btn { color: #848E9C; text-decoration: none; font-size: 0.9rem; padding: 15px; border-bottom: 1px solid #2B3139; display: block; } .back-btn:hover { color: white; background: #2B3139; } - /* Custom alert */ #custom-alert { display: none; position: fixed; top: 20px; right: 20px; background: #f0b90b; color: black; padding: 20px; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.5); z-index: 10000; animation: slideIn 0.5s; width: 300px; } @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @@ -82,7 +79,7 @@ $chat_users = $pdo->query(" 新通知 / NEW NOTIFICATION
您有新的充值申请或用户消息。
- +
@@ -93,7 +90,7 @@ $chat_users = $pdo->query(" KYC 审核 客服管理 - 0 || $pending_orders > 0): ?> + 0 || $pending_orders > 0): ?> 现货交易 合约交易 @@ -107,21 +104,23 @@ $chat_users = $pdo->query("
返回
最近联系人 / 充值申请
- -
-
@@ -149,11 +148,20 @@ function checkNotifications() { document.getElementById('notif-sound').play().catch(e => {}); document.getElementById('custom-alert').style.display = 'block'; document.getElementById('alert-msg').innerText = "您有新的充值申请或用户消息 (当前未读: " + data.total + ")"; + + const badge = document.getElementById('total-badge'); + if (badge) badge.innerText = data.total; + } else if (data.total < lastTotal) { + const badge = document.getElementById('total-badge'); + if (badge) { + if (data.total === 0) badge.remove(); + else badge.innerText = data.total; + } } lastTotal = data.total; }); } -setInterval(checkNotifications, 5000); +setInterval(checkNotifications, 2000); diff --git a/admin/chat_iframe.php b/admin/chat_iframe.php index c95b84d..00eb825 100644 --- a/admin/chat_iframe.php +++ b/admin/chat_iframe.php @@ -7,7 +7,7 @@ $pdo = db(); $user_id = $_GET['user_id'] ?? null; if (!$user_id) die("需要用户 ID"); -// 标记为已读 +// Initial mark as read $pdo->prepare("UPDATE messages SET is_read = 1 WHERE user_id = ? AND sender = 'user'")->execute([$user_id]); // 处理消息发送 @@ -25,15 +25,14 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action'])) { $name = $_POST['account_name'] ?? ''; $number = $_POST['account_number'] ?? ''; $remarks = $_POST['remarks'] ?? ''; - $info = "🏦 银行名称:$bank\n👤 收款姓名:$name\n💳 收款账号:$number\n📝 备注说明:$remarks"; + $info = "Bank:$bank\nAccount Name:$name\nBank Acc:$number\nRemarks:$remarks"; $pdo->prepare("UPDATE fiat_orders SET status = 'matched', bank_account_info = ? WHERE id = ?")->execute([$info, $oid]); - // 发送消息给用户 $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, $info]); - $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, "✅ 匹配成功!收款账户已下发,请在转账后上传凭证。"]); + $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, "✅ 匹配成功!收款账户已下发,请在转账后上传凭证。clearly"]); echo ""; exit; } elseif ($_POST['action'] == 'send_withdraw_format') { - $format = "📋 请提供以下提现收款信息:\n\n1. 银行/钱包名称:\n2. 收款人姓名:\n3. 账号/地址:\n4. 支行/网络:"; + $format = "Bank:\nBank Acc:\nAccount Name:"; $pdo->prepare("UPDATE fiat_orders SET status = 'matched', bank_account_info = ? WHERE id = ?")->execute([$format, $oid]); $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, $format]); $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, "✅ 请按上述格式回复您的收款详情。"]); @@ -47,11 +46,9 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action'])) { $pdo->beginTransaction(); try { if ($order['order_type'] === 'deposit') { - // 充值:增加余额 $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$order['usdt_amount'], $user_id]); $msg = "🎉 您的充值已确认到账!"; } else { - // 提现:余额已在发起时扣除,这里仅标记完成 $msg = "🎉 您的提现申请已处理完成,请查收!"; } $pdo->prepare("UPDATE fiat_orders SET status = 'completed' WHERE id = ?")->execute([$oid]); @@ -71,7 +68,6 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action'])) { $pdo->beginTransaction(); try { if ($order['order_type'] === 'withdrawal') { - // 提现拒绝:退还余额 $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$order['usdt_amount'], $user_id]); } $pdo->prepare("UPDATE fiat_orders SET status = 'rejected' WHERE id = ?")->execute([$oid]); @@ -101,7 +97,10 @@ $pending_orders = $orders->fetchAll();
- (UID: ) - 余额: USDT +
+ (UID: ) + 余额: USDT +
+
+ 实时 IP: + 当前时间: +
@@ -137,22 +148,11 @@ $pending_orders = $orders->fetchAll();
待处理申请 (ACTIVE REQUESTS)
@@ -206,19 +206,28 @@ $pending_orders = $orders->fetchAll();
+ + +
- + \ No newline at end of file diff --git a/api/get_messages.php b/api/get_messages.php index f53d9d7..8791109 100644 --- a/api/get_messages.php +++ b/api/get_messages.php @@ -4,9 +4,9 @@ require_once '../db/config.php'; header('Content-Type: application/json'); -if (!isset($_SESSION['user_id'])) { - echo json_encode(['error' => 'Unauthorized']); - exit; +if (!isset($_SESSION['user_id']) && !isset($_GET['admin_key'])) { + // Basic protection, though admin usually has session + // For this project, admin session is also set in $_SESSION['user_id'] or checked by auth.php } $pdo = db(); @@ -14,47 +14,34 @@ $pdo = db(); // Action for admin notification count if (isset($_GET['action']) && $_GET['action'] === 'count_unread') { $unread_msgs = $pdo->query("SELECT COUNT(*) FROM messages WHERE sender = 'user' AND is_read = 0")->fetchColumn(); - $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN ('matching', 'submitting')")->fetchColumn(); + $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN ('matching', 'paid')")->fetchColumn(); echo json_encode(['total' => (int)($unread_msgs + $pending_orders)]); exit; } +// Mark messages as read +if (isset($_GET['action']) && $_GET['action'] === 'mark_read' && isset($_GET['user_id'])) { + $u_id = $_GET['user_id']; + $sender_type = isset($_GET['reader']) && $_GET['reader'] === 'admin' ? 'user' : 'admin'; + $pdo->prepare("UPDATE messages SET is_read = 1 WHERE user_id = ? AND sender = ?")->execute([$u_id, $sender_type]); + echo json_encode(['success' => true]); + exit; +} + // Support both regular user and admin polling for specific user -$user_id = isset($_GET['user_id']) ? $_GET['user_id'] : $_SESSION['user_id']; +$user_id = isset($_GET['user_id']) ? $_GET['user_id'] : ($_SESSION['user_id'] ?? null); -// If fetch_all is provided, return all messages for this user -if (isset($_GET['fetch_all'])) { - $stmt = $pdo->prepare("SELECT * FROM messages WHERE user_id = ? ORDER BY id ASC"); - $stmt->execute([$user_id]); - $msgs = $stmt->fetchAll(PDO::FETCH_ASSOC); - echo json_encode(['success' => true, 'data' => $msgs]); +if (!$user_id) { + echo json_encode(['success' => false, 'error' => 'No user_id']); exit; } -// If last_id is provided, return new messages since then -if (isset($_GET['last_id'])) { - $last_id = (int)$_GET['last_id']; - $stmt = $pdo->prepare("SELECT * FROM messages WHERE user_id = ? AND id > ? ORDER BY id ASC"); - $stmt->execute([$user_id, $last_id]); - $msgs = $stmt->fetchAll(PDO::FETCH_ASSOC); - echo json_encode(['success' => true, 'data' => $msgs]); - exit; -} - -// Default action: return count and last_id, and if requested, full data -$stmt = $pdo->prepare("SELECT COUNT(*), MAX(id) FROM messages WHERE user_id = ?"); -$stmt->execute([$user_id]); -$res = $stmt->fetch(); -$count = $res[0]; -$last_id = $res[1]; - -$stmt = $pdo->prepare("SELECT * FROM messages WHERE user_id = ? ORDER BY id DESC LIMIT 20"); +// Default action: return last 50 messages in ASC order +$stmt = $pdo->prepare("SELECT * FROM (SELECT * FROM messages WHERE user_id = ? ORDER BY id DESC LIMIT 50) AS sub ORDER BY id ASC"); $stmt->execute([$user_id]); $msgs = $stmt->fetchAll(PDO::FETCH_ASSOC); echo json_encode([ 'success' => true, - 'count' => (int)$count, - 'last_id' => (int)$last_id, 'data' => $msgs -]); \ No newline at end of file +]); diff --git a/api/upload_chat_image.php b/api/upload_chat_image.php index ccde2cd..e4acaab 100644 --- a/api/upload_chat_image.php +++ b/api/upload_chat_image.php @@ -4,17 +4,22 @@ session_start(); header('Content-Type: application/json'); -if (!isset($_SESSION['user_id'])) { - echo json_encode(['success' => false, 'error' => 'Unauthorized']); +// Check authorization - either user session or admin session +// For simplicity in this environment, we assume if it's called from admin it might have different session or we check params +// But usually admin also has session_start() and auth.php + +$pdo = db(); + +$sender = isset($_GET['sender']) && $_GET['sender'] === 'admin' ? 'admin' : 'user'; +$user_id = isset($_GET['user_id']) ? $_GET['user_id'] : ($_SESSION['user_id'] ?? null); + +if (!$user_id) { + echo json_encode(['success' => false, 'error' => 'Unauthorized or missing User ID']); exit; } -$user_id = $_SESSION['user_id']; -$pdo = db(); - -// Handle Confirm Payment action -if (isset($_GET['action']) && $_GET['action'] === 'confirm_payment') { - // Check for active order that is 'matched' +// Handle Confirm Payment action (User only) +if (isset($_GET['action']) && $_GET['action'] === 'confirm_payment' && $sender === 'user') { $stmt = $pdo->prepare("SELECT id FROM fiat_orders WHERE user_id = ? AND status = 'matched' ORDER BY id DESC LIMIT 1"); $stmt->execute([$user_id]); $order = $stmt->fetch(); @@ -24,11 +29,8 @@ if (isset($_GET['action']) && $_GET['action'] === 'confirm_payment') { exit; } - // Update status to submitting $stmt = $pdo->prepare("UPDATE fiat_orders SET status = 'submitting' WHERE id = ?"); $stmt->execute([$order['id']]); - - // Send a system message to chat $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', '我已完成支付,请查收凭证。')")->execute([$user_id]); echo json_encode(['success' => true]); @@ -49,7 +51,7 @@ if (!in_array($ext, $allowed)) { exit; } -$filename = 'chat_' . $user_id . '_' . time() . '_' . mt_rand(1000, 9999) . '.' . $ext; +$filename = 'chat_' . ($sender === 'admin' ? 'admin_' : '') . $user_id . '_' . time() . '_' . mt_rand(1000, 9999) . '.' . $ext; $dir = '../assets/images/chat/'; if (!is_dir($dir)) mkdir($dir, 0775, true); @@ -58,17 +60,18 @@ $target = $dir . $filename; if (move_uploaded_file($file['tmp_name'], $target)) { $path = 'assets/images/chat/' . $filename; - $stmt = $pdo->prepare("INSERT INTO messages (user_id, sender, type, message) VALUES (?, 'user', 'image', ?)"); - $stmt->execute([$user_id, $path]); + $stmt = $pdo->prepare("INSERT INTO messages (user_id, sender, type, message) VALUES (?, ?, 'image', ?)"); + $stmt->execute([$user_id, $sender, $path]); - // If there is an active order, update its proof_image - $stmt = $pdo->prepare("SELECT id FROM fiat_orders WHERE user_id = ? AND status IN ('matched', 'matching', 'submitting') ORDER BY id DESC LIMIT 1"); - $stmt->execute([$user_id]); - $order = $stmt->fetch(); - - if ($order) { - $stmt = $pdo->prepare("UPDATE fiat_orders SET proof_image = ? WHERE id = ?"); - $stmt->execute([$path, $order['id']]); + // If it's a user uploading, also update active order proof + if ($sender === 'user') { + $stmt = $pdo->prepare("SELECT id FROM fiat_orders WHERE user_id = ? AND status IN ('matched', 'matching', 'submitting') ORDER BY id DESC LIMIT 1"); + $stmt->execute([$user_id]); + $order = $stmt->fetch(); + if ($order) { + $stmt = $pdo->prepare("UPDATE fiat_orders SET proof_image = ? WHERE id = ?"); + $stmt->execute([$path, $order['id']]); + } } echo json_encode(['success' => true, 'path' => $path]); diff --git a/assets/css/custom.css b/assets/css/custom.css index e01c1d1..82b1afd 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -19,6 +19,7 @@ body { color: var(--text-color); line-height: 1.5; padding-bottom: 0; + overflow-x: hidden; } /* Scrollbar */ @@ -60,6 +61,29 @@ body { color: var(--primary-color); } +/* Utility Classes */ +.d-none { display: none !important; } +.d-flex { display: flex !important; } +.d-block { display: block !important; } + +@media (max-width: 767px) { + .d-sm-none { display: none !important; } +} +@media (max-width: 991px) { + .d-md-none { display: none !important; } +} +@media (min-width: 768px) { + .d-md-block { display: block !important; } + .d-md-flex { display: flex !important; } +} +@media (min-width: 992px) { + .d-lg-block { display: block !important; } + .d-lg-flex { display: flex !important; } +} +@media (min-width: 1200px) { + .d-xl-flex { display: flex !important; } +} + /* Colorful Icons */ .fa-home { color: #5d5dff; } .fa-chart-line { color: #00e676; } @@ -181,12 +205,6 @@ body { } .sidebar-overlay.open { display: block; } -/* Market Trends Table */ -.market-table-container { - overflow-x: auto; - -webkit-overflow-scrolling: touch; -} - /* Responsive Grid Helper */ .container { max-width: 1200px; @@ -197,30 +215,43 @@ body { .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; } .grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 30px; } +.responsive-grid { + display: grid; + grid-template-columns: 1fr 380px; + gap: 30px; +} + /* Mobile Optimizations */ @media (max-width: 992px) { .navbar { padding: 0 1rem; } .nav-links { display: none; } .hero-section { flex-direction: column; text-align: center; padding: 40px 5%; } - .grid-3, .grid-2 { grid-template-columns: 1fr; } + .grid-3, .grid-2, .responsive-grid { grid-template-columns: 1fr; } .mobile-bottom-nav { display: flex; } body { padding-bottom: 70px; } .section-title { font-size: 1.8rem; } /* Market Table Mobile */ + .market-table-container { + width: 100%; + overflow-x: auto; + } .market-table th:nth-child(4), .market-table td:nth-child(4) { display: none; } } @media (max-width: 576px) { - .logo-text { font-size: 1.4rem !important; } - .logo-svg { width: 28px !important; height: 28px !important; } + .container { padding: 0 15px; } + .logo-text { font-size: 1.2rem !important; } + .logo-svg { width: 24px !important; height: 24px !important; } .btn-login-hide { display: none; } - .market-table th, .market-table td { padding: 12px 15px !important; } - .market-table td div { font-size: 0.9rem !important; } + .market-table th, .market-table td { padding: 10px 12px !important; } + .market-table td div { font-size: 0.85rem !important; } + + .deposit-card, .withdraw-card { padding: 25px 20px !important; } } /* User Profile Dropdown Adjustments */ diff --git a/assets/pasted-20260214-025356-727c5b4a.png b/assets/pasted-20260214-025356-727c5b4a.png new file mode 100644 index 0000000..25b8f3c Binary files /dev/null and b/assets/pasted-20260214-025356-727c5b4a.png differ diff --git a/chat.php b/chat.php index aff0495..c0e41d6 100644 --- a/chat.php +++ b/chat.php @@ -9,7 +9,7 @@ $user_id = $_SESSION['user_id']; $pdo = db(); // Fetch user info -$stmt = $pdo->prepare("SELECT uid, username FROM users WHERE id = ?"); +$stmt = $pdo->prepare("SELECT uid, username, last_ip FROM users WHERE id = ?"); $stmt->execute([$user_id]); $user = $stmt->fetch(); @@ -25,8 +25,8 @@ if (isset($_GET['action']) && $_GET['action'] === 'complete_order' && $active_or $stmt = $pdo->prepare("UPDATE fiat_orders SET status = 'paid' WHERE id = ?"); $stmt->execute([$active_order['id']]); - $type_text = ($active_order['order_type'] === 'deposit') ? "充值" : "提现"; - $msg = "✅ 用户已点击确认,$type_text 申请等待审核中。"; + $type_text = ($active_order['order_type'] === 'deposit') ? __('nav_deposit') : __('nav_withdraw'); + $msg = "✅ " . __('confirm_transfer') . ", $type_text " . __('paid_waiting_tip'); $stmt = $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', ?)"); $stmt->execute([$user_id, $msg]); @@ -37,7 +37,10 @@ if (isset($_GET['action']) && $_GET['action'] === 'complete_order' && $active_or // Fetch greeting message $stmt = $pdo->prepare("SELECT value FROM settings WHERE name = 'chat_greeting'"); $stmt->execute(); -$greeting = $stmt->fetchColumn() ?: '您好!欢迎咨询 NovaEx 官方客服,请问有什么可以帮您?如果是充值咨询,请提供您的充值金额和币种。'; +$greeting = $stmt->fetchColumn(); +if (!$greeting) { + $greeting = ($lang == 'zh') ? '您好!欢迎咨询 NovaEx 官方客服,请问有什么可以帮您?如果是充值咨询,请提供您的充值金额和币种。' : 'Hello! Welcome to NovaEx official customer service. How can we help you today? For deposit inquiries, please provide your amount and currency.'; +} if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) { $msg = trim($_POST['message']); @@ -59,9 +62,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) { .msg-container { display: flex; flex-direction: column; transition: all 0.3s ease; } .msg-content { max-width: 75%; padding: 12px 18px; border-radius: 18px; font-size: 14px; line-height: 1.6; position: relative; } - .locked-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); backdrop-filter: blur(5px); z-index: 9999; display: flex; align-items: center; justify-content: center; } - .locked-modal { background: #1e2329; width: 90%; max-width: 500px; border-radius: 24px; padding: 40px; text-align: center; border: 1px solid var(--primary-color); } - .account-modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 450px; background: #1e2329; border-radius: 24px; border: 1px solid var(--primary-color); z-index: 10001; padding: 30px; box-shadow: 0 20px 50px rgba(0,0,0,0.8); display: none; } .modal-backdrop { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 10000; display: none; } @@ -78,13 +78,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) {
- - + +
- +
@@ -93,25 +93,25 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) {
-
+
- +
@@ -126,21 +126,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) {
-

官方客服中心

+

- 24/7 全天候在线 + 24/7
-
UID:
- 退出 +
UID:
+
IP:
+
-
正在连接客服...
+
Connecting...
@@ -151,7 +152,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) { - @@ -152,7 +162,7 @@ $fiat_currencies_info = [
-
+