Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6490ceff08 | |||
| e13fa0e337 | |||
| 3eae1595aa | |||
| 6f0905d83a | |||
| 033b7509d7 | |||
| 8f9a8d2ad5 | |||
| ffe7adcad2 | |||
| 963dd1846b | |||
| ad6d369069 | |||
| 68411813b3 | |||
| d8780b9000 | |||
| 196bfaf213 | |||
| 2675edb695 | |||
| 1f9d0a7ea2 |
21
README.md
21
README.md
@@ -96,6 +96,11 @@ API端点:
|
||||
| `/api/tags` | GET | 列出标签 |
|
||||
| `/api/tags` | POST | 创建标签 |
|
||||
| `/api/tags/<id>` | DELETE | 删除标签 |
|
||||
| `/api/emails` | GET | 列出邮箱 |
|
||||
| `/api/emails` | POST | 创建邮箱 |
|
||||
| `/api/emails/<id>` | PUT | 更新邮箱 |
|
||||
| `/api/emails/<id>` | DELETE | 删除邮箱 |
|
||||
| `/api/send-email` | POST | 发送收藏到邮箱 |
|
||||
| `/api/stats` | GET | 统计信息 |
|
||||
| `/api/search` | GET | 搜索 (参数 q=关键词) |
|
||||
|
||||
@@ -136,6 +141,22 @@ xian-favor/
|
||||
|
||||
## 版本历史
|
||||
|
||||
- v1.9.0 (2026-04-14): 发送邮件功能 + 邮箱管理
|
||||
- 每个收藏卡片添加"发送邮件"按钮
|
||||
- 选择已有邮箱或输入新邮箱发送
|
||||
- 新邮箱自动保存到邮箱管理
|
||||
- 邮箱管理页面:添加、编辑、删除邮箱
|
||||
- SMTP配置支持环境变量(SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS)
|
||||
- v1.8.0 (2026-04-13): AI自动添加功能,智能识别文本类型并整理数据
|
||||
- 首页新增"AI添加"按钮
|
||||
- 粘贴文本/链接/笔记等,AI自动识别类型并提取关键信息
|
||||
- 支持文本、链接、专栏、待办四种类型自动识别
|
||||
- 自动生成标签和标题
|
||||
- v1.7.0 (2026-04-13): 编辑收藏时支持更改类型,动态显示对应字段
|
||||
- v1.6.0 (2026-04-13): 标签管理添加编辑功能,支持修改标签名称
|
||||
- v1.5.1 (2026-04-13): 标签管理添加搜索功能,实时过滤标签列表
|
||||
- v1.5.0 (2026-04-13): 首页添加分页功能,每页20条记录
|
||||
- v1.4.0 (2026-04-13): 首页添加导出按钮,一键导出所有收藏为JSON文件
|
||||
- v1.3.2 (2026-04-13): 编辑和添加模态框改为大尺寸(modal-lg)
|
||||
- v1.3.1 (2026-04-13): 备注改名为详情,支持换行显示,扩大输入框
|
||||
- v1.3.0 (2026-04-13): 标签管理功能和输入自动提示
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -80,6 +80,16 @@ class Database:
|
||||
)
|
||||
""")
|
||||
|
||||
# 邮箱表
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS emails (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
name TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
|
||||
# 创建索引
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_items_type ON items(type)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_items_status ON items(status)")
|
||||
@@ -244,6 +254,18 @@ class Database:
|
||||
""")
|
||||
return [dict(row) for row in cursor.fetchall()]
|
||||
|
||||
def update_tag(self, tag_id: int, name: str) -> bool:
|
||||
"""更新标签名称"""
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
# 检查名称是否已存在(排除自己)
|
||||
cursor.execute("SELECT id FROM tags WHERE name = ? AND id != ?", (name, tag_id))
|
||||
if cursor.fetchone():
|
||||
return False # 名称已存在
|
||||
cursor.execute("UPDATE tags SET name = ? WHERE id = ?", (name, tag_id))
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
|
||||
def delete_tag(self, tag_id: int = None, name: str = None) -> bool:
|
||||
"""删除标签"""
|
||||
with self.get_conn() as conn:
|
||||
@@ -290,6 +312,65 @@ class Database:
|
||||
""", (item_id,))
|
||||
return [row['name'] for row in cursor.fetchall()]
|
||||
|
||||
# ============ Email 操作 ============
|
||||
|
||||
def create_email(self, email: str, name: str = None) -> int:
|
||||
"""创建邮箱"""
|
||||
now = datetime.now().isoformat()
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
try:
|
||||
cursor.execute("INSERT INTO emails (email, name, created_at) VALUES (?, ?, ?)",
|
||||
(email, name, now))
|
||||
conn.commit()
|
||||
return cursor.lastrowid
|
||||
except sqlite3.IntegrityError:
|
||||
# 邮箱已存在,返回已有ID
|
||||
cursor.execute("SELECT id FROM emails WHERE email = ?", (email,))
|
||||
return cursor.fetchone()['id']
|
||||
|
||||
def list_emails(self) -> List[Dict[str, Any]]:
|
||||
"""列出所有邮箱"""
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM emails ORDER BY created_at DESC")
|
||||
return [dict(row) for row in cursor.fetchall()]
|
||||
|
||||
def get_email(self, email_id: int) -> Optional[Dict[str, Any]]:
|
||||
"""获取单个邮箱"""
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM emails WHERE id = ?", (email_id,))
|
||||
row = cursor.fetchone()
|
||||
return dict(row) if row else None
|
||||
|
||||
def update_email(self, email_id: int, email: str = None, name: str = None) -> bool:
|
||||
"""更新邮箱"""
|
||||
now = datetime.now().isoformat()
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
if email:
|
||||
# 检查邮箱是否已存在(排除自己)
|
||||
cursor.execute("SELECT id FROM emails WHERE email = ? AND id != ?", (email, email_id))
|
||||
if cursor.fetchone():
|
||||
return False # 邎箱已存在
|
||||
if email and name:
|
||||
cursor.execute("UPDATE emails SET email = ?, name = ? WHERE id = ?", (email, name, email_id))
|
||||
elif email:
|
||||
cursor.execute("UPDATE emails SET email = ? WHERE id = ?", (email, email_id))
|
||||
elif name:
|
||||
cursor.execute("UPDATE emails SET name = ? WHERE id = ?", (name, email_id))
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
|
||||
def delete_email(self, email_id: int) -> bool:
|
||||
"""删除邮箱"""
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("DELETE FROM emails WHERE id = ?", (email_id,))
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
|
||||
def stats(self) -> Dict[str, Any]:
|
||||
"""获取统计信息"""
|
||||
self._ensure_init()
|
||||
|
||||
Reference in New Issue
Block a user