refactor(StockQuoteCard): 组件拆分与 FUI 光效统一
- 新增 CardGlow 组件到 @components/FUI,支持多种颜色主题 (gold/cyan/purple) - 拆分 StockQuoteCard 子组件:GlassSection、LoadingSkeleton - 更新 KeyMetrics、MainForceInfo、SecondaryQuote 使用 DEEP_SPACE_THEME - 主组件从 540 行精简到 321 行(减少 40%) - 删除重复的 GlowDecorations,统一使用 FUI/CardGlow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
140
src/components/FUI/CardGlow.tsx
Normal file
140
src/components/FUI/CardGlow.tsx
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* CardGlow - 卡片级装饰光效组件
|
||||
*
|
||||
* 为卡片提供 FUI 风格的装饰元素:
|
||||
* - 顶部光条(Ash Thorp 风格)
|
||||
* - 角落发光效果(James Turrell 风格)
|
||||
* - 可选背景网格
|
||||
*
|
||||
* 与 AmbientGlow 的区别:
|
||||
* - AmbientGlow: 页面级环境光,position: fixed
|
||||
* - CardGlow: 卡片级装饰光,相对于父容器定位
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <Box position="relative" overflow="hidden">
|
||||
* <CardGlow variant="gold" />
|
||||
* {children}
|
||||
* </Box>
|
||||
* ```
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
|
||||
export interface CardGlowProps {
|
||||
/** 预设主题 */
|
||||
variant?: 'gold' | 'cyan' | 'purple' | 'default';
|
||||
/** 是否显示背景网格 */
|
||||
showGrid?: boolean;
|
||||
/** 自定义主色(覆盖 variant) */
|
||||
primaryColor?: string;
|
||||
/** 自定义次色(覆盖 variant) */
|
||||
secondaryColor?: string;
|
||||
}
|
||||
|
||||
// 预设颜色配置
|
||||
const COLOR_PRESETS = {
|
||||
gold: {
|
||||
primary: 'rgba(212, 175, 55, 1)',
|
||||
secondary: 'rgba(0, 212, 255, 0.1)',
|
||||
grid: 'rgba(212, 175, 55, 0.03)',
|
||||
},
|
||||
cyan: {
|
||||
primary: 'rgba(0, 212, 255, 1)',
|
||||
secondary: 'rgba(212, 175, 55, 0.1)',
|
||||
grid: 'rgba(0, 212, 255, 0.03)',
|
||||
},
|
||||
purple: {
|
||||
primary: 'rgba(168, 85, 247, 1)',
|
||||
secondary: 'rgba(0, 212, 255, 0.1)',
|
||||
grid: 'rgba(168, 85, 247, 0.03)',
|
||||
},
|
||||
default: {
|
||||
primary: 'rgba(255, 255, 255, 0.6)',
|
||||
secondary: 'rgba(255, 255, 255, 0.1)',
|
||||
grid: 'rgba(255, 255, 255, 0.02)',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 卡片装饰光效组件
|
||||
*
|
||||
* 纯展示组件,需要父容器设置 position: relative 和 overflow: hidden
|
||||
*/
|
||||
const CardGlow = memo<CardGlowProps>(({
|
||||
variant = 'gold',
|
||||
showGrid = true,
|
||||
primaryColor,
|
||||
secondaryColor,
|
||||
}) => {
|
||||
const preset = COLOR_PRESETS[variant];
|
||||
const primary = primaryColor || preset.primary;
|
||||
const secondary = secondaryColor || preset.secondary;
|
||||
const gridColor = preset.grid;
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* 顶部光条 - Ash Thorp 风格数据终端效果 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top={0}
|
||||
left="50%"
|
||||
transform="translateX(-50%)"
|
||||
width="60%"
|
||||
height="1px"
|
||||
background={`linear-gradient(90deg, transparent, ${primary}, transparent)`}
|
||||
opacity={0.6}
|
||||
pointerEvents="none"
|
||||
/>
|
||||
|
||||
{/* 左上角光晕 - James Turrell 风格光影效果 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top="-40px"
|
||||
left="-40px"
|
||||
width="80px"
|
||||
height="80px"
|
||||
borderRadius="50%"
|
||||
background={`radial-gradient(circle, ${primary.replace('1)', '0.15)')} 0%, transparent 70%)`}
|
||||
filter="blur(20px)"
|
||||
pointerEvents="none"
|
||||
/>
|
||||
|
||||
{/* 右下角光晕 - 补充色,增加层次感 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
bottom="-40px"
|
||||
right="-40px"
|
||||
width="80px"
|
||||
height="80px"
|
||||
borderRadius="50%"
|
||||
background={`radial-gradient(circle, ${secondary} 0%, transparent 70%)`}
|
||||
filter="blur(20px)"
|
||||
pointerEvents="none"
|
||||
/>
|
||||
|
||||
{/* 背景网格 - 微妙的科技感纹理 */}
|
||||
{showGrid && (
|
||||
<Box
|
||||
position="absolute"
|
||||
top={0}
|
||||
left={0}
|
||||
right={0}
|
||||
bottom={0}
|
||||
backgroundImage={`
|
||||
linear-gradient(${gridColor} 1px, transparent 1px),
|
||||
linear-gradient(90deg, ${gridColor} 1px, transparent 1px)
|
||||
`}
|
||||
backgroundSize="40px 40px"
|
||||
pointerEvents="none"
|
||||
opacity={0.5}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
CardGlow.displayName = 'CardGlow';
|
||||
|
||||
export default CardGlow;
|
||||
@@ -1,12 +1,20 @@
|
||||
/**
|
||||
* FUI (Futuristic UI) 组件集合
|
||||
* Ash Thorp 风格的科幻 UI 组件
|
||||
*
|
||||
* 组件说明:
|
||||
* - FuiCorners: 科幻角落装饰
|
||||
* - FuiContainer: FUI 风格容器
|
||||
* - AmbientGlow: 页面级环境光效果(position: fixed)
|
||||
* - CardGlow: 卡片级装饰光效(相对定位,用于卡片内部)
|
||||
*/
|
||||
|
||||
export { default as FuiCorners } from './FuiCorners';
|
||||
export { default as FuiContainer } from './FuiContainer';
|
||||
export { default as AmbientGlow } from './AmbientGlow';
|
||||
export { default as CardGlow } from './CardGlow';
|
||||
|
||||
export type { FuiCornersProps } from './FuiCorners';
|
||||
export type { FuiContainerProps } from './FuiContainer';
|
||||
export type { AmbientGlowProps } from './AmbientGlow';
|
||||
export type { CardGlowProps } from './CardGlow';
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* GlassSection - 玻璃态内嵌区块组件
|
||||
*
|
||||
* 用于包装数据区块(如估值指标、市值股本、主力动态)
|
||||
* 提供统一的 FUI 风格容器样式:
|
||||
* - 半透明背景
|
||||
* - 金色边框高亮
|
||||
* - 顶部光条装饰
|
||||
* - 悬停效果
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { Box, Text } from '@chakra-ui/react';
|
||||
import { DEEP_SPACE_THEME as T } from './theme';
|
||||
|
||||
export interface GlassSectionProps {
|
||||
/** 区块标题 */
|
||||
title: string;
|
||||
/** 区块内容 */
|
||||
children: React.ReactNode;
|
||||
/** flex 布局属性,默认 1 */
|
||||
flex?: number | string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 玻璃态内嵌区块
|
||||
*
|
||||
* 提供统一的数据区块容器样式
|
||||
* 用于包装 KeyMetrics、MainForceInfo 等内容组件
|
||||
*/
|
||||
export const GlassSection: React.FC<GlassSectionProps> = memo(({
|
||||
title,
|
||||
children,
|
||||
flex = 1,
|
||||
}) => (
|
||||
<Box
|
||||
flex={flex}
|
||||
bg={T.bgInset}
|
||||
borderRadius={T.radiusLG}
|
||||
border={`1px solid ${T.borderGlass}`}
|
||||
p={4}
|
||||
position="relative"
|
||||
transition={T.transitionFast}
|
||||
_hover={{
|
||||
borderColor: T.borderGoldHover,
|
||||
bg: 'rgba(15, 18, 35, 0.6)',
|
||||
}}
|
||||
>
|
||||
{/* 区块顶部金色光条装饰 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top={0}
|
||||
left="20px"
|
||||
right="20px"
|
||||
height="1px"
|
||||
background={`linear-gradient(90deg, transparent, ${T.gold}40, transparent)`}
|
||||
/>
|
||||
|
||||
{/* 区块标题 */}
|
||||
<Text
|
||||
fontSize="14px"
|
||||
fontWeight="700"
|
||||
color={T.gold}
|
||||
mb={3}
|
||||
textTransform="uppercase"
|
||||
letterSpacing="0.1em"
|
||||
textShadow={`0 0 12px ${T.gold}60`}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
{/* 区块内容 */}
|
||||
{children}
|
||||
</Box>
|
||||
));
|
||||
|
||||
GlassSection.displayName = 'GlassSection';
|
||||
|
||||
export default GlassSection;
|
||||
@@ -1,23 +1,74 @@
|
||||
/**
|
||||
* KeyMetrics - 关键指标原子组件
|
||||
* 显示 PE、EPS、PB、流通市值、52周波动
|
||||
*
|
||||
* 显示估值和市值相关指标:
|
||||
* - 市盈率 (PE)
|
||||
* - 流通市值
|
||||
* - 发行总股本
|
||||
* - 流通股本
|
||||
* - 换手率
|
||||
* - 52周波动
|
||||
*
|
||||
* 注意:标题由外层 GlassSection 提供
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { Box, VStack, HStack, Text } from '@chakra-ui/react';
|
||||
import { VStack, HStack, Text } from '@chakra-ui/react';
|
||||
import { formatPrice } from './formatters';
|
||||
import { STOCK_CARD_THEME } from './theme';
|
||||
import { DEEP_SPACE_THEME as T } from './theme';
|
||||
|
||||
export interface KeyMetricsProps {
|
||||
/** 市盈率 */
|
||||
pe: number;
|
||||
/** 流通市值(已格式化字符串) */
|
||||
marketCap: string;
|
||||
totalShares?: number; // 发行总股本(亿股)
|
||||
floatShares?: number; // 流通股本(亿股)
|
||||
turnoverRate?: number; // 换手率(%)
|
||||
/** 发行总股本(亿股) */
|
||||
totalShares?: number;
|
||||
/** 流通股本(亿股) */
|
||||
floatShares?: number;
|
||||
/** 换手率(%) */
|
||||
turnoverRate?: number;
|
||||
/** 52周最低价 */
|
||||
week52Low: number;
|
||||
/** 52周最高价 */
|
||||
week52High: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指标行组件 - 内部使用
|
||||
*/
|
||||
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="13px">
|
||||
<Text color={T.textMuted}>{label}</Text>
|
||||
<Text
|
||||
color={valueColor}
|
||||
fontWeight={highlight ? '700' : '600'}
|
||||
fontSize={highlight ? '15px' : '13px'}
|
||||
textShadow={highlight ? `0 0 10px ${valueColor}40` : undefined}
|
||||
>
|
||||
{value}
|
||||
</Text>
|
||||
</HStack>
|
||||
);
|
||||
|
||||
/**
|
||||
* 关键指标展示组件
|
||||
*
|
||||
* 纯展示组件,不包含标题
|
||||
* 应由 GlassSection 包装以提供标题
|
||||
*/
|
||||
export const KeyMetrics: React.FC<KeyMetricsProps> = memo(({
|
||||
pe,
|
||||
marketCap,
|
||||
@@ -26,59 +77,38 @@ export const KeyMetrics: React.FC<KeyMetricsProps> = memo(({
|
||||
turnoverRate,
|
||||
week52Low,
|
||||
week52High,
|
||||
}) => {
|
||||
const { labelColor, valueColor, sectionTitleColor } = STOCK_CARD_THEME;
|
||||
|
||||
return (
|
||||
<Box flex="1">
|
||||
<Text
|
||||
fontSize="14px"
|
||||
fontWeight="bold"
|
||||
color={sectionTitleColor}
|
||||
mb={3}
|
||||
>
|
||||
关键指标
|
||||
</Text>
|
||||
<VStack align="stretch" spacing={2} fontSize="14px">
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>市盈率(PE):</Text>
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{pe ? pe.toFixed(2) : '-'}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>流通市值:</Text>
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{marketCap || '-'}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>发行总股本:</Text>
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{totalShares ? `${totalShares}亿股` : '-'}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>流通股本:</Text>
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{floatShares ? `${floatShares}亿股` : '-'}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>换手率:</Text>
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{turnoverRate !== undefined ? `${turnoverRate.toFixed(2)}%` : '-'}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>52周波动:</Text>
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{formatPrice(week52Low)}-{formatPrice(week52High)}
|
||||
</Text>
|
||||
</HStack>
|
||||
</VStack>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
}) => (
|
||||
<VStack align="stretch" spacing={2}>
|
||||
<MetricRow
|
||||
label="市盈率 (PE)"
|
||||
value={pe ? pe.toFixed(2) : '-'}
|
||||
valueColor={T.cyan}
|
||||
highlight
|
||||
/>
|
||||
<MetricRow
|
||||
label="流通市值"
|
||||
value={marketCap || '-'}
|
||||
valueColor={T.textPrimary}
|
||||
highlight
|
||||
/>
|
||||
<MetricRow
|
||||
label="发行总股本"
|
||||
value={totalShares ? `${totalShares}亿股` : '-'}
|
||||
/>
|
||||
<MetricRow
|
||||
label="流通股本"
|
||||
value={floatShares ? `${floatShares}亿股` : '-'}
|
||||
/>
|
||||
<MetricRow
|
||||
label="换手率"
|
||||
value={turnoverRate !== undefined ? `${turnoverRate.toFixed(2)}%` : '-'}
|
||||
valueColor={turnoverRate && turnoverRate > 5 ? T.orange : T.textWhite}
|
||||
/>
|
||||
<MetricRow
|
||||
label="52周波动"
|
||||
value={`${formatPrice(week52Low)} - ${formatPrice(week52High)}`}
|
||||
/>
|
||||
</VStack>
|
||||
));
|
||||
|
||||
KeyMetrics.displayName = 'KeyMetrics';
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* LoadingSkeleton - 股票行情卡片加载骨架屏
|
||||
*
|
||||
* 在数据加载期间展示的骨架屏组件
|
||||
* 保持与实际内容相同的布局结构,提供良好的加载体验
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { Box, Flex, HStack, VStack, Skeleton } from '@chakra-ui/react';
|
||||
import { CardGlow } from '@components/FUI';
|
||||
import { glassCardStyle, DEEP_SPACE_THEME as T } from './theme';
|
||||
|
||||
/**
|
||||
* 股票行情卡片加载骨架屏
|
||||
*
|
||||
* 布局结构对应实际卡片:
|
||||
* - 头部:股票名称 + 操作按钮
|
||||
* - 价格:当前价格 + 涨跌幅
|
||||
* - 内容:多列数据区块
|
||||
*/
|
||||
export const LoadingSkeleton: React.FC = memo(() => (
|
||||
<Box
|
||||
{...glassCardStyle.containerGold}
|
||||
p={8}
|
||||
>
|
||||
{/* 装饰性光效 */}
|
||||
<CardGlow variant="gold" />
|
||||
|
||||
<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>
|
||||
|
||||
{/* 价格骨架:当前价格 + 涨跌幅 Badge */}
|
||||
<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>
|
||||
<Box flex={1}>
|
||||
<Skeleton
|
||||
height="120px"
|
||||
startColor={T.bgInset}
|
||||
endColor={T.borderGlass}
|
||||
borderRadius={T.radiusLG}
|
||||
/>
|
||||
</Box>
|
||||
<Box flex={1}>
|
||||
<Skeleton
|
||||
height="120px"
|
||||
startColor={T.bgInset}
|
||||
endColor={T.borderGlass}
|
||||
borderRadius={T.radiusLG}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
</VStack>
|
||||
</Box>
|
||||
));
|
||||
|
||||
LoadingSkeleton.displayName = 'LoadingSkeleton';
|
||||
|
||||
export default LoadingSkeleton;
|
||||
@@ -1,70 +1,113 @@
|
||||
/**
|
||||
* MainForceInfo - 主力动态原子组件
|
||||
* 显示主力净流入、机构持仓、买卖比例
|
||||
*
|
||||
* 显示主力资金和机构相关指标:
|
||||
* - 主力净流入(带正负颜色)
|
||||
* - 机构持仓比例
|
||||
* - 买卖比例进度条
|
||||
*
|
||||
* 注意:标题由外层 GlassSection 提供
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { Box, VStack, HStack, Text, Progress } from '@chakra-ui/react';
|
||||
import { formatNetInflow } from './formatters';
|
||||
import { STOCK_CARD_THEME } from './theme';
|
||||
import { DEEP_SPACE_THEME as T } from './theme';
|
||||
|
||||
export interface MainForceInfoProps {
|
||||
/** 主力净流入(亿) */
|
||||
mainNetInflow: number;
|
||||
/** 机构持仓比例(%) */
|
||||
institutionHolding: number;
|
||||
/** 买入比例(%) */
|
||||
buyRatio: number;
|
||||
/** 卖出比例(%) */
|
||||
sellRatio: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指标行组件 - 内部使用
|
||||
*/
|
||||
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="13px">
|
||||
<Text color={T.textMuted}>{label}</Text>
|
||||
<Text
|
||||
color={valueColor}
|
||||
fontWeight={highlight ? '700' : '600'}
|
||||
fontSize={highlight ? '15px' : '13px'}
|
||||
textShadow={highlight ? `0 0 10px ${valueColor}40` : undefined}
|
||||
>
|
||||
{value}
|
||||
</Text>
|
||||
</HStack>
|
||||
);
|
||||
|
||||
/**
|
||||
* 主力动态展示组件
|
||||
*
|
||||
* 纯展示组件,不包含标题
|
||||
* 应由 GlassSection 包装以提供标题
|
||||
*/
|
||||
export const MainForceInfo: React.FC<MainForceInfoProps> = memo(({
|
||||
mainNetInflow,
|
||||
institutionHolding,
|
||||
buyRatio,
|
||||
sellRatio,
|
||||
}) => {
|
||||
const { labelColor, valueColor, sectionTitleColor, borderColor, upColor, downColor } = STOCK_CARD_THEME;
|
||||
const inflowColor = mainNetInflow >= 0 ? upColor : downColor;
|
||||
const inflowColor = mainNetInflow >= 0 ? T.upColor : T.downColor;
|
||||
|
||||
return (
|
||||
<Box flex="1" borderLeftWidth="1px" borderColor={borderColor} pl={8}>
|
||||
<Text
|
||||
fontSize="14px"
|
||||
fontWeight="bold"
|
||||
color={sectionTitleColor}
|
||||
mb={3}
|
||||
>
|
||||
主力动态
|
||||
</Text>
|
||||
<VStack align="stretch" spacing={2} fontSize="14px">
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>主力净流入:</Text>
|
||||
<Text color={inflowColor} fontWeight="bold" fontSize="16px">
|
||||
{formatNetInflow(mainNetInflow)}
|
||||
<VStack align="stretch" spacing={2}>
|
||||
<MetricRow
|
||||
label="主力净流入"
|
||||
value={formatNetInflow(mainNetInflow)}
|
||||
valueColor={inflowColor}
|
||||
highlight
|
||||
/>
|
||||
<MetricRow
|
||||
label="机构持仓"
|
||||
value={`${institutionHolding.toFixed(2)}%`}
|
||||
valueColor={T.purple}
|
||||
highlight
|
||||
/>
|
||||
|
||||
{/* 买卖比例进度条 */}
|
||||
<Box mt={2}>
|
||||
<Progress
|
||||
value={buyRatio}
|
||||
size="sm"
|
||||
sx={{
|
||||
'& > div': {
|
||||
bg: T.upColor,
|
||||
boxShadow: T.upGlow,
|
||||
},
|
||||
}}
|
||||
bg={T.downColor}
|
||||
borderRadius="full"
|
||||
h="8px"
|
||||
/>
|
||||
<HStack justify="space-between" mt={2} fontSize="13px">
|
||||
<Text color={T.upColor} fontWeight="600">
|
||||
买入 {buyRatio}%
|
||||
</Text>
|
||||
<Text color={T.downColor} fontWeight="600">
|
||||
卖出 {sellRatio}%
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>机构持仓:</Text>
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{institutionHolding.toFixed(2)}%
|
||||
</Text>
|
||||
</HStack>
|
||||
{/* 买卖比例条 */}
|
||||
<Box mt={1}>
|
||||
<Progress
|
||||
value={buyRatio}
|
||||
size="sm"
|
||||
sx={{
|
||||
'& > div': { bg: upColor },
|
||||
}}
|
||||
bg={downColor}
|
||||
borderRadius="full"
|
||||
/>
|
||||
<HStack justify="space-between" mt={1} fontSize="14px">
|
||||
<Text color={upColor}>买入{buyRatio}%</Text>
|
||||
<Text color={downColor}>卖出{sellRatio}%</Text>
|
||||
</HStack>
|
||||
</Box>
|
||||
</VStack>
|
||||
</Box>
|
||||
</Box>
|
||||
</VStack>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,59 +1,74 @@
|
||||
/**
|
||||
* SecondaryQuote - 次要行情原子组件
|
||||
* 显示今开、昨收、最高、最低
|
||||
*
|
||||
* 显示今开、昨收、最高、最低等次要行情数据
|
||||
* 使用水平布局,通过竖线分隔符分隔各项
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { HStack, Text } from '@chakra-ui/react';
|
||||
import { Box, HStack, Text } from '@chakra-ui/react';
|
||||
import { formatPrice } from './formatters';
|
||||
import { STOCK_CARD_THEME } from './theme';
|
||||
import { DEEP_SPACE_THEME as T } from './theme';
|
||||
|
||||
export interface SecondaryQuoteProps {
|
||||
/** 今日开盘价 */
|
||||
todayOpen: number;
|
||||
/** 昨日收盘价 */
|
||||
yesterdayClose: number;
|
||||
/** 今日最高价 */
|
||||
todayHigh: number;
|
||||
/** 今日最低价 */
|
||||
todayLow: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 竖线分隔符组件
|
||||
*/
|
||||
const Divider: React.FC = () => (
|
||||
<Box w="1px" h="14px" bg={T.divider} />
|
||||
);
|
||||
|
||||
/**
|
||||
* 次要行情展示组件
|
||||
*
|
||||
* 水平排列展示今开、昨收、最高、最低
|
||||
* 最高使用上涨颜色,最低使用下跌颜色
|
||||
*/
|
||||
export const SecondaryQuote: React.FC<SecondaryQuoteProps> = memo(({
|
||||
todayOpen,
|
||||
yesterdayClose,
|
||||
todayHigh,
|
||||
todayLow,
|
||||
}) => {
|
||||
const { labelColor, valueColor, borderColor, upColor, downColor } = STOCK_CARD_THEME;
|
||||
|
||||
return (
|
||||
<HStack spacing={4} fontSize="14px" flexWrap="wrap">
|
||||
<Text color={labelColor}>
|
||||
今开:
|
||||
<Text as="span" color={valueColor} fontWeight="bold">
|
||||
{formatPrice(todayOpen)}
|
||||
</Text>
|
||||
}) => (
|
||||
<HStack spacing={6} fontSize="14px" flexWrap="wrap">
|
||||
<Text color={T.textMuted}>
|
||||
今开:
|
||||
<Text as="span" color={T.textWhite} fontWeight="600" ml={1}>
|
||||
{formatPrice(todayOpen)}
|
||||
</Text>
|
||||
<Text color={borderColor}>|</Text>
|
||||
<Text color={labelColor}>
|
||||
昨收:
|
||||
<Text as="span" color={valueColor} fontWeight="bold">
|
||||
{formatPrice(yesterdayClose)}
|
||||
</Text>
|
||||
</Text>
|
||||
<Divider />
|
||||
<Text color={T.textMuted}>
|
||||
昨收:
|
||||
<Text as="span" color={T.textWhite} fontWeight="600" ml={1}>
|
||||
{formatPrice(yesterdayClose)}
|
||||
</Text>
|
||||
<Text color={borderColor}>|</Text>
|
||||
<Text color={labelColor}>
|
||||
最高:
|
||||
<Text as="span" color={upColor} fontWeight="bold">
|
||||
{formatPrice(todayHigh)}
|
||||
</Text>
|
||||
</Text>
|
||||
<Divider />
|
||||
<Text color={T.textMuted}>
|
||||
最高:
|
||||
<Text as="span" color={T.upColor} fontWeight="600" ml={1}>
|
||||
{formatPrice(todayHigh)}
|
||||
</Text>
|
||||
<Text color={borderColor}>|</Text>
|
||||
<Text color={labelColor}>
|
||||
最低:
|
||||
<Text as="span" color={downColor} fontWeight="bold">
|
||||
{formatPrice(todayLow)}
|
||||
</Text>
|
||||
</Text>
|
||||
<Divider />
|
||||
<Text color={T.textMuted}>
|
||||
最低:
|
||||
<Text as="span" color={T.downColor} fontWeight="600" ml={1}>
|
||||
{formatPrice(todayLow)}
|
||||
</Text>
|
||||
</HStack>
|
||||
);
|
||||
});
|
||||
</Text>
|
||||
</HStack>
|
||||
));
|
||||
|
||||
SecondaryQuote.displayName = 'SecondaryQuote';
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
/**
|
||||
* StockQuoteCard 组件统一导出
|
||||
*
|
||||
* 组件分类:
|
||||
* - 原子组件:基础展示组件(价格、指标、信息)
|
||||
* - 容器组件:布局和装饰组件(玻璃容器、光效)
|
||||
* - 复合组件:功能组件(对比、搜索)
|
||||
* - 状态组件:加载、错误状态
|
||||
*/
|
||||
|
||||
// 原子组件
|
||||
// ============================================
|
||||
// 原子组件 - 数据展示
|
||||
// ============================================
|
||||
export { PriceDisplay } from './PriceDisplay';
|
||||
export { SecondaryQuote } from './SecondaryQuote';
|
||||
export { KeyMetrics } from './KeyMetrics';
|
||||
@@ -10,18 +18,36 @@ export { MainForceInfo } from './MainForceInfo';
|
||||
export { CompanyInfo } from './CompanyInfo';
|
||||
export { StockHeader } from './StockHeader';
|
||||
|
||||
// 复合组件
|
||||
// ============================================
|
||||
// 容器组件 - 布局
|
||||
// ============================================
|
||||
// 注意: 装饰光效组件已移至 @components/FUI/CardGlow
|
||||
export { GlassSection } from './GlassSection';
|
||||
|
||||
// ============================================
|
||||
// 状态组件 - 加载/错误
|
||||
// ============================================
|
||||
export { LoadingSkeleton } from './LoadingSkeleton';
|
||||
|
||||
// ============================================
|
||||
// 复合组件 - 功能性
|
||||
// ============================================
|
||||
export { default as CompareStockInput } from './CompareStockInput';
|
||||
export { default as StockCompareModal } from './StockCompareModal';
|
||||
|
||||
// ============================================
|
||||
// 工具和主题
|
||||
export { STOCK_CARD_THEME } from './theme';
|
||||
// ============================================
|
||||
export { STOCK_CARD_THEME, DEEP_SPACE_THEME, glassCardStyle } from './theme';
|
||||
export * from './formatters';
|
||||
|
||||
// ============================================
|
||||
// 类型导出
|
||||
// ============================================
|
||||
export type { PriceDisplayProps } from './PriceDisplay';
|
||||
export type { SecondaryQuoteProps } from './SecondaryQuote';
|
||||
export type { KeyMetricsProps } from './KeyMetrics';
|
||||
export type { MainForceInfoProps } from './MainForceInfo';
|
||||
export type { CompanyInfoProps, CompanyBasicInfo } from './CompanyInfo';
|
||||
export type { StockHeaderProps } from './StockHeader';
|
||||
export type { GlassSectionProps } from './GlassSection';
|
||||
|
||||
@@ -6,13 +6,19 @@
|
||||
* - 光影深度,弥散背景光
|
||||
* - 极致圆角,科幻数据终端感
|
||||
*
|
||||
* 保留原有所有功能:
|
||||
* - 股票头部(名称、代码、行业、对比、关注、分享)
|
||||
* - 价格显示(当前价、涨跌幅)
|
||||
* - 次要行情(今开、昨收、最高、最低)
|
||||
* - 关键指标(PE、市值、股本、换手率、52周)
|
||||
* - 主力动态(净流入、机构持仓、买卖比)
|
||||
* - 公司信息(成立、注册资本、所在地、官网、简介)
|
||||
* 功能模块:
|
||||
* - 股票头部:名称、代码、行业标签、操作按钮(对比、关注、分享)
|
||||
* - 价格展示:当前价格、涨跌幅 Badge
|
||||
* - 次要行情:今开、昨收、最高、最低(SecondaryQuote 组件)
|
||||
* - 数据区块:估值指标、市值股本、主力动态(三列 GlassSection 布局)
|
||||
*
|
||||
* 组件结构:
|
||||
* - GlowDecorations:装饰性光效(背景层)
|
||||
* - LoadingSkeleton:加载骨架屏
|
||||
* - GlassSection:玻璃容器(包装数据区块)
|
||||
* - SecondaryQuote:次要行情展示
|
||||
* - KeyMetrics:关键指标(估值 + 市值)
|
||||
* - MainForceInfo:主力动态
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
@@ -25,144 +31,38 @@ import {
|
||||
Badge,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
Skeleton,
|
||||
Progress,
|
||||
Link,
|
||||
Icon,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import { Share2, Calendar, Coins, MapPin, Globe } from 'lucide-react';
|
||||
import { Share2 } from 'lucide-react';
|
||||
import FavoriteButton from '@components/FavoriteButton';
|
||||
import { CardGlow } from '@components/FUI';
|
||||
|
||||
import { StockCompareModal, CompareStockInput } from './components';
|
||||
// 子组件导入
|
||||
import {
|
||||
StockCompareModal,
|
||||
CompareStockInput,
|
||||
LoadingSkeleton,
|
||||
GlassSection,
|
||||
SecondaryQuote,
|
||||
MainForceInfo,
|
||||
} from './components';
|
||||
|
||||
// Hooks 和工具
|
||||
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 { DEEP_SPACE_THEME, glassCardStyle } from './components/theme';
|
||||
import { formatPrice, formatChangePercent } from './components/formatters';
|
||||
import type { StockQuoteCardProps } from './types';
|
||||
|
||||
/** 主题常量简写 */
|
||||
const T = DEEP_SPACE_THEME;
|
||||
|
||||
/**
|
||||
* 装饰性光效组件
|
||||
*/
|
||||
const GlowDecorations: React.FC = () => (
|
||||
<>
|
||||
{/* 顶部金色光条 */}
|
||||
<Box {...decorativeElements.topGlowBar} />
|
||||
|
||||
{/* 左上角光晕 */}
|
||||
<Box
|
||||
{...decorativeElements.cornerGlow}
|
||||
top="-40px"
|
||||
left="-40px"
|
||||
/>
|
||||
|
||||
{/* 右下角光晕 */}
|
||||
<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}
|
||||
>
|
||||
<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>
|
||||
<Box flex={1}>
|
||||
<Skeleton height="120px" startColor={T.bgInset} endColor={T.borderGlass} borderRadius={T.radiusLG} />
|
||||
</Box>
|
||||
</Flex>
|
||||
</VStack>
|
||||
</Box>
|
||||
);
|
||||
|
||||
/**
|
||||
* 玻璃态内嵌区块
|
||||
*/
|
||||
interface GlassSectionProps {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
flex?: number | string;
|
||||
}
|
||||
|
||||
const GlassSection: React.FC<GlassSectionProps> = ({ title, children, flex = 1 }) => (
|
||||
<Box
|
||||
flex={flex}
|
||||
bg={T.bgInset}
|
||||
borderRadius={T.radiusLG}
|
||||
border={`1px solid ${T.borderGlass}`}
|
||||
p={4}
|
||||
position="relative"
|
||||
transition={T.transitionFast}
|
||||
_hover={{
|
||||
borderColor: T.borderGoldHover,
|
||||
bg: 'rgba(15, 18, 35, 0.6)',
|
||||
}}
|
||||
>
|
||||
{/* 区块顶部光条 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top={0}
|
||||
left="20px"
|
||||
right="20px"
|
||||
height="1px"
|
||||
background={`linear-gradient(90deg, transparent, ${T.gold}40, transparent)`}
|
||||
/>
|
||||
|
||||
<Text
|
||||
fontSize="14px"
|
||||
fontWeight="700"
|
||||
color={T.gold}
|
||||
mb={3}
|
||||
textTransform="uppercase"
|
||||
letterSpacing="0.1em"
|
||||
textShadow={`0 0 12px ${T.gold}60`}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
|
||||
/**
|
||||
* 指标行组件
|
||||
* 指标行组件 - 用于数据区块内的单行指标展示
|
||||
*
|
||||
* @param label - 指标标签
|
||||
* @param value - 指标值
|
||||
* @param valueColor - 值的颜色(默认白色)
|
||||
* @param highlight - 是否高亮显示(加粗 + 发光)
|
||||
*/
|
||||
interface MetricRowProps {
|
||||
label: string;
|
||||
@@ -222,12 +122,11 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
return <LoadingSkeleton />;
|
||||
}
|
||||
|
||||
// 涨跌判断
|
||||
// 涨跌判断(用于价格颜色)
|
||||
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 (
|
||||
<>
|
||||
@@ -235,7 +134,7 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
{...glassCardStyle.containerGold}
|
||||
p={6}
|
||||
>
|
||||
<GlowDecorations />
|
||||
<CardGlow variant="gold" />
|
||||
|
||||
{/* 内容区域(在装饰层之上)*/}
|
||||
<VStack align="stretch" spacing={4} position="relative" zIndex={1}>
|
||||
@@ -340,39 +239,16 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
</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>
|
||||
<SecondaryQuote
|
||||
todayOpen={quoteData.todayOpen}
|
||||
yesterdayClose={quoteData.yesterdayClose}
|
||||
todayHigh={quoteData.todayHigh}
|
||||
todayLow={quoteData.todayLow}
|
||||
/>
|
||||
|
||||
{/* ========== 数据区块(三列布局)========== */}
|
||||
<Flex gap={4} flexWrap={{ base: 'wrap', lg: 'nowrap' }}>
|
||||
{/* 第一列:估值指标 */}
|
||||
{/* 第一列:估值指标 - PE、流通股本、换手率 */}
|
||||
<GlassSection title="估值指标" flex={1}>
|
||||
<VStack align="stretch" spacing={2}>
|
||||
<MetricRow
|
||||
@@ -393,7 +269,7 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
</VStack>
|
||||
</GlassSection>
|
||||
|
||||
{/* 第二列:市值股本 */}
|
||||
{/* 第二列:市值股本 - 流通市值、发行总股本、52周波动 */}
|
||||
<GlassSection title="市值股本" flex={1}>
|
||||
<VStack align="stretch" spacing={2}>
|
||||
<MetricRow
|
||||
@@ -415,114 +291,16 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
|
||||
{/* 第三列:主力动态 */}
|
||||
<GlassSection title="主力动态" flex={1}>
|
||||
<VStack align="stretch" spacing={2}>
|
||||
<MetricRow
|
||||
label="主力净流入"
|
||||
value={formatNetInflow(quoteData.mainNetInflow)}
|
||||
valueColor={inflowColor}
|
||||
highlight
|
||||
/>
|
||||
<MetricRow
|
||||
label="机构持仓"
|
||||
value={`${quoteData.institutionHolding.toFixed(2)}%`}
|
||||
valueColor={T.purple}
|
||||
highlight
|
||||
/>
|
||||
|
||||
{/* 买卖比例条 */}
|
||||
<Box mt={2}>
|
||||
<Progress
|
||||
value={quoteData.buyRatio}
|
||||
size="sm"
|
||||
sx={{
|
||||
'& > div': {
|
||||
bg: T.upColor,
|
||||
boxShadow: T.upGlow,
|
||||
},
|
||||
}}
|
||||
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>
|
||||
<MainForceInfo
|
||||
mainNetInflow={quoteData.mainNetInflow || 0}
|
||||
institutionHolding={quoteData.institutionHolding}
|
||||
buyRatio={quoteData.buyRatio}
|
||||
sellRatio={quoteData.sellRatio}
|
||||
/>
|
||||
</GlassSection>
|
||||
</Flex>
|
||||
|
||||
{/* ========== 公司信息(已注释)========== */}
|
||||
{/* {basicInfo && (
|
||||
<>
|
||||
<Box
|
||||
h="1px"
|
||||
bg={`linear-gradient(90deg, transparent, ${T.gold}30, transparent)`}
|
||||
/>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
</>
|
||||
)} */}
|
||||
{/* 公司信息区块已移至 CompanyOverview 模块 */}
|
||||
</VStack>
|
||||
</Box>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user