更新Company页面的UI为FUI风格
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* SubTabContainer - 二级导航容器组件
|
||||
*
|
||||
* 用于模块内的子功能切换(如公司档案下的股权结构、管理团队等)
|
||||
* 与 TabContainer(一级导航)区分:无 Card 包裹,直接融入父容器
|
||||
* 深空 FUI 设计风格(Glassmorphism + Ash Thorp + James Turrell)
|
||||
* - 玻璃态导航栏,漂浮感
|
||||
* - 选中态发光效果,科幻数据终端感
|
||||
* - 流畅的过渡动画
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
@@ -43,6 +45,40 @@ export interface SubTabConfig {
|
||||
component?: ComponentType<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 深空 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<string, SubTabTheme> = {
|
||||
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<SubTabContainerProps> = memo(({
|
||||
index={currentIndex}
|
||||
onChange={handleTabChange}
|
||||
>
|
||||
{/* TabList - 玻璃态导航栏 */}
|
||||
<TabList
|
||||
bg={theme.bg}
|
||||
backdropFilter="blur(20px)"
|
||||
WebkitBackdropFilter="blur(20px)"
|
||||
borderBottom="1px solid"
|
||||
borderColor={theme.borderColor}
|
||||
pl={2}
|
||||
pr={4}
|
||||
borderRadius={DEEP_SPACE.radiusLG}
|
||||
mx={2}
|
||||
mb={2}
|
||||
px={3}
|
||||
py={3}
|
||||
flexWrap="nowrap"
|
||||
gap={2}
|
||||
alignItems="center"
|
||||
overflowX="auto"
|
||||
position="relative"
|
||||
boxShadow={DEEP_SPACE.innerGlow}
|
||||
css={{
|
||||
'&::-webkit-scrollbar': { display: 'none' },
|
||||
scrollbarWidth: 'none',
|
||||
}}
|
||||
>
|
||||
{tabs.map((tab) => (
|
||||
{/* 顶部金色光条 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top={0}
|
||||
left="50%"
|
||||
transform="translateX(-50%)"
|
||||
width="50%"
|
||||
height="1px"
|
||||
background={`linear-gradient(90deg, transparent, rgba(212, 175, 55, 0.4), transparent)`}
|
||||
/>
|
||||
|
||||
{tabs.map((tab, idx) => {
|
||||
const isSelected = idx === currentIndex;
|
||||
|
||||
return (
|
||||
<Tab
|
||||
key={tab.key}
|
||||
color={theme.tabUnselectedColor}
|
||||
borderRadius="md"
|
||||
px={5}
|
||||
py={2.5}
|
||||
fontSize="sm"
|
||||
borderRadius={DEEP_SPACE.radius}
|
||||
px={6}
|
||||
py={3}
|
||||
fontSize="15px"
|
||||
fontWeight="500"
|
||||
whiteSpace="nowrap"
|
||||
flexShrink={0}
|
||||
border="1px solid transparent"
|
||||
position="relative"
|
||||
letterSpacing="0.05em"
|
||||
transition="all 0.25s cubic-bezier(0.4, 0, 0.2, 1)"
|
||||
letterSpacing="0.03em"
|
||||
transition={DEEP_SPACE.transition}
|
||||
_before={{
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
bottom: '-1px',
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
width: '0%',
|
||||
width: isSelected ? '70%' : '0%',
|
||||
height: '2px',
|
||||
bg: '#D4AF37',
|
||||
transition: 'width 0.25s ease',
|
||||
borderRadius: 'full',
|
||||
transition: 'width 0.3s ease',
|
||||
boxShadow: isSelected ? '0 0 10px rgba(212, 175, 55, 0.5)' : 'none',
|
||||
}}
|
||||
_selected={{
|
||||
bg: theme.tabSelectedBg,
|
||||
color: theme.tabSelectedColor,
|
||||
fontWeight: '700',
|
||||
boxShadow: '0 4px 16px rgba(212, 175, 55, 0.35), 0 0 20px rgba(212, 175, 55, 0.15)',
|
||||
border: '1px solid rgba(212, 175, 55, 0.6)',
|
||||
transform: 'translateY(-1px)',
|
||||
_before: {
|
||||
width: '80%',
|
||||
},
|
||||
boxShadow: DEEP_SPACE.glowGold,
|
||||
border: `1px solid ${DEEP_SPACE.borderGoldHover}`,
|
||||
transform: 'translateY(-2px)',
|
||||
}}
|
||||
_hover={{
|
||||
bg: theme.tabHoverBg,
|
||||
border: '1px solid rgba(212, 175, 55, 0.35)',
|
||||
bg: isSelected ? undefined : theme.tabHoverBg,
|
||||
border: isSelected ? undefined : `1px solid ${DEEP_SPACE.borderGold}`,
|
||||
transform: 'translateY(-1px)',
|
||||
_before: {
|
||||
width: '60%',
|
||||
},
|
||||
}}
|
||||
_active={{
|
||||
transform: 'translateY(0)',
|
||||
}}
|
||||
>
|
||||
<HStack spacing={2}>
|
||||
{tab.icon && <Icon as={tab.icon} boxSize={4} />}
|
||||
{tab.icon && (
|
||||
<Icon
|
||||
as={tab.icon}
|
||||
boxSize={4}
|
||||
opacity={isSelected ? 1 : 0.7}
|
||||
transition="opacity 0.2s"
|
||||
/>
|
||||
)}
|
||||
<Text>{tab.name}</Text>
|
||||
</HStack>
|
||||
</Tab>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
{rightElement && (
|
||||
<>
|
||||
<Spacer />
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = () => (
|
||||
<>
|
||||
{/* 顶部金色光条 */}
|
||||
<Box {...decorativeElements.topGlowBar} />
|
||||
|
||||
const MetricCard: React.FC<MetricCardProps> = ({
|
||||
icon: IconComponent,
|
||||
iconColor,
|
||||
title,
|
||||
badge,
|
||||
badgeColor = FUI.textMuted,
|
||||
mainValue,
|
||||
mainColor = FUI.orange,
|
||||
mainUnit,
|
||||
subItems,
|
||||
rightIcon,
|
||||
}) => (
|
||||
{/* 左上角光晕 */}
|
||||
<Box
|
||||
bg={FUI.bgCard}
|
||||
borderRadius="lg"
|
||||
border="1px solid"
|
||||
borderColor={FUI.border}
|
||||
p={4}
|
||||
position="relative"
|
||||
overflow="hidden"
|
||||
transition="all 0.25s ease"
|
||||
_hover={{
|
||||
bg: FUI.bgCardHover,
|
||||
borderColor: FUI.borderGold,
|
||||
transform: 'translateY(-2px)',
|
||||
boxShadow: `0 8px 24px rgba(0, 0, 0, 0.3), 0 0 1px ${FUI.gold}`,
|
||||
}}
|
||||
>
|
||||
{/* 左上角光条 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top={0}
|
||||
left={0}
|
||||
w="40px"
|
||||
h="2px"
|
||||
bg={iconColor}
|
||||
opacity={0.8}
|
||||
{...decorativeElements.cornerGlow}
|
||||
top="-40px"
|
||||
left="-40px"
|
||||
/>
|
||||
|
||||
{/* 顶部:图标 + 标题 + 标签 */}
|
||||
<HStack spacing={2} mb={3}>
|
||||
<Icon as={IconComponent} boxSize={4} color={iconColor} />
|
||||
<Text fontSize="sm" fontWeight="600" color={FUI.text}>
|
||||
{title}
|
||||
</Text>
|
||||
{badge && (
|
||||
<Badge
|
||||
fontSize="10px"
|
||||
px={2}
|
||||
py={0.5}
|
||||
bg="rgba(255, 255, 255, 0.1)"
|
||||
color={badgeColor}
|
||||
borderRadius="sm"
|
||||
fontWeight="500"
|
||||
{/* 右下角光晕 */}
|
||||
<Box
|
||||
{...decorativeElements.cornerGlow}
|
||||
bottom="-40px"
|
||||
right="-40px"
|
||||
background={`radial-gradient(circle, rgba(0, 212, 255, 0.1) 0%, transparent 70%)`}
|
||||
/>
|
||||
|
||||
{/* 背景网格 */}
|
||||
<Box {...decorativeElements.gridOverlay} />
|
||||
</>
|
||||
);
|
||||
|
||||
/**
|
||||
* 加载骨架屏
|
||||
*/
|
||||
const LoadingSkeleton: React.FC = () => (
|
||||
<Box
|
||||
{...glassCardStyle.containerGold}
|
||||
p={8}
|
||||
>
|
||||
{badge}
|
||||
</Badge>
|
||||
)}
|
||||
{rightIcon && (
|
||||
<Box ml="auto" opacity={0.5}>
|
||||
{rightIcon}
|
||||
<GlowDecorations />
|
||||
|
||||
<VStack align="stretch" spacing={6} position="relative" zIndex={1}>
|
||||
{/* 头部骨架 */}
|
||||
<Flex justify="space-between">
|
||||
<HStack spacing={3}>
|
||||
<Skeleton height="32px" width="120px" startColor={T.bgInset} endColor={T.borderGlass} borderRadius={T.radiusSM} />
|
||||
<Skeleton height="24px" width="80px" startColor={T.bgInset} endColor={T.borderGlass} borderRadius={T.radiusSM} />
|
||||
</HStack>
|
||||
<HStack spacing={2}>
|
||||
<Skeleton height="32px" width="32px" startColor={T.bgInset} endColor={T.borderGlass} borderRadius={T.radiusSM} />
|
||||
<Skeleton height="32px" width="32px" startColor={T.bgInset} endColor={T.borderGlass} borderRadius={T.radiusSM} />
|
||||
</HStack>
|
||||
</Flex>
|
||||
|
||||
{/* 价格骨架 */}
|
||||
<HStack>
|
||||
<Skeleton height="56px" width="160px" startColor={T.bgInset} endColor={T.borderGlass} borderRadius={T.radiusMD} />
|
||||
<Skeleton height="36px" width="100px" startColor={T.bgInset} endColor={T.borderGlass} borderRadius={T.radiusMD} />
|
||||
</HStack>
|
||||
|
||||
{/* 内容骨架 */}
|
||||
<Flex gap={6}>
|
||||
<Box flex={1}>
|
||||
<Skeleton height="120px" startColor={T.bgInset} endColor={T.borderGlass} borderRadius={T.radiusLG} />
|
||||
</Box>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
{/* 主数值 */}
|
||||
<Text
|
||||
fontSize="2xl"
|
||||
fontWeight="bold"
|
||||
color={mainColor}
|
||||
lineHeight="1.2"
|
||||
mb={2}
|
||||
>
|
||||
{mainValue}
|
||||
{mainUnit && (
|
||||
<Text as="span" fontSize="md" fontWeight="normal" ml={1}>
|
||||
{mainUnit}
|
||||
</Text>
|
||||
)}
|
||||
</Text>
|
||||
|
||||
{/* 子项目 */}
|
||||
<VStack align="stretch" spacing={1}>
|
||||
{subItems.map((item, idx) => (
|
||||
<HStack key={idx} justify="space-between" fontSize="xs">
|
||||
<Text color={FUI.textMuted}>{item.label}</Text>
|
||||
<Text color={item.color || FUI.text} fontWeight="500">
|
||||
{item.value}
|
||||
</Text>
|
||||
</HStack>
|
||||
))}
|
||||
<Box flex={1}>
|
||||
<Skeleton height="120px" startColor={T.bgInset} endColor={T.borderGlass} borderRadius={T.radiusLG} />
|
||||
</Box>
|
||||
</Flex>
|
||||
</VStack>
|
||||
</Box>
|
||||
);
|
||||
|
||||
// 股票信息卡片(第一个)
|
||||
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<StockInfoCardProps> = ({
|
||||
name,
|
||||
code,
|
||||
currentPrice,
|
||||
changePercent,
|
||||
industry,
|
||||
}) => {
|
||||
const isUp = changePercent >= 0;
|
||||
const priceColor = isUp ? FUI.red : FUI.green;
|
||||
const trendText = isUp ? '强势上涨' : '震荡下跌';
|
||||
|
||||
return (
|
||||
const GlassSection: React.FC<GlassSectionProps> = ({ title, children, flex = 1 }) => (
|
||||
<Box
|
||||
bg={FUI.bgCard}
|
||||
borderRadius="lg"
|
||||
border="1px solid"
|
||||
borderColor={FUI.border}
|
||||
p={4}
|
||||
flex={flex}
|
||||
bg={T.bgInset}
|
||||
borderRadius={T.radiusLG}
|
||||
border={`1px solid ${T.borderGlass}`}
|
||||
p={5}
|
||||
position="relative"
|
||||
overflow="hidden"
|
||||
transition="all 0.25s ease"
|
||||
transition={T.transitionFast}
|
||||
_hover={{
|
||||
bg: FUI.bgCardHover,
|
||||
borderColor: FUI.borderGold,
|
||||
transform: 'translateY(-2px)',
|
||||
boxShadow: `0 8px 24px rgba(0, 0, 0, 0.3), 0 0 1px ${FUI.gold}`,
|
||||
borderColor: T.borderGoldHover,
|
||||
bg: 'rgba(15, 18, 35, 0.6)',
|
||||
}}
|
||||
>
|
||||
{/* 左上角光条 */}
|
||||
{/* 区块顶部光条 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top={0}
|
||||
left={0}
|
||||
w="40px"
|
||||
h="2px"
|
||||
bg={priceColor}
|
||||
opacity={0.8}
|
||||
left="20px"
|
||||
right="20px"
|
||||
height="1px"
|
||||
background={`linear-gradient(90deg, transparent, ${T.gold}40, transparent)`}
|
||||
/>
|
||||
|
||||
{/* 股票名称和代码 */}
|
||||
<HStack spacing={2} mb={3}>
|
||||
<Text fontSize="lg" fontWeight="bold" color={FUI.text}>
|
||||
{name}
|
||||
</Text>
|
||||
<Badge
|
||||
fontSize="10px"
|
||||
px={2}
|
||||
py={0.5}
|
||||
bg="rgba(255, 255, 255, 0.1)"
|
||||
color={FUI.textMuted}
|
||||
borderRadius="sm"
|
||||
<Text
|
||||
fontSize="13px"
|
||||
fontWeight="600"
|
||||
color={T.textSecondary}
|
||||
mb={3}
|
||||
textTransform="uppercase"
|
||||
letterSpacing="0.1em"
|
||||
>
|
||||
{code}
|
||||
</Badge>
|
||||
</HStack>
|
||||
|
||||
{/* 价格和涨跌幅 */}
|
||||
<HStack spacing={3} mb={2}>
|
||||
<Text fontSize="2xl" fontWeight="bold" color={priceColor}>
|
||||
{currentPrice.toFixed(2)}
|
||||
{title}
|
||||
</Text>
|
||||
<Badge
|
||||
fontSize="sm"
|
||||
px={2}
|
||||
py={1}
|
||||
bg={isUp ? 'rgba(255, 71, 87, 0.15)' : 'rgba(0, 217, 132, 0.15)'}
|
||||
color={priceColor}
|
||||
borderRadius="md"
|
||||
fontWeight="bold"
|
||||
>
|
||||
{isUp ? '↗' : '↘'} {isUp ? '+' : ''}{changePercent.toFixed(2)}%
|
||||
</Badge>
|
||||
</HStack>
|
||||
|
||||
{/* 走势标签 */}
|
||||
<HStack fontSize="xs" color={FUI.textMuted}>
|
||||
<Icon as={TrendingUp} boxSize={3} color={priceColor} />
|
||||
<Text>走势:</Text>
|
||||
<Text color={priceColor} fontWeight="500">{trendText}</Text>
|
||||
</HStack>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 指标行组件
|
||||
*/
|
||||
interface MetricRowProps {
|
||||
label: string;
|
||||
value: string | number;
|
||||
valueColor?: string;
|
||||
highlight?: boolean;
|
||||
}
|
||||
|
||||
const MetricRow: React.FC<MetricRowProps> = ({
|
||||
label,
|
||||
value,
|
||||
valueColor = T.textWhite,
|
||||
highlight = false,
|
||||
}) => (
|
||||
<HStack justify="space-between" fontSize="14px">
|
||||
<Text color={T.textMuted}>{label}</Text>
|
||||
<Text
|
||||
color={valueColor}
|
||||
fontWeight={highlight ? '700' : '600'}
|
||||
fontSize={highlight ? '16px' : '14px'}
|
||||
textShadow={highlight ? `0 0 10px ${valueColor}40` : undefined}
|
||||
>
|
||||
{value}
|
||||
</Text>
|
||||
</HStack>
|
||||
);
|
||||
|
||||
const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
stockCode,
|
||||
@@ -269,112 +216,311 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
clearCompare();
|
||||
};
|
||||
|
||||
// 加载中骨架屏
|
||||
// 加载中
|
||||
if (isLoading || !quoteData) {
|
||||
return (
|
||||
<Grid templateColumns="repeat(4, 1fr)" gap={4}>
|
||||
{[1, 2, 3, 4].map((i) => (
|
||||
<Box
|
||||
key={i}
|
||||
bg={FUI.bgCard}
|
||||
borderRadius="lg"
|
||||
border="1px solid"
|
||||
borderColor={FUI.border}
|
||||
p={4}
|
||||
>
|
||||
<Skeleton height="20px" width="120px" mb={3} startColor="rgba(255,255,255,0.05)" endColor="rgba(255,255,255,0.1)" />
|
||||
<Skeleton height="32px" width="80px" mb={2} startColor="rgba(255,255,255,0.05)" endColor="rgba(255,255,255,0.1)" />
|
||||
<Skeleton height="14px" width="100%" startColor="rgba(255,255,255,0.05)" endColor="rgba(255,255,255,0.1)" />
|
||||
</Box>
|
||||
))}
|
||||
</Grid>
|
||||
);
|
||||
return <LoadingSkeleton />;
|
||||
}
|
||||
|
||||
// 格式化数值
|
||||
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 (
|
||||
<>
|
||||
<Grid templateColumns="repeat(4, 1fr)" gap={4}>
|
||||
{/* 卡片1: 股票基本信息 */}
|
||||
<StockInfoCard
|
||||
name={quoteData.name}
|
||||
code={quoteData.code}
|
||||
currentPrice={quoteData.currentPrice}
|
||||
changePercent={quoteData.changePercent}
|
||||
industry={quoteData.industry}
|
||||
<Box
|
||||
{...glassCardStyle.containerGold}
|
||||
p={8}
|
||||
>
|
||||
<GlowDecorations />
|
||||
|
||||
{/* 内容区域(在装饰层之上)*/}
|
||||
<VStack align="stretch" spacing={6} position="relative" zIndex={1}>
|
||||
|
||||
{/* ========== 头部区域 ========== */}
|
||||
<Flex justify="space-between" align="center">
|
||||
{/* 左侧:股票名称 + 代码 + 行业 */}
|
||||
<HStack spacing={4} align="center">
|
||||
<Text
|
||||
fontSize="28px"
|
||||
fontWeight="800"
|
||||
color={T.textPrimary}
|
||||
textShadow={`0 0 20px ${T.gold}40`}
|
||||
>
|
||||
{quoteData.name}
|
||||
</Text>
|
||||
<Text fontSize="18px" color={T.textMuted} fontWeight="normal">
|
||||
({quoteData.code})
|
||||
</Text>
|
||||
|
||||
{/* 行业标签 */}
|
||||
{(quoteData.industryL1 || quoteData.industry) && (
|
||||
<Badge
|
||||
bg="transparent"
|
||||
color={T.textSecondary}
|
||||
fontSize="13px"
|
||||
fontWeight="500"
|
||||
border="1px solid"
|
||||
borderColor={T.borderGold}
|
||||
px={3}
|
||||
py={1}
|
||||
borderRadius={T.radiusMD}
|
||||
>
|
||||
{quoteData.industryL1 && quoteData.industry
|
||||
? `${quoteData.industryL1} · ${quoteData.industry}`
|
||||
: quoteData.industry || quoteData.industryL1}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
{/* 指数标签 */}
|
||||
{quoteData.indexTags && quoteData.indexTags.length > 0 && (
|
||||
<Text fontSize="13px" color={T.textMuted}>
|
||||
{quoteData.indexTags.join('、')}
|
||||
</Text>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
{/* 右侧:操作按钮 */}
|
||||
<HStack spacing={3}>
|
||||
<CompareStockInput
|
||||
onCompare={handleCompare}
|
||||
isLoading={isCompareLoading}
|
||||
currentStockCode={quoteData.code}
|
||||
/>
|
||||
<FavoriteButton
|
||||
isFavorite={isInWatchlist}
|
||||
isLoading={isWatchlistLoading}
|
||||
onClick={onWatchlistToggle || (() => {})}
|
||||
colorScheme="gold"
|
||||
size="sm"
|
||||
/>
|
||||
<Tooltip label="分享" placement="top">
|
||||
<IconButton
|
||||
aria-label="分享"
|
||||
icon={<Share2 size={18} />}
|
||||
variant="ghost"
|
||||
color={T.textSecondary}
|
||||
size="sm"
|
||||
borderRadius={T.radiusSM}
|
||||
_hover={{ bg: T.borderGlass, color: T.textPrimary }}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Text fontSize="13px" color={T.textMuted}>
|
||||
{quoteData.updateTime?.split(' ')[1] || '--:--'}
|
||||
</Text>
|
||||
</HStack>
|
||||
</Flex>
|
||||
|
||||
{/* ========== 价格区域 ========== */}
|
||||
<HStack align="baseline" spacing={4}>
|
||||
<Text
|
||||
fontSize="52px"
|
||||
fontWeight="bold"
|
||||
color={priceColor}
|
||||
textShadow={priceGlow}
|
||||
lineHeight="1"
|
||||
>
|
||||
{formatPrice(quoteData.currentPrice)}
|
||||
</Text>
|
||||
<Badge
|
||||
bg={priceBg}
|
||||
color={priceColor}
|
||||
fontSize="20px"
|
||||
fontWeight="bold"
|
||||
px={4}
|
||||
py={2}
|
||||
borderRadius={T.radiusMD}
|
||||
boxShadow={priceGlow}
|
||||
>
|
||||
{formatChangePercent(quoteData.changePercent)}
|
||||
</Badge>
|
||||
</HStack>
|
||||
|
||||
{/* ========== 次要行情 ========== */}
|
||||
<HStack spacing={6} fontSize="14px" flexWrap="wrap">
|
||||
<Text color={T.textMuted}>
|
||||
今开:
|
||||
<Text as="span" color={T.textWhite} fontWeight="600" ml={1}>
|
||||
{formatPrice(quoteData.todayOpen)}
|
||||
</Text>
|
||||
</Text>
|
||||
<Box w="1px" h="14px" bg={T.divider} />
|
||||
<Text color={T.textMuted}>
|
||||
昨收:
|
||||
<Text as="span" color={T.textWhite} fontWeight="600" ml={1}>
|
||||
{formatPrice(quoteData.yesterdayClose)}
|
||||
</Text>
|
||||
</Text>
|
||||
<Box w="1px" h="14px" bg={T.divider} />
|
||||
<Text color={T.textMuted}>
|
||||
最高:
|
||||
<Text as="span" color={T.upColor} fontWeight="600" ml={1}>
|
||||
{formatPrice(quoteData.todayHigh)}
|
||||
</Text>
|
||||
</Text>
|
||||
<Box w="1px" h="14px" bg={T.divider} />
|
||||
<Text color={T.textMuted}>
|
||||
最低:
|
||||
<Text as="span" color={T.downColor} fontWeight="600" ml={1}>
|
||||
{formatPrice(quoteData.todayLow)}
|
||||
</Text>
|
||||
</Text>
|
||||
</HStack>
|
||||
|
||||
{/* ========== 数据区块(Bento Grid)========== */}
|
||||
<Flex gap={5} flexWrap={{ base: 'wrap', lg: 'nowrap' }}>
|
||||
{/* 关键指标 */}
|
||||
<GlassSection title="关键指标" flex={1}>
|
||||
<VStack align="stretch" spacing={2.5}>
|
||||
<MetricRow
|
||||
label="市盈率 (PE)"
|
||||
value={quoteData.pe ? quoteData.pe.toFixed(2) : '-'}
|
||||
valueColor={T.cyan}
|
||||
highlight
|
||||
/>
|
||||
<MetricRow
|
||||
label="流通市值"
|
||||
value={quoteData.marketCap || '-'}
|
||||
valueColor={T.textPrimary}
|
||||
highlight
|
||||
/>
|
||||
<MetricRow
|
||||
label="发行总股本"
|
||||
value={quoteData.totalShares ? `${quoteData.totalShares}亿股` : '-'}
|
||||
/>
|
||||
<MetricRow
|
||||
label="流通股本"
|
||||
value={quoteData.floatShares ? `${quoteData.floatShares}亿股` : '-'}
|
||||
/>
|
||||
<MetricRow
|
||||
label="换手率"
|
||||
value={quoteData.turnoverRate !== undefined ? `${quoteData.turnoverRate.toFixed(2)}%` : '-'}
|
||||
valueColor={quoteData.turnoverRate && quoteData.turnoverRate > 5 ? T.orange : T.textWhite}
|
||||
/>
|
||||
<MetricRow
|
||||
label="52周波动"
|
||||
value={`${formatPrice(quoteData.week52Low)} - ${formatPrice(quoteData.week52High)}`}
|
||||
/>
|
||||
</VStack>
|
||||
</GlassSection>
|
||||
|
||||
{/* 主力动态 */}
|
||||
<GlassSection title="主力动态" flex={1}>
|
||||
<VStack align="stretch" spacing={3}>
|
||||
<MetricRow
|
||||
label="主力净流入"
|
||||
value={formatNetInflow(quoteData.mainNetInflow)}
|
||||
valueColor={inflowColor}
|
||||
highlight
|
||||
/>
|
||||
<MetricRow
|
||||
label="机构持仓"
|
||||
value={`${quoteData.institutionHolding.toFixed(2)}%`}
|
||||
valueColor={T.purple}
|
||||
highlight
|
||||
/>
|
||||
|
||||
{/* 卡片2: 交易热度 */}
|
||||
<MetricCard
|
||||
icon={Activity}
|
||||
iconColor={FUI.orange}
|
||||
title="交易热度"
|
||||
badge="流动性"
|
||||
mainValue={quoteData.marketCap || '-'}
|
||||
mainColor={FUI.orange}
|
||||
subItems={[
|
||||
{
|
||||
label: '换手率',
|
||||
value: quoteData.turnoverRate ? `${quoteData.turnoverRate.toFixed(2)}%` : '-',
|
||||
color: (quoteData.turnoverRate || 0) > 5 ? FUI.orange : FUI.text,
|
||||
{/* 买卖比例条 */}
|
||||
<Box mt={2}>
|
||||
<Progress
|
||||
value={quoteData.buyRatio}
|
||||
size="sm"
|
||||
sx={{
|
||||
'& > div': {
|
||||
bg: T.upColor,
|
||||
boxShadow: T.upGlow,
|
||||
},
|
||||
{
|
||||
label: '52周区间',
|
||||
value: `${quoteData.week52Low?.toFixed(2) || '-'} - ${quoteData.week52High?.toFixed(2) || '-'}`,
|
||||
},
|
||||
]}
|
||||
}}
|
||||
bg={T.downColor}
|
||||
borderRadius="full"
|
||||
h="8px"
|
||||
/>
|
||||
<HStack justify="space-between" mt={2} fontSize="13px">
|
||||
<Text color={T.upColor} fontWeight="600">
|
||||
买入 {quoteData.buyRatio}%
|
||||
</Text>
|
||||
<Text color={T.downColor} fontWeight="600">
|
||||
卖出 {quoteData.sellRatio}%
|
||||
</Text>
|
||||
</HStack>
|
||||
</Box>
|
||||
</VStack>
|
||||
</GlassSection>
|
||||
</Flex>
|
||||
|
||||
{/* ========== 公司信息 ========== */}
|
||||
{basicInfo && (
|
||||
<>
|
||||
{/* 分隔线 */}
|
||||
<Box
|
||||
h="1px"
|
||||
bg={`linear-gradient(90deg, transparent, ${T.gold}30, transparent)`}
|
||||
/>
|
||||
|
||||
{/* 卡片3: 估值安全 */}
|
||||
<MetricCard
|
||||
icon={DollarSign}
|
||||
iconColor={FUI.cyan}
|
||||
title="估值 VS 安全"
|
||||
badge="便宜否"
|
||||
mainValue={quoteData.pe ? quoteData.pe.toFixed(2) : '-'}
|
||||
mainColor={FUI.cyan}
|
||||
mainUnit=""
|
||||
subItems={[
|
||||
{
|
||||
label: '市盈率(PE)',
|
||||
value: quoteData.pe ? (quoteData.pe > 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}亿股` : '-',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Flex gap={8} flexWrap={{ base: 'wrap', lg: 'nowrap' }}>
|
||||
{/* 公司属性 */}
|
||||
<HStack spacing={6} flex={1} flexWrap="wrap" fontSize="14px">
|
||||
<HStack spacing={2}>
|
||||
<Icon as={Calendar} color={T.textMuted} boxSize={4} />
|
||||
<Text color={T.textMuted}>成立:</Text>
|
||||
<Text color={T.textWhite} fontWeight="600">
|
||||
{formatDate(basicInfo.establish_date)}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={Coins} color={T.textMuted} boxSize={4} />
|
||||
<Text color={T.textMuted}>注册资本:</Text>
|
||||
<Text color={T.textWhite} fontWeight="600">
|
||||
{formatRegisteredCapital(basicInfo.reg_capital)}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={MapPin} color={T.textMuted} boxSize={4} />
|
||||
<Text color={T.textMuted}>所在地:</Text>
|
||||
<Text color={T.textWhite} fontWeight="600">
|
||||
{basicInfo.province} {basicInfo.city}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={Globe} color={T.textMuted} boxSize={4} />
|
||||
{basicInfo.website ? (
|
||||
<Link
|
||||
href={basicInfo.website}
|
||||
isExternal
|
||||
color={T.cyan}
|
||||
fontWeight="600"
|
||||
_hover={{ color: T.textPrimary, textDecoration: 'underline' }}
|
||||
>
|
||||
访问官网
|
||||
</Link>
|
||||
) : (
|
||||
<Text color={T.textWhiteMuted}>暂无官网</Text>
|
||||
)}
|
||||
</HStack>
|
||||
</HStack>
|
||||
|
||||
{/* 卡片4: 股本结构 */}
|
||||
<MetricCard
|
||||
icon={AlertTriangle}
|
||||
iconColor={FUI.green}
|
||||
title="股本结构"
|
||||
badge="资金面"
|
||||
mainValue={quoteData.floatShares ? `${quoteData.floatShares}` : '-'}
|
||||
mainColor={FUI.green}
|
||||
mainUnit="亿股"
|
||||
subItems={[
|
||||
{
|
||||
label: '流通股本',
|
||||
value: quoteData.floatShares ? `${quoteData.floatShares}亿股` : '-',
|
||||
},
|
||||
{
|
||||
label: '行业',
|
||||
value: quoteData.industry || '-',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
{/* 公司简介 */}
|
||||
<Box
|
||||
flex={2}
|
||||
borderLeftWidth="1px"
|
||||
borderColor={T.divider}
|
||||
pl={8}
|
||||
minW="0"
|
||||
>
|
||||
<Text fontSize="14px" color={T.textMuted} noOfLines={2}>
|
||||
<Text as="span" fontWeight="700" color={T.textSecondary}>
|
||||
公司简介:
|
||||
</Text>
|
||||
{basicInfo.company_intro || '暂无'}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
</VStack>
|
||||
</Box>
|
||||
|
||||
{/* 股票对比弹窗 */}
|
||||
<StockCompareModal
|
||||
|
||||
Reference in New Issue
Block a user