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)))
}