Compare commits

...

94 Commits

Author SHA1 Message Date
a7590995e4 fix: Markdown开关改用data属性存储内容,修复切换失效问题 2026-04-24 13:04:44 +08:00
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
e92349e111 feat(v4.2.1): 文件夹按钮样式优化+新增数据到文件夹功能
- hover文件夹时按钮悬浮在右侧,高度一致
- 新增数据按钮(绿色+)直接添加数据到该文件夹
2026-04-22 16:59:27 +08:00
0912d658b8 feat(v4.2.0): 文件夹支持重命名和删除
- hover文件夹时显示编辑和删除按钮
- 编辑按钮打开重命名模态框
- 删除按钮确认后删除,数据移到未分类
2026-04-22 16:27:38 +08:00
8e63db4424 fix(v4.1.1): 待办事务功能优化
- 修复完成状态切换问题(可来回切换完成/未完成)
- 添加全部/未完成/已完成过滤按钮
- 翻页时保持弹窗滚动位置
2026-04-22 15:54:10 +08:00
0335937312 feat(v4.1.0): 文本类别添加待办事务功能
- 可在文本数据详情中追加待办事务
- 支持事务内容、剩余天数(默认1天)、完成状态
- 历史事务按时间倒序排列,显示创建/更新时间
- 分页显示,每页10条
2026-04-22 13:00:00 +08:00
6a0f8d7196 feat(v4.0.0): 快速插入支持选中位置插入
- 先选中部分文本,再双击可在选中位置前/后插入
- 支持替换选中内容
- 自动识别选中文本并在原内容中定位
2026-04-22 12:49:37 +08:00
407a63f3cf fix: 修复JS正则表达式在模板字符串中被破坏的问题 2026-04-22 12:22:07 +08:00
eec8b477be feat: 详情弹框内容支持Markdown格式显示 2026-04-22 12:06:42 +08:00
489e95d677 fix: 修复显示模式切换按钮无效问题(添加currentItems变量) 2026-04-22 12:02:39 +08:00
47cbcb25bc feat: 添加显示模式切换按钮(单行/双行) 2026-04-22 11:56:59 +08:00
527c411d87 fix: 卡片布局自适应,操作按钮不再被挤出可视区域 2026-04-22 11:35:13 +08:00
c8aecaeb03 fix: 修复文件夹过滤时分页总数计算错误 2026-04-22 11:18:51 +08:00
bf63610510 fix: 点击类别同时展开文件夹并过滤数据 2026-04-22 10:52:30 +08:00
7af3a7f21d feat: 侧边栏文件夹UI优化 - 折叠式设计
- 新建文件夹按钮移到类别右侧(文件夹+图标)
- 默认折叠状态,点击类别名称展开/折叠
- 投影箭头指示展开状态(▶折叠,▼展开)
- 按钮hover时显示绿色背景,更明显可见
2026-04-22 10:44:53 +08:00
4783e9d88e feat: 文件夹功能
- 数据库添加 folders 表和 items.folder_id 字段
- API 新增文件夹 CRUD 接口和条目移动接口
- 侧边栏每个类别下显示文件夹列表
- 新建文件夹按钮和模态框
- 条目卡片添加「移动到文件夹」按钮
- 点击文件夹过滤显示该文件夹下的数据
2026-04-21 22:23:20 +08:00
ccbd24be11 feat: 侧边栏和顶部按钮栏固定显示
- 侧边栏固定在左侧(position: fixed)
- 顶部按钮栏固定在顶部(position: sticky)
- 主内容区留出侧边栏空间(margin-left: 200px)
- 滚动页面时侧边栏和顶部栏保持不动
2026-04-21 22:12:03 +08:00
16ed5459fa feat: 连接状态移到侧边栏标题后面,点击标题回到首页 2026-04-20 18:24:29 +08:00
ca7dc10e92 feat: 顶部添加连接状态指示器,掉线时禁止编辑和新增操作 2026-04-20 18:10:37 +08:00
94efc524c6 fix: 修复 JavaScript 语法错误(多余的闭合括号导致页面无法加载) 2026-04-19 23:15:17 +08:00
436f897711 fix: 修复编辑弹框关闭确认只提示一次的问题
- 定义命名函数作为监听器
- 每次打开编辑弹框时移除旧监听器再添加新监听器
- 确保每次关闭时都能检查是否有修改
2026-04-19 23:09:15 +08:00
9d6cea0453 feat: 编辑弹框关闭时检查是否有修改并提示确认
- 打开编辑弹框时保存原始数据状态
- 关闭时比较当前内容和原始内容
- 如果有修改,弹出确认对话框询问是否放弃修改
- 保存成功后清除原始数据标记
2026-04-19 18:49:35 +08:00
c9433a5e98 fix: 修复编辑草稿时重复创建新草稿的问题
- showAddModal 不再重置 currentDraftId
- 编辑已有草稿时会更新该草稿而不是创建新草稿
2026-04-19 18:08:00 +08:00
7d3c5c2ae1 feat: 重构草稿箱功能
- 数据库添加 drafts 表存储草稿数据
- 草稿箱独立页面,侧边栏添加入口
- 自动保存间隔可配置(2/5/10/30/60秒)
- 草稿可编辑、发布为正式条目、删除
- 编辑时自动保存到服务器数据库
2026-04-19 17:55:29 +08:00
51c76ebd24 feat: 新增草稿箱自动保存功能
- 编辑时自动保存到 localStorage(每5秒或输入后2秒)
- 打开添加弹框时检查是否有草稿并提示恢复
- 成功添加后清除草稿
- 弹框标题显示“已自动保存”指示器
2026-04-19 17:31:08 +08:00
facf39e778 fix: 修复回收站显示问题
- 修改提示文字:回收站数据可随时恢复,无30天限制
- 清空分页组件:避免显示错误的分页
2026-04-19 17:09:58 +08:00
51cecf1f4e fix: 修复回收站点击事件被侧边栏通用处理器捕获的问题
- 只为有 data-filter 属性的链接添加过滤事件处理器
- 回收站链接使用 onclick 内联事件,不会被通用处理器干扰
- 从回收站返回时正确重置 trashView 状态
2026-04-19 17:07:48 +08:00
79e4eb4de0 feat: 新增回收站功能
- 数据库添加 is_deleted 和 deleted_at 字段
- 删除数据改为移动到回收站(软删除)
- 回收站支持查看、恢复、彻底删除
- 支持一键清空回收站
- 侧边栏添加回收站入口
2026-04-19 16:57:47 +08:00
70b40cb90b feat: 新增阅读数功能
- 数据库添加 views 字段,兼容旧数据库自动添加
- API 新增 /api/items/<id>/view 接口增加阅读数
- 列表显示阅读数(👁图标)
- 详情页显示阅读数,点击详情时自动增加
2026-04-19 10:44:05 +08:00
22c32a9f3d fix: 编辑保存失败时显示错误提示;修复只修改标签时返回False的问题 2026-04-19 09:25:59 +08:00
c3791ce961 fix: 重点关注图标样式优化,只有五角星变实心,按钮保持outline样式 2026-04-19 09:03:44 +08:00
27e24e2a86 fix: 修复数据库初始化索引创建顺序 2026-04-19 00:13:35 +08:00
0864c99b75 feat: 新增重点关注功能
- 数据库新增 is_starred 字段,兼容旧数据库自动添加
- 所有类别数据支持一键设置/取消重点关注
- 侧边栏新增"重点关注"过滤选项,重点关注数据优先显示
- 新增数据时可直接勾选"设为重点关注"开关
- 编辑时可切换重点关注状态
- 卡片显示重点关注标记(星标图标)和特殊样式
- API新增 /api/items/<id>/star 接口用于切换重点关注状态
- 重点关注数据按创建时间倒序排列并优先显示
2026-04-19 00:11:24 +08:00
0c6057de28 feat: 内容统计信息显示(有效行数/总字数) 2026-04-17 10:51:58 +08:00
6f20e5978d fix: 分页正确显示当前筛选的总数
- API返回 total 字段(筛选后的实际总数)
- 新增 count_items 函数计算筛选条件下的总数
- 分页使用API返回的total而不是全局统计
- 解决筛选后分页显示不正确的问题
2026-04-16 14:08:12 +08:00
56ff1e8163 fix: 搜索输入实时响应修复
- 改用直接 setTimeout 方式,不用 debounce 函数
- 避免函数绑定问题导致搜索不触发
2026-04-16 14:03:05 +08:00
9ec479415a docs: 更新版本历史 v2.4.0 2026-04-16 13:55:07 +08:00
7652718803 feat: 数据库备份机制 v2.4.0
- 新增备份管理 API 和页面
- 自动备份:每天 04:00 执行
- 手动备份:页面一键备份
- 备份清理规则:
  - 保留最近 30 天
  - 每月第一天永久保留
  - 手动备份最多保留 10 个
- 支持恢复和删除备份
2026-04-16 13:54:07 +08:00
d2f64f98a1 fix: 初始化时清空搜索框和筛选状态
- 页面加载时强制清空 searchInput
- 重置 typeFilter 和 currentFilter
- 删除重复的 pageSize 定义
2026-04-16 13:47:46 +08:00
161b93f368 docs: 更新版本历史 v2.3.2 2026-04-16 13:41:06 +08:00
31f2d8b428 fix: 搜索功能修复 - debounce函数定义顺序
- debounce函数在使用前必须先定义
- 之前定义在代码末尾,导致搜索事件绑定失败
- 现移到代码开头,确保正确执行
2026-04-16 13:40:44 +08:00
5d6dd10dfa docs: 更新版本历史 v2.3.1 2026-04-16 12:20:51 +08:00
d0f7b07260 fix: 日期放到标题后面,不增加卡片高度
- 日期紧跟标题后面,同一行显示
- 格式更紧凑:04-16 11:09 →04-16 12:00
- 字体10px,透明度0.5,不影响阅读
2026-04-16 12:20:32 +08:00
0be768ca8e docs: 更新版本历史 v2.3.0 2026-04-16 12:17:24 +08:00
68ecb16303 feat: 卡片显示创建和更新日期
- 每个收藏卡片底部显示日期
- 格式:04-16 11:09(月-日 时:分)
- 有更新时显示:创建 → 更新
- 字体更小更淡,不影响卡片高度
2026-04-16 12:16:54 +08:00
82d928f497 docs: 更新版本历史 v2.2.0 2026-04-16 11:45:57 +08:00
c99eca35f0 feat: 快捷添加按钮,一键选择类型
- 顶部按钮栏分离为4个快捷添加按钮
- 点击直接进入对应类型的添加弹窗
- 弹窗标题显示类型图标和名称
- 不再需要下拉选择类型
2026-04-16 11:45:25 +08:00
47b195ed1c docs: 更新版本历史 v2.1.0 2026-04-16 11:37:49 +08:00
1f1528979c feat: 待办截止时间支持日期+时间
- 截止日期改为日期时间选择器(datetime-local)
- 新增友好显示函数:今天/明天/昨天 + 时间
- 详情页显示完整日期时间格式
- 提醒弹窗显示友好格式
- 后端支持多种日期格式解析
- 只有日期的待办视为当天23:59到期
2026-04-16 11:37:04 +08:00
bcb24e474d docs: 更新版本历史 v2.0.1 2026-04-16 11:26:06 +08:00
a19b260ef7 fix: 转换弹窗优化
- 内容预览保留换行格式,提高可读性
- 转换方式默认改为复制创建
2026-04-16 11:25:49 +08:00
1d8ce5cfb9 docs: 更新版本历史 v2.0.0 2026-04-16 11:18:54 +08:00
cb2cbd4c6b feat: 收藏转待办功能 v2.0.0
- 新增 /api/items/<id>/convert API
- 支持两种转换方式:
  - 直接转换(convert):原收藏变为待办
  - 复制创建(copy):保留原收藏,新建待办
- 文本/链接/专栏类型可转换
- 内容自动合并到待办备注
- 前端列表和详情页添加转换按钮
- 弹窗配置:标题、状态、优先级、截止日期
2026-04-16 11:18:26 +08:00
c0d221c2a3 docs: 更新版本历史 v1.11.0 2026-04-16 11:06:02 +08:00
6b775c99f9 feat: 已完成待办可重新打开
- 新增 /api/items/<id>/reopen 接口
- 前端列表已完成待办显示重新打开按钮
- 恢复为 pending 或 in_progress 状态
2026-04-16 11:05:34 +08:00
061bfa3b55 docs: 更新版本历史 v1.10.0 2026-04-16 10:59:44 +08:00
2eccc11369 feat: 网页端待办到期提醒功能
- 新增 /api/reminders API 接口
- 获取已过期、今天到期、即将到期的待办
- 前端显示提醒栏和弹窗详情
- 每5分钟自动刷新提醒
- 支持快速完成待办
2026-04-16 10:59:26 +08:00
d874577458 feat: 邮件发送历史记录 v1.9.2 2026-04-14 17:27:37 +08:00
bc59fb39db fix: 邮件发送添加Date和Reply-To头 2026-04-14 17:09:04 +08:00
fba2c1290d fix: 端口587无SSL直接连接 2026-04-14 16:40:57 +08:00
6490ceff08 fix: SMTP配置更新为mail.tphai.com端口587 2026-04-14 16:35:20 +08:00
e13fa0e337 feat: 发送邮件功能 + 邮箱管理 v1.9.0 2026-04-14 12:52:49 +08:00
3eae1595aa fix: 修复AI处理f-string中JSON花括号转义问题 2026-04-13 17:03:09 +08:00
6f0905d83a docs: 更新版本历史 2026-04-13 16:57:02 +08:00
033b7509d7 feat: AI自动添加功能,智能识别文本类型并整理数据 2026-04-13 16:56:43 +08:00
8f9a8d2ad5 docs: 更新版本历史 2026-04-13 16:46:10 +08:00
ffe7adcad2 feat: 编辑收藏时支持更改类型,动态显示对应字段 2026-04-13 16:45:48 +08:00
963dd1846b docs: 更新版本历史 2026-04-13 16:35:35 +08:00
ad6d369069 feat: 标签管理添加编辑功能,支持修改标签名称 2026-04-13 16:35:09 +08:00
68411813b3 docs: 更新版本历史 2026-04-13 16:27:56 +08:00
d8780b9000 fix: 标签管理添加搜索功能,实时过滤标签列表 2026-04-13 16:27:36 +08:00
196bfaf213 docs: 更新版本历史 2026-04-13 16:17:23 +08:00
2675edb695 feat: 首页添加分页功能,每页20条记录 2026-04-13 16:17:06 +08:00
1f9d0a7ea2 docs: 更新版本历史 2026-04-13 16:10:41 +08:00
4642a278a5 feat: 首页添加导出按钮,一键导出JSON格式 2026-04-13 16:10:27 +08:00
598a86b32d docs: 更新版本历史 2026-04-13 16:01:20 +08:00
ae27641b6d feat: 编辑和添加模态框改为大尺寸(modal-lg) 2026-04-13 16:01:06 +08:00
7ab6647c32 docs: 更新版本历史 2026-04-13 12:27:08 +08:00
16 changed files with 18687 additions and 249 deletions

View File

@@ -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,78 @@ xian-favor/
## 版本历史
- **v2.4.0** (2026-04-16): 数据库备份机制
- 自动备份:每天 04:00 执行
- 手动备份:页面一键操作
- 备份清理规则保留30天 + 每月第一天永久保留
- 手动备份最多保留10个
- 支持恢复备份和删除备份
- 备份管理页面入口在侧边栏
- **v2.3.2** (2026-04-16): 搜索功能修复
- 修复 debounce 函数定义顺序问题
- 搜索框输入后可正常过滤列表
- **v2.3.1** (2026-04-16): 日期放到标题后面,不增加卡片高度
- 日期紧跟标题,同一行显示
- 格式紧凑:`04-16 11:09→04-16 12:00`
- **v2.3.0** (2026-04-16): 卡片显示创建和更新日期
- 每个收藏卡片底部显示日期
- 格式04-16 11:09月-日 时:分)
- 有更新时显示:创建 → 更新
- 字体更小更淡,不影响卡片高度
- **v2.2.0** (2026-04-16): 快捷添加按钮,一键选择类型
- 顶部按钮栏分离为4个快捷添加按钮文本、链接、待办、专栏
- 点击直接进入对应类型的添加弹窗
- 弹窗标题显示类型图标和名称
- 不再需要下拉选择类型,操作更快捷
- **v2.1.0** (2026-04-16): 待办截止时间支持日期+时间
- 截止日期改为日期时间选择器
- 列表显示友好格式:今天 18:30、明天 09:00 等
- 详情页显示完整格式2026年4月16日 18:30
- 后端支持多种日期格式解析
- 只有日期的待办视为当天 23:59 到期
- **v2.0.1** (2026-04-16): 转换弹窗优化
- 内容预览保留换行格式,提高可读性
- 转换方式默认改为复制创建
- **v2.0.0** (2026-04-16): 收藏转待办功能(大版本更新)
- 新增 `/api/items/<id>/convert` API
- **直接转换**:原收藏变为待办,数据合并
- **复制创建**:保留原收藏,新建待办任务
- 文本/链接/专栏类型可转换
- 内容自动合并到待办备注
- 前端列表和详情页添加转换按钮
- 弹窗配置:标题、状态、优先级、截止日期
- v1.11.0 (2026-04-16): 已完成待办可重新打开
- 新增 `/api/items/<id>/reopen` 接口
- 前端列表已完成待办显示重新打开按钮(↻图标)
- 可恢复为 pending 或 in_progress 状态
- v1.10.0 (2026-04-16): 网页端待办到期提醒功能
- 新增提醒 API `/api/reminders`
- 获取已过期、今天到期、即将到期的待办
- 前端顶部提醒栏显示提醒数量和概要
- 弹窗详情支持快速完成待办
- 每5分钟自动刷新提醒
- v1.9.2 (2026-04-14): 邮件发送历史记录
- 详情页面显示邮件发送记录(发送邮箱、时间)
- 支持多次发送,显示多条记录
- 发送成功/失败状态标记
- 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

View File

@@ -2,12 +2,17 @@
import sqlite3
import json
from datetime import datetime
import shutil
import os
from datetime import datetime, timedelta
from typing import Optional, List, Dict, Any
from contextlib import contextmanager
from .config import DATABASE_URL, TODO_STATUS, PRIORITY_LEVELS
# 备份目录
BACKUP_DIR = os.path.join(os.path.dirname(DATABASE_URL), 'backups')
class Database:
"""SQLite数据库管理"""
@@ -80,6 +85,28 @@ 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 TABLE IF NOT EXISTS email_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
item_id INTEGER NOT NULL,
email TEXT NOT NULL,
sent_at TEXT NOT NULL,
success INTEGER DEFAULT 1,
FOREIGN KEY (item_id) REFERENCES items(id) ON DELETE CASCADE
)
""")
# 创建索引
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)")
@@ -177,6 +204,41 @@ class Database:
return items
def count_items(self, type: str = None, status: str = None, tag: str = None,
keyword: str = None) -> int:
"""计算符合条件的条目总数"""
with self.get_conn() as conn:
cursor = conn.cursor()
query = "SELECT COUNT(DISTINCT i.id) as count FROM items i"
params = []
conditions = []
# 标签过滤需要JOIN
if tag:
query += " JOIN item_tags it ON i.id = it.item_id JOIN tags t ON it.tag_id = t.id"
conditions.append("t.name = ?")
params.append(tag)
if type:
conditions.append("i.type = ?")
params.append(type)
if status:
conditions.append("i.status = ?")
params.append(status)
if keyword:
conditions.append("(i.title LIKE ? OR i.content LIKE ? OR i.note LIKE ?)")
keyword_pattern = f"%{keyword}%"
params.extend([keyword_pattern, keyword_pattern, keyword_pattern])
if conditions:
query += " WHERE " + " AND ".join(conditions)
cursor.execute(query, params)
return cursor.fetchone()['count']
def update_item(self, item_id: int, **kwargs) -> bool:
"""更新条目"""
allowed_fields = ['type', 'title', 'content', 'url', 'source', 'status', 'priority', 'due_date', 'note']
@@ -244,6 +306,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 +364,90 @@ 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 log_email_send(self, item_id: int, email: str, success: bool = True) -> int:
"""记录邮件发送"""
now = datetime.now().isoformat()
with self.get_conn() as conn:
cursor = conn.cursor()
cursor.execute("""
INSERT INTO email_logs (item_id, email, sent_at, success)
VALUES (?, ?, ?, ?)
""", (item_id, email, now, 1 if success else 0))
conn.commit()
return cursor.lastrowid
def get_email_logs(self, item_id: int) -> List[Dict[str, Any]]:
"""获取收藏的邮件发送记录"""
with self.get_conn() as conn:
cursor = conn.cursor()
cursor.execute("""
SELECT * FROM email_logs
WHERE item_id = ?
ORDER BY sent_at DESC
""", (item_id,))
return [dict(row) for row in cursor.fetchall()]
def stats(self) -> Dict[str, Any]:
"""获取统计信息"""
self._ensure_init()
@@ -315,6 +473,252 @@ class Database:
stats['tags'] = cursor.fetchone()['count']
return stats
# ============ 提醒相关 ============
def get_reminders(self) -> Dict[str, Any]:
"""获取提醒信息:即将到期和已过期的待办"""
self._ensure_init()
with self.get_conn() as conn:
cursor = conn.cursor()
now = datetime.now()
reminders = {
'overdue': [], # 已过期
'due_today': [], # 今天到期
'due_soon': [] # 24小时内到期不含今天
}
# 查询未完成的待办(有截止日期的)
cursor.execute("""
SELECT * FROM items
WHERE type = 'todo'
AND status != 'completed'
AND due_date IS NOT NULL
AND due_date != ''
ORDER BY due_date ASC
""")
for row in cursor.fetchall():
item = dict(row)
item['tags'] = self._get_item_tags(conn, item['id'])
try:
due_date_str = item['due_date']
# 支持多种日期格式
if 'T' in due_date_str:
# ISO 格式2026-04-16T14:30
due_date = datetime.strptime(due_date_str[:16], '%Y-%m-%dT%H:%M')
elif len(due_date_str) == 10:
# 只有日期2026-04-16视为当天 23:59:59
due_date = datetime.strptime(due_date_str, '%Y-%m-%d').replace(hour=23, minute=59, second=59)
else:
# 其他格式,尝试解析
due_date = datetime.strptime(due_date_str.split('.')[0], '%Y-%m-%dT%H:%M:%S')
# 计算距离到期的时间
time_left = due_date - now
if time_left.total_seconds() < 0:
# 已过期
days_overdue = abs(int(time_left.total_seconds() / 86400))
item['days_overdue'] = days_overdue
reminders['overdue'].append(item)
elif time_left.total_seconds() < 86400: # 24小时内
# 判断是今天还是明天
if due_date.date() == now.date():
reminders['due_today'].append(item)
else:
reminders['due_soon'].append(item)
elif due_date.date() == now.date():
# 今天到期超过24小时的情况比如现在凌晨截止时间是晚上
reminders['due_today'].append(item)
except (ValueError, AttributeError) as e:
# 日期格式错误,跳过
continue
# 统计总数
reminders['total'] = len(reminders['overdue']) + len(reminders['due_today']) + len(reminders['due_soon'])
return reminders
# ============ 备份操作 ============
def create_backup(self, manual: bool = False) -> Dict[str, Any]:
"""创建数据库备份"""
import os
# 确保备份目录存在
os.makedirs(BACKUP_DIR, exist_ok=True)
now = datetime.now()
backup_name = now.strftime('%Y-%m-%d_%H%M%S')
if manual:
backup_name += '_manual'
backup_path = os.path.join(BACKUP_DIR, f'{backup_name}.db')
# 复制数据库文件
shutil.copy2(self.db_path, backup_path)
# 获取备份信息
backup_info = {
'name': backup_name,
'path': backup_path,
'size': os.path.getsize(backup_path),
'created_at': now.isoformat(),
'manual': manual,
'is_first_of_month': now.day == 1
}
# 保存备份元数据
self._save_backup_meta(backup_info)
# 清理旧备份
self._cleanup_old_backups()
return backup_info
def list_backups(self) -> List[Dict[str, Any]]:
"""列出所有备份"""
import os
if not os.path.exists(BACKUP_DIR):
return []
# 读取备份元数据
meta_path = os.path.join(BACKUP_DIR, 'backup_meta.json')
if os.path.exists(meta_path):
with open(meta_path, 'r') as f:
backups = json.load(f)
else:
# 从文件重建元数据
backups = []
for f in os.listdir(BACKUP_DIR):
if f.endswith('.db'):
path = os.path.join(BACKUP_DIR, f)
backups.append({
'name': f.replace('.db', ''),
'path': path,
'size': os.path.getsize(path),
'created_at': datetime.fromtimestamp(os.path.getmtime(path)).isoformat(),
'manual': '_manual' in f,
'is_first_of_month': self._is_first_of_month_filename(f)
})
# 按时间倒序排列
backups.sort(key=lambda x: x['created_at'], reverse=True)
return backups
def restore_backup(self, backup_name: str) -> bool:
"""恢复备份"""
import os
backup_path = os.path.join(BACKUP_DIR, f'{backup_name}.db')
if not os.path.exists(backup_path):
return False
# 先备份当前数据库(以防万一)
current_backup = self.db_path + '.before_restore'
shutil.copy2(self.db_path, current_backup)
# 恢复备份
shutil.copy2(backup_path, self.db_path)
return True
def delete_backup(self, backup_name: str) -> bool:
"""删除备份"""
import os
backup_path = os.path.join(BACKUP_DIR, f'{backup_name}.db')
if not os.path.exists(backup_path):
return False
os.remove(backup_path)
# 更新元数据
self._remove_backup_meta(backup_name)
return True
def _save_backup_meta(self, backup_info: Dict[str, Any]):
"""保存备份元数据"""
import os
meta_path = os.path.join(BACKUP_DIR, 'backup_meta.json')
# 读取现有元数据
backups = []
if os.path.exists(meta_path):
with open(meta_path, 'r') as f:
backups = json.load(f)
# 添加新备份
backups.append(backup_info)
# 保存
with open(meta_path, 'w') as f:
json.dump(backups, f, indent=2)
def _remove_backup_meta(self, backup_name: str):
"""从元数据中删除备份"""
import os
meta_path = os.path.join(BACKUP_DIR, 'backup_meta.json')
if not os.path.exists(meta_path):
return
with open(meta_path, 'r') as f:
backups = json.load(f)
backups = [b for b in backups if b['name'] != backup_name]
with open(meta_path, 'w') as f:
json.dump(backups, f, indent=2)
def _is_first_of_month_filename(self, filename: str) -> bool:
"""判断是否是每月第一天的备份"""
# 格式2026-04-01_040000.db 或 2026-05-01_...
try:
date_part = filename.split('_')[0]
day = int(date_part.split('-')[2])
return day == 1
except:
return False
def _cleanup_old_backups(self):
"""清理旧备份保留30天 + 每月第一天"""
import os
backups = self.list_backups()
now = datetime.now()
keep_paths = []
for backup in backups:
backup_date = datetime.fromisoformat(backup['created_at'])
days_old = (now - backup_date).days
# 保留条件:
# 1. 手动备份永久保留最多10个
# 2. 30天内的备份
# 3. 每月第一天的备份
if backup['manual']:
# 手动备份保留但最多10个
manual_backups = [b for b in backups if b['manual']]
if manual_backups.index(backup) < 10:
keep_paths.append(backup['path'])
else:
self.delete_backup(backup['name'])
elif days_old <= 30:
keep_paths.append(backup['path'])
elif backup['is_first_of_month']:
# 每月第一天永久保留
keep_paths.append(backup['path'])
else:
# 删除
self.delete_backup(backup['name'])
# 全局数据库实例

0
data/xian_favor.db Normal file
View File

402
logs/api.log Normal file
View File

@@ -0,0 +1,402 @@
* Serving Flask app 'xian_favor.api'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:19014
* Running on http://192.168.2.17:19014
Press CTRL+C to quit
127.0.0.1 - - [19/Apr/2026 10:06:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:07:04] "GET /api/items?limit=2&sort_by=updated_at&sort_order=desc HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:07:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:07:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:07:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:07:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:07:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:07:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:07:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:07:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:07:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:07:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:08:06] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:08:15] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:08:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:08:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:08:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:08:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:08:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:08:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:08:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:08:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:08:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:09:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:09:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:09:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:09:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:09:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:09:33] "GET /api/health HTTP/1.1" 404 -
192.168.2.8 - - [19/Apr/2026 10:09:33] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:09:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:09:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:09:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:09:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:10:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:10:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:10:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:10:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:10:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:10:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:10:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:10:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:10:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:10:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:11:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:11:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:11:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:11:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:11:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:11:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:11:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:11:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:11:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:11:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:12:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:12:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:12:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:12:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:12:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:12:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:12:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:12:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:12:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:12:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:13:06] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:13:16] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:13:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:13:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:13:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:13:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:13:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:13:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:13:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:13:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:13:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:33] "GET /api/health HTTP/1.1" 404 -
192.168.2.8 - - [19/Apr/2026 10:14:33] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:14:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:38] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:14:44] "GET / HTTP/1.1" 200 -
192.168.2.10 - - [19/Apr/2026 10:14:44] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [19/Apr/2026 10:14:44] "GET /api/reminders HTTP/1.1" 200 -
192.168.2.10 - - [19/Apr/2026 10:14:44] "GET /api/tags HTTP/1.1" 200 -
192.168.2.10 - - [19/Apr/2026 10:14:44] "GET /api/items?limit=20&offset=0 HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:14:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:14:58] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:15:01] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:15:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:15:08] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:15:16] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:15:16] "GET /api/items?limit=20&offset=0&sort_by=updated_at&sort_order=desc HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:15:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:15:18] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:15:21] "GET /api/items?limit=20&offset=0&sort_order=desc HTTP/1.1" 200 -
192.168.2.10 - - [19/Apr/2026 10:15:24] "GET /api/items?limit=20&offset=0&sort_by=created_at&sort_order=desc HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:15:26] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:15:27] "GET /api/items?limit=20&offset=0&sort_by=updated_at&sort_order=desc HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:15:28] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:15:31] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:15:34] "GET /api/items?limit=20&offset=0&sort_order=desc HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:15:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:15:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:15:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:15:56] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:15:56] "GET /api/items/59 HTTP/1.1" 200 -
192.168.2.10 - - [19/Apr/2026 10:16:00] "GET /api/items/59 HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:16:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:16:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:16:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:16:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:16:29] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:16:32] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:16:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:16:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:16:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:16:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:17:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:17:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:17:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:17:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:17:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:17:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:17:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:17:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:17:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:17:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:18:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:18:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:18:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:18:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:18:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:18:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:18:36] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:18:46] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:18:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:18:56] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:19:06] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:19:16] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:19:17] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:19:26] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:19:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:19:33] "GET /api/health HTTP/1.1" 404 -
192.168.2.8 - - [19/Apr/2026 10:19:33] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:19:36] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:19:44] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:19:47] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:19:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:19:58] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:20:08] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:20:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:20:19] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:20:29] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:20:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:20:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:20:39] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:20:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:20:49] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:20:59] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:21:09] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:21:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:21:19] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:21:29] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:21:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:21:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:21:39] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:21:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:21:49] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:22:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:22:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:22:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:22:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:22:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:22:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:22:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:22:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:22:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:22:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:23:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:23:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:23:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:23:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:23:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:23:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:23:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:23:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:23:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:23:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:24:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:24:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:24:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:24:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:24:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:24:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:24:33] "GET /api/health HTTP/1.1" 404 -
192.168.2.8 - - [19/Apr/2026 10:24:37] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:24:40] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:24:44] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:24:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:24:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:25:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:25:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:25:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:25:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:25:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:25:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:25:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:25:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:25:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:25:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:26:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:26:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:26:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:26:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:26:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:26:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:26:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:26:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:26:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:26:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:27:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:27:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:27:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:27:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:27:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:27:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:27:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:27:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:27:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:27:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:28:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:28:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:28:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:28:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:28:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:28:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:28:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:28:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:28:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:28:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:29:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:29:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:29:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:29:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:29:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:29:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:29:33] "GET /api/health HTTP/1.1" 404 -
192.168.2.8 - - [19/Apr/2026 10:29:37] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:29:40] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:29:44] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:29:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:29:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:30:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:30:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:30:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:30:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:30:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:30:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:30:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:30:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:30:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:30:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:31:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:31:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:31:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:31:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:31:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:31:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:31:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:31:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:31:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:31:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:32:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:32:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:32:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:32:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:32:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:32:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:32:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:32:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:32:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:32:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:33:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:33:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:33:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:33:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:33:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:33:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:33:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:33:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:33:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:33:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:34:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:34:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:34:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:34:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:34:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:34:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:34:33] "GET /api/health HTTP/1.1" 404 -
192.168.2.8 - - [19/Apr/2026 10:34:37] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:34:40] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:34:44] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:34:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:34:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:35:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:35:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:35:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:35:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:35:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:35:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:35:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:35:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:35:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:35:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:36:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:36:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:36:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:36:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:36:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:36:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:36:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:36:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:36:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:36:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:37:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:37:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:37:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:37:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:37:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:37:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:37:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:37:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:37:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:37:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:38:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:38:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:38:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:38:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:38:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:38:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:38:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:38:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:38:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:38:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:39:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:39:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:39:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:39:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:39:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:39:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:39:33] "GET /api/health HTTP/1.1" 404 -
192.168.2.8 - - [19/Apr/2026 10:39:37] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:39:40] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:39:44] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:39:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:39:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:40:00] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:40:05] "PUT /api/items/59 HTTP/1.1" 200 -
192.168.2.10 - - [19/Apr/2026 10:40:05] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [19/Apr/2026 10:40:05] "GET /api/items?limit=20&offset=0&sort_order=desc HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:40:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:40:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:40:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:40:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:40:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:40:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:40:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:40:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:40:50] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:40:57] "GET /api/items/68 HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:41:00] "GET /api/health HTTP/1.1" 404 -
192.168.2.10 - - [19/Apr/2026 10:41:01] "GET /api/items/68 HTTP/1.1" 200 -
127.0.0.1 - - [19/Apr/2026 10:41:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:41:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:41:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:41:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:41:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:41:33] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:41:40] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:41:48] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:41:50] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:42:00] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:42:10] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:42:18] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:42:20] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:42:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:42:30] "GET /api/health HTTP/1.1" 404 -
127.0.0.1 - - [19/Apr/2026 10:42:33] "GET /api/health HTTP/1.1" 404 -

156
logs/app.log Normal file
View File

@@ -0,0 +1,156 @@
🚀 启动API服务: http://0.0.0.0:19014
* Serving Flask app 'xian_favor.api'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:19014
* Running on http://192.168.2.17:19014
Press CTRL+C to quit
127.0.0.1 - - [20/Apr/2026 18:16:59] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:06] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:09] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:18] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:19] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:23] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:29] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:32] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:36] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:37] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:39] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:49] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:17:59] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:06] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:09] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:10] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:15] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:19] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:19] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:27] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:31] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:33] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:37] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:39] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:41] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:45] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:51] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:18:52] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:00] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:01] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:06] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:07] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:11] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:12] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:20] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:21] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:30] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:31] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:36] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:37] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:41] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:42] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:19:51] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.8 - - [20/Apr/2026 18:19:55] "GET /api/reminders HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:19:55] "GET /api/reminders HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:20:01] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:20:07] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:20:11] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:20:21] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:20:31] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:20:34] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:20:37] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:20:40] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:20:41] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:42] "GET / HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:42] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:42] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:42] "GET /api/reminders HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:42] "GET /api/tags HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:42] "GET /api/items?limit=20&offset=0 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:47] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:20:51] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:52] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:53] "GET / HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:53] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:53] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:54] "GET /api/reminders HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:54] "GET /api/items?limit=20&offset=0 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:54] "GET /api/tags HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:20:58] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:21:01] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:03] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:21:07] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:08] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:21:11] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:13] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:18] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:21:21] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:23] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:28] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:21:32] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:33] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:21:34] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:21:37] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:38] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:21:40] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:21:42] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:43] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:48] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:21:52] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:53] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:21:58] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:22:02] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:03] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:22:07] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:08] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:22:12] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:13] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:18] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:22:22] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:23] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:28] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:31] "GET /api/items?limit=20&offset=20 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:22:32] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:33] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:22:34] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:22:37] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:38] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:40] "GET /api/items?limit=20&offset=0 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:22:40] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:22:42] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:43] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:48] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:22:52] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:53] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:22:58] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:23:02] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:03] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:23:07] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:08] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:23:12] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:13] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:18] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:23:22] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:23] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:28] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:23:32] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:33] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:23:34] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:23:37] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:39] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:23:40] "GET /api/items?limit=1 HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:23:42] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:44] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:48] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:23:52] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:53] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:23:58] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:24:02] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:24:04] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:24:07] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:24:08] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:24:12] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:24:14] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:24:19] "GET /api/stats HTTP/1.1" 200 -
127.0.0.1 - - [20/Apr/2026 18:24:22] "GET /api/items?limit=1 HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:24:24] "GET /api/stats HTTP/1.1" 200 -
192.168.2.10 - - [20/Apr/2026 18:24:28] "GET /api/stats HTTP/1.1" 200 -

9709
logs/server.log Normal file

File diff suppressed because it is too large Load Diff

35
scripts/auto_backup.py Executable file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env python3
"""
Xian Favor 自动备份脚本
定时任务调用此脚本进行自动备份
"""
import sys
import os
# 添加项目路径
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from xian_favor.db import db
def main():
"""执行自动备份"""
print(f"[{datetime.now().isoformat()}] 开始自动备份...")
try:
backup_info = db.create_backup(manual=False)
print(f"备份成功: {backup_info['name']}")
print(f"大小: {backup_info['size']} bytes")
print(f"位置: {backup_info['path']}")
# 清理旧备份
db._cleanup_old_backups()
print("旧备份清理完成")
except Exception as e:
print(f"备份失败: {e}")
sys.exit(1)
if __name__ == '__main__':
from datetime import datetime
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff