From 50d59fd2ad076aa450797c4711fbb39c180276f4 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Thu, 18 Dec 2025 18:27:57 +0800 Subject: [PATCH] =?UTF-8?q?perf(DeepAnalysis):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8A=A0=E8=BD=BD=EF=BC=8C=E5=8F=AA=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=20comprehensive=20=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除初始加载时的 industryRank 请求 - 只加载默认 Tab(战略分析)需要的核心数据 - 其他数据按需懒加载 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/components/FUI/AmbientGlow.tsx | 81 +++++++++++ src/components/FUI/FuiContainer.tsx | 93 +++++++++++++ src/components/FUI/FuiCorners.tsx | 126 ++++++++++++++++++ src/components/FUI/index.ts | 12 ++ src/hooks/useDocumentTitle.ts | 80 +++++++++++ .../shareholder/ConcentrationCard.tsx | 4 +- .../shareholder/ShareholdersTable.tsx | 4 +- .../Company/components/DeepAnalysis/index.js | 3 +- .../StockSummaryCard/MetricCard.tsx | 4 +- .../StockSummaryCard/StockHeaderCard.tsx | 4 +- .../components/StockSummaryCard/index.tsx | 4 +- src/views/Company/index.tsx | 102 +------------- 12 files changed, 410 insertions(+), 107 deletions(-) create mode 100644 src/components/FUI/AmbientGlow.tsx create mode 100644 src/components/FUI/FuiContainer.tsx create mode 100644 src/components/FUI/FuiCorners.tsx create mode 100644 src/components/FUI/index.ts create mode 100644 src/hooks/useDocumentTitle.ts diff --git a/src/components/FUI/AmbientGlow.tsx b/src/components/FUI/AmbientGlow.tsx new file mode 100644 index 00000000..9d202708 --- /dev/null +++ b/src/components/FUI/AmbientGlow.tsx @@ -0,0 +1,81 @@ +/** + * 环境光效果组件 + * James Turrell 风格的背景光晕效果 + */ + +import React, { memo } from 'react'; +import { Box, BoxProps } from '@chakra-ui/react'; + +export interface AmbientGlowProps extends Omit { + /** 预设主题 */ + variant?: 'default' | 'gold' | 'blue' | 'purple' | 'warm'; + /** 自定义渐变(覆盖 variant) */ + customGradient?: string; +} + +// 预设光效配置 +const GLOW_VARIANTS = { + default: ` + radial-gradient(ellipse 100% 80% at 50% -20%, rgba(212, 175, 55, 0.08), transparent 50%), + radial-gradient(ellipse 60% 50% at 0% 50%, rgba(100, 200, 255, 0.04), transparent 40%), + radial-gradient(ellipse 60% 50% at 100% 50%, rgba(255, 200, 100, 0.04), transparent 40%) + `, + gold: ` + radial-gradient(ellipse 100% 80% at 50% -20%, rgba(212, 175, 55, 0.12), transparent 50%), + radial-gradient(ellipse 80% 60% at 20% 80%, rgba(212, 175, 55, 0.06), transparent 40%), + radial-gradient(ellipse 80% 60% at 80% 80%, rgba(255, 200, 100, 0.05), transparent 40%) + `, + blue: ` + radial-gradient(ellipse 100% 80% at 50% -20%, rgba(100, 200, 255, 0.1), transparent 50%), + radial-gradient(ellipse 60% 50% at 0% 50%, rgba(60, 160, 255, 0.06), transparent 40%), + radial-gradient(ellipse 60% 50% at 100% 50%, rgba(140, 220, 255, 0.05), transparent 40%) + `, + purple: ` + radial-gradient(ellipse 100% 80% at 50% -20%, rgba(160, 100, 255, 0.1), transparent 50%), + radial-gradient(ellipse 60% 50% at 0% 50%, rgba(200, 150, 255, 0.05), transparent 40%), + radial-gradient(ellipse 60% 50% at 100% 50%, rgba(120, 80, 255, 0.05), transparent 40%) + `, + warm: ` + radial-gradient(ellipse 100% 80% at 50% -20%, rgba(255, 150, 100, 0.1), transparent 50%), + radial-gradient(ellipse 60% 50% at 0% 50%, rgba(255, 200, 150, 0.05), transparent 40%), + radial-gradient(ellipse 60% 50% at 100% 50%, rgba(255, 180, 120, 0.05), transparent 40%) + `, +}; + +/** + * 环境光效果组件 + * 创建 James Turrell 风格的微妙背景光晕 + * + * @example + * ```tsx + * + * + * {children} + * + * ``` + */ +const AmbientGlow = memo(({ + variant = 'default', + customGradient, + ...boxProps +}) => { + const gradient = customGradient || GLOW_VARIANTS[variant]; + + return ( + + ); +}); + +AmbientGlow.displayName = 'AmbientGlow'; + +export default AmbientGlow; diff --git a/src/components/FUI/FuiContainer.tsx b/src/components/FUI/FuiContainer.tsx new file mode 100644 index 00000000..5d940820 --- /dev/null +++ b/src/components/FUI/FuiContainer.tsx @@ -0,0 +1,93 @@ +/** + * FUI 毛玻璃容器组件 + * 科幻风格的 Glassmorphism 容器,带角落装饰 + */ + +import React, { memo, ReactNode } from 'react'; +import { Box, BoxProps } from '@chakra-ui/react'; +import FuiCorners, { FuiCornersProps } from './FuiCorners'; + +export interface FuiContainerProps extends Omit { + children: ReactNode; + /** 是否显示角落装饰 */ + showCorners?: boolean; + /** 角落装饰配置 */ + cornersProps?: FuiCornersProps; + /** 预设主题 */ + variant?: 'default' | 'gold' | 'blue' | 'dark'; +} + +// 预设主题配置 +const VARIANTS = { + default: { + bg: 'linear-gradient(145deg, rgba(26, 26, 46, 0.95) 0%, rgba(15, 15, 26, 0.98) 100%)', + borderColor: 'rgba(212, 175, 55, 0.15)', + boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.05)', + cornerColor: 'rgba(212, 175, 55, 0.4)', + }, + gold: { + bg: 'linear-gradient(145deg, rgba(26, 26, 46, 0.95) 0%, rgba(15, 15, 26, 0.98) 100%)', + borderColor: 'rgba(212, 175, 55, 0.2)', + boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(212, 175, 55, 0.1)', + cornerColor: 'rgba(212, 175, 55, 0.5)', + }, + blue: { + bg: 'linear-gradient(145deg, rgba(20, 30, 48, 0.95) 0%, rgba(10, 15, 26, 0.98) 100%)', + borderColor: 'rgba(100, 200, 255, 0.15)', + boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(100, 200, 255, 0.05)', + cornerColor: 'rgba(100, 200, 255, 0.4)', + }, + dark: { + bg: 'linear-gradient(145deg, rgba(18, 18, 28, 0.98) 0%, rgba(8, 8, 16, 0.99) 100%)', + borderColor: 'rgba(255, 255, 255, 0.08)', + boxShadow: '0 8px 32px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.03)', + cornerColor: 'rgba(255, 255, 255, 0.2)', + }, +}; + +/** + * FUI 毛玻璃容器组件 + * 带有科幻风格角落装饰的 Glassmorphism 容器 + * + * @example + * ```tsx + * + * + * + * ``` + */ +const FuiContainer = memo(({ + children, + showCorners = true, + cornersProps, + variant = 'default', + ...boxProps +}) => { + const theme = VARIANTS[variant]; + + return ( + + {showCorners && ( + + )} + {children} + + ); +}); + +FuiContainer.displayName = 'FuiContainer'; + +export default FuiContainer; diff --git a/src/components/FUI/FuiCorners.tsx b/src/components/FUI/FuiCorners.tsx new file mode 100644 index 00000000..632d0fda --- /dev/null +++ b/src/components/FUI/FuiCorners.tsx @@ -0,0 +1,126 @@ +/** + * FUI 角落装饰组件 + * Ash Thorp 风格的科幻 UI 角落装饰 + */ + +import React, { memo } from 'react'; +import { Box, BoxProps } from '@chakra-ui/react'; + +export interface FuiCornersProps { + /** 装饰框大小 */ + size?: number; + /** 边框宽度 */ + borderWidth?: number; + /** 边框颜色 */ + borderColor?: string; + /** 透明度 */ + opacity?: number; + /** 距离容器边缘的距离 */ + offset?: number; +} + +interface CornerBoxProps extends BoxProps { + position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; + size: number; + borderWidth: number; + borderColor: string; + opacity: number; + offset: number; +} + +const CornerBox = memo(({ + position, + size, + borderWidth, + borderColor, + opacity, + offset, +}) => { + const positionStyles: Record = { + 'top-left': { + top: `${offset}px`, + left: `${offset}px`, + borderTop: `${borderWidth}px solid`, + borderLeft: `${borderWidth}px solid`, + }, + 'top-right': { + top: `${offset}px`, + right: `${offset}px`, + borderTop: `${borderWidth}px solid`, + borderRight: `${borderWidth}px solid`, + }, + 'bottom-left': { + bottom: `${offset}px`, + left: `${offset}px`, + borderBottom: `${borderWidth}px solid`, + borderLeft: `${borderWidth}px solid`, + }, + 'bottom-right': { + bottom: `${offset}px`, + right: `${offset}px`, + borderBottom: `${borderWidth}px solid`, + borderRight: `${borderWidth}px solid`, + }, + }; + + return ( + + ); +}); + +CornerBox.displayName = 'CornerBox'; + +/** + * FUI 角落装饰组件 + * 在容器四角添加科幻风格的装饰边框 + * + * @example + * ```tsx + * + * + * {children} + * + * ``` + */ +const FuiCorners = memo(({ + size = 16, + borderWidth = 2, + borderColor = 'rgba(212, 175, 55, 0.4)', + opacity = 0.6, + offset = 12, +}) => { + const positions: CornerBoxProps['position'][] = [ + 'top-left', + 'top-right', + 'bottom-left', + 'bottom-right', + ]; + + return ( + <> + {positions.map((position) => ( + + ))} + + ); +}); + +FuiCorners.displayName = 'FuiCorners'; + +export default FuiCorners; diff --git a/src/components/FUI/index.ts b/src/components/FUI/index.ts new file mode 100644 index 00000000..741e91d7 --- /dev/null +++ b/src/components/FUI/index.ts @@ -0,0 +1,12 @@ +/** + * FUI (Futuristic UI) 组件集合 + * Ash Thorp 风格的科幻 UI 组件 + */ + +export { default as FuiCorners } from './FuiCorners'; +export { default as FuiContainer } from './FuiContainer'; +export { default as AmbientGlow } from './AmbientGlow'; + +export type { FuiCornersProps } from './FuiCorners'; +export type { FuiContainerProps } from './FuiContainer'; +export type { AmbientGlowProps } from './AmbientGlow'; diff --git a/src/hooks/useDocumentTitle.ts b/src/hooks/useDocumentTitle.ts new file mode 100644 index 00000000..cee92322 --- /dev/null +++ b/src/hooks/useDocumentTitle.ts @@ -0,0 +1,80 @@ +/** + * 动态设置网页标题的 Hook + */ + +import { useEffect } from 'react'; + +export interface UseDocumentTitleOptions { + /** 基础标题(默认:价值前沿) */ + baseTitle?: string; + /** 是否在组件卸载时恢复基础标题 */ + restoreOnUnmount?: boolean; +} + +/** + * 动态设置网页标题 + * + * @param title - 要显示的标题(会与 baseTitle 组合) + * @param options - 配置选项 + * + * @example + * ```tsx + * // 基础用法 + * useDocumentTitle('我的页面'); + * // 结果: "我的页面 - 价值前沿" + * + * // 股票页面 + * useDocumentTitle(stockName ? `${stockName}(${stockCode})` : stockCode); + * // 结果: "平安银行(000001) - 价值前沿" + * + * // 自定义基础标题 + * useDocumentTitle('Dashboard', { baseTitle: 'My App' }); + * // 结果: "Dashboard - My App" + * ``` + */ +export const useDocumentTitle = ( + title?: string | null, + options: UseDocumentTitleOptions = {} +): void => { + const { baseTitle = '价值前沿', restoreOnUnmount = true } = options; + + useEffect(() => { + if (title) { + document.title = `${title} - ${baseTitle}`; + } else { + document.title = baseTitle; + } + + // 组件卸载时恢复默认标题 + if (restoreOnUnmount) { + return () => { + document.title = baseTitle; + }; + } + }, [title, baseTitle, restoreOnUnmount]); +}; + +/** + * 股票页面专用的标题 Hook + * + * @param stockCode - 股票代码 + * @param stockName - 股票名称(可选) + * + * @example + * ```tsx + * useStockDocumentTitle('000001', '平安银行'); + * // 结果: "平安银行(000001) - 价值前沿" + * ``` + */ +export const useStockDocumentTitle = ( + stockCode: string, + stockName?: string | null +): void => { + const title = stockName + ? `${stockName}(${stockCode})` + : stockCode || null; + + useDocumentTitle(title); +}; + +export default useDocumentTitle; diff --git a/src/views/Company/components/CompanyOverview/components/shareholder/ConcentrationCard.tsx b/src/views/Company/components/CompanyOverview/components/shareholder/ConcentrationCard.tsx index f66773b0..0cad157d 100644 --- a/src/views/Company/components/CompanyOverview/components/shareholder/ConcentrationCard.tsx +++ b/src/views/Company/components/CompanyOverview/components/shareholder/ConcentrationCard.tsx @@ -1,7 +1,7 @@ // src/views/Company/components/CompanyOverview/components/shareholder/ConcentrationCard.tsx // 股权集中度卡片组件 -import React, { useMemo, useRef, useEffect } from "react"; +import React, { useMemo, useRef, useEffect, memo } from "react"; import { Box, VStack, @@ -233,4 +233,4 @@ const ConcentrationCard: React.FC = ({ concentration = [ ); }; -export default ConcentrationCard; +export default memo(ConcentrationCard); diff --git a/src/views/Company/components/CompanyOverview/components/shareholder/ShareholdersTable.tsx b/src/views/Company/components/CompanyOverview/components/shareholder/ShareholdersTable.tsx index 3fbbab47..1967d254 100644 --- a/src/views/Company/components/CompanyOverview/components/shareholder/ShareholdersTable.tsx +++ b/src/views/Company/components/CompanyOverview/components/shareholder/ShareholdersTable.tsx @@ -1,7 +1,7 @@ // src/views/Company/components/CompanyOverview/components/shareholder/ShareholdersTable.tsx // 股东表格组件(合并版)- 支持十大股东和十大流通股东 -import React, { useMemo } from "react"; +import React, { useMemo, memo } from "react"; import { Box, HStack, Heading, Badge, Icon, useBreakpointValue } from "@chakra-ui/react"; import { Table, Tag, Tooltip, ConfigProvider } from "antd"; import type { ColumnsType } from "antd/es/table"; @@ -225,4 +225,4 @@ const ShareholdersTable: React.FC = ({ ); }; -export default ShareholdersTable; +export default memo(ShareholdersTable); diff --git a/src/views/Company/components/DeepAnalysis/index.js b/src/views/Company/components/DeepAnalysis/index.js index dbad8316..c21e69a3 100644 --- a/src/views/Company/components/DeepAnalysis/index.js +++ b/src/views/Company/components/DeepAnalysis/index.js @@ -189,9 +189,8 @@ const DeepAnalysis = ({ stockCode }) => { // 重置为默认 Tab 并加载数据 setActiveTab("strategy"); - // 加载默认 Tab 的数据(战略分析需要 comprehensive 和 industryRank) + // 只加载默认 Tab 的核心数据(comprehensive),其他数据按需加载 loadApiData("comprehensive"); - loadApiData("industryRank"); } }, [stockCode, loadApiData]); diff --git a/src/views/Company/components/MarketDataView/components/StockSummaryCard/MetricCard.tsx b/src/views/Company/components/MarketDataView/components/StockSummaryCard/MetricCard.tsx index 68d07cbb..1c9620d8 100644 --- a/src/views/Company/components/MarketDataView/components/StockSummaryCard/MetricCard.tsx +++ b/src/views/Company/components/MarketDataView/components/StockSummaryCard/MetricCard.tsx @@ -1,5 +1,5 @@ // 指标卡片组件 - FUI 科幻风格 -import React from 'react'; +import React, { memo } from 'react'; import { Box, VStack } from '@chakra-ui/react'; import { DarkGoldCard, CardTitle, MetricValue } from './atoms'; import { darkGoldTheme } from '../../constants'; @@ -125,4 +125,4 @@ const MetricCard: React.FC = ({ ); }; -export default MetricCard; +export default memo(MetricCard); diff --git a/src/views/Company/components/MarketDataView/components/StockSummaryCard/StockHeaderCard.tsx b/src/views/Company/components/MarketDataView/components/StockSummaryCard/StockHeaderCard.tsx index c290c7cb..effb2e6d 100644 --- a/src/views/Company/components/MarketDataView/components/StockSummaryCard/StockHeaderCard.tsx +++ b/src/views/Company/components/MarketDataView/components/StockSummaryCard/StockHeaderCard.tsx @@ -1,5 +1,5 @@ // 股票信息卡片组件(4列布局版本)- FUI 科幻风格 -import React from 'react'; +import React, { memo } from 'react'; import { Box, HStack, VStack, Text, Icon, Badge } from '@chakra-ui/react'; import { TrendingUp, TrendingDown, Activity } from 'lucide-react'; import { DarkGoldCard } from './atoms'; @@ -206,4 +206,4 @@ const StockHeaderCard: React.FC = ({ ); }; -export default StockHeaderCard; +export default memo(StockHeaderCard); diff --git a/src/views/Company/components/MarketDataView/components/StockSummaryCard/index.tsx b/src/views/Company/components/MarketDataView/components/StockSummaryCard/index.tsx index bd1ba208..eb776098 100644 --- a/src/views/Company/components/MarketDataView/components/StockSummaryCard/index.tsx +++ b/src/views/Company/components/MarketDataView/components/StockSummaryCard/index.tsx @@ -1,5 +1,5 @@ // StockSummaryCard 主组件 -import React from 'react'; +import React, { memo } from 'react'; import { SimpleGrid, HStack, Text, VStack } from '@chakra-ui/react'; import { Flame, Coins, DollarSign, Shield } from 'lucide-react'; import StockHeaderCard from './StockHeaderCard'; @@ -111,4 +111,4 @@ const StockSummaryCard: React.FC = ({ summary }) => { ); }; -export default StockSummaryCard; +export default memo(StockSummaryCard); diff --git a/src/views/Company/index.tsx b/src/views/Company/index.tsx index 94a985e4..4697942c 100644 --- a/src/views/Company/index.tsx +++ b/src/views/Company/index.tsx @@ -16,6 +16,8 @@ import './theme/fui-animations.css'; import { useSearchParams } from 'react-router-dom'; import { Box } from '@chakra-ui/react'; import SubTabContainer from '@components/SubTabContainer'; +import { FuiContainer, AmbientGlow } from '@components/FUI'; +import { useStockDocumentTitle } from '@hooks/useDocumentTitle'; import { useCompanyEvents } from './hooks/useCompanyEvents'; import { useCompanyData } from './hooks/useCompanyData'; import CompanyHeader from './components/CompanyHeader'; @@ -52,63 +54,8 @@ const CompanyContent = memo(({ /> - {/* Tab 内容区 */} - - {/* 角落装饰 - FUI 风格 */} - - - - - + {/* Tab 内容区 - 使用 FuiContainer */} + (({ contentPadding={0} isLazy={true} /> - + )); CompanyContent.displayName = 'CompanyContent'; -// ============================================ -// 网页标题 Hook -// ============================================ - -const useDocumentTitle = (stockCode: string, stockName?: string) => { - useEffect(() => { - const baseTitle = '价值前沿'; - if (stockName) { - document.title = `${stockName}(${stockCode}) - ${baseTitle}`; - } else if (stockCode) { - document.title = `${stockCode} - ${baseTitle}`; - } else { - document.title = baseTitle; - } - - // 组件卸载时恢复默认标题 - return () => { - document.title = baseTitle; - }; - }, [stockCode, stockName]); -}; - // ============================================ // 主页面组件 // ============================================ @@ -175,7 +100,7 @@ const CompanyIndex: React.FC = () => { const { trackStockSearched, trackTabChanged, trackWatchlistAdded, trackWatchlistRemoved } = companyEvents; // 设置网页标题 - useDocumentTitle(stockCode, stockInfo?.stock_name); + useStockDocumentTitle(stockCode, stockInfo?.stock_name); // 股票代码变化追踪 useEffect(() => { @@ -220,20 +145,7 @@ const CompanyIndex: React.FC = () => { overflow="hidden" > {/* 全局环境光效果 - James Turrell 风格 */} - + {/* 顶部搜索栏 */}