157 lines
4.5 KiB
Go
157 lines
4.5 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.Model(&model.MatchRecord{}).Count(&totalMatches)
|
||
var todayMatches int64
|
||
db.Model(&model.MatchRecord{}).Where("created_at >= CURDATE()").Count(&todayMatches)
|
||
type TypeCount struct {
|
||
MatchType string `json:"matchType"`
|
||
Count int64 `json:"count"`
|
||
}
|
||
var byType []TypeCount
|
||
db.Model(&model.MatchRecord{}).Select("match_type as match_type, count(*) as count").Group("match_type").Scan(&byType)
|
||
var uniqueUsers int64
|
||
db.Model(&model.MatchRecord{}).Distinct("user_id").Count(&uniqueUsers)
|
||
|
||
// 匹配收益:product_type=match 且 status=paid 的订单金额总和
|
||
var matchRevenue float64
|
||
db.Model(&model.Order{}).Where("product_type = ? AND status = ?", "match", "paid").
|
||
Select("COALESCE(SUM(amount), 0)").Scan(&matchRevenue)
|
||
var paidMatchCount int64
|
||
db.Model(&model.Order{}).Where("product_type = ? AND status = ?", "match", "paid").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 {
|
||
userIDs[r.UserID] = true
|
||
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
|
||
}
|
||
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": getStr(u.Nickname),
|
||
"matchedNickname": getStr(mu.Nickname),
|
||
"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,
|
||
},
|
||
})
|
||
}
|