更新开发者平台:代理商管理、版本管理、UI优化

This commit is contained in:
Admin
2026-04-29 15:19:17 +08:00
parent afe67d704e
commit 5c63882e71
139 changed files with 26533 additions and 365 deletions
+20
View File
@@ -134,6 +134,26 @@ func DeveloperAuth() gin.HandlerFunc {
}
}
// AgentAuth 代理商授权中间件
func AgentAuth() gin.HandlerFunc {
return func(c *gin.Context) {
role, exists := c.Get("role")
if !exists {
response.Error(c, http.StatusForbidden, "Access denied")
c.Abort()
return
}
if role != "agent" && role != "admin" {
response.Error(c, http.StatusForbidden, "Agent access required")
c.Abort()
return
}
c.Next()
}
}
// PackageAuth 套餐授权中间件
func PackageAuth() gin.HandlerFunc {
return func(c *gin.Context) {
+1 -1
View File
@@ -14,7 +14,7 @@ type User struct {
Password string `gorm:"size:255" json:"-"`
Avatar string `gorm:"size:255" json:"avatar"`
Signature string `gorm:"size:255" json:"signature"`
Role string `gorm:"size:20;default:developer" json:"role"`
Role string `gorm:"size:20;default:admin" json:"role"`
Status string `gorm:"size:20;default:active" json:"status"`
DeviceID string `gorm:"size:100" json:"device_id"`
LastLoginAt *time.Time `json:"last_login_at"`
+275
View File
@@ -0,0 +1,275 @@
package agent
import (
"math/rand"
"strconv"
"time"
"verification-platform-backend/internal/database"
"verification-platform-backend/internal/model"
"verification-platform-backend/pkg/response"
"github.com/gin-gonic/gin"
)
func SetupAgentRoutes(r *gin.RouterGroup) {
r.GET("/stats", handleGetStats)
r.GET("/apps", handleGetApps)
r.GET("/cards", handleGetCards)
r.POST("/cards/generate", handleGenerateCards)
r.GET("/users", handleGetUsers)
r.GET("/finance", handleGetFinance)
r.GET("/profile", handleGetProfile)
r.PUT("/profile", handleUpdateProfile)
}
func handleGetStats(c *gin.Context) {
userID := c.GetUint("user_id")
var totalApps int64
database.DB.Model(&model.AgentApplication{}).Where("agent_id = ?", userID).Count(&totalApps)
var totalCards int64
database.DB.Model(&model.Card{}).Where("agent_id = ?", userID).Count(&totalCards)
var totalUsers int64
var agentApps []model.AgentApplication
database.DB.Where("agent_id = ?", userID).Find(&agentApps)
appIDs := make([]uint, 0)
for _, app := range agentApps {
appIDs = append(appIDs, app.ApplicationID)
}
if len(appIDs) > 0 {
database.DB.Model(&model.AppUser{}).Where("application_id IN ?", appIDs).Count(&totalUsers)
}
var totalRevenue float64
database.DB.Model(&model.Card{}).Where("agent_id = ?", userID).Select("COALESCE(SUM(price), 0)").Scan(&totalRevenue)
today := time.Now().Format("2006-01-02")
var todayCards int64
database.DB.Model(&model.Card{}).Where("agent_id = ? AND DATE(created_at) = ?", userID, today).Count(&todayCards)
var todayRevenue float64
database.DB.Model(&model.Card{}).Where("agent_id = ? AND DATE(created_at) = ?", userID, today).Select("COALESCE(SUM(price), 0)").Scan(&todayRevenue)
response.Success(c, gin.H{
"totalApps": totalApps,
"totalCards": totalCards,
"totalUsers": totalUsers,
"totalRevenue": totalRevenue,
"todayCards": todayCards,
"todayRevenue": todayRevenue,
})
}
func handleGetApps(c *gin.Context) {
userID := c.GetUint("user_id")
var agentApps []model.AgentApplication
if err := database.DB.Where("agent_id = ?", userID).Preload("Application").Find(&agentApps).Error; err != nil {
response.Error(c, 500, "获取应用列表失败")
return
}
apps := make([]gin.H, 0)
for _, aa := range agentApps {
if aa.Application.ID > 0 {
apps = append(apps, gin.H{
"id": aa.Application.ID,
"name": aa.Application.Name,
"description": aa.Application.Description,
"status": aa.Application.Status,
"authorized_at": aa.CreatedAt,
"commission": aa.Commission,
})
}
}
response.Success(c, gin.H{
"apps": apps,
})
}
func handleGetCards(c *gin.Context) {
userID := c.GetUint("user_id")
page := c.DefaultQuery("page", "1")
pageSize := c.DefaultQuery("page_size", "20")
var total int64
database.DB.Model(&model.Card{}).Where("agent_id = ?", userID).Count(&total)
var cards []model.Card
offset := 0
if pageInt, err := strconv.Atoi(page); err == nil && pageInt > 1 {
offset = (pageInt - 1) * 20
}
limit := 20
if pageSizeInt, err := strconv.Atoi(pageSize); err == nil && pageSizeInt > 0 {
limit = pageSizeInt
}
database.DB.Where("agent_id = ?", userID).Order("created_at DESC").Limit(limit).Offset(offset).Find(&cards)
response.Success(c, gin.H{
"cards": cards,
"total": total,
})
}
func handleGenerateCards(c *gin.Context) {
userID := c.GetUint("user_id")
var req struct {
ApplicationID uint `json:"application_id"`
CardTypeID uint `json:"card_type_id"`
Quantity int `json:"quantity"`
}
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, 400, "参数错误")
return
}
var agentApp model.AgentApplication
if err := database.DB.Where("agent_id = ? AND application_id = ?", userID, req.ApplicationID).First(&agentApp).Error; err != nil {
response.Error(c, 403, "无权操作该应用")
return
}
cards := make([]model.Card, req.Quantity)
for i := 0; i < req.Quantity; i++ {
cards[i] = model.Card{
ApplicationID: req.ApplicationID,
CardTypeID: req.CardTypeID,
CardKey: generateCardCode(),
CreatorID: userID,
Status: "unused",
}
}
if err := database.DB.Create(&cards).Error; err != nil {
response.Error(c, 500, "生成卡密失败")
return
}
response.Success(c, gin.H{
"count": req.Quantity,
})
}
func generateCardCode() string {
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, 16)
for i := range b {
b[i] = charset[rand.Intn(len(charset))]
}
return string(b)
}
func handleGetUsers(c *gin.Context) {
userID := c.GetUint("user_id")
var agentApps []model.AgentApplication
database.DB.Where("agent_id = ?", userID).Find(&agentApps)
appIDs := make([]uint, 0)
for _, app := range agentApps {
appIDs = append(appIDs, app.ApplicationID)
}
if len(appIDs) == 0 {
response.Success(c, gin.H{
"users": []interface{}{},
"total": 0,
})
return
}
page := c.DefaultQuery("page", "1")
pageSize := c.DefaultQuery("page_size", "20")
var total int64
database.DB.Model(&model.AppUser{}).Where("application_id IN ?", appIDs).Count(&total)
var users []model.AppUser
offset := 0
if pageInt, err := strconv.Atoi(page); err == nil && pageInt > 1 {
offset = (pageInt - 1) * 20
}
limit := 20
if pageSizeInt, err := strconv.Atoi(pageSize); err == nil && pageSizeInt > 0 {
limit = pageSizeInt
}
database.DB.Where("application_id IN ?", appIDs).Order("created_at DESC").Limit(limit).Offset(offset).Find(&users)
response.Success(c, gin.H{
"users": users,
"total": total,
})
}
func handleGetFinance(c *gin.Context) {
userID := c.GetUint("user_id")
var user model.User
if err := database.DB.First(&user, userID).Error; err != nil {
response.Error(c, 404, "用户不存在")
return
}
var records []model.RechargeRecord
database.DB.Where("user_id = ?", userID).Order("created_at DESC").Limit(20).Find(&records)
response.Success(c, gin.H{
"balance": user.Balance,
"commission": user.Commission,
"records": records,
})
}
func handleGetProfile(c *gin.Context) {
userID := c.GetUint("user_id")
var user model.User
if err := database.DB.First(&user, userID).Error; err != nil {
response.Error(c, 404, "用户不存在")
return
}
response.Success(c, gin.H{
"id": user.ID,
"username": user.Username,
"email": user.Email,
"avatar": user.Avatar,
"balance": user.Balance,
"commission": user.Commission,
"can_create_agent": user.CanCreateAgent,
})
}
func handleUpdateProfile(c *gin.Context) {
userID := c.GetUint("user_id")
var req struct {
Email string `json:"email"`
}
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, 400, "参数错误")
return
}
var user model.User
if err := database.DB.First(&user, userID).Error; err != nil {
response.Error(c, 404, "用户不存在")
return
}
if req.Email != "" {
user.Email = &req.Email
}
database.DB.Save(&user)
response.Success(c, nil)
}
+8 -8
View File
@@ -47,7 +47,7 @@ type AgentTreeNode struct {
func handleGetAgents(c *gin.Context) {
var users []model.User
if err := database.DB.Where("role = ?", "developer").
if err := database.DB.Where("role = ?", "admin").
Preload("ParentAgent").
Order("created_at DESC").
Find(&users).Error; err != nil {
@@ -123,7 +123,7 @@ func handleGetAgents(c *gin.Context) {
func handleGetAgentsTree(c *gin.Context) {
var users []model.User
if err := database.DB.Where("role = ?", "developer").
if err := database.DB.Where("role = ?", "admin").
Preload("ParentAgent").
Order("created_at DESC").
Find(&users).Error; err != nil {
@@ -239,7 +239,7 @@ func handleCreateAgent(c *gin.Context) {
if req.ParentAgentID != nil {
var parentAgent model.User
if err := database.DB.Where("id = ? AND role = ?", *req.ParentAgentID, "developer").First(&parentAgent).Error; err != nil {
if err := database.DB.Where("id = ? AND role = ?", *req.ParentAgentID, "admin").First(&parentAgent).Error; err != nil {
response.Error(c, 404, "上级代理不存在")
return
}
@@ -254,7 +254,7 @@ func handleCreateAgent(c *gin.Context) {
user := model.User{
Username: req.Username,
Password: string(hashedPassword),
Role: "developer",
Role: "agent",
Status: "active",
ParentAgentID: req.ParentAgentID,
Commission: req.Commission,
@@ -283,7 +283,7 @@ func handleGetAgentDetail(c *gin.Context) {
agentID := c.Param("id")
var user model.User
if err := database.DB.Where("id = ? AND role = ?", agentID, "developer").
if err := database.DB.Where("id = ? AND role = ?", agentID, "admin").
Preload("ParentAgent").
First(&user).Error; err != nil {
response.Error(c, 404, "代理不存在")
@@ -378,7 +378,7 @@ func handleUpdateAgent(c *gin.Context) {
agentID := c.Param("id")
var user model.User
if err := database.DB.Where("id = ? AND role = ?", agentID, "developer").First(&user).Error; err != nil {
if err := database.DB.Where("id = ? AND role = ?", agentID, "admin").First(&user).Error; err != nil {
response.Error(c, 404, "代理不存在")
return
}
@@ -402,7 +402,7 @@ func handleUpdateAgent(c *gin.Context) {
return
}
var parentAgent model.User
if err := database.DB.Where("id = ? AND role = ?", *req.ParentAgentID, "developer").First(&parentAgent).Error; err != nil {
if err := database.DB.Where("id = ? AND role = ?", *req.ParentAgentID, "admin").First(&parentAgent).Error; err != nil {
response.Error(c, 404, "上级代理不存在")
return
}
@@ -446,7 +446,7 @@ func handleUpdateAgentStatus(c *gin.Context) {
agentID := c.Param("id")
var user model.User
if err := database.DB.Where("id = ? AND role = ?", agentID, "developer").First(&user).Error; err != nil {
if err := database.DB.Where("id = ? AND role = ?", agentID, "admin").First(&user).Error; err != nil {
response.Error(c, 404, "代理不存在")
return
}
+8
View File
@@ -4,6 +4,7 @@ import (
"time"
"verification-platform-backend/internal/middleware"
"verification-platform-backend/internal/router/agent"
"verification-platform-backend/internal/router/app"
"verification-platform-backend/internal/router/developer"
"verification-platform-backend/internal/router/extension"
@@ -36,6 +37,13 @@ func SetupRoutes(r *gin.Engine) {
developer.SetupRoutesWithoutPackage(devGroup)
}
agentGroup := api.Group("/agent")
{
agentGroup.Use(middleware.JWT())
agentGroup.Use(middleware.AgentAuth())
agent.SetupAgentRoutes(agentGroup)
}
appGroup := api.Group("/app/:appKey")
{
appGroup.Use(app.AppCryptoMiddleware())
+7 -6
View File
@@ -56,12 +56,13 @@ func (s *AuthService) Login(username, password, agentPath string) (map[string]in
// 返回用户信息和令牌
return map[string]interface{}{
"user": map[string]interface{}{
"id": user.ID,
"username": user.Username,
"email": user.Email,
"avatar": user.Avatar,
"role": user.Role,
"status": user.Status,
"id": user.ID,
"username": user.Username,
"email": user.Email,
"avatar": user.Avatar,
"role": user.Role,
"status": user.Status,
"parent_agent_id": user.ParentAgentID,
},
"token": token,
}, nil