diff --git a/backend/services/mining-admin-service/src/api/controllers/pool-account.controller.ts b/backend/services/mining-admin-service/src/api/controllers/pool-account.controller.ts index 02e58099..349582dd 100644 --- a/backend/services/mining-admin-service/src/api/controllers/pool-account.controller.ts +++ b/backend/services/mining-admin-service/src/api/controllers/pool-account.controller.ts @@ -53,6 +53,17 @@ export class PoolAccountController { ); } + @Get() + @ApiOperation({ summary: '获取已配置的池账户列表' }) + async listPoolAccounts() { + return Object.entries(this.walletNameMap).map(([walletName, info]) => ({ + walletName, + name: info.name, + walletPoolType: info.walletPoolType, + blockchainPoolType: info.blockchainPoolType, + })); + } + @Get(':walletName/balance') @ApiOperation({ summary: '获取池账户余额(代理到 wallet-service + blockchain-service)' }) @ApiParam({ name: 'walletName', description: '池钱包名称(MPC用户名)' }) diff --git a/frontend/mining-admin-web/src/app/(dashboard)/configs/page.tsx b/frontend/mining-admin-web/src/app/(dashboard)/configs/page.tsx index 29c7bc1c..94124dd3 100644 --- a/frontend/mining-admin-web/src/app/(dashboard)/configs/page.tsx +++ b/frontend/mining-admin-web/src/app/(dashboard)/configs/page.tsx @@ -3,7 +3,8 @@ 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, usePoolAccountBalance, usePoolAccountBlockchainWithdraw, usePoolAccountCentralizedDeposit } from '@/features/configs/hooks/use-configs'; +import { useConfigs, useUpdateConfig, useTransferEnabled, useSetTransferEnabled, useMiningStatus, useActivateMining, useDeactivateMining, useP2pTransferFee, useSetP2pTransferFee, usePoolAccounts, usePoolAccountBalance, usePoolAccountBlockchainWithdraw, usePoolAccountCentralizedDeposit } from '@/features/configs/hooks/use-configs'; +import type { PoolAccountInfo, PoolAccountBalance } from '@/features/configs/api/configs.api'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; @@ -25,9 +26,11 @@ import { Badge } from '@/components/ui/badge'; 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'; -// 池账户钱包名(与后端 .env 中的 BURN_POOL_WALLET_USERNAME / MINING_POOL_WALLET_USERNAME 对应) -const BURN_POOL_WALLET_NAME = 'wallet-22fd661f'; -const MINING_POOL_WALLET_NAME = 'wallet-974e78f5'; +// 根据 blockchainPoolType 映射视觉属性 +const poolVisualMap: Record = { + BURN_POOL: { icon: Flame, color: 'orange' }, + MINING_POOL: { icon: HardHat, color: 'blue' }, +}; const categoryLabels: Record = { mining: '挖矿配置', @@ -36,43 +39,20 @@ const categoryLabels: Record = { system: '系统配置', }; -export default function ConfigsPage() { - const { data: configs, isLoading } = useConfigs(); - const { data: transferEnabled, isLoading: transferLoading } = useTransferEnabled(); - const { data: miningStatus, isLoading: miningLoading } = useMiningStatus(); - const updateConfig = useUpdateConfig(); - const setTransferEnabled = useSetTransferEnabled(); - const activateMining = useActivateMining(); - const deactivateMining = useDeactivateMining(); - - 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); +// 池账户卡片子组件 +function PoolAccountCard({ pool }: { pool: PoolAccountInfo }) { + const { data: balance, isLoading } = usePoolAccountBalance(pool.walletName); const blockchainWithdrawMutation = usePoolAccountBlockchainWithdraw(); const centralizedDepositMutation = usePoolAccountCentralizedDeposit(); - const [editingConfig, setEditingConfig] = useState(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 [burnDepositAmount, setBurnDepositAmount] = useState(''); - const [miningDepositAmount, setMiningDepositAmount] = useState(''); + const [withdrawAddress, setWithdrawAddress] = useState(''); + const [withdrawAmount, setWithdrawAmount] = useState(''); + const [depositAmount, setDepositAmount] = useState(''); const [copiedAddress, setCopiedAddress] = useState(null); - useEffect(() => { - if (feeConfig) { - setFeeValue(feeConfig.fee); - setMinAmountValue(feeConfig.minTransferAmount); - } - }, [feeConfig]); + const visual = poolVisualMap[pool.blockchainPoolType] || { icon: Wallet, color: 'gray' }; + const Icon = visual.icon; + const colorClass = visual.color === 'orange' ? 'text-orange-500' : visual.color === 'blue' ? 'text-blue-500' : 'text-gray-500'; const handleCopyAddress = async (address: string) => { await navigator.clipboard.writeText(address); @@ -87,6 +67,217 @@ export default function ConfigsPage() { return num.toLocaleString(undefined, { minimumFractionDigits: decimals, maximumFractionDigits: decimals }); }; + return ( + + +
+ + + {pool.name} + + + 2-of-3 门限 + +
+ + 钱包: {pool.walletName} + +
+ +
+ {isLoading ? ( + + ) : ( +
+
+

总余额

+

{formatBalance(balance?.balance)}

+
+
+

可用余额

+

{formatBalance(balance?.availableBalance)}

+
+
+

冻结中

+

{formatBalance(balance?.frozenBalance)}

+
+
+ )} + +
+ {/* 充值(中心化 + 区块链) */} + + + + + + + 充值 — {pool.name} + 选择充值方式向{pool.name}充值 + + + + 中心化充值 + 区块链充值 + + +
+ + setDepositAmount(e.target.value)} + placeholder="请输入金额" + /> +
+ +
+ +
+ 向以下地址转入 fUSDT(积分值代币) +
+ {balance?.walletAddress ? ( +
+
+ +
+
+ +
+ + {balance.walletAddress} + + +
+
+
+ + 转账后系统将自动检测并入账(约需12个区块确认) +
+
+ ) : ( +
+ +

钱包地址未配置

+
+ )} +
+
+
+
+ + {/* 区块链提现 */} + + + + + + + 区块链提现 — {pool.name} + 转账 fUSDT(积分值代币)到指定地址 + +
+
+ + setWithdrawAddress(e.target.value)} + placeholder="0x..." + /> +
+
+ + setWithdrawAmount(e.target.value)} + placeholder="请输入金额" + /> +
+ +
+ + 区块链提现将通过 2-of-3 门限签名从{pool.name}钱包转账到目标地址 +
+
+
+
+
+
+
+
+ ); +} + +export default function ConfigsPage() { + const { data: configs, isLoading } = useConfigs(); + const { data: transferEnabled, isLoading: transferLoading } = useTransferEnabled(); + const { data: miningStatus, isLoading: miningLoading } = useMiningStatus(); + const updateConfig = useUpdateConfig(); + const setTransferEnabled = useSetTransferEnabled(); + const activateMining = useActivateMining(); + const deactivateMining = useDeactivateMining(); + + const { data: feeConfig, isLoading: feeLoading } = useP2pTransferFee(); + const setP2pTransferFee = useSetP2pTransferFee(); + + const { data: poolAccounts, isLoading: poolAccountsLoading } = usePoolAccounts(); + + const [editingConfig, setEditingConfig] = useState(null); + const [editValue, setEditValue] = useState(''); + const [feeValue, setFeeValue] = useState(''); + const [minAmountValue, setMinAmountValue] = useState(''); + + useEffect(() => { + if (feeConfig) { + setFeeValue(feeConfig.fee); + setMinAmountValue(feeConfig.minTransferAmount); + } + }, [feeConfig]); + const handleEdit = (config: SystemConfig) => { setEditingConfig(config); setEditValue(config.configValue); @@ -235,374 +426,19 @@ export default function ConfigsPage() { - {/* 池账户管理 */} -
- {/* 100亿销毁池 */} - - -
- - - 100亿销毁池 - - - 2-of-3 门限 - -
- - 钱包: {BURN_POOL_WALLET_NAME} - -
- -
- {burnPoolLoading ? ( - - ) : ( -
-
-

总余额

-

{formatBalance(burnPoolBalance?.balance)}

-
-
-

可用余额

-

{formatBalance(burnPoolBalance?.availableBalance)}

-
-
-

冻结中

-

{formatBalance(burnPoolBalance?.frozenBalance)}

-
-
- )} - -
- {/* 充值(中心化 + 区块链) */} - - - - - - - 充值 — 100亿销毁池 - 选择充值方式向销毁池充值 - - - - 中心化充值 - 区块链充值 - - -
- - setBurnDepositAmount(e.target.value)} - placeholder="请输入金额" - /> -
- -
- -
- 向以下地址转入 fUSDT(积分值代币) -
- {burnPoolBalance?.walletAddress ? ( -
-
- -
-
- -
- - {burnPoolBalance.walletAddress} - - -
-
-
- - 转账后系统将自动检测并入账(约需12个区块确认) -
-
- ) : ( -
- -

钱包地址未配置

-
- )} -
-
-
-
- - {/* 区块链提现 */} - - - - - - - 区块链提现 — 100亿销毁池 - 转账 fUSDT(积分值代币)到指定地址 - -
-
- - setBurnWithdrawAddress(e.target.value)} - placeholder="0x..." - /> -
-
- - setBurnWithdrawAmount(e.target.value)} - placeholder="请输入金额" - /> -
- -
- - 区块链提现将通过 2-of-3 门限签名从销毁池钱包转账到目标地址 -
-
-
-
-
-
-
-
- - {/* 200万挖矿池 */} - - -
- - - 200万挖矿池 - - - 2-of-3 门限 - -
- - 钱包: {MINING_POOL_WALLET_NAME} - -
- -
- {miningPoolLoading ? ( - - ) : ( -
-
-

总余额

-

{formatBalance(miningPoolBalance?.balance)}

-
-
-

可用余额

-

{formatBalance(miningPoolBalance?.availableBalance)}

-
-
-

冻结中

-

{formatBalance(miningPoolBalance?.frozenBalance)}

-
-
- )} - -
- {/* 充值(中心化 + 区块链) */} - - - - - - - 充值 — 200万挖矿池 - 选择充值方式向挖矿池充值 - - - - 中心化充值 - 区块链充值 - - -
- - setMiningDepositAmount(e.target.value)} - placeholder="请输入金额" - /> -
- -
- -
- 向以下地址转入 fUSDT(积分值代币) -
- {miningPoolBalance?.walletAddress ? ( -
-
- -
-
- -
- - {miningPoolBalance.walletAddress} - - -
-
-
- - 转账后系统将自动检测并入账(约需12个区块确认) -
-
- ) : ( -
- -

钱包地址未配置

-
- )} -
-
-
-
- - {/* 区块链提现 */} - - - - - - - 区块链提现 — 200万挖矿池 - 转账 fUSDT(积分值代币)到指定地址 - -
-
- - setMiningWithdrawAddress(e.target.value)} - placeholder="0x..." - /> -
-
- - setMiningWithdrawAmount(e.target.value)} - placeholder="请输入金额" - /> -
- -
- - 区块链提现将通过 2-of-3 门限签名从挖矿池钱包转账到目标地址 -
-
-
-
-
-
-
-
-
+ {/* 池账户管理 — 动态渲染 */} + {poolAccountsLoading ? ( +
+ + +
+ ) : poolAccounts && poolAccounts.length > 0 ? ( +
+ {poolAccounts.map((pool) => ( + + ))} +
+ ) : null} diff --git a/frontend/mining-admin-web/src/features/configs/api/configs.api.ts b/frontend/mining-admin-web/src/features/configs/api/configs.api.ts index 5aa36202..c0655701 100644 --- a/frontend/mining-admin-web/src/features/configs/api/configs.api.ts +++ b/frontend/mining-admin-web/src/features/configs/api/configs.api.ts @@ -7,6 +7,13 @@ export interface ContributionSyncStatus { networkTotalContribution: string; } +export interface PoolAccountInfo { + walletName: string; + name: string; + walletPoolType: string; + blockchainPoolType: string; +} + export interface PoolAccountBalance { walletName: string; walletAddress: string; @@ -74,6 +81,12 @@ export const configsApi = { await apiClient.post('/configs/p2p-transfer-fee', { fee, minTransferAmount }); }, + // 获取已配置的池账户列表 + getPoolAccounts: async (): Promise => { + const response = await apiClient.get('/admin/pool-accounts'); + return response.data.data; + }, + // 获取池账户余额(通过 mining-admin-service 代理) getPoolAccountBalance: async (walletName: string): Promise => { const response = await apiClient.get(`/admin/pool-accounts/${walletName}/balance`); diff --git a/frontend/mining-admin-web/src/features/configs/hooks/use-configs.ts b/frontend/mining-admin-web/src/features/configs/hooks/use-configs.ts index af9d8d9f..120a8cb4 100644 --- a/frontend/mining-admin-web/src/features/configs/hooks/use-configs.ts +++ b/frontend/mining-admin-web/src/features/configs/hooks/use-configs.ts @@ -121,6 +121,13 @@ export function useSetP2pTransferFee() { }); } +export function usePoolAccounts() { + return useQuery({ + queryKey: ['configs', 'pool-accounts'], + queryFn: () => configsApi.getPoolAccounts(), + }); +} + export function usePoolAccountBalance(walletName: string) { return useQuery({ queryKey: ['configs', 'pool-account', walletName],