38350-vm/chat_iframe.php
2026-02-14 05:11:30 +00:00

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>