811 lines
22 KiB
Go
811 lines
22 KiB
Go
package admin
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
"verification-platform-backend/internal/database"
|
|
"verification-platform-backend/internal/model"
|
|
"verification-platform-backend/internal/service"
|
|
"verification-platform-backend/pkg/response"
|
|
"verification-platform-backend/pkg/utils"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type UserWithStatus struct {
|
|
model.AppUser
|
|
OnlineStatus string `json:"online_status"`
|
|
DeviceCount int `json:"device_count"`
|
|
}
|
|
|
|
func getUserOnlineStatus(user model.AppUser, heartbeatTimeout int) string {
|
|
if user.Status == "banned" {
|
|
return "banned"
|
|
}
|
|
|
|
if user.LastHeartbeatAt == nil {
|
|
return "offline"
|
|
}
|
|
|
|
offlineThreshold := time.Duration(heartbeatTimeout) * time.Second
|
|
if time.Since(*user.LastHeartbeatAt) > offlineThreshold {
|
|
return "offline"
|
|
}
|
|
|
|
return "online"
|
|
}
|
|
|
|
func SetupUserRoutes(r *gin.RouterGroup) {
|
|
appUsers := r.Group("/app-users")
|
|
{
|
|
appUsers.GET("", handleGetUsers)
|
|
appUsers.POST("", handleCreateUser)
|
|
appUsers.GET("/:id", handleGetUser)
|
|
appUsers.PUT("/:id", handleUpdateUser)
|
|
appUsers.DELETE("/:id", handleDeleteUser)
|
|
appUsers.GET("/:id/devices", handleGetUserDevices)
|
|
appUsers.DELETE("/:id/devices/:deviceId", handleUnbindDevice)
|
|
appUsers.PUT("/:id/expiry", handleUpdateExpiry)
|
|
appUsers.POST("/batch/status", handleBatchUpdateStatus)
|
|
appUsers.DELETE("/batch", handleBatchDelete)
|
|
}
|
|
}
|
|
|
|
func handleGetUsers(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
log.Printf("[DEBUG] handleGetUsers called, userID: %d", userID)
|
|
|
|
var users []model.AppUser
|
|
var appHeartbeatTimeoutMap map[uint]int
|
|
|
|
applicationID := c.Query("application_id")
|
|
if applicationID != "" {
|
|
var appID uint
|
|
if _, err := fmt.Sscanf(applicationID, "%d", &appID); err != nil {
|
|
response.Error(c, 400, "应用ID格式错误")
|
|
return
|
|
}
|
|
|
|
var app model.Application
|
|
if err := database.DB.First(&app, appID).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
appHeartbeatTimeoutMap = make(map[uint]int)
|
|
timeout := app.HeartbeatTimeout
|
|
if timeout == 0 {
|
|
timeout = 300
|
|
}
|
|
appHeartbeatTimeoutMap[app.ID] = timeout
|
|
|
|
if app.UserID == userID {
|
|
if err := database.DB.Preload("Application").Where("application_id = ?", appID).Find(&users).Error; err != nil {
|
|
response.Error(c, 500, "获取用户列表失败")
|
|
return
|
|
}
|
|
} else {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", appID, userID, true).First(&agentApp).Error; err != nil {
|
|
response.Error(c, 403, "无权限查看该应用的用户")
|
|
return
|
|
}
|
|
|
|
var cardUserIDs []uint
|
|
if err := database.DB.Model(&model.Card{}).
|
|
Where("creator_id = ? AND application_id = ? AND app_user_id IS NOT NULL", userID, appID).
|
|
Pluck("app_user_id", &cardUserIDs).Error; err != nil {
|
|
response.Error(c, 500, "获取用户列表失败")
|
|
return
|
|
}
|
|
|
|
if len(cardUserIDs) > 0 {
|
|
if err := database.DB.Preload("Application").Where("id IN ?", cardUserIDs).Find(&users).Error; err != nil {
|
|
response.Error(c, 500, "获取用户列表失败")
|
|
return
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
var ownApps []model.Application
|
|
if err := database.DB.Where("user_id = ?", userID).Find(&ownApps).Error; err != nil {
|
|
response.Error(c, 500, "获取应用列表失败")
|
|
return
|
|
}
|
|
|
|
var agentApps []model.AgentApplication
|
|
if err := database.DB.Where("agent_id = ? AND is_received = ?", userID, true).Find(&agentApps).Error; err != nil {
|
|
log.Printf("[DEBUG] Failed to get agent apps: %v", err)
|
|
response.Error(c, 500, "获取授权列表失败")
|
|
return
|
|
}
|
|
|
|
log.Printf("[DEBUG] Found %d agent apps for user %d", len(agentApps), userID)
|
|
|
|
appHeartbeatTimeoutMap = make(map[uint]int)
|
|
|
|
for _, app := range ownApps {
|
|
timeout := app.HeartbeatTimeout
|
|
if timeout == 0 {
|
|
timeout = 300
|
|
}
|
|
appHeartbeatTimeoutMap[app.ID] = timeout
|
|
|
|
var appUsers []model.AppUser
|
|
if err := database.DB.Preload("Application").Where("application_id = ?", app.ID).Find(&appUsers).Error; err != nil {
|
|
response.Error(c, 500, "获取用户列表失败")
|
|
return
|
|
}
|
|
users = append(users, appUsers...)
|
|
}
|
|
|
|
for _, agentApp := range agentApps {
|
|
var app model.Application
|
|
if err := database.DB.First(&app, agentApp.ApplicationID).Error; err != nil {
|
|
log.Printf("[DEBUG] Failed to get application %d: %v", agentApp.ApplicationID, err)
|
|
continue
|
|
}
|
|
|
|
log.Printf("[DEBUG] Processing agent app: ApplicationID=%d, AppName=%s", app.ID, app.Name)
|
|
|
|
timeout := app.HeartbeatTimeout
|
|
if timeout == 0 {
|
|
timeout = 300
|
|
}
|
|
appHeartbeatTimeoutMap[app.ID] = timeout
|
|
|
|
var cardUserIDs []uint
|
|
if err := database.DB.Model(&model.Card{}).
|
|
Where("creator_id = ? AND application_id = ? AND app_user_id IS NOT NULL", userID, app.ID).
|
|
Pluck("app_user_id", &cardUserIDs).Error; err != nil {
|
|
log.Printf("[DEBUG] Failed to get card user IDs for app %d: %v", app.ID, err)
|
|
continue
|
|
}
|
|
|
|
log.Printf("[DEBUG] Found %d card user IDs for app %d: %v", len(cardUserIDs), app.ID, cardUserIDs)
|
|
|
|
if len(cardUserIDs) > 0 {
|
|
var appUsers []model.AppUser
|
|
if err := database.DB.Preload("Application").Where("id IN ?", cardUserIDs).Find(&appUsers).Error; err != nil {
|
|
log.Printf("[DEBUG] Failed to get users for app %d: %v", app.ID, err)
|
|
continue
|
|
}
|
|
log.Printf("[DEBUG] Found %d users for app %d", len(appUsers), app.ID)
|
|
users = append(users, appUsers...)
|
|
}
|
|
}
|
|
}
|
|
|
|
totalCount := len(users)
|
|
onlineCount := 0
|
|
offlineCount := 0
|
|
bannedCount := 0
|
|
|
|
usersWithStatus := make([]UserWithStatus, 0, len(users))
|
|
for _, user := range users {
|
|
log.Printf("[DEBUG] User ID=%d, Username=%s, LastLoginAt=%v, LastHeartbeatAt=%v", user.ID, user.Username, user.LastLoginAt, user.LastHeartbeatAt)
|
|
|
|
heartbeatTimeout := 300
|
|
if applicationID != "" {
|
|
heartbeatTimeout = appHeartbeatTimeoutMap[user.ApplicationID]
|
|
} else if appHeartbeatTimeoutMap != nil {
|
|
heartbeatTimeout = appHeartbeatTimeoutMap[user.ApplicationID]
|
|
}
|
|
|
|
onlineStatus := getUserOnlineStatus(user, heartbeatTimeout)
|
|
|
|
switch onlineStatus {
|
|
case "online":
|
|
onlineCount++
|
|
case "offline":
|
|
offlineCount++
|
|
case "banned":
|
|
bannedCount++
|
|
}
|
|
|
|
var deviceCount int64
|
|
database.DB.Model(&model.UserDevice{}).Where("user_id = ?", user.ID).Count(&deviceCount)
|
|
|
|
log.Printf("[DEBUG] 用户 %s (ID=%d) 余额: %f", user.Username, user.ID, user.Balance)
|
|
|
|
usersWithStatus = append(usersWithStatus, UserWithStatus{
|
|
AppUser: user,
|
|
OnlineStatus: onlineStatus,
|
|
DeviceCount: int(deviceCount),
|
|
})
|
|
}
|
|
|
|
responseData := gin.H{
|
|
"users": usersWithStatus,
|
|
"total": totalCount,
|
|
"online_count": onlineCount,
|
|
"offline_count": offlineCount,
|
|
"banned_count": bannedCount,
|
|
}
|
|
log.Printf("[DEBUG] Response data: %+v", responseData)
|
|
response.Success(c, responseData)
|
|
}
|
|
|
|
func handleCreateUser(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
var req struct {
|
|
Username string `json:"username"`
|
|
Email string `json:"email"`
|
|
Password string `json:"password"`
|
|
ApplicationID uint `json:"application_id"`
|
|
CardTypeID *uint `json:"card_type_id"`
|
|
CardQuantity int `json:"card_quantity"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
if req.Username == "" {
|
|
response.Error(c, 400, "用户名不能为空")
|
|
return
|
|
}
|
|
|
|
if req.Password == "" {
|
|
response.Error(c, 400, "密码不能为空")
|
|
return
|
|
}
|
|
|
|
if req.ApplicationID == 0 {
|
|
response.Error(c, 400, "所属应用不能为空")
|
|
return
|
|
}
|
|
|
|
if req.CardQuantity < 1 {
|
|
req.CardQuantity = 1
|
|
}
|
|
if req.CardQuantity > 100 {
|
|
response.Error(c, 400, "卡密数量不能超过100")
|
|
return
|
|
}
|
|
|
|
var app model.Application
|
|
if err := database.DB.First(&app, req.ApplicationID).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if app.UserID != userID {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", req.ApplicationID, userID, true).First(&agentApp).Error; err != nil {
|
|
response.Error(c, 403, "无权限在该应用下创建用户")
|
|
return
|
|
}
|
|
}
|
|
|
|
var existingUser model.AppUser
|
|
if err := database.DB.Where("username = ? AND application_id = ?", req.Username, app.ID).First(&existingUser).Error; err == nil {
|
|
response.Error(c, 400, "用户已存在")
|
|
return
|
|
}
|
|
|
|
var cardType *model.CardType
|
|
if req.CardTypeID != nil && *req.CardTypeID > 0 {
|
|
var ct model.CardType
|
|
if err := database.DB.Where("id = ? AND application_id = ?", *req.CardTypeID, req.ApplicationID).First(&ct).Error; err != nil {
|
|
response.Error(c, 400, "卡密类型不存在或不属于该应用")
|
|
return
|
|
}
|
|
cardType = &ct
|
|
}
|
|
|
|
tx := database.DB.Begin()
|
|
|
|
user := model.AppUser{
|
|
Username: req.Username,
|
|
Email: req.Email,
|
|
Password: req.Password,
|
|
Avatar: "",
|
|
Status: "active",
|
|
ApplicationID: app.ID,
|
|
}
|
|
|
|
if err := tx.Create(&user).Error; err != nil {
|
|
tx.Rollback()
|
|
response.Error(c, 500, "创建用户失败")
|
|
return
|
|
}
|
|
|
|
var cards []model.Card
|
|
if cardType != nil {
|
|
now := time.Now()
|
|
|
|
for i := 0; i < req.CardQuantity; i++ {
|
|
cardKey := "CK" + utils.GenerateRandomString(16)
|
|
card := model.Card{
|
|
ApplicationID: req.ApplicationID,
|
|
CardTypeID: cardType.ID,
|
|
CardKey: cardKey,
|
|
CreatorID: userID,
|
|
AppUserID: &user.ID,
|
|
Status: "used",
|
|
}
|
|
card.UsedAt = &now
|
|
|
|
if err := tx.Create(&card).Error; err != nil {
|
|
tx.Rollback()
|
|
response.Error(c, 500, "生成卡密失败")
|
|
return
|
|
}
|
|
|
|
user.IsTrialUser = false
|
|
|
|
if cardType.Value == -1 {
|
|
if cardType.RechargeType == "subscription" {
|
|
permanentExpiry := time.Date(9999, 12, 31, 23, 59, 59, 0, time.UTC)
|
|
user.ExpiryAt = &permanentExpiry
|
|
user.Balance = -1
|
|
} else {
|
|
user.Balance = -1
|
|
user.ExpiryAt = nil
|
|
}
|
|
} else {
|
|
switch cardType.RechargeType {
|
|
case "subscription":
|
|
var baseTime time.Time
|
|
if user.ExpiryAt != nil && user.ExpiryAt.After(now) {
|
|
baseTime = *user.ExpiryAt
|
|
} else {
|
|
baseTime = now
|
|
}
|
|
var duration time.Duration
|
|
switch cardType.ValueUnit {
|
|
case "minute":
|
|
duration = time.Duration(cardType.Value) * time.Minute
|
|
case "hour":
|
|
duration = time.Duration(cardType.Value) * time.Hour
|
|
case "day":
|
|
duration = time.Duration(cardType.Value) * 24 * time.Hour
|
|
case "month":
|
|
duration = time.Duration(cardType.Value) * 30 * 24 * time.Hour
|
|
case "year":
|
|
duration = time.Duration(cardType.Value) * 365 * 24 * time.Hour
|
|
default:
|
|
duration = time.Duration(cardType.Value) * time.Second
|
|
}
|
|
newExpiry := baseTime.Add(duration)
|
|
user.ExpiryAt = &newExpiry
|
|
case "balance":
|
|
fallthrough
|
|
default:
|
|
user.Balance += cardType.Value
|
|
}
|
|
}
|
|
|
|
rechargeRecord := model.RechargeRecord{
|
|
UserID: user.ID,
|
|
OrderNo: generateUserOrderNo("R"),
|
|
CardID: &card.ID,
|
|
CardCode: card.CardKey,
|
|
Amount: cardType.Price,
|
|
Status: "success",
|
|
PaymentType: "card",
|
|
Remark: "创建用户充值 - " + cardType.Name,
|
|
}
|
|
|
|
if err := tx.Create(&rechargeRecord).Error; err != nil {
|
|
tx.Rollback()
|
|
response.Error(c, 500, "创建充值记录失败")
|
|
return
|
|
}
|
|
|
|
cards = append(cards, card)
|
|
}
|
|
|
|
if err := tx.Save(&user).Error; err != nil {
|
|
tx.Rollback()
|
|
response.Error(c, 500, "充值失败")
|
|
return
|
|
}
|
|
}
|
|
|
|
if err := tx.Commit().Error; err != nil {
|
|
response.Error(c, 500, "创建用户失败")
|
|
return
|
|
}
|
|
|
|
logDesc := fmt.Sprintf("创建用户: %s (应用: %s)", user.Username, app.Name)
|
|
if cardType != nil {
|
|
logDesc += fmt.Sprintf(",充值卡密: %s x%d", cardType.Name, req.CardQuantity)
|
|
}
|
|
service.LogOperation(c, "create", "app_user", &user.ID, logDesc, nil)
|
|
|
|
result := gin.H{
|
|
"user": user,
|
|
}
|
|
if len(cards) > 0 {
|
|
result["cards"] = cards
|
|
}
|
|
|
|
response.Success(c, result)
|
|
}
|
|
|
|
func generateUserOrderNo(prefix string) string {
|
|
return prefix + time.Now().Format("20060102150405") + utils.GenerateRandomString(6)
|
|
}
|
|
|
|
func handleGetUser(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id := c.Param("id")
|
|
var user model.AppUser
|
|
if err := database.DB.Preload("Application").First(&user, id).Error; err != nil {
|
|
response.Error(c, 404, "用户不存在")
|
|
return
|
|
}
|
|
|
|
var app model.Application
|
|
if err := database.DB.First(&app, user.ApplicationID).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if app.UserID != userID {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err != nil {
|
|
response.Error(c, 403, "无权限查看该用户")
|
|
return
|
|
}
|
|
|
|
var card model.Card
|
|
if err := database.DB.Where("creator_id = ? AND app_user_id = ?", userID, user.ID).First(&card).Error; err != nil {
|
|
response.Error(c, 403, "无权限查看该用户")
|
|
return
|
|
}
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"user": user,
|
|
})
|
|
}
|
|
|
|
func handleUpdateUser(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id := c.Param("id")
|
|
var req struct {
|
|
Username string `json:"username"`
|
|
Email string `json:"email"`
|
|
Password string `json:"password"`
|
|
Status string `json:"status"`
|
|
ApplicationID uint `json:"application_id"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
var user model.AppUser
|
|
if err := database.DB.First(&user, id).Error; err != nil {
|
|
response.Error(c, 404, "用户不存在")
|
|
return
|
|
}
|
|
|
|
var app model.Application
|
|
if err := database.DB.First(&app, user.ApplicationID).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if app.UserID != userID {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err != nil {
|
|
response.Error(c, 403, "无权限修改该用户")
|
|
return
|
|
}
|
|
|
|
var card model.Card
|
|
if err := database.DB.Where("creator_id = ? AND app_user_id = ?", userID, user.ID).First(&card).Error; err != nil {
|
|
response.Error(c, 403, "无权限修改该用户")
|
|
return
|
|
}
|
|
}
|
|
|
|
if req.Username != "" {
|
|
user.Username = req.Username
|
|
}
|
|
if req.Email != "" {
|
|
user.Email = req.Email
|
|
}
|
|
if req.Password != "" {
|
|
user.Password = req.Password
|
|
}
|
|
if req.Status != "" {
|
|
user.Status = req.Status
|
|
}
|
|
if req.ApplicationID != 0 {
|
|
var newApp model.Application
|
|
if err := database.DB.First(&newApp, req.ApplicationID).Error; err != nil {
|
|
response.Error(c, 404, "目标应用不存在")
|
|
return
|
|
}
|
|
if newApp.UserID != userID {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", req.ApplicationID, userID, true).First(&agentApp).Error; err != nil {
|
|
response.Error(c, 403, "无权限将用户转移到该应用")
|
|
return
|
|
}
|
|
}
|
|
user.ApplicationID = req.ApplicationID
|
|
}
|
|
|
|
if err := database.DB.Save(&user).Error; err != nil {
|
|
response.Error(c, 500, "更新用户失败")
|
|
return
|
|
}
|
|
|
|
service.LogOperation(c, "update", "app_user", &user.ID, fmt.Sprintf("更新用户: %s", user.Username), nil)
|
|
|
|
response.Success(c, user)
|
|
}
|
|
|
|
func handleDeleteUser(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id := c.Param("id")
|
|
|
|
var user model.AppUser
|
|
if err := database.DB.First(&user, id).Error; err != nil {
|
|
response.Error(c, 404, "用户不存在")
|
|
return
|
|
}
|
|
|
|
var app model.Application
|
|
if err := database.DB.First(&app, user.ApplicationID).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if app.UserID != userID {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err != nil {
|
|
response.Error(c, 403, "无权限删除该用户")
|
|
return
|
|
}
|
|
|
|
var card model.Card
|
|
if err := database.DB.Where("creator_id = ? AND app_user_id = ?", userID, user.ID).First(&card).Error; err != nil {
|
|
response.Error(c, 403, "无权限删除该用户")
|
|
return
|
|
}
|
|
}
|
|
|
|
if err := database.DB.Delete(&user).Error; err != nil {
|
|
response.Error(c, 500, "删除用户失败")
|
|
return
|
|
}
|
|
|
|
service.LogOperation(c, "delete", "app_user", &user.ID, fmt.Sprintf("删除用户: %s (应用: %s)", user.Username, app.Name), nil)
|
|
|
|
response.Success(c, nil)
|
|
}
|
|
|
|
func handleGetUserDevices(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id := c.Param("id")
|
|
|
|
var user model.AppUser
|
|
if err := database.DB.First(&user, id).Error; err != nil {
|
|
response.Error(c, 404, "用户不存在")
|
|
return
|
|
}
|
|
|
|
var app model.Application
|
|
if err := database.DB.First(&app, user.ApplicationID).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if app.UserID != userID {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err != nil {
|
|
response.Error(c, 403, "无权限查看该用户设备")
|
|
return
|
|
}
|
|
}
|
|
|
|
var devices []model.UserDevice
|
|
if err := database.DB.Where("user_id = ? AND application_id = ?", user.ID, app.ID).Find(&devices).Error; err != nil {
|
|
response.Error(c, 500, "获取设备列表失败")
|
|
return
|
|
}
|
|
|
|
response.Success(c, devices)
|
|
}
|
|
|
|
func handleUpdateExpiry(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id := c.Param("id")
|
|
var req struct {
|
|
Amount float64 `json:"amount"`
|
|
Type string `json:"type"`
|
|
Field string `json:"field"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.First(&appUser, id).Error; err != nil {
|
|
response.Error(c, 404, "用户不存在")
|
|
return
|
|
}
|
|
|
|
var app model.Application
|
|
if err := database.DB.First(&app, appUser.ApplicationID).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if app.UserID != userID {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err != nil {
|
|
response.Error(c, 403, "无权限修改该用户")
|
|
return
|
|
}
|
|
|
|
var card model.Card
|
|
if err := database.DB.Where("creator_id = ? AND app_user_id = ?", userID, appUser.ID).First(&card).Error; err != nil {
|
|
response.Error(c, 403, "无权限修改该用户")
|
|
return
|
|
}
|
|
}
|
|
|
|
if req.Amount == 0 {
|
|
response.Error(c, 400, "数值不能为0")
|
|
return
|
|
}
|
|
|
|
if appUser.Balance == -1 {
|
|
response.Error(c, 400, "该用户为永久会员,无需操作")
|
|
return
|
|
}
|
|
|
|
now := time.Now()
|
|
|
|
if app.BillingType == "subscription" || req.Field == "days" {
|
|
if req.Type == "recharge" {
|
|
var baseTime time.Time
|
|
if appUser.ExpiryAt != nil && appUser.ExpiryAt.After(now) {
|
|
baseTime = *appUser.ExpiryAt
|
|
} else {
|
|
baseTime = now
|
|
}
|
|
duration := time.Duration(req.Amount) * 24 * time.Hour
|
|
newExpiry := baseTime.Add(duration)
|
|
appUser.ExpiryAt = &newExpiry
|
|
} else if req.Type == "deduct" {
|
|
if appUser.ExpiryAt == nil || appUser.ExpiryAt.Before(now) {
|
|
response.Error(c, 400, "用户订阅已过期")
|
|
return
|
|
}
|
|
duration := time.Duration(req.Amount) * 24 * time.Hour
|
|
newExpiry := appUser.ExpiryAt.Add(-duration)
|
|
if newExpiry.Before(now) {
|
|
newExpiry = now
|
|
}
|
|
appUser.ExpiryAt = &newExpiry
|
|
} else {
|
|
response.Error(c, 400, "操作类型错误")
|
|
return
|
|
}
|
|
} else {
|
|
if req.Type == "recharge" {
|
|
appUser.Balance += req.Amount
|
|
} else if req.Type == "deduct" {
|
|
if appUser.Balance < req.Amount {
|
|
response.Error(c, 400, "余额不足")
|
|
return
|
|
}
|
|
appUser.Balance -= req.Amount
|
|
} else {
|
|
response.Error(c, 400, "操作类型错误")
|
|
return
|
|
}
|
|
}
|
|
|
|
if err := database.DB.Save(&appUser).Error; err != nil {
|
|
response.Error(c, 500, "更新失败")
|
|
return
|
|
}
|
|
|
|
response.Success(c, appUser)
|
|
}
|
|
|
|
func handleBatchUpdateStatus(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
var req struct {
|
|
UserIDs []uint `json:"user_ids"`
|
|
Status string `json:"status"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
var users []model.AppUser
|
|
if err := database.DB.Where("id IN ?", req.UserIDs).Find(&users).Error; err != nil {
|
|
response.Error(c, 500, "获取用户列表失败")
|
|
return
|
|
}
|
|
|
|
var validUserIDs []uint
|
|
for _, user := range users {
|
|
var app model.Application
|
|
if err := database.DB.First(&app, user.ApplicationID).Error; err != nil {
|
|
continue
|
|
}
|
|
|
|
if app.UserID == userID {
|
|
validUserIDs = append(validUserIDs, user.ID)
|
|
} else {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err == nil {
|
|
var card model.Card
|
|
if err := database.DB.Where("creator_id = ? AND app_user_id = ?", userID, user.ID).First(&card).Error; err == nil {
|
|
validUserIDs = append(validUserIDs, user.ID)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(validUserIDs) > 0 {
|
|
if err := database.DB.Model(&model.AppUser{}).Where("id IN ?", validUserIDs).Update("status", req.Status).Error; err != nil {
|
|
response.Error(c, 500, "批量更新状态失败")
|
|
return
|
|
}
|
|
}
|
|
|
|
response.Success(c, nil)
|
|
}
|
|
|
|
func handleBatchDelete(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
var req struct {
|
|
UserIDs []uint `json:"user_ids"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
var users []model.AppUser
|
|
if err := database.DB.Where("id IN ?", req.UserIDs).Find(&users).Error; err != nil {
|
|
response.Error(c, 500, "获取用户列表失败")
|
|
return
|
|
}
|
|
|
|
var validUserIDs []uint
|
|
for _, user := range users {
|
|
var app model.Application
|
|
if err := database.DB.First(&app, user.ApplicationID).Error; err != nil {
|
|
continue
|
|
}
|
|
|
|
if app.UserID == userID {
|
|
validUserIDs = append(validUserIDs, user.ID)
|
|
} else {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", app.ID, userID, true).First(&agentApp).Error; err == nil {
|
|
var card model.Card
|
|
if err := database.DB.Where("creator_id = ? AND app_user_id = ?", userID, user.ID).First(&card).Error; err == nil {
|
|
validUserIDs = append(validUserIDs, user.ID)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(validUserIDs) > 0 {
|
|
if err := database.DB.Where("id IN ?", validUserIDs).Delete(&model.AppUser{}).Error; err != nil {
|
|
response.Error(c, 500, "批量删除失败")
|
|
return
|
|
}
|
|
}
|
|
|
|
response.Success(c, nil)
|
|
}
|