237 lines
11 KiB
PHP
237 lines
11 KiB
PHP
<?php
|
|
session_start();
|
|
require_once 'db/config.php';
|
|
require_once 'includes/i18n.php';
|
|
|
|
if (!isset($_SESSION['user_id'])) {
|
|
die(__('please_login'));
|
|
}
|
|
|
|
$user_id = $_SESSION['user_id'];
|
|
$db = db();
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) {
|
|
$msg = trim($_POST['message']);
|
|
if ($msg !== '') {
|
|
$stmt = $db->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', ?)");
|
|
$stmt->execute([$user_id, $msg]);
|
|
echo json_encode(['success' => true]);
|
|
}
|
|
exit;
|
|
}
|
|
|
|
// Fetch greeting message
|
|
$stmt = $db->prepare("SELECT value FROM settings WHERE name = 'chat_greeting'");
|
|
$stmt->execute();
|
|
$greeting = $stmt->fetchColumn();
|
|
if (!$greeting) {
|
|
$greeting = ($lang == 'zh') ? '您好!欢迎咨询 NovaEx 官方客服,请问有什么可以帮您?' : 'Hello! Welcome to NovaEx official customer service. How can we help you today?';
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="<?php echo $lang; ?>">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
|
<style>
|
|
:root {
|
|
--primary-color: #f0b90b;
|
|
--bg-color: #161a1e;
|
|
--card-bg: #1e2329;
|
|
--border-color: #2b3139;
|
|
--text-color: #ffffff;
|
|
--text-muted: #848e9c;
|
|
}
|
|
body { margin: 0; padding: 0; font-family: 'Inter', sans-serif; background: var(--bg-color); color: white; height: 100vh; display: flex; flex-direction: column; overflow: hidden; }
|
|
#chat-box { flex: 1; overflow-y: auto; padding: 15px; display: flex; flex-direction: column; gap: 12px; scroll-behavior: smooth; }
|
|
.msg { max-width: 80%; padding: 10px 14px; border-radius: 12px; font-size: 14px; line-height: 1.4; word-wrap: break-word; position: relative; }
|
|
.msg.user { align-self: flex-end; background: var(--primary-color); color: black; border-bottom-right-radius: 2px; }
|
|
.msg.admin { align-self: flex-start; background: #2b3139; color: #EAECEF; border-bottom-left-radius: 2px; border: 1px solid #3b424d; }
|
|
.msg-time { font-size: 10px; opacity: 0.5; margin-top: 4px; display: block; }
|
|
.chat-input-area { padding: 12px; background: #1e2329; border-top: 1px solid #2b3139; display: flex; gap: 10px; align-items: center; }
|
|
input[type="text"] { flex: 1; background: #0b0e11; border: 1px solid #2b3139; border-radius: 8px; padding: 10px 12px; color: white; outline: none; }
|
|
.icon-btn { background: #2b3139; border: 1px solid #3b424d; width: 40px; height: 40px; border-radius: 8px; color: var(--primary-color); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s; }
|
|
.icon-btn:hover { background: #3b424d; }
|
|
.send-btn { background: var(--primary-color); border: none; width: 40px; height: 40px; border-radius: 8px; color: black; cursor: pointer; display: flex; align-items: center; justify-content: center; }
|
|
#chat-box::-webkit-scrollbar { width: 4px; }
|
|
#chat-box::-webkit-scrollbar-thumb { background: #2b3139; border-radius: 10px; }
|
|
img.chat-img { max-width: 100%; border-radius: 8px; margin-top: 5px; cursor: pointer; }
|
|
|
|
/* Modal inside iframe */
|
|
.modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 85%; background: var(--card-bg); border-radius: 16px; border: 1px solid var(--primary-color); z-index: 1000; padding: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.5); display: none; }
|
|
.backdrop { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); z-index: 999; display: none; }
|
|
.modal-btn { width: 100%; background: var(--primary-color); border: none; padding: 10px; border-radius: 8px; font-weight: bold; cursor: pointer; margin-top: 15px; }
|
|
|
|
.sending { opacity: 0.7; }
|
|
.sending::after { content: '...'; position: absolute; right: 5px; bottom: 5px; font-size: 10px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div id="acc-backdrop" class="backdrop"></div>
|
|
<div id="acc-modal" class="modal">
|
|
<div style="text-align: center; margin-bottom: 15px;">
|
|
<i class="fas fa-university" style="color: var(--primary-color); font-size: 24px;"></i>
|
|
<h4 style="margin: 10px 0 5px;" id="modal-title"><?php echo __('matched_status'); ?></h4>
|
|
<p style="color: var(--text-muted); font-size: 12px;" id="modal-tip"><?php echo __('matched_info_tip'); ?></p>
|
|
</div>
|
|
<div id="acc-info" style="background: #161a1e; padding: 15px; border-radius: 8px; font-size: 13px; line-height: 1.6; border: 1px solid #2b3139;"></div>
|
|
<button onclick="closeModal()" class="modal-btn"><?php echo __('confirm'); ?></button>
|
|
</div>
|
|
|
|
<div id="chat-box"></div>
|
|
|
|
<form id="chat-form" class="chat-input-area">
|
|
<button type="button" class="icon-btn" id="upload-btn" onclick="document.getElementById('image-input').click()">
|
|
<i class="fas fa-plus"></i>
|
|
</button>
|
|
<input type="file" id="image-input" accept="image/*" style="display: none;" onchange="uploadImage(this)">
|
|
|
|
<input type="text" id="msg-input" placeholder="<?php echo __('type_message'); ?>" autocomplete="off">
|
|
<button type="submit" class="send-btn"><i class="fas fa-paper-plane"></i></button>
|
|
</form>
|
|
|
|
<script>
|
|
const chatBox = document.getElementById('chat-box');
|
|
const msgInput = document.getElementById('msg-input');
|
|
const uploadBtn = document.getElementById('upload-btn');
|
|
const greeting = `<?php echo addslashes($greeting); ?>`;
|
|
let lastStatus = '';
|
|
let lastOrderId = 0;
|
|
let lastMessagesHtml = '';
|
|
let isSending = false;
|
|
|
|
async function loadMessages() {
|
|
if (isSending) return; // Prevent refresh while sending to avoid flickering
|
|
try {
|
|
const resp = await fetch('api/get_messages.php');
|
|
const res = await resp.json();
|
|
if (res.success) {
|
|
if (res.data.length === 0) {
|
|
chatBox.innerHTML = `
|
|
<div class="msg admin">
|
|
${greeting.replace(/\n/g, '<br>')}
|
|
</div>
|
|
`;
|
|
} else {
|
|
let html = '';
|
|
res.data.forEach(m => {
|
|
const content = m.type === 'image'
|
|
? `<img src="${m.message}" class="chat-img" onclick="window.open(this.src)">`
|
|
: m.message.replace(/\n/g, '<br>');
|
|
|
|
html += `
|
|
<div class="msg ${m.sender}">
|
|
${content}
|
|
<span class="msg-time">${new Date(m.created_at).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</span>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
if (html !== lastMessagesHtml) {
|
|
const isAtBottom = chatBox.scrollHeight - chatBox.scrollTop <= chatBox.clientHeight + 100;
|
|
chatBox.innerHTML = html;
|
|
lastMessagesHtml = html;
|
|
if (isAtBottom) chatBox.scrollTop = chatBox.scrollHeight;
|
|
|
|
// Mark messages as read
|
|
fetch('api/get_messages.php?action=mark_read&user_id=<?php echo $user_id; ?>&reader=user');
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {}
|
|
}
|
|
|
|
async function checkOrderStatus() {
|
|
try {
|
|
const resp = await fetch('api/check_order_status.php');
|
|
const res = await resp.json();
|
|
if (res.success && res.order) {
|
|
if (res.order.status === 'matched' && (res.order.status !== lastStatus || res.order.id !== lastOrderId)) {
|
|
const title = res.order.order_type === 'deposit' ? '<?php echo __('matched_status'); ?>' : '<?php echo __('withdraw_format_title'); ?>';
|
|
const tip = res.order.order_type === 'deposit' ? '<?php echo __('matched_info_tip'); ?>' : '<?php echo __('withdraw_info_tip'); ?>';
|
|
showModal(title, tip, res.order.bank_account_info);
|
|
lastStatus = res.order.status;
|
|
lastOrderId = res.order.id;
|
|
}
|
|
}
|
|
} catch (e) {}
|
|
}
|
|
|
|
function showModal(title, tip, info) {
|
|
if (!info) return;
|
|
document.getElementById('modal-title').innerText = title;
|
|
document.getElementById('modal-tip').innerText = tip;
|
|
document.getElementById('acc-info').innerHTML = info.replace(/\n/g, '<br>');
|
|
document.getElementById('acc-backdrop').style.display = 'block';
|
|
document.getElementById('acc-modal').style.display = 'block';
|
|
}
|
|
|
|
function closeModal() {
|
|
document.getElementById('acc-backdrop').style.display = 'none';
|
|
document.getElementById('acc-modal').style.display = 'none';
|
|
}
|
|
|
|
document.getElementById('chat-form').onsubmit = async (e) => {
|
|
e.preventDefault();
|
|
const msg = msgInput.value.trim();
|
|
if (!msg || isSending) return;
|
|
|
|
msgInput.value = '';
|
|
isSending = true;
|
|
|
|
// Optimistic UI: Add message locally
|
|
const tempMsg = document.createElement('div');
|
|
tempMsg.className = 'msg user sending';
|
|
tempMsg.innerHTML = `${msg.replace(/\n/g, '<br>')}<span class="msg-time">${new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</span>`;
|
|
chatBox.appendChild(tempMsg);
|
|
chatBox.scrollTop = chatBox.scrollHeight;
|
|
|
|
const formData = new FormData();
|
|
formData.append('message', msg);
|
|
|
|
try {
|
|
await fetch('chat_iframe.php', { method: 'POST', body: formData });
|
|
isSending = false;
|
|
await loadMessages();
|
|
} catch (e) {
|
|
isSending = false;
|
|
tempMsg.style.background = '#ff4d4f';
|
|
tempMsg.innerHTML += ' (Failed)';
|
|
}
|
|
};
|
|
|
|
function uploadImage(input) {
|
|
if (!input.files || !input.files[0]) return;
|
|
const formData = new FormData();
|
|
formData.append('image', input.files[0]);
|
|
|
|
uploadBtn.disabled = true;
|
|
uploadBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
|
|
|
|
fetch('api/upload_chat_image.php', { method: 'POST', body: formData })
|
|
.then(res => res.json())
|
|
.then(res => {
|
|
if (res.success) {
|
|
loadMessages();
|
|
} else {
|
|
alert(res.error || 'Upload failed');
|
|
}
|
|
})
|
|
.finally(() => {
|
|
uploadBtn.disabled = false;
|
|
uploadBtn.innerHTML = '<i class="fas fa-plus"></i>';
|
|
input.value = '';
|
|
});
|
|
}
|
|
|
|
// Initial calls
|
|
loadMessages();
|
|
checkOrderStatus();
|
|
|
|
// Polling
|
|
setInterval(loadMessages, 1000);
|
|
setInterval(checkOrderStatus, 2000);
|
|
</script>
|
|
</body>
|
|
</html>
|