主要更新: 1. 按H5网页端完全重构匹配功能(match页面) - 4种匹配类型: 创业合伙/资源对接/导师顾问/团队招募 - 资源对接等类型弹出手机号/微信号输入框 - 去掉重新匹配按钮,改为返回按钮 2. 修复所有卡片对齐和宽度问题 - 目录页附录卡片居中 - 首页阅读进度卡片满宽度 - 我的页面菜单卡片对齐 - 推广中心分享卡片统一宽度 3. 修复目录页图标和文字对齐 - section-icon固定40rpx宽高 - section-title与图标垂直居中 4. 更新真实完整文章标题(62篇) - 从book目录读取真实markdown文件名 - 替换之前的简化标题 5. 新增文章数据API - /api/db/chapters - 获取完整书籍结构 - 支持按ID获取单篇文章内容
570 lines
25 KiB
TypeScript
570 lines
25 KiB
TypeScript
"use client"
|
||
|
||
import { useState, useEffect } from "react"
|
||
import Link from "next/link"
|
||
import {
|
||
ChevronLeft, Copy, Share2, Users, Wallet, MessageCircle, ImageIcon,
|
||
TrendingUp, Gift, Check, ArrowRight, Bell, Clock, AlertCircle,
|
||
CheckCircle, UserPlus, Settings, Zap, ChevronDown, ChevronUp
|
||
} from "lucide-react"
|
||
import { useStore, type Purchase } from "@/lib/store"
|
||
import { PosterModal } from "@/components/modules/referral/poster-modal"
|
||
import { WithdrawalModal } from "@/components/modules/referral/withdrawal-modal"
|
||
import { AutoWithdrawModal } from "@/components/modules/distribution/auto-withdraw-modal"
|
||
import { RealtimeNotification } from "@/components/modules/distribution/realtime-notification"
|
||
|
||
// 绑定用户类型
|
||
interface BindingUser {
|
||
id: string
|
||
visitorNickname?: string
|
||
visitorPhone?: string
|
||
bindingTime: string
|
||
expireTime: string
|
||
status: 'active' | 'converted' | 'expired'
|
||
daysRemaining?: number
|
||
commission?: number
|
||
orderAmount?: number
|
||
}
|
||
|
||
export default function ReferralPage() {
|
||
const { user, isLoggedIn, settings, getAllPurchases, getAllUsers } = useStore()
|
||
const [copied, setCopied] = useState(false)
|
||
const [showPoster, setShowPoster] = useState(false)
|
||
const [showWithdrawal, setShowWithdrawal] = useState(false)
|
||
const [showAutoWithdraw, setShowAutoWithdraw] = useState(false)
|
||
const [referralPurchases, setReferralPurchases] = useState<Purchase[]>([])
|
||
const [referralUsers, setReferralUsers] = useState<number>(0)
|
||
|
||
// 绑定用户相关状态
|
||
const [activeBindings, setActiveBindings] = useState<BindingUser[]>([])
|
||
const [convertedBindings, setConvertedBindings] = useState<BindingUser[]>([])
|
||
const [expiredBindings, setExpiredBindings] = useState<BindingUser[]>([])
|
||
const [expiringCount, setExpiringCount] = useState(0)
|
||
const [showBindingList, setShowBindingList] = useState(true)
|
||
const [activeTab, setActiveTab] = useState<'active' | 'converted' | 'expired'>('active')
|
||
|
||
// 自动提现状态
|
||
const [autoWithdrawEnabled, setAutoWithdrawEnabled] = useState(false)
|
||
const [autoWithdrawThreshold, setAutoWithdrawThreshold] = useState(100)
|
||
|
||
useEffect(() => {
|
||
if (user?.referralCode) {
|
||
const allPurchases = getAllPurchases()
|
||
const allUsers = getAllUsers()
|
||
const usersWithMyCode = allUsers.filter((u) => u.referredBy === user.referralCode)
|
||
const userIds = usersWithMyCode.map((u) => u.id)
|
||
const myReferralPurchases = allPurchases.filter((p) => userIds.includes(p.userId))
|
||
setReferralPurchases(myReferralPurchases)
|
||
setReferralUsers(usersWithMyCode.length)
|
||
|
||
// 模拟绑定数据(实际从API获取)
|
||
loadBindingData()
|
||
}
|
||
}, [user, getAllPurchases, getAllUsers])
|
||
|
||
// 加载绑定数据
|
||
const loadBindingData = async () => {
|
||
// 模拟数据 - 实际项目中从 /api/distribution?type=my-bindings&userId=xxx 获取
|
||
const now = new Date()
|
||
|
||
const mockActiveBindings: BindingUser[] = [
|
||
{
|
||
id: '1',
|
||
visitorNickname: '小明',
|
||
visitorPhone: '138****1234',
|
||
bindingTime: new Date(Date.now() - 25 * 24 * 60 * 60 * 1000).toISOString(),
|
||
expireTime: new Date(Date.now() + 5 * 24 * 60 * 60 * 1000).toISOString(),
|
||
status: 'active',
|
||
daysRemaining: 5,
|
||
},
|
||
{
|
||
id: '2',
|
||
visitorNickname: '小红',
|
||
visitorPhone: '139****5678',
|
||
bindingTime: new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString(),
|
||
expireTime: new Date(Date.now() + 20 * 24 * 60 * 60 * 1000).toISOString(),
|
||
status: 'active',
|
||
daysRemaining: 20,
|
||
},
|
||
{
|
||
id: '3',
|
||
visitorNickname: '阿强',
|
||
visitorPhone: '137****9012',
|
||
bindingTime: new Date(Date.now() - 28 * 24 * 60 * 60 * 1000).toISOString(),
|
||
expireTime: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000).toISOString(),
|
||
status: 'active',
|
||
daysRemaining: 2,
|
||
},
|
||
]
|
||
|
||
const mockConvertedBindings: BindingUser[] = [
|
||
{
|
||
id: '4',
|
||
visitorNickname: '小李',
|
||
visitorPhone: '136****3456',
|
||
bindingTime: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000).toISOString(),
|
||
expireTime: new Date(Date.now() + 15 * 24 * 60 * 60 * 1000).toISOString(),
|
||
status: 'converted',
|
||
commission: 8.91,
|
||
orderAmount: 9.9,
|
||
},
|
||
]
|
||
|
||
const mockExpiredBindings: BindingUser[] = [
|
||
{
|
||
id: '5',
|
||
visitorNickname: '小王',
|
||
visitorPhone: '135****7890',
|
||
bindingTime: new Date(Date.now() - 35 * 24 * 60 * 60 * 1000).toISOString(),
|
||
expireTime: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString(),
|
||
status: 'expired',
|
||
},
|
||
]
|
||
|
||
setActiveBindings(mockActiveBindings)
|
||
setConvertedBindings(mockConvertedBindings)
|
||
setExpiredBindings(mockExpiredBindings)
|
||
setExpiringCount(mockActiveBindings.filter(b => (b.daysRemaining || 0) <= 7).length)
|
||
}
|
||
|
||
if (!isLoggedIn || !user) {
|
||
return (
|
||
<div className="min-h-screen bg-black text-white flex items-center justify-center pb-20">
|
||
<div className="text-center glass-card p-8">
|
||
<p className="text-[var(--app-text-secondary)] mb-4">请先登录</p>
|
||
<Link href="/" className="btn-ios inline-block">
|
||
返回首页
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
const referralLink = `${typeof window !== "undefined" ? window.location.origin : ""}?ref=${user.referralCode}`
|
||
const distributorShare = settings?.distributorShare || 90
|
||
const totalEarnings = user.earnings || 0
|
||
const pendingEarnings = user.pendingEarnings || 0
|
||
|
||
const handleCopy = () => {
|
||
navigator.clipboard.writeText(referralLink)
|
||
setCopied(true)
|
||
setTimeout(() => setCopied(false), 2000)
|
||
}
|
||
|
||
const handleShare = async () => {
|
||
const shareText = `我正在读《一场SOUL的创业实验场》,每天6-9点的真实商业故事,推荐给你!${referralLink}`
|
||
try {
|
||
if (typeof navigator.share === 'function' && typeof navigator.canShare === 'function') {
|
||
await navigator.share({
|
||
title: "一场SOUL的创业实验场",
|
||
text: "来自Soul派对房的真实商业故事",
|
||
url: referralLink,
|
||
})
|
||
} else {
|
||
await navigator.clipboard.writeText(shareText)
|
||
alert("分享文案已复制,快去朋友圈或Soul派对分享吧!")
|
||
}
|
||
} catch {
|
||
await navigator.clipboard.writeText(shareText)
|
||
alert("分享文案已复制!")
|
||
}
|
||
}
|
||
|
||
const handleShareToWechat = async () => {
|
||
const shareText = `📖 推荐一本好书《一场SOUL的创业实验场》
|
||
|
||
这是卡若每天早上6-9点在Soul派对房分享的真实商业故事,55个真实案例,讲透创业的底层逻辑。
|
||
|
||
👉 点击阅读: ${referralLink}
|
||
|
||
#创业 #商业思维 #Soul派对`
|
||
await navigator.clipboard.writeText(shareText)
|
||
alert("朋友圈文案已复制!\n\n打开微信 → 发朋友圈 → 粘贴即可")
|
||
}
|
||
|
||
// 获取绑定状态样式
|
||
const getBindingStatusStyle = (daysRemaining?: number) => {
|
||
if (!daysRemaining) return 'bg-gray-500/20 text-gray-400'
|
||
if (daysRemaining <= 3) return 'bg-red-500/20 text-red-400'
|
||
if (daysRemaining <= 7) return 'bg-orange-500/20 text-orange-400'
|
||
return 'bg-green-500/20 text-green-400'
|
||
}
|
||
|
||
// 获取绑定状态文本
|
||
const getBindingStatusText = (binding: BindingUser) => {
|
||
if (binding.status === 'converted') return '已付款'
|
||
if (binding.status === 'expired') return '已过期'
|
||
if (binding.daysRemaining && binding.daysRemaining <= 3) return `${binding.daysRemaining}天后过期`
|
||
if (binding.daysRemaining && binding.daysRemaining <= 7) return `${binding.daysRemaining}天`
|
||
return `${binding.daysRemaining || 0}天`
|
||
}
|
||
|
||
const currentBindings = activeTab === 'active' ? activeBindings : activeTab === 'converted' ? convertedBindings : expiredBindings
|
||
|
||
return (
|
||
<div className="min-h-screen bg-black text-white pb-24 page-transition">
|
||
{/* 背景光效 */}
|
||
<div className="fixed inset-0 -z-10">
|
||
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-[500px] h-[500px] bg-[var(--app-brand)] opacity-[0.05] blur-[150px] rounded-full" />
|
||
</div>
|
||
|
||
{/* Header - iOS风格 */}
|
||
<header className="sticky top-0 z-50 glass-nav safe-top">
|
||
<div className="max-w-md mx-auto px-4 py-3 flex items-center">
|
||
<Link href="/my" className="w-8 h-8 rounded-full bg-[var(--app-bg-secondary)] flex items-center justify-center touch-feedback">
|
||
<ChevronLeft className="w-5 h-5 text-[var(--app-text-secondary)]" />
|
||
</Link>
|
||
<h1 className="flex-1 text-center font-semibold">分销中心</h1>
|
||
<div className="flex items-center gap-2">
|
||
<RealtimeNotification />
|
||
<button
|
||
onClick={() => setShowAutoWithdraw(true)}
|
||
className="w-8 h-8 rounded-full bg-[var(--app-bg-secondary)] flex items-center justify-center touch-feedback"
|
||
>
|
||
<Settings className="w-4 h-4 text-[var(--app-text-secondary)]" />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main className="max-w-md mx-auto px-4 py-6">
|
||
{/* 过期提醒横幅 */}
|
||
{expiringCount > 0 && (
|
||
<div className="mb-4 glass-card p-4 border border-orange-500/30 bg-orange-500/10">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-10 h-10 rounded-full bg-orange-500/20 flex items-center justify-center flex-shrink-0">
|
||
<Bell className="w-5 h-5 text-orange-400" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<p className="text-white font-medium text-sm">
|
||
{expiringCount} 位用户绑定即将过期
|
||
</p>
|
||
<p className="text-orange-300/80 text-xs mt-0.5">
|
||
30天内未付款将解除绑定关系
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* 收益卡片 - 毛玻璃渐变 */}
|
||
<div className="relative glass-card-heavy p-6 mb-6 overflow-hidden">
|
||
{/* 背景装饰 */}
|
||
<div className="absolute top-0 right-0 w-32 h-32 bg-[var(--app-brand)] opacity-[0.15] blur-[50px] rounded-full" />
|
||
|
||
<div className="relative">
|
||
<div className="flex items-center justify-between mb-4">
|
||
<div className="flex items-center gap-2">
|
||
<div className="w-10 h-10 rounded-xl bg-[var(--app-brand-light)] flex items-center justify-center">
|
||
<Wallet className="w-5 h-5 text-[var(--app-brand)]" />
|
||
</div>
|
||
<div>
|
||
<p className="text-[var(--app-text-tertiary)] text-xs">累计收益</p>
|
||
<p className="text-[var(--app-brand)] text-xs font-medium">{distributorShare}% 返利</p>
|
||
</div>
|
||
</div>
|
||
<div className="text-right">
|
||
<p className="text-3xl font-bold text-white glow-text">¥{totalEarnings.toFixed(2)}</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-xs">待结算: ¥{pendingEarnings.toFixed(2)}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex gap-2">
|
||
<button
|
||
disabled={totalEarnings < 10}
|
||
onClick={() => setShowWithdrawal(true)}
|
||
className="flex-1 btn-ios glow disabled:opacity-50 disabled:cursor-not-allowed"
|
||
>
|
||
{totalEarnings < 10 ? `满10元可提现` : "申请提现"}
|
||
</button>
|
||
{autoWithdrawEnabled && (
|
||
<div className="flex items-center gap-1 px-3 py-2 bg-[var(--app-brand-light)] rounded-xl">
|
||
<Zap className="w-4 h-4 text-[var(--app-brand)]" />
|
||
<span className="text-[var(--app-brand)] text-xs font-medium">自动提现</span>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 数据统计 */}
|
||
<div className="grid grid-cols-4 gap-2 mb-6">
|
||
<div className="glass-card p-3 text-center">
|
||
<p className="text-xl font-bold text-white">{activeBindings.length}</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-[10px]">绑定中</p>
|
||
</div>
|
||
<div className="glass-card p-3 text-center">
|
||
<p className="text-xl font-bold text-white">{convertedBindings.length}</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-[10px]">已付款</p>
|
||
</div>
|
||
<div className="glass-card p-3 text-center">
|
||
<p className="text-xl font-bold text-orange-400">{expiringCount}</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-[10px]">即将过期</p>
|
||
</div>
|
||
<div className="glass-card p-3 text-center">
|
||
<p className="text-xl font-bold text-white">{referralUsers}</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-[10px]">总邀请</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 分销规则说明 */}
|
||
<div className="glass-card p-4 mb-6 border border-[var(--app-brand)]/20 bg-[var(--app-brand)]/5">
|
||
<div className="flex items-start gap-3">
|
||
<div className="w-8 h-8 rounded-lg bg-[var(--app-brand-light)] flex items-center justify-center flex-shrink-0">
|
||
<AlertCircle className="w-4 h-4 text-[var(--app-brand)]" />
|
||
</div>
|
||
<div>
|
||
<p className="text-white font-medium text-sm mb-1">推广规则</p>
|
||
<ul className="text-[var(--app-text-tertiary)] text-xs space-y-1">
|
||
<li>• 好友通过你的链接购买,<span className="text-[#FFD700]">立享5%优惠</span></li>
|
||
<li>• 好友成功付款后,你获得 <span className="text-[var(--app-brand)]">{distributorShare}%</span> 收益</li>
|
||
<li>• 绑定期<span className="text-[var(--app-brand)]">30天</span>,期满未付款自动解除</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 绑定用户列表 */}
|
||
<div className="glass-card overflow-hidden mb-6">
|
||
<button
|
||
onClick={() => setShowBindingList(!showBindingList)}
|
||
className="w-full px-5 py-4 flex items-center justify-between border-b border-[var(--app-separator)]"
|
||
>
|
||
<div className="flex items-center gap-2">
|
||
<Users className="w-5 h-5 text-[var(--app-brand)]" />
|
||
<h3 className="text-white font-semibold">绑定用户</h3>
|
||
<span className="text-[var(--app-text-tertiary)] text-sm">
|
||
({activeBindings.length + convertedBindings.length + expiredBindings.length})
|
||
</span>
|
||
</div>
|
||
{showBindingList ? (
|
||
<ChevronUp className="w-5 h-5 text-[var(--app-text-tertiary)]" />
|
||
) : (
|
||
<ChevronDown className="w-5 h-5 text-[var(--app-text-tertiary)]" />
|
||
)}
|
||
</button>
|
||
|
||
{showBindingList && (
|
||
<>
|
||
{/* Tab切换 */}
|
||
<div className="flex border-b border-[var(--app-separator)]">
|
||
{[
|
||
{ key: 'active', label: '绑定中', count: activeBindings.length },
|
||
{ key: 'converted', label: '已付款', count: convertedBindings.length },
|
||
{ key: 'expired', label: '已过期', count: expiredBindings.length },
|
||
].map((tab) => (
|
||
<button
|
||
key={tab.key}
|
||
onClick={() => setActiveTab(tab.key as typeof activeTab)}
|
||
className={`flex-1 py-3 text-sm font-medium transition-colors relative ${
|
||
activeTab === tab.key
|
||
? 'text-[var(--app-brand)]'
|
||
: 'text-[var(--app-text-tertiary)]'
|
||
}`}
|
||
>
|
||
{tab.label} ({tab.count})
|
||
{activeTab === tab.key && (
|
||
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-12 h-0.5 bg-[var(--app-brand)] rounded-full" />
|
||
)}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* 用户列表 */}
|
||
<div className="max-h-80 overflow-auto scrollbar-hide">
|
||
{currentBindings.length === 0 ? (
|
||
<div className="py-12 text-center">
|
||
<UserPlus className="w-10 h-10 text-[var(--app-text-tertiary)] mx-auto mb-2" />
|
||
<p className="text-[var(--app-text-tertiary)] text-sm">暂无用户</p>
|
||
</div>
|
||
) : (
|
||
currentBindings.map((binding, idx) => (
|
||
<div
|
||
key={binding.id}
|
||
className={`px-5 py-4 flex items-center justify-between ${
|
||
idx !== currentBindings.length - 1 ? 'border-b border-[var(--app-separator)]' : ''
|
||
}`}
|
||
>
|
||
<div className="flex items-center gap-3">
|
||
<div className={`w-10 h-10 rounded-full flex items-center justify-center ${
|
||
binding.status === 'converted'
|
||
? 'bg-green-500/20'
|
||
: binding.status === 'expired'
|
||
? 'bg-gray-500/20'
|
||
: 'bg-[var(--app-brand-light)]'
|
||
}`}>
|
||
{binding.status === 'converted' ? (
|
||
<CheckCircle className="w-5 h-5 text-green-400" />
|
||
) : binding.status === 'expired' ? (
|
||
<Clock className="w-5 h-5 text-gray-400" />
|
||
) : (
|
||
<span className="text-[var(--app-brand)] font-bold">
|
||
{(binding.visitorNickname || '用户')[0]}
|
||
</span>
|
||
)}
|
||
</div>
|
||
<div>
|
||
<p className="text-white text-sm font-medium">
|
||
{binding.visitorNickname || binding.visitorPhone || '匿名用户'}
|
||
</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-xs">
|
||
绑定于 {new Date(binding.bindingTime).toLocaleDateString('zh-CN')}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div className="text-right">
|
||
{binding.status === 'converted' ? (
|
||
<>
|
||
<p className="text-green-400 font-semibold">+¥{binding.commission?.toFixed(2)}</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-xs">订单 ¥{binding.orderAmount}</p>
|
||
</>
|
||
) : (
|
||
<span className={`text-xs px-2 py-1 rounded-full ${getBindingStatusStyle(binding.daysRemaining)}`}>
|
||
{getBindingStatusText(binding)}
|
||
</span>
|
||
)}
|
||
</div>
|
||
</div>
|
||
))
|
||
)}
|
||
</div>
|
||
</>
|
||
)}
|
||
</div>
|
||
|
||
{/* 专属链接 - 简化显示 */}
|
||
<div className="glass-card p-5 mb-6">
|
||
<div className="flex items-center justify-between mb-3">
|
||
<h3 className="text-white font-semibold">我的邀请码</h3>
|
||
<span className="text-[var(--app-brand)] text-sm font-mono bg-[var(--app-brand-light)] px-3 py-1.5 rounded-lg">
|
||
{user.referralCode}
|
||
</span>
|
||
</div>
|
||
|
||
<p className="text-[var(--app-text-tertiary)] text-xs">
|
||
好友通过你的链接购买<span className="text-[#FFD700]">立省5%</span>,你获得<span className="text-[var(--app-brand)]">{distributorShare}%</span>收益
|
||
</p>
|
||
</div>
|
||
|
||
{/* 分享按钮 */}
|
||
<div className="space-y-3 mb-6">
|
||
<button
|
||
onClick={() => setShowPoster(true)}
|
||
className="w-full glass-card p-4 flex items-center gap-4 touch-feedback"
|
||
>
|
||
<div className="w-12 h-12 rounded-xl bg-[var(--ios-indigo)]/20 flex items-center justify-center">
|
||
<ImageIcon className="w-6 h-6 text-[var(--ios-indigo)]" />
|
||
</div>
|
||
<div className="flex-1 text-left">
|
||
<p className="text-white font-medium">生成推广海报</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-xs">一键生成精美海报分享</p>
|
||
</div>
|
||
<ArrowRight className="w-5 h-5 text-[var(--app-text-tertiary)]" />
|
||
</button>
|
||
|
||
<button
|
||
onClick={handleShareToWechat}
|
||
className="w-full glass-card p-4 flex items-center gap-4 touch-feedback"
|
||
>
|
||
<div className="w-12 h-12 rounded-xl bg-[#07C160]/20 flex items-center justify-center">
|
||
<MessageCircle className="w-6 h-6 text-[#07C160]" />
|
||
</div>
|
||
<div className="flex-1 text-left">
|
||
<p className="text-white font-medium">分享到朋友圈</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-xs">复制文案发朋友圈</p>
|
||
</div>
|
||
<ArrowRight className="w-5 h-5 text-[var(--app-text-tertiary)]" />
|
||
</button>
|
||
|
||
<button
|
||
onClick={handleShare}
|
||
className="w-full glass-card p-4 flex items-center gap-4 touch-feedback"
|
||
>
|
||
<div className="w-12 h-12 rounded-xl bg-[var(--app-bg-secondary)] flex items-center justify-center">
|
||
<Share2 className="w-6 h-6 text-[var(--app-text-secondary)]" />
|
||
</div>
|
||
<div className="flex-1 text-left">
|
||
<p className="text-white font-medium">更多分享方式</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-xs">使用系统分享功能</p>
|
||
</div>
|
||
<ArrowRight className="w-5 h-5 text-[var(--app-text-tertiary)]" />
|
||
</button>
|
||
</div>
|
||
|
||
{/* 收益明细 */}
|
||
{referralPurchases.length > 0 && (
|
||
<div className="glass-card overflow-hidden">
|
||
<div className="px-5 py-4 border-b border-[var(--app-separator)]">
|
||
<h3 className="text-white font-semibold">收益明细</h3>
|
||
</div>
|
||
<div className="max-h-60 overflow-auto scrollbar-hide">
|
||
{referralPurchases.slice(0, 10).map((purchase, idx) => (
|
||
<div
|
||
key={purchase.id}
|
||
className={`px-5 py-4 flex items-center justify-between ${idx !== referralPurchases.length - 1 ? 'border-b border-[var(--app-separator)]' : ''}`}
|
||
>
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-10 h-10 rounded-xl bg-[var(--app-brand-light)] flex items-center justify-center">
|
||
<Gift className="w-5 h-5 text-[var(--app-brand)]" />
|
||
</div>
|
||
<div>
|
||
<p className="text-white text-sm font-medium">
|
||
{purchase.type === "fullbook" ? "整本书购买" : "单节购买"}
|
||
</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-xs">
|
||
{new Date(purchase.createdAt).toLocaleDateString("zh-CN")}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<p className="text-[var(--app-brand)] font-semibold">
|
||
+¥{(purchase.referrerEarnings || 0).toFixed(2)}
|
||
</p>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* 空状态 */}
|
||
{referralPurchases.length === 0 && activeBindings.length === 0 && (
|
||
<div className="glass-card p-8 text-center">
|
||
<div className="w-16 h-16 rounded-full bg-[var(--app-bg-secondary)] flex items-center justify-center mx-auto mb-4">
|
||
<Gift className="w-8 h-8 text-[var(--app-text-tertiary)]" />
|
||
</div>
|
||
<p className="text-white font-medium mb-2">暂无收益记录</p>
|
||
<p className="text-[var(--app-text-tertiary)] text-sm">
|
||
分享专属链接,好友购买即可获得 {distributorShare}% 返利
|
||
</p>
|
||
</div>
|
||
)}
|
||
</main>
|
||
|
||
<PosterModal
|
||
isOpen={showPoster}
|
||
onClose={() => setShowPoster(false)}
|
||
referralLink={referralLink}
|
||
referralCode={user.referralCode}
|
||
nickname={user.nickname}
|
||
/>
|
||
|
||
<WithdrawalModal
|
||
isOpen={showWithdrawal}
|
||
onClose={() => setShowWithdrawal(false)}
|
||
availableAmount={totalEarnings}
|
||
/>
|
||
|
||
<AutoWithdrawModal
|
||
isOpen={showAutoWithdraw}
|
||
onClose={() => setShowAutoWithdraw(false)}
|
||
enabled={autoWithdrawEnabled}
|
||
threshold={autoWithdrawThreshold}
|
||
onSave={(enabled, threshold, account) => {
|
||
setAutoWithdrawEnabled(enabled)
|
||
setAutoWithdrawThreshold(threshold)
|
||
// 实际调用API保存
|
||
}}
|
||
/>
|
||
</div>
|
||
)
|
||
}
|