feat(mining-admin): 配置管理新增100亿销毁池和200万挖矿池账户
在配置管理页面新增两个池账户卡片,UI 风格对齐做市商管理中的 "现金余额(积分值)",仅支持区块链方式充值与提现: - 100亿销毁池 (wallet-22fd661f, 2-of-3 门限) 地址: 0xdE2932D2A25e1698c1354A41e2e46B414C46F5a1 - 200万挖矿池 (wallet-974e78f5, 2-of-3 门限) 地址: 0x8BC9091375ae8ef43ae011F0f9bAf10e51bC9D59 具体改动: - .env.production: 新增 BURN_POOL / MINING_POOL 钱包名和地址环境变量 - configs.api.ts: 新增 tradingClient、PoolAccountBalance 接口、 getPoolAccountBalance 和 poolAccountBlockchainWithdraw API - use-configs.ts: 新增 usePoolAccountBalance (30s 刷新) 和 usePoolAccountBlockchainWithdraw hooks - configs/page.tsx: 新增两个并排池账户 Card,包含余额展示、 QR 码充值弹窗、区块链提现弹窗(含 0x 地址校验) 后端需实现: - GET /admin/pool-accounts/:walletName/balance - POST /admin/pool-accounts/:walletName/blockchain-withdraw Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
999d0389b3
commit
6dbb620e82
|
|
@ -1,3 +1,11 @@
|
|||
NEXT_PUBLIC_API_URL=https://mapi.szaiai.com/api/v2/mining-admin
|
||||
TRADING_SERVICE_URL=https://mapi.szaiai.com/api/v2/trading
|
||||
NEXT_PUBLIC_APP_NAME=挖矿管理后台
|
||||
|
||||
# 100亿销毁池钱包配置
|
||||
NEXT_PUBLIC_BURN_POOL_WALLET_NAME=wallet-22fd661f
|
||||
NEXT_PUBLIC_BURN_POOL_WALLET_ADDRESS=0xdE2932D2A25e1698c1354A41e2e46B414C46F5a1
|
||||
|
||||
# 200万挖矿池钱包配置
|
||||
NEXT_PUBLIC_MINING_POOL_WALLET_NAME=wallet-974e78f5
|
||||
NEXT_PUBLIC_MINING_POOL_WALLET_ADDRESS=0x8BC9091375ae8ef43ae011F0f9bAf10e51bC9D59
|
||||
|
|
|
|||
|
|
@ -1,20 +1,34 @@
|
|||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { QRCodeSVG } from 'qrcode.react';
|
||||
import { PageHeader } from '@/components/layout/page-header';
|
||||
import { useConfigs, useUpdateConfig, useTransferEnabled, useSetTransferEnabled, useMiningStatus, useActivateMining, useDeactivateMining, useP2pTransferFee, useSetP2pTransferFee } from '@/features/configs/hooks/use-configs';
|
||||
import { useConfigs, useUpdateConfig, useTransferEnabled, useSetTransferEnabled, useMiningStatus, useActivateMining, useDeactivateMining, useP2pTransferFee, useSetP2pTransferFee, usePoolAccountBalance, usePoolAccountBlockchainWithdraw } from '@/features/configs/hooks/use-configs';
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogFooter,
|
||||
DialogTrigger,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Pencil, Save, X, Play, Pause, AlertCircle, CheckCircle2, Loader2 } from 'lucide-react';
|
||||
import { Pencil, Save, X, Play, Pause, AlertCircle, CheckCircle2, Loader2, Wallet, PlusCircle, MinusCircle, Copy, Check, Flame, HardHat } from 'lucide-react';
|
||||
import type { SystemConfig } from '@/types/config';
|
||||
|
||||
const BURN_POOL_WALLET_NAME = process.env.NEXT_PUBLIC_BURN_POOL_WALLET_NAME || 'wallet-22fd661f';
|
||||
const BURN_POOL_WALLET_ADDRESS = process.env.NEXT_PUBLIC_BURN_POOL_WALLET_ADDRESS || '0xdE2932D2A25e1698c1354A41e2e46B414C46F5a1';
|
||||
const MINING_POOL_WALLET_NAME = process.env.NEXT_PUBLIC_MINING_POOL_WALLET_NAME || 'wallet-974e78f5';
|
||||
const MINING_POOL_WALLET_ADDRESS = process.env.NEXT_PUBLIC_MINING_POOL_WALLET_ADDRESS || '0x8BC9091375ae8ef43ae011F0f9bAf10e51bC9D59';
|
||||
|
||||
const categoryLabels: Record<string, string> = {
|
||||
mining: '挖矿配置',
|
||||
trading: '交易配置',
|
||||
|
|
@ -34,11 +48,22 @@ export default function ConfigsPage() {
|
|||
const { data: feeConfig, isLoading: feeLoading } = useP2pTransferFee();
|
||||
const setP2pTransferFee = useSetP2pTransferFee();
|
||||
|
||||
const { data: burnPoolBalance, isLoading: burnPoolLoading } = usePoolAccountBalance(BURN_POOL_WALLET_NAME);
|
||||
const { data: miningPoolBalance, isLoading: miningPoolLoading } = usePoolAccountBalance(MINING_POOL_WALLET_NAME);
|
||||
const blockchainWithdrawMutation = usePoolAccountBlockchainWithdraw();
|
||||
|
||||
const [editingConfig, setEditingConfig] = useState<SystemConfig | null>(null);
|
||||
const [editValue, setEditValue] = useState('');
|
||||
const [feeValue, setFeeValue] = useState('');
|
||||
const [minAmountValue, setMinAmountValue] = useState('');
|
||||
|
||||
// 池账户区块链提现状态
|
||||
const [burnWithdrawAddress, setBurnWithdrawAddress] = useState('');
|
||||
const [burnWithdrawAmount, setBurnWithdrawAmount] = useState('');
|
||||
const [miningWithdrawAddress, setMiningWithdrawAddress] = useState('');
|
||||
const [miningWithdrawAmount, setMiningWithdrawAmount] = useState('');
|
||||
const [copiedAddress, setCopiedAddress] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (feeConfig) {
|
||||
setFeeValue(feeConfig.fee);
|
||||
|
|
@ -46,6 +71,19 @@ export default function ConfigsPage() {
|
|||
}
|
||||
}, [feeConfig]);
|
||||
|
||||
const handleCopyAddress = async (address: string) => {
|
||||
await navigator.clipboard.writeText(address);
|
||||
setCopiedAddress(address);
|
||||
setTimeout(() => setCopiedAddress(null), 2000);
|
||||
};
|
||||
|
||||
const formatBalance = (value: string | undefined, decimals: number = 2) => {
|
||||
if (!value) return '0';
|
||||
const num = parseFloat(value);
|
||||
if (isNaN(num)) return '0';
|
||||
return num.toLocaleString(undefined, { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
|
||||
};
|
||||
|
||||
const handleEdit = (config: SystemConfig) => {
|
||||
setEditingConfig(config);
|
||||
setEditValue(config.configValue);
|
||||
|
|
@ -194,6 +232,291 @@ export default function ConfigsPage() {
|
|||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 池账户管理 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* 100亿销毁池 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-lg flex items-center gap-2">
|
||||
<Flame className="h-5 w-5 text-orange-500" />
|
||||
100亿销毁池
|
||||
</CardTitle>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
2-of-3 门限
|
||||
</Badge>
|
||||
</div>
|
||||
<CardDescription>
|
||||
钱包: {BURN_POOL_WALLET_NAME}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
{burnPoolLoading ? (
|
||||
<Skeleton className="h-20 w-full" />
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">总余额</p>
|
||||
<p className="text-2xl font-bold">{formatBalance(burnPoolBalance?.balance)}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">可用余额</p>
|
||||
<p className="text-2xl font-bold text-orange-500">{formatBalance(burnPoolBalance?.availableBalance)}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">冻结中</p>
|
||||
<p className="text-lg text-muted-foreground">{formatBalance(burnPoolBalance?.frozenBalance)}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-2 pt-4 border-t">
|
||||
{/* 区块链充值 */}
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button size="sm" variant="outline">
|
||||
<PlusCircle className="h-4 w-4 mr-1" />
|
||||
充值
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>区块链充值 — 100亿销毁池</DialogTitle>
|
||||
<DialogDescription>向以下地址转入 fUSDT(积分值代币)</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<div className="p-4 bg-white rounded-lg">
|
||||
<QRCodeSVG value={BURN_POOL_WALLET_ADDRESS} size={180} />
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<Label className="text-xs text-muted-foreground">钱包地址 (Kava EVM)</Label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<code className="flex-1 text-xs bg-muted p-2 rounded break-all">
|
||||
{BURN_POOL_WALLET_ADDRESS}
|
||||
</code>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => handleCopyAddress(BURN_POOL_WALLET_ADDRESS)}
|
||||
>
|
||||
{copiedAddress === BURN_POOL_WALLET_ADDRESS ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xs text-yellow-600 bg-yellow-50 p-2 rounded w-full">
|
||||
<AlertCircle className="h-3 w-3 inline mr-1" />
|
||||
转账后系统将自动检测并入账(约需12个区块确认)
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 区块链提现 */}
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button size="sm" variant="outline">
|
||||
<MinusCircle className="h-4 w-4 mr-1" />
|
||||
提现
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>区块链提现 — 100亿销毁池</DialogTitle>
|
||||
<DialogDescription>转账 fUSDT(积分值代币)到指定地址</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label>目标地址 (Kava EVM)</Label>
|
||||
<Input
|
||||
value={burnWithdrawAddress}
|
||||
onChange={(e) => setBurnWithdrawAddress(e.target.value)}
|
||||
placeholder="0x..."
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>提现金额</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={burnWithdrawAmount}
|
||||
onChange={(e) => setBurnWithdrawAmount(e.target.value)}
|
||||
placeholder="请输入金额"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="w-full"
|
||||
onClick={() => {
|
||||
blockchainWithdrawMutation.mutate({
|
||||
walletName: BURN_POOL_WALLET_NAME,
|
||||
toAddress: burnWithdrawAddress,
|
||||
amount: burnWithdrawAmount,
|
||||
});
|
||||
setBurnWithdrawAddress('');
|
||||
setBurnWithdrawAmount('');
|
||||
}}
|
||||
disabled={
|
||||
blockchainWithdrawMutation.isPending ||
|
||||
!burnWithdrawAddress ||
|
||||
!burnWithdrawAmount ||
|
||||
!burnWithdrawAddress.startsWith('0x')
|
||||
}
|
||||
>
|
||||
{blockchainWithdrawMutation.isPending ? '链上转账中...' : '确认区块链提现'}
|
||||
</Button>
|
||||
<div className="text-xs text-yellow-600 bg-yellow-50 p-2 rounded">
|
||||
<AlertCircle className="h-3 w-3 inline mr-1" />
|
||||
区块链提现将通过 2-of-3 门限签名从销毁池钱包转账到目标地址
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 200万挖矿池 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-lg flex items-center gap-2">
|
||||
<HardHat className="h-5 w-5 text-blue-500" />
|
||||
200万挖矿池
|
||||
</CardTitle>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
2-of-3 门限
|
||||
</Badge>
|
||||
</div>
|
||||
<CardDescription>
|
||||
钱包: {MINING_POOL_WALLET_NAME}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
{miningPoolLoading ? (
|
||||
<Skeleton className="h-20 w-full" />
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">总余额</p>
|
||||
<p className="text-2xl font-bold">{formatBalance(miningPoolBalance?.balance)}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">可用余额</p>
|
||||
<p className="text-2xl font-bold text-blue-500">{formatBalance(miningPoolBalance?.availableBalance)}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">冻结中</p>
|
||||
<p className="text-lg text-muted-foreground">{formatBalance(miningPoolBalance?.frozenBalance)}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-2 pt-4 border-t">
|
||||
{/* 区块链充值 */}
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button size="sm" variant="outline">
|
||||
<PlusCircle className="h-4 w-4 mr-1" />
|
||||
充值
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>区块链充值 — 200万挖矿池</DialogTitle>
|
||||
<DialogDescription>向以下地址转入 fUSDT(积分值代币)</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<div className="p-4 bg-white rounded-lg">
|
||||
<QRCodeSVG value={MINING_POOL_WALLET_ADDRESS} size={180} />
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<Label className="text-xs text-muted-foreground">钱包地址 (Kava EVM)</Label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<code className="flex-1 text-xs bg-muted p-2 rounded break-all">
|
||||
{MINING_POOL_WALLET_ADDRESS}
|
||||
</code>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => handleCopyAddress(MINING_POOL_WALLET_ADDRESS)}
|
||||
>
|
||||
{copiedAddress === MINING_POOL_WALLET_ADDRESS ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xs text-yellow-600 bg-yellow-50 p-2 rounded w-full">
|
||||
<AlertCircle className="h-3 w-3 inline mr-1" />
|
||||
转账后系统将自动检测并入账(约需12个区块确认)
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 区块链提现 */}
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button size="sm" variant="outline">
|
||||
<MinusCircle className="h-4 w-4 mr-1" />
|
||||
提现
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>区块链提现 — 200万挖矿池</DialogTitle>
|
||||
<DialogDescription>转账 fUSDT(积分值代币)到指定地址</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label>目标地址 (Kava EVM)</Label>
|
||||
<Input
|
||||
value={miningWithdrawAddress}
|
||||
onChange={(e) => setMiningWithdrawAddress(e.target.value)}
|
||||
placeholder="0x..."
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>提现金额</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={miningWithdrawAmount}
|
||||
onChange={(e) => setMiningWithdrawAmount(e.target.value)}
|
||||
placeholder="请输入金额"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="w-full"
|
||||
onClick={() => {
|
||||
blockchainWithdrawMutation.mutate({
|
||||
walletName: MINING_POOL_WALLET_NAME,
|
||||
toAddress: miningWithdrawAddress,
|
||||
amount: miningWithdrawAmount,
|
||||
});
|
||||
setMiningWithdrawAddress('');
|
||||
setMiningWithdrawAmount('');
|
||||
}}
|
||||
disabled={
|
||||
blockchainWithdrawMutation.isPending ||
|
||||
!miningWithdrawAddress ||
|
||||
!miningWithdrawAmount ||
|
||||
!miningWithdrawAddress.startsWith('0x')
|
||||
}
|
||||
>
|
||||
{blockchainWithdrawMutation.isPending ? '链上转账中...' : '确认区块链提现'}
|
||||
</Button>
|
||||
<div className="text-xs text-yellow-600 bg-yellow-50 p-2 rounded">
|
||||
<AlertCircle className="h-3 w-3 inline mr-1" />
|
||||
区块链提现将通过 2-of-3 门限签名从挖矿池钱包转账到目标地址
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">划转开关</CardTitle>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,62 @@
|
|||
import { apiClient } from '@/lib/api/client';
|
||||
import axios from 'axios';
|
||||
import type { SystemConfig } from '@/types/config';
|
||||
|
||||
const tradingBaseURL = '/api/trading';
|
||||
|
||||
const tradingClient = axios.create({
|
||||
baseURL: tradingBaseURL,
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
tradingClient.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = typeof window !== 'undefined' ? localStorage.getItem('admin_token') : null;
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => Promise.reject(error)
|
||||
);
|
||||
|
||||
tradingClient.interceptors.response.use(
|
||||
(response) => {
|
||||
if (response.data && response.data.data !== undefined) {
|
||||
response.data = response.data.data;
|
||||
}
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
if (error.response?.status === 401) {
|
||||
localStorage.removeItem('admin_token');
|
||||
if (typeof window !== 'undefined' && !window.location.pathname.includes('/login')) {
|
||||
window.location.href = '/login';
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export interface ContributionSyncStatus {
|
||||
isSynced: boolean;
|
||||
miningNetworkTotal: string;
|
||||
networkTotalContribution: string;
|
||||
}
|
||||
|
||||
export interface PoolAccountBalance {
|
||||
walletName: string;
|
||||
walletAddress: string;
|
||||
balance: string;
|
||||
availableBalance: string;
|
||||
frozenBalance: string;
|
||||
threshold: string;
|
||||
lastUpdated?: string;
|
||||
}
|
||||
|
||||
export interface MiningStatus {
|
||||
initialized: boolean;
|
||||
isActive: boolean;
|
||||
|
|
@ -63,4 +113,23 @@ export const configsApi = {
|
|||
setP2pTransferFee: async (fee: string, minTransferAmount: string): Promise<void> => {
|
||||
await apiClient.post('/configs/p2p-transfer-fee', { fee, minTransferAmount });
|
||||
},
|
||||
|
||||
// 获取池账户余额
|
||||
getPoolAccountBalance: async (walletName: string): Promise<PoolAccountBalance> => {
|
||||
const response = await tradingClient.get(`/admin/pool-accounts/${walletName}/balance`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// 区块链提现(从池账户)
|
||||
poolAccountBlockchainWithdraw: async (walletName: string, toAddress: string, amount: string): Promise<{
|
||||
success: boolean;
|
||||
message: string;
|
||||
txHash?: string;
|
||||
blockNumber?: number;
|
||||
newBalance?: string;
|
||||
error?: string;
|
||||
}> => {
|
||||
const response = await tradingClient.post(`/admin/pool-accounts/${walletName}/blockchain-withdraw`, { toAddress, amount });
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { configsApi } from '../api/configs.api';
|
||||
import { useToast } from '@/lib/hooks/use-toast';
|
||||
import { toast } from '@/lib/hooks/use-toast';
|
||||
|
||||
export function useConfigs() {
|
||||
return useQuery({
|
||||
|
|
@ -119,3 +120,34 @@ export function useSetP2pTransferFee() {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function usePoolAccountBalance(walletName: string) {
|
||||
return useQuery({
|
||||
queryKey: ['configs', 'pool-account', walletName],
|
||||
queryFn: () => configsApi.getPoolAccountBalance(walletName),
|
||||
refetchInterval: 30000,
|
||||
enabled: !!walletName,
|
||||
});
|
||||
}
|
||||
|
||||
export function usePoolAccountBlockchainWithdraw() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ walletName, toAddress, amount }: { walletName: string; toAddress: string; amount: string }) =>
|
||||
configsApi.poolAccountBlockchainWithdraw(walletName, toAddress, amount),
|
||||
onSuccess: (data) => {
|
||||
if (data.success) {
|
||||
toast({
|
||||
title: '区块链提现成功',
|
||||
description: `交易哈希: ${data.txHash?.slice(0, 20)}...`,
|
||||
});
|
||||
} else {
|
||||
toast({ title: '提现失败', description: data.error || data.message, variant: 'destructive' });
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: ['configs', 'pool-account'] });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
toast({ title: '错误', description: error.response?.data?.message || '区块链提现失败', variant: 'destructive' });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue