586 lines
16 KiB
Go
586 lines
16 KiB
Go
package developer
|
|
|
|
import (
|
|
"fmt"
|
|
"verification-platform-backend/internal/database"
|
|
"verification-platform-backend/internal/model"
|
|
"verification-platform-backend/internal/service"
|
|
"verification-platform-backend/pkg/response"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
func SetupAgentsRoutes(r *gin.RouterGroup) {
|
|
agents := r.Group("/agents")
|
|
{
|
|
agents.GET("", handleGetAgents)
|
|
agents.GET("/tree", handleGetAgentsTree)
|
|
agents.POST("", handleCreateAgent)
|
|
agents.GET("/:id", handleGetAgentDetail)
|
|
agents.PUT("/:id", handleUpdateAgent)
|
|
agents.PUT("/:id/status", handleUpdateAgentStatus)
|
|
agents.DELETE("/:id", handleDeleteAgent)
|
|
agents.GET("/:id/cards", handleGetAgentCards)
|
|
agents.PUT("/:id/cards", handleUpdateAgentCards)
|
|
}
|
|
}
|
|
|
|
type AgentTreeNode struct {
|
|
ID uint `json:"id"`
|
|
Username string `json:"username"`
|
|
Email string `json:"email"`
|
|
Avatar string `json:"avatar"`
|
|
Status string `json:"status"`
|
|
Role string `json:"role"`
|
|
ParentAgentID *uint `json:"parent_agent_id"`
|
|
ParentAgentName string `json:"parent_agent_name"`
|
|
CreatedAt string `json:"created_at"`
|
|
LastLoginAt string `json:"last_login_at"`
|
|
Balance float64 `json:"balance"`
|
|
Commission float64 `json:"commission"`
|
|
CanCreateAgent bool `json:"can_create_agent"`
|
|
CardsCount int `json:"cards_count"`
|
|
ChildAgentsCount int `json:"child_agents_count"`
|
|
Children []AgentTreeNode `json:"children,omitempty"`
|
|
}
|
|
|
|
func handleGetAgents(c *gin.Context) {
|
|
var users []model.User
|
|
if err := database.DB.Where("role = ?", "agent").
|
|
Preload("ParentAgent").
|
|
Order("created_at DESC").
|
|
Find(&users).Error; err != nil {
|
|
response.Error(c, 500, "获取代理列表失败")
|
|
return
|
|
}
|
|
|
|
type AgentResponse struct {
|
|
ID uint `json:"id"`
|
|
Username string `json:"username"`
|
|
Email string `json:"email"`
|
|
Avatar string `json:"avatar"`
|
|
Status string `json:"status"`
|
|
Role string `json:"role"`
|
|
ParentAgentID *uint `json:"parent_agent_id"`
|
|
ParentAgentName string `json:"parent_agent_name"`
|
|
CreatedAt string `json:"created_at"`
|
|
LastLoginAt string `json:"last_login_at"`
|
|
Balance float64 `json:"balance"`
|
|
Commission float64 `json:"commission"`
|
|
CanCreateAgent bool `json:"can_create_agent"`
|
|
CardsCount int `json:"cards_count"`
|
|
ChildAgentsCount int `json:"child_agents_count"`
|
|
}
|
|
|
|
var result []AgentResponse
|
|
for _, user := range users {
|
|
var parentAgentName string
|
|
if user.ParentAgent != nil {
|
|
parentAgentName = user.ParentAgent.Username
|
|
}
|
|
|
|
var childAgentsCount int64
|
|
database.DB.Model(&model.User{}).Where("parent_agent_id = ?", user.ID).Count(&childAgentsCount)
|
|
|
|
var cardsCount int64
|
|
database.DB.Model(&model.Card{}).Where("creator_id = ?", user.ID).Count(&cardsCount)
|
|
|
|
var lastLoginAt string
|
|
if user.LastLoginAt != nil {
|
|
lastLoginAt = user.LastLoginAt.Format("2006-01-02 15:04:05")
|
|
}
|
|
|
|
email := ""
|
|
if user.Email != nil {
|
|
email = *user.Email
|
|
}
|
|
|
|
result = append(result, AgentResponse{
|
|
ID: user.ID,
|
|
Username: user.Username,
|
|
Email: email,
|
|
Avatar: user.Avatar,
|
|
Status: user.Status,
|
|
Role: user.Role,
|
|
ParentAgentID: user.ParentAgentID,
|
|
ParentAgentName: parentAgentName,
|
|
CreatedAt: user.CreatedAt.Format("2006-01-02 15:04:05"),
|
|
LastLoginAt: lastLoginAt,
|
|
Balance: user.Balance,
|
|
Commission: user.Commission,
|
|
CanCreateAgent: user.CanCreateAgent,
|
|
CardsCount: int(cardsCount),
|
|
ChildAgentsCount: int(childAgentsCount),
|
|
})
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"agents": result,
|
|
"total": len(result),
|
|
})
|
|
}
|
|
|
|
func handleGetAgentsTree(c *gin.Context) {
|
|
var users []model.User
|
|
if err := database.DB.Where("role = ?", "agent").
|
|
Preload("ParentAgent").
|
|
Order("created_at DESC").
|
|
Find(&users).Error; err != nil {
|
|
response.Error(c, 500, "获取代理列表失败")
|
|
return
|
|
}
|
|
|
|
userMap := make(map[uint]model.User)
|
|
for _, user := range users {
|
|
userMap[user.ID] = user
|
|
}
|
|
|
|
childrenMap := make(map[uint][]uint)
|
|
var rootUsers []uint
|
|
for _, user := range users {
|
|
if user.ParentAgentID != nil {
|
|
childrenMap[*user.ParentAgentID] = append(childrenMap[*user.ParentAgentID], user.ID)
|
|
} else {
|
|
rootUsers = append(rootUsers, user.ID)
|
|
}
|
|
}
|
|
|
|
var buildTree func(userID uint) AgentTreeNode
|
|
buildTree = func(userID uint) AgentTreeNode {
|
|
user := userMap[userID]
|
|
|
|
var parentAgentName string
|
|
if user.ParentAgent != nil {
|
|
parentAgentName = user.ParentAgent.Username
|
|
}
|
|
|
|
var cardsCount int64
|
|
database.DB.Model(&model.Card{}).Where("creator_id = ?", user.ID).Count(&cardsCount)
|
|
|
|
var childAgentsCount int64
|
|
database.DB.Model(&model.User{}).Where("parent_agent_id = ?", user.ID).Count(&childAgentsCount)
|
|
|
|
var lastLoginAt string
|
|
if user.LastLoginAt != nil {
|
|
lastLoginAt = user.LastLoginAt.Format("2006-01-02 15:04:05")
|
|
}
|
|
|
|
email := ""
|
|
if user.Email != nil {
|
|
email = *user.Email
|
|
}
|
|
|
|
node := AgentTreeNode{
|
|
ID: user.ID,
|
|
Username: user.Username,
|
|
Email: email,
|
|
Avatar: user.Avatar,
|
|
Status: user.Status,
|
|
Role: user.Role,
|
|
ParentAgentID: user.ParentAgentID,
|
|
ParentAgentName: parentAgentName,
|
|
CreatedAt: user.CreatedAt.Format("2006-01-02 15:04:05"),
|
|
LastLoginAt: lastLoginAt,
|
|
Balance: user.Balance,
|
|
Commission: user.Commission,
|
|
CanCreateAgent: user.CanCreateAgent,
|
|
CardsCount: int(cardsCount),
|
|
ChildAgentsCount: int(childAgentsCount),
|
|
}
|
|
|
|
if childIDs, exists := childrenMap[userID]; exists {
|
|
for _, childID := range childIDs {
|
|
node.Children = append(node.Children, buildTree(childID))
|
|
}
|
|
}
|
|
|
|
return node
|
|
}
|
|
|
|
var tree []AgentTreeNode
|
|
for _, rootID := range rootUsers {
|
|
tree = append(tree, buildTree(rootID))
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"tree": tree,
|
|
"total": len(users),
|
|
})
|
|
}
|
|
|
|
func handleCreateAgent(c *gin.Context) {
|
|
var req struct {
|
|
Username string `json:"username" binding:"required"`
|
|
Email string `json:"email"`
|
|
Password string `json:"password" binding:"required"`
|
|
ParentAgentID *uint `json:"parent_agent_id"`
|
|
Commission float64 `json:"commission"`
|
|
CanCreateAgent bool `json:"can_create_agent"`
|
|
Balance float64 `json:"balance"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
var existingUser model.User
|
|
if err := database.DB.Where("username = ?", req.Username).First(&existingUser).Error; err == nil {
|
|
response.Error(c, 400, "用户名已存在")
|
|
return
|
|
}
|
|
|
|
if req.Email != "" {
|
|
if err := database.DB.Where("email = ?", req.Email).First(&existingUser).Error; err == nil {
|
|
response.Error(c, 400, "邮箱已被使用")
|
|
return
|
|
}
|
|
}
|
|
|
|
if req.ParentAgentID != nil {
|
|
var parentAgent model.User
|
|
if err := database.DB.Where("id = ? AND role = ?", *req.ParentAgentID, "agent").First(&parentAgent).Error; err != nil {
|
|
response.Error(c, 404, "上级代理不存在")
|
|
return
|
|
}
|
|
}
|
|
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
response.Error(c, 500, "密码加密失败")
|
|
return
|
|
}
|
|
|
|
user := model.User{
|
|
Username: req.Username,
|
|
Password: string(hashedPassword),
|
|
Role: "agent",
|
|
Status: "active",
|
|
ParentAgentID: req.ParentAgentID,
|
|
Commission: req.Commission,
|
|
CanCreateAgent: req.CanCreateAgent,
|
|
Balance: req.Balance,
|
|
}
|
|
|
|
if req.Email != "" {
|
|
user.Email = &req.Email
|
|
}
|
|
|
|
if err := database.DB.Create(&user).Error; err != nil {
|
|
response.Error(c, 500, "创建代理失败")
|
|
return
|
|
}
|
|
|
|
service.LogOperation(c, "create", "agent", &user.ID, fmt.Sprintf("创建代理: %s", user.Username), nil)
|
|
|
|
response.Success(c, gin.H{
|
|
"id": user.ID,
|
|
"username": user.Username,
|
|
})
|
|
}
|
|
|
|
func handleGetAgentDetail(c *gin.Context) {
|
|
agentID := c.Param("id")
|
|
|
|
var user model.User
|
|
if err := database.DB.Where("id = ? AND role = ?", agentID, "agent").
|
|
Preload("ParentAgent").
|
|
First(&user).Error; err != nil {
|
|
response.Error(c, 404, "代理不存在")
|
|
return
|
|
}
|
|
|
|
var agentApps []model.AgentApplication
|
|
database.DB.Where("agent_id = ?", user.ID).
|
|
Preload("Application").
|
|
Find(&agentApps)
|
|
|
|
var childAgents []model.User
|
|
database.DB.Where("parent_agent_id = ?", user.ID).Find(&childAgents)
|
|
|
|
var cards []model.Card
|
|
database.DB.Where("creator_id = ?", user.ID).
|
|
Preload("Application").
|
|
Preload("CardType").
|
|
Find(&cards)
|
|
|
|
type CardResponse struct {
|
|
ID uint `json:"id"`
|
|
CardKey string `json:"card_key"`
|
|
ApplicationID uint `json:"application_id"`
|
|
AppName string `json:"app_name"`
|
|
CardTypeID uint `json:"card_type_id"`
|
|
CardTypeName string `json:"card_type_name"`
|
|
Price float64 `json:"price"`
|
|
Status string `json:"status"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
var cardsResponse []CardResponse
|
|
for _, card := range cards {
|
|
appName := ""
|
|
if card.Application != nil {
|
|
appName = card.Application.Name
|
|
}
|
|
cardTypeName := ""
|
|
if card.CardType.ID != 0 {
|
|
cardTypeName = card.CardType.Name
|
|
}
|
|
cardsResponse = append(cardsResponse, CardResponse{
|
|
ID: card.ID,
|
|
CardKey: card.CardKey,
|
|
ApplicationID: card.ApplicationID,
|
|
AppName: appName,
|
|
CardTypeID: card.CardTypeID,
|
|
CardTypeName: cardTypeName,
|
|
Price: card.CardType.Price,
|
|
Status: card.Status,
|
|
CreatedAt: card.CreatedAt.Format("2006-01-02 15:04:05"),
|
|
})
|
|
}
|
|
|
|
var lastLoginAt string
|
|
if user.LastLoginAt != nil {
|
|
lastLoginAt = user.LastLoginAt.Format("2006-01-02 15:04:05")
|
|
}
|
|
|
|
email := ""
|
|
if user.Email != nil {
|
|
email = *user.Email
|
|
}
|
|
|
|
var parentAgentName string
|
|
if user.ParentAgent != nil {
|
|
parentAgentName = user.ParentAgent.Username
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"id": user.ID,
|
|
"username": user.Username,
|
|
"email": email,
|
|
"avatar": user.Avatar,
|
|
"status": user.Status,
|
|
"role": user.Role,
|
|
"parent_agent_id": user.ParentAgentID,
|
|
"parent_agent_name": parentAgentName,
|
|
"commission": user.Commission,
|
|
"can_create_agent": user.CanCreateAgent,
|
|
"balance": user.Balance,
|
|
"created_at": user.CreatedAt.Format("2006-01-02 15:04:05"),
|
|
"last_login_at": lastLoginAt,
|
|
"cards": cardsResponse,
|
|
"cards_count": len(cardsResponse),
|
|
"child_agents_count": len(childAgents),
|
|
})
|
|
}
|
|
|
|
func handleUpdateAgent(c *gin.Context) {
|
|
agentID := c.Param("id")
|
|
|
|
var user model.User
|
|
if err := database.DB.Where("id = ? AND role = ?", agentID, "agent").First(&user).Error; err != nil {
|
|
response.Error(c, 404, "代理不存在")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
ParentAgentID *uint `json:"parent_agent_id"`
|
|
Commission *float64 `json:"commission"`
|
|
Email *string `json:"email"`
|
|
Password *string `json:"password"`
|
|
CanCreateAgent *bool `json:"can_create_agent"`
|
|
Balance *float64 `json:"balance"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
if req.ParentAgentID != nil {
|
|
if *req.ParentAgentID == user.ID {
|
|
response.Error(c, 400, "不能将自己设为上级代理")
|
|
return
|
|
}
|
|
var parentAgent model.User
|
|
if err := database.DB.Where("id = ? AND role = ?", *req.ParentAgentID, "agent").First(&parentAgent).Error; err != nil {
|
|
response.Error(c, 404, "上级代理不存在")
|
|
return
|
|
}
|
|
user.ParentAgentID = req.ParentAgentID
|
|
}
|
|
|
|
if req.Email != nil {
|
|
user.Email = req.Email
|
|
}
|
|
if req.Commission != nil {
|
|
user.Commission = *req.Commission
|
|
}
|
|
if req.Password != nil && *req.Password != "" {
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(*req.Password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
response.Error(c, 500, "密码加密失败")
|
|
return
|
|
}
|
|
user.Password = string(hashedPassword)
|
|
}
|
|
if req.CanCreateAgent != nil {
|
|
user.CanCreateAgent = *req.CanCreateAgent
|
|
}
|
|
if req.Balance != nil {
|
|
user.Balance = *req.Balance
|
|
}
|
|
|
|
if err := database.DB.Save(&user).Error; err != nil {
|
|
response.Error(c, 500, "更新失败")
|
|
return
|
|
}
|
|
|
|
service.LogOperation(c, "update", "agent", &user.ID, fmt.Sprintf("更新代理: %s", user.Username), nil)
|
|
|
|
response.Success(c, gin.H{
|
|
"id": user.ID,
|
|
})
|
|
}
|
|
|
|
func handleUpdateAgentStatus(c *gin.Context) {
|
|
agentID := c.Param("id")
|
|
|
|
var user model.User
|
|
if err := database.DB.Where("id = ? AND role = ?", agentID, "agent").First(&user).Error; err != nil {
|
|
response.Error(c, 404, "代理不存在")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Status string `json:"status" binding:"required,oneof=active inactive banned"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
user.Status = req.Status
|
|
if err := database.DB.Save(&user).Error; err != nil {
|
|
response.Error(c, 500, "更新状态失败")
|
|
return
|
|
}
|
|
|
|
service.LogOperation(c, "update_status", "agent", &user.ID, fmt.Sprintf("更新代理状态: %s -> %s", user.Username, user.Status), nil)
|
|
|
|
response.Success(c, gin.H{
|
|
"id": user.ID,
|
|
"status": user.Status,
|
|
})
|
|
}
|
|
|
|
func handleDeleteAgent(c *gin.Context) {
|
|
agentID := c.Param("id")
|
|
|
|
var user model.User
|
|
if err := database.DB.Where("id = ? AND role = ?", agentID, "agent").First(&user).Error; err != nil {
|
|
response.Error(c, 404, "代理不存在")
|
|
return
|
|
}
|
|
|
|
database.DB.Model(&model.User{}).Where("parent_agent_id = ?", user.ID).Update("parent_agent_id", nil)
|
|
|
|
if err := database.DB.Delete(&user).Error; err != nil {
|
|
response.Error(c, 500, "删除失败")
|
|
return
|
|
}
|
|
|
|
service.LogOperation(c, "delete", "agent", &user.ID, fmt.Sprintf("删除代理: %s", user.Username), nil)
|
|
|
|
response.Success(c, gin.H{
|
|
"id": user.ID,
|
|
})
|
|
}
|
|
|
|
func handleGetAgentCards(c *gin.Context) {
|
|
agentID := c.Param("id")
|
|
|
|
var user model.User
|
|
if err := database.DB.Where("id = ? AND role = ?", agentID, "agent").First(&user).Error; err != nil {
|
|
response.Error(c, 404, "代理不存在")
|
|
return
|
|
}
|
|
|
|
var cards []model.Card
|
|
database.DB.Where("creator_id = ?", user.ID).
|
|
Preload("Application").
|
|
Preload("CardType").
|
|
Order("created_at DESC").
|
|
Find(&cards)
|
|
|
|
type CardResponse struct {
|
|
ID uint `json:"id"`
|
|
CardKey string `json:"card_key"`
|
|
ApplicationID uint `json:"application_id"`
|
|
AppName string `json:"app_name"`
|
|
CardTypeID uint `json:"card_type_id"`
|
|
CardTypeName string `json:"card_type_name"`
|
|
Price float64 `json:"price"`
|
|
Status string `json:"status"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
var result []CardResponse
|
|
for _, card := range cards {
|
|
appName := ""
|
|
if card.Application != nil {
|
|
appName = card.Application.Name
|
|
}
|
|
cardTypeName := ""
|
|
if card.CardType.ID != 0 {
|
|
cardTypeName = card.CardType.Name
|
|
}
|
|
result = append(result, CardResponse{
|
|
ID: card.ID,
|
|
CardKey: card.CardKey,
|
|
ApplicationID: card.ApplicationID,
|
|
AppName: appName,
|
|
CardTypeID: card.CardTypeID,
|
|
CardTypeName: cardTypeName,
|
|
Price: card.CardType.Price,
|
|
Status: card.Status,
|
|
CreatedAt: card.CreatedAt.Format("2006-01-02 15:04:05"),
|
|
})
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"cards": result,
|
|
"total": len(result),
|
|
})
|
|
}
|
|
|
|
func handleUpdateAgentCards(c *gin.Context) {
|
|
agentID := c.Param("id")
|
|
|
|
var user model.User
|
|
if err := database.DB.Where("id = ? AND role = ?", agentID, "agent").First(&user).Error; err != nil {
|
|
response.Error(c, 404, "代理不存在")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Cards []struct {
|
|
CardID uint `json:"card_id"`
|
|
Status string `json:"status"`
|
|
} `json:"cards"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
for _, cardReq := range req.Cards {
|
|
database.DB.Model(&model.Card{}).
|
|
Where("id = ? AND creator_id = ?", cardReq.CardID, user.ID).
|
|
Update("status", cardReq.Status)
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "更新成功",
|
|
})
|
|
}
|