387 lines
13 KiB
JavaScript
387 lines
13 KiB
JavaScript
/**
|
||
* 创建预测话题模态框
|
||
* 用户可以发起新的预测市场话题
|
||
*/
|
||
|
||
import React, { useState } from 'react';
|
||
import {
|
||
Modal,
|
||
ModalOverlay,
|
||
ModalContent,
|
||
ModalHeader,
|
||
ModalBody,
|
||
ModalFooter,
|
||
ModalCloseButton,
|
||
Button,
|
||
VStack,
|
||
FormControl,
|
||
FormLabel,
|
||
Input,
|
||
Textarea,
|
||
Select,
|
||
HStack,
|
||
Text,
|
||
Box,
|
||
Icon,
|
||
Alert,
|
||
AlertIcon,
|
||
useToast,
|
||
} from '@chakra-ui/react';
|
||
import { Zap, Calendar, DollarSign } from 'lucide-react';
|
||
import { forumColors } from '@theme/forumTheme';
|
||
import { createTopic } from '@services/predictionMarketService';
|
||
import { getUserAccount, CREDIT_CONFIG } from '@services/creditSystemService';
|
||
import { useAuth } from '@contexts/AuthContext';
|
||
|
||
const CreatePredictionModal = ({ isOpen, onClose, onTopicCreated }) => {
|
||
const toast = useToast();
|
||
const { user } = useAuth();
|
||
|
||
// 表单状态
|
||
const [formData, setFormData] = useState({
|
||
title: '',
|
||
description: '',
|
||
category: 'stock',
|
||
deadline_days: 7,
|
||
});
|
||
|
||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||
|
||
// 获取用户余额
|
||
const userAccount = user ? getUserAccount(user.id) : null;
|
||
|
||
// 处理表单变化
|
||
const handleChange = (field, value) => {
|
||
setFormData((prev) => ({ ...prev, [field]: value }));
|
||
};
|
||
|
||
// 提交表单
|
||
const handleSubmit = async () => {
|
||
try {
|
||
setIsSubmitting(true);
|
||
|
||
// 验证
|
||
if (!formData.title.trim()) {
|
||
toast({
|
||
title: '请填写话题标题',
|
||
status: 'warning',
|
||
duration: 3000,
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!formData.description.trim()) {
|
||
toast({
|
||
title: '请填写话题描述',
|
||
status: 'warning',
|
||
duration: 3000,
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 检查余额
|
||
if (userAccount.balance < CREDIT_CONFIG.CREATE_TOPIC_COST) {
|
||
toast({
|
||
title: '积分不足',
|
||
description: `创建话题需要${CREDIT_CONFIG.CREATE_TOPIC_COST}积分`,
|
||
status: 'error',
|
||
duration: 3000,
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 计算截止时间
|
||
const deadline = new Date();
|
||
deadline.setDate(deadline.getDate() + parseInt(formData.deadline_days));
|
||
|
||
const settlement_date = new Date(deadline);
|
||
settlement_date.setDate(settlement_date.getDate() + 1);
|
||
|
||
// 创建话题
|
||
const newTopic = createTopic({
|
||
author_id: user.id,
|
||
author_name: user.name || user.username,
|
||
author_avatar: user.avatar,
|
||
title: formData.title,
|
||
description: formData.description,
|
||
category: formData.category,
|
||
deadline: deadline.toISOString(),
|
||
settlement_date: settlement_date.toISOString(),
|
||
});
|
||
|
||
toast({
|
||
title: '创建成功!',
|
||
description: `话题已发布,扣除${CREDIT_CONFIG.CREATE_TOPIC_COST}积分`,
|
||
status: 'success',
|
||
duration: 3000,
|
||
});
|
||
|
||
// 重置表单
|
||
setFormData({
|
||
title: '',
|
||
description: '',
|
||
category: 'stock',
|
||
deadline_days: 7,
|
||
});
|
||
|
||
// 通知父组件
|
||
if (onTopicCreated) {
|
||
onTopicCreated(newTopic);
|
||
}
|
||
|
||
onClose();
|
||
} catch (error) {
|
||
console.error('创建话题失败:', error);
|
||
toast({
|
||
title: '创建失败',
|
||
description: error.message,
|
||
status: 'error',
|
||
duration: 3000,
|
||
});
|
||
} finally {
|
||
setIsSubmitting(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Modal isOpen={isOpen} onClose={onClose} size="xl" isCentered>
|
||
<ModalOverlay backdropFilter="blur(4px)" />
|
||
<ModalContent
|
||
bg={forumColors.background.card}
|
||
borderRadius="xl"
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
>
|
||
<ModalHeader
|
||
bg={forumColors.gradients.goldSubtle}
|
||
borderTopRadius="xl"
|
||
borderBottom="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
>
|
||
<HStack spacing="2">
|
||
<Icon as={Zap} boxSize="20px" color={forumColors.primary[500]} />
|
||
<Text color={forumColors.text.primary}>发起预测话题</Text>
|
||
</HStack>
|
||
</ModalHeader>
|
||
<ModalCloseButton color={forumColors.text.primary} />
|
||
|
||
<ModalBody py="6">
|
||
<VStack spacing="5" align="stretch">
|
||
{/* 提示信息 */}
|
||
<Alert
|
||
status="info"
|
||
bg={forumColors.background.hover}
|
||
borderRadius="lg"
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
>
|
||
<AlertIcon color={forumColors.primary[500]} />
|
||
<VStack align="start" spacing="1" flex="1">
|
||
<Text fontSize="sm" color={forumColors.text.primary} fontWeight="600">
|
||
创建预测话题
|
||
</Text>
|
||
<Text fontSize="xs" color={forumColors.text.secondary}>
|
||
• 创建费用:{CREDIT_CONFIG.CREATE_TOPIC_COST}积分(进入奖池)
|
||
</Text>
|
||
<Text fontSize="xs" color={forumColors.text.secondary}>
|
||
• 作者不能参与自己发起的话题
|
||
</Text>
|
||
<Text fontSize="xs" color={forumColors.text.secondary}>
|
||
• 截止后由作者提交结果进行结算
|
||
</Text>
|
||
</VStack>
|
||
</Alert>
|
||
|
||
{/* 话题标题 */}
|
||
<FormControl isRequired>
|
||
<FormLabel fontSize="sm" color={forumColors.text.primary}>
|
||
话题标题
|
||
</FormLabel>
|
||
<Input
|
||
placeholder="例如:贵州茅台下周会涨吗?"
|
||
value={formData.title}
|
||
onChange={(e) => handleChange('title', e.target.value)}
|
||
bg={forumColors.background.main}
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
color={forumColors.text.primary}
|
||
_placeholder={{ color: forumColors.text.tertiary }}
|
||
_hover={{ borderColor: forumColors.border.light }}
|
||
_focus={{
|
||
borderColor: forumColors.border.gold,
|
||
boxShadow: `0 0 0 1px ${forumColors.border.goldGlow}`,
|
||
}}
|
||
/>
|
||
</FormControl>
|
||
|
||
{/* 话题描述 */}
|
||
<FormControl isRequired>
|
||
<FormLabel fontSize="sm" color={forumColors.text.primary}>
|
||
话题描述
|
||
</FormLabel>
|
||
<Textarea
|
||
placeholder="详细描述预测的内容、判断标准、数据来源等..."
|
||
value={formData.description}
|
||
onChange={(e) => handleChange('description', e.target.value)}
|
||
rows={4}
|
||
bg={forumColors.background.main}
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
color={forumColors.text.primary}
|
||
_placeholder={{ color: forumColors.text.tertiary }}
|
||
_hover={{ borderColor: forumColors.border.light }}
|
||
_focus={{
|
||
borderColor: forumColors.border.gold,
|
||
boxShadow: `0 0 0 1px ${forumColors.border.goldGlow}`,
|
||
}}
|
||
/>
|
||
</FormControl>
|
||
|
||
{/* 分类 */}
|
||
<FormControl>
|
||
<FormLabel fontSize="sm" color={forumColors.text.primary}>
|
||
分类
|
||
</FormLabel>
|
||
<Select
|
||
value={formData.category}
|
||
onChange={(e) => handleChange('category', e.target.value)}
|
||
bg={forumColors.background.main}
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
color={forumColors.text.primary}
|
||
_hover={{ borderColor: forumColors.border.light }}
|
||
_focus={{
|
||
borderColor: forumColors.border.gold,
|
||
boxShadow: `0 0 0 1px ${forumColors.border.goldGlow}`,
|
||
}}
|
||
>
|
||
<option value="stock">股票行情</option>
|
||
<option value="index">指数走势</option>
|
||
<option value="concept">概念板块</option>
|
||
<option value="policy">政策影响</option>
|
||
<option value="event">事件预测</option>
|
||
<option value="other">其他</option>
|
||
</Select>
|
||
</FormControl>
|
||
|
||
{/* 截止时间 */}
|
||
<FormControl>
|
||
<FormLabel fontSize="sm" color={forumColors.text.primary}>
|
||
<HStack spacing="2">
|
||
<Icon as={Calendar} boxSize="16px" />
|
||
<Text>交易截止时间</Text>
|
||
</HStack>
|
||
</FormLabel>
|
||
<Select
|
||
value={formData.deadline_days}
|
||
onChange={(e) => handleChange('deadline_days', e.target.value)}
|
||
bg={forumColors.background.main}
|
||
border="1px solid"
|
||
borderColor={forumColors.border.default}
|
||
color={forumColors.text.primary}
|
||
_hover={{ borderColor: forumColors.border.light }}
|
||
_focus={{
|
||
borderColor: forumColors.border.gold,
|
||
boxShadow: `0 0 0 1px ${forumColors.border.goldGlow}`,
|
||
}}
|
||
>
|
||
<option value="1">1天后</option>
|
||
<option value="3">3天后</option>
|
||
<option value="7">7天后(推荐)</option>
|
||
<option value="14">14天后</option>
|
||
<option value="30">30天后</option>
|
||
</Select>
|
||
<Text fontSize="xs" color={forumColors.text.tertiary} mt="2">
|
||
截止后次日可提交结果进行结算
|
||
</Text>
|
||
</FormControl>
|
||
|
||
{/* 费用说明 */}
|
||
<Box
|
||
bg={forumColors.gradients.goldSubtle}
|
||
border="1px solid"
|
||
borderColor={forumColors.border.gold}
|
||
borderRadius="lg"
|
||
p="4"
|
||
>
|
||
<HStack justify="space-between">
|
||
<VStack align="start" spacing="1">
|
||
<Text fontSize="sm" fontWeight="600" color={forumColors.text.primary}>
|
||
创建费用
|
||
</Text>
|
||
<Text fontSize="xs" color={forumColors.text.secondary}>
|
||
将进入奖池,奖励给获胜者
|
||
</Text>
|
||
</VStack>
|
||
|
||
<HStack spacing="1">
|
||
<Icon as={DollarSign} boxSize="20px" color={forumColors.primary[500]} />
|
||
<Text fontSize="2xl" fontWeight="bold" color={forumColors.primary[500]}>
|
||
{CREDIT_CONFIG.CREATE_TOPIC_COST}
|
||
</Text>
|
||
<Text fontSize="sm" color={forumColors.text.secondary}>
|
||
积分
|
||
</Text>
|
||
</HStack>
|
||
</HStack>
|
||
|
||
<Box mt="3" pt="3" borderTop="1px solid" borderColor={forumColors.border.default}>
|
||
<HStack justify="space-between" fontSize="sm">
|
||
<Text color={forumColors.text.secondary}>你的余额:</Text>
|
||
<Text fontWeight="600" color={forumColors.text.primary}>
|
||
{userAccount?.balance || 0} 积分
|
||
</Text>
|
||
</HStack>
|
||
<HStack justify="space-between" fontSize="sm" mt="1">
|
||
<Text color={forumColors.text.secondary}>创建后:</Text>
|
||
<Text
|
||
fontWeight="600"
|
||
color={
|
||
(userAccount?.balance || 0) >= CREDIT_CONFIG.CREATE_TOPIC_COST
|
||
? forumColors.success[500]
|
||
: forumColors.error[500]
|
||
}
|
||
>
|
||
{(userAccount?.balance || 0) - CREDIT_CONFIG.CREATE_TOPIC_COST} 积分
|
||
</Text>
|
||
</HStack>
|
||
</Box>
|
||
</Box>
|
||
</VStack>
|
||
</ModalBody>
|
||
|
||
<ModalFooter borderTop="1px solid" borderColor={forumColors.border.default}>
|
||
<HStack spacing="3">
|
||
<Button
|
||
variant="ghost"
|
||
onClick={onClose}
|
||
color={forumColors.text.secondary}
|
||
_hover={{ bg: forumColors.background.hover }}
|
||
>
|
||
取消
|
||
</Button>
|
||
<Button
|
||
bg={forumColors.gradients.goldPrimary}
|
||
color={forumColors.background.main}
|
||
fontWeight="bold"
|
||
onClick={handleSubmit}
|
||
isLoading={isSubmitting}
|
||
loadingText="创建中..."
|
||
isDisabled={(userAccount?.balance || 0) < CREDIT_CONFIG.CREATE_TOPIC_COST}
|
||
_hover={{
|
||
opacity: 0.9,
|
||
transform: 'translateY(-2px)',
|
||
}}
|
||
_active={{ transform: 'translateY(0)' }}
|
||
>
|
||
发布话题
|
||
</Button>
|
||
</HStack>
|
||
</ModalFooter>
|
||
</ModalContent>
|
||
</Modal>
|
||
);
|
||
};
|
||
|
||
export default CreatePredictionModal;
|