376 lines
16 KiB
TypeScript
376 lines
16 KiB
TypeScript
|
|
"use client"
|
|||
|
|
|
|||
|
|
import { useState, useEffect } from "react"
|
|||
|
|
import { useStore } from "@/lib/store"
|
|||
|
|
import { Button } from "@/components/ui/button"
|
|||
|
|
import { Input } from "@/components/ui/input"
|
|||
|
|
import { Label } from "@/components/ui/label"
|
|||
|
|
import { Switch } from "@/components/ui/switch"
|
|||
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
|||
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|||
|
|
import {
|
|||
|
|
Save,
|
|||
|
|
RefreshCw,
|
|||
|
|
Smartphone,
|
|||
|
|
CreditCard,
|
|||
|
|
ExternalLink,
|
|||
|
|
Bitcoin,
|
|||
|
|
Globe,
|
|||
|
|
Copy,
|
|||
|
|
Check,
|
|||
|
|
HelpCircle,
|
|||
|
|
} from "lucide-react"
|
|||
|
|
|
|||
|
|
export default function PaymentConfigPage() {
|
|||
|
|
const { settings, updateSettings, fetchSettings } = useStore()
|
|||
|
|
const [loading, setLoading] = useState(false)
|
|||
|
|
const [localSettings, setLocalSettings] = useState(settings.paymentMethods)
|
|||
|
|
const [copied, setCopied] = useState("")
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
setLocalSettings(settings.paymentMethods)
|
|||
|
|
}, [settings.paymentMethods])
|
|||
|
|
|
|||
|
|
const handleSave = async () => {
|
|||
|
|
setLoading(true)
|
|||
|
|
updateSettings({ paymentMethods: localSettings })
|
|||
|
|
await new Promise((resolve) => setTimeout(resolve, 800))
|
|||
|
|
setLoading(false)
|
|||
|
|
alert("配置已保存!")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const handleRefresh = async () => {
|
|||
|
|
setLoading(true)
|
|||
|
|
await fetchSettings()
|
|||
|
|
setLoading(false)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const handleCopy = (text: string, field: string) => {
|
|||
|
|
navigator.clipboard.writeText(text)
|
|||
|
|
setCopied(field)
|
|||
|
|
setTimeout(() => setCopied(""), 2000)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const updateWechat = (field: string, value: any) => {
|
|||
|
|
setLocalSettings((prev) => ({
|
|||
|
|
...prev,
|
|||
|
|
wechat: { ...prev.wechat, [field]: value },
|
|||
|
|
}))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const updateAlipay = (field: string, value: any) => {
|
|||
|
|
setLocalSettings((prev) => ({
|
|||
|
|
...prev,
|
|||
|
|
alipay: { ...prev.alipay, [field]: value },
|
|||
|
|
}))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const updateUsdt = (field: string, value: any) => {
|
|||
|
|
setLocalSettings((prev) => ({
|
|||
|
|
...prev,
|
|||
|
|
usdt: { ...prev.usdt, [field]: value },
|
|||
|
|
}))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const updatePaypal = (field: string, value: any) => {
|
|||
|
|
setLocalSettings((prev) => ({
|
|||
|
|
...prev,
|
|||
|
|
paypal: { ...prev.paypal, [field]: value },
|
|||
|
|
}))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div className="p-8 max-w-5xl mx-auto">
|
|||
|
|
<div className="flex justify-between items-center mb-8">
|
|||
|
|
<div>
|
|||
|
|
<h1 className="text-2xl font-bold mb-2 text-white">支付配置</h1>
|
|||
|
|
<p className="text-gray-400">配置微信、支付宝、USDT、PayPal等支付参数</p>
|
|||
|
|
</div>
|
|||
|
|
<div className="flex gap-3">
|
|||
|
|
<Button
|
|||
|
|
variant="outline"
|
|||
|
|
onClick={handleRefresh}
|
|||
|
|
className="border-gray-600 text-gray-300 hover:bg-gray-700/50 bg-transparent"
|
|||
|
|
>
|
|||
|
|
<RefreshCw className={`w-4 h-4 mr-2 ${loading ? "animate-spin" : ""}`} />
|
|||
|
|
同步配置
|
|||
|
|
</Button>
|
|||
|
|
<Button onClick={handleSave} className="bg-[#38bdac] hover:bg-[#2da396] text-white">
|
|||
|
|
<Save className="w-4 h-4 mr-2" />
|
|||
|
|
保存配置
|
|||
|
|
</Button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="mb-6 bg-[#07C160]/10 border border-[#07C160]/30 rounded-xl p-4">
|
|||
|
|
<div className="flex items-start gap-3">
|
|||
|
|
<HelpCircle className="w-5 h-5 text-[#07C160] flex-shrink-0 mt-0.5" />
|
|||
|
|
<div className="text-sm">
|
|||
|
|
<p className="font-medium mb-2 text-[#07C160]">如何获取微信群跳转链接?</p>
|
|||
|
|
<ol className="text-[#07C160]/80 space-y-1 list-decimal list-inside">
|
|||
|
|
<li>打开微信,进入目标微信群</li>
|
|||
|
|
<li>点击右上角"..." → "群二维码"</li>
|
|||
|
|
<li>点击右上角"..." → "发送到电脑"</li>
|
|||
|
|
<li>在电脑上保存二维码图片,上传到图床获取URL</li>
|
|||
|
|
<li>或使用草料二维码等工具解析二维码获取链接</li>
|
|||
|
|
</ol>
|
|||
|
|
<p className="text-[#07C160]/60 mt-2">提示:微信群二维码7天后失效,建议使用活码工具</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<Tabs defaultValue="wechat" className="space-y-6">
|
|||
|
|
<TabsList className="bg-[#0f2137] border border-gray-700/50 p-1 grid grid-cols-4 w-full">
|
|||
|
|
<TabsTrigger
|
|||
|
|
value="wechat"
|
|||
|
|
className="data-[state=active]:bg-[#07C160]/20 data-[state=active]:text-[#07C160] text-gray-400"
|
|||
|
|
>
|
|||
|
|
<Smartphone className="w-4 h-4 mr-2" />
|
|||
|
|
微信
|
|||
|
|
</TabsTrigger>
|
|||
|
|
<TabsTrigger
|
|||
|
|
value="alipay"
|
|||
|
|
className="data-[state=active]:bg-[#1677FF]/20 data-[state=active]:text-[#1677FF] text-gray-400"
|
|||
|
|
>
|
|||
|
|
<CreditCard className="w-4 h-4 mr-2" />
|
|||
|
|
支付宝
|
|||
|
|
</TabsTrigger>
|
|||
|
|
<TabsTrigger
|
|||
|
|
value="usdt"
|
|||
|
|
className="data-[state=active]:bg-[#26A17B]/20 data-[state=active]:text-[#26A17B] text-gray-400"
|
|||
|
|
>
|
|||
|
|
<Bitcoin className="w-4 h-4 mr-2" />
|
|||
|
|
USDT
|
|||
|
|
</TabsTrigger>
|
|||
|
|
<TabsTrigger
|
|||
|
|
value="paypal"
|
|||
|
|
className="data-[state=active]:bg-[#003087]/20 data-[state=active]:text-[#169BD7] text-gray-400"
|
|||
|
|
>
|
|||
|
|
<Globe className="w-4 h-4 mr-2" />
|
|||
|
|
PayPal
|
|||
|
|
</TabsTrigger>
|
|||
|
|
</TabsList>
|
|||
|
|
|
|||
|
|
{/* 微信支付配置 */}
|
|||
|
|
<TabsContent value="wechat" className="space-y-4">
|
|||
|
|
<Card className="bg-[#0f2137] border-gray-700/50 shadow-xl">
|
|||
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|||
|
|
<div className="space-y-1">
|
|||
|
|
<CardTitle className="text-[#07C160] flex items-center gap-2">
|
|||
|
|
<Smartphone className="w-5 h-5" />
|
|||
|
|
微信支付配置
|
|||
|
|
</CardTitle>
|
|||
|
|
<CardDescription className="text-gray-400">配置微信支付参数和跳转链接</CardDescription>
|
|||
|
|
</div>
|
|||
|
|
<Switch checked={localSettings.wechat.enabled} onCheckedChange={(c) => updateWechat("enabled", c)} />
|
|||
|
|
</CardHeader>
|
|||
|
|
<CardContent className="space-y-4">
|
|||
|
|
{/* API配置 */}
|
|||
|
|
<div className="grid grid-cols-2 gap-4">
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">网站AppID</Label>
|
|||
|
|
<Input
|
|||
|
|
className="bg-[#0a1628] border-gray-700 text-white font-mono text-sm"
|
|||
|
|
value={localSettings.wechat.websiteAppId || ""}
|
|||
|
|
onChange={(e) => updateWechat("websiteAppId", e.target.value)}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">商户号</Label>
|
|||
|
|
<Input
|
|||
|
|
className="bg-[#0a1628] border-gray-700 text-white font-mono text-sm"
|
|||
|
|
value={localSettings.wechat.merchantId || ""}
|
|||
|
|
onChange={(e) => updateWechat("merchantId", e.target.value)}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 跳转链接配置 - 重点 */}
|
|||
|
|
<div className="border-t border-gray-700/50 pt-4 space-y-4">
|
|||
|
|
<h4 className="text-white font-medium flex items-center gap-2">
|
|||
|
|
<ExternalLink className="w-4 h-4 text-[#38bdac]" />
|
|||
|
|
跳转链接配置(核心功能)
|
|||
|
|
</h4>
|
|||
|
|
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">微信收款码/支付链接</Label>
|
|||
|
|
<Input
|
|||
|
|
className="bg-[#0a1628] border-gray-700 text-white placeholder:text-gray-500"
|
|||
|
|
placeholder="https://收款码图片URL 或 weixin://支付链接"
|
|||
|
|
value={localSettings.wechat.qrCode || ""}
|
|||
|
|
onChange={(e) => updateWechat("qrCode", e.target.value)}
|
|||
|
|
/>
|
|||
|
|
<p className="text-xs text-gray-500">用户点击微信支付后显示的二维码图片URL</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="space-y-2 bg-[#07C160]/5 p-4 rounded-xl border border-[#07C160]/20">
|
|||
|
|
<Label className="text-[#07C160] font-medium">微信群跳转链接(支付成功后跳转)</Label>
|
|||
|
|
<Input
|
|||
|
|
className="bg-[#0a1628] border-[#07C160]/30 text-white placeholder:text-gray-500"
|
|||
|
|
placeholder="https://weixin.qq.com/g/... 或微信群二维码图片URL"
|
|||
|
|
value={localSettings.wechat.groupQrCode || ""}
|
|||
|
|
onChange={(e) => updateWechat("groupQrCode", e.target.value)}
|
|||
|
|
/>
|
|||
|
|
<p className="text-xs text-[#07C160]/70">用户支付成功后将自动跳转到此链接,进入指定微信群</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</CardContent>
|
|||
|
|
</Card>
|
|||
|
|
</TabsContent>
|
|||
|
|
|
|||
|
|
{/* 支付宝配置 */}
|
|||
|
|
<TabsContent value="alipay" className="space-y-4">
|
|||
|
|
<Card className="bg-[#0f2137] border-gray-700/50 shadow-xl">
|
|||
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|||
|
|
<div className="space-y-1">
|
|||
|
|
<CardTitle className="text-[#1677FF] flex items-center gap-2">
|
|||
|
|
<CreditCard className="w-5 h-5" />
|
|||
|
|
支付宝配置
|
|||
|
|
</CardTitle>
|
|||
|
|
<CardDescription className="text-gray-400">已加载真实支付宝参数</CardDescription>
|
|||
|
|
</div>
|
|||
|
|
<Switch checked={localSettings.alipay.enabled} onCheckedChange={(c) => updateAlipay("enabled", c)} />
|
|||
|
|
</CardHeader>
|
|||
|
|
<CardContent className="space-y-4">
|
|||
|
|
<div className="grid grid-cols-2 gap-4">
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">合作者身份 (PID)</Label>
|
|||
|
|
<div className="flex gap-2">
|
|||
|
|
<Input
|
|||
|
|
className="bg-[#0a1628] border-gray-700 text-white font-mono text-sm"
|
|||
|
|
value={localSettings.alipay.partnerId || ""}
|
|||
|
|
onChange={(e) => updateAlipay("partnerId", e.target.value)}
|
|||
|
|
/>
|
|||
|
|
<Button
|
|||
|
|
size="icon"
|
|||
|
|
variant="outline"
|
|||
|
|
className="border-gray-700 bg-transparent"
|
|||
|
|
onClick={() => handleCopy(localSettings.alipay.partnerId || "", "pid")}
|
|||
|
|
>
|
|||
|
|
{copied === "pid" ? (
|
|||
|
|
<Check className="w-4 h-4 text-green-500" />
|
|||
|
|
) : (
|
|||
|
|
<Copy className="w-4 h-4 text-gray-400" />
|
|||
|
|
)}
|
|||
|
|
</Button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">安全校验码 (Key)</Label>
|
|||
|
|
<Input
|
|||
|
|
type="password"
|
|||
|
|
className="bg-[#0a1628] border-gray-700 text-white font-mono text-sm"
|
|||
|
|
value={localSettings.alipay.securityKey || ""}
|
|||
|
|
onChange={(e) => updateAlipay("securityKey", e.target.value)}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="border-t border-gray-700/50 pt-4 space-y-4">
|
|||
|
|
<h4 className="text-white font-medium flex items-center gap-2">
|
|||
|
|
<ExternalLink className="w-4 h-4 text-[#38bdac]" />
|
|||
|
|
跳转链接配置
|
|||
|
|
</h4>
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">支付宝收款码/跳转链接</Label>
|
|||
|
|
<Input
|
|||
|
|
className="bg-[#0a1628] border-gray-700 text-white placeholder:text-gray-500"
|
|||
|
|
placeholder="https://qr.alipay.com/... 或收款码图片URL"
|
|||
|
|
value={localSettings.alipay.qrCode || ""}
|
|||
|
|
onChange={(e) => updateAlipay("qrCode", e.target.value)}
|
|||
|
|
/>
|
|||
|
|
<p className="text-xs text-gray-500">用户点击支付宝支付后显示的二维码</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</CardContent>
|
|||
|
|
</Card>
|
|||
|
|
</TabsContent>
|
|||
|
|
|
|||
|
|
{/* USDT配置 */}
|
|||
|
|
<TabsContent value="usdt" className="space-y-4">
|
|||
|
|
<Card className="bg-[#0f2137] border-gray-700/50 shadow-xl">
|
|||
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|||
|
|
<div className="space-y-1">
|
|||
|
|
<CardTitle className="text-[#26A17B] flex items-center gap-2">
|
|||
|
|
<Bitcoin className="w-5 h-5" />
|
|||
|
|
USDT配置
|
|||
|
|
</CardTitle>
|
|||
|
|
<CardDescription className="text-gray-400">配置加密货币收款地址</CardDescription>
|
|||
|
|
</div>
|
|||
|
|
<Switch checked={localSettings.usdt.enabled} onCheckedChange={(c) => updateUsdt("enabled", c)} />
|
|||
|
|
</CardHeader>
|
|||
|
|
<CardContent className="space-y-4">
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">网络类型</Label>
|
|||
|
|
<select
|
|||
|
|
className="w-full bg-[#0a1628] border border-gray-700 text-white rounded-md p-2"
|
|||
|
|
value={localSettings.usdt.network}
|
|||
|
|
onChange={(e) => updateUsdt("network", e.target.value)}
|
|||
|
|
>
|
|||
|
|
<option value="TRC20">TRC20 (波场)</option>
|
|||
|
|
<option value="ERC20">ERC20 (以太坊)</option>
|
|||
|
|
<option value="BEP20">BEP20 (币安链)</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">收款地址</Label>
|
|||
|
|
<Input
|
|||
|
|
className="bg-[#0a1628] border-gray-700 text-white font-mono text-sm"
|
|||
|
|
placeholder="T... (TRC20地址)"
|
|||
|
|
value={localSettings.usdt.address || ""}
|
|||
|
|
onChange={(e) => updateUsdt("address", e.target.value)}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">汇率 (1 USD = ? CNY)</Label>
|
|||
|
|
<Input
|
|||
|
|
type="number"
|
|||
|
|
className="bg-[#0a1628] border-gray-700 text-white"
|
|||
|
|
value={localSettings.usdt.exchangeRate}
|
|||
|
|
onChange={(e) => updateUsdt("exchangeRate", Number.parseFloat(e.target.value) || 7.2)}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</CardContent>
|
|||
|
|
</Card>
|
|||
|
|
</TabsContent>
|
|||
|
|
|
|||
|
|
{/* PayPal配置 */}
|
|||
|
|
<TabsContent value="paypal" className="space-y-4">
|
|||
|
|
<Card className="bg-[#0f2137] border-gray-700/50 shadow-xl">
|
|||
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|||
|
|
<div className="space-y-1">
|
|||
|
|
<CardTitle className="text-[#169BD7] flex items-center gap-2">
|
|||
|
|
<Globe className="w-5 h-5" />
|
|||
|
|
PayPal配置
|
|||
|
|
</CardTitle>
|
|||
|
|
<CardDescription className="text-gray-400">配置PayPal收款账户</CardDescription>
|
|||
|
|
</div>
|
|||
|
|
<Switch checked={localSettings.paypal.enabled} onCheckedChange={(c) => updatePaypal("enabled", c)} />
|
|||
|
|
</CardHeader>
|
|||
|
|
<CardContent className="space-y-4">
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">PayPal邮箱</Label>
|
|||
|
|
<Input
|
|||
|
|
className="bg-[#0a1628] border-gray-700 text-white"
|
|||
|
|
placeholder="your@email.com"
|
|||
|
|
value={localSettings.paypal.email || ""}
|
|||
|
|
onChange={(e) => updatePaypal("email", e.target.value)}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<Label className="text-gray-300">汇率 (1 USD = ? CNY)</Label>
|
|||
|
|
<Input
|
|||
|
|
type="number"
|
|||
|
|
className="bg-[#0a1628] border-gray-700 text-white"
|
|||
|
|
value={localSettings.paypal.exchangeRate}
|
|||
|
|
onChange={(e) => updatePaypal("exchangeRate", Number.parseFloat(e.target.value) || 7.2)}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</CardContent>
|
|||
|
|
</Card>
|
|||
|
|
</TabsContent>
|
|||
|
|
</Tabs>
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|