From bb14c2ece790b157397a4e3d529d84c67a074d1d Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sun, 22 Feb 2026 08:19:34 +0000 Subject: [PATCH] 123456 --- admin/customer_service.php | 34 +++++--- admin/layout.php | 20 +++-- api/chat.php | 97 +++++++++------------ assets/pasted-20260222-081324-8196b7b9.png | Bin 0 -> 8910 bytes db/config.php | 9 +- recharge.php | 22 ++--- 6 files changed, 95 insertions(+), 87 deletions(-) create mode 100644 assets/pasted-20260222-081324-8196b7b9.png diff --git a/admin/customer_service.php b/admin/customer_service.php index ac3c97c..97afce0 100644 --- a/admin/customer_service.php +++ b/admin/customer_service.php @@ -313,6 +313,9 @@ let currentUserContext = ''; let lastMsgCount = 0; let notifySound = new Audio('https://assets.mixkit.co/active_storage/sfx/2358/2358-preview.mp3'); +// Get API path dynamically +const apiPath = (window.location.origin + window.location.pathname).split('/admin/')[0] + '/api/'; + async function refreshUsers() { try { const list = document.getElementById('user-list'); @@ -321,10 +324,17 @@ let notifySound = new Audio('https://assets.mixkit.co/active_storage/sfx/2358/23 const searchInput = document.getElementById('user-search'); const search = searchInput ? searchInput.value.toLowerCase() : ''; - const r = await fetch('../api/chat.php?action=admin_get_all'); - if (!r.ok) return; + const r = await fetch(apiPath + 'chat.php?action=admin_get_all&v=' + Date.now()); + if (!r.ok) { + list.innerHTML = `
API 错误: ${r.status} ${r.statusText}
`; + return; + } const users = await r.json(); + if (users.success === false) { + list.innerHTML = `
服务器错误: ${users.error}
`; + return; + } if (users.error || !Array.isArray(users)) return; // Sound notification for new messages based on total unread count @@ -452,14 +462,14 @@ let notifySound = new Audio('https://assets.mixkit.co/active_storage/sfx/2358/23 fd.append('user_id', userId); fd.append('ip_address', ip); fd.append('session_id', sid); - fetch('../api/chat.php?action=mark_read', { method: 'POST', body: fd }).then(() => refreshUsers()); + fetch(apiPath + 'chat.php?action=mark_read&v=' + Date.now(), { method: 'POST', body: fd }).then(() => refreshUsers()); } async function recallMessage(msgId) { if (!confirm('确定撤回该消息吗?')) return; const fd = new URLSearchParams(); fd.append('message_id', msgId); - const r = await fetch('../api/chat.php?action=admin_recall_message', { method: 'POST', body: fd }); + const r = await fetch(apiPath + 'chat.php?action=admin_recall_message&v=' + Date.now(), { method: 'POST', body: fd }); const res = await r.json(); if (res.success) { fetchMessages(); @@ -473,7 +483,7 @@ async function deleteChat(userId, ip, sid, event) { fd.append('user_id', userId); fd.append('ip_address', ip); fd.append('session_id', sid); - const r = await fetch('../api/chat.php?action=admin_delete_user', { method: 'POST', body: fd }); + const r = await fetch(apiPath + 'chat.php?action=admin_delete_user&v=' + Date.now(), { method: 'POST', body: fd }); const res = await r.json(); if (res.success) { if (selectedSid == sid && selectedIp == ip && selectedUser == userId) { @@ -500,7 +510,7 @@ async function deleteUser() { fd.append('user_id', selectedUser); fd.append('ip_address', selectedIp); fd.append('session_id', selectedSid); - const r = await fetch('../api/chat.php?action=admin_delete_user', { method: 'POST', body: fd }); + const r = await fetch(apiPath + 'chat.php?action=admin_delete_user&v=' + Date.now(), { method: 'POST', body: fd }); const res = await r.json(); if (res.success) { selectedUser = null; @@ -522,7 +532,7 @@ async function deleteUser() { async function fetchMessages() { if (!selectedIp && !selectedUser && !selectedSid) return; try { - const r = await fetch(`../api/chat.php?action=get_messages&user_id=${selectedUser}&ip=${selectedIp}&session_id=${selectedSid}`); + const r = await fetch(apiPath + `chat.php?action=get_messages&user_id=${selectedUser}&ip=${selectedIp}&session_id=${selectedSid}&v=${Date.now()}`); const msgs = await r.json(); if (!msgs || !Array.isArray(msgs)) return; @@ -634,7 +644,7 @@ async function notifyMatchSuccess() { fd.append('account', account); try { - const r = await fetch('../api/admin_recharge.php?action=match_success', { method: 'POST', body: fd }); + const r = await fetch(apiPath + 'admin_recharge.php?action=match_success&v=' + Date.now(), { method: 'POST', body: fd }); const res = await r.json(); if (res.success) { alert('匹配成功!状态已更新。若要向用户显示收款账户,请继续点击“发送账户”按钮。'); @@ -663,7 +673,7 @@ async function sendPaymentInfo() { try { console.log('Sending account info...', { bank, name, account }); - const r = await fetch('../api/admin_recharge.php?action=send_account', { method: 'POST', body: fd }); + const r = await fetch(apiPath + 'admin_recharge.php?action=send_account&v=' + Date.now(), { method: 'POST', body: fd }); const res = await r.json(); if (res.success) { @@ -709,7 +719,7 @@ document.getElementById('image-input').addEventListener('change', async (e) => { formData.append('session_id', selectedSid || ''); try { - const r = await fetch('../api/chat.php?action=upload_image', { + const r = await fetch(apiPath + 'chat.php?action=upload_image&v=' + Date.now(), { method: 'POST', body: formData }); @@ -759,7 +769,7 @@ document.getElementById('chat-form').addEventListener('submit', async (e) => { fd.append('session_id', selectedSid); try { - const r = await fetch('../api/chat.php?action=admin_send', { method: 'POST', body: fd }); + const r = await fetch(apiPath + 'chat.php?action=admin_send&v=' + Date.now(), { method: 'POST', body: fd }); const res = await r.json(); const tempMsg = document.querySelector(`[data-id="${tempId}"]`); @@ -781,7 +791,7 @@ document.getElementById('save-remark-btn').addEventListener('click', async () => fd.append('session_id', selectedSid); fd.append('remark', remark); - const r = await fetch('../api/chat.php?action=save_remark', { method: 'POST', body: fd }); + const r = await fetch(apiPath + 'chat.php?action=save_remark&v=' + Date.now(), { method: 'POST', body: fd }); const res = await r.json(); if (res.success) { alert('备注已保存'); diff --git a/admin/layout.php b/admin/layout.php index b079364..4f00f33 100644 --- a/admin/layout.php +++ b/admin/layout.php @@ -281,21 +281,24 @@ function renderAdminPage($content, $title = '后台管理') { const visitedPages = JSON.parse(localStorage.getItem('visited_admin_pages') || '[]'); const currentPage = window.location.pathname; + // Detect base path for API calls + const apiPath = (window.location.origin + window.location.pathname).split('/admin/')[0] + '/api/'; + // Clear badges based on current page if (currentPage.includes('finance.php')) { - fetch('../api/admin_notifications.php?action=clear&type=finance'); + fetch(apiPath + 'admin_notifications.php?action=clear&type=finance&v=' + Date.now()); } else if (currentPage.includes('kyc.php')) { - fetch('../api/admin_notifications.php?action=clear&type=kyc'); + fetch(apiPath + 'admin_notifications.php?action=clear&type=kyc&v=' + Date.now()); } else if (currentPage.includes('binary.php')) { - fetch('../api/admin_notifications.php?action=clear&type=binary'); + fetch(apiPath + 'admin_notifications.php?action=clear&type=binary&v=' + Date.now()); } else if (currentPage.includes('contract.php')) { - fetch('../api/admin_notifications.php?action=clear&type=contract'); + fetch(apiPath + 'admin_notifications.php?action=clear&type=contract&v=' + Date.now()); } else if (currentPage.includes('spot.php')) { - fetch('../api/admin_notifications.php?action=clear&type=spot'); + fetch(apiPath + 'admin_notifications.php?action=clear&type=spot&v=' + Date.now()); } else if (currentPage.includes('customer_service.php')) { - fetch('../api/admin_notifications.php?action=clear&type=messages'); + fetch(apiPath + 'admin_notifications.php?action=clear&type=messages&v=' + Date.now()); } else if (currentPage.includes('users.php')) { - fetch('../api/admin_notifications.php?action=clear&type=users'); + fetch(apiPath + 'admin_notifications.php?action=clear&type=users&v=' + Date.now()); } document.querySelectorAll('.card-dismissible').forEach(card => { @@ -351,7 +354,8 @@ function renderAdminPage($content, $title = '后台管理') { function checkNotifications() { const currentPage = window.location.pathname; const isDashboard = currentPage.includes('index.php') || currentPage.endsWith('/admin/'); - const url = isDashboard ? '../api/admin_notifications.php?stats=1' : '../api/admin_notifications.php'; + const apiPath = (window.location.origin + window.location.pathname).split('/admin/')[0] + '/api/'; + const url = apiPath + 'admin_notifications.php?v=' + Date.now() + (isDashboard ? '&stats=1' : ''); fetch(url) .then(r => r.json()) diff --git a/api/chat.php b/api/chat.php index b405aa6..7d4fd37 100644 --- a/api/chat.php +++ b/api/chat.php @@ -233,71 +233,55 @@ if ($action === 'admin_get_all') { exit; } try { - // Improved query to get all active chat sessions. - // We group by user_id if it's set (>0). - // If user_id is 0, we group by session_id. - // If session_id is also empty, we group by IP. + // Simplified and robust query for deployment compatibility $stmt = db()->query(" SELECT v.final_user_id as user_id, - v.effective_ip as ip_address, - v.effective_sid as session_id, - v.unread_count, + MAX(v.effective_ip) as ip_address, + MAX(v.effective_sid) as session_id, + SUM(v.is_unread) as unread_count, + MAX(v.has_recharge) as has_recharge, CASE WHEN m.message LIKE ' 0 THEN final_user_id ELSE 0 END, - CASE WHEN final_user_id = 0 THEN effective_sid ELSE '' END, - CASE WHEN final_user_id = 0 AND effective_sid = '' THEN effective_ip ELSE '' END + IFNULL(user_id, 0) as final_user_id, + CASE WHEN ip_address = '---' THEN '' ELSE IFNULL(ip_address, '') END as effective_ip, + IFNULL(session_id, '') as effective_sid, + created_at as last_activity, + NULL as user_time, + 0 as has_recharge, + CASE WHEN sender = 'user' AND is_read = 0 THEN 1 ELSE 0 END as is_unread + FROM messages + UNION ALL + SELECT + IFNULL(user_id, 0) as final_user_id, + CASE WHEN ip_address = '---' THEN '' ELSE IFNULL(ip_address, '') END as effective_ip, + IFNULL(session_id, '') as effective_sid, + last_ping as last_activity, + user_time, + 0 as has_recharge, + 0 as is_unread + FROM chat_visitors + UNION ALL + SELECT + IFNULL(user_id, 0) as final_user_id, + CASE WHEN ip_address = '---' THEN '' ELSE IFNULL(ip_address, '') END as effective_ip, + '' as effective_sid, + created_at as last_activity, + NULL as user_time, + 1 as has_recharge, + 0 as is_unread + FROM finance_requests WHERE type='recharge' AND status NOT IN ('3', '4') ) v LEFT JOIN ( SELECT m1.*, @@ -322,6 +306,10 @@ if ($action === 'admin_get_all') { (v.final_user_id = 0 AND v.effective_sid != '' AND v.effective_sid = r.session_id) OR (v.final_user_id = 0 AND v.effective_sid = '' AND v.effective_ip = r.ip_address) ) + GROUP BY + v.final_user_id, + CASE WHEN v.final_user_id = 0 THEN v.effective_sid ELSE '' END, + CASE WHEN v.final_user_id = 0 AND v.effective_sid = '' THEN v.effective_ip ELSE '' END ORDER BY created_at DESC "); $results = $stmt->fetchAll(); @@ -332,7 +320,8 @@ if ($action === 'admin_get_all') { echo json_encode($results); } catch (Exception $e) { error_log("Chat API Error: " . $e->getMessage()); - echo json_encode(['error' => $e->getMessage()]); + // Return structured error for front-end handling + echo json_encode(['success' => false, 'error' => $e->getMessage()]); } exit; } diff --git a/assets/pasted-20260222-081324-8196b7b9.png b/assets/pasted-20260222-081324-8196b7b9.png new file mode 100644 index 0000000000000000000000000000000000000000..888ae69be12df0b9fa0f806ea9a7399f4c09519d GIT binary patch literal 8910 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'; +const apiPath = (window.location.origin + window.location.pathname).split('/recharge.php')[0] + '/api/'; let rechargeCountdownInterval; let modalChatLastIds = new Set(); let remainingSeconds = 1800; @@ -430,7 +431,7 @@ async function updateRate() { // Try to get fresh rates try { - const resp = await fetch('api/exchange.php'); + const resp = await fetch(apiPath + 'exchange.php?v=' + Date.now()); const data = await resp.json(); if (data.success && data.rates) { exchangeRates = data.rates; @@ -496,7 +497,7 @@ function finishTransfer() { const formData = new FormData(); formData.append('action', 'complete_transfer'); formData.append('order_id', orderId); - fetch('api/finance.php', { method: 'POST', body: formData }) + fetch(apiPath + 'finance.php?v=' + Date.now(), { method: 'POST', body: formData }) .then(r => r.json()) .then(data => { if (data.success) renderRechargeUI({status: 'finished'}); }); } else { @@ -552,8 +553,7 @@ function startStatusPolling(order_id) { const modalEl = document.getElementById('rechargeModal'); if (!modalEl || !modalEl.classList.contains('show')) return; try { - const path = (window.REL_PATH || '') + `api/recharge_status.php?id=${order_id}&_t=${Date.now()}`; - const r = await fetch(path); + const r = await fetch(apiPath + `recharge_status.php?id=${order_id}&v=${Date.now()}`); const data = await r.json(); if (data.success) { console.log('Order status update:', data.status, data); @@ -745,7 +745,7 @@ function initModalChat() { scrollModalToBottom(); const formData = new FormData(); formData.append('file', file); formData.append('action', 'upload_image'); try { - const resp = await fetch('api/chat.php', { method: 'POST', body: formData }), data = await resp.json(); + const resp = await fetch(apiPath + 'chat.php?v=' + Date.now(), { method: 'POST', body: formData }), data = await resp.json(); document.querySelector(`[data-modal-id="${tempId}"]`)?.remove(); if (data.success) { appendModalMessage(data.message); scrollModalToBottom(); } } catch (err) { console.error(err); } @@ -757,7 +757,7 @@ function initModalChat() { appendModalMessage({ id: tempId, sender: 'user', message: msg, created_at: new Date().toISOString() }); scrollModalToBottom(); try { - const resp = await fetch('api/chat.php?action=send_message', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `message=${encodeURIComponent(msg)}` }); + const resp = await fetch(apiPath + 'chat.php?action=send_message&v=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `message=${encodeURIComponent(msg)}` }); const data = await resp.json(); document.querySelector(`[data-modal-id="${tempId}"]`)?.remove(); if (data.success) { appendModalMessage(data.message); scrollModalToBottom(); } @@ -769,8 +769,8 @@ function initModalChat() { return; } try { - fetch(`api/chat.php?action=ping&user_time=${encodeURIComponent(new Date().toLocaleString())}`); - const resp = await fetch('api/chat.php?action=get_messages'), data = await resp.json(); + fetch(apiPath + `chat.php?action=ping&user_time=${encodeURIComponent(new Date().toLocaleString())}&v=` + Date.now()); + const resp = await fetch(apiPath + 'chat.php?action=get_messages&v=' + Date.now()), data = await resp.json(); if (Array.isArray(data)) { data.forEach(m => { if (!modalChatLastIds.has(m.id)) { appendModalMessage(m); modalChatLastIds.add(m.id); scrollModalToBottom(); } }); } } catch (err) {} setTimeout(modalPoll, 2000); @@ -779,7 +779,7 @@ function initModalChat() { } async function sendModalMessage(msg) { - try { await fetch('api/chat.php?action=send_message', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `message=${encodeURIComponent(msg)}` }); } catch (err) {} + try { await fetch(apiPath + 'chat.php?action=send_message&v=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `message=${encodeURIComponent(msg)}` }); } catch (err) {} } function appendModalMessage(m) { @@ -812,7 +812,7 @@ function confirmFiatOrder(btn, event) { if (isNaN(amount) || amount <= 0) { notify('warning', ''); return; } const originalText = btn.innerHTML; btn.disabled = true; btn.innerHTML = `${originalText}`; const formData = new FormData(); formData.append('action', 'recharge'); formData.append('amount', amount / rate); formData.append('symbol', 'USDT'); formData.append('fiat_amount', amount); formData.append('fiat_currency', currency); formData.append('method', ' (' + currency + ')'); - fetch((window.REL_PATH || '') + 'api/finance.php', { method: 'POST', body: formData }).then(r => r.json()).then(data => { + fetch(apiPath + 'finance.php?v=' + Date.now(), { method: 'POST', body: formData }).then(r => r.json()).then(data => { btn.disabled = false; btn.innerHTML = originalText; if (data.success) { let msg = ``; @@ -832,7 +832,7 @@ function confirmCryptoOrder(btn, event) { if (isNaN(amount) || amount <= 0) { notify('warning', ''); return; } const originalText = btn.innerHTML; btn.disabled = true; btn.innerHTML = `${originalText}`; const formData = new FormData(); formData.append('action', 'recharge'); formData.append('amount', amount); formData.append('symbol', 'USDT'); formData.append('method', currentNetwork); - fetch((window.REL_PATH || '') + 'api/finance.php', { method: 'POST', body: formData }).then(r => r.json()).then(data => { + fetch(apiPath + 'finance.php?v=' + Date.now(), { method: 'POST', body: formData }).then(r => r.json()).then(data => { btn.disabled = false; btn.innerHTML = originalText; if (data.success) { let msg = ``;