- DeepAnalysisTab: 移除 useColorModeValue,使用固定颜色值 - NewsEventsTab: 移除 useColorModeValue,简化 hover 颜色 - FinancialPanorama: 移除 useColorMode/useColorModeValue - MarketDataView: 移除 dark 主题配置,简化颜色逻辑 - StockQuoteCard: 移除 useColorModeValue,使用固定颜色 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
221 lines
6.6 KiB
TypeScript
221 lines
6.6 KiB
TypeScript
/**
|
||
* StockQuoteCard - 股票行情卡片组件
|
||
*
|
||
* 展示股票的实时行情、关键指标和主力动态
|
||
*/
|
||
|
||
import React from 'react';
|
||
import {
|
||
Box,
|
||
Card,
|
||
CardBody,
|
||
Flex,
|
||
HStack,
|
||
VStack,
|
||
Text,
|
||
Badge,
|
||
Progress,
|
||
Skeleton,
|
||
} from '@chakra-ui/react';
|
||
|
||
import type { StockQuoteCardProps } from './types';
|
||
import { mockStockQuoteData } from './mockData';
|
||
|
||
/**
|
||
* 格式化价格显示
|
||
*/
|
||
const formatPrice = (price: number): string => {
|
||
return price.toLocaleString('zh-CN', {
|
||
minimumFractionDigits: 2,
|
||
maximumFractionDigits: 2,
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 格式化涨跌幅显示
|
||
*/
|
||
const formatChangePercent = (percent: number): string => {
|
||
const sign = percent >= 0 ? '+' : '';
|
||
return `${sign}${percent.toFixed(2)}%`;
|
||
};
|
||
|
||
/**
|
||
* 格式化主力净流入显示
|
||
*/
|
||
const formatNetInflow = (value: number): string => {
|
||
const sign = value >= 0 ? '+' : '';
|
||
return `${sign}${value.toFixed(2)}亿`;
|
||
};
|
||
|
||
const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||
data = mockStockQuoteData,
|
||
isLoading = false,
|
||
}) => {
|
||
// 颜色配置
|
||
const cardBg = 'white';
|
||
const borderColor = 'gray.200';
|
||
const labelColor = 'gray.500';
|
||
const valueColor = 'gray.800';
|
||
const sectionTitleColor = 'gray.600';
|
||
|
||
// 涨跌颜色
|
||
const priceColor = data.changePercent >= 0 ? 'green.500' : 'red.500';
|
||
const inflowColor = data.mainNetInflow >= 0 ? 'green.500' : 'red.500';
|
||
|
||
if (isLoading) {
|
||
return (
|
||
<Card bg={cardBg} shadow="sm" borderWidth="1px" borderColor={borderColor}>
|
||
<CardBody>
|
||
<Skeleton height="120px" />
|
||
</CardBody>
|
||
</Card>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<Card bg={cardBg} shadow="sm" borderWidth="1px" borderColor={borderColor}>
|
||
<CardBody py={4} px={6}>
|
||
{/* 顶部:股票名称 + 更新时间 */}
|
||
<Flex justify="space-between" align="center" mb={4}>
|
||
<HStack spacing={3}>
|
||
<Text fontSize="xl" fontWeight="bold" color={valueColor}>
|
||
{data.name}
|
||
</Text>
|
||
<Text fontSize="md" color={labelColor}>
|
||
({data.code})
|
||
</Text>
|
||
{data.indexTags.map((tag) => (
|
||
<Badge
|
||
key={tag}
|
||
variant="outline"
|
||
colorScheme="gray"
|
||
fontSize="xs"
|
||
px={2}
|
||
>
|
||
{tag}
|
||
</Badge>
|
||
))}
|
||
</HStack>
|
||
<Text fontSize="sm" color={labelColor}>
|
||
更新时间:{data.updateTime}
|
||
</Text>
|
||
</Flex>
|
||
|
||
{/* 三栏布局 */}
|
||
<Flex gap={8}>
|
||
{/* 左栏:价格信息 */}
|
||
<Box flex="1">
|
||
<HStack align="baseline" spacing={3} mb={3}>
|
||
<Text fontSize="3xl" fontWeight="bold" color={priceColor}>
|
||
{formatPrice(data.currentPrice)}
|
||
</Text>
|
||
<Badge
|
||
colorScheme={data.changePercent >= 0 ? 'green' : 'red'}
|
||
fontSize="md"
|
||
px={2}
|
||
py={0.5}
|
||
>
|
||
{formatChangePercent(data.changePercent)}
|
||
</Badge>
|
||
</HStack>
|
||
<HStack spacing={6} color={labelColor} fontSize="sm">
|
||
<Text>
|
||
今开:
|
||
<Text as="span" color={valueColor} fontWeight="medium">
|
||
{formatPrice(data.todayOpen)}
|
||
</Text>
|
||
</Text>
|
||
<Text>
|
||
昨收:
|
||
<Text as="span" color={valueColor} fontWeight="medium">
|
||
{formatPrice(data.yesterdayClose)}
|
||
</Text>
|
||
</Text>
|
||
</HStack>
|
||
</Box>
|
||
|
||
{/* 中栏:关键指标 */}
|
||
<Box flex="1" borderLeftWidth="1px" borderColor={borderColor} pl={8}>
|
||
<Text
|
||
fontSize="sm"
|
||
fontWeight="medium"
|
||
color={sectionTitleColor}
|
||
mb={3}
|
||
>
|
||
关键指标
|
||
</Text>
|
||
<VStack align="stretch" spacing={2} fontSize="sm">
|
||
<HStack justify="space-between">
|
||
<Text color={labelColor}>市盈率(PE):</Text>
|
||
<Text color={valueColor} fontWeight="medium">
|
||
{data.pe.toFixed(2)}
|
||
</Text>
|
||
</HStack>
|
||
<HStack justify="space-between">
|
||
<Text color={labelColor}>市净率(PB):</Text>
|
||
<Text color={valueColor} fontWeight="medium">
|
||
{data.pb.toFixed(2)}
|
||
</Text>
|
||
</HStack>
|
||
<HStack justify="space-between">
|
||
<Text color={labelColor}>流通市值:</Text>
|
||
<Text color={valueColor} fontWeight="medium">
|
||
{data.marketCap}
|
||
</Text>
|
||
</HStack>
|
||
<HStack justify="space-between">
|
||
<Text color={labelColor}>52周波动:</Text>
|
||
<Text color={valueColor} fontWeight="medium">
|
||
{formatPrice(data.week52Low)}-{formatPrice(data.week52High)}
|
||
</Text>
|
||
</HStack>
|
||
</VStack>
|
||
</Box>
|
||
|
||
{/* 右栏:主力动态 */}
|
||
<Box flex="1" borderLeftWidth="1px" borderColor={borderColor} pl={8}>
|
||
<Text
|
||
fontSize="sm"
|
||
fontWeight="medium"
|
||
color={sectionTitleColor}
|
||
mb={3}
|
||
>
|
||
主力动态
|
||
</Text>
|
||
<VStack align="stretch" spacing={2} fontSize="sm">
|
||
<HStack justify="space-between">
|
||
<Text color={labelColor}>主力净流入:</Text>
|
||
<Text color={inflowColor} fontWeight="medium">
|
||
{formatNetInflow(data.mainNetInflow)}
|
||
</Text>
|
||
</HStack>
|
||
<HStack justify="space-between">
|
||
<Text color={labelColor}>机构持仓:</Text>
|
||
<Text color={valueColor} fontWeight="medium">
|
||
{data.institutionHolding.toFixed(2)}%
|
||
</Text>
|
||
</HStack>
|
||
{/* 买卖比例条 */}
|
||
<Box mt={1}>
|
||
<Progress
|
||
value={data.buyRatio}
|
||
size="sm"
|
||
colorScheme="green"
|
||
bg="red.400"
|
||
borderRadius="full"
|
||
/>
|
||
<HStack justify="space-between" mt={1} fontSize="xs">
|
||
<Text color="green.500">买入{data.buyRatio}%</Text>
|
||
<Text color="red.500">卖出{data.sellRatio}%</Text>
|
||
</HStack>
|
||
</Box>
|
||
</VStack>
|
||
</Box>
|
||
</Flex>
|
||
</CardBody>
|
||
</Card>
|
||
);
|
||
};
|
||
|
||
export default StockQuoteCard;
|