package handlers import ( "html/template" "math" "net/http" "strconv" "time" "goblog/config" "goblog/database" "goblog/models" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // 模板函数 func templateFuncs() template.FuncMap { return template.FuncMap{ "add": func(a, b int) int { return a + b }, "sub": func(a, b int) int { return a - b }, "html": func(s string) template.HTML { return template.HTML(s) }, } } // 初始化模板 - 返回 gin 可用的 HTMLRender func InitTemplates(theme string) (*template.Template, error) { tmpl, err := template.New("").Funcs(templateFuncs()).ParseGlob("templates/" + theme + "/*.html") return tmpl, err } // 首页 type IndexData struct { Title string SiteName string SiteDesc string Description string Posts []models.Post Pages []models.Page CurrentPage int TotalPages int Year int } func IndexView(c *gin.Context) { cfg := config.Load() page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) if page < 1 { page = 1 } pageSize := 10 categoryID, _ := strconv.Atoi(c.Query("category")) tagID, _ := strconv.Atoi(c.Query("tag")) db := database.DB.Model(&models.Post{}).Preload("Category").Preload("Tags").Preload("Author"). Where("status = ?", "published"). Where("published_at IS NOT NULL") if categoryID > 0 { db = db.Where("category_id = ?", categoryID) } if tagID > 0 { db = db.Joins("JOIN post_tags ON post_tags.post_id = posts.id"). Where("post_tags.tag_id = ?", tagID) } var total int64 db.Count(&total) var posts []models.Post offset := (page - 1) * pageSize db.Order("is_top DESC, published_at DESC, created_at DESC"). Offset(offset).Limit(pageSize).Find(&posts) // 获取页面 var pages []models.Page database.DB.Where("status = ?", "published").Order("`order` ASC").Find(&pages) totalPages := int(math.Ceil(float64(total) / float64(pageSize))) data := IndexData{ Title: "首页", SiteName: cfg.App.Name, SiteDesc: cfg.App.Description, Description: cfg.App.Description, Posts: posts, Pages: pages, CurrentPage: page, TotalPages: totalPages, Year: time.Now().Year(), } c.HTML(http.StatusOK, "base.html", data) } // 文章详情页 type PostDetailData struct { Title string SiteName string SiteDesc string Description string Post models.Post Pages []models.Page Comments []models.Comment CommentCount int64 Year int } func PostView(c *gin.Context) { cfg := config.Load() slug := c.Param("slug") var post models.Post err := database.DB.Preload("Category").Preload("Tags").Preload("Author"). Preload("Comments", func(db *gorm.DB) *gorm.DB { return db.Where("status = ? AND parent_id IS NULL", "approved").Preload("Children", func(db *gorm.DB) *gorm.DB { return db.Where("status = ?", "approved") }) }). Where("slug = ? AND status = ?", slug, "published"). First(&post).Error if err != nil { c.HTML(http.StatusNotFound, "base.html", gin.H{ "Title": "404 - 页面不存在", "SiteName": cfg.App.Name, "Year": time.Now().Year(), }) return } // 增加浏览量 database.DB.Model(&post).UpdateColumn("views", gorm.Expr("views + 1")) // 获取页面 var pages []models.Page database.DB.Where("status = ?", "published").Order("`order` ASC").Find(&pages) // 统计评论数 var commentCount int64 database.DB.Model(&models.Comment{}).Where("post_id = ? AND status = ?", post.ID, "approved").Count(&commentCount) data := PostDetailData{ Title: post.Title, SiteName: cfg.App.Name, SiteDesc: cfg.App.Description, Description: post.Summary, Post: post, Pages: pages, Comments: post.Comments, CommentCount: commentCount, Year: time.Now().Year(), } c.HTML(http.StatusOK, "base.html", data) } // 独立页面 type PageDetailData struct { Title string SiteName string SiteDesc string Description string Page models.Page Pages []models.Page Year int } func PageView(c *gin.Context) { cfg := config.Load() slug := c.Param("slug") var page models.Page err := database.DB.Where("slug = ? AND status = ?", slug, "published").First(&page).Error if err != nil { c.HTML(http.StatusNotFound, "base.html", gin.H{ "Title": "404 - 页面不存在", "SiteName": cfg.App.Name, "Year": time.Now().Year(), }) return } // 获取所有页面 var pages []models.Page database.DB.Where("status = ?", "published").Order("`order` ASC").Find(&pages) data := PageDetailData{ Title: page.Title, SiteName: cfg.App.Name, SiteDesc: cfg.App.Description, Description: "", Page: page, Pages: pages, Year: time.Now().Year(), } c.HTML(http.StatusOK, "base.html", data) } // 提交评论(表单提交) func SubmitComment(c *gin.Context) { postID, _ := strconv.Atoi(c.PostForm("post_id")) author := c.PostForm("author") email := c.PostForm("email") website := c.PostForm("website") content := c.PostForm("content") // 检查文章是否存在 var post models.Post if err := database.DB.First(&post, postID).Error; err != nil { c.String(http.StatusBadRequest, "文章不存在") return } comment := models.Comment{ PostID: uint(postID), Author: author, Email: email, Website: website, Content: content, IP: c.ClientIP(), Status: "pending", } if err := database.DB.Create(&comment).Error; err != nil { c.String(http.StatusInternalServerError, "发表评论失败") return } c.Redirect(http.StatusFound, "/post/"+post.Slug+"#comment-"+strconv.Itoa(int(comment.ID))) }