feat: 添加股票行情卡片
This commit is contained in:
221
src/views/Company/components/StockQuoteCard/index.tsx
Normal file
221
src/views/Company/components/StockQuoteCard/index.tsx
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
/**
|
||||||
|
* StockQuoteCard - 股票行情卡片组件
|
||||||
|
*
|
||||||
|
* 展示股票的实时行情、关键指标和主力动态
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Card,
|
||||||
|
CardBody,
|
||||||
|
Flex,
|
||||||
|
HStack,
|
||||||
|
VStack,
|
||||||
|
Text,
|
||||||
|
Badge,
|
||||||
|
Progress,
|
||||||
|
Skeleton,
|
||||||
|
useColorModeValue,
|
||||||
|
} 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 = useColorModeValue('white', 'gray.800');
|
||||||
|
const borderColor = useColorModeValue('gray.200', 'gray.700');
|
||||||
|
const labelColor = useColorModeValue('gray.500', 'gray.400');
|
||||||
|
const valueColor = useColorModeValue('gray.800', 'gray.100');
|
||||||
|
const sectionTitleColor = useColorModeValue('gray.600', 'gray.300');
|
||||||
|
|
||||||
|
// 涨跌颜色
|
||||||
|
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;
|
||||||
33
src/views/Company/components/StockQuoteCard/mockData.ts
Normal file
33
src/views/Company/components/StockQuoteCard/mockData.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import type { StockQuoteCardData } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 贵州茅台 Mock 数据
|
||||||
|
*/
|
||||||
|
export const mockStockQuoteData: StockQuoteCardData = {
|
||||||
|
// 基础信息
|
||||||
|
name: '贵州茅台',
|
||||||
|
code: '600519.SH',
|
||||||
|
indexTags: ['沪深300'],
|
||||||
|
|
||||||
|
// 价格信息
|
||||||
|
currentPrice: 2178.5,
|
||||||
|
changePercent: 3.65,
|
||||||
|
todayOpen: 2156.0,
|
||||||
|
yesterdayClose: 2101.0,
|
||||||
|
|
||||||
|
// 关键指标
|
||||||
|
pe: 38.62,
|
||||||
|
pb: 14.82,
|
||||||
|
marketCap: '2.73万亿',
|
||||||
|
week52Low: 1980,
|
||||||
|
week52High: 2350,
|
||||||
|
|
||||||
|
// 主力动态
|
||||||
|
mainNetInflow: 1.28,
|
||||||
|
institutionHolding: 72.35,
|
||||||
|
buyRatio: 85,
|
||||||
|
sellRatio: 15,
|
||||||
|
|
||||||
|
// 更新时间
|
||||||
|
updateTime: '2025-12-03 14:30:25',
|
||||||
|
};
|
||||||
43
src/views/Company/components/StockQuoteCard/types.ts
Normal file
43
src/views/Company/components/StockQuoteCard/types.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* StockQuoteCard 组件类型定义
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 股票行情卡片数据
|
||||||
|
*/
|
||||||
|
export interface StockQuoteCardData {
|
||||||
|
// 基础信息
|
||||||
|
name: string; // 股票名称
|
||||||
|
code: string; // 股票代码
|
||||||
|
indexTags: string[]; // 指数标签(如 沪深300、上证50)
|
||||||
|
|
||||||
|
// 价格信息
|
||||||
|
currentPrice: number; // 当前价格
|
||||||
|
changePercent: number; // 涨跌幅(百分比,如 3.65 表示 +3.65%)
|
||||||
|
todayOpen: number; // 今开
|
||||||
|
yesterdayClose: number; // 昨收
|
||||||
|
|
||||||
|
// 关键指标
|
||||||
|
pe: number; // 市盈率
|
||||||
|
pb: number; // 市净率
|
||||||
|
marketCap: string; // 流通市值(已格式化,如 "2.73万亿")
|
||||||
|
week52Low: number; // 52周最低
|
||||||
|
week52High: number; // 52周最高
|
||||||
|
|
||||||
|
// 主力动态
|
||||||
|
mainNetInflow: number; // 主力净流入(亿)
|
||||||
|
institutionHolding: number; // 机构持仓比例(百分比)
|
||||||
|
buyRatio: number; // 买入比例(百分比)
|
||||||
|
sellRatio: number; // 卖出比例(百分比)
|
||||||
|
|
||||||
|
// 更新时间
|
||||||
|
updateTime: string; // 格式:YYYY-MM-DD HH:mm:ss
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StockQuoteCard 组件 Props
|
||||||
|
*/
|
||||||
|
export interface StockQuoteCardProps {
|
||||||
|
data?: StockQuoteCardData;
|
||||||
|
isLoading?: boolean;
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import { useCompanyEvents } from './hooks/useCompanyEvents';
|
|||||||
|
|
||||||
// 页面组件
|
// 页面组件
|
||||||
import CompanyHeader from './components/CompanyHeader';
|
import CompanyHeader from './components/CompanyHeader';
|
||||||
|
import StockQuoteCard from './components/StockQuoteCard';
|
||||||
import CompanyTabs from './components/CompanyTabs';
|
import CompanyTabs from './components/CompanyTabs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,6 +81,9 @@ const CompanyIndex = () => {
|
|||||||
bgColor={bgColor}
|
bgColor={bgColor}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* 股票行情卡片:价格、关键指标、主力动态 */}
|
||||||
|
<StockQuoteCard />
|
||||||
|
|
||||||
{/* Tab 切换区域:概览、行情、财务、预测 */}
|
{/* Tab 切换区域:概览、行情、财务、预测 */}
|
||||||
<CompanyTabs
|
<CompanyTabs
|
||||||
stockCode={stockCode}
|
stockCode={stockCode}
|
||||||
|
|||||||
Reference in New Issue
Block a user