From 51c76ebd24f0c6c66bfb5fff8a4160249c3e49fa Mon Sep 17 00:00:00 2001 From: hubian <908234780@qq.com> Date: Sun, 19 Apr 2026 17:31:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E8=8D=89=E7=A8=BF?= =?UTF-8?q?=E7=AE=B1=E8=87=AA=E5=8A=A8=E4=BF=9D=E5=AD=98=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 编辑时自动保存到 localStorage(每5秒或输入后2秒) - 打开添加弹框时检查是否有草稿并提示恢复 - 成功添加后清除草稿 - 弹框标题显示“已自动保存”指示器 --- xian_favor/api.py | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/xian_favor/api.py b/xian_favor/api.py index 11769ca..af631c8 100644 --- a/xian_favor/api.py +++ b/xian_favor/api.py @@ -848,6 +848,7 @@ INDEX_TEMPLATE = ''' @@ -1531,6 +1532,129 @@ function changeSort() { // ============ 添加功能 ============ // 快捷添加按钮 +// ============ 草稿箱 ============ + +const DRAFT_KEY = 'xian_favor_draft'; +let draftTimer = null; + +// 保存草稿到 localStorage +function saveDraft() { + const type = document.getElementById('addType')?.value || 'text'; + const draft = { + type, + title: document.getElementById('addTitle')?.value || '', + content: document.getElementById('addContent')?.value || '', + url: document.getElementById('addUrl')?.value || '', + source: document.getElementById('addSource')?.value || '', + status: document.getElementById('addStatus')?.value || 'pending', + priority: document.getElementById('addPriority')?.value || 'medium', + due_date: document.getElementById('addDueDate')?.value || '', + note: document.getElementById('addNote')?.value || '', + tags: document.getElementById('addTags')?.value || '', + is_starred: document.getElementById('addStarred')?.checked || false, + saved_at: new Date().toISOString() + }; + + // 只在有内容时保存 + if (draft.title || draft.content || draft.url || draft.note) { + localStorage.setItem(DRAFT_KEY, JSON.stringify(draft)); + showDraftIndicator(); + } +} + +// 加载草稿 +function loadDraft() { + const draft = localStorage.getItem(DRAFT_KEY); + if (!draft) return null; + return JSON.parse(draft); +} + +// 清除草稿 +function clearDraft() { + localStorage.removeItem(DRAFT_KEY); + hideDraftIndicator(); +} + +// 显示草稿指示器 +function showDraftIndicator() { + const indicator = document.getElementById('draftIndicator'); + if (indicator) indicator.style.display = 'inline'; +} + +// 隐藏草稿指示器 +function hideDraftIndicator() { + const indicator = document.getElementById('draftIndicator'); + if (indicator) indicator.style.display = 'none'; +} + +// 检查是否有草稿并提示恢复 +function checkAndRestoreDraft(type) { + const draft = loadDraft(); + if (!draft) return false; + + // 草稿类型匹配才提示 + if (draft.type === type && (draft.title || draft.content || draft.url || draft.note)) { + const savedTime = new Date(draft.saved_at).toLocaleString('zh-CN'); + if (confirm(`发现未保存的草稿(${savedTime}),是否恢复?`)) { + restoreDraftToForm(draft); + return true; + } else { + clearDraft(); // 用户选择不恢复,清除草稿 + } + } + return false; +} + +// 将草稿恢复到表单 +function restoreDraftToForm(draft) { + document.getElementById('addTitle').value = draft.title || ''; + if (draft.type === 'text') { + document.getElementById('addContent').value = draft.content || ''; + } + if (['link', 'column'].includes(draft.type)) { + document.getElementById('addUrl').value = draft.url || ''; + } + if (draft.type === 'column') { + document.getElementById('addSource').value = draft.source || ''; + } + if (draft.type === 'todo') { + document.getElementById('addStatus').value = draft.status || 'pending'; + document.getElementById('addPriority').value = draft.priority || 'medium'; + document.getElementById('addDueDate').value = draft.due_date || ''; + } + document.getElementById('addNote').value = draft.note || ''; + document.getElementById('addTags').value = draft.tags || ''; + document.getElementById('addStarred').checked = draft.is_starred || false; + showDraftIndicator(); +} + +// 启动自动保存 +function startAutoSave() { + // 每5秒自动保存一次 + draftTimer = setInterval(saveDraft, 5000); + + // 监听输入事件立即保存(带延迟) + const form = document.getElementById('addForm'); + if (form) { + form.addEventListener('input', () => { + clearTimeout(draftTimer); + draftTimer = setTimeout(saveDraft, 2000); // 输入后2秒保存 + // 重新启动定时保存 + clearInterval(draftTimer); + draftTimer = setInterval(saveDraft, 5000); + }); + } +} + +// 停止自动保存 +function stopAutoSave() { + if (draftTimer) { + clearInterval(draftTimer); + clearTimeout(draftTimer); + draftTimer = null; + } +} + function showAddModal(type) { // 设置类型 document.getElementById('addType').value = type; @@ -1555,8 +1679,19 @@ function showAddModal(type) { // 清空表单 document.getElementById('addForm').reset(); + // 检查是否有草稿 + const restored = checkAndRestoreDraft(type); + // 打开弹窗 new bootstrap.Modal(document.getElementById('addModal')).show(); + + // 启动自动保存 + startAutoSave(); + + // 弹框关闭时停止自动保存 + document.getElementById('addModal').addEventListener('hidden.bs.modal', () => { + stopAutoSave(); + }, { once: true }); } // 添加条目 @@ -1585,6 +1720,8 @@ async function addItem() { if (res.ok) { bootstrap.Modal.getInstance(document.getElementById('addModal')).hide(); document.getElementById('addForm').reset(); + clearDraft(); // 成功添加后清除草稿 + stopAutoSave(); // 停止自动保存 refreshData(); } }