diff --git a/api/handler/invite_handler.go b/api/handler/invite_handler.go index 40477fed..14c51c5c 100644 --- a/api/handler/invite_handler.go +++ b/api/handler/invite_handler.go @@ -8,14 +8,17 @@ package handler // * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import ( + "fmt" "geekai/core" "geekai/store/model" "geekai/store/vo" "geekai/utils" "geekai/utils/resp" + "strings" + "time" + "github.com/gin-gonic/gin" "gorm.io/gorm" - "strings" ) // InviteHandler 用户邀请 @@ -33,6 +36,8 @@ func (h *InviteHandler) RegisterRoutes() { group.GET("code", h.Code) group.GET("list", h.List) group.GET("hits", h.Hits) + group.GET("stats", h.Stats) + group.GET("rules", h.Rules) } // Code 获取当前用户邀请码 @@ -73,21 +78,34 @@ func (h *InviteHandler) List(c *gin.Context) { var total int64 session.Model(&model.InviteLog{}).Count(&total) var items []model.InviteLog - var list = make([]vo.InviteLog, 0) offset := (page - 1) * pageSize - res := session.Order("id DESC").Offset(offset).Limit(pageSize).Find(&items) - if res.Error == nil { - for _, item := range items { - var v vo.InviteLog - err := utils.CopyObject(item, &v) - if err == nil { - v.Id = item.Id - v.CreatedAt = item.CreatedAt.Unix() - list = append(list, v) - } else { - logger.Error(err) - } + err := session.Order("id DESC").Offset(offset).Limit(pageSize).Find(&items).Error + if err != nil { + resp.ERROR(c, err.Error()) + return + } + + userIds := make([]uint, 0) + for _, item := range items { + userIds = append(userIds, item.UserId) + } + userMap := make(map[uint]model.User) + var users []model.User + h.DB.Model(&model.User{}).Where("id IN (?)", userIds).Find(&users) + for _, user := range users { + userMap[user.Id] = user + } + + var list = make([]vo.InviteLog, 0) + for _, item := range items { + var v vo.InviteLog + err := utils.CopyObject(item, &v) + if err != nil { + continue } + v.CreatedAt = item.CreatedAt.Unix() + v.Avatar = userMap[item.UserId].Avatar + list = append(list, v) } resp.SUCCESS(c, vo.NewPage(total, page, pageSize, list)) } @@ -98,3 +116,89 @@ func (h *InviteHandler) Hits(c *gin.Context) { h.DB.Model(&model.InviteCode{}).Where("code = ?", code).UpdateColumn("hits", gorm.Expr("hits + ?", 1)) resp.SUCCESS(c) } + +// Stats 获取邀请统计 +func (h *InviteHandler) Stats(c *gin.Context) { + userId := h.GetLoginUserId(c) + + // 获取邀请码 + var inviteCode model.InviteCode + res := h.DB.Where("user_id = ?", userId).First(&inviteCode) + if res.Error != nil { + resp.ERROR(c, "邀请码不存在") + return + } + + // 统计累计邀请数 + var totalInvite int64 + h.DB.Model(&model.InviteLog{}).Where("inviter_id = ?", userId).Count(&totalInvite) + + // 统计今日邀请数 + today := time.Now().Format("2006-01-02") + var todayInvite int64 + h.DB.Model(&model.InviteLog{}).Where("inviter_id = ? AND DATE(created_at) = ?", userId, today).Count(&todayInvite) + + // 获取系统配置中的邀请奖励 + var config model.Config + var invitePower int = 200 // 默认值 + if h.DB.Where("name = ?", "system").First(&config).Error == nil { + var configMap map[string]any + if utils.JsonDecode(config.Value, &configMap) == nil { + if power, ok := configMap["invite_power"].(float64); ok { + invitePower = int(power) + } + } + } + + // 计算获得奖励总数 + rewardTotal := int(totalInvite) * invitePower + + // 构建邀请链接 + inviteLink := fmt.Sprintf("%s/register?invite=%s", h.App.Config.StaticUrl, inviteCode.Code) + + stats := vo.InviteStats{ + InviteCount: int(totalInvite), + RewardTotal: rewardTotal, + TodayInvite: int(todayInvite), + InviteCode: inviteCode.Code, + InviteLink: inviteLink, + } + + resp.SUCCESS(c, stats) +} + +// Rules 获取奖励规则 +func (h *InviteHandler) Rules(c *gin.Context) { + // 获取系统配置中的邀请奖励 + var config model.Config + var invitePower int = 200 // 默认值 + if h.DB.Where("name = ?", "system").First(&config).Error == nil { + var configMap map[string]interface{} + if utils.JsonDecode(config.Value, &configMap) == nil { + if power, ok := configMap["invite_power"].(float64); ok { + invitePower = int(power) + } + } + } + + rules := []vo.RewardRule{ + { + Id: 1, + Title: "好友注册", + Desc: "好友通过邀请链接成功注册", + Icon: "icon-user-fill", + Color: "#1989fa", + Reward: invitePower, + }, + { + Id: 2, + Title: "好友首次充值", + Desc: "好友首次充值任意金额", + Icon: "icon-money", + Color: "#07c160", + Reward: invitePower * 2, // 假设首次充值奖励是注册奖励的2倍 + }, + } + + resp.SUCCESS(c, rules) +} diff --git a/api/handler/power_log_handler.go b/api/handler/power_log_handler.go index d4c1f418..a74389fd 100644 --- a/api/handler/power_log_handler.go +++ b/api/handler/power_log_handler.go @@ -14,6 +14,7 @@ import ( "geekai/store/vo" "geekai/utils" "geekai/utils/resp" + "time" "github.com/gin-gonic/gin" "gorm.io/gorm" @@ -31,6 +32,7 @@ func NewPowerLogHandler(app *core.AppServer, db *gorm.DB) *PowerLogHandler { func (h *PowerLogHandler) RegisterRoutes() { group := h.App.Engine.Group("/api/powerLog/") group.POST("list", h.List) + group.GET("stats", h.Stats) } func (h *PowerLogHandler) List(c *gin.Context) { @@ -78,3 +80,45 @@ func (h *PowerLogHandler) List(c *gin.Context) { } resp.SUCCESS(c, vo.NewPage(total, data.Page, data.PageSize, list)) } + +// Stats 获取用户算力统计 +func (h *PowerLogHandler) Stats(c *gin.Context) { + userId := h.GetLoginUserId(c) + if userId == 0 { + resp.NotAuth(c) + return + } + + // 获取用户信息(包含余额) + var user model.User + if err := h.DB.Where("id", userId).First(&user).Error; err != nil { + resp.ERROR(c, "用户不存在") + return + } + + // 计算总消费(所有支出记录) + var totalConsume int64 + h.DB.Model(&model.PowerLog{}). + Where("user_id", userId). + Where("mark", types.PowerSub). + Select("COALESCE(SUM(amount), 0)"). + Scan(&totalConsume) + + // 计算今日消费 + today := time.Now().Format("2006-01-02") + var todayConsume int64 + h.DB.Model(&model.PowerLog{}). + Where("user_id", userId). + Where("mark", types.PowerSub). + Where("DATE(created_at) = ?", today). + Select("COALESCE(SUM(amount), 0)"). + Scan(&todayConsume) + + stats := map[string]interface{}{ + "total": totalConsume, + "today": todayConsume, + "balance": user.Power, + } + + resp.SUCCESS(c, stats) +} diff --git a/api/store/vo/invite_log.go b/api/store/vo/invite_log.go index 3be80c32..4a17f6d3 100644 --- a/api/store/vo/invite_log.go +++ b/api/store/vo/invite_log.go @@ -5,6 +5,7 @@ type InviteLog struct { InviterId uint `json:"inviter_id"` UserId uint `json:"user_id"` Username string `json:"username"` + Avatar string `json:"avatar"` InviteCode string `json:"invite_code"` Remark string `json:"remark"` CreatedAt int64 `json:"created_at"` diff --git a/api/store/vo/invite_stats.go b/api/store/vo/invite_stats.go new file mode 100644 index 00000000..ce372c3c --- /dev/null +++ b/api/store/vo/invite_stats.go @@ -0,0 +1,9 @@ +package vo + +type InviteStats struct { + InviteCount int `json:"invite_count"` // 累计邀请数 + RewardTotal int `json:"reward_total"` // 获得奖励总数 + TodayInvite int `json:"today_invite"` // 今日邀请数 + InviteCode string `json:"invite_code"` // 邀请码 + InviteLink string `json:"invite_link"` // 邀请链接 +} diff --git a/api/store/vo/reward_rule.go b/api/store/vo/reward_rule.go new file mode 100644 index 00000000..b932c3a4 --- /dev/null +++ b/api/store/vo/reward_rule.go @@ -0,0 +1,10 @@ +package vo + +type RewardRule struct { + Id int `json:"id"` // 规则ID + Title string `json:"title"` // 规则标题 + Desc string `json:"desc"` // 规则描述 + Icon string `json:"icon"` // 图标类名 + Color string `json:"color"` // 图标颜色 + Reward int `json:"reward"` // 奖励算力 +} diff --git a/web/src/components/LoginDialog.vue b/web/src/components/LoginDialog.vue index 2c705920..e183895a 100644 --- a/web/src/components/LoginDialog.vue +++ b/web/src/components/LoginDialog.vue @@ -46,24 +46,6 @@ >忘记密码? -