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();
}
}