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 showToast = (message, type = 'success') => { const container = document.querySelector('.toast-container'); if (!container) return; const toast = document.createElement('div'); toast.className = `toast align-items-center text-bg-${type} border-0 show`; toast.setAttribute('role', 'alert'); toast.innerHTML = `
${message}
`; container.appendChild(toast); setTimeout(() => toast.remove(), 3200); }; const initFrontend = () => { const countrySearch = document.getElementById('countrySearch'); const countryList = document.getElementById('countryList'); const selectedCode = document.getElementById('selectedCode'); const phoneNumber = document.getElementById('phoneNumber'); const startChat = document.getElementById('startChat'); const shortcutListUI = document.getElementById('shortcutList'); const newShortcut = document.getElementById('newShortcut'); const addShortcut = document.getElementById('addShortcut'); const chatInput = document.querySelector('[data-chat-input]'); const shortcutsDisplay = document.querySelector('[data-shortcuts]'); const emojiTrigger = document.querySelector('[data-emoji-trigger]'); const emojiPicker = document.querySelector('[data-emoji-picker]'); // Country Search & Selection const renderCountries = (filter = '') => { countryList.innerHTML = countries .filter(c => c.name.includes(filter) || c.code.includes(filter)) .map(c => `
${c.name} ${c.code}
`).join(''); }; countrySearch.addEventListener('input', (e) => renderCountries(e.target.value)); window.selectCountry = (name, code) => { selectedCode.textContent = code; document.getElementById('searchTrigger').textContent = name + ' (' + code + ')'; bootstrap.Modal.getInstance(document.getElementById('countryModal')).hide(); }; renderCountries(); // Shortcuts Management let shortcuts = JSON.parse(localStorage.getItem('shortcuts') || '[]'); const renderShortcuts = () => { shortcutListUI.innerHTML = shortcuts.map((s, i) => `
  • ${s}
  • `).join(''); shortcutsDisplay.innerHTML = shortcuts.map(s => ` `).join(''); }; window.insertShortcut = (text) => chatInput.value += text; window.deleteShortcut = (index) => { shortcuts.splice(index, 1); localStorage.setItem('shortcuts', JSON.stringify(shortcuts)); renderShortcuts(); }; addShortcut.addEventListener('click', () => { if (!newShortcut.value) return; shortcuts.push(newShortcut.value); localStorage.setItem('shortcuts', JSON.stringify(shortcuts)); newShortcut.value = ''; renderShortcuts(); }); renderShortcuts(); // Emoji Picker emojiTrigger.addEventListener('click', () => emojiPicker.toggleAttribute('hidden')); emojiPicker.addEventListener('emoji-click', (e) => { chatInput.value += e.detail.unicode; emojiPicker.setAttribute('hidden', ''); }); // Start Chat startChat.addEventListener('click', () => { if (!phoneNumber.value) return; const phone = selectedCode.textContent + phoneNumber.value; document.querySelector('[data-chat-title]').textContent = phone; bootstrap.Modal.getInstance(document.getElementById('countryModal')).hide(); showToast('已开始与 ' + phone + ' 的聊天'); }); }; const initAdmin = () => { const navLinks = document.querySelectorAll('[data-section-link]'); const sections = document.querySelectorAll('[data-section]'); navLinks.forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); const target = link.dataset.sectionLink; navLinks.forEach(l => l.classList.remove('active')); link.classList.add('active'); sections.forEach(s => s.classList.add('d-none')); document.querySelector(`[data-section="${target}"]`).classList.remove('d-none'); if (target === 'dashboard') loadDashboard(); if (target === 'contacts') loadAdminContacts(); if (target === 'messages') loadAdminMessages(); if (target === 'auto') loadAutoReplies(); if (target === 'settings') loadSettings(); }); }); // Forms document.querySelector('[data-send-form]')?.addEventListener('submit', async (e) => { e.preventDefault(); const data = Object.fromEntries(new FormData(e.target)); try { await apiFetch('/api/messages.php', { method: 'POST', body: { contact_phone: data.phone, body: data.body, direction: 'out' } }); showToast('发送成功'); e.target.reset(); } catch (e) { showToast('发送失败', 'danger'); } }); document.querySelector('[data-reply-form]')?.addEventListener('submit', async (e) => { e.preventDefault(); const data = Object.fromEntries(new FormData(e.target)); try { await apiFetch('/api/auto_reply.php', { method: 'POST', body: data }); showToast('已添加规则'); e.target.reset(); loadAutoReplies(); } catch (e) { showToast('添加失败', 'danger'); } }); document.querySelector('[data-settings-form]')?.addEventListener('submit', async (e) => { e.preventDefault(); const data = Object.fromEntries(new FormData(e.target)); try { await apiFetch('/api/settings.php', { method: 'POST', body: data }); showToast('配置已保存'); } catch (e) { showToast('保存失败', 'danger'); } }); const loadDashboard = async () => { try { const data = await apiFetch('/api/stats.php'); document.querySelector('[data-stat="sent"]').textContent = data.sent || 0; document.querySelector('[data-stat="received"]').textContent = data.received || 0; document.querySelector('[data-stat="active"]').textContent = data.active || 0; } catch (e) { console.error(e); } }; const loadAdminContacts = async () => { const data = await apiFetch('/api/contacts.php'); const list = document.querySelector('[data-admin-contacts]'); list.innerHTML = (data.contacts || []).map(c => ` ${c.phone} ${c.tags || '-'} ${c.status} `).join(''); }; window.toggleBlock = async (id, currentStatus) => { const newStatus = currentStatus === 'blocked' ? 'normal' : 'blocked'; await apiFetch(`/api/contacts.php?action=update&id=${id}`, { method: 'POST', body: { status: newStatus } }); loadAdminContacts(); }; window.deleteContact = async (id) => { if (!confirm('确定删除?')) return; await apiFetch(`/api/contacts.php?action=delete&id=${id}`, { method: 'POST' }); loadAdminContacts(); }; const loadAdminMessages = async () => { const data = await apiFetch('/api/messages.php'); const list = document.querySelector('[data-admin-messages]'); list.innerHTML = (data.messages || []).map(m => ` ${m.phone} ${m.direction} ${m.body} ${m.created_at} `).join(''); }; const loadAutoReplies = async () => { const data = await apiFetch('/api/auto_reply.php'); const list = document.querySelector('[data-reply-list]'); list.innerHTML = (data.rules || []).map(r => `
  • ${r.keyword}: ${r.reply}
  • `).join(''); }; window.deleteRule = async (id) => { await apiFetch(`/api/auto_reply.php?action=delete&id=${id}`, { method: 'POST' }); loadAutoReplies(); }; const loadSettings = async () => { const data = await apiFetch('/api/settings.php'); if (!data) return; const form = document.querySelector('[data-settings-form]'); form.sid.value = data.sid || ''; form.token.value = data.token || ''; form.from.value = data.from || ''; form.webhook.value = data.webhook || ''; }; loadDashboard(); }; document.addEventListener('DOMContentLoaded', () => { if (document.body.dataset.page === 'agent') initFrontend(); if (document.body.dataset.page === 'admin') initAdmin(); });