更新小程序环境变量以切换至开发 API 地址,调整分销页面以支持新字段展示,包括推荐人和消费者的头像及昵称,优化绑定记录的状态显示和佣金计算逻辑,提升用户体验和代码可读性。

This commit is contained in:
乘风
2026-02-13 17:32:50 +08:00
parent 35b669c31e
commit eea4a542de
11 changed files with 535 additions and 491 deletions

View File

@@ -1,2 +1,3 @@
# 开发环境:对接当前 Next 后端(与现网 API 路径完全一致,无缝切换)
VITE_API_BASE_URL=https://soulapi.quwanzhi.com
# VITE_API_BASE_URL=https://soulapi.quwanzhi.com
VITE_API_BASE_URL=https://souldev.quwanzhi.com

File diff suppressed because one or more lines are too long

454
soul-admin/dist/assets/index-CbOmKBRd.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,8 +4,8 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>管理后台 - Soul创业派对</title>
<script type="module" crossorigin src="/assets/index-CgjaRP73.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-2chBMZjx.css">
<script type="module" crossorigin src="/assets/index-CbOmKBRd.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DBQ1UORI.css">
</head>
<body>
<div id="root"></div>

View File

@@ -44,14 +44,17 @@ interface Binding {
id: string
referrerId: string
referrerName?: string
referrerCode: string
referrerCode?: string
referrerAvatar?: string | null
refereeId: string
refereePhone?: string
refereeNickname?: string
refereeAvatar?: string | null
boundAt: string
expiresAt: string
status: 'active' | 'converted' | 'expired' | 'cancelled'
commission?: number
totalCommission?: number
}
interface Withdrawal {
@@ -771,8 +774,12 @@ export function DistributionPage() {
<option value="active"></option>
<option value="converted"></option>
<option value="expired"></option>
<option value="cancelled"></option>
</select>
</div>
<p className="text-xs text-gray-500">
30 广 bindingDays = = = =
</p>
<Card className="bg-[#0f2137] border-gray-700/50">
<CardContent className="p-0">
{filteredBindings.length === 0 ? (
@@ -782,8 +789,8 @@ export function DistributionPage() {
<table className="w-full text-sm">
<thead>
<tr className="bg-[#0a1628] text-gray-400">
<th className="p-4 text-left font-medium">访</th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
<th className="p-4 text-left font-medium"></th>
@@ -794,36 +801,55 @@ export function DistributionPage() {
{filteredBindings.map((binding) => (
<tr key={binding.id} className="hover:bg-[#0a1628] transition-colors">
<td className="p-4">
<div>
<p className="text-white font-medium">
{binding.refereeNickname || '匿名用户'}
</p>
<p className="text-gray-500 text-xs">{binding.refereePhone}</p>
<div className="flex items-center gap-2">
<div className="w-8 h-8 rounded-full bg-[#38bdac]/20 flex items-center justify-center text-sm text-[#38bdac] overflow-hidden shrink-0">
{binding.referrerAvatar ? (
<img src={binding.referrerAvatar} className="w-full h-full object-cover" alt="" />
) : (
(binding.referrerName || binding.referrerCode || '?').charAt(0)
)}
</div>
<div>
<p className="text-white font-medium">{binding.referrerName || '-'}</p>
<p className="text-gray-500 text-xs font-mono">
{binding.referrerCode || '-'}
</p>
</div>
</div>
</td>
<td className="p-4">
<div>
<p className="text-white">{binding.referrerName || '-'}</p>
<p className="text-gray-500 text-xs font-mono">
{binding.referrerCode}
</p>
<div className="flex items-center gap-2">
<div className="w-8 h-8 rounded-full bg-[#38bdac]/20 flex items-center justify-center text-sm text-[#38bdac] overflow-hidden shrink-0">
{binding.refereeAvatar ? (
<img src={binding.refereeAvatar} className="w-full h-full object-cover" alt="" />
) : (
(binding.refereeNickname || '?').charAt(0)
)}
</div>
<div>
<p className="text-white">
{binding.refereeNickname || '微信用户'}
</p>
<p className="text-gray-500 text-xs">{binding.refereePhone || '-'}</p>
</div>
</div>
</td>
<td className="p-4 text-gray-400">
{binding.boundAt
? new Date(binding.boundAt).toLocaleDateString('zh-CN')
? new Date(binding.boundAt).toLocaleString('zh-CN', { dateStyle: 'short', timeStyle: 'short' })
: '-'}
</td>
<td className="p-4 text-gray-400">
{binding.expiresAt
? new Date(binding.expiresAt).toLocaleDateString('zh-CN')
? new Date(binding.expiresAt).toLocaleString('zh-CN', { dateStyle: 'short', timeStyle: 'short' })
: '-'}
</td>
<td className="p-4">{getStatusBadge(binding.status)}</td>
<td className="p-4">
{binding.commission ? (
{(binding.totalCommission ?? binding.commission) != null &&
(binding.totalCommission ?? binding.commission) !== undefined ? (
<span className="text-[#38bdac] font-medium">
¥{binding.commission.toFixed(2)}
¥{Number(binding.totalCommission ?? binding.commission).toFixed(2)}
</span>
) : (
<span className="text-gray-500">-</span>

View File

@@ -34,7 +34,7 @@ import {
ChevronRight,
} from 'lucide-react'
import { UserDetailModal } from '@/components/modules/user/UserDetailModal'
import { get, del, post, put } from '@/api/client'
import { get, del, put } from '@/api/client'
interface User {
id: string

View File

@@ -781,31 +781,48 @@ func DBDistribution(c *gin.Context) {
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(bindings))
for _, b := range bindings {
refNick := "用户"
if u := userMap[b.RefereeID]; u != nil && u.Nickname != nil {
refNick = *u.Nickname
} else {
refNick = refNick + b.RefereeID
refNick := "微信用户"
var refereePhone, refereeAvatar *string
if u := userMap[b.RefereeID]; u != nil {
if u.Nickname != nil && *u.Nickname != "" {
refNick = *u.Nickname
} else {
refNick = "微信用户"
}
refereePhone = u.Phone
refereeAvatar = u.Avatar
}
var referrerName *string
var referrerName, referrerAvatar *string
if u := userMap[b.ReferrerID]; u != nil {
referrerName = u.Nickname
referrerAvatar = u.Avatar
}
days := 0
if b.ExpiryDate.After(time.Now()) {
days = int(b.ExpiryDate.Sub(time.Now()).Hours() / 24)
}
var refereePhone *string
if u := userMap[b.RefereeID]; u != nil {
refereePhone = u.Phone
// 佣金展示用累计佣金 total_commission支付回调累加无则用 commission_amount
commissionVal := b.TotalCommission
if commissionVal == nil {
commissionVal = b.CommissionAmount
}
statusVal := ""
if b.Status != nil {
statusVal = *b.Status
}
out = append(out, gin.H{
"id": b.ID, "referrer_id": b.ReferrerID, "referrer_name": referrerName, "referrer_code": b.ReferralCode,
"referee_id": b.RefereeID, "referee_nickname": refNick, "referee_phone": refereePhone,
"bound_at": b.BindingDate, "expires_at": b.ExpiryDate, "status": b.Status,
"days_remaining": days, "commission": b.CommissionAmount, "source": "miniprogram",
"id": b.ID, "referrerId": b.ReferrerID, "referrerName": getStr(referrerName), "referrerCode": b.ReferralCode, "referrerAvatar": getStr(referrerAvatar),
"refereeId": b.RefereeID, "refereeNickname": refNick, "refereePhone": getStr(refereePhone), "refereeAvatar": getStr(refereeAvatar),
"boundAt": b.BindingDate, "expiresAt": b.ExpiryDate, "status": statusVal,
"daysRemaining": days, "commission": commissionVal, "totalCommission": commissionVal, "source": "miniprogram",
})
}
c.JSON(http.StatusOK, gin.H{"success": true, "bindings": out, "total": len(out)})

View File

@@ -555,12 +555,12 @@ func processReferralCommission(db *gorm.DB, buyerUserID string, amount float64,
db.Model(&model.User{}).Where("id = ?", binding.ReferrerID).
Update("pending_earnings", db.Raw("pending_earnings + ?", commission))
// 更新绑定记录
// 更新绑定记录COALESCE 避免 total_commission 为 NULL 时 NULL+?=NULL
db.Exec(`
UPDATE referral_bindings
SET last_purchase_date = NOW(),
purchase_count = purchase_count + 1,
total_commission = total_commission + ?
purchase_count = COALESCE(purchase_count, 0) + 1,
total_commission = COALESCE(total_commission, 0) + ?
WHERE id = ?
`, commission, binding.ID)

Binary file not shown.