Files
soul-yongping/soul-api/internal/handler/orders.go

206 lines
6.1 KiB
Go
Raw Normal View History

2026-02-25 11:52:11 +08:00
package handler
import (
"encoding/json"
"net/http"
"strconv"
"strings"
"time"
2026-02-25 11:52:11 +08:00
"soul-api/internal/database"
"soul-api/internal/model"
"github.com/gin-gonic/gin"
)
// OrdersList GET /api/orders带用户昵称/头像/手机号,分销佣金按配置比例计算;支持分页 page、pageSize筛选 status搜索 search
2026-02-25 11:52:11 +08:00
func OrdersList(c *gin.Context) {
db := database.DB()
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
statusFilter := c.Query("status")
search := strings.TrimSpace(c.Query("search"))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 10
}
q := db.Model(&model.Order{})
if statusFilter != "" && statusFilter != "all" {
if statusFilter == "completed" {
q = q.Where("status IN ?", []string{"paid", "completed"})
} else {
q = q.Where("status = ?", statusFilter)
}
}
if search != "" {
pattern := "%" + search + "%"
q = q.Where("order_sn LIKE ? OR id LIKE ? OR user_id IN (SELECT id FROM users WHERE COALESCE(nickname,'') LIKE ? OR COALESCE(phone,'') LIKE ? OR id LIKE ?)",
pattern, pattern, pattern, pattern, pattern)
}
var total int64
q.Count(&total)
var totalRevenue, todayRevenue float64
db.Model(&model.Order{}).Select("COALESCE(SUM(amount), 0)").
Where("status IN ?", []string{"paid", "completed"}).Scan(&totalRevenue)
todayStart := time.Now().Truncate(24 * time.Hour)
todayEnd := todayStart.Add(24 * time.Hour)
db.Model(&model.Order{}).Select("COALESCE(SUM(amount), 0)").
Where("status IN ? AND created_at >= ? AND created_at < ?", []string{"paid", "completed"}, todayStart, todayEnd).
Scan(&todayRevenue)
2026-02-25 11:52:11 +08:00
var orders []model.Order
query := db.Model(&model.Order{})
if statusFilter != "" && statusFilter != "all" {
if statusFilter == "completed" {
query = query.Where("status IN ?", []string{"paid", "completed"})
} else {
query = query.Where("status = ?", statusFilter)
}
}
if search != "" {
pattern := "%" + search + "%"
query = query.Where("order_sn LIKE ? OR id LIKE ? OR user_id IN (SELECT id FROM users WHERE COALESCE(nickname,'') LIKE ? OR COALESCE(phone,'') LIKE ? OR id LIKE ?)",
pattern, pattern, pattern, pattern, pattern)
}
if err := query.Order("created_at DESC").
Offset((page - 1) * pageSize).
Limit(pageSize).
Find(&orders).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error(), "orders": []interface{}{}, "total": 0})
2026-02-25 11:52:11 +08:00
return
}
totalPages := int(total) / pageSize
if int(total)%pageSize > 0 {
totalPages++
}
2026-02-25 11:52:11 +08:00
if len(orders) == 0 {
c.JSON(http.StatusOK, gin.H{
"success": true, "orders": []interface{}{},
"total": total, "page": page, "pageSize": pageSize, "totalPages": totalPages,
})
2026-02-25 11:52:11 +08:00
return
}
// 分销比例(与支付回调一致)
distributorShare := 0.9
var cfg model.SystemConfig
if err := db.Where("config_key = ?", "referral_config").First(&cfg).Error; err == nil {
var config map[string]interface{}
if _ = json.Unmarshal(cfg.ConfigValue, &config); config["distributorShare"] != nil {
if share, ok := config["distributorShare"].(float64); ok {
distributorShare = share / 100
}
}
}
// 收集订单中的 user_id、referrer_id查用户信息
userIDs := make(map[string]bool)
for _, o := range orders {
if o.UserID != "" {
userIDs[o.UserID] = true
}
if o.ReferrerID != nil && *o.ReferrerID != "" {
userIDs[*o.ReferrerID] = true
}
}
ids := make([]string, 0, len(userIDs))
for id := range userIDs {
ids = append(ids, id)
}
var users []model.User
if len(ids) > 0 {
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 || *s == "" {
return ""
}
return *s
}
out := make([]gin.H, 0, len(orders))
for _, o := range orders {
// 序列化订单为基础字段
b, _ := json.Marshal(o)
var m map[string]interface{}
_ = json.Unmarshal(b, &m)
// 用户信息
if u := userMap[o.UserID]; u != nil {
m["userNickname"] = getStr(u.Nickname)
m["userPhone"] = getStr(u.Phone)
m["userAvatar"] = getStr(u.Avatar)
} else {
m["userNickname"] = ""
m["userPhone"] = ""
m["userAvatar"] = ""
}
// 推荐人信息
if o.ReferrerID != nil && *o.ReferrerID != "" {
if u := userMap[*o.ReferrerID]; u != nil {
m["referrerNickname"] = getStr(u.Nickname)
m["referrerCode"] = getStr(u.ReferralCode)
}
}
// 分销佣金:仅对已支付且存在推荐人的订单,按配置比例计算(与支付回调口径一致)
status := getStr(o.Status)
if status == "paid" && o.ReferrerID != nil && *o.ReferrerID != "" {
m["referrerEarnings"] = o.Amount * distributorShare
} else {
m["referrerEarnings"] = nil
}
out = append(out, m)
}
c.JSON(http.StatusOK, gin.H{
"success": true, "orders": out,
"total": total, "page": page, "pageSize": pageSize, "totalPages": totalPages,
"totalRevenue": totalRevenue, "todayRevenue": todayRevenue,
})
}
// MiniprogramOrders GET /api/miniprogram/orders 小程序-当前用户订单列表(按 userId 过滤,返回 data
func MiniprogramOrders(c *gin.Context) {
userID := c.Query("userId")
if userID == "" {
c.JSON(http.StatusOK, gin.H{"success": true, "data": []interface{}{}})
return
}
db := database.DB()
var orders []model.Order
if err := db.Where("user_id = ?", userID).Order("created_at DESC").Find(&orders).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": true, "data": []interface{}{}})
return
}
out := make([]gin.H, 0, len(orders))
for _, o := range orders {
desc := ""
if o.Description != nil {
desc = *o.Description
}
productID := ""
if o.ProductID != nil {
productID = *o.ProductID
}
status := "created"
if o.Status != nil {
status = *o.Status
}
out = append(out, gin.H{
"id": o.ID, "order_sn": o.OrderSN, "user_id": o.UserID,
"product_id": productID, "product_type": o.ProductType,
"product_name": desc, "section_id": productID,
"amount": o.Amount, "status": status,
"created_at": o.CreatedAt,
})
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": out})
2026-02-25 11:52:11 +08:00
}