Files
NetworkAuth/controllers/admin/dashboard.go

247 lines
6.8 KiB
Go
Raw Normal View History

2025-10-24 00:09:45 +08:00
package admin
import (
2026-03-18 21:51:17 +08:00
"NetworkAuth/constants"
"NetworkAuth/controllers"
"NetworkAuth/middleware"
"NetworkAuth/models"
"NetworkAuth/services"
"NetworkAuth/utils"
"NetworkAuth/utils/timeutil"
2025-10-24 00:09:45 +08:00
"net/http"
2026-03-18 21:51:17 +08:00
"strconv"
2025-10-24 00:09:45 +08:00
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
// - 自动清理失效的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) {
// 获取或生成CSRF令牌
var token string
2025-10-26 14:48:02 +08:00
if existingToken := utils.GetCSRFTokenFromCookie(c); existingToken != "" {
// 重用现有的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)
return
}
token = newToken
2025-10-26 14:48:02 +08:00
utils.SetCSRFToken(c, token)
}
// 准备模板数据
data := handlersBaseController.GetDefaultTemplateData()
data["CSRFToken"] = token
2025-10-24 00:09:45 +08:00
// 从数据库读取站点标题,如果失败则使用默认值
2026-03-18 21:51:17 +08:00
settingsSvc := services.GetSettingsService()
data["Title"] = settingsSvc.GetString("site_title", "后台管理")
2025-10-24 00:09:45 +08:00
// 合并其他数据(如果有的话)
extraData := gin.H{}
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
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
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
}
2026-03-18 21:51:17 +08:00
// DashboardLoginLogsHandler 获取管理员最近登录日志
func DashboardLoginLogsHandler(c *gin.Context) {
db, ok := handlersBaseController.GetDB(c)
if !ok {
return
}
// 获取分页参数
pageStr := c.DefaultQuery("page", "1")
limitStr := c.DefaultQuery("limit", "10")
page, _ := strconv.Atoi(pageStr)
limit, _ := strconv.Atoi(limitStr)
if page < 1 {
page = 1
}
if limit < 1 || limit > 100 {
limit = 10
}
offset := (page - 1) * limit
2026-03-19 05:11:44 +08:00
// 获取当前管理员信息(可能是 username 或 admin_username具体取决于认证中间件设置的 key
username := c.GetString("admin_username")
if username == "" {
// 尝试获取其他可能的键名
username = c.GetString("username")
}
2026-03-18 21:51:17 +08:00
var total int64
2026-03-19 05:11:44 +08:00
query := db.Model(&models.LoginLog{}).Where("type = ?", "admin")
// 如果有用户名,则仅过滤该用户的日志
if username != "" {
query = query.Where("username = ?", username)
}
2026-03-18 21:51:17 +08:00
if err := query.Count(&total).Error; err != nil {
handlersBaseController.HandleInternalError(c, "获取登录日志总数失败", err)
return
}
var logs []models.LoginLog
if err := query.Order("created_at desc").Offset(offset).Limit(limit).Find(&logs).Error; err != nil {
handlersBaseController.HandleInternalError(c, "获取登录日志列表失败", err)
return
}
data := gin.H{
"total": total,
"list": logs,
}
handlersBaseController.HandleSuccess(c, "获取登录日志成功", data)
}
2026-03-19 05:11:44 +08:00