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

206 lines
6.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"encoding/json"
"net/http"
"strconv"
"strings"
"time"
"soul-api/internal/database"
"soul-api/internal/model"
"github.com/gin-gonic/gin"
)
// OrdersList GET /api/orders带用户昵称/头像/手机号,分销佣金按配置比例计算;支持分页 page、pageSize筛选 status搜索 search
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)
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})
return
}
totalPages := int(total) / pageSize
if int(total)%pageSize > 0 {
totalPages++
}
if len(orders) == 0 {
c.JSON(http.StatusOK, gin.H{
"success": true, "orders": []interface{}{},
"total": total, "page": page, "pageSize": pageSize, "totalPages": totalPages,
})
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})
}