feat: 新增草稿箱自动保存功能

- 编辑时自动保存到 localStorage(每5秒或输入后2秒)
- 打开添加弹框时检查是否有草稿并提示恢复
- 成功添加后清除草稿
- 弹框标题显示“已自动保存”指示器
This commit is contained in:
2026-04-19 17:31:08 +08:00
parent facf39e778
commit 51c76ebd24

View File

@@ -848,6 +848,7 @@ INDEX_TEMPLATE = '''
<h5 class="modal-title">
<span id="addModalIcon"></span>
<span id="addModalTitle">添加条目</span>
<span id="draftIndicator" class="badge bg-secondary ms-2" style="display:none;">已自动保存</span>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
@@ -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();
}
}