update pay function

This commit is contained in:
2025-11-23 19:44:49 +08:00
parent 2fb12e0cc7
commit 3fa3e52d65
4 changed files with 2633 additions and 1 deletions

View File

@@ -0,0 +1,713 @@
/**
* 预测市场玩法说明模态框
* 帮助用户理解游戏规则和操作流程
*/
import React, { useState } from 'react';
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalFooter,
ModalCloseButton,
Button,
VStack,
HStack,
Text,
Box,
Icon,
Badge,
Tabs,
TabList,
TabPanels,
Tab,
TabPanel,
Divider,
List,
ListItem,
ListIcon,
Accordion,
AccordionItem,
AccordionButton,
AccordionPanel,
AccordionIcon,
Image,
SimpleGrid,
Flex,
useColorModeValue,
} from '@chakra-ui/react';
import {
Zap,
TrendingUp,
TrendingDown,
Crown,
DollarSign,
Users,
Clock,
Trophy,
CheckCircle2,
AlertCircle,
ArrowRight,
Target,
Wallet,
RefreshCw,
Gift,
} from 'lucide-react';
import { motion } from 'framer-motion';
import { forumColors } from '@theme/forumTheme';
const MotionBox = motion(Box);
const PredictionGuideModal = ({ isOpen, onClose }) => {
const [activeTab, setActiveTab] = useState(0);
// 特性列表
const features = [
{
icon: Zap,
title: '预测市场',
desc: '对未来事件进行预测,购买看涨/看跌席位',
color: 'yellow.400',
},
{
icon: DollarSign,
title: '虚拟积分',
desc: '使用论坛积分参与初始10,000积分',
color: 'green.400',
},
{
icon: Crown,
title: '领主系统',
desc: '持有最多份额者成为领主,拥有特权',
color: 'orange.400',
},
{
icon: Trophy,
title: '赢取奖池',
desc: '预测正确者分享奖池,最高收益无上限',
color: 'purple.400',
},
];
// 操作步骤
const steps = [
{
step: 1,
title: '发起预测话题',
desc: '创建一个可预测的话题,设置截止时间',
icon: Zap,
details: [
'点击"发起预测"按钮',
'填写话题标题和描述',
'选择分类和截止时间',
'支付100积分创建费用进入奖池',
],
},
{
step: 2,
title: '购买席位表达观点',
desc: '选择看涨或看跌方向,购买席位',
icon: TrendingUp,
details: [
'浏览预测话题,选择感兴趣的',
'点击"购买席位"',
'选择方向:看涨(Yes) 或 看跌(No)',
'调整购买份额1-10份',
'支付积分含2%交易税)',
],
},
{
step: 3,
title: '成为领主获得特权',
desc: '持有最多份额自动成为领主',
icon: Crown,
details: [
'持有某方向最多份额即成为领主',
'领主评论自动置顶(计划中)',
'专属👑领主徽章显示',
'领主身份随交易实时变更',
],
},
{
step: 4,
title: '等待结果揭晓',
desc: '话题到期后,作者提交结果',
icon: Clock,
details: [
'话题到达截止时间,停止交易',
'作者提交结果和证据',
'系统自动计算奖池分配',
'获胜方按份额比例分享奖池',
],
},
];
// 常见问题
const faqs = [
{
q: '💰 初始积分是多少?会破产吗?',
a: '每个用户初始获得10,000积分。系统有破产保护机制最低保留100积分不会完全归零。每日签到可获得100积分奖励。',
},
{
q: '📊 价格是如何变动的?',
a: '价格根据供需关系动态调整。购买某方向会导致该方向价格上涨对方价格下跌。采用简化版AMM自动做市商算法。',
},
{
q: '👑 领主有什么特权?',
a: '领主是持有某方向最多份额的用户。特权包括:评论自动置顶(计划中)、专属徽章显示、更高的话语权。领主身份随交易实时变更。',
},
{
q: '🎯 如何计算收益?',
a: '获胜方按持有份额比例分享奖池。例如奖池1000积分你持有获胜方30%份额则获得300积分 + 返还本金。',
},
{
q: '💸 交易税去哪了?',
a: '每笔交易收取2%交易税,全部进入话题奖池。这确保了即使无人参与对立面,奖池也有资金可分配。',
},
{
q: '🔄 可以卖出席位吗?',
a: '可以!在话题截止前,随时可以卖出席位。卖出价格同样根据市场供需动态计算,可能高于或低于买入价。',
},
{
q: '⚖️ 如何确保公平?',
a: '作者不能参与自己发起的话题。结果需要提交证据。未来将引入社区投票仲裁机制处理争议。',
},
{
q: '📈 单次最多能买多少?',
a: '单次购买上限1000积分避免大户操纵市场。每个方向最多5个席位持有者确保市场活跃度。',
},
];
// 示例场景
const exampleScenario = {
title: '📖 完整示例:贵州茅台预测',
steps: [
{
title: '1. 创建话题',
content: '小明创建话题:"贵州茅台下周会涨吗?"支付100积分。奖池100积分。',
},
{
title: '2. 用户参与',
content: [
'小红购买3份"看涨"花费1,530积分含税',
'小李购买2份"看跌"花费1,020积分含税',
'交易税进入奖池51积分',
'当前奖池151积分',
],
},
{
title: '3. 价格变动',
content: '看涨份额增加 → 看涨价格上涨至680积分/份看跌价格下跌至320积分/份',
},
{
title: '4. 领主诞生',
content: '小红持有看涨方最多份额,成为看涨方👑领主',
},
{
title: '5. 结果揭晓',
content: [
'一周后茅台上涨5%,小明提交结果:"看涨"获胜',
'小红获得本金1500积分 + 奖池151积分 = 1651积分',
'小红净收益1651 - 1530 = +121积分 (收益率7.9%)',
'小李损失本金1000积分',
],
},
],
};
return (
<Modal isOpen={isOpen} onClose={onClose} size="6xl" isCentered scrollBehavior="inside">
<ModalOverlay backdropFilter="blur(4px)" bg="blackAlpha.800" />
<ModalContent
bg={forumColors.background.card}
borderRadius="2xl"
border="2px solid"
borderColor={forumColors.border.gold}
maxH="90vh"
>
<ModalHeader
bg={forumColors.gradients.goldPrimary}
borderTopRadius="2xl"
py="6"
>
<HStack spacing="3">
<Icon as={Zap} boxSize="28px" color={forumColors.background.main} />
<VStack align="start" spacing="0">
<Text fontSize="2xl" fontWeight="bold" color={forumColors.background.main}>
预测市场玩法说明
</Text>
<Text fontSize="sm" color={forumColors.background.main} opacity={0.9}>
5分钟快速上手开启预测之旅
</Text>
</VStack>
</HStack>
</ModalHeader>
<ModalCloseButton color={forumColors.background.main} top="6" right="6" />
<ModalBody py="6">
<Tabs
index={activeTab}
onChange={setActiveTab}
variant="soft-rounded"
colorScheme="yellow"
>
<TabList mb="6" flexWrap="wrap">
<Tab
_selected={{
bg: forumColors.gradients.goldPrimary,
color: forumColors.background.main,
}}
>
<Icon as={Target} boxSize="16px" mr="2" />
核心玩法
</Tab>
<Tab
_selected={{
bg: forumColors.gradients.goldPrimary,
color: forumColors.background.main,
}}
>
<Icon as={CheckCircle2} boxSize="16px" mr="2" />
操作步骤
</Tab>
<Tab
_selected={{
bg: forumColors.gradients.goldPrimary,
color: forumColors.background.main,
}}
>
<Icon as={AlertCircle} boxSize="16px" mr="2" />
常见问题
</Tab>
<Tab
_selected={{
bg: forumColors.gradients.goldPrimary,
color: forumColors.background.main,
}}
>
<Icon as={Trophy} boxSize="16px" mr="2" />
示例演示
</Tab>
</TabList>
<TabPanels>
{/* 核心玩法 */}
<TabPanel p="0">
<VStack spacing="6" align="stretch">
{/* 核心特性 */}
<SimpleGrid columns={{ base: 1, md: 2 }} spacing="4">
{features.map((feature, index) => (
<MotionBox
key={index}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1 }}
bg={forumColors.background.hover}
p="5"
borderRadius="xl"
border="1px solid"
borderColor={forumColors.border.default}
_hover={{
borderColor: forumColors.border.gold,
transform: 'translateY(-4px)',
boxShadow: forumColors.shadows.gold,
}}
>
<HStack spacing="4" align="start">
<Box
bg={forumColors.gradients.goldSubtle}
p="3"
borderRadius="lg"
>
<Icon as={feature.icon} boxSize="24px" color={feature.color} />
</Box>
<VStack align="start" spacing="1" flex="1">
<Text fontWeight="700" fontSize="lg" color={forumColors.text.primary}>
{feature.title}
</Text>
<Text fontSize="sm" color={forumColors.text.secondary}>
{feature.desc}
</Text>
</VStack>
</HStack>
</MotionBox>
))}
</SimpleGrid>
<Divider borderColor={forumColors.border.default} />
{/* 游戏规则 */}
<Box>
<Text fontSize="xl" fontWeight="700" color={forumColors.text.primary} mb="4">
📜 游戏规则
</Text>
<VStack spacing="3" align="stretch">
<Box
bg={forumColors.gradients.goldSubtle}
p="4"
borderRadius="lg"
border="1px solid"
borderColor={forumColors.border.gold}
>
<HStack spacing="2" mb="2">
<Icon as={Wallet} boxSize="18px" color={forumColors.primary[500]} />
<Text fontWeight="600" color={forumColors.text.primary}>
积分系统
</Text>
</HStack>
<List spacing="2" fontSize="sm" color={forumColors.text.secondary}>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
初始积分10,000积分免费领取
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
最低保留100积分破产保护
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
单次上限1,000积分防止操纵
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
每日签到+100积分每天领取
</ListItem>
</List>
</Box>
<Box
bg={forumColors.background.hover}
p="4"
borderRadius="lg"
border="1px solid"
borderColor={forumColors.border.default}
>
<HStack spacing="2" mb="2">
<Icon as={TrendingUp} boxSize="18px" color="green.400" />
<Text fontWeight="600" color={forumColors.text.primary}>
双向市场
</Text>
</HStack>
<List spacing="2" fontSize="sm" color={forumColors.text.secondary}>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
看涨 (Yes)预测会上涨/发生
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
看跌 (No)预测会下跌/不发生
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
价格动态变化根据供需关系调整
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
可以随时买入和卖出截止前
</ListItem>
</List>
</Box>
<Box
bg={forumColors.background.hover}
p="4"
borderRadius="lg"
border="1px solid"
borderColor={forumColors.border.default}
>
<HStack spacing="2" mb="2">
<Icon as={Crown} boxSize="18px" color="yellow.400" />
<Text fontWeight="600" color={forumColors.text.primary}>
领主系统
</Text>
</HStack>
<List spacing="2" fontSize="sm" color={forumColors.text.secondary}>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
持有最多份额者自动成为领主
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
领主评论自动置顶计划中
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
专属👑徽章和金色边框
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
领主身份随交易实时变更
</ListItem>
</List>
</Box>
<Box
bg={forumColors.background.hover}
p="4"
borderRadius="lg"
border="1px solid"
borderColor={forumColors.border.default}
>
<HStack spacing="2" mb="2">
<Icon as={Trophy} boxSize="18px" color="purple.400" />
<Text fontWeight="600" color={forumColors.text.primary}>
奖池分配
</Text>
</HStack>
<List spacing="2" fontSize="sm" color={forumColors.text.secondary}>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
交易税每笔交易2%进入奖池
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
获胜方按份额比例分享奖池
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
返还本金 + 奖池分成
</ListItem>
<ListItem>
<ListIcon as={CheckCircle2} color="green.400" />
失败方损失本金
</ListItem>
</List>
</Box>
</VStack>
</Box>
</VStack>
</TabPanel>
{/* 操作步骤 */}
<TabPanel p="0">
<VStack spacing="6" align="stretch">
{steps.map((step, index) => (
<MotionBox
key={index}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.1 }}
bg={forumColors.background.hover}
p="6"
borderRadius="xl"
border="2px solid"
borderColor={forumColors.border.default}
position="relative"
overflow="hidden"
_hover={{
borderColor: forumColors.border.gold,
boxShadow: forumColors.shadows.gold,
}}
>
{/* 步骤编号 */}
<Box
position="absolute"
top="-10px"
right="-10px"
fontSize="120px"
fontWeight="900"
color={forumColors.border.default}
opacity={0.1}
lineHeight="1"
>
{step.step}
</Box>
<HStack spacing="4" align="start" mb="4" position="relative" zIndex={1}>
<Box
bg={forumColors.gradients.goldPrimary}
p="3"
borderRadius="lg"
>
<Icon as={step.icon} boxSize="24px" color={forumColors.background.main} />
</Box>
<VStack align="start" spacing="1" flex="1">
<HStack>
<Badge
bg={forumColors.primary[500]}
color={forumColors.background.main}
px="3"
py="1"
borderRadius="full"
fontSize="xs"
>
步骤 {step.step}
</Badge>
</HStack>
<Text fontSize="xl" fontWeight="700" color={forumColors.text.primary}>
{step.title}
</Text>
<Text fontSize="sm" color={forumColors.text.secondary}>
{step.desc}
</Text>
</VStack>
</HStack>
<Divider borderColor={forumColors.border.default} mb="4" />
<List spacing="2" pl="4">
{step.details.map((detail, i) => (
<ListItem
key={i}
fontSize="sm"
color={forumColors.text.secondary}
>
<HStack spacing="2">
<Icon as={ArrowRight} boxSize="14px" color={forumColors.primary[500]} />
<Text>{detail}</Text>
</HStack>
</ListItem>
))}
</List>
</MotionBox>
))}
</VStack>
</TabPanel>
{/* 常见问题 */}
<TabPanel p="0">
<Accordion allowMultiple>
{faqs.map((faq, index) => (
<AccordionItem
key={index}
border="1px solid"
borderColor={forumColors.border.default}
borderRadius="lg"
mb="3"
bg={forumColors.background.hover}
>
<AccordionButton
py="4"
_hover={{ bg: forumColors.background.card }}
borderRadius="lg"
>
<Box flex="1" textAlign="left">
<Text fontWeight="600" color={forumColors.text.primary}>
{faq.q}
</Text>
</Box>
<AccordionIcon color={forumColors.primary[500]} />
</AccordionButton>
<AccordionPanel pb="4">
<Text fontSize="sm" color={forumColors.text.secondary} lineHeight="1.8">
{faq.a}
</Text>
</AccordionPanel>
</AccordionItem>
))}
</Accordion>
</TabPanel>
{/* 示例演示 */}
<TabPanel p="0">
<VStack spacing="6" align="stretch">
<Box
bg={forumColors.gradients.goldSubtle}
p="6"
borderRadius="xl"
border="2px solid"
borderColor={forumColors.border.gold}
>
<Text fontSize="2xl" fontWeight="700" color={forumColors.text.primary} mb="2">
{exampleScenario.title}
</Text>
<Text fontSize="sm" color={forumColors.text.secondary}>
通过完整案例理解预测市场的运作流程
</Text>
</Box>
{exampleScenario.steps.map((item, index) => (
<Box
key={index}
bg={forumColors.background.hover}
p="5"
borderRadius="lg"
border="1px solid"
borderColor={forumColors.border.default}
>
<Text fontWeight="700" color={forumColors.primary[500]} mb="3">
{item.title}
</Text>
{Array.isArray(item.content) ? (
<VStack spacing="2" align="stretch">
{item.content.map((line, i) => (
<HStack key={i} spacing="2">
<Icon as={ArrowRight} boxSize="14px" color={forumColors.primary[500]} />
<Text fontSize="sm" color={forumColors.text.secondary}>
{line}
</Text>
</HStack>
))}
</VStack>
) : (
<Text fontSize="sm" color={forumColors.text.secondary}>
{item.content}
</Text>
)}
</Box>
))}
{/* 关键提示 */}
<Box
bg="green.50"
border="2px solid"
borderColor="green.400"
p="5"
borderRadius="lg"
>
<HStack spacing="3" mb="3">
<Icon as={Gift} boxSize="24px" color="green.600" />
<Text fontWeight="700" color="green.700" fontSize="lg">
💡 关键提示
</Text>
</HStack>
<VStack spacing="2" align="stretch">
<Text fontSize="sm" color="green.700">
早期参与价格低后期参与价格高
</Text>
<Text fontSize="sm" color="green.700">
可以通过"低买高卖"赚取差价Flipper玩法
</Text>
<Text fontSize="sm" color="green.700">
即使预测失败也可能通过卖出获利
</Text>
<Text fontSize="sm" color="green.700">
成为领主可获得社区影响力
</Text>
</VStack>
</Box>
</VStack>
</TabPanel>
</TabPanels>
</Tabs>
</ModalBody>
<ModalFooter
borderTop="1px solid"
borderColor={forumColors.border.default}
py="4"
>
<HStack spacing="3" w="full" justify="space-between">
<Text fontSize="xs" color={forumColors.text.tertiary}>
💡 提示每日签到可获得100积分
</Text>
<Button
bg={forumColors.gradients.goldPrimary}
color={forumColors.background.main}
fontWeight="bold"
onClick={onClose}
_hover={{ opacity: 0.9 }}
>
开始预测
</Button>
</HStack>
</ModalFooter>
</ModalContent>
</Modal>
);
};
export default PredictionGuideModal;

View File

@@ -29,7 +29,7 @@ import {
TabPanel,
Icon,
} from '@chakra-ui/react';
import { Search, PenSquare, TrendingUp, Clock, Heart, Zap } from 'lucide-react';
import { Search, PenSquare, TrendingUp, Clock, Heart, Zap, HelpCircle } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { forumColors } from '@theme/forumTheme';
import { getPosts, searchPosts } from '@services/elasticsearchService';
@@ -38,6 +38,7 @@ import PostCard from './components/PostCard';
import PredictionTopicCard from './components/PredictionTopicCard';
import CreatePostModal from './components/CreatePostModal';
import CreatePredictionModal from './components/CreatePredictionModal';
import PredictionGuideModal from './components/PredictionGuideModal';
const MotionBox = motion(Box);
@@ -54,6 +55,7 @@ const ValueForum = () => {
const { isOpen: isPostModalOpen, onOpen: onPostModalOpen, onClose: onPostModalClose } = useDisclosure();
const { isOpen: isPredictionModalOpen, onOpen: onPredictionModalOpen, onClose: onPredictionModalClose } = useDisclosure();
const { isOpen: isGuideModalOpen, onOpen: onGuideModalOpen, onClose: onGuideModalClose } = useDisclosure();
// 获取帖子列表
const fetchPosts = async (currentPage = 1, reset = false) => {
@@ -178,6 +180,24 @@ const ValueForum = () => {
{/* 发帖按钮 */}
<HStack spacing="3">
<Button
leftIcon={<HelpCircle size={18} />}
variant="outline"
color={forumColors.primary[500]}
borderColor={forumColors.primary[500]}
size="lg"
fontWeight="bold"
onClick={onGuideModalOpen}
_hover={{
transform: 'translateY(-2px)',
bg: forumColors.primary[50],
borderColor: forumColors.primary[600],
}}
_active={{ transform: 'translateY(0)' }}
>
玩法说明
</Button>
<Button
leftIcon={<PenSquare size={18} />}
bg={forumColors.background.card}
@@ -462,6 +482,12 @@ const ValueForum = () => {
onClose={onPredictionModalClose}
onTopicCreated={handlePredictionCreated}
/>
{/* 玩法说明模态框 */}
<PredictionGuideModal
isOpen={isGuideModalOpen}
onClose={onGuideModalClose}
/>
</Box>
);
};