Files
soul-yongping/soul-api/internal/handler/match_records.go
卡若 76965adb23 chore: 清理敏感与开发文档,仅同步代码
- 永久忽略并从仓库移除 开发文档/
- 移除并忽略 .env 与小程序私有配置
- 同步小程序/管理端/API与脚本改动

Made-with: Cursor
2026-03-17 17:50:12 +08:00

164 lines
4.7 KiB
Go

package handler
import (
"net/http"
"strconv"
"soul-api/internal/database"
"soul-api/internal/model"
"github.com/gin-gonic/gin"
)
// DBMatchRecordsList GET /api/db/match-records 管理端-匹配记录列表(分页、按类型筛选)
// 当 ?stats=true 时返回汇总统计
func DBMatchRecordsList(c *gin.Context) {
db := database.DB()
if c.Query("stats") == "true" {
var totalMatches int64
db.Raw("SELECT COUNT(*) FROM match_records").Scan(&totalMatches)
var todayMatches int64
db.Raw("SELECT COUNT(*) FROM match_records WHERE created_at >= CURDATE()").Scan(&todayMatches)
type TypeCount struct {
MatchType string `json:"matchType" gorm:"column:match_type"`
Count int64 `json:"count" gorm:"column:count"`
}
var byType []TypeCount
db.Raw("SELECT match_type, COUNT(*) as count FROM match_records GROUP BY match_type").Scan(&byType)
var uniqueUsers int64
db.Raw("SELECT COUNT(DISTINCT user_id) FROM match_records WHERE user_id IS NOT NULL AND user_id != ''").Scan(&uniqueUsers)
var matchRevenue float64
db.Model(&model.Order{}).Where("product_type = ? AND status IN ?", "match", []string{"paid", "completed", "success"}).
Select("COALESCE(SUM(amount), 0)").Scan(&matchRevenue)
var paidMatchCount int64
db.Model(&model.Order{}).Where("product_type = ? AND status IN ?", "match", []string{"paid", "completed", "success"}).Count(&paidMatchCount)
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": gin.H{
"totalMatches": totalMatches,
"todayMatches": todayMatches,
"byType": byType,
"uniqueUsers": uniqueUsers,
"matchRevenue": matchRevenue,
"paidMatchCount": paidMatchCount,
},
})
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
matchType := c.Query("matchType")
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 10
}
q := db.Model(&model.MatchRecord{})
if matchType != "" {
q = q.Where("match_type = ?", matchType)
}
var total int64
q.Count(&total)
var records []model.MatchRecord
if err := q.Order("created_at DESC").Offset((page - 1) * pageSize).Limit(pageSize).Find(&records).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error(), "records": []interface{}{}})
return
}
userIDs := make(map[string]bool)
for _, r := range records {
if r.UserID != "" {
userIDs[r.UserID] = true
}
if r.MatchedUserID != "" {
userIDs[r.MatchedUserID] = true
}
}
ids := make([]string, 0, len(userIDs))
for id := range userIDs {
ids = append(ids, id)
}
var users []model.User
if len(ids) > 0 {
database.DB().Where("id IN ?", ids).Find(&users)
}
userMap := make(map[string]*model.User)
for i := range users {
userMap[users[i].ID] = &users[i]
}
getStr := func(s *string) string {
if s == nil {
return ""
}
return *s
}
out := make([]gin.H, 0, len(records))
for _, r := range records {
u := userMap[r.UserID]
mu := userMap[r.MatchedUserID]
userAvatar := ""
matchedUserAvatar := ""
if u != nil && u.Avatar != nil {
userAvatar = *u.Avatar
}
if mu != nil && mu.Avatar != nil {
matchedUserAvatar = *mu.Avatar
}
userNickname := ""
if u != nil {
userNickname = getStr(u.Nickname)
}
matchedNickname := ""
if mu != nil {
matchedNickname = getStr(mu.Nickname)
}
out = append(out, gin.H{
"id": r.ID, "userId": r.UserID, "matchedUserId": r.MatchedUserID,
"matchType": r.MatchType, "phone": getStr(r.Phone), "wechatId": getStr(r.WechatID),
"userNickname": userNickname,
"matchedNickname": matchedNickname,
"userAvatar": userAvatar,
"matchedUserAvatar": matchedUserAvatar,
"matchScore": r.MatchScore,
"createdAt": r.CreatedAt,
})
}
totalPages := int(total) / pageSize
if int(total)%pageSize > 0 {
totalPages++
}
c.JSON(http.StatusOK, gin.H{
"success": true, "records": out,
"total": total, "page": page, "pageSize": pageSize, "totalPages": totalPages,
})
}
// DBMatchPoolCounts GET /api/db/match-pool-counts 返回各匹配池的用户人数
func DBMatchPoolCounts(c *gin.Context) {
db := database.DB()
var vipCount int64
db.Model(&model.User{}).Where("is_vip = 1 AND vip_expire_date > NOW()").Count(&vipCount)
var completeCount int64
db.Model(&model.User{}).Where(
"(phone IS NOT NULL AND phone != '') AND (nickname IS NOT NULL AND nickname != '' AND nickname != '微信用户') AND (avatar IS NOT NULL AND avatar != '')",
).Count(&completeCount)
var allCount int64
db.Model(&model.User{}).Where(
"((wechat_id IS NOT NULL AND wechat_id != '') OR (phone IS NOT NULL AND phone != ''))",
).Count(&allCount)
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": gin.H{
"vip": vipCount,
"complete": completeCount,
"all": allCount,
},
})
}