feat(db): add word_count and reading_time columns to posts

This commit is contained in:
xfy 2026-06-17 16:06:21 +08:00
parent 51e20980db
commit a6f08d5d3f
3 changed files with 24 additions and 4 deletions

View File

@ -0,0 +1,8 @@
-- 为 posts 表添加字数与阅读时长列。
--
-- 旧数据默认 0在管理员执行重建或编辑文章后自动回填。
-- 0 也被 row_to_post_full 用作“未计算”标记,触发基于 content_md 的回退计算。
ALTER TABLE posts
ADD COLUMN IF NOT EXISTS word_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS reading_time INTEGER NOT NULL DEFAULT 0;

View File

@ -91,6 +91,10 @@ pub async fn create_post(
let post_status = PostStatus::from_str(&status).unwrap_or(PostStatus::Draft);
let cover_image = cover_image.filter(|s| !s.trim().is_empty());
// 计算字数与阅读时长,随文章一并持久化,供列表查询直接使用。
let word_count = crate::utils::text::count_words(&content_md);
let reading_time = (word_count / 200).max(1);
// 发布状态的文章设置当前发布时间;草稿则为 None。
let published_at = if post_status == PostStatus::Published {
Some(chrono::Utc::now())
@ -106,8 +110,8 @@ pub async fn create_post(
// 插入文章记录。
let row = tx
.query_one(
"INSERT INTO posts (author_id, title, slug, summary, content_md, content_html, toc_html, status, published_at, cover_image)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
"INSERT INTO posts (author_id, title, slug, summary, content_md, content_html, toc_html, status, published_at, cover_image, word_count, reading_time)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
RETURNING id",
&[
&user.id,
@ -120,6 +124,8 @@ pub async fn create_post(
&post_status.as_str(),
&published_at,
&cover_image,
&(word_count as i32),
&(reading_time as i32),
],
)
.await

View File

@ -55,6 +55,10 @@ pub async fn update_post(
let post_status = PostStatus::from_str(&status).unwrap_or(PostStatus::Draft);
let cover_image = cover_image.filter(|s| !s.trim().is_empty());
// 重新计算字数与阅读时长,保持与正文同步。
let word_count = crate::utils::text::count_words(&content_md);
let reading_time = (word_count / 200).max(1);
let tx = client.transaction().await.map_err(AppError::tx)?;
// 查询旧 slug用于后续缓存失效。
@ -150,8 +154,8 @@ pub async fn update_post(
// 更新文章主表。
let updated = tx
.execute(
"UPDATE posts SET title = $1, slug = $2, summary = $3, content_md = $4, content_html = $5, toc_html = $6, status = $7, published_at = $8, cover_image = $9, updated_at = NOW()
WHERE id = $10",
"UPDATE posts SET title = $1, slug = $2, summary = $3, content_md = $4, content_html = $5, toc_html = $6, status = $7, published_at = $8, cover_image = $9, word_count = $10, reading_time = $11, updated_at = NOW()
WHERE id = $12",
&[
&title.trim(),
&final_slug,
@ -162,6 +166,8 @@ pub async fn update_post(
&post_status.as_str(),
&published_at,
&cover_image,
&(word_count as i32),
&(reading_time as i32),
&post_id,
],
)