const API_BASE = ''; // 状态 let currentRecordId = null; let lastRecordTime = 0; let longPressTimer = null; let isLongPress = false; const LONG_PRESS_DURATION = 500; // 长按触发时间 // DOM 元素 const triggerArea = document.getElementById('trigger-area'); const dinBtn = document.getElementById('din-btn'); const inputOverlay = document.getElementById('input-overlay'); const quickInput = document.getElementById('quick-input'); const toast = document.getElementById('toast'); const achievementToast = document.getElementById('achievement-toast'); // ========== 核心交互:超快记录 ========== // 点击/触摸开始 dinBtn.addEventListener('touchstart', handleStart, { passive: false }); dinBtn.addEventListener('mousedown', handleStart); // 点击/触摸结束 dinBtn.addEventListener('touchend', handleEnd, { passive: false }); dinBtn.addEventListener('mouseup', handleEnd); dinBtn.addEventListener('mouseleave', cancelLongPress); // 防止双击缩放 dinBtn.addEventListener('touchmove', (e) => e.preventDefault(), { passive: false }); function handleStart(e) { e.preventDefault(); isLongPress = false; // 视觉反馈 dinBtn.classList.add('recording'); // 启动长按计时器 longPressTimer = setTimeout(() => { isLongPress = true; dinBtn.classList.remove('recording'); // 长按直接进入输入模式 createRecord(true); }, LONG_PRESS_DURATION); } function handleEnd(e) { e.preventDefault(); clearTimeout(longPressTimer); dinBtn.classList.remove('recording'); // 如果不是长按,直接记录 if (!isLongPress) { createRecord(false); } } function cancelLongPress() { clearTimeout(longPressTimer); dinBtn.classList.remove('recording'); } // ========== 记录逻辑 ========== async function createRecord(showInput = false) { // 防抖:1秒内不能重复点击 const now = Date.now(); if (now - lastRecordTime < 1000) return; lastRecordTime = now; try { // 立即显示反馈(不等待网络) showToast('已记录!'); // 后台发送请求 const res = await fetch(`${API_BASE}/api/din`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: '' }) }); const data = await res.json(); currentRecordId = data.id; // 更新统计和列表 updateStats(); prependToList(data); // 检查成就 checkNewAchievements(); // 如果需要输入,显示输入面板 if (showInput) { showInputPanel(data.created_at); } } catch (err) { console.error('记录失败:', err); showToast('记录失败', false); } } // ========== 输入面板 ========== function showInputPanel(timestamp) { document.getElementById('input-timestamp').textContent = formatTimeOnly(timestamp); inputOverlay.classList.add('active'); quickInput.value = ''; setTimeout(() => quickInput.focus(), 100); } function hideInputPanel() { inputOverlay.classList.remove('active'); quickInput.blur(); } // 保存按钮 document.getElementById('btn-save').addEventListener('click', async () => { if (!currentRecordId) return; const content = quickInput.value.trim(); if (!content) { hideInputPanel(); return; } try { await fetch(`${API_BASE}/api/din/${currentRecordId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content }) }); // 更新列表中的内容 updateListItem(currentRecordId, content); hideInputPanel(); showToast('已保存'); } catch (err) { showToast('保存失败', false); } }); // 跳过按钮 document.getElementById('btn-skip').addEventListener('click', () => { hideInputPanel(); }); // 点击遮罩关闭 inputOverlay.addEventListener('click', (e) => { if (e.target === inputOverlay) { hideInputPanel(); } }); // 回车保存 quickInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { document.getElementById('btn-save').click(); } }); // 快速标签 document.querySelectorAll('.tag').forEach(tag => { tag.addEventListener('click', () => { const text = tag.dataset.text; quickInput.value = text; document.getElementById('btn-save').click(); }); }); // ========== 数据更新 ========== async function updateStats() { try { const res = await fetch(`${API_BASE}/api/stats`); const stats = await res.json(); document.getElementById('stat-today').textContent = stats.today; document.getElementById('stat-week').textContent = stats.week; document.getElementById('stat-total').textContent = stats.total; document.getElementById('recent-count').textContent = stats.total; } catch (err) { console.error('更新统计失败:', err); } } function prependToList(record) { const list = document.getElementById('recent-list'); const emptyMsg = list.querySelector('.recent-item .empty'); if (emptyMsg) { list.innerHTML = ''; } const item = document.createElement('div'); item.className = 'recent-item'; item.dataset.id = record.id; item.innerHTML = ` ${formatTimeOnly(record.created_at)} (未备注) `; list.insertBefore(item, list.firstChild); // 保持最多10条 while (list.children.length > 10) { list.removeChild(list.lastChild); } } function updateListItem(id, content) { const item = document.querySelector(`.recent-item[data-id="${id}"]`); if (item) { const contentEl = item.querySelector('.recent-content'); contentEl.textContent = content; contentEl.classList.remove('empty'); } } // ========== 成就检查 ========== let lastAchievementCount = 0; async function checkNewAchievements() { try { const res = await fetch(`${API_BASE}/api/achievements`); const data = await res.json(); if (data.unlocked_count > lastAchievementCount) { // 有新成就解锁 const newAchievements = data.achievements.filter(a => a.unlocked).slice(-1); if (newAchievements.length > 0) { showAchievementToast(newAchievements[0]); } } lastAchievementCount = data.unlocked_count; } catch (err) { console.error('检查成就失败:', err); } } function showAchievementToast(achievement) { const icon = achievementToast.querySelector('.achievement-icon'); const text = document.getElementById('achievement-text'); icon.textContent = achievement.icon; text.textContent = `解锁:${achievement.name}`; achievementToast.classList.add('show'); setTimeout(() => { achievementToast.classList.remove('show'); }, 3000); } // ========== 辅助函数 ========== function showToast(message, success = true) { toast.textContent = message; toast.style.background = success ? '#ff4757' : '#ff6b6b'; toast.classList.add('show'); setTimeout(() => { toast.classList.remove('show'); }, 1500); } function formatTimeOnly(isoString) { const date = new Date(isoString); const hours = date.getHours().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0'); return `${hours}:${minutes}`; } // ========== 初始化 ========== async function init() { await updateStats(); await loadRecent(); await checkNewAchievements(); } async function loadRecent() { try { const res = await fetch(`${API_BASE}/api/din?limit=10`); const records = await res.json(); const list = document.getElementById('recent-list'); document.getElementById('recent-count').textContent = records.length; if (records.length === 0) { list.innerHTML = '
点击大按钮开始记录
'; return; } list.innerHTML = records.map(r => `
${formatTimeOnly(r.created_at)} ${r.content || '(未备注)'}
`).join(''); } catch (err) { console.error('加载记录失败:', err); } } // ========== 历史记录面板 ========== const historyOverlay = document.getElementById('history-overlay'); const historyList = document.getElementById('history-list'); // 打开历史面板 document.getElementById('view-all').addEventListener('click', () => { historyOverlay.classList.add('active'); loadHistory(); }); // 关闭历史面板 document.getElementById('close-history').addEventListener('click', () => { historyOverlay.classList.remove('active'); }); // 点击遮罩关闭 historyOverlay.addEventListener('click', (e) => { if (e.target === historyOverlay) { historyOverlay.classList.remove('active'); } }); async function loadHistory() { try { const res = await fetch(`${API_BASE}/api/din?limit=100`); const records = await res.json(); if (records.length === 0) { historyList.innerHTML = '
暂无记录
'; return; } // 按日期分组 const grouped = groupByDate(records); historyList.innerHTML = Object.entries(grouped).map(([date, items]) => `
${date}
${items.map(r => `
${formatTimeOnly(r.created_at)} ${r.content || '(未备注)'}
`).join('')}
`).join(''); } catch (err) { console.error('加载历史失败:', err); showToast('加载失败', false); } } function groupByDate(records) { const groups = {}; records.forEach(r => { const date = new Date(r.created_at); const key = `${date.getMonth() + 1}月${date.getDate()}日`; if (!groups[key]) groups[key] = []; groups[key].push(r); }); return groups; } // 编辑历史记录 window.editHistoryItem = async function(id, currentContent) { const newContent = prompt('修改备注:', currentContent); if (newContent === null) return; try { await fetch(`${API_BASE}/api/din/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: newContent.trim() }) }); showToast('已更新'); loadHistory(); // 刷新历史列表 loadRecent(); // 刷新最近列表 } catch (err) { showToast('更新失败', false); } }; // 删除历史记录 window.deleteHistoryItem = async function(id) { if (!confirm('确定删除这条记录?')) return; try { await fetch(`${API_BASE}/api/din/${id}`, { method: 'DELETE' }); showToast('已删除'); loadHistory(); // 刷新历史列表 loadRecent(); // 刷新最近列表 updateStats(); // 刷新统计 } catch (err) { showToast('删除失败', false); } }; function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML.replace(/'/g, "'").replace(/"/g, """); } // 启动 init();