249 lines
12 KiB
TypeScript
249 lines
12 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 } from "lucide-react"
|
||
|
||
export default function PaymentConfigPage() {
|
||
const { settings, updateSettings, fetchSettings } = useStore()
|
||
const [loading, setLoading] = useState(false)
|
||
const [localSettings, setLocalSettings] = useState(settings.paymentMethods)
|
||
|
||
// Sync with store on mount
|
||
useEffect(() => {
|
||
setLocalSettings(settings.paymentMethods)
|
||
}, [settings.paymentMethods])
|
||
|
||
const handleSave = async () => {
|
||
setLoading(true)
|
||
// Update store (and local storage)
|
||
updateSettings({ paymentMethods: localSettings })
|
||
|
||
// Simulate API call delay
|
||
await new Promise(resolve => setTimeout(resolve, 800))
|
||
setLoading(false)
|
||
alert("配置已保存!")
|
||
}
|
||
|
||
const handleRefresh = async () => {
|
||
setLoading(true)
|
||
await fetchSettings()
|
||
setLoading(false)
|
||
}
|
||
|
||
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 }
|
||
}))
|
||
}
|
||
|
||
return (
|
||
<div className="p-8 max-w-5xl mx-auto text-white">
|
||
<div className="flex justify-between items-center mb-8">
|
||
<div>
|
||
<h1 className="text-2xl font-bold mb-2">支付配置</h1>
|
||
<p className="text-gray-400">配置微信、支付宝及USDT支付参数</p>
|
||
</div>
|
||
<div className="flex gap-4">
|
||
<Button variant="outline" onClick={handleRefresh} className="border-gray-600 text-gray-300 hover:text-white 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="grid grid-cols-1 gap-8">
|
||
{/* Wechat Pay */}
|
||
<Card className="bg-[#1e293b] border-gray-700">
|
||
<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">
|
||
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"><path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 0 1 .213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 0 0 .167-.054l1.903-1.114a.864.864 0 0 1 .717-.098 10.16 10.16 0 0 0 2.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178A1.17 1.17 0 0 1 4.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178 1.17 1.17 0 0 1-1.162-1.178c0-.651.52-1.18 1.162-1.18zm5.34 2.867c-1.797-.052-3.746.512-5.28 1.786-1.72 1.428-2.687 3.72-1.78 6.22.942 2.453 3.666 4.229 6.884 4.229.826 0 1.622-.12 2.361-.336a.722.722 0 0 1 .598.082l1.584.926a.272.272 0 0 0 .14.047c.134 0 .24-.111.24-.247 0-.06-.023-.12-.038-.177l-.327-1.233a.582.582 0 0 1-.023-.156.49.49 0 0 1 .201-.398C23.024 18.48 24 16.82 24 14.98c0-3.21-2.931-5.837-6.656-6.088V8.89c-.135-.01-.269-.03-.406-.03zm-2.53 3.274c.535 0 .969.44.969.982a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.982.97-.982zm4.844 0c.535 0 .969.44.969.982a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.982.969-.982z"/></svg>
|
||
微信支付
|
||
</CardTitle>
|
||
<CardDescription className="text-gray-400">配置微信商户号及API密钥</CardDescription>
|
||
</div>
|
||
<Switch
|
||
checked={localSettings.wechat.enabled}
|
||
onCheckedChange={(c) => updateWechat('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">网站应用 AppID</Label>
|
||
<Input
|
||
className="bg-[#0f172a] border-gray-600 text-white"
|
||
placeholder="wx..."
|
||
value={localSettings.wechat.websiteAppId || ''}
|
||
onChange={(e) => updateWechat('websiteAppId', e.target.value)}
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label className="text-gray-300">网站应用 AppSecret</Label>
|
||
<Input
|
||
type="password"
|
||
className="bg-[#0f172a] border-gray-600 text-white"
|
||
placeholder="......"
|
||
value={localSettings.wechat.websiteAppSecret || ''}
|
||
onChange={(e) => updateWechat('websiteAppSecret', e.target.value)}
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label className="text-gray-300">商户号 (MchId)</Label>
|
||
<Input
|
||
className="bg-[#0f172a] border-gray-600 text-white"
|
||
placeholder="160..."
|
||
value={localSettings.wechat.merchantId || ''}
|
||
onChange={(e) => updateWechat('merchantId', e.target.value)}
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label className="text-gray-300">API v3 密钥</Label>
|
||
<Input
|
||
type="password"
|
||
className="bg-[#0f172a] border-gray-600 text-white"
|
||
placeholder="......"
|
||
value={localSettings.wechat.apiKey || ''}
|
||
onChange={(e) => updateWechat('apiKey', e.target.value)}
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label className="text-gray-300">个人收款码 URL (兜底方案)</Label>
|
||
<Input
|
||
className="bg-[#0f172a] border-gray-600 text-white"
|
||
placeholder="/images/wechat-pay.png"
|
||
value={localSettings.wechat.qrCode || ''}
|
||
onChange={(e) => updateWechat('qrCode', e.target.value)}
|
||
/>
|
||
<p className="text-xs text-gray-500">当未配置企业支付参数时,将显示此二维码进行个人收款</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Alipay */}
|
||
<Card className="bg-[#1e293b] border-gray-700">
|
||
<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">
|
||
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"><path d="M8.77 20.62l9.92-4.33c-.12-.33-.24-.66-.38-.99-.14-.33-.3-.66-.47-.99H8.08c-2.2 0-3.99-1.79-3.99-3.99V8.08c0-2.2 1.79-3.99 3.99-3.99h7.84c2.2 0 3.99 1.79 3.99 3.99v2.24h-8.66c-.55 0-1 .45-1 1s.45 1 1 1h10.66c-.18 1.73-.71 3.36-1.53 4.83l-2.76 1.2c-.74-1.69-1.74-3.24-2.93-4.6-.52-.59-1.11-1.13-1.76-1.59H4.09v4.24c0 2.2 1.79 3.99 3.99 3.99h.69v.23z"/></svg>
|
||
支付宝
|
||
</CardTitle>
|
||
<CardDescription className="text-gray-400">配置支付宝PID及密钥</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>
|
||
<Input
|
||
className="bg-[#0f172a] border-gray-600 text-white"
|
||
placeholder="2088..."
|
||
value={localSettings.alipay.partnerId || ''}
|
||
onChange={(e) => updateAlipay('partnerId', e.target.value)}
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label className="text-gray-300">安全校验码 (Key)</Label>
|
||
<Input
|
||
type="password"
|
||
className="bg-[#0f172a] border-gray-600 text-white"
|
||
placeholder="......"
|
||
value={localSettings.alipay.securityKey || ''}
|
||
onChange={(e) => updateAlipay('securityKey', e.target.value)}
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label className="text-gray-300">个人收款码 URL (兜底方案)</Label>
|
||
<Input
|
||
className="bg-[#0f172a] border-gray-600 text-white"
|
||
placeholder="/images/alipay.png"
|
||
value={localSettings.alipay.qrCode || ''}
|
||
onChange={(e) => updateAlipay('qrCode', e.target.value)}
|
||
/>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* USDT */}
|
||
<Card className="bg-[#1e293b] border-gray-700">
|
||
<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">
|
||
<span className="font-bold">₮</span> 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="grid grid-cols-2 gap-4">
|
||
<div className="space-y-2">
|
||
<Label className="text-gray-300">网络协议</Label>
|
||
<Input
|
||
className="bg-[#0f172a] border-gray-600 text-white"
|
||
value={localSettings.usdt.network || 'TRC20'}
|
||
onChange={(e) => updateUsdt('network', e.target.value)}
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label className="text-gray-300">汇率 (USD -> CNY)</Label>
|
||
<Input
|
||
type="number"
|
||
className="bg-[#0f172a] border-gray-600 text-white"
|
||
value={localSettings.usdt.exchangeRate || 7.2}
|
||
onChange={(e) => updateUsdt('exchangeRate', parseFloat(e.target.value))}
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label className="text-gray-300">钱包地址</Label>
|
||
<Input
|
||
className="bg-[#0f172a] border-gray-600 text-white font-mono"
|
||
placeholder="T..."
|
||
value={localSettings.usdt.address || ''}
|
||
onChange={(e) => updateUsdt('address', e.target.value)}
|
||
/>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|