This commit is contained in:
Flatlogic Bot 2026-02-21 03:04:07 +00:00
parent 2abf771e6c
commit 582dc33422
15 changed files with 473 additions and 253 deletions

View File

@ -6,28 +6,28 @@ require_once __DIR__ . '/includes/header.php';
<div class="row justify-content-center">
<div class="col-lg-8">
<h1 class="mb-4 fw-bold"><?php echo __('about_us'); ?></h1>
<div class="card bg-dark border-secondary p-4">
<p class="lead mb-4"><?php echo __('about_content'); ?></p>
<h3 class="mt-4 mb-3"><?= __('our_mission') ?></h3>
<p class="text-muted">
<div class="card bg-surface border-secondary p-4">
<p class="lead mb-4 text-white"><?php echo __('about_content'); ?></p>
<h3 class="mt-4 mb-3 text-white"><?= __('our_mission') ?></h3>
<p class="text-white-50">
<?= __('mission_content') ?>
</p>
<h3 class="mt-4 mb-3"><?= __('global_presence') ?></h3>
<p class="text-muted">
<h3 class="mt-4 mb-3 text-white"><?= __('global_presence') ?></h3>
<p class="text-white-50">
<?= __('presence_content') ?>
</p>
<div class="row mt-5 text-center">
<div class="col-4">
<h2 class="fw-bold text-primary">5M+</h2>
<p class="small text-muted"><?= __('users') ?></p>
<p class="small text-white-50"><?= __('users') ?></p>
</div>
<div class="col-4">
<h2 class="fw-bold text-primary">100+</h2>
<p class="small text-muted"><?= __('countries') ?></p>
<p class="small text-white-50"><?= __('countries') ?></p>
</div>
<div class="col-4">
<h2 class="fw-bold text-primary">$10B+</h2>
<p class="small text-muted"><?= __('daily_volume') ?></p>
<p class="small text-white-50"><?= __('daily_volume') ?></p>
</div>
</div>
</div>

View File

@ -250,86 +250,83 @@ let currentUserContext = '';
async function refreshUsers() {
try {
const searchInput = document.getElementById('user-search');
const search = searchInput ? searchInput.value.toLowerCase() : '';
const r = await fetch('/api/chat.php?action=admin_get_all');
const users = await r.json();
const list = document.getElementById('user-list');
if (!list) return;
if (users.error) {
console.error('API Error:', users.error);
list.innerHTML = `<div class="p-4 text-center text-danger small">接口错误: ${users.error}</div>`;
return;
}
if (!Array.isArray(users)) {
console.error('API response is not an array:', users);
list.innerHTML = `<div class="p-4 text-center text-danger small">数据格式错误</div>`;
return;
}
if (users.length === 0) {
list.innerHTML = '<div class="p-4 text-center text-muted small">暂无活跃会话 (720h内)</div>';
return;
}
const list = document.getElementById('user-list');
const searchInput = document.getElementById('user-search');
const search = searchInput ? searchInput.value.toLowerCase() : '';
let html = '';
users.forEach(u => {
try {
const userId = u.user_id;
const username = u.username || '匿名用户';
const uid = u.uid || '---';
const ip = u.ip_address || '---';
const rawRemark = u.remark || '';
const remark = rawRemark.toString().replace(/\n/g, " ");
const userTime = u.user_time || '---';
const lastTime = u.created_at ? new Date(u.created_at.replace(/-/g, "/")) : new Date();
let lastMsgText = u.message || '';
if (lastMsgText.startsWith('[PAYMENT_INFO]')) {
lastMsgText = '[收款账号信息]';
}
const isActive = (selectedIp === ip && selectedUser == userId);
if (isActive) {
const infoUserTime = document.getElementById('info-user-time');
if (infoUserTime) infoUserTime.innerText = userTime;
}
// Using data attributes to avoid escaping issues in onclick
html += `
<div class="user-card ${isActive ? 'active' : ''}"
data-user-id="${userId}"
data-ip="${ip}"
data-name="${username.replace(/"/g, '&quot;')}"
data-uid="${uid}"
data-remark="${remark.replace(/"/g, '&quot;')}"
data-user-time="${userTime}">
<div class="d-flex justify-content-between mb-1">
<span class="fw-bold small text-truncate" style="max-width: 150px;">${username}</span>
<span class="text-muted" style="font-size: 10px;">${lastTime.toLocaleTimeString('zh-CN', {hour: '2-digit', minute:'2-digit'})}</span>
</div>
${rawRemark ? `<div class="small text-danger text-truncate mb-1" style="font-size: 11px;">[备注: ${rawRemark}]</div>` : ''}
<div class="small text-truncate text-muted mb-1" style="font-size: 12px;">${lastMsgText}</div>
<div class="d-flex justify-content-between align-items-center" style="font-size: 10px;">
<span class="text-secondary">UID: ${uid}</span>
<span class="text-primary fw-bold">${ip}</span>
</div>
</div>
`;
} catch (e) {
console.error('Error rendering user card:', e, u);
const userId = u.user_id || 0;
const username = (u.username || '匿名用户').toString();
const uid = (u.uid || '---').toString();
const ip = (u.ip_address || '---').toString();
const rawRemark = (u.remark || '').toString();
const userTime = (u.user_time || '---').toString();
const lastTimeStr = u.created_at ? u.created_at.replace(/-/g, "/") : new Date().toISOString();
const lastTime = new Date(lastTimeStr);
// Search filter
if (search && !username.toLowerCase().includes(search) && !ip.includes(search) && !uid.includes(search)) {
return;
}
let lastMsgText = (u.message || '').toString();
if (lastMsgText.startsWith('[PAYMENT_INFO]')) {
lastMsgText = '[收款账号信息]';
}
const isActive = (selectedIp === ip && selectedUser == userId);
// Safe strings for onclick
const jsName = username.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
const jsRemark = rawRemark.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
html += `
<div class="user-card ${isActive ? 'active' : ''}"
onclick="openChat('${userId}', '${ip}', '${jsName}', '${uid}', '${jsRemark}', '${userTime}')">
<div class="d-flex justify-content-between mb-1">
<span class="fw-bold small text-truncate" style="max-width: 150px;">${username}</span>
<span class="text-muted" style="font-size: 10px;">${isNaN(lastTime.getTime()) ? '---' : lastTime.toLocaleTimeString('zh-CN', {hour: '2-digit', minute:'2-digit'})}</span>
</div>
${rawRemark ? `<div class="small text-danger text-truncate mb-1" style="font-size: 11px;">[备注: ${rawRemark}]</div>` : ''}
<div class="small text-truncate text-muted mb-1" style="font-size: 12px;">${lastMsgText}</div>
<div class="d-flex justify-content-between align-items-center" style="font-size: 10px;">
<span class="text-secondary">UID: ${uid}</span>
<span class="text-primary fw-bold">${ip}</span>
</div>
</div>
`;
});
list.innerHTML = html || '<div class="p-4 text-center text-muted small">暂无活跃会话</div>';
list.innerHTML = html || '<div class="p-4 text-center text-muted small">未找到匹配的会话</div>';
} catch (err) {
console.error('Refresh users failed:', err);
const list = document.getElementById('user-list');
if (list) {
list.innerHTML = `<div class="p-4 text-center text-danger small">脚本运行错误,请刷新页面</div>`;
}
}
}
// Handle clicks on user cards using event delegation
document.getElementById('user-list').addEventListener('click', (e) => {
const card = e.target.closest('.user-card');
if (card) {
const d = card.dataset;
openChat(d.userId, d.ip, d.name, d.uid, d.remark, d.userTime);
}
});
function openChat(userId, ip, name, uid, remark, userTime) {
selectedUser = userId;
selectedIp = ip;
@ -347,7 +344,7 @@ function openChat(userId, ip, name, uid, remark, userTime) {
lastMsgId = 0;
fetchMessages();
refreshUsers(); // Refresh list to update active state
refreshUsers();
}
async function recallMessage(msgId) {
@ -391,7 +388,6 @@ async function fetchMessages() {
const msgs = await r.json();
if (!msgs || !Array.isArray(msgs)) return;
// If user changed, clear everything
const context = selectedUser + '_' + selectedIp;
if (currentUserContext !== context) {
document.getElementById('messages-area').innerHTML = '';
@ -427,7 +423,7 @@ async function fetchMessages() {
function appendMessageHTML(m) {
const area = document.getElementById('messages-area');
if (!area || area.querySelector(`[data-id="${m.id}"]`)) return;
if (!area) return;
const time = m.created_at || new Date().toISOString();
const msgDate = time.includes('-') ? new Date(time.replace(/-/g, "/")) : new Date(time);
@ -440,10 +436,10 @@ function appendMessageHTML(m) {
div.className = `msg ${m.sender === 'admin' ? 'msg-admin' : 'msg-user'}`;
div.setAttribute('data-id', m.id);
let displayMsg = m.message;
let displayMsg = (m.message || '').toString();
if (isPaymentInfo) {
try {
const info = JSON.parse(m.message.replace('[PAYMENT_INFO]', ''));
const info = JSON.parse(displayMsg.replace('[PAYMENT_INFO]', ''));
displayMsg = `<div class="p-2 border border-white border-opacity-20 rounded bg-white bg-opacity-10 small">
<div class="fw-bold"><i class="bi bi-bank me-1"></i>已发送收款账号</div>
<div class="mt-1 opacity-75">${info.bank} - ${info.name}</div>
@ -469,9 +465,10 @@ document.getElementById('plus-btn').addEventListener('click', () => {
document.getElementById('image-input').click();
});
const paymentModal = new bootstrap.Modal(document.getElementById('paymentModal'));
const paymentModalEl = document.getElementById('paymentModal');
const paymentModal = paymentModalEl ? new bootstrap.Modal(paymentModalEl) : null;
document.getElementById('payment-btn').addEventListener('click', () => {
paymentModal.show();
if (paymentModal) paymentModal.show();
});
async function sendPaymentInfo() {
@ -497,8 +494,7 @@ async function sendPaymentInfo() {
const r = await fetch('/api/chat.php?action=admin_send', { method: 'POST', body: fd });
const res = await r.json();
if (res.success) {
paymentModal.hide();
// Clear inputs
if (paymentModal) paymentModal.hide();
document.getElementById('pay-bank').value = '';
document.getElementById('pay-name').value = '';
document.getElementById('pay-account').value = '';
@ -512,7 +508,6 @@ document.getElementById('image-input').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
// Local preview for "0 latency"
const localUrl = URL.createObjectURL(file);
const tempId = 'temp_img_' + Date.now();
const localMsgHtml = `<img src="${localUrl}" class="img-fluid rounded" style="max-width: 100%; max-height: 250px; object-fit: contain; margin: 5px 0; opacity: 0.6;">`;
@ -524,7 +519,7 @@ document.getElementById('image-input').addEventListener('change', async (e) => {
created_at: new Date().toISOString()
});
const area = document.getElementById('messages-area');
area.scrollTop = area.scrollHeight;
if (area) area.scrollTop = area.scrollHeight;
const formData = new FormData();
formData.append('file', file);
@ -538,13 +533,12 @@ document.getElementById('image-input').addEventListener('change', async (e) => {
});
const res = await r.json();
// Remove temp
const tempMsg = document.querySelector(`[data-id="${tempId}"]`);
if (tempMsg) tempMsg.remove();
if (res.success && res.message) {
appendMessageHTML(res.message);
area.scrollTop = area.scrollHeight;
if (area) area.scrollTop = area.scrollHeight;
fetchMessages();
} else {
alert('上传失败: ' + res.error);
@ -554,7 +548,7 @@ document.getElementById('image-input').addEventListener('change', async (e) => {
if (tempMsg) tempMsg.remove();
}
e.target.value = ''; // Reset
e.target.value = '';
setTimeout(() => URL.revokeObjectURL(localUrl), 5000);
});
@ -566,7 +560,6 @@ document.getElementById('chat-form').addEventListener('submit', async (e) => {
input.value = '';
// Optimistic UI
const tempId = 'temp_msg_' + Date.now();
appendMessageHTML({
id: tempId,
@ -575,7 +568,7 @@ document.getElementById('chat-form').addEventListener('submit', async (e) => {
created_at: new Date().toISOString()
});
const area = document.getElementById('messages-area');
area.scrollTop = area.scrollHeight;
if (area) area.scrollTop = area.scrollHeight;
const fd = new URLSearchParams();
fd.append('message', msg);
@ -591,7 +584,7 @@ document.getElementById('chat-form').addEventListener('submit', async (e) => {
if (res.success && res.message) {
appendMessageHTML(res.message);
area.scrollTop = area.scrollHeight;
if (area) area.scrollTop = area.scrollHeight;
fetchMessages();
}
} catch(err) {}

View File

@ -95,7 +95,7 @@ ob_start();
$type = $_GET['type'] ?? 'recharge';
$user_id = isset($_GET['user_id']) ? (int)$_GET['user_id'] : null;
$sql = "SELECT r.*, u.username, u.uid FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = ?";
$sql = "SELECT r.*, u.username, u.uid FROM finance_requests r LEFT JOIN users u ON r.user_id = u.id WHERE r.type = ?";
$params = [$type];
if ($admin['is_agent']) {
@ -155,8 +155,8 @@ $requests = $stmt->fetchAll();
<tr>
<td><?= $r['id'] ?></td>
<td>
<div><?= htmlspecialchars($r['username']) ?></div>
<code class="small"><?= $r['uid'] ?></code>
<div><?= htmlspecialchars($r['username'] ?? '未知用户') ?></div>
<code class="small"><?= htmlspecialchars($r['uid'] ?? '---') ?></code>
</td>
<td>
<span class="fw-bold <?= $r['type'] === 'recharge' ? 'text-success' : 'text-danger' ?>">

40
api.php
View File

@ -4,48 +4,48 @@ require_once __DIR__ . '/includes/header.php';
?>
<main class="container py-5">
<h1 class="mb-4 fw-bold"><?php echo __('api_doc'); ?></h1>
<div class="card bg-dark border-secondary p-4">
<div class="card bg-surface border-secondary p-4 shadow-sm">
<div class="row">
<div class="col-md-3 border-end border-secondary">
<nav class="nav flex-column sticky-top" style="top: 100px;">
<a class="nav-link text-white fw-bold mb-2" href="#intro"><?= __('api_intro') ?></a>
<a class="nav-link text-muted mb-2" href="#auth"><?= __('api_auth') ?></a>
<a class="nav-link text-muted mb-2" href="#market"><?= __('api_market_data') ?></a>
<a class="nav-link text-muted mb-2" href="#trade"><?= __('api_trade_endpoints') ?></a>
<a class="nav-link text-muted mb-2" href="#errors"><?= __('api_errors') ?></a>
<a class="nav-link text-white-50 mb-2" href="#auth"><?= __('api_auth') ?></a>
<a class="nav-link text-white-50 mb-2" href="#market"><?= __('api_market_data') ?></a>
<a class="nav-link text-white-50 mb-2" href="#trade"><?= __('api_trade_endpoints') ?></a>
<a class="nav-link text-white-50 mb-2" href="#errors"><?= __('api_errors') ?></a>
</nav>
</div>
<div class="col-md-9 ps-md-4">
<section id="intro" class="mb-5">
<h2 class="fw-bold"><?= __('api_intro') ?></h2>
<p class="text-muted"><?= __('api_intro_desc') ?></p>
<h2 class="fw-bold text-white"><?= __('api_intro') ?></h2>
<p class="text-white-50"><?= __('api_intro_desc') ?></p>
</section>
<section id="auth" class="mb-5">
<h2 class="fw-bold"><?= __('api_auth') ?></h2>
<p class="text-muted"><?= __('api_auth_desc') ?></p>
<div class="bg-black p-3 rounded mb-3">
<h2 class="fw-bold text-white"><?= __('api_auth') ?></h2>
<p class="text-white-50"><?= __('api_auth_desc') ?></p>
<div class="bg-black p-3 rounded mb-3 border border-secondary">
<code class="text-success">Authorization: Bearer YOUR_API_KEY</code>
</div>
</section>
<section id="market" class="mb-5">
<h2 class="fw-bold"><?= __('api_market_data') ?></h2>
<h5 class="mt-4"><?= __('api_get_ticker') ?></h5>
<div class="bg-black p-3 rounded mb-2">
<code>GET /api/v1/market/ticker?symbol=BTCUSDT</code>
<h2 class="fw-bold text-white"><?= __('api_market_data') ?></h2>
<h5 class="mt-4 text-white"><?= __('api_get_ticker') ?></h5>
<div class="bg-black p-3 rounded mb-2 border border-secondary">
<code class="text-info">GET /api/v1/market/ticker?symbol=BTCUSDT</code>
</div>
<p class="small text-muted"><?= __('api_get_ticker_desc') ?></p>
<p class="small text-white-50"><?= __('api_get_ticker_desc') ?></p>
</section>
<section id="trade" class="mb-5">
<h2 class="fw-bold"><?= __('trade') ?></h2>
<h5 class="mt-4"><?= __('api_place_order') ?></h5>
<div class="bg-black p-3 rounded mb-2">
<h2 class="fw-bold text-white"><?= __('trade') ?></h2>
<h5 class="mt-4 text-white"><?= __('api_place_order') ?></h5>
<div class="bg-black p-3 rounded mb-2 border border-secondary">
<code class="text-info">POST /api/v1/trade/order</code>
</div>
<p class="small text-muted"><?= __('api_payload_example') ?></p>
<pre class="bg-black p-3 rounded text-warning"><code>{
<p class="small text-white-50"><?= __('api_payload_example') ?></p>
<pre class="bg-black p-3 rounded text-warning border border-secondary"><code>{
"symbol": "BTCUSDT",
"side": "buy",
"type": "limit",

View File

@ -135,6 +135,7 @@ if ($action === 'ping') {
if ($action === 'admin_get_all') {
header('Content-Type: application/json');
if (!isset($_SESSION['admin_id'])) {
echo json_encode(['error' => 'Unauthorized']);
exit;
@ -147,18 +148,18 @@ if ($action === 'admin_get_all') {
v.ip_address,
CASE
WHEN m.message LIKE '<img%' THEN '[图片消息]'
WHEN m.message IS NULL AND v.has_recharge = 1 THEN '[充值申请]'
WHEN (m.message IS NULL OR m.message = '') AND v.has_recharge = 1 THEN '[充值申请]'
ELSE COALESCE(m.message, '新会话')
END as message,
COALESCE(m.created_at, v.last_activity) as created_at,
CASE WHEN u.email LIKE '%@user.byro' THEN u.username ELSE COALESCE(u.email, u.username) END as username,
COALESCE(u.username, u.email, CONCAT('访客 ', v.ip_address)) as username,
u.uid,
r.remark,
v.user_time
FROM (
SELECT
user_id,
MAX(ip_address) as ip_address,
ip_address,
MAX(last_activity) as last_activity,
MAX(user_time) as user_time,
MAX(has_recharge) as has_recharge
@ -169,7 +170,7 @@ if ($action === 'admin_get_all') {
UNION ALL
SELECT COALESCE(user_id, 0) as user_id, ip_address, created_at as last_activity, NULL as user_time, 1 as has_recharge FROM finance_requests
) t1
GROUP BY user_id, (CASE WHEN user_id = 0 THEN ip_address ELSE '0' END)
GROUP BY (CASE WHEN user_id = 0 THEN 0 ELSE user_id END), (CASE WHEN user_id = 0 THEN ip_address ELSE '0' END)
) v
LEFT JOIN (
SELECT m1.* FROM messages m1
@ -179,11 +180,12 @@ if ($action === 'admin_get_all') {
) m ON (v.user_id = COALESCE(m.user_id, 0) AND (v.user_id != 0 OR v.ip_address = m.ip_address))
LEFT JOIN users u ON (v.user_id = u.id AND v.user_id != 0)
LEFT JOIN chat_remarks r ON (v.user_id = COALESCE(r.user_id, 0) AND (v.user_id != 0 OR v.ip_address = r.ip_address))
WHERE v.last_activity > DATE_SUB(NOW(), INTERVAL 72 HOUR)
WHERE v.last_activity > DATE_SUB(NOW(), INTERVAL 720 HOUR)
ORDER BY created_at DESC
");
echo json_encode($stmt->fetchAll());
} catch (Exception $e) {
error_log("Chat API Error: " . $e->getMessage());
echo json_encode(['error' => $e->getMessage()]);
}
exit;

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -4,14 +4,14 @@ require_once __DIR__ . '/includes/header.php';
?>
<main class="container py-5">
<h1 class="mb-4 fw-bold"><?php echo __('fee_structure'); ?></h1>
<div class="card bg-dark border-secondary p-4 mb-5">
<p class="text-muted"><?php echo __('fees_content'); ?></p>
<div class="card bg-surface border-secondary p-4 mb-5 shadow-sm">
<p class="text-white-50"><?php echo __('fees_content'); ?></p>
<h3 class="mt-4 mb-4"><?= __('spot_fees') ?></h3>
<h3 class="mt-4 mb-4 text-white"><?= __('spot_fees') ?></h3>
<div class="table-responsive">
<table class="table table-dark table-hover border-secondary">
<thead>
<tr class="text-muted">
<tr class="text-white-50">
<th><?= __('tier') ?></th>
<th><?= __('trading_vol_30d') ?></th>
<th><?= __('maker_fee') ?></th>
@ -19,25 +19,25 @@ require_once __DIR__ . '/includes/header.php';
</tr>
</thead>
<tbody>
<tr>
<tr class="text-white">
<td><?= __('level') ?> 0 (<?= __('regular') ?>)</td>
<td>< $10,000</td>
<td>0.100%</td>
<td>0.100%</td>
</tr>
<tr>
<tr class="text-white">
<td><?= __('level') ?> 1</td>
<td> $10,000</td>
<td>0.080%</td>
<td>0.090%</td>
</tr>
<tr>
<tr class="text-white">
<td><?= __('level') ?> 2</td>
<td> $100,000</td>
<td>0.060%</td>
<td>0.080%</td>
</tr>
<tr>
<tr class="text-white">
<td><?= __('level') ?> 3</td>
<td> $500,000</td>
<td>0.040%</td>
@ -47,23 +47,23 @@ require_once __DIR__ . '/includes/header.php';
</table>
</div>
<h3 class="mt-5 mb-4"><?= __('contract_fees') ?></h3>
<h3 class="mt-5 mb-4 text-white"><?= __('contract_fees') ?></h3>
<div class="table-responsive">
<table class="table table-dark table-hover border-secondary">
<thead>
<tr class="text-muted">
<tr class="text-white-50">
<th><?= __('tier') ?></th>
<th><?= __('maker_fee') ?></th>
<th><?= __('taker_fee') ?></th>
</tr>
</thead>
<tbody>
<tr>
<tr class="text-white">
<td><?= __('regular') ?></td>
<td>0.020%</td>
<td>0.050%</td>
</tr>
<tr>
<tr class="text-white">
<td><?= __('level') ?> 1</td>
<td>0.015%</td>
<td>0.045%</td>

View File

@ -5,7 +5,7 @@ require_once __DIR__ . '/includes/header.php';
<main class="container py-5">
<div class="text-center mb-5">
<h1 class="display-5 fw-bold mb-3"><?php echo __('help'); ?></h1>
<p class="text-muted"><?= __('help_subtitle') ?></p>
<p class="text-white-50"><?= __('help_subtitle') ?></p>
<div class="input-group mb-3 mx-auto" style="max-width: 600px;">
<input type="text" class="form-control form-control-lg bg-dark text-white border-secondary" placeholder="<?= __('help_search_placeholder') ?>">
<button class="btn btn-primary px-4"><i class="bi bi-search"></i></button>
@ -14,50 +14,50 @@ require_once __DIR__ . '/includes/header.php';
<div class="row g-4">
<div class="col-md-4">
<div class="card bg-dark border-secondary h-100 p-4 text-center hover-up">
<div class="card bg-surface border-secondary h-100 p-4 text-center hover-up shadow-sm">
<i class="bi bi-person-plus fs-1 text-primary mb-3"></i>
<h4 class="fw-bold"><?= __('getting_started') ?></h4>
<p class="text-muted small"><?= __('getting_started_desc') ?></p>
<h4 class="fw-bold text-white"><?= __('getting_started') ?></h4>
<p class="text-white-50 small"><?= __('getting_started_desc') ?></p>
<a href="#" class="stretched-link"></a>
</div>
</div>
<div class="col-md-4">
<div class="card bg-dark border-secondary h-100 p-4 text-center hover-up">
<div class="card bg-surface border-secondary h-100 p-4 text-center hover-up shadow-sm">
<i class="bi bi-wallet2 fs-1 text-success mb-3"></i>
<h4 class="fw-bold"><?= __('dep_with_title') ?></h4>
<p class="text-muted small"><?= __('dep_with_desc') ?></p>
<h4 class="fw-bold text-white"><?= __('dep_with_title') ?></h4>
<p class="text-white-50 small"><?= __('dep_with_desc') ?></p>
<a href="#" class="stretched-link"></a>
</div>
</div>
<div class="col-md-4">
<div class="card bg-dark border-secondary h-100 p-4 text-center hover-up">
<div class="card bg-surface border-secondary h-100 p-4 text-center hover-up shadow-sm">
<i class="bi bi-graph-up-arrow fs-1 text-info mb-3"></i>
<h4 class="fw-bold"><?= __('trading_tutorials') ?></h4>
<p class="text-muted small"><?= __('trading_tutorials_desc') ?></p>
<h4 class="fw-bold text-white"><?= __('trading_tutorials') ?></h4>
<p class="text-white-50 small"><?= __('trading_tutorials_desc') ?></p>
<a href="#" class="stretched-link"></a>
</div>
</div>
<div class="col-md-4">
<div class="card bg-dark border-secondary h-100 p-4 text-center hover-up">
<div class="card bg-surface border-secondary h-100 p-4 text-center hover-up shadow-sm">
<i class="bi bi-shield-lock fs-1 text-warning mb-3"></i>
<h4 class="fw-bold"><?= __('sec_acc_title') ?></h4>
<p class="text-muted small"><?= __('sec_acc_desc') ?></p>
<h4 class="fw-bold text-white"><?= __('sec_acc_title') ?></h4>
<p class="text-white-50 small"><?= __('sec_acc_desc') ?></p>
<a href="#" class="stretched-link"></a>
</div>
</div>
<div class="col-md-4">
<div class="card bg-dark border-secondary h-100 p-4 text-center hover-up">
<div class="card bg-surface border-secondary h-100 p-4 text-center hover-up shadow-sm">
<i class="bi bi-cpu fs-1 text-danger mb-3"></i>
<h4 class="fw-bold"><?= __('api_doc_title') ?></h4>
<p class="text-muted small"><?= __('api_doc_desc') ?></p>
<h4 class="fw-bold text-white"><?= __('api_doc_title') ?></h4>
<p class="text-white-50 small"><?= __('api_doc_desc') ?></p>
<a href="/api.php" class="stretched-link"></a>
</div>
</div>
<div class="col-md-4">
<div class="card bg-dark border-secondary h-100 p-4 text-center hover-up">
<div class="card bg-surface border-secondary h-100 p-4 text-center hover-up shadow-sm">
<i class="bi bi-chat-dots fs-1 text-light mb-3"></i>
<h4 class="fw-bold"><?= __('contact_sup_title') ?></h4>
<p class="text-muted small"><?= __('contact_sup_desc') ?></p>
<h4 class="fw-bold text-white"><?= __('contact_sup_title') ?></h4>
<p class="text-white-50 small"><?= __('contact_sup_desc') ?></p>
<a href="/support.php" class="stretched-link"></a>
</div>
</div>

View File

@ -330,11 +330,11 @@ csForm.addEventListener('submit', async (e) => {
});
function appendMessageHTML(m) {
if (document.querySelector(`[data-id="${m.id}"]`)) return;
if (!m || !m.id || document.querySelector(`[data-id="${m.id}"]`)) return;
const sender = m.sender;
const text = m.message;
const time = m.created_at;
const text = (m.message || '').toString();
const time = m.created_at || new Date().toISOString();
const isImage = text.indexOf('<img') !== -1;
let dateObj;
@ -343,7 +343,7 @@ function appendMessageHTML(m) {
} else {
dateObj = new Date(time);
}
const timeStr = dateObj.toLocaleTimeString('zh-CN', {hour: '2-digit', minute:'2-digit', second: '2-digit'});
const timeStr = isNaN(dateObj.getTime()) ? '---' : dateObj.toLocaleTimeString('zh-CN', {hour: '2-digit', minute:'2-digit', second: '2-digit'});
const msgHtml = `
<div class="mb-3 d-flex flex-column ${sender === 'user' ? 'align-items-end' : 'align-items-start'} message-item" data-id="${m.id}">

View File

@ -551,6 +551,43 @@ $translations = [
'step_4' => '转账完成后在聊天框告知客服或等待系统同步',
'recharge_success_title' => '申请已提交',
'recharge_success_text' => '您的充值申请已收到,请等待审核通过。',
'recharge_instruction_1' => '系统正在为您分配专属收款账户,请耐心等待',
'recharge_instruction_2' => '匹配期间请勿刷新页面或重复提交订单',
'recharge_instruction_3' => '若超过倒计时仍未匹配成功,请及时联系在线客服',
'recharge_instruction_4' => '收到充值账户,完成转账后,请将转账凭证提交给在线客服',
'recharge_instruction_5' => '客服将在核实资金后为您确认到账',
'finished_transfer' => '完成转账',
'matching_instructions' => '匹配说明',
'matching_system_active' => '匹配系统已激活',
'high_encryption' => '高等级加密',
'online' => '在线',
'ip' => 'IP:',
'news_title_1' => 'BYRO正式上线全新秒合约交易系统',
'news_title_2' => '关于新增多种支付方式的公告',
'news_title_3' => 'BYRO获得数字货币运营牌照',
'news_title_4' => '提升账户安全:启用谷歌身份验证器',
'news_title_5' => '2026年市场研究报告加密货币的未来',
'news_desc_1' => '我们很高兴地宣布BYRO全新的秒合约系统已正式上线提供更快的结算速度。',
'news_desc_2' => '为了方便全球用户,我们新增了包括本地银行转账在内的多种法币充值方式。',
'news_desc_3' => 'BYRO致力于合规化运营近期已成功获得关键市场的运营许可。',
'news_desc_4' => '用户的资产安全是我们的首要任务,我们建议所有用户开启谷歌二次验证。',
'news_desc_5' => '深入了解2026年加密货币市场的发展趋势和潜在机会。',
'news_meta' => '发布于 2026年2月21日 • 公告',
'help_subtitle' => '在这里您可以找到有关使用BYRO的所有问题的答案',
'help_search_placeholder' => '搜索问题、功能或教程...',
'getting_started' => '新手入门',
'getting_started_desc' => '了解如何注册账户并开始您的第一笔交易。',
'dep_with_title' => '充值与提现',
'dep_with_desc' => '关于如何存入资金和提取资产的详细指南。',
'trading_tutorials' => '交易教程',
'trading_tutorials_desc' => '掌握现货、合约和秒合约的交易技巧。',
'sec_acc_title' => '账户安全',
'sec_acc_desc' => '保护您的账户免受未经授权的访问。',
'api_doc_title' => '接口文档',
'api_doc_desc' => '为开发者提供的完整 API 集成文档。',
'contact_sup_title' => '联系支持',
'contact_sup_desc' => '如果您遇到问题,我们的团队将全天候为您服务。',
'fees_content' => 'BYRO采用透明的费率结构旨在为用户提供最具竞争力的交易成本。',
],
'en' => [
'home' => 'Home',
@ -1081,6 +1118,43 @@ $translations = [
'step_4' => 'Click "I have paid" in chat or wait for system sync',
'recharge_success_title' => 'Request Submitted',
'recharge_success_text' => 'Your recharge request has been received. Please wait for approval.',
'recharge_instruction_1' => 'System is allocating an exclusive account for you, please wait patiently.',
'recharge_instruction_2' => 'Do not refresh the page or resubmit the order during matching.',
'recharge_instruction_3' => 'If matching fails after the countdown, please contact support.',
'recharge_instruction_4' => 'After receiving the account, submit the transfer voucher to support.',
'recharge_instruction_5' => 'Support will confirm your deposit after verifying the funds.',
'finished_transfer' => 'Finished Transfer',
'matching_instructions' => 'Matching Instructions',
'matching_system_active' => 'MATCHING SYSTEM ACTIVE',
'high_encryption' => 'HIGH ENCRYPTION',
'online' => 'ONLINE',
'ip' => 'IP:',
'news_title_1' => 'BYRO Officially Launches New Binary Trading System',
'news_title_2' => 'Announcement on New Payment Methods',
'news_title_3' => 'BYRO Obtains Digital Currency Operation License',
'news_title_4' => 'Enhance Account Security: Enable Google Authenticator',
'news_title_5' => '2026 Market Research: The Future of Crypto',
'news_desc_1' => 'We are excited to announce that BYRO\'s new binary system is live, offering faster settlement.',
'news_desc_2' => 'To facilitate global users, we have added multiple fiat deposit methods including local bank transfers.',
'news_desc_3' => 'BYRO is committed to compliant operations and has successfully obtained key licenses.',
'news_desc_4' => 'Your security is our priority. We recommend all users enable Google 2FA.',
'news_desc_5' => 'Deep dive into the 2026 crypto market trends and potential opportunities.',
'news_meta' => 'Published on Feb 21, 2026 • Announcement',
'help_subtitle' => 'Find answers to all your questions about using BYRO',
'help_search_placeholder' => 'Search for issues, features or tutorials...',
'getting_started' => 'Getting Started',
'getting_started_desc' => 'Learn how to register and start your first trade.',
'dep_with_title' => 'Deposit & Withdraw',
'dep_with_desc' => 'Detailed guides on how to fund and withdraw from your account.',
'trading_tutorials' => 'Trading Tutorials',
'trading_tutorials_desc' => 'Master spot, contract, and binary trading skills.',
'sec_acc_title' => 'Account Security',
'sec_acc_desc' => 'Protect your account from unauthorized access.',
'api_doc_title' => 'API Documentation',
'api_doc_desc' => 'Complete API integration documentation for developers.',
'contact_sup_title' => 'Contact Support',
'contact_sup_desc' => 'Our team is available 24/7 if you encounter any issues.',
'fees_content' => 'BYRO uses a transparent fee structure designed to provide competitive trading costs.',
],
];

View File

@ -6,27 +6,27 @@ require_once __DIR__ . '/includes/header.php';
<div class="row justify-content-center">
<div class="col-lg-10">
<h1 class="mb-5 fw-bold"><?php echo __('privacy'); ?></h1>
<div class="card bg-dark border-secondary p-5">
<p class="text-muted mb-4"><?= __('last_updated') ?></p>
<div class="card bg-surface border-secondary p-5 shadow-sm">
<p class="text-white-50 mb-4"><?= __('last_updated') ?></p>
<section class="mb-5">
<h3 class="fw-bold mb-3"><?= __('privacy_1_title') ?></h3>
<p class="text-muted"><?= __('privacy_1_content') ?></p>
<h3 class="fw-bold mb-3 text-white"><?= __('privacy_1_title') ?></h3>
<p class="text-white-50"><?= __('privacy_1_content') ?></p>
</section>
<section class="mb-5">
<h3 class="fw-bold mb-3"><?= __('privacy_2_title') ?></h3>
<p class="text-muted"><?= __('privacy_2_content') ?></p>
<h3 class="fw-bold mb-3 text-white"><?= __('privacy_2_title') ?></h3>
<p class="text-white-50"><?= __('privacy_2_content') ?></p>
</section>
<section class="mb-5">
<h3 class="fw-bold mb-3"><?= __('privacy_3_title') ?></h3>
<p class="text-muted"><?= __('privacy_3_content') ?></p>
<h3 class="fw-bold mb-3 text-white"><?= __('privacy_3_title') ?></h3>
<p class="text-white-50"><?= __('privacy_3_content') ?></p>
</section>
<section class="mb-5">
<h3 class="fw-bold mb-3"><?= __('privacy_4_title') ?></h3>
<p class="text-muted"><?= __('privacy_4_content') ?></p>
<h3 class="fw-bold mb-3 text-white"><?= __('privacy_4_title') ?></h3>
<p class="text-white-50"><?= __('privacy_4_content') ?></p>
</section>
<section>
<h3 class="fw-bold mb-3"><?= __('privacy_5_title') ?></h3>
<p class="text-muted"><?= __('privacy_5_content') ?></p>
<h3 class="fw-bold mb-3 text-white"><?= __('privacy_5_title') ?></h3>
<p class="text-white-50"><?= __('privacy_5_content') ?></p>
</section>
</div>
</div>

View File

@ -6,29 +6,29 @@ require_once __DIR__ . '/includes/header.php';
<h1 class="mb-4 fw-bold"><?php echo __('news'); ?></h1>
<div class="row g-4">
<div class="col-md-8">
<p class="text-muted mb-5"><?php echo __('news_content'); ?></p>
<p class="text-white-50 mb-5"><?php echo __('news_content'); ?></p>
<?php for($i=1; $i<=5; $i++): ?>
<div class="card bg-dark border-secondary mb-4 coin-card">
<div class="card bg-surface border-secondary mb-4 coin-card shadow-sm">
<div class="card-body">
<span class="badge bg-primary mb-2"><?= __('announcement') ?></span>
<h4 class="fw-bold"><?= __('news_title_' . $i) ?></h4>
<p class="text-muted small"><?= __('news_meta') ?></p>
<p><?= __('news_desc_' . $i) ?></p>
<a href="#" class="btn btn-link p-0 text-primary"><?= __('read_more') ?> <i class="bi bi-arrow-right"></i></a>
<h4 class="fw-bold text-white"><?= __('news_title_' . $i) ?></h4>
<p class="text-white-50 small"><?= __('news_meta') ?></p>
<p class="text-white-50"><?= __('news_desc_' . $i) ?></p>
<a href="#" class="btn btn-link p-0 text-primary fw-bold"><?= __('read_more') ?> <i class="bi bi-arrow-right"></i></a>
</div>
</div>
<?php endfor; ?>
</div>
<div class="col-md-4">
<div class="card bg-dark border-secondary p-4 sticky-top" style="top: 100px;">
<h5 class="fw-bold mb-3"><?= __('newsletter') ?></h5>
<p class="small text-muted"><?= __('newsletter_desc') ?></p>
<div class="card bg-surface border-secondary p-4 sticky-top" style="top: 100px;">
<h5 class="fw-bold mb-3 text-white"><?= __('newsletter') ?></h5>
<p class="small text-white-50"><?= __('newsletter_desc') ?></p>
<div class="input-group mb-3">
<input type="email" class="form-control bg-dark text-white border-secondary" placeholder="<?= __('email_address') ?>">
<button class="btn btn-primary"><?= __('join') ?></button>
</div>
<hr class="border-secondary">
<h5 class="fw-bold mb-3"><?= __('popular_topics') ?></h5>
<h5 class="fw-bold mb-3 text-white"><?= __('popular_topics') ?></h5>
<div class="d-flex flex-wrap gap-2">
<span class="badge border border-secondary p-2">#BTC</span>
<span class="badge border border-secondary p-2">#Web3</span>

View File

@ -1,12 +1,23 @@
<?php
require_once __DIR__ . '/includes/header.php';
require_once __DIR__ . '/includes/exchange.php';
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/includes/lang.php';
if (session_status() === PHP_SESSION_NONE) session_start();
$user = null;
if (isset($_SESSION['user_id'])) {
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch();
}
if (!$user) {
header('Location: /auth/login.php');
exit;
}
require_once __DIR__ . '/includes/header.php';
require_once __DIR__ . '/includes/exchange.php';
// Fetch rates
$rates = get_exchange_rates();
@ -209,8 +220,8 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
<div class="flex-grow-1">
<h6 class="mb-0 fw-bold text-white fs-5" style="letter-spacing: 0.5px;"><?= __('online_support') ?></h6>
<div class="d-flex align-items-center gap-2 mt-1">
<span class="badge bg-primary bg-opacity-20 text-primary border border-primary border-opacity-30 small px-2 py-1" style="font-size: 10px;">ONLINE</span>
<span class="text-white opacity-50 small">IP:</span>
<span class="badge bg-primary bg-opacity-20 text-primary border border-primary border-opacity-30 small px-2 py-1" style="font-size: 10px;"><?= __('online') ?></span>
<span class="text-white opacity-50 small"><?= __('ip') ?></span>
<span class="text-info small fw-bold fw-mono" style="text-shadow: 0 0 5px rgba(0,210,255,0.3);"><?= getRealIP() ?></span>
</div>
</div>
@ -241,49 +252,69 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
</div>
<!-- Right Side: Account Matching -->
<div class="col-lg-6 p-4 p-lg-5 d-flex flex-column justify-content-center info-side position-relative overflow-hidden order-1 order-lg-2">
<div class="col-lg-6 p-4 p-lg-5 d-flex flex-column justify-content-center info-side position-relative overflow-hidden order-1">
<!-- Vibrant & Coordinated Background -->
<div class="position-absolute top-0 start-0 w-100 h-100 vibrancy-bg"></div>
<div class="position-absolute top-0 start-0 w-100 h-100 bg-black bg-opacity-40" style="z-index: 1; backdrop-filter: blur(2px);"></div>
<div class="position-absolute top-0 start-0 w-100 h-100 bg-black bg-opacity-40" style="z-index: 1; backdrop-filter: blur(5px);"></div>
<div class="text-center text-lg-start position-relative" style="z-index: 2;">
<div class="mb-4">
<div class="d-inline-flex align-items-center gap-2 px-3 py-1 rounded-pill bg-white bg-opacity-10 text-white small fw-bold mb-3 border border-white border-opacity-20 shadow-sm" style="backdrop-filter: blur(10px);">
<span class="pulse-dot-white"></span> <?= __('executing') ?>
<div class="d-inline-flex align-items-center gap-2 px-3 py-2 rounded-pill bg-primary bg-opacity-20 text-white small fw-bold mb-3 border border-primary border-opacity-30 shadow-lg" style="backdrop-filter: blur(10px);">
<span class="pulse-dot-white"></span> <span style="letter-spacing: 1px;"><?= __('matching_system_active') ?></span>
</div>
<h3 class="fw-bold text-white mb-2 text-shadow-ultra"><?= __('matching_account') ?>...</h3>
<p class="text-white small fw-bold opacity-90 text-shadow-heavy"><?= __('matching_desc') ?></p>
<h2 class="fw-bold text-white mb-2 text-shadow-ultra" style="font-size: 2.5rem;"><?= __('matching_account') ?></h2>
<p class="text-white-50 small fw-medium"><?= __('matching_desc') ?></p>
</div>
<div class="mb-4 py-3 px-4 rounded-4 shadow-2xl border border-white border-opacity-30" style="background: rgba(255,255,255,0.1); backdrop-filter: blur(40px);">
<div class="row align-items-center">
<div class="col-6">
<div class="text-white small mb-1 fw-bold text-shadow-medium"><?= __('remaining_time') ?></div>
<div class="h3 fw-bold text-warning tracking-wider text-shadow-glow mb-0" id="modal-countdown" style="font-family: 'Courier New', monospace;">30:00</div>
<div class="mb-4 py-4 px-4 rounded-4 shadow-2xl border border-white border-opacity-10" style="background: rgba(0,0,0,0.3); backdrop-filter: blur(20px);">
<div class="row align-items-center text-center text-lg-start">
<div class="col-lg-7 mb-3 mb-lg-0">
<div class="text-white-50 small mb-1 fw-bold"><?= __('remaining_time') ?></div>
<div class="display-5 fw-bold text-warning tracking-wider text-shadow-glow mb-0" id="modal-countdown" style="font-family: 'Monaco', 'Consolas', monospace;">30:00</div>
</div>
<div class="col-6 border-start border-white border-opacity-20 ps-4">
<div class="text-white small mb-1 fw-bold text-shadow-medium"><?= __('security_level') ?></div>
<div class="d-flex gap-1 mb-1">
<div class="bg-success rounded-pill shadow-glow-green" style="width: 15px; height: 4px;"></div>
<div class="bg-success rounded-pill shadow-glow-green" style="width: 15px; height: 4px;"></div>
<div class="bg-success rounded-pill shadow-glow-green" style="width: 15px; height: 4px;"></div>
<div class="bg-success rounded-pill shadow-glow-green" style="width: 15px; height: 4px;"></div>
<div class="col-lg-5 border-start border-white border-opacity-10 ps-lg-4">
<div class="text-white-50 small mb-2 fw-bold"><?= __('security_level') ?></div>
<div class="d-flex justify-content-center justify-content-lg-start gap-1 mb-2">
<div class="bg-success rounded-pill shadow-glow-green" style="width: 20px; height: 6px;"></div>
<div class="bg-success rounded-pill shadow-glow-green" style="width: 20px; height: 6px;"></div>
<div class="bg-success rounded-pill shadow-glow-green" style="width: 20px; height: 6px;"></div>
<div class="bg-success rounded-pill shadow-glow-green" style="width: 20px; height: 6px;"></div>
</div>
<div class="text-white fw-bold text-shadow-glow-sm" style="color: #4ade80 !important; font-size: 10px;"><?= __('high') ?></div>
<div class="text-success fw-bold small text-shadow-glow-sm" style="letter-spacing: 1px;"><?= __('high_encryption') ?></div>
</div>
</div>
</div>
<div class="p-3 rounded-4 bg-black bg-opacity-30 border border-white border-opacity-10">
<h6 class="text-white fw-bold mb-3 d-flex align-items-center gap-2" style="font-size: 14px;">
<i class="bi bi-shield-lock-fill text-warning"></i> <?= __('security_instructions') ?>
<div class="p-4 rounded-4 bg-black bg-opacity-40 border border-white border-opacity-5">
<h6 class="text-white fw-bold mb-3 d-flex align-items-center gap-2" style="font-size: 15px; letter-spacing: 0.5px;">
<i class="bi bi-shield-lock-fill text-warning fs-5"></i> <?= __('matching_instructions') ?>
</h6>
<div class="text-white opacity-90 small lh-base" style="font-size: 13px !important;">
<div class="mb-2 d-flex gap-2"><i class="bi bi-dot text-primary"></i> <span>系统正在为您分配专属收款账户,请耐心等待</span></div>
<div class="mb-2 d-flex gap-2"><i class="bi bi-dot text-primary"></i> <span>匹配期间请勿刷新页面或重复提交订单</span></div>
<div class="mb-2 d-flex gap-2"><i class="bi bi-dot text-primary"></i> <span>若超过倒计时仍未匹配成功,请及时联系在线客服</span></div>
<div class="mb-2 d-flex gap-2"><i class="bi bi-dot text-primary"></i> <span>收到充值账户,完成转账后,请将转账凭证提交给在线客服</span></div>
<div class="d-flex gap-2"><i class="bi bi-dot text-primary"></i> <span>客服将在核实资金后为您确认到账</span></div>
<div class="text-white-50 small lh-lg" style="font-size: 13.5px !important; font-weight: 400;">
<div class="mb-3 d-flex gap-3 instruction-item p-2 rounded">
<i class="bi bi-1-circle-fill text-primary"></i>
<span><?= __('recharge_instruction_1') ?></span>
</div>
<div class="mb-3 d-flex gap-3 instruction-item p-2 rounded">
<i class="bi bi-2-circle-fill text-primary"></i>
<span><?= __('recharge_instruction_2') ?></span>
</div>
<div class="mb-3 d-flex gap-3 instruction-item p-2 rounded">
<i class="bi bi-3-circle-fill text-primary"></i>
<span><?= __('recharge_instruction_3') ?></span>
</div>
<div class="mb-3 d-flex gap-3 instruction-item p-2 rounded">
<i class="bi bi-4-circle-fill text-primary"></i>
<span><?= __('recharge_instruction_4') ?></span>
</div>
<div class="d-flex gap-3 instruction-item p-2 rounded">
<i class="bi bi-5-circle-fill text-primary"></i>
<span><?= __('recharge_instruction_5') ?></span>
</div>
</div>
<div class="mt-4">
<button type="button" class="btn btn-outline-light w-100 rounded-pill py-2 fw-bold" onclick="finishTransfer()">
<?= __('finished_transfer') ?>
</button>
</div>
</div>
</div>
@ -375,10 +406,58 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}
@media (max-width: 992px) {
.chat-column { height: 450px !important; }
.modal-xl { margin: 10px; max-width: calc(100% - 20px); }
.modal-dialog-centered { align-items: flex-start; }
.info-side { padding: 1.5rem !important; }
.chat-column { display: none !important; }
.info-side {
width: 100% !important;
min-height: 100vh !important;
border-radius: 24px !important;
}
.modal-dialog { margin: 0; }
.modal-content { border-radius: 0; height: 100vh; }
}
/* Premium Desktop Styling */
.modal-content {
box-shadow: 0 0 50px rgba(0,0,0,0.5), 0 0 100px rgba(0,123,255,0.1) !important;
}
.info-side {
background: #1c2127;
border-radius: 0 24px 24px 0;
}
@media (max-width: 992px) {
.info-side { border-radius: 24px; }
}
.text-shadow-ultra {
text-shadow: 0 4px 15px rgba(0,0,0,0.6), 0 0 40px rgba(0,123,255,0.4);
letter-spacing: 1px;
font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
.tracking-wider {
letter-spacing: 0.15em;
}
.vibrancy-bg {
background: linear-gradient(135deg, #0f172a 0%, #1e3a8a 30%, #1e40af 60%, #1d4ed8 100%);
opacity: 0.85;
}
.instruction-item {
background: rgba(255,255,255,0.04);
border: 1px solid rgba(255,255,255,0.08);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
backdrop-filter: blur(5px);
}
.instruction-item:hover {
background: rgba(255,255,255,0.08);
transform: translateX(8px);
border-color: rgba(255,255,255,0.15);
}
.display-5 {
font-size: 3.5rem;
font-weight: 800;
}
@media (min-width: 992px) {
.modal-xl {
max-width: 1000px;
}
}
</style>
@ -438,40 +517,104 @@ function selectNetwork(net, addr) {
const userId = '<?= $user['uid'] ?? $user['id'] ?>';
let rechargeCountdownInterval;
let modalChatLastIds = new Set();
let remainingSeconds = 1800;
function openRechargeModal(initialMessage) {
const modal = new bootstrap.Modal(document.getElementById('rechargeModal'));
function saveRechargeState(state) {
localStorage.setItem('recharge_state', JSON.stringify({
...state,
timestamp: Date.now(),
remainingSeconds: remainingSeconds
}));
}
function clearRechargeState() {
localStorage.removeItem('recharge_state');
if (rechargeCountdownInterval) clearInterval(rechargeCountdownInterval);
}
function finishTransfer() {
clearRechargeState();
bootstrap.Modal.getInstance(document.getElementById('rechargeModal'))?.hide();
notify('success', '<?= __("recharge_success_title") ?>', '<?= __("recharge_success_text") ?>');
}
function openRechargeModal(initialMessage, isRestore = false) {
const modalElement = document.getElementById('rechargeModal');
const modal = new bootstrap.Modal(modalElement);
modal.show();
if (!isRestore) {
remainingSeconds = 1800;
saveRechargeState({ phase: 'matching', initialMessage });
}
// Start countdown
let seconds = 1800;
const display = document.getElementById('modal-countdown');
if (rechargeCountdownInterval) clearInterval(rechargeCountdownInterval);
rechargeCountdownInterval = setInterval(() => {
let mins = Math.floor(seconds / 60);
let secs = seconds % 60;
display.innerText = `${mins}:${secs < 10 ? '0' : ''}${secs}`;
if (--seconds < 0) clearInterval(rechargeCountdownInterval);
let mins = Math.floor(remainingSeconds / 60);
let secs = remainingSeconds % 60;
if (display) display.innerText = `${mins}:${secs < 10 ? '0' : ''}${secs}`;
const state = JSON.parse(localStorage.getItem('recharge_state') || '{}');
state.remainingSeconds = remainingSeconds;
localStorage.setItem('recharge_state', JSON.stringify(state));
if (--remainingSeconds < 0) {
clearInterval(rechargeCountdownInterval);
}
}, 1000);
// Send initial message and show in chat
const tempId = 'modal_temp_' + Date.now();
appendModalMessage({
id: tempId,
sender: 'user',
message: initialMessage,
created_at: new Date().toISOString()
});
// Ping first to register visitor, then send message
fetch(`/api/chat.php?action=ping&user_time=${encodeURIComponent(new Date().toLocaleString())}`)
.then(() => sendModalMessage(initialMessage))
.catch(err => console.error('Ping failed:', err));
// Clear chat last ids for new session if not restoring
if (!isRestore) {
modalChatLastIds.clear();
document.getElementById('modal-chat-messages').innerHTML = `
<div class="text-center text-muted small mb-4 py-3 bg-white bg-opacity-5 rounded-3 border border-white border-opacity-5">
<i class="bi bi-shield-lock-fill text-success me-2"></i><?= __('welcome_support') ?>
</div>
`;
// Ping first to register visitor, then send message to ensure visibility
const userTime = new Date().toLocaleString('zh-CN');
fetch(`/api/chat.php?action=ping&user_time=${encodeURIComponent(userTime)}`)
.then(() => {
// Append locally first
appendModalMessage({
id: 'modal_temp_init_' + Date.now(),
sender: 'user',
message: initialMessage,
created_at: new Date().toISOString()
});
// Then send to server
return sendModalMessage(initialMessage);
})
.catch(err => console.error('Initial sequence failed:', err));
}
// Start polling for modal
initModalChat();
}
document.addEventListener('DOMContentLoaded', () => {
const savedState = localStorage.getItem('recharge_state');
if (savedState) {
const state = JSON.parse(savedState);
const elapsed = Math.floor((Date.now() - state.timestamp) / 1000);
remainingSeconds = (state.remainingSeconds || 1800) - elapsed;
if (remainingSeconds > 0) {
if (state.phase === 'matched') {
openRechargeModal(state.initialMessage, true);
updateMatchingSide(state.info, true);
} else {
openRechargeModal(state.initialMessage, true);
}
} else {
localStorage.removeItem('recharge_state');
}
}
});
let modalChatPolling = false;
function initModalChat() {
@ -627,11 +770,16 @@ function appendModalMessage(m) {
modalChatLastIds.add(m.id);
}
function updateMatchingSide(info) {
function updateMatchingSide(info, isRestore = false) {
const side = document.querySelector('.info-side');
if (!side) return;
if (rechargeCountdownInterval) clearInterval(rechargeCountdownInterval);
if (!isRestore) {
const state = JSON.parse(localStorage.getItem('recharge_state') || '{}');
saveRechargeState({ ...state, phase: 'matched', info });
}
side.innerHTML = `
<div class="position-absolute top-0 start-0 w-100 h-100 vibrancy-bg"></div>
@ -683,16 +831,19 @@ function updateMatchingSide(info) {
<h6 class="text-white fw-bold mb-4 d-flex align-items-center gap-2 text-shadow-heavy">
<i class="bi bi-info-circle-fill text-white fs-5"></i> <?= __('transfer_steps_title') ?>
</h6>
<div class="d-flex flex-column gap-3">
<div class="d-flex flex-column gap-3 mb-4">
<div class="d-flex gap-3 align-items-start p-3 rounded-3 bg-white bg-opacity-10 border border-white border-opacity-20 shadow-sm hover-scale-sm" style="backdrop-filter: blur(10px);">
<div class="fw-bold text-warning fs-5 text-shadow-glow-sm" style="min-width: 25px;">01</div>
<div class="text-white small lh-base fw-bold text-shadow-medium">完成转账后,请将转账凭证提交给在线客服</div>
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('recharge_instruction_4') ?></div>
</div>
<div class="d-flex gap-3 align-items-start p-3 rounded-3 bg-white bg-opacity-10 border border-white border-opacity-20 shadow-sm hover-scale-sm" style="backdrop-filter: blur(10px);">
<div class="fw-bold text-warning fs-5 text-shadow-glow-sm" style="min-width: 25px;">02</div>
<div class="text-white small lh-base fw-bold text-shadow-medium">客服将在核实资金后为您确认到账</div>
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('recharge_instruction_5') ?></div>
</div>
</div>
<button type="button" class="btn btn-warning w-100 rounded-pill py-3 fw-bold shadow-lg" onclick="finishTransfer()">
<?= __('finished_transfer') ?>
</button>
</div>
</div>
`;

View File

@ -6,15 +6,15 @@ require_once __DIR__ . '/includes/header.php';
<div class="row justify-content-center">
<div class="col-lg-8">
<h1 class="mb-4 fw-bold text-center"><?php echo __('submit_request'); ?></h1>
<div class="card bg-dark border-secondary p-4">
<div class="card bg-surface border-secondary p-4 shadow-sm">
<form action="#" method="POST">
<div class="mb-3">
<label class="form-label text-muted small"><?= __('email_address') ?></label>
<input type="email" class="form-control bg-dark text-white border-secondary" placeholder="email@example.com" required>
<label class="form-label text-white-50 small fw-bold"><?= __('email_address') ?></label>
<input type="email" class="form-control bg-dark text-white border-secondary py-2" placeholder="email@example.com" required>
</div>
<div class="mb-3">
<label class="form-label text-muted small"><?= __('issue_type') ?></label>
<select class="form-select bg-dark text-white border-secondary">
<label class="form-label text-white-50 small fw-bold"><?= __('issue_type') ?></label>
<select class="form-select bg-dark text-white border-secondary py-2">
<option><?= __('account_access') ?></option>
<option><?= __('dep_with_issue') ?></option>
<option><?= __('trading_issue') ?></option>
@ -23,16 +23,16 @@ require_once __DIR__ . '/includes/header.php';
</select>
</div>
<div class="mb-3">
<label class="form-label text-muted small"><?= __('subject') ?></label>
<input type="text" class="form-control bg-dark text-white border-secondary" placeholder="<?= __('subject') ?>" required>
<label class="form-label text-white-50 small fw-bold"><?= __('subject') ?></label>
<input type="text" class="form-control bg-dark text-white border-secondary py-2" placeholder="<?= __('subject') ?>" required>
</div>
<div class="mb-4">
<label class="form-label text-muted small"><?= __('description') ?></label>
<label class="form-label text-white-50 small fw-bold"><?= __('description') ?></label>
<textarea class="form-control bg-dark text-white border-secondary" rows="5" placeholder="<?= __('description') ?>" required></textarea>
</div>
<button type="submit" class="btn btn-primary w-100 py-3 fw-bold"><?= __('submit_ticket') ?></button>
<button type="submit" class="btn btn-primary w-100 py-3 fw-bold rounded-pill shadow-lg"><?= __('submit_ticket') ?></button>
</form>
<div class="mt-4 text-center small text-muted">
<div class="mt-4 text-center small text-white-50 fw-bold">
<?= __('support_response_time') ?>
</div>
</div>

24
tos.php
View File

@ -6,27 +6,27 @@ require_once __DIR__ . '/includes/header.php';
<div class="row justify-content-center">
<div class="col-lg-10">
<h1 class="mb-5 fw-bold"><?php echo __('terms'); ?></h1>
<div class="card bg-dark border-secondary p-5">
<p class="text-muted mb-4"><?= __('effective_date') ?></p>
<div class="card bg-surface border-secondary p-5">
<p class="text-white-50 mb-4"><?= __('effective_date') ?></p>
<section class="mb-5">
<h3 class="fw-bold mb-3"><?= __('tos_1_title') ?></h3>
<p class="text-muted"><?= __('tos_1_content') ?></p>
<h3 class="fw-bold mb-3 text-white"><?= __('tos_1_title') ?></h3>
<p class="text-white-50"><?= __('tos_1_content') ?></p>
</section>
<section class="mb-5">
<h3 class="fw-bold mb-3"><?= __('tos_2_title') ?></h3>
<p class="text-muted"><?= __('tos_2_content') ?></p>
<h3 class="fw-bold mb-3 text-white"><?= __('tos_2_title') ?></h3>
<p class="text-white-50"><?= __('tos_2_content') ?></p>
</section>
<section class="mb-5">
<h3 class="fw-bold mb-3"><?= __('tos_3_title') ?></h3>
<p class="text-muted"><?= __('tos_3_content') ?></p>
<h3 class="fw-bold mb-3 text-white"><?= __('tos_3_title') ?></h3>
<p class="text-white-50"><?= __('tos_3_content') ?></p>
</section>
<section class="mb-5">
<h3 class="fw-bold mb-3"><?= __('tos_4_title') ?></h3>
<p class="text-muted"><?= __('tos_4_content') ?></p>
<h3 class="fw-bold mb-3 text-white"><?= __('tos_4_title') ?></h3>
<p class="text-white-50"><?= __('tos_4_content') ?></p>
</section>
<section>
<h3 class="fw-bold mb-3"><?= __('tos_5_title') ?></h3>
<p class="text-muted"><?= __('tos_5_content') ?></p>
<h3 class="fw-bold mb-3 text-white"><?= __('tos_5_title') ?></h3>
<p class="text-white-50"><?= __('tos_5_content') ?></p>
</section>
</div>
</div>