705 lines
21 KiB
Go
705 lines
21 KiB
Go
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 ""
|
|
}
|