/** * 交易模态框组件 * 用于买入/卖出预测市场席位 */ import React, { useState, useEffect } from 'react'; import { Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, ModalCloseButton, Button, VStack, HStack, Text, Box, Icon, Slider, SliderTrack, SliderFilledTrack, SliderThumb, RadioGroup, Radio, Stack, Flex, useToast, Badge, } from '@chakra-ui/react'; import { TrendingUp, TrendingDown, Coins, AlertCircle, Zap } from 'lucide-react'; import { motion } from 'framer-motion'; import { forumColors } from '@theme/forumTheme'; import { buyShares, getUserAccount, calculateBuyCost, calculateTax, MARKET_CONFIG, } from '@services/predictionMarketService.api'; import { CREDIT_CONFIG } from '@services/creditSystemService'; import { useAuth } from '@contexts/AuthContext'; const MotionBox = motion(Box); const TradeModal = ({ isOpen, onClose, topic, mode = 'buy', onTradeSuccess }) => { const toast = useToast(); const { user } = useAuth(); // 状态 const [selectedOption, setSelectedOption] = useState('yes'); const [shares, setShares] = useState(1); const [isSubmitting, setIsSubmitting] = useState(false); const [userAccount, setUserAccount] = useState(null); // 异步获取用户账户 useEffect(() => { const fetchAccount = async () => { if (!user || !isOpen) return; try { const response = await getUserAccount(); if (response.success) { setUserAccount(response.data); } } catch (error) { console.error('获取账户失败:', error); } }; fetchAccount(); }, [user, isOpen]); // 重置状态 useEffect(() => { if (isOpen) { setSelectedOption('yes'); setShares(1); } }, [isOpen]); if (!topic || !userAccount) return null; // 构建市场数据(兼容后端字段) const positions = { yes: { total_shares: topic.yes_total_shares || 0, current_price: topic.yes_price || 500, }, no: { total_shares: topic.no_total_shares || 0, current_price: topic.no_price || 500, }, }; // 获取市场数据 const selectedSide = positions[selectedOption]; const otherOption = selectedOption === 'yes' ? 'no' : 'yes'; const otherSide = positions[otherOption]; // 计算交易数据 let cost = 0; let tax = 0; let totalCost = 0; let avgPrice = 0; if (mode === 'buy') { const costData = calculateBuyCost( selectedOption === 'yes' ? selectedSide.total_shares : otherSide.total_shares, selectedOption === 'yes' ? otherSide.total_shares : selectedSide.total_shares, shares ); cost = costData.amount; tax = costData.tax; totalCost = costData.total; avgPrice = costData.avgPrice; } else { // 卖出功能暂未实现,使用简化计算 const currentPrice = selectedSide.current_price || MARKET_CONFIG.BASE_PRICE; cost = currentPrice * shares; tax = calculateTax(cost); totalCost = cost - tax; avgPrice = currentPrice; } // 获取用户在该方向的持仓 const userPosition = userAccount.active_positions?.find( (p) => p.topic_id === topic.id && p.option_id === selectedOption ); const maxShares = mode === 'buy' ? 10 : userPosition?.shares || 0; // 检查是否可以交易 const canTrade = () => { if (mode === 'buy') { // 检查余额 if (userAccount.balance < totalCost) { return { ok: false, reason: '积分不足' }; } // 检查单次上限 if (totalCost > CREDIT_CONFIG.MAX_SINGLE_BET) { return { ok: false, reason: `单次购买上限${CREDIT_CONFIG.MAX_SINGLE_BET}积分` }; } return { ok: true }; } else { // 检查持仓 if (!userPosition || userPosition.shares < shares) { return { ok: false, reason: '持仓不足' }; } return { ok: true }; } }; const tradeCheck = canTrade(); // 处理交易 const handleTrade = async () => { try { setIsSubmitting(true); if (mode === 'buy') { // 调用买入 API const response = await buyShares({ topic_id: topic.id, direction: selectedOption, shares, }); if (response.success) { toast({ title: '购买成功!', description: `花费${totalCost}积分,剩余 ${response.data.new_balance} 积分`, status: 'success', duration: 3000, }); // 刷新账户数据 const accountResponse = await getUserAccount(); if (accountResponse.success) { setUserAccount(accountResponse.data); } // 通知父组件刷新 if (onTradeSuccess) { onTradeSuccess(response.data); } onClose(); } } else { // 卖出功能暂未实现 toast({ title: '功能暂未开放', description: '卖出功能正在开发中,敬请期待', status: 'warning', duration: 3000, }); } } catch (error) { console.error('交易失败:', error); toast({ title: '交易失败', description: error.response?.data?.message || error.message, status: 'error', duration: 3000, }); } finally { setIsSubmitting(false); } }; return ( {mode === 'buy' ? '购买席位' : '卖出席位'} {/* 话题标题 */} {topic.title} {/* 选择方向 */} 选择方向 {/* Yes 选项 */} setSelectedOption('yes')} minH={{ base: "auto", sm: "auto" }} > 看涨 / Yes {positions.yes.total_shares}份持仓 {Math.round(positions.yes.current_price)} 积分/份 {/* No 选项 */} setSelectedOption('no')} minH={{ base: "auto", sm: "auto" }} > 看跌 / No {positions.no.total_shares}份持仓 {Math.round(positions.no.current_price)} 积分/份 {/* 购买份额 */} {mode === 'buy' ? '购买份额' : '卖出份额'} {shares} 份 1份 {maxShares}份 (最大) {mode === 'sell' && userPosition && ( 你的持仓:{userPosition.shares}份 · 平均成本:{Math.round(userPosition.avg_cost)}积分/份 )} {/* 费用明细 */} {mode === 'buy' ? '购买成本' : '卖出收益'} {Math.round(cost)} 积分 平均价格 {Math.round(avgPrice)} 积分/份 交易税 (2%) {Math.round(tax)} 积分 {mode === 'buy' ? '总计' : '净收益'} {Math.round(totalCost)} 积分 {/* 余额提示 */} 你的余额: {userAccount.balance} 积分 {mode === 'buy' ? '交易后:' : '交易后:'} = totalCost ? forumColors.success[500] : forumColors.error[500] : forumColors.success[500] } > {mode === 'buy' ? userAccount.balance - totalCost : userAccount.balance + totalCost}{' '} 积分 {/* 警告提示 */} {!tradeCheck.ok && ( {tradeCheck.reason} )} ); }; export default TradeModal;