From c0d8bf20a3d8ff72b1820de22fdacbcfa48bb376 Mon Sep 17 00:00:00 2001
From: zdl <3489966805@qq.com>
Date: Wed, 3 Dec 2025 17:15:48 +0800
Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E9=A6=96=E9=A1=B5=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/Home/HomePage.tsx | 29 +++----
src/views/Home/components/HeroBackground.tsx | 87 --------------------
2 files changed, 10 insertions(+), 106 deletions(-)
delete mode 100644 src/views/Home/components/HeroBackground.tsx
diff --git a/src/views/Home/HomePage.tsx b/src/views/Home/HomePage.tsx
index 38f1484e..ef50e489 100644
--- a/src/views/Home/HomePage.tsx
+++ b/src/views/Home/HomePage.tsx
@@ -1,7 +1,7 @@
// src/views/Home/HomePage.tsx
// 首页 - 专业投资分析平台
-import React, { useEffect, useCallback, useState } from 'react';
+import React, { useEffect, useCallback, useRef } from 'react';
import { Box, Container, VStack, SimpleGrid } from '@chakra-ui/react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '@/contexts/AuthContext';
@@ -11,7 +11,6 @@ import { ACQUISITION_EVENTS } from '@/lib/constants';
import { CORE_FEATURES } from '@/constants/homeFeatures';
import { performanceMonitor } from '@/utils/performanceMonitor';
import type { Feature } from '@/types/home';
-import { HeroBackground } from './components/HeroBackground';
import { HeroHeader } from './components/HeroHeader';
import { FeaturedFeatureCard } from './components/FeaturedFeatureCard';
import { FeatureCard } from './components/FeatureCard';
@@ -25,7 +24,13 @@ const HomePage: React.FC = () => {
const { user, isAuthenticated } = useAuth();
const navigate = useNavigate();
const { track } = usePostHogTrack();
- const [imageLoaded, setImageLoaded] = useState(false);
+
+ // ⚡ 性能标记:渲染开始(组件函数执行时,使用 ref 避免严格模式下重复标记)
+ const hasMarkedStart = useRef(false);
+ if (!hasMarkedStart.current) {
+ performanceMonitor.mark('homepage-render-start');
+ hasMarkedStart.current = true;
+ }
// 响应式配置
const {
@@ -34,12 +39,11 @@ const HomePage: React.FC = () => {
headingLetterSpacing,
heroTextSize,
containerPx,
- showDecorations
} = useHomeResponsive();
- // ⚡ 性能标记:首页组件挂载 = 渲染开始
+ // ⚡ 性能标记:渲染完成(DOM 已挂载)
useEffect(() => {
- performanceMonitor.mark('homepage-render-start');
+ performanceMonitor.mark('homepage-render-end');
}, []);
// PostHog 追踪:页面浏览
@@ -70,13 +74,6 @@ const HomePage: React.FC = () => {
}
}, [track, navigate]);
- // 背景图片加载完成回调
- const handleImageLoad = useCallback(() => {
- setImageLoaded(true);
- // ⚡ 性能标记:首页渲染完成(背景图片加载完成 = 首屏视觉完整)
- performanceMonitor.mark('homepage-render-end');
- }, []);
-
// 特色功能(第一个)
const featuredFeature = CORE_FEATURES[0];
// 其他功能
@@ -91,12 +88,6 @@ const HomePage: React.FC = () => {
bg="linear-gradient(135deg, #0E0C15 0%, #15131D 50%, #252134 100%)"
overflow="hidden"
>
- {/* 背景装饰 */}
-
void;
- showDecorations: boolean | undefined;
-}
-
-/**
- * 首页英雄区背景组件
- * 包含背景图片和装饰性几何图形
- */
-export const HeroBackground: React.FC = ({
- imageLoaded,
- onImageLoad,
- showDecorations
-}) => {
- return (
- <>
- {/* 背景图片 */}
-
-
- {/* 预加载背景图片 */}
-
-
-
-
- {/* 装饰性几何图形 - 移动端隐藏 */}
- {showDecorations && (
- <>
-
-
- >
- )}
- >
- );
-};
From cdca8890831f9d1b8200d8e536a081b29e607324 Mon Sep 17 00:00:00 2001
From: zdl <3489966805@qq.com>
Date: Wed, 3 Dec 2025 17:28:23 +0800
Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E5=8E=BB=E9=99=A4=E4=B8=AA=E8=82=A1?=
=?UTF-8?q?=E4=B8=AD=E5=BF=83=E5=8A=A8=E7=94=BB=EF=BC=8C=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?mock=E6=95=B0=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/mocks/handlers/market.js | 193 +++++++++++++++++++++++++++++++
src/views/StockOverview/index.js | 20 +---
2 files changed, 195 insertions(+), 18 deletions(-)
diff --git a/src/mocks/handlers/market.js b/src/mocks/handlers/market.js
index e9515767..28757c99 100644
--- a/src/mocks/handlers/market.js
+++ b/src/mocks/handlers/market.js
@@ -71,4 +71,197 @@ export const marketHandlers = [
const data = generateMarketData(stockCode);
return HttpResponse.json(data.latestMinuteData);
}),
+
+ // 9. 热门概念数据(个股中心页面使用)
+ http.get('/api/concepts/daily-top', async ({ request }) => {
+ await delay(300);
+ const url = new URL(request.url);
+ const limit = parseInt(url.searchParams.get('limit') || '6');
+ const date = url.searchParams.get('date');
+
+ // 获取当前日期或指定日期
+ const tradeDate = date || new Date().toISOString().split('T')[0];
+
+ // 热门概念列表
+ const conceptPool = [
+ { name: '人工智能', desc: '人工智能是"技术突破+政策扶持"双轮驱动的硬科技主题。随着大模型技术的突破,AI应用场景不断拓展。' },
+ { name: '新能源汽车', desc: '新能源汽车行业景气度持续向好,渗透率不断提升。政策支持力度大,产业链上下游企业均受益。' },
+ { name: '半导体', desc: '国产半导体替代加速,自主可控需求强烈。政策和资金支持力度大,行业迎来黄金发展期。' },
+ { name: '光伏', desc: '光伏装机量快速增长,成本持续下降,行业景气度维持高位。双碳目标下前景广阔。' },
+ { name: '锂电池', desc: '锂电池技术进步,成本优势扩大,下游应用领域持续扩张。新能源汽车和储能需求旺盛。' },
+ { name: '储能', desc: '储能市场爆发式增长,政策支持力度大,应用场景不断拓展。未来市场空间巨大。' },
+ { name: '算力', desc: 'AI大模型推动算力需求爆发,数据中心、服务器、芯片等产业链受益明显。' },
+ { name: '机器人', desc: '人形机器人产业化加速,特斯拉、小米等巨头入局,产业链迎来发展机遇。' },
+ ];
+
+ // 股票池
+ const stockPool = [
+ { stock_code: '600519', stock_name: '贵州茅台' },
+ { stock_code: '300750', stock_name: '宁德时代' },
+ { stock_code: '601318', stock_name: '中国平安' },
+ { stock_code: '002594', stock_name: '比亚迪' },
+ { stock_code: '601012', stock_name: '隆基绿能' },
+ { stock_code: '300274', stock_name: '阳光电源' },
+ { stock_code: '688981', stock_name: '中芯国际' },
+ { stock_code: '000725', stock_name: '京东方A' },
+ ];
+
+ // 生成概念数据
+ const concepts = [];
+ for (let i = 0; i < Math.min(limit, conceptPool.length); i++) {
+ const concept = conceptPool[i];
+ const changePercent = parseFloat((Math.random() * 8 - 1).toFixed(2)); // -1% ~ 7%
+ const stockCount = Math.floor(Math.random() * 40) + 20; // 20-60只股票
+
+ // 随机选取3-4只相关股票
+ const relatedStocks = [];
+ const stockIndices = new Set();
+ while (stockIndices.size < Math.min(4, stockPool.length)) {
+ stockIndices.add(Math.floor(Math.random() * stockPool.length));
+ }
+ stockIndices.forEach(idx => relatedStocks.push(stockPool[idx]));
+
+ concepts.push({
+ concept_id: `CONCEPT_${1001 + i}`,
+ concept_name: concept.name,
+ change_percent: changePercent,
+ stock_count: stockCount,
+ description: concept.desc,
+ stocks: relatedStocks
+ });
+ }
+
+ // 按涨跌幅降序排序
+ concepts.sort((a, b) => b.change_percent - a.change_percent);
+
+ console.log('[Mock Market] 获取热门概念:', { limit, date: tradeDate, count: concepts.length });
+
+ return HttpResponse.json({
+ success: true,
+ data: concepts,
+ trade_date: tradeDate
+ });
+ }),
+
+ // 10. 市值热力图数据(个股中心页面使用)
+ http.get('/api/market/heatmap', async ({ request }) => {
+ await delay(400);
+ const url = new URL(request.url);
+ const limit = parseInt(url.searchParams.get('limit') || '500');
+ const date = url.searchParams.get('date');
+
+ const tradeDate = date || new Date().toISOString().split('T')[0];
+
+ // 行业列表
+ const industries = ['食品饮料', '银行', '医药生物', '电子', '计算机', '汽车', '电力设备', '机械设备', '化工', '房地产', '有色金属', '钢铁'];
+ const provinces = ['北京', '上海', '广东', '浙江', '江苏', '山东', '四川', '湖北', '福建', '安徽'];
+
+ // 常见股票数据
+ const majorStocks = [
+ { code: '600519', name: '贵州茅台', cap: 1850, industry: '食品饮料', province: '贵州' },
+ { code: '601318', name: '中国平安', cap: 920, industry: '保险', province: '广东' },
+ { code: '600036', name: '招商银行', cap: 850, industry: '银行', province: '广东' },
+ { code: '300750', name: '宁德时代', cap: 780, industry: '电力设备', province: '福建' },
+ { code: '601166', name: '兴业银行', cap: 420, industry: '银行', province: '福建' },
+ { code: '000858', name: '五粮液', cap: 580, industry: '食品饮料', province: '四川' },
+ { code: '002594', name: '比亚迪', cap: 650, industry: '汽车', province: '广东' },
+ { code: '601012', name: '隆基绿能', cap: 320, industry: '电力设备', province: '陕西' },
+ { code: '688981', name: '中芯国际', cap: 280, industry: '电子', province: '上海' },
+ { code: '600900', name: '长江电力', cap: 520, industry: '公用事业', province: '湖北' },
+ ];
+
+ // 生成热力图数据
+ const heatmapData = [];
+ let risingCount = 0;
+ let fallingCount = 0;
+
+ // 先添加主要股票
+ majorStocks.forEach(stock => {
+ const changePercent = parseFloat((Math.random() * 12 - 4).toFixed(2)); // -4% ~ 8%
+ const amount = parseFloat((Math.random() * 100 + 10).toFixed(2)); // 10-110亿
+
+ if (changePercent > 0) risingCount++;
+ else if (changePercent < 0) fallingCount++;
+
+ heatmapData.push({
+ stock_code: stock.code,
+ stock_name: stock.name,
+ market_cap: stock.cap,
+ change_percent: changePercent,
+ amount: amount,
+ industry: stock.industry,
+ province: stock.province
+ });
+ });
+
+ // 生成更多随机股票数据
+ for (let i = majorStocks.length; i < Math.min(limit, 200); i++) {
+ const changePercent = parseFloat((Math.random() * 14 - 5).toFixed(2)); // -5% ~ 9%
+ const marketCap = parseFloat((Math.random() * 500 + 20).toFixed(2)); // 20-520亿
+ const amount = parseFloat((Math.random() * 50 + 1).toFixed(2)); // 1-51亿
+
+ if (changePercent > 0) risingCount++;
+ else if (changePercent < 0) fallingCount++;
+
+ heatmapData.push({
+ stock_code: `${600000 + i}`,
+ stock_name: `股票${i}`,
+ market_cap: marketCap,
+ change_percent: changePercent,
+ amount: amount,
+ industry: industries[Math.floor(Math.random() * industries.length)],
+ province: provinces[Math.floor(Math.random() * provinces.length)]
+ });
+ }
+
+ console.log('[Mock Market] 获取热力图数据:', { limit, date: tradeDate, count: heatmapData.length });
+
+ return HttpResponse.json({
+ success: true,
+ data: heatmapData,
+ trade_date: tradeDate,
+ statistics: {
+ rising_count: risingCount,
+ falling_count: fallingCount
+ }
+ });
+ }),
+
+ // 11. 市场统计数据(个股中心页面使用)
+ http.get('/api/market/statistics', async ({ request }) => {
+ await delay(200);
+ const url = new URL(request.url);
+ const date = url.searchParams.get('date');
+
+ const tradeDate = date || new Date().toISOString().split('T')[0];
+
+ // 生成最近30个交易日
+ const availableDates = [];
+ const currentDate = new Date(tradeDate);
+ for (let i = 0; i < 30; i++) {
+ const d = new Date(currentDate);
+ d.setDate(d.getDate() - i);
+ // 跳过周末
+ if (d.getDay() !== 0 && d.getDay() !== 6) {
+ availableDates.push(d.toISOString().split('T')[0]);
+ }
+ }
+
+ console.log('[Mock Market] 获取市场统计数据:', { date: tradeDate });
+
+ return HttpResponse.json({
+ success: true,
+ summary: {
+ total_market_cap: parseFloat((Math.random() * 5000 + 80000).toFixed(2)), // 80000-85000亿
+ total_amount: parseFloat((Math.random() * 3000 + 8000).toFixed(2)), // 8000-11000亿
+ avg_pe: parseFloat((Math.random() * 5 + 12).toFixed(2)), // 12-17
+ avg_pb: parseFloat((Math.random() * 0.5 + 1.3).toFixed(2)), // 1.3-1.8
+ rising_stocks: Math.floor(Math.random() * 1500 + 1500), // 1500-3000
+ falling_stocks: Math.floor(Math.random() * 1500 + 1000), // 1000-2500
+ unchanged_stocks: Math.floor(Math.random() * 200 + 100) // 100-300
+ },
+ trade_date: tradeDate,
+ available_dates: availableDates.slice(0, 20) // 返回最近20个交易日
+ });
+ }),
];
diff --git a/src/views/StockOverview/index.js b/src/views/StockOverview/index.js
index 52da86e9..1dde440b 100644
--- a/src/views/StockOverview/index.js
+++ b/src/views/StockOverview/index.js
@@ -42,7 +42,6 @@ import {
useDisclosure,
Image,
Fade,
- ScaleFade,
Collapse,
Stack,
Progress,
@@ -58,25 +57,12 @@ import {
import { SearchIcon, CloseIcon, ArrowForwardIcon, TrendingUpIcon, InfoIcon, ChevronRightIcon, MoonIcon, SunIcon, CalendarIcon } from '@chakra-ui/icons';
import { FaChartLine, FaFire, FaRocket, FaBrain, FaCalendarAlt, FaChevronRight, FaArrowUp, FaArrowDown, FaChartBar } from 'react-icons/fa';
import { BsGraphUp, BsLightningFill } from 'react-icons/bs';
-import { keyframes } from '@emotion/react';
import * as echarts from 'echarts';
import { logger } from '../../utils/logger';
import { useStockOverviewEvents } from './hooks/useStockOverviewEvents';
// Navigation bar now provided by MainLayout
// import HomeNavbar from '../../components/Navbars/HomeNavbar';
-// 动画定义
-const pulseAnimation = keyframes`
- 0% { transform: scale(1); }
- 50% { transform: scale(1.05); }
- 100% { transform: scale(1); }
-`;
-
-const floatAnimation = keyframes`
- 0%, 100% { transform: translateY(0px); }
- 50% { transform: translateY(-10px); }
-`;
-
const StockOverview = () => {
const navigate = useNavigate();
const toast = useToast();
@@ -622,7 +608,7 @@ const StockOverview = () => {
-
+
{
) : (
{topConcepts.map((concept, index) => (
-
{
px={3}
py={1}
borderRadius="full"
- animation={Math.abs(concept.change_percent) > 5 ? `${pulseAnimation} 2s infinite` : 'none'}
border={colorMode === 'dark' ? '1px solid' : 'none'}
borderColor={colorMode === 'dark' ? concept.change_percent > 0 ? '#ff4d4d' : '#22c55e' : 'transparent'}
>
@@ -1039,7 +1024,6 @@ const StockOverview = () => {
-
))}
)}