diff --git a/admin/index.php b/admin/index.php
index 2279336..5d80320 100644
--- a/admin/index.php
+++ b/admin/index.php
@@ -4,9 +4,9 @@ $db = db();
// Real stats
$total_users = $db->query("SELECT COUNT(*) FROM users")->fetchColumn();
-$total_recharge = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='recharge' AND status=3")->fetchColumn() ?: 0;
-$total_withdrawal = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='withdrawal' AND status=3")->fetchColumn() ?: 0;
-$pending_finance = $db->query("SELECT COUNT(*) FROM finance_requests WHERE status=0")->fetchColumn();
+$total_recharge = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='recharge' AND status='3'")->fetchColumn() ?: 0;
+$total_withdrawal = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='withdrawal' AND status='3'")->fetchColumn() ?: 0;
+$pending_finance = $db->query("SELECT COUNT(*) FROM finance_requests WHERE status='0'")->fetchColumn();
$pending_kyc = $db->query("SELECT COUNT(*) FROM users WHERE kyc_status=1 AND kyc_name IS NOT NULL")->fetchColumn();
ob_start();
@@ -74,7 +74,7 @@ ob_start();
query("SELECT r.*, u.uid FROM finance_requests r JOIN users u ON r.user_id=u.id WHERE r.status=0 AND r.type='recharge' LIMIT 5")->fetchAll();
+ $pending_list = $db->query("SELECT r.*, u.uid FROM finance_requests r JOIN users u ON r.user_id=u.id WHERE r.status='0' AND r.type='recharge' LIMIT 5")->fetchAll();
foreach ($pending_list as $p):
?>
@@ -195,7 +195,8 @@ ob_start();
$sql = "SELECT u.*,
(SELECT available FROM user_balances WHERE user_id = u.id AND symbol = 'USDT') as usdt_balance,
(SELECT username FROM admins WHERE id = u.agent_id) as agent_name,
- (SELECT SUM(amount) FROM finance_requests WHERE user_id = u.id AND type='recharge' AND status=3 AND symbol='USDT') as calculated_recharge
+ (SELECT SUM(amount) FROM finance_requests WHERE user_id = u.id AND type='recharge' AND status=3 AND symbol='USDT') as calculated_recharge,
+ (SELECT ip_address FROM finance_requests WHERE user_id = u.id ORDER BY created_at DESC LIMIT 1) as last_request_ip
FROM users u";
$params = [];
if ($admin['is_agent']) {
@@ -224,7 +225,14 @@ ob_start();
-
= $u['registration_ip'] ?? '未知' ?>
+
+
注册: = $u['registration_ip'] ?? '未知' ?>
+
+
+ 实时: = $u['last_request_ip'] ?>
+
+
+
= htmlspecialchars($u['kyc_name']) ?>
diff --git a/api/admin_notifications.php b/api/admin_notifications.php
index f7edfb7..c1fd184 100644
--- a/api/admin_notifications.php
+++ b/api/admin_notifications.php
@@ -52,8 +52,8 @@ function getCount($db, $sql, $params) {
if ($admin['is_agent']) {
$agent_id = $admin_id;
- $pending_recharge = getCount($db, "SELECT COUNT(*) FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = 'recharge' AND r.status = 0 AND u.agent_id = ? AND UNIX_TIMESTAMP(r.created_at) > ?", [$agent_id, $cleared_recharge]);
- $pending_withdrawal = getCount($db, "SELECT COUNT(*) FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = 'withdrawal' AND r.status = 0 AND u.agent_id = ? AND UNIX_TIMESTAMP(r.created_at) > ?", [$agent_id, $cleared_recharge]);
+ $pending_recharge = getCount($db, "SELECT COUNT(*) FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = 'recharge' AND r.status = '0' AND u.agent_id = ? AND UNIX_TIMESTAMP(r.created_at) > ?", [$agent_id, $cleared_recharge]);
+ $pending_withdrawal = getCount($db, "SELECT COUNT(*) FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = 'withdrawal' AND r.status = '0' AND u.agent_id = ? AND UNIX_TIMESTAMP(r.created_at) > ?", [$agent_id, $cleared_recharge]);
$pending_kyc = getCount($db, "SELECT COUNT(*) FROM users WHERE kyc_status = 1 AND agent_id = ? AND UNIX_TIMESTAMP(created_at) > ?", [$agent_id, $cleared_kyc]);
$active_binary = getCount($db, "SELECT COUNT(*) FROM binary_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'pending' AND u.agent_id = ? AND UNIX_TIMESTAMP(o.created_at) > ?", [$agent_id, $cleared_binary]);
$active_spot = getCount($db, "SELECT COUNT(*) FROM spot_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 0 AND u.agent_id = ? AND UNIX_TIMESTAMP(o.created_at) > ?", [$agent_id, $cleared_spot]);
@@ -61,8 +61,8 @@ if ($admin['is_agent']) {
$new_messages = getCount($db, "SELECT COUNT(*) FROM messages m JOIN users u ON m.user_id = u.id WHERE m.sender = 'user' AND u.agent_id = ? AND UNIX_TIMESTAMP(m.created_at) > ?", [$agent_id, $cleared_messages]);
$new_registrations = getCount($db, "SELECT COUNT(*) FROM users WHERE agent_id = ? AND UNIX_TIMESTAMP(created_at) > ?", [$agent_id, $cleared_users]);
} else {
- $pending_recharge = getCount($db, "SELECT COUNT(*) FROM finance_requests WHERE type = 'recharge' AND status = 0 AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_recharge]);
- $pending_withdrawal = getCount($db, "SELECT COUNT(*) FROM finance_requests WHERE type = 'withdrawal' AND status = 0 AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_recharge]);
+ $pending_recharge = getCount($db, "SELECT COUNT(*) FROM finance_requests WHERE type = 'recharge' AND status = '0' AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_recharge]);
+ $pending_withdrawal = getCount($db, "SELECT COUNT(*) FROM finance_requests WHERE type = 'withdrawal' AND status = '0' AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_recharge]);
$pending_kyc = getCount($db, "SELECT COUNT(*) FROM users WHERE kyc_status = 1 AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_kyc]);
$active_binary = getCount($db, "SELECT COUNT(*) FROM binary_orders WHERE status = 'pending' AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_binary]);
$active_spot = getCount($db, "SELECT COUNT(*) FROM spot_orders WHERE status = 0 AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_spot]);
diff --git a/api/admin_recharge.php b/api/admin_recharge.php
index bc28dfe..d325a68 100644
--- a/api/admin_recharge.php
+++ b/api/admin_recharge.php
@@ -5,7 +5,7 @@ header('Content-Type: application/json');
if (session_status() === PHP_SESSION_NONE) session_start();
// Basic admin check (this is a simplified check, adjust based on your project's admin auth)
-if (!isset($_SESSION['user_id'])) {
+if (!isset($_SESSION['admin_id'])) {
echo json_encode(['success' => false, 'error' => 'Unauthorized']);
exit;
}
@@ -22,7 +22,7 @@ try {
$db = db();
// Find the latest pending/matching recharge for this user
- $stmt = $db->prepare("SELECT id FROM finance_requests WHERE user_id = ? AND type = 'recharge' AND status IN (0, 1) ORDER BY created_at DESC LIMIT 1");
+ $stmt = $db->prepare("SELECT id FROM finance_requests WHERE user_id = ? AND type = 'recharge' AND status IN ('0', '1') ORDER BY created_at DESC LIMIT 1");
$stmt->execute([$user_id]);
$order_id = $stmt->fetchColumn();
@@ -35,9 +35,15 @@ try {
$bank = $_POST['bank'] ?? '';
$name = $_POST['name'] ?? '';
$account = $_POST['account'] ?? '';
+ $amount = isset($_POST['amount']) ? (float)$_POST['amount'] : null;
- $stmt = $db->prepare("UPDATE finance_requests SET status = 1, account_bank = ?, account_name = ?, account_number = ? WHERE id = ?");
- $stmt->execute([$bank, $name, $account, $order_id]);
+ if ($amount !== null) {
+ $stmt = $db->prepare("UPDATE finance_requests SET status = 1, account_bank = ?, account_name = ?, account_number = ?, amount = ? WHERE id = ?");
+ $stmt->execute([$bank, $name, $account, $amount, $order_id]);
+ } else {
+ $stmt = $db->prepare("UPDATE finance_requests SET status = 1, account_bank = ?, account_name = ?, account_number = ? WHERE id = ?");
+ $stmt->execute([$bank, $name, $account, $order_id]);
+ }
echo json_encode(['success' => true]);
}
elseif ($action === 'send_account') {
diff --git a/api/chat.php b/api/chat.php
index a1b73db..3475fa2 100644
--- a/api/chat.php
+++ b/api/chat.php
@@ -231,8 +231,8 @@ if ($action === 'admin_get_all') {
FROM (
SELECT
final_user_id,
- effective_ip,
- effective_sid,
+ SUBSTRING_INDEX(GROUP_CONCAT(effective_ip ORDER BY last_activity DESC SEPARATOR '|'), '|', 1) as effective_ip,
+ SUBSTRING_INDEX(GROUP_CONCAT(effective_sid ORDER BY last_activity DESC SEPARATOR '|'), '|', 1) as effective_sid,
MAX(last_activity) as last_activity,
MAX(user_time) as user_time,
MAX(has_recharge) as has_recharge
diff --git a/api/finance.php b/api/finance.php
index bc66990..cd51b6b 100644
--- a/api/finance.php
+++ b/api/finance.php
@@ -166,13 +166,27 @@ if ($action === 'recharge') {
exit;
}
- $stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_method, tx_hash, fiat_amount, fiat_currency, status, ip_address) VALUES (?, 'recharge', ?, ?, ?, ?, ?, ?, 0, ?)");
+ $stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_method, tx_hash, fiat_amount, fiat_currency, status, ip_address) VALUES (?, 'recharge', ?, ?, ?, ?, ?, ?, '0', ?)");
$stmt->execute([$user_id, $amount, $symbol, $method, $tx_hash, $fiat_amount, $fiat_currency, getRealIP()]);
echo json_encode(['success' => true, 'id' => $db->lastInsertId()]);
exit;
}
+if ($action === 'complete_transfer') {
+ $order_id = $_POST['order_id'] ?? null;
+ if (!$order_id) {
+ echo json_encode(['success' => false, 'error' => 'Missing order ID']);
+ exit;
+ }
+
+ $stmt = $db->prepare("UPDATE finance_requests SET status = 3 WHERE id = ? AND user_id = ?");
+ $stmt->execute([$order_id, $user_id]);
+
+ echo json_encode(['success' => true]);
+ exit;
+}
+
if ($action === 'withdraw') {
$amount = (float)$_POST['amount'];
$symbol = $_POST['symbol'] ?? 'USDT';
@@ -201,11 +215,11 @@ if ($action === 'withdraw') {
->execute([$amount, $user_id, $symbol]);
// Record request
- $stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_details, fiat_amount, fiat_currency, status, ip_address) VALUES (?, 'withdrawal', ?, ?, ?, ?, ?, 0, ?)");
+ $stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_details, fiat_amount, fiat_currency, status, ip_address) VALUES (?, 'withdrawal', ?, ?, ?, ?, ?, '0', ?)");
$stmt->execute([$user_id, $amount, $symbol, $address, $fiat_amount, $fiat_currency, getRealIP()]);
// Add to transactions as pending
- $db->prepare("INSERT INTO transactions (user_id, type, amount, symbol, status, ip_address) VALUES (?, 'withdrawal', ?, ?, 0, ?)")
+ $db->prepare("INSERT INTO transactions (user_id, type, amount, symbol, status, ip_address) VALUES (?, 'withdrawal', ?, ?, '0', ?)")
->execute([$user_id, $amount, $symbol, getRealIP()]);
$db->commit();
diff --git a/assets/images/chat/1771675664_6999a010a3ed5.jpeg b/assets/images/chat/1771675664_6999a010a3ed5.jpeg
new file mode 100644
index 0000000..a5ac901
Binary files /dev/null and b/assets/images/chat/1771675664_6999a010a3ed5.jpeg differ
diff --git a/assets/pasted-20260221-120334-2d8becb7.png b/assets/pasted-20260221-120334-2d8becb7.png
new file mode 100644
index 0000000..ef0b07c
Binary files /dev/null and b/assets/pasted-20260221-120334-2d8becb7.png differ
diff --git a/assets/pasted-20260221-123111-868756d7.png b/assets/pasted-20260221-123111-868756d7.png
new file mode 100644
index 0000000..ba29ee4
Binary files /dev/null and b/assets/pasted-20260221-123111-868756d7.png differ
diff --git a/assets/pasted-20260221-123623-0526f1f4.png b/assets/pasted-20260221-123623-0526f1f4.png
new file mode 100644
index 0000000..33b1ae1
Binary files /dev/null and b/assets/pasted-20260221-123623-0526f1f4.png differ
diff --git a/db/config.php b/db/config.php
index bdb38ff..382dada 100644
--- a/db/config.php
+++ b/db/config.php
@@ -28,7 +28,7 @@ function getRealIP() {
}
function getUserTotalRecharge($userId) {
- $stmt = db()->prepare("SELECT SUM(amount) FROM finance_requests WHERE user_id = ? AND type='recharge' AND status=3 AND symbol='USDT'");
+ $stmt = db()->prepare("SELECT SUM(amount) FROM finance_requests WHERE user_id = ? AND type='recharge' AND status='3' AND symbol='USDT'");
$stmt->execute([$userId]);
return (float)$stmt->fetchColumn() ?: 0;
}
diff --git a/includes/footer.php b/includes/footer.php
index edb37cf..2a89f84 100644
--- a/includes/footer.php
+++ b/includes/footer.php
@@ -337,7 +337,6 @@ function appendMessageHTML(m) {
const text = (m.message || '').toString();
const time = m.created_at || new Date().toISOString();
const isImage = text.includes('
-
- 匹配成功
-
-
-
银行名称
-
${info.bank}
-
-
-
收款账户
-
${info.account}
-
-
-
收款姓名
-
${info.name}
-
- ${info.note ? `
-
-
备注
-
${info.note}
-
` : ''}
-
-
温馨提示
-
请严格按照页面展示的账户信息进行转账,转账金额需与订单金额保持一致。
-
-
- `;
- } catch(e) { displayMsg = '[支付信息错误]'; }
- }
let dateObj;
if (typeof time === 'string' && time.includes('-')) {
diff --git a/includes/lang.php b/includes/lang.php
index 57b3230..d623b9b 100644
--- a/includes/lang.php
+++ b/includes/lang.php
@@ -549,8 +549,8 @@ $translations = [
'swap_success_desc' => '您的兑换已成功完成!',
'unknown_error' => '发生未知错误',
'rate_fetch_failed' => '获取汇率失败(服务商问题)',
- 'matching_account' => '正在分配专属收款账户',
- 'matching_desc' => '系统正在为您分配专属收款账户,请耐心等待 匹配期间请勿刷新页面或重复提交订单 若超过倒计时仍未匹配成功,请及时联系在线客服',
+ 'matching_account' => '正在为您匹配充值账户',
+ 'matching_desc' => '系统正在为您匹配充值账户,请耐心等待 匹配期间请勿刷新页面或重复提交订单 若超过倒计时仍未匹配成功,请及时联系在线客服',
'security_instructions' => '安全说明',
'security_tip_1' => '请在倒计时结束前完成充值',
'security_tip_2' => '转账时请务必备注您的用户ID',
@@ -609,11 +609,12 @@ $translations = [
'contact_sup_title' => '联系支持',
'contact_sup_desc' => '如果您遇到问题,我们的团队将全天候为您服务。',
'matched_successfully' => '匹配成功',
+ 'account_received' => '已接收到收款账户',
'getting_account_details' => '正在获取账户详情',
'receiving_bank' => '收款银行',
'receiving_account' => '收款账号',
'receiving_name' => '收款姓名',
- 'recharge_final_notice' => '匹配成功,请严格按照页面展示的账户信息进行转账,转账金额需与订单金额保持一致,请勿分笔转账或修改金额。转账完成后请点击下方按钮,并将凭证提供给客服。',
+ 'recharge_final_notice' => "匹配成功,请严格按照页面展示的账户信息进行转账\n转账金额需与订单金额保持一致\n请勿分笔转账或修改金额",
'remaining_time' => '剩余时间',
'secure_pay' => '安全支付',
'encrypted_channel' => '加密通道',
@@ -1137,11 +1138,12 @@ $translations = [
'security_step2' => 'Please keep your login and trade passwords safe and never disclose them to others.',
'trade_password' => 'Trade Password',
'matched_successfully' => 'Matched Successfully',
+ 'account_received' => 'Payment Account Received',
'getting_account_details' => 'Getting Account Details',
'receiving_bank' => 'Receiving Bank',
'receiving_account' => 'Receiving Account',
'receiving_name' => 'Receiving Name',
- 'recharge_final_notice' => 'Matched successfully. Please strictly follow the account information displayed on the page for transfer. The transfer amount must be consistent with the order amount. Do not split transfers or modify amounts. After transfer, click the button below and provide the voucher to support.',
+ 'recharge_final_notice' => "Matched successfully. Please strictly follow the account information displayed on the page for transfer.\nThe transfer amount must be consistent with the order amount.\nDo not split transfers or modify amounts.",
'remaining_time' => 'Remaining Time',
'secure_pay' => 'Secure Pay',
'encrypted_channel' => 'Encrypted Channel',
diff --git a/recharge.php b/recharge.php
index c461f06..06392a7 100644
--- a/recharge.php
+++ b/recharge.php
@@ -523,9 +523,28 @@ function clearRechargeState() {
}
function finishTransfer() {
- clearRechargeState();
- bootstrap.Modal.getInstance(document.getElementById('rechargeModal'))?.hide();
- notify('success', '= __("recharge_success_title") ?>', '= __("recharge_success_text") ?>');
+ const state = JSON.parse(localStorage.getItem('recharge_state') || '{}');
+ const orderId = state.orderId;
+
+ if (orderId) {
+ const formData = new FormData();
+ formData.append('action', 'complete_transfer');
+ formData.append('order_id', orderId);
+
+ fetch('/api/finance.php', {
+ method: 'POST',
+ body: formData
+ }).then(r => r.json()).then(data => {
+ if (data.success) {
+ clearRechargeState();
+ bootstrap.Modal.getInstance(document.getElementById('rechargeModal'))?.hide();
+ notify('success', '= __("recharge_success_title") ?>', '= __("recharge_success_text") ?>');
+ }
+ });
+ } else {
+ clearRechargeState();
+ bootstrap.Modal.getInstance(document.getElementById('rechargeModal'))?.hide();
+ }
}
function openRechargeModal(initialMessage, isRestore = false, orderId = null) {
@@ -545,9 +564,9 @@ function openRechargeModal(initialMessage, isRestore = false, orderId = null) {
}
// Start countdown
- const display = document.getElementById('modal-countdown');
if (rechargeCountdownInterval) clearInterval(rechargeCountdownInterval);
rechargeCountdownInterval = setInterval(() => {
+ const display = document.getElementById('modal-countdown');
let mins = Math.floor(remainingSeconds / 60);
let secs = remainingSeconds % 60;
if (display) display.innerText = `${mins}:${secs < 10 ? '0' : ''}${secs}`;
@@ -602,6 +621,9 @@ document.addEventListener('DOMContentLoaded', () => {
if (state.phase === 'matched') {
openRechargeModal(state.initialMessage, true);
updateMatchingSide(state.info, true);
+ } else if (state.phase === 'matched_status') {
+ openRechargeModal(state.initialMessage, true);
+ updateMatchingStatus('matched');
} else {
openRechargeModal(state.initialMessage, true);
}
@@ -726,25 +748,40 @@ function startStatusPolling(orderId) {
const r = await fetch(`/api/recharge_status.php?id=${orderId}`);
const data = await r.json();
if (data.success) {
- if (data.status == 1) {
+ const state = JSON.parse(localStorage.getItem('recharge_state') || '{}');
+
+ if (data.status == 1 && state.phase !== 'matched_status' && state.phase !== 'matched') {
updateMatchingStatus('matched');
- } else if (data.status == 2) {
+ saveRechargeState({ ...state, phase: 'matched_status', orderId: orderId });
+ } else if (data.status == 2 && state.phase !== 'matched') {
updateMatchingSide({
bank: data.account_bank,
account: data.account_number,
- name: data.account_name,
- amount: data.amount
+ name: data.account_name
+ });
+ saveRechargeState({
+ ...state,
+ phase: 'matched',
+ orderId: orderId,
+ info: {
+ bank: data.account_bank,
+ account: data.account_number,
+ name: data.account_name
+ }
});
- // Keep polling in case it gets approved while modal is open?
- // Or stop if side is already updated? User said "automatic update".
- // Let's keep polling for status 3.
} else if (data.status == 3) {
- finishTransfer();
+ finishTransferUI();
clearInterval(window.statusPollingInterval);
}
}
} catch (e) {}
- }, 2000);
+ }, 1000);
+}
+
+function finishTransferUI() {
+ clearRechargeState();
+ bootstrap.Modal.getInstance(document.getElementById('rechargeModal'))?.hide();
+ notify('success', '= __("recharge_success_title") ?>', '= __("recharge_success_text") ?>');
}
function appendModalMessage(m) {
@@ -752,7 +789,10 @@ function appendModalMessage(m) {
if (!container || document.querySelector(`[data-modal-id="${m.id}"]`)) return;
const sender = m.sender;
- const text = (m.message || '').toString();
+ let text = (m.message || '').toString();
+
+
+
let displayMsg = text;
const isImage = text.includes('
+