2026-03-12 03:03:10 +00:00

186 lines
6.3 KiB
JavaScript

document.addEventListener('DOMContentLoaded', () => {
const app = document.getElementById('chat-app');
if (!app) return;
const twilioSelect = document.getElementById('twilio-select');
const conversationList = document.getElementById('conversation-list');
const messageList = document.getElementById('message-list');
const messageForm = document.getElementById('message-form');
const messageInput = document.getElementById('message-input');
const conversationTitle = document.getElementById('conversation-title');
const conversationStatus = document.getElementById('conversation-status');
const searchInput = document.getElementById('search-input');
const addContactForm = document.getElementById('add-contact-form');
const alertBox = document.getElementById('chat-alert');
let activeConversationId = null;
let activeTwilioId = twilioSelect ? twilioSelect.value : null;
let pollTimer = null;
const showAlert = (text, type = 'info') => {
if (!alertBox) return;
alertBox.textContent = text;
alertBox.className = `alert alert-${type} alert-inline`;
alertBox.classList.remove('d-none');
setTimeout(() => alertBox.classList.add('d-none'), 3000);
};
const formatTime = (iso) => {
if (!iso) return '';
const dt = new Date(iso.replace(' ', 'T'));
return dt.toLocaleString();
};
const renderConversations = (items) => {
conversationList.innerHTML = '';
if (!items.length) {
conversationList.innerHTML = '<div class="p-3 muted">暂无会话。添加号码开始对话。</div>';
return;
}
items.forEach((item) => {
const div = document.createElement('div');
div.className = 'conversation-item' + (item.id === activeConversationId ? ' active' : '');
div.dataset.id = item.id;
div.innerHTML = `
<div class="conversation-avatar">${(item.name || item.phone).slice(0, 2).toUpperCase()}</div>
<div class="conversation-meta">
<div class="fw-semibold">${item.name || item.phone}</div>
<small>${item.last_message || '暂无消息'}</small>
</div>
<small class="text-muted">${item.last_time ? formatTime(item.last_time) : ''}</small>
`;
div.addEventListener('click', () => {
activeConversationId = item.id;
conversationTitle.textContent = item.name || item.phone;
conversationStatus.textContent = item.phone;
fetchMessages();
fetchConversations();
});
conversationList.appendChild(div);
});
};
const renderMessages = (items) => {
messageList.innerHTML = '';
if (!items.length) {
messageList.innerHTML = '<div class="muted">暂无消息,开始发送第一条短信。</div>';
return;
}
items.forEach((msg) => {
const div = document.createElement('div');
div.className = `message ${msg.direction === 'outbound' ? 'outbound' : 'inbound'}`;
div.innerHTML = `
<div>${msg.body}</div>
<span class="timestamp">${formatTime(msg.created_at)}</span>
`;
messageList.appendChild(div);
});
messageList.scrollTop = messageList.scrollHeight;
};
const fetchConversations = async () => {
if (!activeTwilioId) return;
const res = await fetch(`api/conversations.php?twilio_number_id=${activeTwilioId}`);
const data = await res.json();
renderConversations(data.items || []);
if (!activeConversationId && data.items && data.items.length) {
activeConversationId = data.items[0].id;
conversationTitle.textContent = data.items[0].name || data.items[0].phone;
conversationStatus.textContent = data.items[0].phone;
fetchMessages();
}
};
const fetchMessages = async () => {
if (!activeConversationId) {
renderMessages([]);
return;
}
const res = await fetch(`api/messages.php?conversation_id=${activeConversationId}`);
const data = await res.json();
renderMessages(data.items || []);
};
const startPolling = () => {
if (pollTimer) clearInterval(pollTimer);
pollTimer = setInterval(() => {
fetchConversations();
fetchMessages();
}, 5000);
};
if (twilioSelect) {
twilioSelect.addEventListener('change', () => {
activeTwilioId = twilioSelect.value;
activeConversationId = null;
conversationTitle.textContent = '请选择会话';
conversationStatus.textContent = '';
fetchConversations();
fetchMessages();
});
}
if (searchInput) {
searchInput.addEventListener('input', () => {
const term = searchInput.value.toLowerCase();
const items = conversationList.querySelectorAll('.conversation-item');
items.forEach((item) => {
const text = item.textContent.toLowerCase();
item.style.display = text.includes(term) ? 'flex' : 'none';
});
});
}
if (messageForm) {
messageForm.addEventListener('submit', async (e) => {
e.preventDefault();
const body = messageInput.value.trim();
if (!body) return;
if (!activeConversationId) {
showAlert('请先选择一个会话。', 'warning');
return;
}
messageInput.value = '';
const res = await fetch('api/send_message.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ conversation_id: activeConversationId, body })
});
const data = await res.json();
if (!data.success) {
showAlert(data.error || '发送失败', 'danger');
}
fetchMessages();
fetchConversations();
});
}
if (addContactForm) {
addContactForm.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(addContactForm);
formData.append('twilio_number_id', activeTwilioId || '');
const res = await fetch('api/add_contact.php', {
method: 'POST',
body: formData
});
const data = await res.json();
if (data.success) {
activeConversationId = data.conversation_id;
fetchConversations();
fetchMessages();
showAlert('已添加号码并创建会话。', 'success');
const modal = bootstrap.Modal.getInstance(document.getElementById('addContactModal'));
if (modal) modal.hide();
addContactForm.reset();
} else {
showAlert(data.error || '添加失败', 'danger');
}
});
}
fetchConversations();
fetchMessages();
startPolling();
});