feat: 重构草稿箱功能
- 数据库添加 drafts 表存储草稿数据 - 草稿箱独立页面,侧边栏添加入口 - 自动保存间隔可配置(2/5/10/30/60秒) - 草稿可编辑、发布为正式条目、删除 - 编辑时自动保存到服务器数据库
This commit is contained in:
123
xian_favor/db.py
123
xian_favor/db.py
@@ -99,6 +99,26 @@ class Database:
|
||||
)
|
||||
""")
|
||||
|
||||
# 草稿表
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS drafts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
type TEXT NOT NULL DEFAULT 'text',
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
url TEXT,
|
||||
source TEXT,
|
||||
status TEXT DEFAULT 'pending',
|
||||
priority TEXT DEFAULT 'medium',
|
||||
due_date TEXT,
|
||||
note TEXT,
|
||||
tags TEXT,
|
||||
is_starred INTEGER DEFAULT 0,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
|
||||
# 邮件发送记录表
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS email_logs (
|
||||
@@ -444,6 +464,109 @@ class Database:
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
|
||||
# ============ Draft 草稿操作 ============
|
||||
|
||||
def save_draft(self, type: str = "text", title: str = None, content: str = None,
|
||||
url: str = None, source: str = None, status: str = "pending",
|
||||
priority: str = "medium", due_date: str = None, note: str = None,
|
||||
tags: str = None, is_starred: bool = False) -> int:
|
||||
"""保存草稿"""
|
||||
self._ensure_init()
|
||||
now = datetime.now().isoformat()
|
||||
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
INSERT INTO drafts (type, title, content, url, source, status, priority, due_date, note, tags, is_starred, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (type, title, content, url, source, status, priority, due_date, note, tags, 1 if is_starred else 0, now, now))
|
||||
draft_id = cursor.lastrowid
|
||||
conn.commit()
|
||||
return draft_id
|
||||
|
||||
def update_draft(self, draft_id: int, **kwargs) -> bool:
|
||||
"""更新草稿"""
|
||||
allowed_fields = ['type', 'title', 'content', 'url', 'source', 'status', 'priority', 'due_date', 'note', 'tags', 'is_starred']
|
||||
update_fields = {k: v for k, v in kwargs.items() if k in allowed_fields}
|
||||
|
||||
if not update_fields:
|
||||
return False
|
||||
|
||||
now = datetime.now().isoformat()
|
||||
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT id FROM drafts WHERE id = ?", (draft_id,))
|
||||
if not cursor.fetchone():
|
||||
return False
|
||||
|
||||
set_clause = ", ".join(f"{k} = ?" for k in update_fields.keys())
|
||||
set_clause += ", updated_at = ?"
|
||||
values = list(update_fields.values()) + [now, draft_id]
|
||||
cursor.execute(f"UPDATE drafts SET {set_clause} WHERE id = ?", values)
|
||||
conn.commit()
|
||||
return True
|
||||
|
||||
def list_drafts(self, limit: int = 50, offset: int = 0) -> List[Dict[str, Any]]:
|
||||
"""列出草稿"""
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM drafts ORDER BY updated_at DESC LIMIT ? OFFSET ?", (limit, offset))
|
||||
return [dict(row) for row in cursor.fetchall()]
|
||||
|
||||
def count_drafts(self) -> int:
|
||||
"""计算草稿总数"""
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT COUNT(*) as count FROM drafts")
|
||||
return cursor.fetchone()['count']
|
||||
|
||||
def get_draft(self, draft_id: int) -> Optional[Dict[str, Any]]:
|
||||
"""获取单个草稿"""
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM drafts WHERE id = ?", (draft_id,))
|
||||
row = cursor.fetchone()
|
||||
return dict(row) if row else None
|
||||
|
||||
def delete_draft(self, draft_id: int) -> bool:
|
||||
"""删除草稿"""
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("DELETE FROM drafts WHERE id = ?", (draft_id,))
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
|
||||
def draft_to_item(self, draft_id: int) -> Optional[int]:
|
||||
"""将草稿转为正式条目"""
|
||||
draft = self.get_draft(draft_id)
|
||||
if not draft:
|
||||
return None
|
||||
|
||||
# 创建条目
|
||||
tags_list = draft['tags'].split(',') if draft['tags'] else []
|
||||
tags_list = [t.strip() for t in tags_list if t.strip()]
|
||||
|
||||
item_id = self.create_item(
|
||||
type=draft['type'],
|
||||
title=draft['title'],
|
||||
content=draft['content'],
|
||||
url=draft['url'],
|
||||
source=draft['source'],
|
||||
status=draft['status'],
|
||||
priority=draft['priority'],
|
||||
due_date=draft['due_date'],
|
||||
note=draft['note'],
|
||||
tags=tags_list,
|
||||
is_starred=draft['is_starred']
|
||||
)
|
||||
|
||||
# 删除草稿
|
||||
if item_id:
|
||||
self.delete_draft(draft_id)
|
||||
|
||||
return item_id
|
||||
|
||||
# ============ Tag 操作 ============
|
||||
|
||||
def create_tag(self, name: str, color: str = "#3498db") -> int:
|
||||
|
||||
Reference in New Issue
Block a user