2025-10-24 00:09:45 +08:00
|
|
|
|
package admin
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"net/http"
|
2025-10-26 14:48:02 +08:00
|
|
|
|
"networkDev/constants"
|
|
|
|
|
|
"networkDev/controllers"
|
2025-10-26 22:28:50 +08:00
|
|
|
|
"networkDev/middleware"
|
2025-10-26 11:57:31 +08:00
|
|
|
|
"networkDev/models"
|
2025-10-24 00:09:45 +08:00
|
|
|
|
"networkDev/services"
|
|
|
|
|
|
"networkDev/utils"
|
|
|
|
|
|
"networkDev/utils/timeutil"
|
|
|
|
|
|
|
2025-10-26 14:48:02 +08:00
|
|
|
|
"github.com/gin-gonic/gin"
|
2025-10-24 00:09:45 +08:00
|
|
|
|
"github.com/spf13/viper"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-10-27 23:12:15 +08:00
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// 全局变量
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
2025-10-26 14:48:02 +08:00
|
|
|
|
// 创建基础控制器实例
|
|
|
|
|
|
var handlersBaseController = controllers.NewBaseController()
|
|
|
|
|
|
|
2025-10-27 23:12:15 +08:00
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// 辅助函数
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
2025-10-26 11:57:31 +08:00
|
|
|
|
// formatDBType 格式化数据库类型显示
|
|
|
|
|
|
// 将配置文件中的小写类型转换为友好的显示格式
|
|
|
|
|
|
func formatDBType(dbType string) string {
|
|
|
|
|
|
switch dbType {
|
|
|
|
|
|
case "mysql":
|
|
|
|
|
|
return "MySQL"
|
|
|
|
|
|
case "sqlite":
|
|
|
|
|
|
return "SQLite"
|
|
|
|
|
|
case "postgresql", "postgres":
|
|
|
|
|
|
return "PostgreSQL"
|
|
|
|
|
|
case "sqlserver":
|
|
|
|
|
|
return "SQL Server"
|
|
|
|
|
|
default:
|
|
|
|
|
|
return "SQLite" // 默认显示
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-27 23:12:15 +08:00
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// 页面处理器
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
2025-10-26 11:57:31 +08:00
|
|
|
|
// AdminIndexHandler 后台首页处理器/admin 与 /admin/ 根路径入口
|
2025-10-24 00:09:45 +08:00
|
|
|
|
// - 未登录:重定向到 /admin/login
|
|
|
|
|
|
// - 已登录:渲染后台布局页(或重定向到 /admin/layout)
|
2025-10-26 01:51:25 +08:00
|
|
|
|
// - 自动清理失效的JWT Cookie
|
2025-10-26 14:48:02 +08:00
|
|
|
|
func AdminIndexHandler(c *gin.Context) {
|
|
|
|
|
|
if IsAdminAuthenticatedWithCleanup(c) {
|
2025-10-24 00:09:45 +08:00
|
|
|
|
// 直接渲染布局页,保持URL为 /admin
|
2025-10-26 14:48:02 +08:00
|
|
|
|
AdminLayoutHandler(c)
|
2025-10-24 00:09:45 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-10-26 14:48:02 +08:00
|
|
|
|
c.Redirect(http.StatusFound, "/admin/login")
|
2025-10-24 00:09:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminLayoutHandler 后台布局页渲染
|
|
|
|
|
|
// - 渲染 layout.html,包含顶部导航、侧边栏与动态内容容器
|
2025-10-26 14:48:02 +08:00
|
|
|
|
func AdminLayoutHandler(c *gin.Context) {
|
2025-10-26 03:05:27 +08:00
|
|
|
|
// 获取或生成CSRF令牌
|
|
|
|
|
|
var token string
|
2025-10-26 14:48:02 +08:00
|
|
|
|
if existingToken := utils.GetCSRFTokenFromCookie(c); existingToken != "" {
|
2025-10-26 03:05:27 +08:00
|
|
|
|
// 重用现有的Cookie令牌
|
|
|
|
|
|
token = existingToken
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 生成新的CSRF令牌并设置到Cookie
|
|
|
|
|
|
newToken, err := utils.GenerateCSRFToken()
|
|
|
|
|
|
if err != nil {
|
2025-10-26 14:48:02 +08:00
|
|
|
|
handlersBaseController.HandleInternalError(c, "生成CSRF令牌失败", err)
|
2025-10-26 03:05:27 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
token = newToken
|
2025-10-26 14:48:02 +08:00
|
|
|
|
utils.SetCSRFToken(c, token)
|
2025-10-26 03:05:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-27 21:06:41 +08:00
|
|
|
|
// 准备模板数据
|
|
|
|
|
|
data := handlersBaseController.GetDefaultTemplateData()
|
|
|
|
|
|
data["CSRFToken"] = token
|
2025-10-24 00:09:45 +08:00
|
|
|
|
|
2025-10-27 21:06:41 +08:00
|
|
|
|
// 从数据库读取站点标题,如果失败则使用默认值
|
|
|
|
|
|
if db, ok := handlersBaseController.GetDB(c); ok {
|
|
|
|
|
|
if siteTitle, err := services.FindSettingByName("site_title", db); err == nil && siteTitle != nil {
|
|
|
|
|
|
data["Title"] = siteTitle.Value
|
2025-10-24 00:09:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-27 21:06:41 +08:00
|
|
|
|
// 合并其他数据(如果有的话)
|
|
|
|
|
|
extraData := gin.H{}
|
2025-10-26 03:05:27 +08:00
|
|
|
|
for key, value := range extraData {
|
|
|
|
|
|
data[key] = value
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-26 14:48:02 +08:00
|
|
|
|
c.HTML(http.StatusOK, "layout.html", data)
|
2025-10-24 00:09:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DashboardFragmentHandler 仪表盘片段渲染
|
2025-10-26 11:57:31 +08:00
|
|
|
|
// - 展示系统信息:版本、开发模式、数据库类型、启动时长
|
2025-10-26 14:48:02 +08:00
|
|
|
|
func DashboardFragmentHandler(c *gin.Context) {
|
|
|
|
|
|
version := constants.AppVersion
|
2025-10-26 22:28:50 +08:00
|
|
|
|
mode := middleware.IsDevModeFromContext(c)
|
2025-10-24 00:09:45 +08:00
|
|
|
|
dbType := viper.GetString("database.type")
|
|
|
|
|
|
if dbType == "" {
|
|
|
|
|
|
dbType = "sqlite"
|
|
|
|
|
|
}
|
|
|
|
|
|
uptime := timeutil.GetServerUptimeString()
|
|
|
|
|
|
|
2025-10-26 14:48:02 +08:00
|
|
|
|
data := gin.H{
|
2025-10-24 00:09:45 +08:00
|
|
|
|
"Version": version,
|
|
|
|
|
|
"Mode": mode,
|
2025-10-26 11:57:31 +08:00
|
|
|
|
"DBType": formatDBType(dbType),
|
2025-10-24 00:09:45 +08:00
|
|
|
|
"Uptime": uptime,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-26 14:48:02 +08:00
|
|
|
|
c.HTML(http.StatusOK, "dashboard.html", data)
|
2025-10-24 00:09:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-27 23:12:15 +08:00
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// API处理器
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
2025-10-24 00:09:45 +08:00
|
|
|
|
// SystemInfoHandler 系统信息API接口
|
|
|
|
|
|
// - 返回系统运行状态的JSON数据,用于前端定时刷新
|
2025-10-26 14:48:02 +08:00
|
|
|
|
func SystemInfoHandler(c *gin.Context) {
|
|
|
|
|
|
version := constants.AppVersion
|
2025-10-26 22:28:50 +08:00
|
|
|
|
mode := middleware.IsDevModeFromContext(c)
|
2025-10-24 00:09:45 +08:00
|
|
|
|
dbType := viper.GetString("database.type")
|
|
|
|
|
|
if dbType == "" {
|
|
|
|
|
|
dbType = "sqlite"
|
|
|
|
|
|
}
|
|
|
|
|
|
uptime := timeutil.GetServerUptimeString()
|
|
|
|
|
|
|
2025-10-26 14:48:02 +08:00
|
|
|
|
data := gin.H{
|
2025-10-24 00:09:45 +08:00
|
|
|
|
"version": version,
|
|
|
|
|
|
"mode": mode,
|
2025-10-26 11:57:31 +08:00
|
|
|
|
"db_type": formatDBType(dbType),
|
2025-10-24 00:09:45 +08:00
|
|
|
|
"uptime": uptime,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-26 14:48:02 +08:00
|
|
|
|
handlersBaseController.HandleSuccess(c, "ok", data)
|
2025-10-24 00:09:45 +08:00
|
|
|
|
}
|
2025-10-26 11:57:31 +08:00
|
|
|
|
|
|
|
|
|
|
// DashboardStatsHandler 仪表盘统计数据API接口
|
|
|
|
|
|
// - 返回应用统计数据的JSON数据,包括全部/启用/禁用/变量数量
|
2025-10-26 14:48:02 +08:00
|
|
|
|
func DashboardStatsHandler(c *gin.Context) {
|
2025-10-26 11:57:31 +08:00
|
|
|
|
// 获取数据库连接
|
2025-10-26 14:48:02 +08:00
|
|
|
|
db, ok := handlersBaseController.GetDB(c)
|
|
|
|
|
|
if !ok {
|
2025-10-26 11:57:31 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 统计应用数据
|
|
|
|
|
|
var totalApps int64
|
|
|
|
|
|
var enabledApps int64
|
|
|
|
|
|
var disabledApps int64
|
|
|
|
|
|
var totalVariables int64
|
|
|
|
|
|
|
|
|
|
|
|
// 统计全部应用数量
|
|
|
|
|
|
if err := db.Model(&models.App{}).Count(&totalApps).Error; err != nil {
|
2025-10-26 14:48:02 +08:00
|
|
|
|
handlersBaseController.HandleInternalError(c, "统计应用数量失败", err)
|
2025-10-26 11:57:31 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 统计启用应用数量
|
|
|
|
|
|
if err := db.Model(&models.App{}).Where("status = ?", 1).Count(&enabledApps).Error; err != nil {
|
2025-10-26 14:48:02 +08:00
|
|
|
|
handlersBaseController.HandleInternalError(c, "统计启用应用数量失败", err)
|
2025-10-26 11:57:31 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 统计禁用应用数量
|
|
|
|
|
|
if err := db.Model(&models.App{}).Where("status = ?", 0).Count(&disabledApps).Error; err != nil {
|
2025-10-26 14:48:02 +08:00
|
|
|
|
handlersBaseController.HandleInternalError(c, "统计禁用应用数量失败", err)
|
2025-10-26 11:57:31 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 统计变量数量
|
|
|
|
|
|
if err := db.Model(&models.Variable{}).Count(&totalVariables).Error; err != nil {
|
2025-10-26 14:48:02 +08:00
|
|
|
|
handlersBaseController.HandleInternalError(c, "统计变量数量失败", err)
|
2025-10-26 11:57:31 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-26 14:48:02 +08:00
|
|
|
|
data := gin.H{
|
2025-10-26 11:57:31 +08:00
|
|
|
|
"total_apps": totalApps,
|
|
|
|
|
|
"enabled_apps": enabledApps,
|
|
|
|
|
|
"disabled_apps": disabledApps,
|
|
|
|
|
|
"total_variables": totalVariables,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-26 14:48:02 +08:00
|
|
|
|
handlersBaseController.HandleSuccess(c, "ok", data)
|
2025-10-26 11:57:31 +08:00
|
|
|
|
}
|