diff --git a/src/components/SubTabContainer/index.tsx b/src/components/SubTabContainer/index.tsx index 9a413f44..84d65d1d 100644 --- a/src/components/SubTabContainer/index.tsx +++ b/src/components/SubTabContainer/index.tsx @@ -1,8 +1,10 @@ /** * SubTabContainer - 二级导航容器组件 * - * 用于模块内的子功能切换(如公司档案下的股权结构、管理团队等) - * 与 TabContainer(一级导航)区分:无 Card 包裹,直接融入父容器 + * 深空 FUI 设计风格(Glassmorphism + Ash Thorp + James Turrell) + * - 玻璃态导航栏,漂浮感 + * - 选中态发光效果,科幻数据终端感 + * - 流畅的过渡动画 * * @example * ```tsx @@ -43,6 +45,40 @@ export interface SubTabConfig { component?: ComponentType; } +/** + * 深空 FUI 主题配置 + */ +const DEEP_SPACE = { + // 背景 + bgGlass: 'rgba(12, 14, 28, 0.6)', + bgGlassHover: 'rgba(18, 22, 42, 0.7)', + + // 边框 + borderGold: 'rgba(212, 175, 55, 0.2)', + borderGoldHover: 'rgba(212, 175, 55, 0.5)', + borderGlass: 'rgba(255, 255, 255, 0.06)', + + // 发光 + glowGold: '0 0 30px rgba(212, 175, 55, 0.25), 0 4px 20px rgba(0, 0, 0, 0.3)', + innerGlow: 'inset 0 1px 0 rgba(255, 255, 255, 0.08)', + + // 文字 + textWhite: 'rgba(255, 255, 255, 0.95)', + textMuted: 'rgba(255, 255, 255, 0.6)', + textGold: '#F4D03F', + textDark: '#0A0A14', + + // 选中态 + selectedBg: 'linear-gradient(135deg, rgba(212, 175, 55, 0.95) 0%, rgba(184, 150, 12, 0.95) 100%)', + + // 圆角 + radius: '12px', + radiusLG: '16px', + + // 动画 + transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', +}; + /** * 主题配置 */ @@ -56,16 +92,16 @@ export interface SubTabTheme { } /** - * 预设主题 - FUI 风格优化 + * 预设主题 - 深空 FUI 风格 */ const THEME_PRESETS: Record = { blackGold: { - bg: 'transparent', - borderColor: 'rgba(212, 175, 55, 0.15)', - tabSelectedBg: 'linear-gradient(135deg, rgba(212, 175, 55, 0.95) 0%, rgba(184, 150, 12, 0.95) 100%)', - tabSelectedColor: '#0A0A14', - tabUnselectedColor: 'rgba(255, 255, 255, 0.85)', // 调亮:白色更清晰 - tabHoverBg: 'rgba(212, 175, 55, 0.15)', + bg: DEEP_SPACE.bgGlass, + borderColor: DEEP_SPACE.borderGold, + tabSelectedBg: DEEP_SPACE.selectedBg, + tabSelectedColor: DEEP_SPACE.textDark, + tabUnselectedColor: DEEP_SPACE.textWhite, + tabHoverBg: DEEP_SPACE.bgGlassHover, }, default: { bg: 'white', @@ -158,74 +194,102 @@ const SubTabContainer: React.FC = memo(({ index={currentIndex} onChange={handleTabChange} > + {/* TabList - 玻璃态导航栏 */} - {tabs.map((tab) => ( - - - {tab.icon && } - {tab.name} - - - ))} + {/* 顶部金色光条 */} + + + {tabs.map((tab, idx) => { + const isSelected = idx === currentIndex; + + return ( + + + {tab.icon && ( + + )} + {tab.name} + + + ); + })} {rightElement && ( <> diff --git a/src/views/Company/components/StockQuoteCard/components/theme.ts b/src/views/Company/components/StockQuoteCard/components/theme.ts index 5358a125..e9614204 100644 --- a/src/views/Company/components/StockQuoteCard/components/theme.ts +++ b/src/views/Company/components/StockQuoteCard/components/theme.ts @@ -1,20 +1,193 @@ /** - * StockQuoteCard 黑金主题配置 + * StockQuoteCard 深空 FUI 主题配置 + * + * 设计灵感: + * - Ash Thorp / Linear.app 科幻 FUI 风格 + * - James Turrell 光影艺术 + * - Glassmorphism 玻璃态设计 + * - 深空漂浮的数据终端 */ -export const STOCK_CARD_THEME = { - // 背景和边框 - cardBg: '#1A202C', - borderColor: '#C9A961', +// ============================================ +// 深空 FUI 主题系统 +// ============================================ +export const DEEP_SPACE_THEME = { + // === 深空背景层 === + // 最深层背景(宇宙深邃) + bgDeep: 'rgba(8, 8, 18, 0.98)', + // 玻璃卡片背景(半透明漂浮) + bgGlass: 'rgba(15, 18, 35, 0.65)', + bgGlassHover: 'rgba(20, 25, 50, 0.75)', + // 内嵌区块背景 + bgInset: 'rgba(10, 12, 25, 0.5)', - // 文字颜色 - labelColor: '#C9A961', - valueColor: '#F4D03F', - sectionTitleColor: '#F4D03F', + // === Glassmorphism 效果 === + blur: '24px', + blurLight: '12px', - // 涨跌颜色(红涨绿跌) - upColor: '#F44336', - downColor: '#4CAF50', + // === 边框系统 === + // 主边框(发光金边) + borderGold: 'rgba(212, 175, 55, 0.4)', + borderGoldHover: 'rgba(212, 175, 55, 0.7)', + // 玻璃边框(微妙白边) + borderGlass: 'rgba(255, 255, 255, 0.08)', + borderGlassHover: 'rgba(255, 255, 255, 0.15)', + // 分隔线 + divider: 'rgba(212, 175, 55, 0.15)', + + // === 发光系统(James Turrell 风格)=== + // 金色光晕 + glowGold: '0 0 40px rgba(212, 175, 55, 0.15), 0 0 80px rgba(212, 175, 55, 0.08)', + glowGoldHover: '0 0 60px rgba(212, 175, 55, 0.25), 0 0 120px rgba(212, 175, 55, 0.12)', + // 青色光晕(科技感) + glowCyan: '0 0 30px rgba(0, 212, 255, 0.2), 0 0 60px rgba(0, 212, 255, 0.1)', + // 漂浮阴影(深度感) + floatShadow: '0 20px 60px rgba(0, 0, 0, 0.4), 0 8px 20px rgba(0, 0, 0, 0.3)', + // 内发光(Turrell 光隧道效果) + innerGlow: 'inset 0 1px 0 rgba(255, 255, 255, 0.05), inset 0 -1px 0 rgba(0, 0, 0, 0.2)', + + // === 圆角系统(极致圆角)=== + radiusXL: '24px', + radiusLG: '16px', + radiusMD: '12px', + radiusSM: '8px', + + // === 文字颜色 === + // 主文字(高亮金色) + textPrimary: '#F4D03F', + // 次要文字(柔和金色) + textSecondary: 'rgba(212, 175, 55, 0.85)', + // 标签文字(低对比度) + textMuted: 'rgba(180, 160, 120, 0.7)', + // 纯白文字 + textWhite: 'rgba(255, 255, 255, 0.95)', + textWhiteMuted: 'rgba(255, 255, 255, 0.6)', + + // === 涨跌颜色(红涨绿跌)=== + upColor: '#FF4757', + upColorMuted: 'rgba(255, 71, 87, 0.15)', + upGlow: '0 0 20px rgba(255, 71, 87, 0.3)', + downColor: '#00D984', + downColorMuted: 'rgba(0, 217, 132, 0.15)', + downGlow: '0 0 20px rgba(0, 217, 132, 0.3)', + + // === 强调色 === + gold: '#D4AF37', + goldBright: '#F4D03F', + cyan: '#00D4FF', + purple: '#A855F7', + orange: '#FF6B35', + + // === 动画 === + transitionFast: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)', + transitionNormal: 'all 0.35s cubic-bezier(0.4, 0, 0.2, 1)', + transitionSlow: 'all 0.5s cubic-bezier(0.4, 0, 0.2, 1)', } as const; +// 兼容旧组件的导出 +export const STOCK_CARD_THEME = { + cardBg: DEEP_SPACE_THEME.bgGlass, + borderColor: DEEP_SPACE_THEME.borderGold, + labelColor: DEEP_SPACE_THEME.textSecondary, + valueColor: DEEP_SPACE_THEME.textPrimary, + sectionTitleColor: DEEP_SPACE_THEME.textPrimary, + upColor: DEEP_SPACE_THEME.upColor, + downColor: DEEP_SPACE_THEME.downColor, +} as const; + +// ============================================ +// 玻璃卡片样式生成器 +// ============================================ +export const glassCardStyle = { + // 主容器玻璃效果 + container: { + bg: DEEP_SPACE_THEME.bgGlass, + backdropFilter: `blur(${DEEP_SPACE_THEME.blur})`, + WebkitBackdropFilter: `blur(${DEEP_SPACE_THEME.blur})`, + borderRadius: DEEP_SPACE_THEME.radiusXL, + border: `1px solid ${DEEP_SPACE_THEME.borderGlass}`, + boxShadow: `${DEEP_SPACE_THEME.floatShadow}, ${DEEP_SPACE_THEME.innerGlow}`, + position: 'relative' as const, + overflow: 'hidden' as const, + transition: DEEP_SPACE_THEME.transitionNormal, + _hover: { + bg: DEEP_SPACE_THEME.bgGlassHover, + borderColor: DEEP_SPACE_THEME.borderGoldHover, + boxShadow: `${DEEP_SPACE_THEME.glowGoldHover}, ${DEEP_SPACE_THEME.floatShadow}`, + transform: 'translateY(-2px)', + }, + }, + + // 金色高亮边框版本 + containerGold: { + bg: DEEP_SPACE_THEME.bgGlass, + backdropFilter: `blur(${DEEP_SPACE_THEME.blur})`, + WebkitBackdropFilter: `blur(${DEEP_SPACE_THEME.blur})`, + borderRadius: DEEP_SPACE_THEME.radiusXL, + border: `1px solid ${DEEP_SPACE_THEME.borderGold}`, + boxShadow: `${DEEP_SPACE_THEME.glowGold}, ${DEEP_SPACE_THEME.floatShadow}, ${DEEP_SPACE_THEME.innerGlow}`, + position: 'relative' as const, + overflow: 'hidden' as const, + transition: DEEP_SPACE_THEME.transitionNormal, + _hover: { + bg: DEEP_SPACE_THEME.bgGlassHover, + borderColor: DEEP_SPACE_THEME.borderGoldHover, + boxShadow: `${DEEP_SPACE_THEME.glowGoldHover}, ${DEEP_SPACE_THEME.floatShadow}`, + transform: 'translateY(-2px)', + }, + }, + + // 内嵌区块 + insetSection: { + bg: DEEP_SPACE_THEME.bgInset, + borderRadius: DEEP_SPACE_THEME.radiusLG, + border: `1px solid ${DEEP_SPACE_THEME.borderGlass}`, + p: 4, + }, +}; + +// ============================================ +// 装饰元素 +// ============================================ +export const decorativeElements = { + // 顶部金色光条(Ash Thorp 风格) + topGlowBar: { + position: 'absolute' as const, + top: 0, + left: '50%', + transform: 'translateX(-50%)', + width: '60%', + height: '1px', + background: `linear-gradient(90deg, transparent, ${DEEP_SPACE_THEME.gold}, transparent)`, + opacity: 0.6, + }, + + // 角落光点 + cornerGlow: { + position: 'absolute' as const, + width: '80px', + height: '80px', + borderRadius: '50%', + background: `radial-gradient(circle, rgba(212, 175, 55, 0.15) 0%, transparent 70%)`, + filter: 'blur(20px)', + }, + + // 背景网格(微妙的科技感) + gridOverlay: { + position: 'absolute' as const, + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundImage: ` + linear-gradient(rgba(212, 175, 55, 0.03) 1px, transparent 1px), + linear-gradient(90deg, rgba(212, 175, 55, 0.03) 1px, transparent 1px) + `, + backgroundSize: '40px 40px', + pointerEvents: 'none' as const, + opacity: 0.5, + }, +}; + +export type DeepSpaceTheme = typeof DEEP_SPACE_THEME; export type StockCardTheme = typeof STOCK_CARD_THEME; diff --git a/src/views/Company/components/StockQuoteCard/index.tsx b/src/views/Company/components/StockQuoteCard/index.tsx index acc2b986..bab956ac 100644 --- a/src/views/Company/components/StockQuoteCard/index.tsx +++ b/src/views/Company/components/StockQuoteCard/index.tsx @@ -1,246 +1,193 @@ /** * StockQuoteCard - 股票行情卡片组件 * - * 采用四卡片布局 FUI 风格设计 - * 参考:交易热度、估值安全、情绪风险等分区展示 + * 深空 FUI 设计风格(Glassmorphism + Ash Thorp + James Turrell) + * - 半透明玻璃态卡片,漂浮在深空中 + * - 光影深度,弥散背景光 + * - 极致圆角,科幻数据终端感 + * + * 保留原有所有功能: + * - 股票头部(名称、代码、行业、对比、关注、分享) + * - 价格显示(当前价、涨跌幅) + * - 次要行情(今开、昨收、最高、最低) + * - 关键指标(PE、市值、股本、换手率、52周) + * - 主力动态(净流入、机构持仓、买卖比) + * - 公司信息(成立、注册资本、所在地、官网、简介) */ import React from 'react'; import { Box, Flex, - Grid, - VStack, HStack, - Skeleton, + VStack, Text, Badge, + IconButton, + Tooltip, + Skeleton, + Progress, + Link, Icon, useDisclosure, } from '@chakra-ui/react'; -import { TrendingUp, Activity, DollarSign, AlertTriangle } from 'lucide-react'; +import { Share2, Calendar, Coins, MapPin, Globe } from 'lucide-react'; +import FavoriteButton from '@components/FavoriteButton'; -import { StockCompareModal } from './components'; +import { StockCompareModal, CompareStockInput } from './components'; import { useStockQuoteData, useStockCompare } from './hooks'; +import { DEEP_SPACE_THEME, glassCardStyle, decorativeElements } from './components/theme'; +import { formatPrice, formatChangePercent, formatNetInflow } from './components/formatters'; +import { formatRegisteredCapital, formatDate } from '../CompanyOverview/utils'; import type { StockQuoteCardProps } from './types'; -// FUI 主题色彩 -const FUI = { - gold: '#D4AF37', - orange: '#FF6B35', - green: '#00D984', - red: '#FF4757', - cyan: '#00D4FF', - purple: '#A855F7', - bgCard: 'rgba(20, 20, 30, 0.95)', - bgCardHover: 'rgba(30, 30, 45, 0.98)', - border: 'rgba(255, 255, 255, 0.08)', - borderGold: 'rgba(212, 175, 55, 0.3)', - text: 'rgba(255, 255, 255, 0.95)', - textMuted: 'rgba(255, 255, 255, 0.6)', -}; +const T = DEEP_SPACE_THEME; -// 单个指标卡片组件 -interface MetricCardProps { - icon: React.ElementType; - iconColor: string; - title: string; - badge?: string; - badgeColor?: string; - mainValue: string | number; - mainColor?: string; - mainUnit?: string; - subItems: Array<{ label: string; value: string | number; color?: string }>; - rightIcon?: React.ReactNode; -} +/** + * 装饰性光效组件 + */ +const GlowDecorations: React.FC = () => ( + <> + {/* 顶部金色光条 */} + -const MetricCard: React.FC = ({ - icon: IconComponent, - iconColor, - title, - badge, - badgeColor = FUI.textMuted, - mainValue, - mainColor = FUI.orange, - mainUnit, - subItems, - rightIcon, -}) => ( - - {/* 左上角光条 */} + {/* 左上角光晕 */} - {/* 顶部:图标 + 标题 + 标签 */} - - - - {title} - - {badge && ( - - {badge} - - )} - {rightIcon && ( - - {rightIcon} - - )} - + {/* 右下角光晕 */} + - {/* 主数值 */} - - {mainValue} - {mainUnit && ( - - {mainUnit} - - )} - + {/* 背景网格 */} + + +); - {/* 子项目 */} - - {subItems.map((item, idx) => ( - - {item.label} - - {item.value} - +/** + * 加载骨架屏 + */ +const LoadingSkeleton: React.FC = () => ( + + + + + {/* 头部骨架 */} + + + + - ))} + + + + + + + {/* 价格骨架 */} + + + + + + {/* 内容骨架 */} + + + + + + + + ); -// 股票信息卡片(第一个) -interface StockInfoCardProps { - name: string; - code: string; - currentPrice: number; - changePercent: number; - industry?: string; +/** + * 玻璃态内嵌区块 + */ +interface GlassSectionProps { + title: string; + children: React.ReactNode; + flex?: number | string; } -const StockInfoCard: React.FC = ({ - name, - code, - currentPrice, - changePercent, - industry, -}) => { - const isUp = changePercent >= 0; - const priceColor = isUp ? FUI.red : FUI.green; - const trendText = isUp ? '强势上涨' : '震荡下跌'; - - return ( +const GlassSection: React.FC = ({ title, children, flex = 1 }) => ( + + {/* 区块顶部光条 */} + + - {/* 左上角光条 */} - + {title} + + {children} + +); - {/* 股票名称和代码 */} - - - {name} - - - {code} - - +/** + * 指标行组件 + */ +interface MetricRowProps { + label: string; + value: string | number; + valueColor?: string; + highlight?: boolean; +} - {/* 价格和涨跌幅 */} - - - {currentPrice.toFixed(2)} - - - {isUp ? '↗' : '↘'} {isUp ? '+' : ''}{changePercent.toFixed(2)}% - - - - {/* 走势标签 */} - - - 走势: - {trendText} - - - ); -}; +const MetricRow: React.FC = ({ + label, + value, + valueColor = T.textWhite, + highlight = false, +}) => ( + + {label} + + {value} + + +); const StockQuoteCard: React.FC = ({ stockCode, @@ -269,112 +216,311 @@ const StockQuoteCard: React.FC = ({ clearCompare(); }; - // 加载中骨架屏 + // 加载中 if (isLoading || !quoteData) { - return ( - - {[1, 2, 3, 4].map((i) => ( - - - - - - ))} - - ); + return ; } - // 格式化数值 - const formatVolume = (val: number) => { - if (!val) return '-'; - if (val >= 100000000) return `${(val / 100000000).toFixed(2)}亿`; - if (val >= 10000) return `${(val / 10000).toFixed(0)}万`; - return val.toString(); - }; + // 涨跌判断 + const isUp = quoteData.changePercent >= 0; + const priceColor = isUp ? T.upColor : T.downColor; + const priceGlow = isUp ? T.upGlow : T.downGlow; + const priceBg = isUp ? T.upColorMuted : T.downColorMuted; + const inflowColor = (quoteData.mainNetInflow || 0) >= 0 ? T.upColor : T.downColor; return ( <> - - {/* 卡片1: 股票基本信息 */} - + + - {/* 卡片2: 交易热度 */} - 5 ? FUI.orange : FUI.text, - }, - { - label: '52周区间', - value: `${quoteData.week52Low?.toFixed(2) || '-'} - ${quoteData.week52High?.toFixed(2) || '-'}`, - }, - ]} - /> + {/* 内容区域(在装饰层之上)*/} + - {/* 卡片3: 估值安全 */} - 50 ? '高估值' : quoteData.pe > 20 ? '合理' : '低估值') : '-', - color: quoteData.pe ? (quoteData.pe > 50 ? FUI.orange : quoteData.pe > 20 ? FUI.gold : FUI.green) : FUI.textMuted, - }, - { - label: '发行总股本', - value: quoteData.totalShares ? `${quoteData.totalShares}亿股` : '-', - }, - ]} - /> + {/* ========== 头部区域 ========== */} + + {/* 左侧:股票名称 + 代码 + 行业 */} + + + {quoteData.name} + + + ({quoteData.code}) + - {/* 卡片4: 股本结构 */} - - + {/* 行业标签 */} + {(quoteData.industryL1 || quoteData.industry) && ( + + {quoteData.industryL1 && quoteData.industry + ? `${quoteData.industryL1} · ${quoteData.industry}` + : quoteData.industry || quoteData.industryL1} + + )} + + {/* 指数标签 */} + {quoteData.indexTags && quoteData.indexTags.length > 0 && ( + + {quoteData.indexTags.join('、')} + + )} + + + {/* 右侧:操作按钮 */} + + + {})} + colorScheme="gold" + size="sm" + /> + + } + variant="ghost" + color={T.textSecondary} + size="sm" + borderRadius={T.radiusSM} + _hover={{ bg: T.borderGlass, color: T.textPrimary }} + /> + + + {quoteData.updateTime?.split(' ')[1] || '--:--'} + + + + + {/* ========== 价格区域 ========== */} + + + {formatPrice(quoteData.currentPrice)} + + + {formatChangePercent(quoteData.changePercent)} + + + + {/* ========== 次要行情 ========== */} + + + 今开: + + {formatPrice(quoteData.todayOpen)} + + + + + 昨收: + + {formatPrice(quoteData.yesterdayClose)} + + + + + 最高: + + {formatPrice(quoteData.todayHigh)} + + + + + 最低: + + {formatPrice(quoteData.todayLow)} + + + + + {/* ========== 数据区块(Bento Grid)========== */} + + {/* 关键指标 */} + + + + + + + 5 ? T.orange : T.textWhite} + /> + + + + + {/* 主力动态 */} + + + + + + {/* 买卖比例条 */} + + div': { + bg: T.upColor, + boxShadow: T.upGlow, + }, + }} + bg={T.downColor} + borderRadius="full" + h="8px" + /> + + + 买入 {quoteData.buyRatio}% + + + 卖出 {quoteData.sellRatio}% + + + + + + + + {/* ========== 公司信息 ========== */} + {basicInfo && ( + <> + {/* 分隔线 */} + + + + {/* 公司属性 */} + + + + 成立: + + {formatDate(basicInfo.establish_date)} + + + + + 注册资本: + + {formatRegisteredCapital(basicInfo.reg_capital)} + + + + + 所在地: + + {basicInfo.province} {basicInfo.city} + + + + + {basicInfo.website ? ( + + 访问官网 + + ) : ( + 暂无官网 + )} + + + + {/* 公司简介 */} + + + + 公司简介: + + {basicInfo.company_intro || '暂无'} + + + + + )} + + {/* 股票对比弹窗 */}