Compare commits

...

17 Commits

Author SHA1 Message Date
d7b4b48cc7 feat: 详情弹框内容添加Markdown显示开关 2026-04-24 12:58:09 +08:00
3f5284e067 feat: 统计卡片改一行显示+列表上方增加翻页 2026-04-24 12:24:54 +08:00
50d2e62694 feat: 添加置顶功能,置顶优先级最高 2026-04-24 12:16:39 +08:00
70dee494f3 fix: 点击未读数据后更新未读状态和类别计数 2026-04-22 23:49:49 +08:00
4b2a94002b feat: 添加未读提醒功能
- 数据列表中未读数据(views=0)显示特殊样式(黄色背景+红色边框+红点标记)
- 左侧类别显示未读数量(红色badge)
- API返回unread和unread_by_type统计数据
2026-04-22 23:44:22 +08:00
9eb872391e fix: 修复alert字符串中\n导致的JS语法错误 2026-04-22 23:33:32 +08:00
784830bd62 fix: 修复systemConfig变量定义顺序导致的JS错误 2026-04-22 23:24:08 +08:00
252bda696f feat: 添加系统配置功能
- AI自动添加的大模型接口配置(URL/Key/Model)
- 服务器连接状态刷新频率配置
- 数据列表每页显示条数配置
- 草稿自动保存间隔配置
- 显示统计/阅读次数开关
- 配置保存到localStorage
2026-04-22 23:09:39 +08:00
ef822d0eba feat: 编辑和新增弹框优化 - 导航按钮、固定底部、拖拽缩放、大尺寸 2026-04-22 22:47:59 +08:00
cc54fd52c6 feat: 导航按钮移到底部操作栏左侧 2026-04-22 22:00:22 +08:00
e4115b8baa fix: 详情弹框默认宽度改为800px 2026-04-22 21:56:32 +08:00
b99e3e88c9 fix: 详情弹框默认宽度改为600px,可拖拽放大到95vw 2026-04-22 21:53:38 +08:00
35198a8edb feat: 详情弹框添加JavaScript拖拽缩放功能 2026-04-22 18:52:26 +08:00
c9142c3f8a feat: 详情弹框尺寸优化 - 更宽、占满屏幕、支持拖拽缩放 2026-04-22 18:46:07 +08:00
9797ddf3f7 fix: 导航按钮改为absolute定位,显示在内容区域右上角 2026-04-22 18:40:56 +08:00
b92239fb1b feat(v4.4.0): 详情弹框添加导航按钮和固定底部操作栏
- 右侧固定显示向上/向下导航按钮
- 底部操作栏(转为待办、编辑、关闭)固定悬浮
2026-04-22 18:35:20 +08:00
105f4d5492 feat(v4.3.0): 新增/编辑弹框中添加文件夹选择
- 新增数据时可选择所属文件夹
- 编辑数据时可更改所属文件夹
- 切换类型时自动更新文件夹列表
2026-04-22 18:08:41 +08:00
2 changed files with 769 additions and 77 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -187,6 +187,15 @@ class Database:
cursor.execute("CREATE INDEX IF NOT EXISTS idx_folders_type ON folders(type)")
cursor.execute("CREATE INDEX IF NOT EXISTS idx_folders_parent ON folders(parent_id)")
# 检查并添加 is_pinned 字段(置顶功能,兼容旧数据库)
try:
cursor.execute("SELECT is_pinned FROM items LIMIT 1")
except sqlite3.OperationalError:
cursor.execute("ALTER TABLE items ADD COLUMN is_pinned INTEGER DEFAULT 0")
# 创建 is_pinned 索引
cursor.execute("CREATE INDEX IF NOT EXISTS idx_items_pinned ON items(is_pinned)")
# 待办事务表关联到文本类别的items
cursor.execute("""
CREATE TABLE IF NOT EXISTS todo_events (
@@ -305,18 +314,16 @@ class Database:
if conditions:
query += " WHERE " + " AND ".join(conditions)
# 排序逻辑
# 排序逻辑:置顶 > 关注 > 创建时间
if sort_by == 'updated_at':
order_field = 'i.updated_at'
elif sort_by == 'created_at':
order_field = 'i.created_at'
else:
# 默认:重点关注优先 + 创建时间降序
# 默认:置顶优先 + 关注优先 + 创建时间降序
order_field = 'i.created_at'
order_dir = 'DESC' if (sort_order == 'asc' or sort_order is None) else 'ASC'
# 这里反转逻辑:用户选择"降序"时用DESC选择"升序"时用ASC
# 确定排序方向
if sort_order == 'asc':
order_dir = 'ASC'
elif sort_order == 'desc':
@@ -324,12 +331,12 @@ class Database:
else:
order_dir = 'DESC' # 默认降序
# 如果有指定排序字段,按该字段排序;否则默认重点关注优先
# 如果有指定排序字段,按该字段排序,但置顶始终优先
if sort_by:
query += f" ORDER BY {order_field} {order_dir} LIMIT ? OFFSET ?"
query += f" ORDER BY i.is_pinned DESC, {order_field} {order_dir} LIMIT ? OFFSET ?"
else:
# 默认:重点关注优先,然后创建时间降序
query += f" ORDER BY i.is_starred DESC, i.created_at DESC LIMIT ? OFFSET ?"
# 默认:置顶 > 关注 > 创建时间降序
query += f" ORDER BY i.is_pinned DESC, i.is_starred DESC, i.created_at DESC LIMIT ? OFFSET ?"
params.extend([limit, offset])
cursor.execute(query, params)
@@ -391,7 +398,7 @@ class Database:
def update_item(self, item_id: int, **kwargs) -> bool:
"""更新条目"""
allowed_fields = ['type', 'title', 'content', 'url', 'source', 'status', 'priority', 'due_date', 'note', 'is_starred']
allowed_fields = ['type', 'title', 'content', 'url', 'source', 'status', 'priority', 'due_date', 'note', 'is_starred', 'folder_id']
update_fields = {k: v for k, v in kwargs.items() if k in allowed_fields}
# 只有 tags 变化也算有效更新
@@ -517,6 +524,31 @@ class Database:
conn.commit()
return cursor.rowcount > 0
def toggle_pin(self, item_id: int) -> bool:
"""切换置顶状态"""
with self.get_conn() as conn:
cursor = conn.cursor()
# 先获取当前状态
cursor.execute("SELECT is_pinned FROM items WHERE id = ?", (item_id,))
row = cursor.fetchone()
if not row:
return False
new_status = 0 if row['is_pinned'] else 1
now = datetime.now().isoformat()
cursor.execute("UPDATE items SET is_pinned = ?, updated_at = ? WHERE id = ?", (new_status, now, item_id))
conn.commit()
return True
def set_pin(self, item_id: int, pinned: bool = True) -> bool:
"""设置置顶状态"""
with self.get_conn() as conn:
cursor = conn.cursor()
now = datetime.now().isoformat()
cursor.execute("UPDATE items SET is_pinned = ?, updated_at = ? WHERE id = ?", (1 if pinned else 0, now, item_id))
conn.commit()
return cursor.rowcount > 0
def increment_views(self, item_id: int) -> bool:
"""增加阅读数"""
with self.get_conn() as conn:
@@ -919,15 +951,23 @@ class Database:
stats = {}
# 总数
cursor.execute("SELECT COUNT(*) as count FROM items")
cursor.execute("SELECT COUNT(*) as count FROM items WHERE is_deleted = 0")
stats['total'] = cursor.fetchone()['count']
# 按类型统计
cursor.execute("SELECT type, COUNT(*) as count FROM items GROUP BY type")
cursor.execute("SELECT type, COUNT(*) as count FROM items WHERE is_deleted = 0 GROUP BY type")
stats['by_type'] = {row['type']: row['count'] for row in cursor.fetchall()}
# 未读数量统计views = 0
cursor.execute("SELECT COUNT(*) as count FROM items WHERE is_deleted = 0 AND (views IS NULL OR views = 0)")
stats['unread'] = cursor.fetchone()['count']
# 按类型统计未读数量
cursor.execute("SELECT type, COUNT(*) as count FROM items WHERE is_deleted = 0 AND (views IS NULL OR views = 0) GROUP BY type")
stats['unread_by_type'] = {row['type']: row['count'] for row in cursor.fetchall()}
# 待办状态统计
cursor.execute("SELECT status, COUNT(*) as count FROM items WHERE type = 'todo' GROUP BY status")
cursor.execute("SELECT status, COUNT(*) as count FROM items WHERE type = 'todo' AND is_deleted = 0 GROUP BY status")
stats['todo_status'] = {row['status']: row['count'] for row in cursor.fetchall()}
# 标签数