2e2c161770
- backed/: Go Fiber backend with cpdaily integration - frondend/: Vue 3 + Vite frontend - Dockerfile: multi-stage build (Node → Go → Alpine) - deploy/docker-compose.yml: production compose file - .woodpecker/build.yml: CI/CD with blue-green zero-downtime deploy - /health endpoint for deployment health checks - Port 8884/8885 blue-green swap via 1Panel OpenResty
184 lines
4.9 KiB
Go
184 lines
4.9 KiB
Go
package handler
|
|
|
|
import (
|
|
"cpdaily-new/internal/database"
|
|
"cpdaily-new/internal/model"
|
|
"cpdaily-new/internal/service"
|
|
"cpdaily-new/internal/utils"
|
|
"log/slog"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
// AdminSetupStatus 检查是否已安装(是否有admin账号)
|
|
func AdminSetupStatus(c *fiber.Ctx) error {
|
|
var count int64
|
|
database.DB.Model(&model.AgentUser{}).Where("role = ?", "admin").Count(&count)
|
|
return utils.Success(c, fiber.Map{
|
|
"installed": count > 0,
|
|
})
|
|
}
|
|
|
|
// AdminSetupInitRequest 初始化安装请求
|
|
type AdminSetupInitRequest struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
// AdminSetupInit 初始化创建管理员账号
|
|
func AdminSetupInit(c *fiber.Ctx) error {
|
|
var req AdminSetupInitRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return utils.FailParam(c, "请求参数错误")
|
|
}
|
|
if req.Username == "" || req.Password == "" {
|
|
return utils.FailParam(c, "用户名和密码不能为空")
|
|
}
|
|
if len(req.Password) < 6 {
|
|
return utils.FailParam(c, "密码长度不能少于6位")
|
|
}
|
|
|
|
// 检查是否已存在admin
|
|
var count int64
|
|
database.DB.Model(&model.AgentUser{}).Where("role = ?", "admin").Count(&count)
|
|
if count > 0 {
|
|
return utils.Fail(c, 400, "管理员账号已存在,不能重复初始化")
|
|
}
|
|
|
|
// 加密密码
|
|
hashedPwd, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
slog.Error("密码加密失败", "error", err)
|
|
return utils.FailServer(c, "初始化失败")
|
|
}
|
|
|
|
// 创建管理员
|
|
admin := model.AgentUser{
|
|
Username: req.Username,
|
|
Password: string(hashedPwd),
|
|
Role: "admin",
|
|
Rate: 1.00,
|
|
Balance: 0,
|
|
Status: "active",
|
|
}
|
|
if err := database.DB.Create(&admin).Error; err != nil {
|
|
slog.Error("创建管理员失败", "error", err)
|
|
return utils.FailServer(c, "初始化失败")
|
|
}
|
|
|
|
// 生成 token 直接登录
|
|
token, expiresIn, err := service.GenerateAdminToken(admin.ID, admin.Username, admin.Role)
|
|
if err != nil {
|
|
slog.Error("生成token失败", "error", err)
|
|
return utils.FailServer(c, "初始化成功但生成token失败,请前往登录")
|
|
}
|
|
|
|
slog.Info("管理员初始化成功", "username", req.Username)
|
|
|
|
return utils.Success(c, fiber.Map{
|
|
"token": fiber.Map{
|
|
"accessToken": token,
|
|
"expiresIn": expiresIn,
|
|
"tokenType": "Bearer",
|
|
},
|
|
"agent": fiber.Map{
|
|
"id": admin.ID,
|
|
"username": admin.Username,
|
|
"role": admin.Role,
|
|
"rate": admin.Rate,
|
|
"balance": admin.Balance,
|
|
"status": admin.Status,
|
|
},
|
|
})
|
|
}
|
|
|
|
// AdminLoginRequest 管理员登录请求
|
|
type AdminLoginRequest struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
// AdminLogin 管理员/代理登录
|
|
func AdminLogin(c *fiber.Ctx) error {
|
|
var req AdminLoginRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return utils.FailParam(c, "请求参数错误")
|
|
}
|
|
if req.Username == "" || req.Password == "" {
|
|
return utils.FailParam(c, "用户名或密码不能为空")
|
|
}
|
|
|
|
// 查找管理员/代理
|
|
var agent model.AgentUser
|
|
if err := database.DB.Where("username = ?", req.Username).First(&agent).Error; err != nil {
|
|
return utils.Fail(c, 401, "用户名或密码错误")
|
|
}
|
|
|
|
// 验证密码
|
|
if err := bcrypt.CompareHashAndPassword([]byte(agent.Password), []byte(req.Password)); err != nil {
|
|
return utils.Fail(c, 401, "用户名或密码错误")
|
|
}
|
|
|
|
// 检查状态
|
|
if agent.Status == "disabled" {
|
|
return utils.Fail(c, 403, "账号已被禁用")
|
|
}
|
|
|
|
// 生成 token
|
|
token, expiresIn, err := service.GenerateAdminToken(agent.ID, agent.Username, agent.Role)
|
|
if err != nil {
|
|
slog.Error("生成管理员token失败", "error", err)
|
|
return utils.FailServer(c, "登录失败")
|
|
}
|
|
|
|
slog.Info("管理员登录成功", "agentId", agent.ID, "username", agent.Username, "role", agent.Role)
|
|
|
|
return utils.Success(c, fiber.Map{
|
|
"token": fiber.Map{
|
|
"accessToken": token,
|
|
"expiresIn": expiresIn,
|
|
"tokenType": "Bearer",
|
|
},
|
|
"agent": fiber.Map{
|
|
"id": agent.ID,
|
|
"username": agent.Username,
|
|
"role": agent.Role,
|
|
"rate": agent.Rate,
|
|
"balance": agent.Balance,
|
|
"status": agent.Status,
|
|
},
|
|
})
|
|
}
|
|
|
|
// AdminMe 获取当前管理员/代理信息
|
|
func AdminMe(c *fiber.Ctx) error {
|
|
agentID := c.Locals("adminId").(uint)
|
|
|
|
var agent model.AgentUser
|
|
if err := database.DB.First(&agent, agentID).Error; err != nil {
|
|
return utils.FailAuth(c, "账号不存在")
|
|
}
|
|
|
|
// 查询下级代理数量
|
|
var subCount int64
|
|
database.DB.Model(&model.AgentUser{}).Where("parent_id = ?", agentID).Count(&subCount)
|
|
|
|
// 查询CDK数量
|
|
var cdkCount int64
|
|
database.DB.Model(&model.CDKCode{}).Where("agent_id = ?", agentID).Count(&cdkCount)
|
|
|
|
return utils.Success(c, fiber.Map{
|
|
"id": agent.ID,
|
|
"username": agent.Username,
|
|
"role": agent.Role,
|
|
"rate": agent.Rate,
|
|
"balance": agent.Balance,
|
|
"status": agent.Status,
|
|
"parentId": agent.ParentID,
|
|
"subCount": subCount,
|
|
"cdkCount": cdkCount,
|
|
"createdAt": agent.CreatedAt,
|
|
})
|
|
}
|