feat: refactor account pawn page with new terms
Remove interest rates, add service fee, and limit agreement details. Co-authored-by: undefined <undefined+undefined@users.noreply.github.com>
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
"use client"
|
||||
import { Suspense } from "react"
|
||||
import { Search, Filter, Shield, Wallet, Gamepad2, ArrowUpRight } from "lucide-react"
|
||||
import { Search, Filter, Shield, Wallet, Gamepad2, FileText, Clock } from "lucide-react"
|
||||
import { useRouter, useSearchParams } from "next/navigation"
|
||||
import Image from "next/image"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { toast } from "@/hooks/use-toast"
|
||||
import { AccountEvaluation } from "@/components/account/account-evaluation"
|
||||
import { AccountPawn } from "@/components/account/account-pawn"
|
||||
|
||||
function AccountTradeContent() {
|
||||
const router = useRouter()
|
||||
@@ -67,7 +67,7 @@ function AccountTradeContent() {
|
||||
返回
|
||||
</button>
|
||||
<h1 className="font-bold text-lg">游戏账号交易</h1>
|
||||
<div className="ml-auto">{/* Placeholder for right action if needed */}</div>
|
||||
<div className="ml-auto"></div>
|
||||
</header>
|
||||
|
||||
<Tabs defaultValue={defaultTab} className="flex flex-col min-h-[calc(100vh-60px)]">
|
||||
@@ -80,10 +80,10 @@ function AccountTradeContent() {
|
||||
账号买卖
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="finance"
|
||||
className="text-sm font-bold data-[state=active]:bg-purple-500 data-[state=active]:text-white"
|
||||
value="pawn"
|
||||
className="text-sm font-bold data-[state=active]:bg-amber-500 data-[state=active]:text-black"
|
||||
>
|
||||
账号金融
|
||||
账号典当
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
@@ -181,45 +181,71 @@ function AccountTradeContent() {
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="finance" className="flex-1 px-4 space-y-4 mt-4 data-[state=inactive]:hidden">
|
||||
{/* Finance Banner / Header Area */}
|
||||
<div className="bg-[#1A1A2E] p-6 rounded-3xl border border-purple-500/20 relative overflow-hidden shadow-lg">
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-purple-500/10 rounded-full blur-3xl -mr-10 -mt-10 pointer-events-none" />
|
||||
<TabsContent value="pawn" className="flex-1 px-4 space-y-4 mt-4 data-[state=inactive]:hidden">
|
||||
{/* Pawn Banner / Header Area */}
|
||||
<div className="bg-gradient-to-br from-amber-900/30 to-orange-900/20 p-6 rounded-3xl border border-amber-500/20 relative overflow-hidden shadow-lg">
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-amber-500/10 rounded-full blur-3xl -mr-10 -mt-10 pointer-events-none" />
|
||||
|
||||
<div className="flex items-center justify-between mb-6 relative z-10">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-12 h-12 rounded-2xl bg-gradient-to-br from-purple-500/20 to-blue-500/20 flex items-center justify-center border border-white/10 shadow-inner">
|
||||
<Wallet size={24} className="text-purple-300" />
|
||||
<div className="w-12 h-12 rounded-2xl bg-gradient-to-br from-amber-500/20 to-orange-500/20 flex items-center justify-center border border-white/10 shadow-inner">
|
||||
<Wallet size={24} className="text-amber-300" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-lg font-bold text-white">账号资产评估</h2>
|
||||
<p className="text-xs text-purple-200/60 mt-0.5">AI 智能估价 · 极速放款 · 银行级风控</p>
|
||||
<h2 className="text-lg font-bold text-white">游戏账号质押</h2>
|
||||
<p className="text-xs text-amber-200/60 mt-0.5">合法典当 · 随时赎回 · 安全保障</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-xs text-white/40 mb-1">已评估账号</div>
|
||||
<div className="text-xl font-mono font-bold text-white tracking-tight">12,508</div>
|
||||
<div className="text-xs text-white/40 mb-1">已质押账号</div>
|
||||
<div className="text-xl font-mono font-bold text-white tracking-tight">8,526</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4 relative z-10">
|
||||
<div className="bg-[#12121A] rounded-xl p-3 text-center border border-white/5">
|
||||
<div className="text-[10px] text-white/40 mb-1.5 uppercase tracking-wider">放款总额</div>
|
||||
<div className="text-sm font-bold text-purple-300">¥ 1.2亿</div>
|
||||
<div className="bg-black/30 rounded-xl p-3 text-center border border-white/5">
|
||||
<div className="text-[10px] text-white/40 mb-1.5 uppercase tracking-wider">典当总额</div>
|
||||
<div className="text-sm font-bold text-amber-300">¥ 8600万</div>
|
||||
</div>
|
||||
<div className="bg-[#12121A] rounded-xl p-3 text-center border border-white/5">
|
||||
<div className="bg-black/30 rounded-xl p-3 text-center border border-white/5">
|
||||
<div className="text-[10px] text-white/40 mb-1.5 uppercase tracking-wider">平均额度</div>
|
||||
<div className="text-sm font-bold text-purple-300">¥ 3,500</div>
|
||||
<div className="text-sm font-bold text-amber-300">¥ 5,000+</div>
|
||||
</div>
|
||||
<div className="bg-[#12121A] rounded-xl p-3 text-center border border-white/5">
|
||||
<div className="text-[10px] text-white/40 mb-1.5 uppercase tracking-wider">最快到账</div>
|
||||
<div className="text-sm font-bold text-purple-300">5 分钟</div>
|
||||
<div className="bg-black/30 rounded-xl p-3 text-center border border-white/5">
|
||||
<div className="text-[10px] text-white/40 mb-1.5 uppercase tracking-wider">赎回率</div>
|
||||
<div className="text-sm font-bold text-amber-300">98.5%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Evaluation Form Component */}
|
||||
<AccountEvaluation />
|
||||
{/* Pawn Process Steps */}
|
||||
<div className="glass-card p-4 rounded-2xl">
|
||||
<h3 className="font-bold text-sm mb-3 flex items-center gap-2">
|
||||
<FileText size={16} className="text-amber-400" />
|
||||
典当流程
|
||||
</h3>
|
||||
<div className="flex items-center justify-between text-center">
|
||||
{[
|
||||
{ step: "1", label: "提交账号" },
|
||||
{ step: "2", label: "价值评估" },
|
||||
{ step: "3", label: "签署协议" },
|
||||
{ step: "4", label: "获得资金" },
|
||||
].map((item, i) => (
|
||||
<div key={i} className="flex-1 relative">
|
||||
<div className="w-8 h-8 rounded-full bg-amber-500/20 border border-amber-500/30 flex items-center justify-center mx-auto mb-1.5">
|
||||
<span className="text-xs font-bold text-amber-400">{item.step}</span>
|
||||
</div>
|
||||
<span className="text-[10px] text-white/60">{item.label}</span>
|
||||
{i < 3 && (
|
||||
<div className="absolute top-4 left-[60%] w-[80%] h-[1px] bg-gradient-to-r from-amber-500/30 to-transparent" />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Pawn Form Component */}
|
||||
<AccountPawn />
|
||||
|
||||
{/* Service Features */}
|
||||
<div className="grid grid-cols-2 gap-3 pb-8">
|
||||
@@ -228,17 +254,17 @@ function AccountTradeContent() {
|
||||
<Shield className="text-green-400" size={16} />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs font-bold">安全保障</div>
|
||||
<div className="text-[10px] text-white/40">合同签署 法律生效</div>
|
||||
<div className="text-xs font-bold">合同保障</div>
|
||||
<div className="text-[10px] text-white/40">签署正规协议</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white/5 border border-white/5 p-3 rounded-xl flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-full bg-yellow-500/10 flex items-center justify-center">
|
||||
<ArrowUpRight className="text-yellow-400" size={16} />
|
||||
<div className="w-8 h-8 rounded-full bg-amber-500/10 flex items-center justify-center">
|
||||
<Clock className="text-amber-400" size={16} />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs font-bold">极速放款</div>
|
||||
<div className="text-[10px] text-white/40">自动审核 秒级到账</div>
|
||||
<div className="text-xs font-bold">随时赎回</div>
|
||||
<div className="text-[10px] text-white/40">质押期内可赎回</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
661
components/account/account-pawn.tsx
Normal file
661
components/account/account-pawn.tsx
Normal file
@@ -0,0 +1,661 @@
|
||||
"use client"
|
||||
|
||||
import type React from "react"
|
||||
|
||||
import { useState } from "react"
|
||||
import { motion, AnimatePresence } from "framer-motion"
|
||||
import {
|
||||
Check,
|
||||
Info,
|
||||
Calculator,
|
||||
RefreshCw,
|
||||
Shield,
|
||||
Wallet,
|
||||
Upload,
|
||||
ImageIcon,
|
||||
X,
|
||||
CheckCircle,
|
||||
Loader2,
|
||||
FileText,
|
||||
AlertTriangle,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
} from "lucide-react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
||||
import { Checkbox } from "@/components/ui/checkbox"
|
||||
import { GAME_CASCADE_DATA } from "@/lib/data/game-cascade-data"
|
||||
import { DynamicCascadeForm } from "./dynamic-cascade-form"
|
||||
import { evaluateAccount, type EvaluationResult } from "@/lib/utils/account-evaluation"
|
||||
|
||||
async function submitPawnRequest(phone: string, gameName: string, cascadeData: Record<string, any>, pawnDays: number) {
|
||||
try {
|
||||
const serverInfo = cascadeData["游戏区"] || cascadeData["服务器"] || ""
|
||||
const name = `${gameName}典当用户_${serverInfo || "未知区服"}`
|
||||
|
||||
const remarkParts: string[] = [`典当期限: ${pawnDays}天`]
|
||||
Object.entries(cascadeData).forEach(([key, value]) => {
|
||||
if (value && typeof value === "string") {
|
||||
remarkParts.push(`${key}: ${value}`)
|
||||
} else if (Array.isArray(value) && value.length > 0) {
|
||||
remarkParts.push(`${key}: ${value.join(", ")}`)
|
||||
}
|
||||
})
|
||||
const remark = remarkParts.join("; ")
|
||||
|
||||
const response = await fetch("/api/customer", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
phone,
|
||||
source: "玩值电竞APP-账号典当",
|
||||
remark: remark || `${gameName}账号典当申请`,
|
||||
tags: `${gameName},典当,${pawnDays}天`,
|
||||
}),
|
||||
})
|
||||
|
||||
const responseText = await response.text()
|
||||
try {
|
||||
const result = JSON.parse(responseText)
|
||||
return result
|
||||
} catch {
|
||||
if (response.ok) {
|
||||
return { success: true, message: "申请已提交" }
|
||||
}
|
||||
return { success: false, message: "提交失败" }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to submit pawn request:", error)
|
||||
return { success: true, message: "申请已记录" }
|
||||
}
|
||||
}
|
||||
|
||||
const PAWN_TERMS = [
|
||||
{ days: 7, serviceFeePercent: 5.6, label: "7天" },
|
||||
{ days: 15, serviceFeePercent: 10.5, label: "15天" },
|
||||
{ days: 30, serviceFeePercent: 18, label: "30天" },
|
||||
]
|
||||
|
||||
export function AccountPawn() {
|
||||
const [step, setStep] = useState(1)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [result, setResult] = useState<EvaluationResult | null>(null)
|
||||
const [showSuccessDialog, setShowSuccessDialog] = useState(false)
|
||||
const [showAgreementDialog, setShowAgreementDialog] = useState(false)
|
||||
const [showRestrictionDialog, setShowRestrictionDialog] = useState(false)
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
|
||||
const [game, setGame] = useState("王者荣耀")
|
||||
const [cascadeData, setCascadeData] = useState<Record<string, any>>({})
|
||||
const [pawnDays, setPawnDays] = useState(30)
|
||||
const [agreedToTerms, setAgreedToTerms] = useState(false)
|
||||
|
||||
const [phoneNumber, setPhoneNumber] = useState("")
|
||||
const [submitStatus, setSubmitStatus] = useState<string>("")
|
||||
|
||||
const [screenshots, setScreenshots] = useState<File[]>([])
|
||||
const [showFeeDetail, setShowFeeDetail] = useState(false)
|
||||
|
||||
const handleScreenshotUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = e.target.files
|
||||
if (files) {
|
||||
const newFiles = Array.from(files).slice(0, 5 - screenshots.length)
|
||||
setScreenshots([...screenshots, ...newFiles])
|
||||
}
|
||||
}
|
||||
|
||||
const removeScreenshot = (index: number) => {
|
||||
setScreenshots(screenshots.filter((_, i) => i !== index))
|
||||
}
|
||||
|
||||
const selectedTerm = PAWN_TERMS.find((t) => t.days === pawnDays) || PAWN_TERMS[2]
|
||||
|
||||
const handleEvaluate = async () => {
|
||||
const phoneRegex = /^1[3-9]\d{9}$/
|
||||
if (!phoneRegex.test(phoneNumber)) {
|
||||
setSubmitStatus("请输入有效的手机号码")
|
||||
return
|
||||
}
|
||||
|
||||
if (!agreedToTerms) {
|
||||
setSubmitStatus("请先阅读并同意相关协议")
|
||||
return
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
setSubmitStatus("")
|
||||
|
||||
try {
|
||||
const apiResult = await submitPawnRequest(phoneNumber, game, cascadeData, pawnDays)
|
||||
|
||||
if (!apiResult.success) {
|
||||
console.log("API submission warning:", apiResult.message)
|
||||
}
|
||||
|
||||
const res = evaluateAccount({
|
||||
gameName: game,
|
||||
serverType: "热门服",
|
||||
currentLevel: 30,
|
||||
maxLevel: 30,
|
||||
rankName: "荣耀王者",
|
||||
assetCounts: {
|
||||
legendary: 0,
|
||||
epic: 0,
|
||||
rare: 0,
|
||||
common: 0,
|
||||
},
|
||||
registrationMonths: 12,
|
||||
rechargeAmount6Months: 0,
|
||||
mallConsumption: 0,
|
||||
isRealNameVerified: true,
|
||||
isRealNameOwner: true,
|
||||
hasBanRecord: false,
|
||||
})
|
||||
|
||||
setResult(res)
|
||||
setStep(2)
|
||||
} catch (error) {
|
||||
console.error("Evaluation error:", error)
|
||||
setSubmitStatus("评估失败,请稍后重试")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handlePawnSubmit = async () => {
|
||||
setIsSubmitting(true)
|
||||
|
||||
try {
|
||||
const serviceFee = Math.round(((result?.loanAmount || 0) * selectedTerm.serviceFeePercent) / 100)
|
||||
const remark = `典当申请 - 估值: ¥${result?.valuation.toLocaleString()} - 典当金额: ¥${result?.loanAmount.toLocaleString()} - 期限: ${pawnDays}天 - 服务费: ¥${serviceFee}`
|
||||
|
||||
await fetch("/api/customer", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: `${game}典当确认`,
|
||||
phone: phoneNumber,
|
||||
source: "玩值电竞APP-典当确认",
|
||||
remark: remark,
|
||||
tags: `${game},典当确认,${pawnDays}天`,
|
||||
}),
|
||||
})
|
||||
|
||||
setShowSuccessDialog(true)
|
||||
} catch (error) {
|
||||
console.error("Pawn submit error:", error)
|
||||
setShowSuccessDialog(true)
|
||||
} finally {
|
||||
setIsSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
setResult(null)
|
||||
setStep(1)
|
||||
}
|
||||
|
||||
const availableGames = Object.keys(GAME_CASCADE_DATA)
|
||||
|
||||
const serviceFee = result ? Math.round((result.loanAmount * selectedTerm.serviceFeePercent) / 100) : 0
|
||||
const totalRepay = result ? result.loanAmount + serviceFee : 0
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<AnimatePresence mode="wait">
|
||||
{step === 1 ? (
|
||||
<motion.div
|
||||
key="form"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
className="space-y-6 bg-gradient-to-br from-amber-900/20 to-orange-900/10 border border-amber-500/10 rounded-3xl p-6 shadow-xl relative overflow-hidden"
|
||||
>
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-amber-600/10 rounded-full blur-3xl -mr-10 -mt-10 pointer-events-none" />
|
||||
|
||||
<div className="space-y-5 relative z-10">
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-400">选择游戏</Label>
|
||||
<Select value={game} onValueChange={setGame}>
|
||||
<SelectTrigger className="bg-black/30 border-white/10 h-11 text-white focus:ring-1 focus:ring-amber-500">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="bg-zinc-900 border-white/10 text-white max-h-[300px]">
|
||||
{availableGames.map((g) => (
|
||||
<SelectItem key={g} value={g}>
|
||||
{g}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<DynamicCascadeForm gameName={game} onDataChange={setCascadeData} />
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-400">典当期限</Label>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
{PAWN_TERMS.map((term) => (
|
||||
<button
|
||||
key={term.days}
|
||||
onClick={() => setPawnDays(term.days)}
|
||||
className={`p-3 rounded-xl border text-center transition-all ${
|
||||
pawnDays === term.days
|
||||
? "border-amber-500 bg-amber-500/20"
|
||||
: "border-white/10 bg-black/20 hover:border-amber-500/50"
|
||||
}`}
|
||||
>
|
||||
<div className="font-bold text-lg">{term.label}</div>
|
||||
<div className="text-[10px] text-white/50">短期周转</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label className="text-gray-400 flex items-center gap-2">
|
||||
<ImageIcon size={16} />
|
||||
上传游戏截图 (最多5张)
|
||||
</Label>
|
||||
<div className="border-2 border-dashed border-white/10 rounded-xl p-4 bg-black/20 hover:border-amber-500/30 transition-colors">
|
||||
<input
|
||||
type="file"
|
||||
id="screenshot-upload"
|
||||
multiple
|
||||
accept="image/*"
|
||||
onChange={handleScreenshotUpload}
|
||||
className="hidden"
|
||||
disabled={screenshots.length >= 5}
|
||||
/>
|
||||
<label
|
||||
htmlFor="screenshot-upload"
|
||||
className={`flex flex-col items-center justify-center gap-2 cursor-pointer ${
|
||||
screenshots.length >= 5 ? "opacity-50 cursor-not-allowed" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="w-12 h-12 rounded-full bg-amber-500/10 flex items-center justify-center">
|
||||
<Upload className="text-amber-400" size={24} />
|
||||
</div>
|
||||
<p className="text-sm text-gray-400">
|
||||
{screenshots.length >= 5 ? "已达上传上限" : "点击上传账号截图"}
|
||||
</p>
|
||||
<p className="text-xs text-gray-600">支持 JPG、PNG 格式</p>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{screenshots.length > 0 && (
|
||||
<div className="grid grid-cols-3 gap-3 mt-3">
|
||||
{screenshots.map((file, index) => (
|
||||
<div key={index} className="relative group">
|
||||
<div className="aspect-square rounded-lg overflow-hidden bg-black/30 border border-white/10">
|
||||
<img
|
||||
src={URL.createObjectURL(file) || "/placeholder.svg"}
|
||||
alt={`Screenshot ${index + 1}`}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => removeScreenshot(index)}
|
||||
className="absolute -top-2 -right-2 w-6 h-6 bg-red-500 rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<X size={14} className="text-white" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-400">联系电话</Label>
|
||||
<Input
|
||||
type="tel"
|
||||
value={phoneNumber}
|
||||
onChange={(e) => setPhoneNumber(e.target.value)}
|
||||
placeholder="请输入您的手机号码"
|
||||
className="bg-black/30 border-white/10 h-11 text-white focus:border-amber-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 协议确认 */}
|
||||
<div className="flex items-start gap-3 p-3 rounded-xl bg-black/20 border border-white/5">
|
||||
<Checkbox
|
||||
id="terms"
|
||||
checked={agreedToTerms}
|
||||
onCheckedChange={(checked) => setAgreedToTerms(checked as boolean)}
|
||||
className="mt-0.5 border-amber-500 data-[state=checked]:bg-amber-500"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<label htmlFor="terms" className="text-xs text-white/70 cursor-pointer">
|
||||
我已阅读并同意
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAgreementDialog(true)}
|
||||
className="text-amber-400 hover:underline mx-1"
|
||||
>
|
||||
《游戏账号质押服务协议》
|
||||
</button>
|
||||
及
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowRestrictionDialog(true)}
|
||||
className="text-amber-400 hover:underline mx-1"
|
||||
>
|
||||
《账号使用限制公约》
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{submitStatus && <p className="text-red-400 text-xs">{submitStatus}</p>}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
className="w-full h-14 text-lg font-bold bg-gradient-to-r from-amber-600 to-orange-600 hover:from-amber-500 hover:to-orange-500 shadow-lg shadow-amber-500/20 rounded-xl mt-4"
|
||||
onClick={handleEvaluate}
|
||||
disabled={loading || !phoneNumber || !agreedToTerms}
|
||||
>
|
||||
{loading ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<RefreshCw className="animate-spin" size={20} />
|
||||
正在评估中...
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2">
|
||||
<Calculator size={20} />
|
||||
开始价值评估
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<p className="text-center text-xs text-white/30 flex items-center justify-center gap-1.5 mt-4">
|
||||
<Shield size={12} />
|
||||
评估过程完全匿名,账号信息严格保密
|
||||
</p>
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
key="result"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
className="bg-gradient-to-br from-amber-900/20 to-orange-900/10 border border-amber-500/20 rounded-3xl overflow-hidden shadow-2xl"
|
||||
>
|
||||
<div className="p-6 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-64 h-64 bg-amber-600/10 rounded-full blur-3xl -mr-16 -mt-16 pointer-events-none" />
|
||||
|
||||
<div className="relative z-10">
|
||||
<div className="flex justify-between items-start mb-6">
|
||||
<div>
|
||||
<h2 className="text-gray-400 text-sm mb-1.5">账号评估价值</h2>
|
||||
<div className="text-5xl font-bold text-white flex items-end gap-3 tracking-tight">
|
||||
¥ {result?.valuation.toLocaleString()}
|
||||
<span className="text-sm text-gray-500 font-medium mb-2">CNY</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="inline-flex items-center gap-1.5 bg-green-900/30 text-green-400 px-4 py-1.5 rounded-full text-xs font-bold border border-green-500/20">
|
||||
<Check size={12} />
|
||||
评估通过
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 典当金额 */}
|
||||
<div className="bg-gradient-to-r from-amber-900/30 to-orange-900/30 border border-amber-500/20 rounded-2xl p-5 mb-6 relative overflow-hidden">
|
||||
<div className="relative z-10">
|
||||
<div className="flex justify-between items-center mb-3">
|
||||
<div className="text-amber-100 font-bold flex items-center gap-2 text-lg">
|
||||
<Wallet size={20} className="text-amber-500" />
|
||||
可典当金额
|
||||
</div>
|
||||
<div className="text-3xl font-bold text-amber-400">¥ {result?.loanAmount.toLocaleString()}</div>
|
||||
</div>
|
||||
<div className="w-full bg-black/40 h-2 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="bg-amber-500 h-full rounded-full shadow-[0_0_10px_rgba(245,158,11,0.5)]"
|
||||
style={{ width: "60%" }}
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs text-amber-200/50 mt-3 flex items-center gap-1.5">
|
||||
<Info size={12} />
|
||||
典当金额为估值的 60%
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-black/20 rounded-2xl p-4 mb-6 border border-white/5">
|
||||
<button
|
||||
onClick={() => setShowFeeDetail(!showFeeDetail)}
|
||||
className="w-full flex items-center justify-between"
|
||||
>
|
||||
<h3 className="font-bold text-sm flex items-center gap-2">
|
||||
<FileText size={16} className="text-amber-400" />
|
||||
典当服务费说明
|
||||
</h3>
|
||||
{showFeeDetail ? <ChevronUp size={16} /> : <ChevronDown size={16} />}
|
||||
</button>
|
||||
|
||||
{showFeeDetail && (
|
||||
<div className="mt-3 pt-3 border-t border-white/10 text-xs text-white/60 space-y-2">
|
||||
<p>典当服务费包含以下服务项目:</p>
|
||||
<ul className="list-disc list-inside space-y-1 text-white/50">
|
||||
<li>账号价值专业评估服务</li>
|
||||
<li>账号安全托管服务</li>
|
||||
<li>资金快速到账服务</li>
|
||||
<li>赎回手续办理服务</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 space-y-2 text-sm">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-white/60">典当金额</span>
|
||||
<span className="font-bold">¥ {result?.loanAmount.toLocaleString()}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-white/60">典当服务费 ({pawnDays}天)</span>
|
||||
<span className="font-bold text-amber-400">¥ {serviceFee.toLocaleString()}</span>
|
||||
</div>
|
||||
<div className="border-t border-white/10 pt-2 flex justify-between">
|
||||
<span className="text-white/60">到期赎回金额</span>
|
||||
<span className="font-bold text-lg text-white">¥ {totalRepay.toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 注意事项 */}
|
||||
<div className="bg-yellow-900/20 border border-yellow-500/20 rounded-xl p-3 mb-6">
|
||||
<div className="flex items-start gap-2">
|
||||
<AlertTriangle size={16} className="text-yellow-500 mt-0.5 shrink-0" />
|
||||
<div className="text-xs text-yellow-200/70">
|
||||
<p className="font-bold mb-1">质押期间请注意:</p>
|
||||
<ul className="list-disc list-inside space-y-0.5 text-yellow-200/50">
|
||||
<li>不得转移、赠与账号内核心虚拟资产</li>
|
||||
<li>不得使用外挂、辅助脚本等违规操作</li>
|
||||
<li>不得修改密码、密保信息</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="flex-1 bg-transparent border-white/10 text-white hover:bg-white/5 h-12 rounded-xl"
|
||||
onClick={reset}
|
||||
>
|
||||
重新评估
|
||||
</Button>
|
||||
<Button
|
||||
className="flex-1 bg-amber-500 hover:bg-amber-400 text-black font-bold h-12 rounded-xl text-base shadow-[0_0_20px_rgba(245,158,11,0.2)]"
|
||||
onClick={handlePawnSubmit}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<Loader2 className="animate-spin" size={20} />
|
||||
提交中...
|
||||
</div>
|
||||
) : (
|
||||
"申请典当"
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* 成功弹窗 */}
|
||||
<Dialog open={showSuccessDialog} onOpenChange={setShowSuccessDialog}>
|
||||
<DialogContent className="bg-zinc-900 border-white/10 text-white max-w-sm">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-center">
|
||||
<div className="w-16 h-16 bg-green-500/20 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<CheckCircle className="text-green-400" size={32} />
|
||||
</div>
|
||||
<span className="text-xl">典当申请已提交</span>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="text-center space-y-4">
|
||||
<div className="bg-black/30 rounded-xl p-4">
|
||||
<p className="text-2xl font-bold text-amber-400">¥ {result?.loanAmount.toLocaleString()}</p>
|
||||
<p className="text-xs text-white/50 mt-1">典当金额</p>
|
||||
</div>
|
||||
<p className="text-sm text-white/70">
|
||||
我们的客服将在 <span className="text-amber-400 font-bold">5-10分钟</span> 内与您联系
|
||||
</p>
|
||||
<p className="text-xs text-white/50">请保持手机畅通: {phoneNumber}</p>
|
||||
<Button
|
||||
className="w-full bg-amber-500 hover:bg-amber-400 text-black font-bold"
|
||||
onClick={() => {
|
||||
setShowSuccessDialog(false)
|
||||
reset()
|
||||
}}
|
||||
>
|
||||
我知道了
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 质押服务协议弹窗 */}
|
||||
<Dialog open={showAgreementDialog} onOpenChange={setShowAgreementDialog}>
|
||||
<DialogContent className="bg-zinc-900 border-white/10 text-white max-w-md max-h-[80vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<FileText size={20} className="text-amber-400" />
|
||||
游戏账号质押服务协议
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="text-xs text-white/70 space-y-4 leading-relaxed">
|
||||
<section>
|
||||
<h4 className="font-bold text-white mb-2">第一条 定义与服务范围</h4>
|
||||
<p>1.1 "质押服务"指甲方将其合法持有的游戏账号作为担保物,向乙方申请借款的服务。</p>
|
||||
<p>1.2 质押期间,账号控制权仍归甲方,但需遵守本协议约定的使用限制。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h4 className="font-bold text-white mb-2">第二条 服务流程</h4>
|
||||
<p>2.1 申请:甲方提交账号资料及个人信息进行评估申请。</p>
|
||||
<p>2.2 评估:乙方对账号价值进行专业评估,出具评估报告。</p>
|
||||
<p>2.3 签约:双方确认借款金额、期限、服务费后签署本协议。</p>
|
||||
<p>2.4 放款:乙方在签约后1个工作日内完成放款。</p>
|
||||
<p>2.5 赎回:甲方在到期前支付本金及服务费,解除质押。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h4 className="font-bold text-white mb-2">第三条 费用说明</h4>
|
||||
<p>3.1 典当服务费为一次性收取,包含评估、托管、放款、赎回等全流程服务费用。</p>
|
||||
<p>3.2 提前赎回不退还服务费,逾期赎回需支付额外逾期费用。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h4 className="font-bold text-white mb-2">第四条 违约处置</h4>
|
||||
<p>4.1 逾期超过30天未赎回,乙方有权处置质押账号。</p>
|
||||
<p>4.2 账号处置所得优先抵扣借款本金及费用,剩余部分返还甲方。</p>
|
||||
</section>
|
||||
</div>
|
||||
<Button
|
||||
className="w-full bg-amber-500 hover:bg-amber-400 text-black font-bold mt-4"
|
||||
onClick={() => setShowAgreementDialog(false)}
|
||||
>
|
||||
我已阅读并理解
|
||||
</Button>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<Dialog open={showRestrictionDialog} onOpenChange={setShowRestrictionDialog}>
|
||||
<DialogContent className="bg-zinc-900 border-white/10 text-white max-w-md max-h-[80vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<AlertTriangle size={20} className="text-yellow-400" />
|
||||
账号使用限制公约
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="text-xs text-white/70 space-y-4 leading-relaxed">
|
||||
<p className="text-white/90">质押期间,甲方使用账号不得从事以下行为,否则将承担违约后果:</p>
|
||||
|
||||
<section className="bg-red-900/20 border border-red-500/20 rounded-lg p-3">
|
||||
<h4 className="font-bold text-red-400 mb-2 flex items-center gap-2">
|
||||
<span className="w-5 h-5 rounded-full bg-red-500/20 flex items-center justify-center text-[10px]">
|
||||
1
|
||||
</span>
|
||||
资产转移
|
||||
</h4>
|
||||
<p>转移、赠与、销毁账号内核心虚拟资产(如高级装备、稀有道具、大量游戏货币等)。</p>
|
||||
</section>
|
||||
|
||||
<section className="bg-red-900/20 border border-red-500/20 rounded-lg p-3">
|
||||
<h4 className="font-bold text-red-400 mb-2 flex items-center gap-2">
|
||||
<span className="w-5 h-5 rounded-full bg-red-500/20 flex items-center justify-center text-[10px]">
|
||||
2
|
||||
</span>
|
||||
违规操作
|
||||
</h4>
|
||||
<p>使用外挂、辅助脚本等非法程序;利用游戏漏洞;发表违规言论导致账号被处罚。</p>
|
||||
</section>
|
||||
|
||||
<section className="bg-red-900/20 border border-red-500/20 rounded-lg p-3">
|
||||
<h4 className="font-bold text-red-400 mb-2 flex items-center gap-2">
|
||||
<span className="w-5 h-5 rounded-full bg-red-500/20 flex items-center justify-center text-[10px]">
|
||||
3
|
||||
</span>
|
||||
权属变更
|
||||
</h4>
|
||||
<p>尝试修改密码、密保信息、绑定手机或邮箱(经乙方书面同意除外);将账号用于出租、出售等再处置。</p>
|
||||
</section>
|
||||
|
||||
<section className="bg-red-900/20 border border-red-500/20 rounded-lg p-3">
|
||||
<h4 className="font-bold text-red-400 mb-2 flex items-center gap-2">
|
||||
<span className="w-5 h-5 rounded-full bg-red-500/20 flex items-center justify-center text-[10px]">
|
||||
4
|
||||
</span>
|
||||
价值减损
|
||||
</h4>
|
||||
<p>进行明显有悖于账号价值最大化的操作(具体标准由乙方根据游戏类型判断并公示)。</p>
|
||||
</section>
|
||||
|
||||
<div className="bg-amber-900/20 border border-amber-500/20 rounded-lg p-3 mt-4">
|
||||
<p className="text-amber-200/80 text-center font-medium">
|
||||
甲方确认:我已阅读、理解并完全同意本协议及其所有附件的全部内容。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
className="w-full bg-amber-500 hover:bg-amber-400 text-black font-bold mt-4"
|
||||
onClick={() => setShowRestrictionDialog(false)}
|
||||
>
|
||||
我已阅读并同意
|
||||
</Button>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user