Files
web_template/internal/handler/dashboard.go

353 lines
9.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handler
import (
"strconv"
"gotest/internal/model"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// tableRegistry 映射前端模块名 → GORM 模型(用于通用 CRUD)
var tableRegistry = map[string]interface{}{
// 企业模块
"enterprise_company": &model.Company{},
"enterprise_news": &model.EnterpriseNews{},
"enterprise_services": &model.EnterpriseService{},
"enterprise_team": &model.TeamMember{},
// 电商模块
"shop_products": &model.Product{},
"shop_categories": &model.ProductCategory{},
// 外卖模块
"food_restaurants": &model.Restaurant{},
"food_categories": &model.RestaurantCategory{},
"food_menu_items": &model.MenuItem{},
"food_menu_categories": &model.MenuCategory{},
// 游戏模块
"game_games": &model.Game{},
"game_categories": &model.GameCategory{},
// 应用模块
"app_apps": &model.App{},
"app_categories": &model.AppCategory{},
// 音乐模块
"music_songs": &model.Song{},
"music_categories": &model.MusicCategory{},
}
// tableLabels 模块中文标签(用于前端展示)
var tableLabels = map[string]string{
"enterprise_company": "企业信息",
"enterprise_news": "企业新闻",
"enterprise_services": "企业服务",
"enterprise_team": "团队成员",
"shop_products": "商品管理",
"shop_categories": "商品分类",
"food_restaurants": "餐厅管理",
"food_categories": "餐厅分类",
"food_menu_items": "菜品管理",
"food_menu_categories": "菜品分类",
"game_games": "游戏管理",
"game_categories": "游戏分类",
"app_apps": "应用管理",
"app_categories": "应用分类",
"music_songs": "歌曲管理",
"music_categories": "音乐分类",
}
// tablesWithSort 拥有 sort 列的表(用于排序)
var tablesWithSort = map[string]bool{
"enterprise_services": true,
"enterprise_team": true,
"shop_products": true,
"shop_categories": true,
"food_restaurants": true,
"food_categories": true,
"food_menu_items": true,
"food_menu_categories": true,
"game_games": true,
"game_categories": true,
"app_apps": true,
"app_categories": true,
"music_songs": true,
"music_categories": true,
}
// tablesWithName 拥有 name 列的表(用于关键词搜索)
var tablesWithName = map[string]bool{
"enterprise_company": true,
"enterprise_team": true,
"enterprise_services": false, // 有 title 无 name
"enterprise_news": false,
"shop_products": true,
"shop_categories": true,
"food_restaurants": true,
"food_categories": true,
"food_menu_items": true,
"food_menu_categories": true,
"game_games": true,
"game_categories": true,
"app_apps": true,
"app_categories": true,
"music_songs": false, // 有 title 无 name
"music_categories": true,
}
// tablesWithTitle 拥有 title 列的表(用于关键词搜索)
var tablesWithTitle = map[string]bool{
"enterprise_news": true,
"enterprise_services": true,
"music_songs": true,
}
// tablesWithStatus 拥有 status 列的表(用于状态过滤)
var tablesWithStatus = map[string]bool{
"enterprise_news": true,
"shop_products": true,
"food_restaurants": true,
"food_menu_items": true,
"game_games": true,
"app_apps": true,
"music_songs": true,
}
// DashboardHandler 管理后台仪表盘处理器(通用 CRUD + 统计)
type DashboardHandler struct {
db *gorm.DB
}
// NewDashboardHandler 创建仪表盘处理器
func NewDashboardHandler(db *gorm.DB) *DashboardHandler {
return &DashboardHandler{db: db}
}
// GetStats 获取仪表盘统计数据 GET /api/v1/admin/dashboard/stats
func (h *DashboardHandler) GetStats(c *gin.Context) {
stats := gin.H{}
// 用户统计
var userCount int64
h.db.Model(&model.User{}).Count(&userCount)
stats["users"] = userCount
// 各业务模块统计
for table, modelType := range tableRegistry {
var count int64
h.db.Model(modelType).Count(&count)
stats[table] = count
}
// 按业务线分组
grouped := gin.H{
"enterprise": gin.H{
"label": "企业官网",
"items": gin.H{
"company": stats["enterprise_company"],
"news": stats["enterprise_news"],
"services": stats["enterprise_services"],
"team": stats["enterprise_team"],
},
},
"shop": gin.H{
"label": "跨境电商",
"items": gin.H{
"products": stats["shop_products"],
"categories": stats["shop_categories"],
},
},
"food": gin.H{
"label": "外卖平台",
"items": gin.H{
"restaurants": stats["food_restaurants"],
"categories": stats["food_categories"],
"menu_items": stats["food_menu_items"],
"menu_categories": stats["food_menu_categories"],
},
},
"game": gin.H{
"label": "游戏平台",
"items": gin.H{
"games": stats["game_games"],
"categories": stats["game_categories"],
},
},
"app": gin.H{
"label": "应用商店",
"items": gin.H{
"apps": stats["app_apps"],
"categories": stats["app_categories"],
},
},
"music": gin.H{
"label": "音乐平台",
"items": gin.H{
"songs": stats["music_songs"],
"categories": stats["music_categories"],
},
},
}
Success(c, gin.H{
"total_counts": stats,
"grouped": grouped,
"tables": getTableList(),
})
}
// getTableList 返回所有可管理的表列表
func getTableList() []gin.H {
list := make([]gin.H, 0, len(tableRegistry))
for key := range tableRegistry {
list = append(list, gin.H{
"key": key,
"label": tableLabels[key],
})
}
return list
}
// ListItems 通用列表查询 GET /api/v1/admin/dashboard/:table
func (h *DashboardHandler) ListItems(c *gin.Context) {
table := c.Param("table")
modelType, ok := tableRegistry[table]
if !ok {
FailBadRequest(c, "无效的数据表: "+table)
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
keyword := c.Query("keyword")
status := c.Query("status")
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 20
}
offset := (page - 1) * pageSize
query := h.db.Model(modelType)
// 关键词搜索(根据表实际拥有的列动态构建条件)
if keyword != "" {
hasName := tablesWithName[table]
hasTitle := tablesWithTitle[table]
switch {
case hasName && hasTitle:
query = query.Where("name LIKE ? OR title LIKE ?", "%"+keyword+"%", "%"+keyword+"%")
case hasName:
query = query.Where("name LIKE ?", "%"+keyword+"%")
case hasTitle:
query = query.Where("title LIKE ?", "%"+keyword+"%")
}
}
// 状态过滤(仅对拥有 status 列的表生效)
if status != "" && tablesWithStatus[table] {
query = query.Where("status = ?", status)
}
var total int64
query.Count(&total)
// 排序:有 sort 列的表按 sort ASC, id DESC;否则按 id DESC
orderClause := "id DESC"
if tablesWithSort[table] {
orderClause = "sort ASC, id DESC"
}
var results []map[string]interface{}
if err := query.Order(orderClause).Offset(offset).Limit(pageSize).Find(&results).Error; err != nil {
FailInternal(c, "查询失败: "+err.Error())
return
}
Success(c, gin.H{
"list": results,
"total": total,
"page": page,
"page_size": pageSize,
})
}
// CreateItem 通用创建 POST /api/v1/admin/dashboard/:table
func (h *DashboardHandler) CreateItem(c *gin.Context) {
table := c.Param("table")
modelType, ok := tableRegistry[table]
if !ok {
FailBadRequest(c, "无效的数据表: "+table)
return
}
var body map[string]interface{}
if err := c.ShouldBindJSON(&body); err != nil {
FailBadRequest(c, "参数解析失败")
return
}
if err := h.db.Model(modelType).Create(&body).Error; err != nil {
FailBadRequest(c, "创建失败: "+err.Error())
return
}
Success(c, body)
}
// UpdateItem 通用更新 PUT /api/v1/admin/dashboard/:table/:id
func (h *DashboardHandler) UpdateItem(c *gin.Context) {
table := c.Param("table")
modelType, ok := tableRegistry[table]
if !ok {
FailBadRequest(c, "无效的数据表: "+table)
return
}
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
FailBadRequest(c, "无效的 ID")
return
}
var body map[string]interface{}
if err := c.ShouldBindJSON(&body); err != nil {
FailBadRequest(c, "参数解析失败")
return
}
// 移除不允许更新的字段
delete(body, "id")
delete(body, "created_at")
if err := h.db.Model(modelType).Where("id = ?", id).Updates(body).Error; err != nil {
FailBadRequest(c, "更新失败: "+err.Error())
return
}
SuccessMsg(c, "更新成功")
}
// DeleteItem 通用删除 DELETE /api/v1/admin/dashboard/:table/:id
func (h *DashboardHandler) DeleteItem(c *gin.Context) {
table := c.Param("table")
modelType, ok := tableRegistry[table]
if !ok {
FailBadRequest(c, "无效的数据表: "+table)
return
}
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
FailBadRequest(c, "无效的 ID")
return
}
if err := h.db.Model(modelType).Where("id = ?", id).Delete(nil).Error; err != nil {
FailBadRequest(c, "删除失败: "+err.Error())
return
}
SuccessMsg(c, "删除成功")
}