'use client'; import { useState } from 'react'; import { QRCodeSVG } from 'qrcode.react'; import { PageHeader } from '@/components/layout/page-header'; import { useMarketMakerConfig, useInitializeMarketMaker, useUpdateMarketMakerConfig, useDepositCash, useWithdrawCash, useDepositShares, useWithdrawShares, useBlockchainWithdrawCash, useBlockchainWithdrawShares, useStartTaker, useStopTaker, useTakeOrder, useStartMaker, useStopMaker, useRefreshOrders, useCancelAllOrders, useDepth, useDepthEnabled, useSetDepthEnabled, } from '@/features/market-maker'; 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 { Label } from '@/components/ui/label'; import { Skeleton } from '@/components/ui/skeleton'; import { Badge } from '@/components/ui/badge'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Switch } from '@/components/ui/switch'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog'; import { Play, Pause, AlertCircle, CheckCircle2, RefreshCw, Wallet, TrendingUp, TrendingDown, BarChart3, Zap, PlusCircle, MinusCircle, Copy, Check, } from 'lucide-react'; export default function MarketMakerPage() { const { data: configData, isLoading: configLoading, refetch } = useMarketMakerConfig(); const { data: depthData, isLoading: depthLoading } = useDepth(10); const { data: depthEnabled, isLoading: depthEnabledLoading } = useDepthEnabled(); const runningStatus = configData?.runningStatus; const initializeMutation = useInitializeMarketMaker(); const depositCashMutation = useDepositCash(); const withdrawCashMutation = useWithdrawCash(); const depositSharesMutation = useDepositShares(); const withdrawSharesMutation = useWithdrawShares(); const blockchainWithdrawCashMutation = useBlockchainWithdrawCash(); const blockchainWithdrawSharesMutation = useBlockchainWithdrawShares(); const startTakerMutation = useStartTaker(); const stopTakerMutation = useStopTaker(); const takeOrderMutation = useTakeOrder(); const startMakerMutation = useStartMaker(); const stopMakerMutation = useStopMaker(); const refreshOrdersMutation = useRefreshOrders(); const cancelAllOrdersMutation = useCancelAllOrders(); const setDepthEnabledMutation = useSetDepthEnabled(); const updateConfigMutation = useUpdateMarketMakerConfig(); const [initAccountSeq, setInitAccountSeq] = useState('MM001'); const [walletAddressInput, setWalletAddressInput] = useState(''); const [depositCashAmount, setDepositCashAmount] = useState(''); const [withdrawCashAmount, setWithdrawCashAmount] = useState(''); const [depositSharesAmount, setDepositSharesAmount] = useState(''); const [withdrawSharesAmount, setWithdrawSharesAmount] = useState(''); const [copiedAddress, setCopiedAddress] = useState(false); // 区块链提现 const [blockchainWithdrawCashAddress, setBlockchainWithdrawCashAddress] = useState(''); const [blockchainWithdrawCashAmount, setBlockchainWithdrawCashAmount] = useState(''); const [blockchainWithdrawSharesAddress, setBlockchainWithdrawSharesAddress] = useState(''); const [blockchainWithdrawSharesAmount, setBlockchainWithdrawSharesAmount] = useState(''); const handleCopyAddress = async (address: string) => { await navigator.clipboard.writeText(address); setCopiedAddress(true); setTimeout(() => setCopiedAddress(false), 2000); }; const config = configData?.config; const formatNumber = (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 }); }; return (
{/* 未初始化状态 */} {!configLoading && !config && ( 初始化做市商 做市商尚未初始化,请先创建做市商配置
setInitAccountSeq(e.target.value)} placeholder="做市商专用账户序列号" />
)} {configLoading && (
)} {config && ( <> {/* 资金状态卡片 */}
{/* 现金余额 */}
现金余额(积分值)

总余额

{formatNumber(config.cashBalance, 2)}

可用余额

{formatNumber(config.availableCash, 2)}

冻结中

{formatNumber(config.frozenCash, 2)}

充值现金(积分值) 选择充值方式向做市商账户充值 中心化充值 区块链充值
setDepositCashAmount(e.target.value)} placeholder="请输入金额" />
向以下地址转入 fUSDT (积分值代币)
{config.kavaWalletAddress ? (
{config.kavaWalletAddress}
转账后系统将自动检测并入账(约需12个区块确认)
) : (

做市商钱包地址未配置

setWalletAddressInput(e.target.value)} placeholder="0x..." className="mt-1" />
)}
提现现金(积分值) 选择提现方式从做市商账户提取 中心化提现 区块链提现
setWithdrawCashAmount(e.target.value)} placeholder="请输入金额" />
转账 fUSDT(积分值代币)到指定地址
setBlockchainWithdrawCashAddress(e.target.value)} placeholder="0x..." />
setBlockchainWithdrawCashAmount(e.target.value)} placeholder="请输入金额" />
区块链提现将从做市商钱包直接转账到目标地址
{/* 积分股余额 */}
积分股余额

总余额

{formatNumber(config.shareBalance, 2)}

可用余额

{formatNumber(config.availableShares, 2)}

冻结中

{formatNumber(config.frozenShares, 2)}

充值积分股 选择充值方式向做市商账户充值积分股 中心化充值 区块链充值
setDepositSharesAmount(e.target.value)} placeholder="请输入数量" />
向以下地址转入 eUSDT (积分股代币)
{config.kavaWalletAddress ? (
{config.kavaWalletAddress}
转账后系统将自动检测并入账(约需12个区块确认)
) : (

做市商钱包地址未配置

setWalletAddressInput(e.target.value)} placeholder="0x..." className="mt-1" />
)}
提取积分股 选择提现方式从做市商账户提取 中心化提取 区块链提现
setWithdrawSharesAmount(e.target.value)} placeholder="请输入数量" />
转账 eUSDT(积分股代币)到指定地址
setBlockchainWithdrawSharesAddress(e.target.value)} placeholder="0x..." />
setBlockchainWithdrawSharesAmount(e.target.value)} placeholder="请输入数量" />
区块链提现将从做市商钱包直接转账到目标地址
{/* 运行模式状态 */}
当前运行模式 {runningStatus?.mode === 'idle' && ( 空闲 )} {runningStatus?.mode === 'taker' && ( 吃单模式运行中 )} {runningStatus?.mode === 'maker' && ( 挂单模式运行中 )}
吃单模式: {runningStatus?.takerRunning ? '运行中' : '未运行'}
挂单模式: {runningStatus?.makerRunning ? '运行中' : '未运行'}
两种模式互斥,启动一个会自动停止另一个
{/* 运行模式控制 */} 吃单模式 挂单模式(深度) 深度显示 {/* 吃单模式 */}
吃单模式 自动买入用户卖单(Taker 策略)— 做市商作为买方,不触发额外销毁
{runningStatus?.takerRunning ? ( 运行中 ) : ( 已停止 )}

单次最大买入比例

{formatNumber(String(parseFloat(config.maxBuyRatio) * 100), 2)}%

最小间隔

{config.minIntervalMs}ms

最大间隔

{config.maxIntervalMs}ms

价格策略

{config.priceStrategy}

{runningStatus?.takerRunning ? ( ) : ( )}
{runningStatus?.makerRunning && (
启动吃单模式将自动停止当前运行的挂单模式
)}
{/* 挂单模式 */}
挂单模式(双边深度) 自动挂买卖单形成深度(Maker 策略)— 做市商卖单被吃会触发销毁
{runningStatus?.makerRunning ? ( 运行中 ) : ( 已停止 )}
{/* 警告提示 */}
注意:挂单模式下做市商会挂卖单,当卖单被用户买入时会触发销毁机制导致价格上涨。 如果只想提供流动性而不影响价格,请使用吃单模式。

买单档位

{config.bidLevels || 5}

买单价差

{formatNumber(String(parseFloat(config.bidSpread || '0.01') * 100), 2)}%

每档买单量

{formatNumber(config.bidQuantityPerLevel || '1000', 0)}

卖单档位

{config.askLevels || 5}

卖单价差

{formatNumber(String(parseFloat(config.askSpread || '0.01') * 100), 2)}%

每档卖单量

{formatNumber(config.askQuantityPerLevel || '1000', 0)}

{runningStatus?.makerRunning ? ( ) : ( )}
{runningStatus?.takerRunning && (
启动挂单模式将自动停止当前运行的吃单模式
)}
{/* 深度显示控制 */}
{/* 深度开关 */}
深度显示开关 控制App端是否显示买卖深度
{depthEnabledLoading ? ( ) : depthEnabled?.enabled ? ( 已开启 ) : ( 已关闭 )}

深度显示

{depthEnabled?.enabled ? '用户可以在App中查看买卖深度' : '深度功能已关闭,用户无法查看'}

setDepthEnabledMutation.mutate(checked)} disabled={setDepthEnabledMutation.isPending || depthEnabledLoading} />
{/* 当前深度 */} 当前深度 {depthLoading ? ( ) : (
{/* 买单深度 */}

买单深度

{depthData?.bids?.length ? ( 价格 数量 累计 {depthData.bids.map((bid, idx) => ( {formatNumber(bid.price, 8)} {formatNumber(bid.quantity, 2)} {formatNumber(bid.total, 2)} ))}
) : (

暂无买单

)}
{/* 卖单深度 */}

卖单深度

{depthData?.asks?.length ? ( 价格 数量 累计 {depthData.asks.map((ask, idx) => ( {formatNumber(ask.price, 8)} {formatNumber(ask.quantity, 2)} {formatNumber(ask.total, 2)} ))}
) : (

暂无卖单

)}
)}
)}
); }