update pay function
This commit is contained in:
@@ -35,7 +35,7 @@
|
||||
"echarts": "^5.6.0",
|
||||
"echarts-for-react": "^3.0.2",
|
||||
"echarts-wordcloud": "^2.1.0",
|
||||
"framer-motion": "^4.1.17",
|
||||
"framer-motion": "^12.23.24",
|
||||
"fullcalendar": "^5.9.0",
|
||||
"globalize": "^1.7.0",
|
||||
"history": "^5.3.0",
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
### 🚀 技术栈
|
||||
|
||||
- **Hero UI** - 现代化 React UI 组件库(NextUI 的继任者)
|
||||
- **Framer Motion** - 物理动画引擎
|
||||
- **Framer Motion 12** - 物理动画引擎(已升级!)
|
||||
- **Tailwind CSS** - 原子化 CSS 框架(Hero UI 内置)
|
||||
- **Lucide Icons** - 现代化图标库
|
||||
- **Chakra UI Toast** - 通知提示(保留)
|
||||
- **Chakra UI Toast** - 通知提示(待迁移到 Hero UI Toast)
|
||||
|
||||
### 🎨 视觉特性
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
- `backdrop-blur-xl` + 渐变背景
|
||||
- 深色模式完美支持
|
||||
|
||||
2. **流畅动画**
|
||||
- 侧边栏 Spring 动画滑入/滑出
|
||||
- 消息依次淡入(错开延迟)
|
||||
- 按钮悬停/点击缩放效果
|
||||
- AI 头像持续旋转动画
|
||||
2. **流畅动画(Framer Motion 12 物理引擎)**
|
||||
- ✨ 侧边栏 **Spring 弹性动画**滑入/滑出(stiffness: 300, damping: 30)
|
||||
- ✨ 消息 **淡入上移** + **错开延迟**(staggerChildren: 0.05)
|
||||
- ✨ 按钮 **悬停缩放**(1.05x) + **点击压缩**(0.95x)
|
||||
- ✨ AI 头像 **360度持续旋转**(duration: 3s, linear)
|
||||
- ✨ 快捷问题卡片 **退出动画**(AnimatePresence)
|
||||
|
||||
3. **渐变色设计**
|
||||
- 标题:蓝到紫渐变
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// src/views/AgentChat/index.js
|
||||
// 超炫酷的 AI 投研助手 - Hero UI 版本
|
||||
// 使用 CSS 动画替代 Framer Motion(避免版本冲突)
|
||||
// 使用 Framer Motion 物理动画引擎
|
||||
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
@@ -67,6 +68,78 @@ import {
|
||||
Rocket,
|
||||
} from 'lucide-react';
|
||||
|
||||
/**
|
||||
* Framer Motion 动画变体配置
|
||||
*/
|
||||
const animations = {
|
||||
// 侧边栏滑入动画(带弹性效果)
|
||||
slideInLeft: {
|
||||
initial: { x: -320, opacity: 0 },
|
||||
animate: {
|
||||
x: 0,
|
||||
opacity: 1,
|
||||
transition: {
|
||||
type: 'spring',
|
||||
stiffness: 300,
|
||||
damping: 30,
|
||||
},
|
||||
},
|
||||
exit: {
|
||||
x: -320,
|
||||
opacity: 0,
|
||||
transition: { duration: 0.2 },
|
||||
},
|
||||
},
|
||||
slideInRight: {
|
||||
initial: { x: 320, opacity: 0 },
|
||||
animate: {
|
||||
x: 0,
|
||||
opacity: 1,
|
||||
transition: {
|
||||
type: 'spring',
|
||||
stiffness: 300,
|
||||
damping: 30,
|
||||
},
|
||||
},
|
||||
exit: {
|
||||
x: 320,
|
||||
opacity: 0,
|
||||
transition: { duration: 0.2 },
|
||||
},
|
||||
},
|
||||
// 消息淡入动画(带上移效果)
|
||||
fadeInUp: {
|
||||
initial: { opacity: 0, y: 20 },
|
||||
animate: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
type: 'spring',
|
||||
stiffness: 400,
|
||||
damping: 25,
|
||||
},
|
||||
},
|
||||
},
|
||||
// 列表项淡入(错开延迟)
|
||||
staggerItem: {
|
||||
initial: { opacity: 0, y: 10 },
|
||||
animate: { opacity: 1, y: 0 },
|
||||
},
|
||||
// 父容器错开动画
|
||||
staggerContainer: {
|
||||
animate: {
|
||||
transition: {
|
||||
staggerChildren: 0.05,
|
||||
},
|
||||
},
|
||||
},
|
||||
// 按钮点击动画
|
||||
pressScale: {
|
||||
whileTap: { scale: 0.95 },
|
||||
whileHover: { scale: 1.05 },
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
@@ -355,7 +428,13 @@ const AgentChat = () => {
|
||||
<div className="flex h-screen bg-gradient-to-br from-gray-50 to-blue-50 dark:from-gray-900 dark:to-gray-800 overflow-hidden">
|
||||
{/* 左侧栏 */}
|
||||
{isLeftSidebarOpen && (
|
||||
<div className="w-80 flex flex-col bg-white/80 dark:bg-gray-800/80 backdrop-blur-xl border-r border-gray-200 dark:border-gray-700 shadow-xl animate-slide-in-left">
|
||||
<motion.div
|
||||
className="w-80 flex flex-col bg-white/80 dark:bg-gray-800/80 backdrop-blur-xl border-r border-gray-200 dark:border-gray-700 shadow-xl"
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
exit="exit"
|
||||
variants={animations.slideInLeft}
|
||||
>
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -457,7 +536,7 @@ const AgentChat = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* 中间主聊天区域 */}
|
||||
@@ -476,12 +555,17 @@ const AgentChat = () => {
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<motion.div
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 3, repeat: Infinity, ease: 'linear' }}
|
||||
>
|
||||
<Avatar
|
||||
icon={<Cpu className="w-6 h-6" />}
|
||||
classNames={{
|
||||
base: 'bg-gradient-to-br from-purple-500 to-pink-500 animate-spin-slow',
|
||||
base: 'bg-gradient-to-br from-purple-500 to-pink-500',
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
<div>
|
||||
<h1 className="text-xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
|
||||
@@ -524,18 +608,39 @@ const AgentChat = () => {
|
||||
</div>
|
||||
|
||||
<ScrollShadow className="flex-1 p-6">
|
||||
<div className="max-w-4xl mx-auto space-y-4">
|
||||
{messages.map((message) => (
|
||||
<div key={message.id} className="animate-fade-in">
|
||||
<motion.div
|
||||
className="max-w-4xl mx-auto space-y-4"
|
||||
variants={animations.staggerContainer}
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
>
|
||||
<AnimatePresence mode="popLayout">
|
||||
{messages.map((message, index) => (
|
||||
<motion.div
|
||||
key={message.id}
|
||||
variants={animations.fadeInUp}
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
exit={{ opacity: 0, y: -20 }}
|
||||
layout
|
||||
>
|
||||
<MessageRenderer message={message} userAvatar={user?.avatar} />
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
</motion.div>
|
||||
</ScrollShadow>
|
||||
|
||||
<AnimatePresence>
|
||||
{messages.length <= 2 && !isProcessing && (
|
||||
<div className="px-6 py-3 animate-fade-in">
|
||||
<motion.div
|
||||
className="px-6 py-3"
|
||||
variants={animations.fadeInUp}
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
exit={{ opacity: 0, y: 20 }}
|
||||
>
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<p className="text-xs text-gray-500 mb-2 font-medium flex items-center gap-1">
|
||||
<Sparkles className="w-3 h-3" />
|
||||
@@ -543,11 +648,11 @@ const AgentChat = () => {
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{quickQuestions.map((question, idx) => (
|
||||
<motion.div key={idx} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
|
||||
<Button
|
||||
key={idx}
|
||||
variant="bordered"
|
||||
color="primary"
|
||||
className="w-full justify-start h-auto py-3 hover:scale-105 transition-transform"
|
||||
className="w-full justify-start h-auto py-3"
|
||||
onPress={() => {
|
||||
setInputValue(question.text);
|
||||
inputRef.current?.focus();
|
||||
@@ -556,11 +661,13 @@ const AgentChat = () => {
|
||||
<span className="mr-2">{question.emoji}</span>
|
||||
{question.text}
|
||||
</Button>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="bg-white/70 dark:bg-gray-800/70 backdrop-blur-xl border-t border-gray-200 dark:border-gray-700 px-6 py-4">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
@@ -579,6 +686,7 @@ const AgentChat = () => {
|
||||
inputWrapper: 'border-2 hover:border-primary-500 transition-colors',
|
||||
}}
|
||||
/>
|
||||
<motion.div whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
|
||||
<Button
|
||||
isIconOnly
|
||||
color="primary"
|
||||
@@ -587,10 +695,11 @@ const AgentChat = () => {
|
||||
onPress={handleSendMessage}
|
||||
isLoading={isProcessing}
|
||||
isDisabled={!inputValue.trim() || isProcessing}
|
||||
className="bg-gradient-to-r from-blue-500 to-purple-500 hover:scale-105 transition-transform"
|
||||
className="bg-gradient-to-r from-blue-500 to-purple-500"
|
||||
>
|
||||
{!isProcessing && <Send className="w-5 h-5" />}
|
||||
</Button>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4 mt-2 text-xs text-gray-500">
|
||||
@@ -611,7 +720,13 @@ const AgentChat = () => {
|
||||
|
||||
{/* 右侧栏 */}
|
||||
{isRightSidebarOpen && (
|
||||
<div className="w-80 flex flex-col bg-white/80 dark:bg-gray-800/80 backdrop-blur-xl border-l border-gray-200 dark:border-gray-700 shadow-xl animate-slide-in-right">
|
||||
<motion.div
|
||||
className="w-80 flex flex-col bg-white/80 dark:bg-gray-800/80 backdrop-blur-xl border-l border-gray-200 dark:border-gray-700 shadow-xl"
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
exit="exit"
|
||||
variants={animations.slideInRight}
|
||||
>
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -709,80 +824,14 @@ const AgentChat = () => {
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</ScrollShadow>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
<style>{`
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-in-left {
|
||||
from {
|
||||
transform: translateX(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-in-right {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin-slow {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-fade-in {
|
||||
animation: fade-in 0.3s ease-out;
|
||||
}
|
||||
|
||||
.animate-slide-in-left {
|
||||
animation: slide-in-left 0.3s ease-out;
|
||||
}
|
||||
|
||||
.animate-slide-in-right {
|
||||
animation: slide-in-right 0.3s ease-out;
|
||||
}
|
||||
|
||||
.animate-spin-slow {
|
||||
animation: spin-slow 3s linear infinite;
|
||||
}
|
||||
|
||||
.hover\\:scale-102:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.hover\\:scale-105:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AgentChat;
|
||||
|
||||
/**
|
||||
* 消息渲染器
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user