feat: 分类系统 + 标签系统 — Phase 4 完成

分类:Model/Repo/Service/Controller + 管理后台树形页面 + 首页导航栏
标签:Model/Repo/Service/Controller + /tags/{slug} 落地页 + 写文章页输入
Post 加 CategoryID,Create/Update 支持分类和标签
SQL 迁移含 categories/tags/post_tags 表及预设未分类
This commit is contained in:
2026-06-22 00:30:29 +08:00
parent 977c52513a
commit 0b8f6f890d
30 changed files with 988 additions and 13 deletions

View File

@ -33,6 +33,7 @@ func setupAdminRoutes(r *gin.Engine, cfg *config.Config, d *dependencies) {
adminPages.GET("/energy/fund-logs", d.adminEnergyCtrl.FundLogPage)
adminPages.GET("/comments", d.adminCommentCtrl.CommentsPage)
adminPages.GET("/announcements", d.announcementCtrl.Page)
adminPages.GET("/categories", d.categoryCtrl.Page)
}
// --- 管理后台 API ---
@ -115,4 +116,17 @@ func setupAdminRoutes(r *gin.Engine, cfg *config.Config, d *dependencies) {
announcementAPI.PUT("/:id", d.announcementCtrl.Update)
announcementAPI.DELETE("/:id", d.announcementCtrl.Delete)
}
// --- 分类管理 APImoderator+ ---
categoryAPI := r.Group("/api/admin/categories")
categoryAPI.Use(d.authMdw.Required())
categoryAPI.Use(middleware.RequireMinRole(model.RoleModerator))
categoryAPI.Use(d.authMdw.BannedWriteGuard())
categoryAPI.Use(middleware.CSRF(cfg))
{
categoryAPI.GET("", d.categoryCtrl.List)
categoryAPI.POST("", d.categoryCtrl.Create)
categoryAPI.PUT("/:id", d.categoryCtrl.Update)
categoryAPI.DELETE("/:id", d.categoryCtrl.Delete)
}
}

View File

@ -47,6 +47,10 @@ type dependencies struct {
homeCache *cache.HomePageCache
announcementService *service.AnnouncementService
announcementCtrl *adminCtrl.AnnouncementController
categoryCtrl *adminCtrl.CategoryController
categoryService *service.CategoryService
tagCtrl *controller.TagController
tagService *service.TagService
}
func buildDepsCore(db *gorm.DB, cfg *config.Config, siteSettings *config.SiteSettings, redisClient *redis.Client) (

View File

@ -103,6 +103,18 @@ func buildDeps(db *gorm.DB, cfg *config.Config, siteSettings *config.SiteSetting
maintenanceMdw := middleware.NewMaintenanceMiddleware(cfg, siteSettings, sessionMgr)
// 分类系统
categoryRepo := repository.NewCategoryRepo(db)
categoryService := service.NewCategoryService(categoryRepo)
categoryCtrl := adminCtrl.NewCategoryController(categoryService)
studioCtrl.WithCategoryService(categoryService)
// 标签系统
tagRepo := repository.NewTagRepo(db)
tagService := service.NewTagService(tagRepo)
tagCtrl := controller.NewTagController(tagService)
studioCtrl.WithTagService(tagService)
// 公告系统
announcementRepo := repository.NewAnnouncementRepo(db)
announcementService := service.NewAnnouncementService(announcementRepo)
@ -135,5 +147,9 @@ func buildDeps(db *gorm.DB, cfg *config.Config, siteSettings *config.SiteSetting
homeCache: homeCache,
announcementService: announcementService,
announcementCtrl: announcementCtrl,
categoryCtrl: categoryCtrl,
categoryService: categoryService,
tagCtrl: tagCtrl,
tagService: tagService,
}
}

View File

@ -34,12 +34,14 @@ func setupFrontendRoutes(r *gin.Engine, cfg *config.Config, d *dependencies) {
}
}
announcements, _ := d.announcementService.ListActive()
categoryNav, _ := d.categoryService.GetLeaves()
c.HTML(http.StatusOK, "home/index.html", common.BuildPageData(c, gin.H{
"Title": "首页",
"ExtraCSS": "/static/css/home.css",
"Posts": posts,
"PostCount": total,
"Announcements": announcements,
"CategoryNav": categoryNav,
}))
})
@ -56,6 +58,9 @@ func setupFrontendRoutes(r *gin.Engine, cfg *config.Config, d *dependencies) {
// 帖子页面
pages.GET("/posts", d.postCtrl.ListPage)
pages.GET("/posts/:id", d.postCtrl.ShowPage)
// 标签落地页
pages.GET("/tags/:slug", d.tagCtrl.TagPage)
pages.GET("/posts/:id/edit", d.authMdw.Required(), func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/studio/write?id="+c.Param("id"))
})