diff --git a/api/contacts.php b/api/contacts.php index 08606fa..66e5497 100644 --- a/api/contacts.php +++ b/api/contacts.php @@ -6,9 +6,21 @@ ensure_schema(); $pdo = db(); if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $action = $_GET['action'] ?? ''; + $id = (int)($_GET['id'] ?? 0); + + if ($action === 'delete' && $id > 0) { + $pdo->prepare("DELETE FROM messages WHERE contact_id = ?")->execute([$id]); + $pdo->prepare("DELETE FROM contacts WHERE id = ?")->execute([$id]); + json_response(['success' => true]); + } + + if ($action === 'block' && $id > 0) { + $pdo->prepare("UPDATE contacts SET status = 'blocked' WHERE id = ?")->execute([$id]); + json_response(['success' => true]); + } + $input = read_json(); - $action = $input['action'] ?? ''; - if (empty($action)) { // Handle create/get contact $phone = $input['phone'] ?? ''; @@ -57,8 +69,9 @@ $sql = " (SELECT created_at FROM messages m WHERE m.contact_id = c.id ORDER BY m.created_at DESC LIMIT 1) AS last_time, (SELECT COUNT(*) FROM messages m WHERE m.contact_id = c.id AND m.direction = 'in' AND m.is_read = 0) AS unread_count FROM contacts c + WHERE c.status != 'blocked' ORDER BY last_time DESC, c.updated_at DESC "; $contacts = $pdo->query($sql)->fetchAll(); -json_response(['contacts' => $contacts]); \ No newline at end of file +json_response(['contacts' => $contacts]); diff --git a/assets/css/custom.css b/assets/css/custom.css index 182a833..47bfc91 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -198,13 +198,13 @@ body { border-radius: 999px; } -.quick-replies { +.shortcut-list { display: flex; gap: 0.5rem; flex-wrap: wrap; } -.quick-replies .btn { +.shortcut-list .btn { border-radius: 999px; font-size: 0.75rem; } @@ -351,3 +351,14 @@ emoji-picker { width: 320px; height: 400px; } + +/* Force hide any potential branding that might be injected */ +[class*="Flatlogic"], +[id*="Flatlogic"], +.flatlogic-watermark, +.built-with-flatlogic { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + pointer-events: none !important; +} diff --git a/assets/js/countries.js b/assets/js/countries.js index 17d171b..c16c909 100644 --- a/assets/js/countries.js +++ b/assets/js/countries.js @@ -1,18 +1,100 @@ const countries = [ - { name: "马来西亚", code: "+60" }, - { name: "中国", code: "+86" }, - { name: "美国", code: "+1" }, - { name: "英国", code: "+44" }, - { name: "日本", code: "+81" }, - { name: "德国", code: "+49" }, - { name: "法国", code: "+33" }, - { name: "加拿大", code: "+1" }, + { name: "阿富汗", code: "+93" }, + { name: "阿尔巴尼亚", code: "+355" }, + { name: "阿尔及利亚", code: "+213" }, + { name: "安道尔", code: "+376" }, + { name: "安哥拉", code: "+244" }, + { name: "阿根廷", code: "+54" }, { name: "澳大利亚", code: "+61" }, - { name: "俄罗斯", code: "+7" }, - { name: "韩国", code: "+82" }, + { name: "奥地利", code: "+43" }, + { name: "巴哈马", code: "+1-242" }, + { name: "巴林", code: "+973" }, + { name: "孟加拉国", code: "+880" }, + { name: "巴巴多斯", code: "+1-246" }, + { name: "白俄罗斯", code: "+375" }, + { name: "比利时", code: "+32" }, + { name: "伯利兹", code: "+501" }, + { name: "贝宁", code: "+229" }, + { name: "不丹", code: "+975" }, + { name: "玻利维亚", code: "+591" }, + { name: "波黑", code: "+387" }, + { name: "博茨瓦纳", code: "+267" }, { name: "巴西", code: "+55" }, + { name: "文莱", code: "+673" }, + { name: "保加利亚", code: "+359" }, + { name: "柬埔寨", code: "+855" }, + { name: "喀麦隆", code: "+237" }, + { name: "加拿大", code: "+1" }, + { name: "智利", code: "+56" }, + { name: "中国", code: "+86" }, + { name: "哥伦比亚", code: "+57" }, + { name: "哥斯达黎加", code: "+506" }, + { name: "克罗地亚", code: "+385" }, + { name: "古巴", code: "+53" }, + { name: "塞浦路斯", code: "+357" }, + { name: "捷克", code: "+420" }, + { name: "丹麦", code: "+45" }, + { name: "埃及", code: "+20" }, + { name: "爱沙尼亚", code: "+372" }, + { name: "埃塞俄比亚", code: "+251" }, + { name: "芬兰", code: "+358" }, + { name: "法国", code: "+33" }, + { name: "德国", code: "+49" }, + { name: "希腊", code: "+30" }, + { name: "匈牙利", code: "+36" }, + { name: "冰岛", code: "+354" }, { name: "印度", code: "+91" }, + { name: "印度尼西亚", code: "+62" }, + { name: "伊朗", code: "+98" }, + { name: "伊拉克", code: "+964" }, + { name: "爱尔兰", code: "+353" }, + { name: "以色列", code: "+972" }, { name: "意大利", code: "+39" }, + { name: "日本", code: "+81" }, + { name: "约旦", code: "+962" }, + { name: "哈萨克斯坦", code: "+7" }, + { name: "肯尼亚", code: "+254" }, + { name: "科威特", code: "+965" }, + { name: "老挝", code: "+856" }, + { name: "拉脱维亚", code: "+371" }, + { name: "黎巴嫩", code: "+961" }, + { name: "利比亚", code: "+218" }, + { name: "立陶宛", code: "+370" }, + { name: "卢森堡", code: "+352" }, + { name: "马来西亚", code: "+60" }, + { name: "马尔代夫", code: "+960" }, + { name: "马耳他", code: "+356" }, + { name: "墨西哥", code: "+52" }, + { name: "摩纳哥", code: "+377" }, + { name: "蒙古", code: "+976" }, + { name: "摩洛哥", code: "+212" }, + { name: "缅甸", code: "+95" }, + { name: "尼泊尔", code: "+977" }, + { name: "荷兰", code: "+31" }, + { name: "新西兰", code: "+64" }, + { name: "尼日利亚", code: "+234" }, + { name: "朝鲜", code: "+850" }, + { name: "挪威", code: "+47" }, + { name: "巴基斯坦", code: "+92" }, + { name: "巴拿马", code: "+507" }, + { name: "秘鲁", code: "+51" }, + { name: "菲律宾", code: "+63" }, + { name: "波兰", code: "+48" }, + { name: "葡萄牙", code: "+351" }, + { name: "卡塔尔", code: "+974" }, + { name: "罗马尼亚", code: "+40" }, + { name: "俄罗斯", code: "+7" }, + { name: "沙特阿拉伯", code: "+966" }, + { name: "新加坡", code: "+65" }, + { name: "南非", code: "+27" }, + { name: "韩国", code: "+82" }, { name: "西班牙", code: "+34" }, - { name: "墨西哥", code: "+52" } + { name: "瑞典", code: "+46" }, + { name: "瑞士", code: "+41" }, + { name: "泰国", code: "+66" }, + { name: "土耳其", code: "+90" }, + { name: "阿联酋", code: "+971" }, + { name: "英国", code: "+44" }, + { name: "美国", code: "+1" }, + { name: "越南", code: "+84" } ]; \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js index 6d63bcd..dc2dd56 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -38,92 +38,117 @@ const formatTime = (value) => { const initAgent = () => { const listEl = document.querySelector('[data-contacts]'); const chatTitle = document.querySelector('[data-chat-title]'); + const chatMeta = document.querySelector('[data-chat-meta]'); const chatBody = document.querySelector('[data-chat-body]'); const form = document.querySelector('[data-chat-form]'); const input = document.querySelector('[data-chat-input]'); const emojiTrigger = document.querySelector('[data-emoji-trigger]'); const emojiPicker = document.querySelector('[data-emoji-picker]'); - const shortcutList = document.getElementById('shortcutList'); - const newShortcutInput = document.getElementById('newShortcut'); - const addShortcutBtn = document.getElementById('addShortcut'); const shortcutContainer = document.querySelector('[data-shortcuts]'); + const shortcutList = document.getElementById('shortcutList'); + const newShortcut = document.getElementById('newShortcut'); + const addShortcutBtn = document.getElementById('addShortcut'); let contacts = []; let activeId = null; - let shortcuts = JSON.parse(localStorage.getItem('shortcuts') || '["你好", "请问有什么可以帮您?", "谢谢"]'); + let shortcuts = JSON.parse(localStorage.getItem('sms_shortcuts') || '[]'); + + // Quick reply logic + const renderShortcuts = () => { + shortcutList.innerHTML = ''; + shortcutContainer.innerHTML = ''; + shortcuts.forEach((s, i) => { + const li = document.createElement('li'); + li.className = 'list-group-item d-flex justify-content-between'; + li.innerHTML = `${s}`; + shortcutList.appendChild(li); + + const btn = document.createElement('button'); + btn.className = 'btn btn-sm btn-outline-primary me-1 mb-1'; + btn.textContent = s; + btn.onclick = () => { input.value = s; }; + shortcutContainer.appendChild(btn); + }); + }; + + window.removeShortcut = (index) => { + shortcuts.splice(index, 1); + localStorage.setItem('sms_shortcuts', JSON.stringify(shortcuts)); + renderShortcuts(); + }; + + addShortcutBtn.onclick = () => { + const val = newShortcut.value.trim(); + if (!val) return; + shortcuts.push(val); + localStorage.setItem('sms_shortcuts', JSON.stringify(shortcuts)); + newShortcut.value = ''; + renderShortcuts(); + }; + renderShortcuts(); + + // Emoji picker + emojiTrigger.addEventListener("click", (e) => { + e.stopPropagation(); + emojiPicker.classList.toggle("d-none"); + }); + + emojiPicker.addEventListener("emoji-click", e => { + input.value += e.detail.unicode; + emojiPicker.classList.add('d-none'); + }); + + document.addEventListener('click', (e) => { + if (!emojiTrigger.contains(e.target) && !emojiPicker.contains(e.target)) { + emojiPicker.classList.add('d-none'); + } + }); // Country selector - const countryList = document.getElementById('countryList'); + const countryListEl = document.getElementById('countryList'); const countrySearch = document.getElementById('countrySearch'); const selectedCode = document.getElementById('selectedCode'); const phoneInput = document.getElementById('phoneNumber'); + const startChatBtn = document.getElementById('startChat'); - const renderCountryList = (filter = '') => { - countryList.innerHTML = ''; - countries.filter(c => c.name.includes(filter) || c.code.includes(filter)).forEach(c => { + const renderCountries = (filter = "") => { + countryListEl.innerHTML = ''; + countries.filter(c => c.name.includes(filter)).forEach(c => { const item = document.createElement('div'); item.className = 'country-item'; - item.textContent = `${c.name} (${c.code})`; + item.innerHTML = `${c.name} (${c.code})`; item.onclick = () => { selectedCode.textContent = c.code; - countrySearch.value = c.name; - renderCountryList(); + countrySearch.value = ""; + renderCountries(); }; - countryList.appendChild(item); + countryListEl.appendChild(item); }); }; + countrySearch.addEventListener('input', (e) => renderCountries(e.target.value)); + renderCountries(); - countrySearch.addEventListener('input', e => renderCountryList(e.target.value)); - renderCountryList(); - - document.getElementById('startChat').onclick = async () => { - const phone = selectedCode.textContent + phoneInput.value; - if (!phoneInput.value) return; - + startChatBtn.addEventListener('click', async () => { + const fullPhone = selectedCode.textContent + phoneInput.value; + if (!phoneInput.value) return showToast('请输入手机号', 'danger'); try { - // Send to API to create/get contact - const res = await apiFetch('/api/contacts.php', { method: 'POST', body: { phone } }); - const newContact = res.contact; - contacts.unshift(newContact); - renderContacts(); - setActive(newContact.id); + const res = await apiFetch('/api/contacts.php', { method: 'POST', body: { phone: fullPhone } }); bootstrap.Modal.getInstance(document.getElementById('countryModal')).hide(); - } catch (err) { - showToast('无法启动聊天', 'danger'); - } - }; - - const renderShortcuts = () => { - shortcutContainer.innerHTML = shortcuts.map(s => - `` - ).join(''); - - shortcutList.innerHTML = shortcuts.map((s, i) => ` -