const apiFetch = async (url, options = {}) => { const opts = { headers: { 'Content-Type': 'application/json' }, ...options, }; if (opts.body && typeof opts.body !== 'string') { opts.body = JSON.stringify(opts.body); } const res = await fetch(url, opts); if (!res.ok) { throw new Error(`API error: ${res.status}`); } return res.json(); }; const initFrontend = () => { const contactsList = document.querySelector('[data-contacts]'); const chatForm = document.querySelector('[data-chat-form]'); const chatInput = document.querySelector('[data-chat-input]'); const chatBody = document.querySelector('[data-chat-body]'); const chatTitle = document.querySelector('[data-chat-title]'); const countryModal = new bootstrap.Modal(document.getElementById('countryModal')); // Emoji Picker const emojiPicker = document.querySelector('emoji-picker'); const emojiTrigger = document.querySelector('[data-emoji-trigger]'); if (emojiPicker && emojiTrigger) { emojiPicker.addEventListener('emoji-click', event => { chatInput.value += event.detail.unicode; emojiPicker.classList.add('d-none'); }); emojiTrigger.addEventListener('click', (e) => { e.stopPropagation(); emojiPicker.classList.toggle('d-none'); }); document.addEventListener('click', (e) => { if (!emojiTrigger.contains(e.target) && !emojiPicker.contains(e.target)) { emojiPicker.classList.add('d-none'); } }); } let state = JSON.parse(localStorage.getItem('sms_state') || '{"contacts": {}, "messages": {}}'); let currentChatPhone = null; const saveState = () => localStorage.setItem('sms_state', JSON.stringify(state)); const formatTime = (ts) => new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); const renderContacts = () => { contactsList.innerHTML = Object.keys(state.contacts).sort((a,b) => (state.messages[b]?.slice(-1)[0]?.time || 0) - (state.messages[a]?.slice(-1)[0]?.time || 0)).map(phone => `
${phone.substring(phone.length - 2)}
${phone}
${state.messages[phone]?.slice(-1)[0]?.text || ''}
`).join(''); }; window.switchChat = (phone) => { currentChatPhone = phone; chatTitle.textContent = phone; chatBody.innerHTML = (state.messages[phone] || []).map((m, idx) => `
${m.text}
${formatTime(m.time)}
`).join(''); renderContacts(); }; window.showMsgActions = (e, phone, idx) => { const bubble = e.currentTarget; const dropdown = bubble.querySelector('.dropdown-toggle') || bubble.querySelector('[data-bs-toggle="dropdown"]'); if (dropdown) { const bsDropdown = new bootstrap.Dropdown(dropdown); bsDropdown.show(); } }; window.msgAction = (action, phone, idx) => { if (action === 'delete' || action === 'recall') { state.messages[phone].splice(idx, 1); } else if (action === 'edit') { const newText = prompt('编辑消息:', state.messages[phone][idx].text); if (newText) state.messages[phone][idx].text = newText; } saveState(); switchChat(phone); }; window.deleteContact = (phone) => { delete state.contacts[phone]; delete state.messages[phone]; if (currentChatPhone === phone) { currentChatPhone = null; chatTitle.textContent = '请选择联系人'; chatBody.innerHTML = ''; } saveState(); renderContacts(); }; const selectedCode = document.getElementById('selectedCode'); const phoneNumber = document.getElementById('phoneNumber'); document.getElementById('startChat').addEventListener('click', () => { if (!phoneNumber.value) return; const phone = selectedCode.textContent + phoneNumber.value; if (!state.contacts[phone]) { state.contacts[phone] = { created: Date.now() }; state.messages[phone] = []; } currentChatPhone = phone; saveState(); renderContacts(); switchChat(phone); countryModal.hide(); }); chatForm.addEventListener('submit', (e) => { e.preventDefault(); if(!currentChatPhone || !chatInput.value) return; const msg = { type: 'out', text: chatInput.value, time: Date.now() }; state.messages[currentChatPhone].push(msg); saveState(); chatInput.value = ''; switchChat(currentChatPhone); apiFetch('/api/messages.php', { method: 'POST', body: { phone: currentChatPhone, body: msg.text, direction: 'out' } }).catch(() => {}); }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { currentChatPhone = null; chatTitle.textContent = '请选择联系人'; chatBody.innerHTML = ''; renderContacts(); } }); renderContacts(); }; document.addEventListener('DOMContentLoaded', () => { if (document.body.dataset.page === 'agent') initFrontend(); });