2025-10-24 00:09:45 +08:00
|
|
|
|
package admin
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
"networkDev/database"
|
|
|
|
|
|
"networkDev/services"
|
|
|
|
|
|
"networkDev/utils"
|
|
|
|
|
|
"networkDev/utils/timeutil"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/spf13/viper"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// AdminIndexHandler /admin 与 /admin/ 根路径入口
|
|
|
|
|
|
// - 未登录:重定向到 /admin/login
|
|
|
|
|
|
// - 已登录:渲染后台布局页(或重定向到 /admin/layout)
|
2025-10-26 01:51:25 +08:00
|
|
|
|
// - 自动清理失效的JWT Cookie
|
2025-10-24 00:09:45 +08:00
|
|
|
|
func AdminIndexHandler(w http.ResponseWriter, r *http.Request) {
|
2025-10-26 01:51:25 +08:00
|
|
|
|
if IsAdminAuthenticatedWithCleanup(w, r) {
|
2025-10-24 00:09:45 +08:00
|
|
|
|
// 直接渲染布局页,保持URL为 /admin
|
|
|
|
|
|
AdminLayoutHandler(w, r)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
http.Redirect(w, r, "/admin/login", http.StatusFound)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminLayoutHandler 后台布局页渲染
|
|
|
|
|
|
// - 渲染 layout.html,包含顶部导航、侧边栏与动态内容容器
|
|
|
|
|
|
func AdminLayoutHandler(w http.ResponseWriter, r *http.Request) {
|
2025-10-26 03:05:27 +08:00
|
|
|
|
// 获取或生成CSRF令牌
|
|
|
|
|
|
var token string
|
|
|
|
|
|
if existingToken := utils.GetCSRFTokenFromCookie(r); existingToken != "" {
|
|
|
|
|
|
// 重用现有的Cookie令牌
|
|
|
|
|
|
token = existingToken
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 生成新的CSRF令牌并设置到Cookie
|
|
|
|
|
|
newToken, err := utils.GenerateCSRFToken()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
http.Error(w, "生成CSRF令牌失败", http.StatusInternalServerError)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
token = newToken
|
|
|
|
|
|
utils.SetCSRFToken(w, token)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 准备额外的模板数据
|
|
|
|
|
|
extraData := make(map[string]interface{})
|
2025-10-24 00:09:45 +08:00
|
|
|
|
|
|
|
|
|
|
// 从数据库读取站点标题
|
2025-10-26 03:05:27 +08:00
|
|
|
|
db, dbErr := database.GetDB()
|
|
|
|
|
|
if dbErr != nil {
|
|
|
|
|
|
extraData["Title"] = "凌动技术"
|
2025-10-24 00:09:45 +08:00
|
|
|
|
} else {
|
2025-10-26 03:05:27 +08:00
|
|
|
|
siteTitle, settingErr := services.FindSettingByName("site_title", db)
|
|
|
|
|
|
if settingErr != nil || siteTitle == nil {
|
|
|
|
|
|
extraData["Title"] = "凌动技术"
|
2025-10-24 00:09:45 +08:00
|
|
|
|
} else {
|
2025-10-26 03:05:27 +08:00
|
|
|
|
extraData["Title"] = siteTitle.Value
|
2025-10-24 00:09:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-26 03:05:27 +08:00
|
|
|
|
// 准备模板数据
|
|
|
|
|
|
data := utils.GetDefaultTemplateData()
|
|
|
|
|
|
data["CSRFToken"] = token
|
|
|
|
|
|
|
|
|
|
|
|
// 合并额外数据
|
|
|
|
|
|
for key, value := range extraData {
|
|
|
|
|
|
data[key] = value
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-24 00:09:45 +08:00
|
|
|
|
utils.RenderTemplate(w, "layout.html", data)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DashboardFragmentHandler 仪表盘片段渲染
|
|
|
|
|
|
// - 展示系统信息:版本、运行模式、数据库类型、启动时长
|
|
|
|
|
|
func DashboardFragmentHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
version := "1.0.0"
|
|
|
|
|
|
mode := viper.GetString("server.mode")
|
|
|
|
|
|
dbType := viper.GetString("database.type")
|
|
|
|
|
|
if dbType == "" {
|
|
|
|
|
|
dbType = "sqlite"
|
|
|
|
|
|
}
|
|
|
|
|
|
uptime := timeutil.GetServerUptimeString()
|
|
|
|
|
|
|
|
|
|
|
|
data := map[string]interface{}{
|
|
|
|
|
|
"Version": version,
|
|
|
|
|
|
"Mode": mode,
|
|
|
|
|
|
"DBType": dbType,
|
|
|
|
|
|
"Uptime": uptime,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.RenderTemplate(w, "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"
|
|
|
|
|
|
mode := viper.GetString("server.mode")
|
|
|
|
|
|
dbType := viper.GetString("database.type")
|
|
|
|
|
|
if dbType == "" {
|
|
|
|
|
|
dbType = "sqlite"
|
|
|
|
|
|
}
|
|
|
|
|
|
uptime := timeutil.GetServerUptimeString()
|
|
|
|
|
|
|
|
|
|
|
|
data := map[string]interface{}{
|
|
|
|
|
|
"version": version,
|
|
|
|
|
|
"mode": mode,
|
|
|
|
|
|
"db_type": dbType,
|
|
|
|
|
|
"uptime": uptime,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.JsonResponse(w, http.StatusOK, true, "ok", data)
|
|
|
|
|
|
}
|