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

@ -0,0 +1,100 @@
package admin
import (
"net/http"
"strconv"
"metazone.cc/mce/internal/common"
"metazone.cc/mce/internal/model"
"github.com/gin-gonic/gin"
)
// CategoryController 分类管理控制器
type CategoryController struct {
svc categoryUseCase
}
type categoryUseCase interface {
Create(c *model.Category) error
Update(c *model.Category) error
Delete(id uint) error
Tree() ([]model.Category, error)
}
// NewCategoryController 构造函数
func NewCategoryController(svc categoryUseCase) *CategoryController {
return &CategoryController{svc: svc}
}
// Page 分类管理页面
func (cc *CategoryController) Page(c *gin.Context) {
tree, _ := cc.svc.Tree()
c.HTML(http.StatusOK, "admin/categories/index.html", common.BuildAdminPageData(c, gin.H{
"Title": "分类管理",
"ExtraCSS": "/admin/static/css/categories.css",
"ExtraJS": "/admin/static/js/categories.js",
"Tree": tree,
}))
}
// List 分类列表 API
func (cc *CategoryController) List(c *gin.Context) {
tree, err := cc.svc.Tree()
if err != nil {
common.Error(c, http.StatusInternalServerError, "查询失败")
return
}
if tree == nil {
tree = []model.Category{}
}
common.Ok(c, tree)
}
// Create 创建分类
func (cc *CategoryController) Create(c *gin.Context) {
var req model.Category
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, http.StatusBadRequest, "参数错误")
return
}
if err := cc.svc.Create(&req); err != nil {
common.Error(c, http.StatusInternalServerError, "创建失败")
return
}
common.OkMessage(c, "分类已创建")
}
// Update 更新分类
func (cc *CategoryController) Update(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的 ID")
return
}
var req model.Category
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, http.StatusBadRequest, "参数错误")
return
}
req.ID = uint(id)
if err := cc.svc.Update(&req); err != nil {
common.Error(c, http.StatusInternalServerError, "更新失败")
return
}
common.OkMessage(c, "分类已更新")
}
// Delete 删除分类
func (cc *CategoryController) Delete(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的 ID")
return
}
if err := cc.svc.Delete(uint(id)); err != nil {
common.Error(c, http.StatusInternalServerError, "删除失败")
return
}
common.OkMessage(c, "分类已删除")
}