✨ 新增几大中心功能
This commit is contained in:
704
server/api/v1/admin/app_users.go
Normal file
704
server/api/v1/admin/app_users.go
Normal file
@@ -0,0 +1,704 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.echol.cn/loser/Go-Web-Template/server/global"
|
||||
appModel "git.echol.cn/loser/Go-Web-Template/server/model/app"
|
||||
"git.echol.cn/loser/Go-Web-Template/server/model/common/response"
|
||||
systemSvc "git.echol.cn/loser/Go-Web-Template/server/service/system"
|
||||
"git.echol.cn/loser/Go-Web-Template/server/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type AppUsersApi struct{}
|
||||
|
||||
type appUserListItem struct {
|
||||
ID uint `json:"id"`
|
||||
UUID string `json:"uuid"`
|
||||
Username string `json:"username"`
|
||||
Enable int `json:"enable"`
|
||||
NickName string `json:"nickName,omitempty"`
|
||||
AccountBalanceLi int64 `json:"accountBalanceLi"`
|
||||
GameCoinBalanceLi int64 `json:"gameCoinBalanceLi"`
|
||||
LastLoginAt *time.Time `json:"lastLoginAt,omitempty"`
|
||||
LastActiveAt *time.Time `json:"lastActiveAt,omitempty"`
|
||||
IsOnline bool `json:"isOnline"`
|
||||
}
|
||||
|
||||
type createAppUserRequest struct {
|
||||
Username string `json:"username" binding:"required,min=3,max=64"`
|
||||
Password string `json:"password" binding:"required,min=6,max=128"`
|
||||
Enable *bool `json:"enable"`
|
||||
NickName string `json:"nickName"`
|
||||
WelcomePhrase string `json:"welcomePhrase"`
|
||||
}
|
||||
|
||||
type updateAppUserRequest struct {
|
||||
Enable *bool `json:"enable"`
|
||||
WelcomePhrase *string `json:"welcomePhrase"`
|
||||
}
|
||||
|
||||
type resetPasswordRequest struct {
|
||||
NewPassword string `json:"newPassword" binding:"required,min=6,max=128"`
|
||||
}
|
||||
|
||||
type appUserDetailItem struct {
|
||||
ID uint `json:"id"`
|
||||
UUID string `json:"uuid"`
|
||||
Username string `json:"username"`
|
||||
Enable int `json:"enable"`
|
||||
NickName string `json:"nickName,omitempty"`
|
||||
WelcomePhrase string `json:"welcomePhrase,omitempty"`
|
||||
}
|
||||
|
||||
type appUserOverviewResponse struct {
|
||||
User struct {
|
||||
ID uint `json:"id"`
|
||||
UUID string `json:"uuid"`
|
||||
Username string `json:"username"`
|
||||
Enable int `json:"enable"`
|
||||
NickName string `json:"nickName,omitempty"`
|
||||
} `json:"user"`
|
||||
Asset struct {
|
||||
AccountBalanceLi int64 `json:"accountBalanceLi"`
|
||||
GameCoinBalanceLi int64 `json:"gameCoinBalanceLi"`
|
||||
} `json:"asset"`
|
||||
Activity struct {
|
||||
LastLoginAt *time.Time `json:"lastLoginAt,omitempty"`
|
||||
LastActiveAt *time.Time `json:"lastActiveAt,omitempty"`
|
||||
LastActiveIP string `json:"lastActiveIp,omitempty"`
|
||||
IsOnline bool `json:"isOnline"`
|
||||
} `json:"activity"`
|
||||
RecentLoginLogs []appModel.AppLoginLog `json:"recentLoginLogs"`
|
||||
RecentTx []appModel.AppAssetTransaction `json:"recentTx"`
|
||||
Invite struct {
|
||||
InviterUserID *uint `json:"inviterUserId,omitempty"`
|
||||
InviterUsername string `json:"inviterUsername,omitempty"`
|
||||
InvitedCount int64 `json:"invitedCount"`
|
||||
HasUnusedCode bool `json:"hasUnusedCode"`
|
||||
UnusedCodeLast4 string `json:"unusedCodeLast4,omitempty"`
|
||||
UnusedExpiresAt *time.Time `json:"unusedExpiresAt,omitempty"`
|
||||
} `json:"invite"`
|
||||
}
|
||||
|
||||
// GetAppUsersList
|
||||
// @Tags AppUsersAdmin
|
||||
// @Summary 后台获取玩家列表
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param pageSize query int false "每页大小" default(10)
|
||||
// @Param keyword query string false "用户名关键字"
|
||||
// @Param isOnline query bool false "是否在线(基于 lastActiveAt 与在线窗口判断)"
|
||||
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
|
||||
// @Router /admin/app-users [get]
|
||||
func (a *AppUsersApi) GetAppUsersList(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize <= 0 || pageSize > 200 {
|
||||
pageSize = 10
|
||||
}
|
||||
keyword := c.Query("keyword")
|
||||
var isOnlineFilter *bool
|
||||
if raw := strings.TrimSpace(c.Query("isOnline")); raw != "" {
|
||||
if v, err := strconv.ParseBool(raw); err == nil {
|
||||
isOnlineFilter = &v
|
||||
}
|
||||
}
|
||||
|
||||
db := global.GVA_DB.Model(&appModel.AppUser{})
|
||||
if keyword != "" {
|
||||
db = db.Where("username ILIKE ?", "%"+keyword+"%")
|
||||
}
|
||||
// 在线状态过滤:通过 join 活跃表,按窗口阈值判断
|
||||
windowMin := systemSvc.GetAppOnlineWindowMinutes()
|
||||
now := time.Now()
|
||||
if isOnlineFilter != nil {
|
||||
threshold := now.Add(-time.Duration(windowMin) * time.Minute)
|
||||
db = db.Joins("LEFT JOIN app_user_activity act ON act.app_user_id = app_users.id")
|
||||
db = db.Select("app_users.*")
|
||||
if *isOnlineFilter {
|
||||
db = db.Where("act.last_active_at IS NOT NULL AND act.last_active_at >= ?", threshold)
|
||||
} else {
|
||||
db = db.Where("act.last_active_at IS NULL OR act.last_active_at < ?", threshold)
|
||||
}
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := db.Count(&total).Error; err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
var users []appModel.AppUser
|
||||
if err := db.Order("id desc").Limit(pageSize).Offset((page - 1) * pageSize).Find(&users).Error; err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
ids := make([]uint, 0, len(users))
|
||||
for _, u := range users {
|
||||
ids = append(ids, u.ID)
|
||||
}
|
||||
|
||||
profiles := map[uint]appModel.AppUserProfile{}
|
||||
if len(ids) > 0 {
|
||||
var list []appModel.AppUserProfile
|
||||
_ = global.GVA_DB.Where("app_user_id IN ?", ids).Find(&list).Error
|
||||
for _, p := range list {
|
||||
profiles[p.AppUserID] = p
|
||||
}
|
||||
}
|
||||
|
||||
assets := map[uint]appModel.AppUserAsset{}
|
||||
if len(ids) > 0 {
|
||||
var list []appModel.AppUserAsset
|
||||
_ = global.GVA_DB.Where("app_user_id IN ?", ids).Find(&list).Error
|
||||
for _, a := range list {
|
||||
assets[a.AppUserID] = a
|
||||
}
|
||||
}
|
||||
|
||||
activities := map[uint]appModel.AppUserActivity{}
|
||||
if len(ids) > 0 {
|
||||
var list []appModel.AppUserActivity
|
||||
_ = global.GVA_DB.Where("app_user_id IN ?", ids).Find(&list).Error
|
||||
for _, a := range list {
|
||||
activities[a.AppUserID] = a
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]appUserListItem, 0, len(users))
|
||||
for _, u := range users {
|
||||
p := profiles[u.ID]
|
||||
asset := assets[u.ID]
|
||||
act := activities[u.ID]
|
||||
isOnline := false
|
||||
if act.LastActiveAt != nil && windowMin > 0 {
|
||||
isOnline = now.Sub(*act.LastActiveAt) <= time.Duration(windowMin)*time.Minute
|
||||
}
|
||||
items = append(items, appUserListItem{
|
||||
ID: u.ID,
|
||||
UUID: u.UUID.String(),
|
||||
Username: u.Username,
|
||||
Enable: u.Enable,
|
||||
NickName: p.NickName,
|
||||
AccountBalanceLi: asset.AccountBalanceLi,
|
||||
GameCoinBalanceLi: asset.GameCoinBalanceLi,
|
||||
LastLoginAt: act.LastLoginAt,
|
||||
LastActiveAt: act.LastActiveAt,
|
||||
IsOnline: isOnline,
|
||||
})
|
||||
}
|
||||
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: items,
|
||||
Total: total,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
||||
type rechargeRequest struct {
|
||||
AssetType string `json:"assetType" binding:"required"`
|
||||
RechargeType string `json:"rechargeType" binding:"required"`
|
||||
DeltaLi int64 `json:"deltaLi" binding:"required"`
|
||||
Reason string `json:"reason" binding:"required"`
|
||||
}
|
||||
|
||||
// RechargeAppUser
|
||||
// @Tags AppUsersAdmin
|
||||
// @Summary 后台手动充值(账户余额/游戏币,单位:厘)
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param id path int true "玩家ID"
|
||||
// @Param data body rechargeRequest true "充值信息"
|
||||
// @Success 200 {object} response.Response{msg=string} "充值成功"
|
||||
// @Router /admin/app-users/{id}/recharge [post]
|
||||
func (a *AppUsersApi) RechargeAppUser(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
if id <= 0 {
|
||||
response.FailWithMessage("参数错误", c)
|
||||
return
|
||||
}
|
||||
var req rechargeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
req.AssetType = strings.TrimSpace(req.AssetType)
|
||||
req.RechargeType = strings.TrimSpace(req.RechargeType)
|
||||
req.Reason = strings.TrimSpace(req.Reason)
|
||||
if req.Reason == "" {
|
||||
response.FailWithMessage("原因不能为空", c)
|
||||
return
|
||||
}
|
||||
if req.DeltaLi == 0 {
|
||||
response.FailWithMessage("变动金额不能为 0", c)
|
||||
return
|
||||
}
|
||||
if req.AssetType != "account" && req.AssetType != "game_coin" {
|
||||
response.FailWithMessage("assetType 不合法", c)
|
||||
return
|
||||
}
|
||||
if req.RechargeType != "offline" && req.RechargeType != "online_not_arrived" && req.RechargeType != "activity_subsidy" && req.RechargeType != "manual_adjustment" {
|
||||
response.FailWithMessage("rechargeType 不合法", c)
|
||||
return
|
||||
}
|
||||
if req.RechargeType == "activity_subsidy" && req.AssetType != "game_coin" {
|
||||
response.FailWithMessage("活动补贴仅支持充值游戏币", c)
|
||||
return
|
||||
}
|
||||
|
||||
operatorID := utils.GetUserID(c)
|
||||
if operatorID == 0 {
|
||||
response.FailWithMessage("未登录", c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := global.GVA_DB.Transaction(func(tx *gorm.DB) error {
|
||||
// 确保玩家存在
|
||||
var user appModel.AppUser
|
||||
if err := tx.First(&user, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.New("用户不存在")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var asset appModel.AppUserAsset
|
||||
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("app_user_id = ?", user.ID).First(&asset).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
asset = appModel.AppUserAsset{AppUserID: user.ID}
|
||||
if err := tx.Create(&asset).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("app_user_id = ?", user.ID).First(&asset).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var before, after int64
|
||||
if req.AssetType == "account" {
|
||||
before = asset.AccountBalanceLi
|
||||
after = before + req.DeltaLi
|
||||
if after < 0 {
|
||||
return errors.New("账户余额不足")
|
||||
}
|
||||
asset.AccountBalanceLi = after
|
||||
if err := tx.Model(&asset).Select("account_balance_li").Updates(&asset).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
before = asset.GameCoinBalanceLi
|
||||
after = before + req.DeltaLi
|
||||
if after < 0 {
|
||||
return errors.New("游戏币余额不足")
|
||||
}
|
||||
asset.GameCoinBalanceLi = after
|
||||
if err := tx.Model(&asset).Select("game_coin_balance_li").Updates(&asset).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
txRec := appModel.AppAssetTransaction{
|
||||
AppUserID: user.ID,
|
||||
AssetType: appModel.AppAssetType(req.AssetType),
|
||||
RechargeType: appModel.AppRechargeType(req.RechargeType),
|
||||
DeltaLi: req.DeltaLi,
|
||||
BeforeLi: before,
|
||||
AfterLi: after,
|
||||
Reason: req.Reason,
|
||||
OperatorUserID: operatorID,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
return tx.Create(&txRec).Error
|
||||
}); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("充值成功", c)
|
||||
}
|
||||
|
||||
// GetAppUserById
|
||||
// @Tags AppUsersAdmin
|
||||
// @Summary 后台获取玩家详情
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param id path int true "玩家ID"
|
||||
// @Success 200 {object} response.Response{data=appUserDetailItem,msg=string} "获取成功"
|
||||
// @Router /admin/app-users/{id} [get]
|
||||
func (a *AppUsersApi) GetAppUserById(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
if id <= 0 {
|
||||
response.FailWithMessage("参数错误", c)
|
||||
return
|
||||
}
|
||||
var user appModel.AppUser
|
||||
if err := global.GVA_DB.First(&user, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
response.FailWithMessage("用户不存在", c)
|
||||
return
|
||||
}
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
var profile appModel.AppUserProfile
|
||||
_ = global.GVA_DB.Where("app_user_id = ?", user.ID).First(&profile).Error
|
||||
|
||||
response.OkWithData(appUserDetailItem{
|
||||
ID: user.ID,
|
||||
UUID: user.UUID.String(),
|
||||
Username: user.Username,
|
||||
Enable: user.Enable,
|
||||
NickName: profile.NickName,
|
||||
WelcomePhrase: profile.WelcomePhrase,
|
||||
}, c)
|
||||
}
|
||||
|
||||
// GetAppUserOverview
|
||||
// @Tags AppUsersAdmin
|
||||
// @Summary 后台获取玩家聚合详情(概览)
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param id path int true "玩家ID"
|
||||
// @Success 200 {object} response.Response{data=appUserOverviewResponse,msg=string} "获取成功"
|
||||
// @Router /admin/app-users/{id}/overview [get]
|
||||
func (a *AppUsersApi) GetAppUserOverview(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
if id <= 0 {
|
||||
response.FailWithMessage("参数错误", c)
|
||||
return
|
||||
}
|
||||
|
||||
var user appModel.AppUser
|
||||
if err := global.GVA_DB.First(&user, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
response.FailWithMessage("用户不存在", c)
|
||||
return
|
||||
}
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
var profile appModel.AppUserProfile
|
||||
_ = global.GVA_DB.Where("app_user_id = ?", user.ID).First(&profile).Error
|
||||
|
||||
var asset appModel.AppUserAsset
|
||||
_ = global.GVA_DB.Where("app_user_id = ?", user.ID).First(&asset).Error
|
||||
|
||||
var act appModel.AppUserActivity
|
||||
_ = global.GVA_DB.Where("app_user_id = ?", user.ID).First(&act).Error
|
||||
|
||||
windowMin := systemSvc.GetAppOnlineWindowMinutes()
|
||||
now := time.Now()
|
||||
isOnline := false
|
||||
if act.LastActiveAt != nil && windowMin > 0 {
|
||||
isOnline = now.Sub(*act.LastActiveAt) <= time.Duration(windowMin)*time.Minute
|
||||
}
|
||||
|
||||
var recentLoginLogs []appModel.AppLoginLog
|
||||
_ = global.GVA_DB.Where("app_user_id = ?", user.ID).Order("id desc").Limit(20).Find(&recentLoginLogs).Error
|
||||
|
||||
var recentTx []appModel.AppAssetTransaction
|
||||
_ = global.GVA_DB.Where("app_user_id = ?", user.ID).Order("id desc").Limit(20).Find(&recentTx).Error
|
||||
|
||||
// invite summary
|
||||
var invitedCount int64
|
||||
_ = global.GVA_DB.Model(&appModel.AppUserInviteRelation{}).Where("inviter_user_id = ?", user.ID).Count(&invitedCount).Error
|
||||
|
||||
var inviterUserID *uint
|
||||
var inviterUsername string
|
||||
{
|
||||
var rel appModel.AppUserInviteRelation
|
||||
if err := global.GVA_DB.Where("invitee_user_id = ?", user.ID).First(&rel).Error; err == nil {
|
||||
inviterUserID = &rel.InviterUserID
|
||||
var inviter appModel.AppUser
|
||||
_ = global.GVA_DB.Select("id, username").First(&inviter, rel.InviterUserID).Error
|
||||
inviterUsername = inviter.Username
|
||||
}
|
||||
}
|
||||
|
||||
hasUnusedCode := false
|
||||
var unusedLast4 string
|
||||
var unusedExpiresAt *time.Time
|
||||
{
|
||||
var code appModel.AppInviteCode
|
||||
err := global.GVA_DB.
|
||||
Where("created_by_user_id = ? AND status = ?", user.ID, appModel.InviteCodeStatusUnused).
|
||||
Order("id desc").
|
||||
First(&code).Error
|
||||
if err == nil {
|
||||
hasUnusedCode = true
|
||||
unusedLast4 = code.CodeLast4
|
||||
unusedExpiresAt = code.ExpiresAt
|
||||
}
|
||||
}
|
||||
|
||||
var resp appUserOverviewResponse
|
||||
resp.User.ID = user.ID
|
||||
resp.User.UUID = user.UUID.String()
|
||||
resp.User.Username = user.Username
|
||||
resp.User.Enable = user.Enable
|
||||
resp.User.NickName = profile.NickName
|
||||
resp.Asset.AccountBalanceLi = asset.AccountBalanceLi
|
||||
resp.Asset.GameCoinBalanceLi = asset.GameCoinBalanceLi
|
||||
resp.Activity.LastLoginAt = act.LastLoginAt
|
||||
resp.Activity.LastActiveAt = act.LastActiveAt
|
||||
resp.Activity.LastActiveIP = act.LastActiveIP
|
||||
resp.Activity.IsOnline = isOnline
|
||||
resp.RecentLoginLogs = recentLoginLogs
|
||||
resp.RecentTx = recentTx
|
||||
resp.Invite.InviterUserID = inviterUserID
|
||||
resp.Invite.InviterUsername = inviterUsername
|
||||
resp.Invite.InvitedCount = invitedCount
|
||||
resp.Invite.HasUnusedCode = hasUnusedCode
|
||||
resp.Invite.UnusedCodeLast4 = unusedLast4
|
||||
resp.Invite.UnusedExpiresAt = unusedExpiresAt
|
||||
|
||||
response.OkWithDetailed(resp, "获取成功", c)
|
||||
}
|
||||
|
||||
// CreateAppUser
|
||||
// @Tags AppUsersAdmin
|
||||
// @Summary 后台手动新增玩家
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param data body createAppUserRequest true "玩家信息"
|
||||
// @Success 200 {object} response.Response{msg=string} "创建成功"
|
||||
// @Router /admin/app-users [post]
|
||||
func (a *AppUsersApi) CreateAppUser(c *gin.Context) {
|
||||
var req createAppUserRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
req.Username = strings.TrimSpace(req.Username)
|
||||
req.NickName = strings.TrimSpace(req.NickName)
|
||||
req.WelcomePhrase = strings.TrimSpace(req.WelcomePhrase)
|
||||
|
||||
enable := 1
|
||||
if req.Enable != nil && !*req.Enable {
|
||||
enable = 2
|
||||
}
|
||||
|
||||
if err := global.GVA_DB.Transaction(func(tx *gorm.DB) error {
|
||||
var existed appModel.AppUser
|
||||
if err := tx.Where("username = ?", req.Username).First(&existed).Error; err == nil {
|
||||
return errors.New("用户名已存在")
|
||||
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
|
||||
user := appModel.AppUser{
|
||||
UUID: uuid.New(),
|
||||
Username: req.Username,
|
||||
Password: utils.BcryptHash(req.Password),
|
||||
Enable: enable,
|
||||
}
|
||||
if err := tx.Create(&user).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
profile := appModel.AppUserProfile{
|
||||
AppUserID: user.ID,
|
||||
WelcomePhrase: req.WelcomePhrase,
|
||||
NickName: firstNonEmpty(req.NickName, req.Username),
|
||||
}
|
||||
return tx.Create(&profile).Error
|
||||
}); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("创建成功", c)
|
||||
}
|
||||
|
||||
// UpdateAppUser
|
||||
// @Tags AppUsersAdmin
|
||||
// @Summary 编辑玩家(仅启用状态/欢迎词)
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param id path int true "玩家ID"
|
||||
// @Param data body updateAppUserRequest true "更新字段"
|
||||
// @Success 200 {object} response.Response{msg=string} "更新成功"
|
||||
// @Router /admin/app-users/{id} [patch]
|
||||
func (a *AppUsersApi) UpdateAppUser(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
if id <= 0 {
|
||||
response.FailWithMessage("参数错误", c)
|
||||
return
|
||||
}
|
||||
var req updateAppUserRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := global.GVA_DB.Transaction(func(tx *gorm.DB) error {
|
||||
var user appModel.AppUser
|
||||
if err := tx.First(&user, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.New("用户不存在")
|
||||
}
|
||||
return err
|
||||
}
|
||||
if req.Enable != nil {
|
||||
if *req.Enable {
|
||||
user.Enable = 1
|
||||
} else {
|
||||
user.Enable = 2
|
||||
}
|
||||
if err := tx.Model(&user).Select("enable").Updates(&user).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if req.WelcomePhrase != nil {
|
||||
wp := strings.TrimSpace(*req.WelcomePhrase)
|
||||
var profile appModel.AppUserProfile
|
||||
err := tx.Where("app_user_id = ?", user.ID).First(&profile).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
profile = appModel.AppUserProfile{
|
||||
AppUserID: user.ID,
|
||||
WelcomePhrase: wp,
|
||||
NickName: user.Username,
|
||||
}
|
||||
return tx.Create(&profile).Error
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
profile.WelcomePhrase = wp
|
||||
return tx.Model(&profile).Select("welcome_phrase").Updates(&profile).Error
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("更新成功", c)
|
||||
}
|
||||
|
||||
// ResetAppUserPassword
|
||||
// @Tags AppUsersAdmin
|
||||
// @Summary 重置玩家密码
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param id path int true "玩家ID"
|
||||
// @Param data body resetPasswordRequest true "新密码"
|
||||
// @Success 200 {object} response.Response{msg=string} "重置成功"
|
||||
// @Router /admin/app-users/{id}/reset-password [post]
|
||||
func (a *AppUsersApi) ResetAppUserPassword(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
if id <= 0 {
|
||||
response.FailWithMessage("参数错误", c)
|
||||
return
|
||||
}
|
||||
var req resetPasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
var user appModel.AppUser
|
||||
if err := global.GVA_DB.First(&user, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
response.FailWithMessage("用户不存在", c)
|
||||
return
|
||||
}
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if err := global.GVA_DB.Model(&user).Update("password", utils.BcryptHash(req.NewPassword)).Error; err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("重置成功", c)
|
||||
}
|
||||
|
||||
// ToggleAppUserEnable
|
||||
// @Tags AppUsersAdmin
|
||||
// @Summary 启用/停用玩家
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param id path int true "玩家ID"
|
||||
// @Success 200 {object} response.Response{msg=string} "操作成功"
|
||||
// @Router /admin/app-users/{id}/toggle-enable [post]
|
||||
func (a *AppUsersApi) ToggleAppUserEnable(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
if id <= 0 {
|
||||
response.FailWithMessage("参数错误", c)
|
||||
return
|
||||
}
|
||||
var user appModel.AppUser
|
||||
if err := global.GVA_DB.First(&user, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
response.FailWithMessage("用户不存在", c)
|
||||
return
|
||||
}
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
next := 1
|
||||
if user.Enable == 1 {
|
||||
next = 2
|
||||
}
|
||||
if err := global.GVA_DB.Model(&user).Update("enable", next).Error; err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("操作成功", c)
|
||||
}
|
||||
|
||||
// DeleteAppUser
|
||||
// @Tags AppUsersAdmin
|
||||
// @Summary 软删除玩家
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param id path int true "玩家ID"
|
||||
// @Success 200 {object} response.Response{msg=string} "删除成功"
|
||||
// @Router /admin/app-users/{id} [delete]
|
||||
func (a *AppUsersApi) DeleteAppUser(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
if id <= 0 {
|
||||
response.FailWithMessage("参数错误", c)
|
||||
return
|
||||
}
|
||||
var user appModel.AppUser
|
||||
if err := global.GVA_DB.First(&user, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
response.FailWithMessage("用户不存在", c)
|
||||
return
|
||||
}
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
if err := global.GVA_DB.Delete(&user).Error; err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, v := range values {
|
||||
if v != "" {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user