diff --git a/package.json b/package.json index 0477a556..f2adc836 100755 --- a/package.json +++ b/package.json @@ -25,8 +25,6 @@ "@visx/responsive": "^3.12.0", "@visx/scale": "^3.12.0", "@visx/text": "^3.12.0", - "@tsparticles/react": "^3.0.0", - "@tsparticles/slim": "^3.0.0", "@visx/visx": "^3.12.0", "@visx/wordcloud": "^3.12.0", "antd": "^5.27.4", @@ -57,6 +55,7 @@ "react-github-btn": "^1.2.1", "react-icons": "^4.12.0", "react-input-pin-code": "^1.1.5", + "react-is": "^19.0.0", "react-just-parallax": "^3.1.16", "react-markdown": "^10.1.0", "react-redux": "^9.2.0", @@ -64,14 +63,12 @@ "react-responsive-masonry": "^2.7.1", "react-router-dom": "^6.30.1", "react-scripts": "^5.0.1", - "react-is": "^19.0.0", "react-scroll": "^1.8.4", "react-scroll-into-view": "^2.1.3", "react-table": "^7.7.0", "react-tagsinput": "3.19.0", - "react-to-print": "^2.13.0", - "react-tsparticles": "^2.12.2", "react-to-print": "^3.0.3", + "react-tsparticles": "^2.12.2", "recharts": "^3.1.2", "sass": "^1.49.9", "socket.io-client": "^4.7.4", diff --git a/src/views/Community/components/MidjourneyHeroSection.js b/src/views/Community/components/MidjourneyHeroSection.js deleted file mode 100644 index 46db5c52..00000000 --- a/src/views/Community/components/MidjourneyHeroSection.js +++ /dev/null @@ -1,814 +0,0 @@ -import React, { useRef, useMemo, useState, useEffect } from 'react'; -import { motion } from 'framer-motion'; -import Particles from '@tsparticles/react'; -import { loadSlim } from '@tsparticles/slim'; -import { - Box, - Container, - Heading, - Text, - Button, - HStack, - VStack, - Badge, - Grid, - GridItem, - Stat, - StatLabel, - StatNumber, - Flex, - Tag, - useColorModeValue, -} from '@chakra-ui/react'; -import { - LineChart, - Line, - AreaChart, - Area, - BarChart, - Bar, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, - ComposedChart, - ReferenceLine, - ReferenceDot, - Cell, -} from 'recharts'; -import { indexService } from '../../../services/eventService'; - -// 将后端分钟/分时数据转换为 Recharts 数据 -const toLineSeries = (resp) => { - const arr = resp?.data || []; - return arr.map((d, i) => ({ time: d.time || i, value: d.price ?? d.close, volume: d.volume })); -}; - -// 提取昨日收盘价:优先使用最后一条记录的 prev_close;否则回退到倒数第二条的 close -const getPrevClose = (resp) => { - const arr = resp?.data || []; - if (!arr.length) return null; - const last = arr[arr.length - 1] || {}; - if (last.prev_close !== undefined && last.prev_close !== null && isFinite(Number(last.prev_close))) { - return Number(last.prev_close); - } - const idx = arr.length >= 2 ? arr.length - 2 : arr.length - 1; - const k = arr[idx] || {}; - const candidate = k.close ?? k.c ?? k.price ?? null; - return candidate != null ? Number(candidate) : null; -}; - -// 组合图表组件(折线图 + 成交量柱状图) -const CombinedChart = ({ series, title, color = "#FFD700", basePrice = null }) => { - const [cursorIndex, setCursorIndex] = useState(0); - const cursorRef = useRef(0); - - // 直接将光标设置到最后一个数据点,不再使用动画 - useEffect(() => { - if (!series || series.length === 0) return; - // 直接设置到最后一个点 - const lastIndex = series.length - 1; - cursorRef.current = lastIndex; - setCursorIndex(lastIndex); - }, [series && series.length]); - - - const yDomain = useMemo(() => { - if (!series || series.length === 0) return ['auto', 'auto']; - const values = series - .map((d) => d?.value) - .filter((v) => typeof v === 'number' && isFinite(v)); - if (values.length === 0) return ['auto', 'auto']; - const minVal = Math.min(...values); - const maxVal = Math.max(...values); - const maxAbs = Math.max(Math.abs(minVal), Math.abs(maxVal)); - const padding = Math.max(maxAbs * 0.1, 0.2); - return [-maxAbs - padding, maxAbs + padding]; - }, [series]); - - // 当前高亮点 - const activePoint = useMemo(() => { - if (!series || series.length === 0) return null; - if (cursorIndex < 0 || cursorIndex >= series.length) return null; - return series[cursorIndex]; - }, [series, cursorIndex]); - - // 稳定的X轴ticks,避免随渲染跳动而闪烁 - const xTicks = useMemo(() => { - if (!series || series.length === 0) return []; - const desiredLabels = ['09:30', '10:30', '11:30', '14:00', '15:00']; - const set = new Set(series.map(d => d?.time)); - let ticks = desiredLabels.filter(t => set.has(t)); - if (ticks.length === 0) { - // 回退到首/中/尾的稳定采样,避免空白 - const len = series.length; - const idxs = [0, Math.round(len * 0.25), Math.round(len * 0.5), Math.round(len * 0.75), len - 1]; - ticks = idxs.map(i => series[i]?.time).filter(Boolean); - } - return ticks; - }, [series && series.length]); - - return ( - - - {title} - - - - - - - - - - - - - - - - - {/* 发光效果 */} - - - - - - - - - - - - - - {/* 左Y轴 - 价格 */} - `${v.toFixed(2)}%`} - orientation="left" - /> - - {/* 右Y轴 - 成交量(隐藏) */} - - - `时间: ${label}`} - formatter={(value, name) => { - if (name === 'value') { - const pct = Number(value); - if (typeof basePrice === 'number' && isFinite(basePrice)) { - const price = basePrice * (1 + pct / 100); - return [price.toFixed(2), '价格']; - } - return [`${pct.toFixed(2)}%`, '涨跌幅']; - } - if (name === 'volume') return [`${(Number(value) / 100000000).toFixed(2)}亿`, '成交量']; - return [value, name]; - }} - /> - - {/* 零轴参考线 */} - - - {/* 成交量柱状图 */} - - {series.map((entry, index) => ( - - ))} - - - {/* 价格折线 */} - - - {/* 移动的亮点 - 使用 ReferenceDot 贴合主数据坐标系 */} - {activePoint && ( - ( - - - - )} - /> - )} - - - - ); -}; - -// 数据流动线条组件 -function DataStreams() { - const lines = useMemo(() => { - return [...Array(15)].map((_, i) => ({ - id: i, - startX: Math.random() * 100, - delay: Math.random() * 5, - duration: 3 + Math.random() * 2, - height: 30 + Math.random() * 70 - })); - }, []); - - return ( - - {lines.map((line) => ( - - ))} - - ); -} - -// 主组件 -export default function MidjourneyHeroSection() { - const [sse, setSse] = useState({ - sh: { data: [], base: null }, - sz: { data: [], base: null }, - cyb: { data: [], base: null } - }); - - useEffect(() => { - const fetchData = async () => { - try { - const [shTL, szTL, cybTL, shDaily, szDaily, cybDaily] = await Promise.all([ - // 指数不传 event_time,后端自动返回"最新可用"交易日 - indexService.getKlineData('000001.SH', 'timeline'), - indexService.getKlineData('399001.SZ', 'timeline'), - indexService.getKlineData('399006.SZ', 'timeline'), // 创业板指 - indexService.getKlineData('000001.SH', 'daily'), - indexService.getKlineData('399001.SZ', 'daily'), - indexService.getKlineData('399006.SZ', 'daily'), - ]); - - const shPrevClose = getPrevClose(shDaily); - const szPrevClose = getPrevClose(szDaily); - const cybPrevClose = getPrevClose(cybDaily); - - const shSeries = toLineSeries(shTL); - const szSeries = toLineSeries(szTL); - const cybSeries = toLineSeries(cybTL); - - const baseSh = (typeof shPrevClose === 'number' && isFinite(shPrevClose)) - ? shPrevClose - : (shSeries.length ? shSeries[0].value : 1); - const baseSz = (typeof szPrevClose === 'number' && isFinite(szPrevClose)) - ? szPrevClose - : (szSeries.length ? szSeries[0].value : 1); - const baseCyb = (typeof cybPrevClose === 'number' && isFinite(cybPrevClose)) - ? cybPrevClose - : (cybSeries.length ? cybSeries[0].value : 1); - - const shPct = shSeries.map(p => ({ - time: p.time, - value: ((p.value / baseSh) - 1) * 100, - volume: p.volume || 0 - })); - const szPct = szSeries.map(p => ({ - time: p.time, - value: ((p.value / baseSz) - 1) * 100, - volume: p.volume || 0 - })); - const cybPct = cybSeries.map(p => ({ - time: p.time, - value: ((p.value / baseCyb) - 1) * 100, - volume: p.volume || 0 - })); - - setSse({ - sh: { data: shPct, base: baseSh }, - sz: { data: szPct, base: baseSz }, - cyb: { data: cybPct, base: baseCyb } - }); - } catch (e) { - // ignore - } - }; - fetchData(); - }, []); - - const particlesInit = async (engine) => { - await loadSlim(engine); - }; - - const particlesOptions = { - particles: { - number: { - value: 80, - density: { - enable: true, - value_area: 800 - } - }, - color: { - value: ["#FFD700", "#FF9800", "#FFC107", "#FFEB3B"] - }, - shape: { - type: "circle" - }, - opacity: { - value: 0.3, - random: true, - anim: { - enable: true, - speed: 1, - opacity_min: 0.1, - sync: false - } - }, - size: { - value: 2, - random: true, - anim: { - enable: true, - speed: 2, - size_min: 0.1, - sync: false - } - }, - line_linked: { - enable: true, - distance: 150, - color: "#FFD700", - opacity: 0.2, - width: 1 - }, - move: { - enable: true, - speed: 0.5, - direction: "none", - random: false, - straight: false, - out_mode: "out", - bounce: false, - } - }, - interactivity: { - detect_on: "canvas", - events: { - onhover: { - enable: true, - mode: "grab" - }, - onclick: { - enable: true, - mode: "push" - }, - resize: true - }, - modes: { - grab: { - distance: 140, - line_linked: { - opacity: 0.5 - } - }, - push: { - particles_nb: 4 - } - } - }, - retina_detect: true - }; - - const containerVariants = { - hidden: { opacity: 0 }, - visible: { - opacity: 1, - transition: { - staggerChildren: 0.1 - } - } - }; - - const itemVariants = { - hidden: { opacity: 0, y: 20 }, - visible: { - opacity: 1, - y: 0, - transition: { - duration: 0.6, - ease: "easeOut" - } - } - }; - - return ( - - {/* 粒子背景 */} - - - - - {/* 数据流动效果 */} - - - {/* 内容容器 */} - - - - {/* 左侧文本内容 */} - - - - {/* 标签 */} - - - - AI-Assisted Curation - - - - {/* 主标题 */} - - - - ME-Agent - -
- - 实时分析系统 - -
-
- - {/* 副标题 */} - - - 基于微调版{' '} - - deepseek-r1 - {' '} - 进行深度研究 - - - - {/* 描述文本 */} - - - ME (Money Edge) 是一款以大模型为底座、由资深分析师参与校准的信息辅助系统, - 专为金融研究与企业决策等场景设计。系统侧重于多源信息的汇聚、清洗与结构化整理, - 结合自主训练的领域知识图谱,并配合专家人工复核与整合,帮助用户高效获取相关线索与参考资料。 - - - - {/* 特性标签 */} - - - {['海量信息整理', '领域知识图谱', '分析师复核', '结构化呈现'].map((tag) => ( - - {tag} - - ))} - - - - {/* 按钮组 */} - - - - - - - {/* 统计数据 */} - - - {[ - { label: '数据源', value: '10K+' }, - { label: '日处理', value: '1M+' }, - { label: '准确率', value: '98%' } - ].map((stat) => ( - - - {stat.value} - - - {stat.label} - - - ))} - - -
-
-
- - {/* 右侧金融图表可视化 */} - - - - {/* 图表网格布局 */} - - {/* 上证指数 */} - - - - - - - {/* 深证成指 */} - - - - - - - {/* 创业板指 */} - - - - - - - - {/* 装饰性光效 */} - - - - - - - -
-
- - {/* 底部渐变遮罩 */} - - - {/* 全局样式 */} - - - ); -} \ No newline at end of file diff --git a/src/views/Home/HomePage.js b/src/views/Home/HomePage.js index 0a7f5321..fed74cf1 100755 --- a/src/views/Home/HomePage.js +++ b/src/views/Home/HomePage.js @@ -20,7 +20,6 @@ import { useNavigate } from 'react-router-dom'; import heroBg from '../../assets/img/BackgroundCard1.png'; import '../../styles/home-animations.css'; import { logger } from '../../utils/logger'; -import MidjourneyHeroSection from '../Community/components/MidjourneyHeroSection'; import { usePostHogTrack } from '../../hooks/usePostHogRedux'; import { ACQUISITION_EVENTS } from '../../lib/constants'; @@ -377,10 +376,6 @@ export default function HomePage() {
- - - {/* Midjourney风格英雄区域 */} -