Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 51c76ebd24 | |||
| facf39e778 | |||
| 51cecf1f4e |
@@ -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>
|
||||
@@ -1362,9 +1363,15 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
});
|
||||
|
||||
// 侧边栏过滤
|
||||
document.querySelectorAll('.sidebar a').forEach(a => {
|
||||
document.querySelectorAll('.sidebar a[data-filter]').forEach(a => {
|
||||
a.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
// 如果在回收站视图,先退出
|
||||
if (trashView) {
|
||||
trashView = false;
|
||||
}
|
||||
|
||||
document.querySelectorAll('.sidebar a').forEach(x => x.classList.remove('active'));
|
||||
a.classList.add('active');
|
||||
|
||||
@@ -1525,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;
|
||||
@@ -1549,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 });
|
||||
}
|
||||
|
||||
// 添加条目
|
||||
@@ -1579,6 +1720,8 @@ async function addItem() {
|
||||
if (res.ok) {
|
||||
bootstrap.Modal.getInstance(document.getElementById('addModal')).hide();
|
||||
document.getElementById('addForm').reset();
|
||||
clearDraft(); // 成功添加后清除草稿
|
||||
stopAutoSave(); // 停止自动保存
|
||||
refreshData();
|
||||
}
|
||||
}
|
||||
@@ -2334,13 +2477,17 @@ async function loadTrash() {
|
||||
|
||||
function renderTrash(items, total) {
|
||||
const container = document.getElementById('itemList');
|
||||
const paginationContainer = document.getElementById('pagination');
|
||||
|
||||
// 清空分页
|
||||
paginationContainer.innerHTML = '';
|
||||
|
||||
// 显示回收站标题和操作按钮
|
||||
let header = `
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<h5><i class="bi bi-trash"></i> 回收站 (${total} 条数据)</h5>
|
||||
<small class="text-muted">删除的数据可在30天内恢复</small>
|
||||
<small class="text-muted">回收站数据可随时恢复或彻底删除</small>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-outline-secondary" onclick="hideTrash()">
|
||||
|
||||
Reference in New Issue
Block a user