时间线操作行补真实计数(评论数 / 浏览数),classic 首页同步加操作行
- posts 表加 view_count 列(迁移自动补列),公开文章详情每被拉取 +1; 列表接口子查询带出非删除评论数 - classic 首页文章卡补上操作行(回复 / 赞 / 查看),与 vivid 同行为: 回复跳评论区锚点、赞本机 localStorage、查看进详情; 卡片底部 meta 行的日期不再重复包「查看」链接 - vivid 操作行的回复 / 查看旁展示对应计数(万以上缩写)
This commit is contained in:
1 parent
7171c95275
commit
916dd74034
6 files changed
+102
-12
No files matched your search
@@ -192,6 +192,9 @@ func (a *API) getPost(w http.ResponseWriter, r *http.Request) {
|
||||
httpx.NotFound(w)
|
||||
return
|
||||
}
|
||||
// 浏览数:详情页每被拉取一次 +1(草稿不走这里;不区分访客,博客够用)。
|
||||
// 自增失败静默——计数器丢一次无关紧要,不能让文章因此打不开。
|
||||
a.Store.BumpViewCount(p.ID)
|
||||
// 邻居给详情页侧栏的时间线用;取不到不该让详情页挂掉。
|
||||
nb, err := a.Store.Neighbors(slug)
|
||||
if err != nil {
|
||||
|
||||
@@ -35,6 +35,10 @@ type Post struct {
|
||||
// LinkCard 是正文里第一个外链的预览卡片(发布时抓一次,存 posts.link_card)。
|
||||
// nil = 没有链接或抓取失败,前台不渲染卡片。
|
||||
LinkCard *LinkCard `json:"link_card,omitempty"`
|
||||
// CommentCount 是非删除评论数(列表接口子查询带出,操作行「回复」旁展示)。
|
||||
CommentCount int64 `json:"comment_count"`
|
||||
// ViewCount 是浏览数(公开文章详情每次拉取 +1)。
|
||||
ViewCount int64 `json:"view_count"`
|
||||
}
|
||||
|
||||
// LinkCard 是链接预览卡片:由 internal/linkmeta 抓取,以 JSON 存在 posts 表里。
|
||||
|
||||
@@ -164,6 +164,8 @@ func (s *Store) migrate() error {
|
||||
`ALTER TABLE posts ADD COLUMN images TEXT NOT NULL DEFAULT '[]'`,
|
||||
// 正文首个外链的预览卡片(og 标题/描述/封面),JSON 对象或空串
|
||||
`ALTER TABLE posts ADD COLUMN link_card TEXT NOT NULL DEFAULT ''`,
|
||||
// 浏览数:公开文章详情每被拉取一次 +1(不区分访客,博客场景够用)
|
||||
`ALTER TABLE posts ADD COLUMN view_count INTEGER NOT NULL DEFAULT 0`,
|
||||
// 账号角色:owner(站主,全库唯一)/ reader(评论区访客)
|
||||
`ALTER TABLE users ADD COLUMN role TEXT NOT NULL DEFAULT 'reader'`,
|
||||
// 后台账号密码(provider=admin 的行才有值):多用户改造后密码上库,
|
||||
@@ -580,7 +582,9 @@ const postCols = `id, kind, title, slug, summary, cover_url, content_md, content
|
||||
const listCols = `id, kind, title, slug, summary, cover_url,
|
||||
'' AS content_md,
|
||||
CASE WHEN kind = 'short' THEN content_html ELSE substr(content_html, 1, 600) END AS content_html,
|
||||
status, published_at, created_at, updated_at, reading_minutes, LENGTH(content_md), images, link_card`
|
||||
status, published_at, created_at, updated_at, reading_minutes, LENGTH(content_md), images, link_card,
|
||||
(SELECT COUNT(*) FROM comments c WHERE c.post_id = posts.id AND c.is_deleted = 0) AS comment_count,
|
||||
view_count`
|
||||
|
||||
// images 列的 JSON 编解码(列存 '[]',Go 侧 []string;坏数据静默为空)。
|
||||
func decodeImages(s string) []string {
|
||||
@@ -634,7 +638,7 @@ func scanPost(rows interface{ Scan(...any) error }) (model.Post, error) {
|
||||
var imgs, card string
|
||||
err := rows.Scan(&p.ID, &p.Kind, &p.Title, &p.Slug, &p.Summary, &p.CoverURL,
|
||||
&p.ContentMd, &p.ContentHTML, &p.Status, &p.PublishedAt, &p.CreatedAt, &p.UpdatedAt,
|
||||
&p.ReadingMinutes, &p.ContentLen, &imgs, &card)
|
||||
&p.ReadingMinutes, &p.ContentLen, &imgs, &card, &p.CommentCount, &p.ViewCount)
|
||||
p.Tags = []string{}
|
||||
p.Images = decodeImages(imgs)
|
||||
p.LinkCard = decodeLinkCard(card)
|
||||
@@ -1473,6 +1477,11 @@ func (s *Store) Archive() ([]model.ArchiveYear, error) {
|
||||
return years, nil
|
||||
}
|
||||
|
||||
// BumpViewCount 浏览数自增。静默失败:计数器不该影响文章可读性。
|
||||
func (s *Store) BumpViewCount(id int64) {
|
||||
_, _ = s.db.Exec(s.db.Q(`UPDATE posts SET view_count = view_count + 1 WHERE id = ?`), id)
|
||||
}
|
||||
|
||||
func splitDate(rfc3339 string) (string, string) {
|
||||
if len(rfc3339) < 7 {
|
||||
return "", ""
|
||||
|
||||
Reference in new issue
Block a user