update pay function

This commit is contained in:
2025-11-28 12:37:01 +08:00
parent 9c5900c7f5
commit c1937b9e31
2 changed files with 343 additions and 80 deletions

View File

@@ -0,0 +1,310 @@
// src/views/AgentChat/components/ChatArea/WelcomeScreen.js
// 欢迎界面组件 - 类似 Gemini/ChatGPT 风格
import React from 'react';
import { motion } from 'framer-motion';
import {
Box,
VStack,
HStack,
Text,
SimpleGrid,
Icon,
} from '@chakra-ui/react';
import {
Cpu,
TrendingUp,
BarChart3,
Newspaper,
Target,
Lightbulb,
Search,
PieChart,
Sparkles,
} from 'lucide-react';
/**
* 建议任务卡片数据
*/
const SUGGESTION_CARDS = [
{
icon: TrendingUp,
title: '今日涨停分析',
description: '分析今天涨停板的概念分布和热点板块',
prompt: '分析一下今天的涨停板,有哪些热点概念?',
gradient: 'linear(to-br, orange.400, red.500)',
shadowColor: 'rgba(251, 146, 60, 0.3)',
},
{
icon: Search,
title: '个股深度研究',
description: '全面分析某只股票的基本面和技术面',
prompt: '帮我分析一下贵州茅台的投资价值',
gradient: 'linear(to-br, blue.400, cyan.500)',
shadowColor: 'rgba(59, 130, 246, 0.3)',
},
{
icon: BarChart3,
title: '板块轮动追踪',
description: '追踪近期市场板块轮动和资金流向',
prompt: '最近有哪些板块在轮动?资金流向如何?',
gradient: 'linear(to-br, purple.400, pink.500)',
shadowColor: 'rgba(168, 85, 247, 0.3)',
},
{
icon: Newspaper,
title: '财经热点解读',
description: '解读最新的财经新闻和政策影响',
prompt: '今天有什么重要的财经新闻?对市场有什么影响?',
gradient: 'linear(to-br, green.400, teal.500)',
shadowColor: 'rgba(34, 197, 94, 0.3)',
},
];
/**
* 能力标签
*/
const CAPABILITIES = [
{ icon: Target, text: '精准股票分析' },
{ icon: Lightbulb, text: '智能投资建议' },
{ icon: PieChart, text: '数据可视化' },
{ icon: Sparkles, text: '实时热点追踪' },
];
/**
* 建议卡片组件
*/
const SuggestionCard = ({ card, onClick, index }) => {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 + index * 0.1, duration: 0.4 }}
whileHover={{ scale: 1.02, y: -4 }}
whileTap={{ scale: 0.98 }}
>
<Box
as="button"
w="full"
p={4}
bg="rgba(255, 255, 255, 0.03)"
backdropFilter="blur(12px)"
border="1px solid"
borderColor="rgba(255, 255, 255, 0.08)"
borderRadius="xl"
textAlign="left"
cursor="pointer"
transition="all 0.3s"
onClick={() => onClick(card.prompt)}
_hover={{
bg: 'rgba(255, 255, 255, 0.06)',
borderColor: 'rgba(255, 255, 255, 0.15)',
boxShadow: `0 8px 32px ${card.shadowColor}`,
}}
>
<HStack spacing={3} mb={2}>
<Box
p={2}
borderRadius="lg"
bgGradient={card.gradient}
boxShadow={`0 4px 12px ${card.shadowColor}`}
>
<Icon as={card.icon} w={4} h={4} color="white" />
</Box>
<Text fontWeight="semibold" color="gray.200" fontSize="sm">
{card.title}
</Text>
</HStack>
<Text fontSize="xs" color="gray.500" lineHeight="tall">
{card.description}
</Text>
</Box>
</motion.div>
);
};
/**
* WelcomeScreen - 欢迎界面组件
*
* @param {Object} props
* @param {Function} props.onSuggestionClick - 点击建议时的回调
* @returns {JSX.Element}
*/
const WelcomeScreen = ({ onSuggestionClick }) => {
return (
<Box
flex={1}
display="flex"
flexDirection="column"
alignItems="center"
justifyContent="center"
px={6}
py={8}
>
<VStack spacing={8} maxW="700px" w="full">
{/* Logo 和标题 */}
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.5 }}
>
<VStack spacing={4}>
{/* 动态 Logo */}
<Box position="relative">
{/* 外层光晕 */}
<motion.div
animate={{
boxShadow: [
'0 0 30px rgba(139, 92, 246, 0.3)',
'0 0 60px rgba(139, 92, 246, 0.5)',
'0 0 30px rgba(139, 92, 246, 0.3)',
],
}}
transition={{ duration: 2, repeat: Infinity }}
style={{
position: 'absolute',
inset: -8,
borderRadius: '50%',
}}
/>
{/* 旋转边框 */}
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 8, repeat: Infinity, ease: 'linear' }}
style={{
position: 'absolute',
inset: -4,
borderRadius: '50%',
background: 'linear-gradient(45deg, transparent 40%, rgba(139, 92, 246, 0.5) 50%, transparent 60%)',
}}
/>
<Box
w={20}
h={20}
borderRadius="full"
bgGradient="linear(to-br, purple.500, pink.500, blue.500)"
display="flex"
alignItems="center"
justifyContent="center"
position="relative"
boxShadow="0 8px 32px rgba(139, 92, 246, 0.4)"
>
<Cpu className="w-10 h-10" color="white" />
</Box>
</Box>
{/* 标题 */}
<VStack spacing={1}>
<Text
fontSize="3xl"
fontWeight="bold"
bgGradient="linear(to-r, blue.300, purple.400, pink.400)"
bgClip="text"
letterSpacing="tight"
>
你好我是价小前
</Text>
<Text fontSize="md" color="gray.400" textAlign="center">
你的 AI 投研助手
</Text>
</VStack>
</VStack>
</motion.div>
{/* 简介 */}
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2, duration: 0.4 }}
>
<Box
p={4}
bg="rgba(255, 255, 255, 0.02)"
borderRadius="xl"
border="1px solid"
borderColor="rgba(255, 255, 255, 0.05)"
>
<Text fontSize="sm" color="gray.400" textAlign="center" lineHeight="tall">
基于最先进的大语言模型结合专业微调的金融理解能力
<br />
整合实时投研数据与专业分析工具为你提供智能投资研究服务
</Text>
</Box>
</motion.div>
{/* 能力标签 */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.3, duration: 0.4 }}
>
<HStack spacing={4} flexWrap="wrap" justify="center">
{CAPABILITIES.map((cap, idx) => (
<motion.div
key={idx}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: 0.3 + idx * 0.05 }}
>
<HStack
spacing={2}
px={3}
py={1.5}
bg="rgba(139, 92, 246, 0.1)"
borderRadius="full"
border="1px solid"
borderColor="rgba(139, 92, 246, 0.2)"
>
<Icon as={cap.icon} w={3.5} h={3.5} color="purple.400" />
<Text fontSize="xs" color="purple.300" fontWeight="medium">
{cap.text}
</Text>
</HStack>
</motion.div>
))}
</HStack>
</motion.div>
{/* 建议任务卡片 */}
<Box w="full">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.4 }}
>
<HStack spacing={2} mb={4} justify="center">
<Sparkles className="w-4 h-4" color="#a78bfa" />
<Text fontSize="sm" color="gray.400" fontWeight="medium">
试试这些问题
</Text>
</HStack>
</motion.div>
<SimpleGrid columns={{ base: 1, md: 2 }} spacing={3}>
{SUGGESTION_CARDS.map((card, idx) => (
<SuggestionCard
key={idx}
card={card}
index={idx}
onClick={onSuggestionClick}
/>
))}
</SimpleGrid>
</Box>
{/* 底部提示 */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.6 }}
>
<Text fontSize="xs" color="gray.600" textAlign="center">
输入你的问题或点击上方卡片快速开始
</Text>
</motion.div>
</VStack>
</Box>
);
};
export default WelcomeScreen;

View File

@@ -5,7 +5,6 @@ import React, { useRef, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import {
Box,
Button,
Input,
Avatar,
Badge,
@@ -27,14 +26,13 @@ import {
Settings,
Cpu,
Zap,
Sparkles,
Paperclip,
Image as ImageIcon,
} from 'lucide-react';
import { AVAILABLE_MODELS } from '../../constants/models';
import { quickQuestions } from '../../constants/quickQuestions';
import { animations } from '../../constants/animations';
import MessageRenderer from './MessageRenderer';
import WelcomeScreen from './WelcomeScreen';
/**
* ChatArea - 中间聊天区域组件
@@ -215,14 +213,25 @@ const ChatArea = ({
</Flex>
</Box>
{/* 消息列表 */}
{/* 消息列表 / 欢迎界面 */}
<Box
flex={1}
bgGradient="linear(to-b, rgba(17, 24, 39, 0.5), rgba(17, 24, 39, 0.3))"
overflowY="auto"
display="flex"
flexDirection="column"
>
{/* 判断是否显示欢迎界面只有初始欢迎消息1条或没有消息时显示 */}
{messages.length <= 1 && !isProcessing ? (
<WelcomeScreen
onSuggestionClick={(prompt) => {
onInputChange(prompt);
inputRef.current?.focus();
}}
/>
) : (
<motion.div
style={{ maxWidth: '896px', margin: '0 auto' }}
style={{ maxWidth: '896px', margin: '0 auto', width: '100%', padding: '16px' }}
variants={animations.staggerContainer}
initial="initial"
animate="animate"
@@ -245,64 +254,8 @@ const ChatArea = ({
<div ref={messagesEndRef} />
</VStack>
</motion.div>
</Box>
{/* 快捷问题 */}
<AnimatePresence>
{messages.length <= 2 && !isProcessing && (
<motion.div
variants={animations.fadeInUp}
initial="initial"
animate="animate"
exit={{ opacity: 0, y: 20 }}
>
<Box px={6}>
<Box maxW="896px" mx="auto">
<HStack fontSize="xs" color="gray.500" mb={2} fontWeight="medium" spacing={1}>
<Sparkles className="w-3 h-3" />
<Text>快速开始</Text>
</HStack>
<Box display="grid" gridTemplateColumns="repeat(2, 1fr)" gap={2}>
{quickQuestions.map((question, idx) => (
<motion.div
key={idx}
whileHover={{ scale: 1.02, y: -2 }}
whileTap={{ scale: 0.98 }}
transition={{ type: 'spring', stiffness: 400, damping: 17 }}
>
<Button
variant="outline"
w="full"
justifyContent="flex-start"
h="auto"
py={3}
bg="rgba(255, 255, 255, 0.05)"
backdropFilter="blur(12px)"
border="1px solid"
borderColor="rgba(255, 255, 255, 0.1)"
color="gray.300"
_hover={{
bg: 'rgba(59, 130, 246, 0.15)',
borderColor: 'blue.400',
boxShadow: '0 4px 12px rgba(59, 130, 246, 0.3)',
color: 'white',
}}
onClick={() => {
onInputChange(question.text);
inputRef.current?.focus();
}}
>
<Text mr={2}>{question.emoji}</Text>
<Text>{question.text}</Text>
</Button>
</motion.div>
))}
</Box>
</Box>
</Box>
</motion.div>
)}
</AnimatePresence>
</Box>
{/* 输入栏 - 深色毛玻璃 */}
<Box