Use the gin framework

This commit is contained in:
2025-10-26 14:48:02 +08:00
parent 9e0eb1497b
commit d844403505
29 changed files with 1612 additions and 1858 deletions

View File

@@ -2,15 +2,20 @@ package admin
import (
"net/http"
"networkDev/database"
"networkDev/constants"
"networkDev/controllers"
"networkDev/models"
"networkDev/services"
"networkDev/utils"
"networkDev/utils/timeutil"
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
)
// 创建基础控制器实例
var handlersBaseController = controllers.NewBaseController()
// formatDBType 格式化数据库类型显示
// 将配置文件中的小写类型转换为友好的显示格式
func formatDBType(dbType string) string {
@@ -32,40 +37,40 @@ func formatDBType(dbType string) string {
// - 未登录:重定向到 /admin/login
// - 已登录:渲染后台布局页(或重定向到 /admin/layout
// - 自动清理失效的JWT Cookie
func AdminIndexHandler(w http.ResponseWriter, r *http.Request) {
if IsAdminAuthenticatedWithCleanup(w, r) {
func AdminIndexHandler(c *gin.Context) {
if IsAdminAuthenticatedWithCleanup(c) {
// 直接渲染布局页保持URL为 /admin
AdminLayoutHandler(w, r)
AdminLayoutHandler(c)
return
}
http.Redirect(w, r, "/admin/login", http.StatusFound)
c.Redirect(http.StatusFound, "/admin/login")
}
// AdminLayoutHandler 后台布局页渲染
// - 渲染 layout.html包含顶部导航、侧边栏与动态内容容器
func AdminLayoutHandler(w http.ResponseWriter, r *http.Request) {
func AdminLayoutHandler(c *gin.Context) {
// 获取或生成CSRF令牌
var token string
if existingToken := utils.GetCSRFTokenFromCookie(r); existingToken != "" {
if existingToken := utils.GetCSRFTokenFromCookie(c); existingToken != "" {
// 重用现有的Cookie令牌
token = existingToken
} else {
// 生成新的CSRF令牌并设置到Cookie
newToken, err := utils.GenerateCSRFToken()
if err != nil {
http.Error(w, "生成CSRF令牌失败", http.StatusInternalServerError)
handlersBaseController.HandleInternalError(c, "生成CSRF令牌失败", err)
return
}
token = newToken
utils.SetCSRFToken(w, token)
utils.SetCSRFToken(c, token)
}
// 准备额外的模板数据
extraData := make(map[string]interface{})
extraData := gin.H{}
// 从数据库读取站点标题
db, dbErr := database.GetDB()
if dbErr != nil {
db, ok := handlersBaseController.GetDB(c)
if !ok {
extraData["Title"] = "凌动技术"
} else {
siteTitle, settingErr := services.FindSettingByName("site_title", db)
@@ -77,7 +82,7 @@ func AdminLayoutHandler(w http.ResponseWriter, r *http.Request) {
}
// 准备模板数据
data := utils.GetDefaultTemplateData()
data := handlersBaseController.GetDefaultTemplateData()
data["CSRFToken"] = token
// 合并额外数据
@@ -85,13 +90,13 @@ func AdminLayoutHandler(w http.ResponseWriter, r *http.Request) {
data[key] = value
}
utils.RenderTemplate(w, "layout.html", data)
c.HTML(http.StatusOK, "layout.html", data)
}
// DashboardFragmentHandler 仪表盘片段渲染
// - 展示系统信息:版本、开发模式、数据库类型、启动时长
func DashboardFragmentHandler(w http.ResponseWriter, r *http.Request) {
version := "1.0.0"
func DashboardFragmentHandler(c *gin.Context) {
version := constants.AppVersion
mode := viper.GetBool("server.dev_mode")
dbType := viper.GetString("database.type")
if dbType == "" {
@@ -99,25 +104,20 @@ func DashboardFragmentHandler(w http.ResponseWriter, r *http.Request) {
}
uptime := timeutil.GetServerUptimeString()
data := map[string]interface{}{
data := gin.H{
"Version": version,
"Mode": mode,
"DBType": formatDBType(dbType),
"Uptime": uptime,
}
utils.RenderTemplate(w, "dashboard.html", data)
c.HTML(http.StatusOK, "dashboard.html", data)
}
// SystemInfoHandler 系统信息API接口
// - 返回系统运行状态的JSON数据用于前端定时刷新
func SystemInfoHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
return
}
version := "1.0.0"
func SystemInfoHandler(c *gin.Context) {
version := constants.AppVersion
mode := viper.GetBool("server.dev_mode")
dbType := viper.GetString("database.type")
if dbType == "" {
@@ -125,28 +125,22 @@ func SystemInfoHandler(w http.ResponseWriter, r *http.Request) {
}
uptime := timeutil.GetServerUptimeString()
data := map[string]interface{}{
data := gin.H{
"version": version,
"mode": mode,
"db_type": formatDBType(dbType),
"uptime": uptime,
}
utils.JsonResponse(w, http.StatusOK, true, "ok", data)
handlersBaseController.HandleSuccess(c, "ok", data)
}
// DashboardStatsHandler 仪表盘统计数据API接口
// - 返回应用统计数据的JSON数据包括全部/启用/禁用/变量数量
func DashboardStatsHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
return
}
func DashboardStatsHandler(c *gin.Context) {
// 获取数据库连接
db, err := database.GetDB()
if err != nil {
utils.JsonResponse(w, http.StatusInternalServerError, false, "数据库连接失败", nil)
db, ok := handlersBaseController.GetDB(c)
if !ok {
return
}
@@ -158,34 +152,34 @@ func DashboardStatsHandler(w http.ResponseWriter, r *http.Request) {
// 统计全部应用数量
if err := db.Model(&models.App{}).Count(&totalApps).Error; err != nil {
utils.JsonResponse(w, http.StatusInternalServerError, false, "统计应用数量失败", nil)
handlersBaseController.HandleInternalError(c, "统计应用数量失败", err)
return
}
// 统计启用应用数量
if err := db.Model(&models.App{}).Where("status = ?", 1).Count(&enabledApps).Error; err != nil {
utils.JsonResponse(w, http.StatusInternalServerError, false, "统计启用应用数量失败", nil)
handlersBaseController.HandleInternalError(c, "统计启用应用数量失败", err)
return
}
// 统计禁用应用数量
if err := db.Model(&models.App{}).Where("status = ?", 0).Count(&disabledApps).Error; err != nil {
utils.JsonResponse(w, http.StatusInternalServerError, false, "统计禁用应用数量失败", nil)
handlersBaseController.HandleInternalError(c, "统计禁用应用数量失败", err)
return
}
// 统计变量数量
if err := db.Model(&models.Variable{}).Count(&totalVariables).Error; err != nil {
utils.JsonResponse(w, http.StatusInternalServerError, false, "统计变量数量失败", nil)
handlersBaseController.HandleInternalError(c, "统计变量数量失败", err)
return
}
data := map[string]interface{}{
data := gin.H{
"total_apps": totalApps,
"enabled_apps": enabledApps,
"disabled_apps": disabledApps,
"total_variables": totalVariables,
}
utils.JsonResponse(w, http.StatusOK, true, "ok", data)
handlersBaseController.HandleSuccess(c, "ok", data)
}