feat: 站点单页、时间线导入与行级 BBCode 短代码

首页右栏接入单页入口与公告置顶/全部页;Markdown 编辑器支持可视化时间线与 Git 导入;隐藏块改为 [hide]/[timeline] 命名闭合,并修复单页/公告 GORM 更新只改 updated_at 的问题。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-17 19:52:06 +08:00
parent 2aacf99a49
commit a83276060f
52 changed files with 5073 additions and 648 deletions

View File

@@ -51,6 +51,7 @@ type AnnouncementItem struct {
Title string `json:"title"`
Tag string `json:"tag"`
TagColor string `json:"tag_color"`
Pinned bool `json:"pinned"`
CreatedAt time.Time `json:"created_at"`
}
@@ -65,13 +66,15 @@ type NewUserItem struct {
// OverviewData 首页聚合数据
type OverviewData struct {
Stats OverviewStats `json:"stats"`
Hot []PostListItem `json:"hot"`
ActiveUsers []ActiveUser `json:"active_users"`
Boards []BoardCount `json:"boards"`
Announcements []AnnouncementItem `json:"announcements"`
NewUsers []NewUserItem `json:"new_users"`
Checkin *CheckinStatus `json:"checkin,omitempty"`
Stats OverviewStats `json:"stats"`
Hot []PostListItem `json:"hot"`
ActiveUsers []ActiveUser `json:"active_users"`
Boards []BoardCount `json:"boards"`
Announcements []AnnouncementItem `json:"announcements"`
AnnouncementsTotal int64 `json:"announcements_total"`
SidebarPages []SidebarPageItem `json:"sidebar_pages"`
NewUsers []NewUserItem `json:"new_users"`
Checkin *CheckinStatus `json:"checkin,omitempty"`
}
const (
@@ -98,6 +101,7 @@ func (s *OverviewService) Get() (*OverviewData, error) {
ActiveUsers: []ActiveUser{},
Boards: []BoardCount{},
Announcements: []AnnouncementItem{},
SidebarPages: []SidebarPageItem{},
NewUsers: []NewUserItem{},
}
@@ -230,10 +234,14 @@ LIMIT 5`
data.Boards = append(data.Boards, BoardCount{Board: b, PostCount: countMap[b.ID]})
}
// 站点公告(已发布,最新 5 条)
// 站点公告(已发布,置顶优先,最新 5 条)+ 总数
if err := s.db.Model(&model.Announcement{}).Where("published = ?", true).
Count(&data.AnnouncementsTotal).Error; err != nil {
return nil, err
}
var anns []model.Announcement
if err := s.db.Where("published = ?", true).
Order("created_at DESC, id DESC").Limit(5).Find(&anns).Error; err != nil {
Order("pinned DESC, created_at DESC, id DESC").Limit(5).Find(&anns).Error; err != nil {
return nil, err
}
for _, a := range anns {
@@ -242,10 +250,25 @@ LIMIT 5`
Title: a.Title,
Tag: a.Tag,
TagColor: a.TagColor,
Pinned: a.Pinned,
CreatedAt: a.CreatedAt,
})
}
// 侧栏单页入口(已发布且勾选侧栏)
var pages []model.SitePage
if err := s.db.Where("published = ? AND show_in_sidebar = ?", true, true).
Order("sort_order ASC, id ASC").
Select("id", "slug", "title", "excerpt").
Find(&pages).Error; err != nil {
return nil, err
}
for _, p := range pages {
data.SidebarPages = append(data.SidebarPages, SidebarPageItem{
ID: p.ID, Slug: p.Slug, Title: p.Title, Excerpt: p.Excerpt,
})
}
// 最新注册成员
var newUsers []model.User
if err := s.db.Select("id, username, nickname, avatar, created_at").