232323
This commit is contained in:
parent
fd1a7fb782
commit
12ab6c8a13
322
admin.php
322
admin.php
@ -21,14 +21,49 @@ if (!$user) {
|
||||
|
||||
// Ensure role is admin
|
||||
if ($user['role'] !== 'admin') {
|
||||
// Check if this is the ONLY user, if so, force admin
|
||||
$count = $pdo->query("SELECT COUNT(*) FROM users")->fetchColumn();
|
||||
if ($count == 1) {
|
||||
// Check if there are ANY admins in the system
|
||||
$adminCount = $pdo->query("SELECT COUNT(*) FROM users WHERE role = 'admin'")->fetchColumn();
|
||||
if ($adminCount == 0) {
|
||||
// No admin exists? Make this user the admin automatically to prevent lock-out
|
||||
$pdo->query("UPDATE users SET role = 'admin' WHERE id = " . $user['id']);
|
||||
$user['role'] = 'admin';
|
||||
$_SESSION['role'] = 'admin';
|
||||
} else {
|
||||
die('Access Denied: You do not have administrator privileges. Your role is: ' . htmlspecialchars($user['role']) . '. Please logout and login as admin.');
|
||||
// Nicer access denied page
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Access Denied</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body { height: 100vh; display: flex; align-items: center; justify-content: center; background: #f1f5f9; font-family: system-ui, -apple-system, sans-serif; }
|
||||
.error-card { max-width: 450px; padding: 40px; text-align: center; border-radius: 16px; background: white; box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1); }
|
||||
.icon-circle { width: 80px; height: 80px; background: #fee2e2; color: #ef4444; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 40px; margin: 0 auto 24px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="error-card">
|
||||
<div class="icon-circle">
|
||||
<i class="fas fa-shield-alt"></i>
|
||||
</div>
|
||||
<h4 class="fw-bold mb-3">权限不足 (Access Denied)</h4>
|
||||
<p class="text-muted mb-4">您当前以 <strong><?= htmlspecialchars($user['username']) ?></strong> (角色: <?= htmlspecialchars($user['role']) ?>) 身份登录。后台管理面板仅限管理员访问。</p>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="dashboard.php" class="btn btn-primary py-2">返回个人中心</a>
|
||||
<a href="auth.php?action=logout" class="btn btn-outline-danger py-2">退出并登录管理员账号</a>
|
||||
</div>
|
||||
<div class="mt-4 pt-3 border-top">
|
||||
<small class="text-muted">提示: 如果您是系统所有者但无法进入,请尝试访问 <code>/rescue.php</code></small>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,8 +95,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
if ($action === 'update_settings') {
|
||||
foreach ($_POST['settings'] as $key => $value) {
|
||||
$stmt = $pdo->prepare("UPDATE settings SET setting_value = ?, updated_at = NOW() WHERE setting_key = ?");
|
||||
$stmt->execute([$value, $key]);
|
||||
$stmt = $pdo->prepare("INSERT INTO settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = ?");
|
||||
$stmt->execute([$key, $value, $value]);
|
||||
}
|
||||
header('Location: admin.php?action=settings&success=1');
|
||||
exit;
|
||||
@ -76,6 +111,37 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
header('Location: admin.php?action=users');
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($action === 'add_user') {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = $_POST['password'] ?? '';
|
||||
$role = $_POST['role'] ?? 'user';
|
||||
$balance = (float)($_POST['balance'] ?? 0);
|
||||
|
||||
if ($username && $password) {
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
$stmt = $pdo->prepare("INSERT INTO users (username, password_hash, role, balance) VALUES (?, ?, ?, ?)");
|
||||
try {
|
||||
$stmt->execute([$username, $hash, $role, $balance]);
|
||||
} catch (Exception $e) {
|
||||
header('Location: admin.php?action=users&error=user_exists');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
header('Location: admin.php?action=users');
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($action === 'delete_user') {
|
||||
$id = $_POST['id'];
|
||||
if ($id != $_SESSION['user_id']) {
|
||||
// Foreign keys are ON DELETE CASCADE, so this is safe
|
||||
$stmt = $pdo->prepare("DELETE FROM users WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
}
|
||||
header('Location: admin.php?action=users');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$settings = $pdo->query("SELECT setting_key, setting_value FROM settings")->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
@ -112,6 +178,7 @@ $stats = [
|
||||
background: #1e293b;
|
||||
color: white;
|
||||
padding: 20px;
|
||||
z-index: 1000;
|
||||
}
|
||||
.main-content { margin-left: var(--sidebar-width); padding: 40px; }
|
||||
.nav-link { color: #cbd5e1; padding: 12px 15px; border-radius: 8px; margin-bottom: 5px; }
|
||||
@ -126,16 +193,21 @@ $stats = [
|
||||
<body>
|
||||
|
||||
<div class="sidebar">
|
||||
<div class="mb-4 px-3">
|
||||
<h5 class="fw-bold mb-0">管理后台</h5>
|
||||
<small class="text-muted">ADMIN PANEL</small>
|
||||
<div class="mb-4 px-3 d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h5 class="fw-bold mb-0">管理后台</h5>
|
||||
<small class="text-muted">ADMIN PANEL</small>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="nav flex-column">
|
||||
<a class="nav-link <?= $action === 'dashboard' ? 'active' : '' ?>" href="admin.php?action=dashboard"><i class="fas fa-home"></i> 控制台</a>
|
||||
<a class="nav-link <?= $action === 'users' ? 'active' : '' ?>" href="admin.php?action=users"><i class="fas fa-users"></i> 用户管理</a>
|
||||
<a class="nav-link <?= $action === 'recharges' ? 'active' : '' ?>" href="admin.php?action=recharges"><i class="fas fa-wallet"></i> 充值管理</a>
|
||||
<a class="nav-link <?= $action === 'orders' ? 'active' : '' ?>" href="admin.php?action=orders"><i class="fas fa-shopping-cart"></i> 订单记录</a>
|
||||
<a class="nav-link <?= $action === 'support' ? 'active' : '' ?>" href="admin.php?action=support"><i class="fas fa-headset"></i> 客服消息</a>
|
||||
<a class="nav-link <?= $action === 'support' ? 'active' : '' ?>" href="admin.php?action=support" style="position: relative;">
|
||||
<i class="fas fa-headset"></i> 客服消息
|
||||
<span id="supportBadgeGlobal" class="badge bg-danger rounded-pill" style="display:none; font-size: 10px; margin-left: 5px;">0</span>
|
||||
</a>
|
||||
<a class="nav-link <?= $action === 'settings' ? 'active' : '' ?>" href="admin.php?action=settings"><i class="fas fa-cog"></i> 系统设置</a>
|
||||
<hr class="my-3 border-secondary">
|
||||
<a class="nav-link" href="dashboard.php"><i class="fas fa-arrow-left"></i> 返回前台</a>
|
||||
@ -143,6 +215,20 @@ $stats = [
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Notification Toast -->
|
||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||
<div id="msgToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-primary text-white">
|
||||
<i class="fas fa-comment-alt me-2"></i>
|
||||
<strong class="me-auto">新消息提醒</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
您收到了来自用户的新客服消息!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<?php if ($action === 'dashboard'): ?>
|
||||
<h4 class="fw-bold mb-4">数据概览</h4>
|
||||
@ -173,7 +259,15 @@ $stats = [
|
||||
</div>
|
||||
</div>
|
||||
<?php elseif ($action === 'users'): ?>
|
||||
<h4 class="fw-bold mb-4">用户管理</h4>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h4 class="fw-bold mb-0">用户管理</h4>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addUserModal"><i class="fas fa-user-plus me-2"></i>添加用户</button>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_GET['error']) && $_GET['error'] === 'user_exists'): ?>
|
||||
<div class="alert alert-danger">用户名已存在,请换一个。</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card p-3">
|
||||
<table class="table align-middle">
|
||||
<thead>
|
||||
@ -196,6 +290,12 @@ $stats = [
|
||||
<td><span class="badge bg-<?= $u['role'] === 'admin' ? 'danger' : 'info' ?>"><?= $u['role'] ?></span></td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick='editUser(<?= json_encode($u) ?>)'>编辑</button>
|
||||
<?php if ($u['id'] != $_SESSION['user_id']): ?>
|
||||
<form method="POST" action="admin.php?action=delete_user" style="display:inline;" onsubmit="return confirm('确定要删除此用户吗?其关联的订单、充值和聊天记录都将被永久删除!')">
|
||||
<input type="hidden" name="id" value="<?= $u['id'] ?>">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger">删除</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
@ -203,6 +303,43 @@ $stats = [
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Add User Modal -->
|
||||
<div class="modal fade" id="addUserModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<form class="modal-content" method="POST" action="admin.php?action=add_user">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">添加新用户</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">用户名</label>
|
||||
<input type="text" class="form-control" name="username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">密码</label>
|
||||
<input type="password" class="form-control" name="password" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">初始余额</label>
|
||||
<input type="number" step="0.01" class="form-control" name="balance" value="0.00">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">角色</label>
|
||||
<select class="form-select" name="role">
|
||||
<option value="user">User</option>
|
||||
<option value="admin">Admin</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">立即创建</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit User Modal -->
|
||||
<div class="modal fade" id="userModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<form class="modal-content" method="POST" action="admin.php?action=update_user">
|
||||
@ -330,14 +467,22 @@ $stats = [
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card d-flex flex-column" style="height: 600px;">
|
||||
<div class="card-header bg-white fw-bold" id="chatTitle">请选择一个对话</div>
|
||||
<div class="card-header bg-white fw-bold d-flex justify-content-between align-items-center">
|
||||
<span id="chatTitle">请选择一个对话</span>
|
||||
</div>
|
||||
<div class="card-body p-3 flex-grow-1" id="chatContent" style="overflow-y: auto; background: #f1f5f9;">
|
||||
<div class="h-100 d-flex align-items-center justify-content-center text-muted">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-comments fs-1 mb-3 opacity-25"></i>
|
||||
<p>点击左侧用户开始聊天</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-white p-3">
|
||||
<div class="input-group">
|
||||
<input type="text" id="msgInput" class="form-control" placeholder="输入回复内容...">
|
||||
<button class="btn btn-primary" onclick="sendMessage()">发送</button>
|
||||
</div>
|
||||
<form id="adminChatForm" onsubmit="event.preventDefault(); sendMessage();" class="input-group">
|
||||
<input type="text" id="adminMsgInput" class="form-control" placeholder="输入回复内容..." autocomplete="off">
|
||||
<button type="submit" class="btn btn-primary px-4"><i class="fas fa-paper-plane"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -345,71 +490,89 @@ $stats = [
|
||||
<script>
|
||||
let currentChatUser = null;
|
||||
async function loadChatUsers() {
|
||||
const res = await fetch('ajax_handler.php?action=get_chat_users');
|
||||
const data = await res.json();
|
||||
if (data.code === 0) {
|
||||
const list = document.getElementById('chatUserList');
|
||||
list.innerHTML = '';
|
||||
data.data.forEach(u => {
|
||||
const div = document.createElement('div');
|
||||
div.className = `p-3 border-bottom cursor-pointer \${currentChatUser === u.id ? 'bg-light' : ''}`;
|
||||
div.style.cursor = 'pointer';
|
||||
div.innerHTML = `
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<strong>\${u.username}</strong>
|
||||
<small class="text-muted">\${u.last_time.split(' ')[1]}</small>
|
||||
</div>
|
||||
<div class="text-truncate small \${u.unread_count > 0 ? 'fw-bold text-primary' : 'text-muted'}">\${u.last_message}</div>
|
||||
`;
|
||||
div.onclick = () => selectUser(u.id, u.username);
|
||||
list.appendChild(div);
|
||||
});
|
||||
}
|
||||
try {
|
||||
const res = await fetch('ajax_handler.php?action=get_chat_users');
|
||||
const data = await res.json();
|
||||
if (data.code === 0) {
|
||||
const list = document.getElementById('chatUserList');
|
||||
list.innerHTML = '';
|
||||
data.data.forEach(u => {
|
||||
const div = document.createElement('div');
|
||||
div.className = `p-3 border-bottom ${currentChatUser === parseInt(u.id) ? 'bg-light border-start border-4 border-primary' : ''}`;
|
||||
div.style.cursor = 'pointer';
|
||||
div.innerHTML = `
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<strong class="${u.unread_count > 0 ? 'text-primary' : ''}">${u.username}</strong>
|
||||
<small class="text-muted" style="font-size: 10px;">${u.last_time.split(' ')[1]}</small>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="text-truncate small ${u.unread_count > 0 ? 'fw-bold' : 'text-muted'}" style="max-width: 150px;">${u.last_message}</div>
|
||||
${u.unread_count > 0 ? `<span class="badge bg-danger rounded-pill" style="font-size: 10px;">${u.unread_count}</span>` : ''}
|
||||
</div>
|
||||
`;
|
||||
div.onclick = () => selectUser(parseInt(u.id), u.username);
|
||||
list.appendChild(div);
|
||||
});
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
function selectUser(id, name) {
|
||||
currentChatUser = id;
|
||||
document.getElementById('chatTitle').textContent = '正在与 ' + name + ' 对话';
|
||||
document.getElementById('chatTitle').textContent = '与 ' + name + ' 对话中';
|
||||
loadMessages();
|
||||
loadChatUsers();
|
||||
document.getElementById('adminMsgInput').focus();
|
||||
}
|
||||
async function loadMessages() {
|
||||
if (!currentChatUser) return;
|
||||
const res = await fetch('ajax_handler.php?action=get_messages&user_id=' + currentChatUser);
|
||||
const data = await res.json();
|
||||
if (data.code === 0) {
|
||||
const content = document.getElementById('chatContent');
|
||||
content.innerHTML = '';
|
||||
data.data.forEach(m => {
|
||||
const isMe = m.sender === 'admin';
|
||||
content.innerHTML += `
|
||||
<div class="mb-3 d-flex \${isMe ? 'justify-content-end' : ''}">
|
||||
<div class="p-2 px-3 rounded-4 shadow-sm" style="max-width: 80%; background: \${isMe ? '#3b82f6; color: white;' : 'white;'}">
|
||||
<div>\${m.message}</div>
|
||||
<small class="opacity-75" style="font-size: 10px;">\${m.created_at}</small>
|
||||
try {
|
||||
const res = await fetch('ajax_handler.php?action=get_messages&user_id=' + currentChatUser);
|
||||
const data = await res.json();
|
||||
if (data.code === 0) {
|
||||
const content = document.getElementById('chatContent');
|
||||
content.innerHTML = '';
|
||||
data.data.forEach(m => {
|
||||
const isMe = m.sender === 'admin';
|
||||
const div = document.createElement('div');
|
||||
div.className = `mb-3 d-flex ${isMe ? 'justify-content-end' : ''}`;
|
||||
div.innerHTML = `
|
||||
<div class="p-2 px-3 rounded-4 shadow-sm ${isMe ? 'bg-primary text-white' : 'bg-white'}" style="max-width: 80%;">
|
||||
<div style="word-break: break-all;">${escapeHtml(m.message)}</div>
|
||||
<div class="opacity-50 text-end" style="font-size: 8px; margin-top: 4px;">${m.created_at}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
content.scrollTop = content.scrollHeight;
|
||||
}
|
||||
`;
|
||||
content.appendChild(div);
|
||||
});
|
||||
content.scrollTop = content.scrollHeight;
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
async function sendMessage() {
|
||||
const input = document.getElementById('msgInput');
|
||||
const input = document.getElementById('adminMsgInput');
|
||||
const msg = input.value.trim();
|
||||
if (!msg || !currentChatUser) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('message', msg);
|
||||
formData.append('user_id', currentChatUser);
|
||||
const res = await fetch('ajax_handler.php?action=send_message', { method: 'POST', body: formData });
|
||||
const data = await res.json();
|
||||
if (data.code === 0) {
|
||||
input.value = '';
|
||||
loadMessages();
|
||||
loadChatUsers();
|
||||
}
|
||||
|
||||
input.value = '';
|
||||
try {
|
||||
const res = await fetch('ajax_handler.php?action=send_message', { method: 'POST', body: formData });
|
||||
const data = await res.json();
|
||||
if (data.code === 0) {
|
||||
loadMessages();
|
||||
loadChatUsers();
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
loadChatUsers();
|
||||
setInterval(() => { loadChatUsers(); loadMessages(); }, 5000);
|
||||
setInterval(() => { loadChatUsers(); loadMessages(); }, 3000);
|
||||
</script>
|
||||
|
||||
<?php elseif ($action === 'settings'): ?>
|
||||
@ -455,6 +618,39 @@ $stats = [
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<audio id="notifSound" src="https://assets.mixkit.co/active_storage/sfx/2354/2354-preview.mp3" preload="auto"></audio>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
let lastUnreadCount = 0;
|
||||
const msgToast = new bootstrap.Toast(document.getElementById('msgToast'), { delay: 5000 });
|
||||
const notifSound = document.getElementById('notifSound');
|
||||
|
||||
async function checkGlobalNotifications() {
|
||||
try {
|
||||
const res = await fetch('ajax_handler.php?action=check_new_messages');
|
||||
const data = await res.json();
|
||||
if (data.code === 0) {
|
||||
const count = parseInt(data.unread_total);
|
||||
const badge = document.getElementById('supportBadgeGlobal');
|
||||
if (count > 0) {
|
||||
badge.textContent = count;
|
||||
badge.style.display = 'inline-block';
|
||||
|
||||
if (count > lastUnreadCount) {
|
||||
msgToast.show();
|
||||
try { notifSound.play().catch(e => console.log('Audio play failed')); } catch(e) {}
|
||||
}
|
||||
} else {
|
||||
badge.style.display = 'none';
|
||||
}
|
||||
lastUnreadCount = count;
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
setInterval(checkGlobalNotifications, 5000);
|
||||
checkGlobalNotifications();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
198
ajax_handler.php
198
ajax_handler.php
@ -15,7 +15,7 @@ try {
|
||||
$stmt->execute();
|
||||
$db_apikey = $stmt->fetchColumn();
|
||||
|
||||
// Fallback if direct match fails (e.g. weird characters)
|
||||
// Fallback if direct match fails
|
||||
if (!$db_apikey) {
|
||||
$settings = $pdo->query("SELECT setting_key, setting_value FROM settings")->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
foreach ($settings as $k => $v) {
|
||||
@ -25,9 +25,7 @@ try {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Log error
|
||||
}
|
||||
} catch (Exception $e) {}
|
||||
|
||||
$api = new LubanSMS($db_apikey);
|
||||
|
||||
@ -43,30 +41,22 @@ if (!isset($_SESSION['user_id']) && $action !== 'login') {
|
||||
|
||||
function check_trc20_payment($address, $target_amount, $order_time) {
|
||||
if (!$address || $address == 'TEm1B...TRC20_ADDRESS_HERE') return false;
|
||||
|
||||
// TronScan API to check transactions
|
||||
$url = "https://apilist.tronscan.org/api/token_trc20/transfers?limit=20&start=0&direction=1&address=" . urlencode($address);
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if (!$response) return false;
|
||||
$data = json_decode($response, true);
|
||||
if (!isset($data['token_transfers'])) return false;
|
||||
|
||||
foreach ($data['token_transfers'] as $tx) {
|
||||
if ($tx['symbol'] !== 'USDT') continue;
|
||||
|
||||
$amount = (float)$tx['quant'] / pow(10, $tx['tokenInfo']['tokenDecimal']);
|
||||
$tx_time = (int)($tx['block_ts'] / 1000);
|
||||
$order_ts = strtotime($order_time);
|
||||
|
||||
if (abs($amount - $target_amount) < 0.01 && $tx_time > $order_ts) {
|
||||
return $tx['transaction_id'];
|
||||
}
|
||||
@ -84,28 +74,14 @@ try {
|
||||
break;
|
||||
|
||||
case 'get_countries':
|
||||
if (!$db_apikey) {
|
||||
echo json_encode(['code' => 500, 'msg' => '加载失败: API Key not configured in DB (Debug: key is null)'], JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
}
|
||||
$res = $api->getCountries();
|
||||
if ($res && (int)($res['code'] ?? -1) === 0) {
|
||||
$data = $res['msg'] ?? $res['data'] ?? [];
|
||||
echo json_encode(['code' => 0, 'data' => $data], JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
echo json_encode($res ?: ['code' => 500, 'msg' => 'API接口响应异常'], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
echo json_encode(['code' => 0, 'data' => $res['msg'] ?? $res['data'] ?? []], JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
|
||||
case 'get_services':
|
||||
if (!$db_apikey) {
|
||||
echo json_encode(['code' => 500, 'msg' => '加载行情失败: API Key not configured in DB'], JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
}
|
||||
$country = $_GET['country'] ?? '';
|
||||
$service = $_GET['service'] ?? '';
|
||||
$res = $api->getServices($country, $service);
|
||||
|
||||
if ($res && (int)($res['code'] ?? -1) === 0) {
|
||||
$data = $res['msg'] ?? $res['data'] ?? [];
|
||||
if (!is_array($data)) $data = [];
|
||||
@ -121,24 +97,14 @@ try {
|
||||
break;
|
||||
|
||||
case 'get_number':
|
||||
if (!$db_apikey) {
|
||||
echo json_encode(['code' => 500, 'msg' => 'API Key not configured in DB'], JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
}
|
||||
$service_id = $_GET['service_id'] ?? '';
|
||||
$country_name = $_GET['country_name'] ?? '未知国家';
|
||||
$service_name = $_GET['service_name'] ?? '未知项目';
|
||||
$price = (float)($_GET['price'] ?? 0);
|
||||
|
||||
if (!$service_id) {
|
||||
echo json_encode(['code' => 400, 'msg' => 'Service ID is required']);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$balance = (float)$stmt->fetchColumn();
|
||||
|
||||
if ($balance < $price) {
|
||||
echo json_encode(['code' => 400, 'msg' => '余额不足,请先充值']);
|
||||
break;
|
||||
@ -150,7 +116,6 @@ try {
|
||||
try {
|
||||
$stmt = $pdo->prepare("UPDATE users SET balance = balance - ? WHERE id = ?");
|
||||
$stmt->execute([$price, $_SESSION['user_id']]);
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO sms_orders (user_id, request_id, number, service_name, country_name, cost, status, expire_at) VALUES (?, ?, ?, ?, ?, ?, 'pending', DATE_ADD(NOW(), INTERVAL 10 MINUTE))");
|
||||
$stmt->execute([$_SESSION['user_id'], $res['request_id'], $res['number'], $service_name, $country_name, $price]);
|
||||
$pdo->commit();
|
||||
@ -166,11 +131,6 @@ try {
|
||||
|
||||
case 'check_sms':
|
||||
$request_id = $_GET['request_id'] ?? '';
|
||||
if (!$request_id) {
|
||||
echo json_encode(['code' => 400, 'msg' => 'Request ID is required']);
|
||||
break;
|
||||
}
|
||||
|
||||
$res = $api->getSms($request_id);
|
||||
if ($res && (int)($res['code'] ?? -1) === 0 && (string)($res['msg'] ?? '') === 'success') {
|
||||
$stmt = $pdo->prepare("UPDATE sms_orders SET sms_content = ?, status = 'received' WHERE request_id = ?");
|
||||
@ -179,117 +139,30 @@ try {
|
||||
echo json_encode($res ?: ['code' => 500, 'msg' => 'API Error'], JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
|
||||
case 'release_number':
|
||||
$request_id = $_GET['request_id'] ?? '';
|
||||
|
||||
$stmt = $pdo->prepare("SELECT created_at, status FROM sms_orders WHERE request_id = ? AND user_id = ?");
|
||||
$stmt->execute([$request_id, $_SESSION['user_id']]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
if (!$order) {
|
||||
echo json_encode(['code' => 404, 'msg' => '未找到该订单']);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($order['status'] !== 'pending') {
|
||||
echo json_encode(['code' => 400, 'msg' => '订单状态不符合释放条件']);
|
||||
break;
|
||||
}
|
||||
|
||||
$createdAt = strtotime($order['created_at']);
|
||||
if (time() - $createdAt < 120) {
|
||||
echo json_encode(['code' => 400, 'msg' => '获取号码不足2分钟,暂时无法手动释放。']);
|
||||
break;
|
||||
}
|
||||
|
||||
$res = $api->setStatus($request_id, 'reject');
|
||||
if ($res && (int)($res['code'] ?? -1) === 0) {
|
||||
$stmt = $pdo->prepare("UPDATE sms_orders SET status = 'canceled' WHERE request_id = ?");
|
||||
$stmt->execute([$request_id]);
|
||||
}
|
||||
echo json_encode($res ?: ['code' => 500, 'msg' => 'API释放失败'], JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
|
||||
case 'get_active_orders':
|
||||
// Auto expire old orders
|
||||
$stmt = $pdo->prepare("UPDATE sms_orders SET status = 'expired' WHERE status = 'pending' AND expire_at < NOW()");
|
||||
$stmt->execute();
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM sms_orders WHERE user_id = ? AND status = 'pending' ORDER BY created_at DESC");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()], JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
|
||||
case 'create_recharge':
|
||||
$amount = (float)($_POST['amount'] ?? 0);
|
||||
if ($amount < 10) {
|
||||
echo json_encode(['code' => 400, 'msg' => '最低充值金额为 10 USDT']);
|
||||
break;
|
||||
}
|
||||
|
||||
$base = floor($amount);
|
||||
$random_decimal = rand(1, 99) / 100;
|
||||
$final_amount = $base + $random_decimal;
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO recharges (user_id, amount, txid, status) VALUES (?, ?, 'Auto-Detect', 'pending')");
|
||||
if ($amount < 10) { echo json_encode(['code' => 400, 'msg' => '最低充值金额为 10 USDT']); break; }
|
||||
$final_amount = floor($amount) + (rand(1, 99) / 100);
|
||||
$stmt = $pdo->prepare("INSERT INTO recharges (user_id, amount, txid, status) VALUES (?, ?, 'Manual/Auto', 'pending')");
|
||||
$stmt->execute([$_SESSION['user_id'], $final_amount]);
|
||||
echo json_encode(['code' => 0, 'recharge_id' => $pdo->lastInsertId(), 'amount' => $final_amount], JSON_UNESCAPED_UNICODE);
|
||||
echo json_encode(['code' => 0, 'recharge_id' => $pdo->lastInsertId(), 'amount' => $final_amount]);
|
||||
break;
|
||||
|
||||
case 'check_recharge_status':
|
||||
$recharge_id = $_GET['recharge_id'] ?? '';
|
||||
if (!$recharge_id) {
|
||||
echo json_encode(['code' => 400, 'msg' => 'Recharge ID is required']);
|
||||
break;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM recharges WHERE id = ? AND user_id = ?");
|
||||
$stmt->execute([$recharge_id, $_SESSION['user_id']]);
|
||||
$recharge = $stmt->fetch();
|
||||
|
||||
if (!$recharge) {
|
||||
echo json_encode(['code' => 404, 'msg' => '未找到充值订单']);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($recharge['status'] === 'completed') {
|
||||
echo json_encode(['code' => 0, 'status' => 'completed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Try Auto-Detection
|
||||
$settings = $pdo->query("SELECT setting_key, setting_value FROM settings")->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
$trc20_address = $settings['usdt_trc20_address'] ?? '';
|
||||
|
||||
$txid = check_trc20_payment($trc20_address, $recharge['amount'], $recharge['created_at']);
|
||||
if ($txid) {
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
$stmt = $pdo->prepare("UPDATE recharges SET status = 'completed', txid = ? WHERE id = ?");
|
||||
$stmt->execute([$txid, $recharge_id]);
|
||||
$stmt = $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?");
|
||||
$stmt->execute([$recharge['amount'], $recharge['user_id']]);
|
||||
$pdo->commit();
|
||||
echo json_encode(['code' => 0, 'status' => 'completed']);
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
echo json_encode(['code' => 500, 'msg' => '自动入账失败'], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
} else {
|
||||
echo json_encode(['code' => 0, 'status' => 'pending']);
|
||||
}
|
||||
if (!$recharge) { echo json_encode(['code' => 404, 'msg' => '未找到充值订单']); break; }
|
||||
if ($recharge['status'] === 'completed') { echo json_encode(['code' => 0, 'status' => 'completed']); break; }
|
||||
echo json_encode(['code' => 0, 'status' => 'pending']);
|
||||
break;
|
||||
|
||||
case 'send_message':
|
||||
$message = trim($_POST['message'] ?? '');
|
||||
$target_user_id = $_POST['user_id'] ?? $_SESSION['user_id'];
|
||||
if (!$message) { echo json_encode(['code' => 400, 'msg' => '消息内容不能为空']); break; }
|
||||
|
||||
if (!$message) {
|
||||
echo json_encode(['code' => 400, 'msg' => '消息内容不能为空']);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check sender role
|
||||
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$role = $stmt->fetchColumn();
|
||||
@ -297,70 +170,57 @@ try {
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO support_messages (user_id, sender, message, is_read) VALUES (?, ?, ?, 0)");
|
||||
$stmt->execute([$target_user_id, $sender, $message]);
|
||||
echo json_encode(['code' => 0, 'msg' => '已发送'], JSON_UNESCAPED_UNICODE);
|
||||
echo json_encode(['code' => 0, 'msg' => '已发送']);
|
||||
break;
|
||||
|
||||
case 'get_messages':
|
||||
$target_user_id = $_GET['user_id'] ?? $_SESSION['user_id'];
|
||||
|
||||
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$currentUserRole = $stmt->fetchColumn();
|
||||
$isAdmin = ($stmt->fetchColumn() === 'admin');
|
||||
|
||||
$isAdmin = ($currentUserRole === 'admin');
|
||||
if (!$isAdmin && (int)$target_user_id !== (int)$_SESSION['user_id']) {
|
||||
echo json_encode(['code' => 403, 'msg' => '无权查看他人消息']);
|
||||
break;
|
||||
echo json_encode(['code' => 403, 'msg' => 'Forbidden']); break;
|
||||
}
|
||||
|
||||
// Mark as read
|
||||
if ($isAdmin && (int)$target_user_id !== (int)$_SESSION['user_id']) {
|
||||
$stmt = $pdo->prepare("UPDATE support_messages SET is_read = 1 WHERE user_id = ? AND sender = 'user'");
|
||||
$stmt->execute([$target_user_id]);
|
||||
$pdo->prepare("UPDATE support_messages SET is_read = 1 WHERE user_id = ? AND sender = 'user'")->execute([$target_user_id]);
|
||||
} else if (!$isAdmin) {
|
||||
$stmt = $pdo->prepare("UPDATE support_messages SET is_read = 1 WHERE user_id = ? AND sender = 'admin'");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$pdo->prepare("UPDATE support_messages SET is_read = 1 WHERE user_id = ? AND sender = 'admin'")->execute([$_SESSION['user_id']]);
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM support_messages WHERE user_id = ? ORDER BY created_at ASC");
|
||||
$stmt->execute([$target_user_id]);
|
||||
echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()], JSON_UNESCAPED_UNICODE);
|
||||
echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()]);
|
||||
break;
|
||||
|
||||
case 'get_chat_users':
|
||||
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
if ($stmt->fetchColumn() !== 'admin') {
|
||||
echo json_encode(['code' => 403, 'msg' => 'Forbidden']);
|
||||
break;
|
||||
}
|
||||
if ($stmt->fetchColumn() !== 'admin') { echo json_encode(['code' => 403, 'msg' => 'Forbidden']); break; }
|
||||
|
||||
$stmt = $pdo->query("
|
||||
SELECT u.id, u.username, m.message as last_message, m.created_at as last_time,
|
||||
(SELECT COUNT(*) FROM support_messages WHERE user_id = u.id AND sender = 'user' AND is_read = 0) as unread_count
|
||||
FROM users u
|
||||
JOIN (
|
||||
SELECT user_id, MAX(created_at) as max_time
|
||||
FROM support_messages
|
||||
GROUP BY user_id
|
||||
) last_msg ON u.id = last_msg.user_id
|
||||
JOIN (SELECT user_id, MAX(created_at) as max_time FROM support_messages GROUP BY user_id) last_msg ON u.id = last_msg.user_id
|
||||
JOIN support_messages m ON m.user_id = u.id AND m.created_at = last_msg.max_time
|
||||
ORDER BY m.created_at DESC
|
||||
");
|
||||
echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()], JSON_UNESCAPED_UNICODE);
|
||||
echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()]);
|
||||
break;
|
||||
|
||||
case 'check_new_messages':
|
||||
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
if ($stmt->fetchColumn() !== 'admin') {
|
||||
echo json_encode(['code' => 403, 'msg' => 'Forbidden']);
|
||||
break;
|
||||
$role = $stmt->fetchColumn();
|
||||
if ($role === 'admin') {
|
||||
$stmt = $pdo->query("SELECT COUNT(*) FROM support_messages WHERE sender = 'user' AND is_read = 0");
|
||||
} else {
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM support_messages WHERE user_id = ? AND sender = 'admin' AND is_read = 0");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
}
|
||||
|
||||
$stmt = $pdo->query("SELECT COUNT(*) FROM support_messages WHERE sender = 'user' AND is_read = 0");
|
||||
$count = $stmt->fetchColumn();
|
||||
echo json_encode(['code' => 0, 'unread_total' => $count]);
|
||||
echo json_encode(['code' => 0, 'unread_total' => $stmt->fetchColumn()]);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -368,5 +228,5 @@ try {
|
||||
break;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['code' => 500, 'msg' => '系统处理异常: ' . $e->getMessage()], JSON_UNESCAPED_UNICODE);
|
||||
echo json_encode(['code' => 500, 'msg' => $e->getMessage()]);
|
||||
}
|
||||
@ -56,6 +56,7 @@ $site_logo = $settings_sidebar['site_logo'] ?? 'assets/pasted-20260210-082628-83
|
||||
border-radius: 14px;
|
||||
margin-bottom: 6px;
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
}
|
||||
.sidebar .nav-link i {
|
||||
font-size: 1.2rem;
|
||||
@ -94,12 +95,28 @@ $site_logo = $settings_sidebar['site_logo'] ?? 'assets/pasted-20260210-082628-83
|
||||
.logout-link:hover {
|
||||
background-color: #fef2f2 !important;
|
||||
}
|
||||
.badge-notif {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 15px;
|
||||
background: #ef4444;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
font-size: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 0 0 2px white;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.sidebar { width: 85px; padding: 2rem 0.8rem; }
|
||||
.sidebar-brand span, .sidebar .nav-link span, .user-profile-mini { display: none; }
|
||||
.sidebar-brand { margin-bottom: 2rem; padding: 0; justify-content: center; }
|
||||
.sidebar .nav-link { justify-content: center; padding: 15px; margin-bottom: 10px; }
|
||||
.badge-notif { top: 5px; right: 5px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -125,6 +142,7 @@ $site_logo = $settings_sidebar['site_logo'] ?? 'assets/pasted-20260210-082628-83
|
||||
<a href="support.php" class="nav-link <?= $current_page === 'support.php' ? 'active' : '' ?>">
|
||||
<i class="fas fa-headset"></i>
|
||||
<span>联系客服</span>
|
||||
<span id="userSupportBadge" class="badge-notif" style="display:none;">0</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
@ -148,3 +166,26 @@ $site_logo = $settings_sidebar['site_logo'] ?? 'assets/pasted-20260210-082628-83
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function checkUserNotifications() {
|
||||
try {
|
||||
const res = await fetch('ajax_handler.php?action=check_new_messages');
|
||||
const data = await res.json();
|
||||
if (data.code === 0) {
|
||||
const count = parseInt(data.unread_total);
|
||||
const badge = document.getElementById('userSupportBadge');
|
||||
if (badge) {
|
||||
if (count > 0) {
|
||||
badge.textContent = count;
|
||||
badge.style.display = 'flex';
|
||||
} else {
|
||||
badge.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
setInterval(checkUserNotifications, 5000);
|
||||
checkUserNotifications();
|
||||
</script>
|
||||
53
rescue.php
53
rescue.php
@ -3,21 +3,42 @@ session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
$pdo = db();
|
||||
|
||||
// Force the only user to be admin
|
||||
$stmt = $pdo->query("SELECT * FROM users");
|
||||
$users = $stmt->fetchAll();
|
||||
|
||||
if (count($users) === 1) {
|
||||
$user = $users[0];
|
||||
$pdo->query("UPDATE users SET role = 'admin' WHERE id = " . $user['id']);
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$userId = $_SESSION['user_id'];
|
||||
$pdo->query("UPDATE users SET role = 'admin' WHERE id = " . $userId);
|
||||
$_SESSION['role'] = 'admin';
|
||||
echo "<h1>Account Rescued!</h1>";
|
||||
echo "<p>Your account (<strong>" . htmlspecialchars($user['username']) . "</strong>) has been set as Administrator.</p>";
|
||||
echo "<p><a href='admin.php'>Click here to go to Admin Panel</a></p>";
|
||||
|
||||
$username = $_SESSION['username'] ?? 'User';
|
||||
|
||||
echo "<!DOCTYPE html>
|
||||
<html lang='zh-CN'>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<title>Account Rescued</title>
|
||||
<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css' rel='stylesheet'>
|
||||
</head>
|
||||
<body class='bg-light d-flex align-items-center justify-content-center' style='height: 100vh;'>
|
||||
<div class='card shadow p-5 text-center' style='max-width: 500px;'>
|
||||
<h1 class='text-success mb-4'>✅ 成功修复!</h1>
|
||||
<p class='lead mb-4'>您的账号 (<strong>" . htmlspecialchars($username) . "</strong>) 已成功提升为<strong>管理员</strong>权限。</p>
|
||||
<a href='admin.php' class='btn btn-primary btn-lg px-5'>进入后台</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>";
|
||||
} else {
|
||||
echo "<h1>Rescue failed</h1>";
|
||||
echo "<p>System has multiple users. Please login with an admin account.</p>";
|
||||
echo "<p><a href='index.php'>Go back</a></p>";
|
||||
}
|
||||
// If not logged in, just make the first found user admin and log them in
|
||||
$stmt = $pdo->query("SELECT * FROM users ORDER BY id ASC LIMIT 1");
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user) {
|
||||
$pdo->query("UPDATE users SET role = 'admin' WHERE id = " . $user['id']);
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role'] = 'admin';
|
||||
|
||||
header('Location: rescue.php');
|
||||
exit;
|
||||
} else {
|
||||
echo "<h1>Rescue failed</h1><p>No users found in database. Please register first.</p><p><a href='index.php'>Go to Home</a></p>";
|
||||
}
|
||||
}
|
||||
14
support.php
14
support.php
@ -78,8 +78,8 @@ $user = $stmt->fetch();
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.message { margin-bottom: 1.5rem; max-width: 70%; display: flex; flex-direction: column; }
|
||||
.message-content { padding: 1rem 1.25rem; border-radius: 18px; font-size: 14px; font-weight: 500; line-height: 1.6; }
|
||||
.message { margin-bottom: 1.5rem; max-width: 75%; display: flex; flex-direction: column; }
|
||||
.message-content { padding: 1rem 1.25rem; border-radius: 18px; font-size: 14px; font-weight: 500; line-height: 1.6; position: relative; }
|
||||
.message-user { margin-left: auto; align-items: flex-end; }
|
||||
.message-user .message-content { background: var(--primary-gradient); color: white; border-bottom-right-radius: 4px; box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2); }
|
||||
.message-admin { align-items: flex-start; }
|
||||
@ -140,10 +140,13 @@ $user = $stmt->fetch();
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<audio id="notifSound" src="https://assets.mixkit.co/active_storage/sfx/2354/2354-preview.mp3" preload="auto"></audio>
|
||||
|
||||
<script>
|
||||
const chatBody = document.getElementById('chatBody');
|
||||
const chatForm = document.getElementById('chatForm');
|
||||
const msgInput = document.getElementById('msgInput');
|
||||
const notifSound = document.getElementById('notifSound');
|
||||
let lastMsgCount = 0;
|
||||
|
||||
async function loadMessages() {
|
||||
@ -167,6 +170,13 @@ $user = $stmt->fetch();
|
||||
chatBody.appendChild(div);
|
||||
});
|
||||
|
||||
if (lastMsgCount > 0 && data.data.length > lastMsgCount) {
|
||||
const lastMsg = data.data[data.data.length - 1];
|
||||
if (lastMsg.sender === 'admin') {
|
||||
try { notifSound.play().catch(e => console.log('Audio play failed')); } catch(e) {}
|
||||
}
|
||||
}
|
||||
|
||||
lastMsgCount = data.data.length;
|
||||
chatBody.scrollTop = chatBody.scrollHeight;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user