67 lines
2.3 KiB
Markdown
67 lines
2.3 KiB
Markdown
# PRD:博客文章列表排序修复
|
||
|
||
## 问题描述
|
||
|
||
Admin 页面和公开首页的文章列表,在同日期文章之间顺序不确定。
|
||
|
||
**复现步骤:**
|
||
1. 同一天创建/发布多篇文章(如 2026-05-12 有 5 篇)
|
||
2. 打开 `blog.ephron.ren/admin` 或 `blog.ephron.ren/`
|
||
3. 同日期的文章顺序每次可能不同,最新创建的文章不一定排在最前面
|
||
|
||
**根因:**
|
||
|
||
`blog/src/services/posts.py` 的排序逻辑:
|
||
|
||
```python
|
||
# 第 325 行
|
||
posts.sort(key=lambda p: (not p.pinned, -p.date.toordinal()))
|
||
```
|
||
|
||
只用了 `date`(`datetime.date` 类型,只有日期没有时间)。同日期的文章 `toordinal()` 值相同,排序退化为 Python 的 stable sort,顺序取决于 `glob()` 文件系统迭代顺序,非确定性。
|
||
|
||
**影响范围:**
|
||
- Admin 文章管理页(`/admin`)
|
||
- 公开首页(`/`)
|
||
- 博客列表页(`/posts`)
|
||
- 归档页(`/archive`)
|
||
- 标签筛选(`/tags/{tag}`)
|
||
- RSS feed(`/feed`)
|
||
- 搜索结果(`/search`)
|
||
|
||
所有页面都调用 `get_all_posts()` 或 `search_posts()`,共用同一个排序逻辑。
|
||
|
||
## 期望行为
|
||
|
||
同日期的文章按创建/修改时间倒序排列,最新创建的排最前面。
|
||
|
||
## 修复方案
|
||
|
||
在排序 key 中增加 `file_path.stat().st_mtime` 作为三级排序键:
|
||
|
||
```python
|
||
# posts.py 第 325 行
|
||
posts.sort(key=lambda p: (not p.pinned, -p.date.toordinal(), -p.file_path.stat().st_mtime))
|
||
|
||
# posts.py 第 643 行
|
||
results.sort(key=lambda p: (not p[0].pinned, -p[0].date.toordinal(), -p[0].file_path.stat().st_mtime))
|
||
```
|
||
|
||
排序优先级:
|
||
1. 置顶文章优先(`not p.pinned`)
|
||
2. 日期倒序(`-p.date.toordinal()`)
|
||
3. **同日期时,按文件修改时间倒序**(`-p.file_path.stat().st_mtime`)
|
||
|
||
## 验证方式
|
||
|
||
1. 同一天创建 3 篇文章 A、B、C(按此顺序创建)
|
||
2. Admin 页面应显示 C、B、A(最新创建的在前)
|
||
3. 公开首页同样顺序
|
||
4. 修改文章 A 的内容后,A 应排到最前
|
||
|
||
## 注意事项
|
||
|
||
- `st_mtime` 在文件被编辑时会更新,这意味着"最后修改的文章"排最前,不完全是"创建时间"
|
||
- 如果需要严格按创建时间排序,可以考虑在 frontmatter 中增加 `created_at` 字段,但当前用 `st_mtime` 是最小改动方案
|
||
- Canvas 服务已用 `updated_at`(datetime 类型)排序,不存在此问题
|