Compare commits
3 Commits
4274341ed5
...
3382dd1036
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3382dd1036 | ||
|
|
9423094af2 | ||
|
|
4f38505a80 |
84
src/components/FavoriteButton/index.tsx
Normal file
84
src/components/FavoriteButton/index.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* FavoriteButton - 通用关注/收藏按钮组件(图标按钮)
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { IconButton, Tooltip, Spinner } from '@chakra-ui/react';
|
||||
import { Star } from 'lucide-react';
|
||||
|
||||
export interface FavoriteButtonProps {
|
||||
/** 是否已关注 */
|
||||
isFavorite: boolean;
|
||||
/** 加载状态 */
|
||||
isLoading?: boolean;
|
||||
/** 点击回调 */
|
||||
onClick: () => void;
|
||||
/** 按钮大小 */
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
/** 颜色主题 */
|
||||
colorScheme?: 'gold' | 'default';
|
||||
/** 是否显示 tooltip */
|
||||
showTooltip?: boolean;
|
||||
}
|
||||
|
||||
// 颜色配置
|
||||
const COLORS = {
|
||||
gold: {
|
||||
active: '#F4D03F', // 已关注 - 亮金色
|
||||
inactive: '#C9A961', // 未关注 - 暗金色
|
||||
hoverBg: 'whiteAlpha.100',
|
||||
},
|
||||
default: {
|
||||
active: 'yellow.400',
|
||||
inactive: 'gray.400',
|
||||
hoverBg: 'gray.100',
|
||||
},
|
||||
};
|
||||
|
||||
const FavoriteButton: React.FC<FavoriteButtonProps> = ({
|
||||
isFavorite,
|
||||
isLoading = false,
|
||||
onClick,
|
||||
size = 'sm',
|
||||
colorScheme = 'gold',
|
||||
showTooltip = true,
|
||||
}) => {
|
||||
const colors = COLORS[colorScheme];
|
||||
const currentColor = isFavorite ? colors.active : colors.inactive;
|
||||
const label = isFavorite ? '取消关注' : '加入自选';
|
||||
|
||||
const iconButton = (
|
||||
<IconButton
|
||||
aria-label={label}
|
||||
icon={
|
||||
isLoading ? (
|
||||
<Spinner size="sm" color={currentColor} />
|
||||
) : (
|
||||
<Star
|
||||
size={size === 'sm' ? 18 : size === 'md' ? 20 : 24}
|
||||
fill={isFavorite ? currentColor : 'none'}
|
||||
stroke={currentColor}
|
||||
/>
|
||||
)
|
||||
}
|
||||
variant="ghost"
|
||||
color={currentColor}
|
||||
size={size}
|
||||
onClick={onClick}
|
||||
isDisabled={isLoading}
|
||||
_hover={{ bg: colors.hoverBg }}
|
||||
/>
|
||||
);
|
||||
|
||||
if (showTooltip) {
|
||||
return (
|
||||
<Tooltip label={label} placement="top">
|
||||
{iconButton}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return iconButton;
|
||||
};
|
||||
|
||||
export default FavoriteButton;
|
||||
@@ -1,5 +1,5 @@
|
||||
// src/views/Company/components/CompanyHeader/SearchBar.js
|
||||
// 股票搜索栏组件
|
||||
// 股票搜索栏组件 - 金色主题
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
@@ -30,7 +30,7 @@ const SearchBar = ({
|
||||
<HStack spacing={3}>
|
||||
<InputGroup size="lg" maxW="300px">
|
||||
<InputLeftElement pointerEvents="none">
|
||||
<SearchIcon color="gray.400" />
|
||||
<SearchIcon color="#C9A961" />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
placeholder="输入股票代码"
|
||||
@@ -38,17 +38,27 @@ const SearchBar = ({
|
||||
onChange={(e) => onInputChange(e.target.value)}
|
||||
onKeyPress={onKeyPress}
|
||||
borderRadius="md"
|
||||
color="white"
|
||||
borderColor="#C9A961"
|
||||
_placeholder={{ color: '#C9A961' }}
|
||||
_focus={{
|
||||
borderColor: 'blue.500',
|
||||
boxShadow: '0 0 0 1px #3182ce',
|
||||
borderColor: '#F4D03F',
|
||||
boxShadow: '0 0 0 1px #F4D03F',
|
||||
}}
|
||||
_hover={{
|
||||
borderColor: '#F4D03F',
|
||||
}}
|
||||
/>
|
||||
</InputGroup>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
size="lg"
|
||||
onClick={onSearch}
|
||||
leftIcon={<SearchIcon />}
|
||||
bg="#1A202C"
|
||||
color="#C9A961"
|
||||
borderWidth="1px"
|
||||
borderColor="#C9A961"
|
||||
_hover={{ bg: '#1a1a1a', borderColor: '#F4D03F', color: '#F4D03F' }}
|
||||
>
|
||||
查询
|
||||
</Button>
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// src/views/Company/components/CompanyHeader/WatchlistButton.js
|
||||
// 自选股按钮组件
|
||||
|
||||
import React from 'react';
|
||||
import { Button } from '@chakra-ui/react';
|
||||
import { StarIcon } from '@chakra-ui/icons';
|
||||
|
||||
/**
|
||||
* 自选股按钮组件
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {boolean} props.isInWatchlist - 是否已在自选股中
|
||||
* @param {boolean} props.isLoading - 是否正在加载
|
||||
* @param {Function} props.onClick - 点击回调
|
||||
*/
|
||||
const WatchlistButton = ({
|
||||
isInWatchlist,
|
||||
isLoading,
|
||||
onClick,
|
||||
}) => {
|
||||
return (
|
||||
<Button
|
||||
colorScheme={isInWatchlist ? 'yellow' : 'teal'}
|
||||
variant={isInWatchlist ? 'solid' : 'outline'}
|
||||
size="lg"
|
||||
onClick={onClick}
|
||||
leftIcon={<StarIcon />}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{isInWatchlist ? '已关注' : '关注'}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default WatchlistButton;
|
||||
@@ -9,82 +9,50 @@ import {
|
||||
VStack,
|
||||
Heading,
|
||||
Text,
|
||||
Badge,
|
||||
} from '@chakra-ui/react';
|
||||
|
||||
import SearchBar from './SearchBar';
|
||||
import WatchlistButton from './WatchlistButton';
|
||||
|
||||
/**
|
||||
* 公司详情页面头部区域组件
|
||||
*
|
||||
* 包含:
|
||||
* - 页面标题和描述
|
||||
* - 页面标题和描述(金色主题)
|
||||
* - 股票搜索栏
|
||||
* - 自选股按钮
|
||||
* - 当前股票代码显示
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {string} props.stockCode - 当前股票代码
|
||||
* @param {string} props.inputCode - 搜索输入框值
|
||||
* @param {Function} props.onInputChange - 输入变化回调
|
||||
* @param {Function} props.onSearch - 搜索回调
|
||||
* @param {Function} props.onKeyPress - 键盘事件回调
|
||||
* @param {boolean} props.isInWatchlist - 是否在自选股中
|
||||
* @param {boolean} props.isWatchlistLoading - 自选股操作加载中
|
||||
* @param {Function} props.onWatchlistToggle - 自选股切换回调
|
||||
* @param {string} props.bgColor - 背景颜色
|
||||
*/
|
||||
const CompanyHeader = ({
|
||||
stockCode,
|
||||
inputCode,
|
||||
onInputChange,
|
||||
onSearch,
|
||||
onKeyPress,
|
||||
isInWatchlist,
|
||||
isWatchlistLoading,
|
||||
onWatchlistToggle,
|
||||
bgColor,
|
||||
}) => {
|
||||
return (
|
||||
<Card bg={bgColor} shadow="md">
|
||||
<CardBody>
|
||||
<HStack justify="space-between" align="center">
|
||||
{/* 标题区域 */}
|
||||
{/* 标题区域 - 金色主题 */}
|
||||
<VStack align="start" spacing={1}>
|
||||
<Heading size="lg">个股详情</Heading>
|
||||
<Text color="gray.600" fontSize="sm">
|
||||
<Heading size="lg" color="#F4D03F">个股详情</Heading>
|
||||
<Text color="#C9A961" fontSize="sm">
|
||||
查看股票实时行情、财务数据和盈利预测
|
||||
</Text>
|
||||
</VStack>
|
||||
|
||||
{/* 操作区域 */}
|
||||
<HStack spacing={3}>
|
||||
{/* 搜索栏 */}
|
||||
<SearchBar
|
||||
inputCode={inputCode}
|
||||
onInputChange={onInputChange}
|
||||
onSearch={onSearch}
|
||||
onKeyPress={onKeyPress}
|
||||
/>
|
||||
|
||||
{/* 自选股按钮 */}
|
||||
<WatchlistButton
|
||||
isInWatchlist={isInWatchlist}
|
||||
isLoading={isWatchlistLoading}
|
||||
onClick={onWatchlistToggle}
|
||||
/>
|
||||
</HStack>
|
||||
</HStack>
|
||||
|
||||
{/* 当前股票信息 */}
|
||||
<HStack mt={4} spacing={4}>
|
||||
<Badge colorScheme="blue" fontSize="md" px={3} py={1}>
|
||||
股票代码: {stockCode}
|
||||
</Badge>
|
||||
<Text fontSize="sm" color="gray.600">
|
||||
更新时间: {new Date().toLocaleString()}
|
||||
</Text>
|
||||
{/* 搜索栏 */}
|
||||
<SearchBar
|
||||
inputCode={inputCode}
|
||||
onInputChange={onInputChange}
|
||||
onSearch={onSearch}
|
||||
onKeyPress={onKeyPress}
|
||||
/>
|
||||
</HStack>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// src/views/Company/components/CompanyTabs/TabNavigation.js
|
||||
// Tab 导航组件 - 动态渲染 Tab 按钮
|
||||
// Tab 导航组件 - 动态渲染 Tab 按钮(黑金主题)
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
@@ -10,31 +10,41 @@ import {
|
||||
Text,
|
||||
} from '@chakra-ui/react';
|
||||
|
||||
import { COMPANY_TABS, TAB_SELECTED_STYLE } from '../../constants';
|
||||
import { COMPANY_TABS } from '../../constants';
|
||||
|
||||
// 黑金主题颜色配置
|
||||
const THEME_COLORS = {
|
||||
bg: '#1A202C', // 背景纯黑
|
||||
selectedBg: '#C9A961', // 选中项金色背景
|
||||
selectedText: '#FFFFFF', // 选中项白色文字
|
||||
unselectedText: '#999999', // 未选中项深灰色
|
||||
};
|
||||
|
||||
/**
|
||||
* Tab 导航组件
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {string} props.tabBg - Tab 列表背景色
|
||||
* @param {string} props.activeBg - 激活状态背景色
|
||||
* Tab 导航组件(黑金主题)
|
||||
*/
|
||||
const TabNavigation = ({ tabBg, activeBg }) => {
|
||||
const TabNavigation = () => {
|
||||
return (
|
||||
<TabList p={4} bg={tabBg}>
|
||||
<TabList py={4} bg={THEME_COLORS.bg} borderTopLeftRadius="16px" borderTopRightRadius="16px">
|
||||
{COMPANY_TABS.map((tab, index) => (
|
||||
<Tab
|
||||
key={tab.key}
|
||||
color={THEME_COLORS.unselectedText}
|
||||
borderRadius="full"
|
||||
px={4}
|
||||
py={2}
|
||||
_selected={{
|
||||
bg: activeBg,
|
||||
color: 'white',
|
||||
...TAB_SELECTED_STYLE,
|
||||
bg: THEME_COLORS.selectedBg,
|
||||
color: THEME_COLORS.selectedText,
|
||||
}}
|
||||
_hover={{
|
||||
color: THEME_COLORS.selectedText,
|
||||
}}
|
||||
mr={index < COMPANY_TABS.length - 1 ? 2 : 0}
|
||||
>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={tab.icon} />
|
||||
<Text>{tab.name}</Text>
|
||||
<Icon as={tab.icon} boxSize="18px" />
|
||||
<Text fontSize="15px">{tab.name}</Text>
|
||||
</HStack>
|
||||
</Tab>
|
||||
))}
|
||||
|
||||
@@ -46,9 +46,8 @@ const TAB_COMPONENTS = {
|
||||
* @param {Object} props
|
||||
* @param {string} props.stockCode - 当前股票代码
|
||||
* @param {Function} props.onTabChange - Tab 变更回调 (index, tabName, prevIndex) => void
|
||||
* @param {string} props.bgColor - 背景颜色
|
||||
*/
|
||||
const CompanyTabs = ({ stockCode, onTabChange, bgColor }) => {
|
||||
const CompanyTabs = ({ stockCode, onTabChange }) => {
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
|
||||
/**
|
||||
@@ -65,7 +64,7 @@ const CompanyTabs = ({ stockCode, onTabChange, bgColor }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Card bg={bgColor} shadow="lg">
|
||||
<Card shadow="lg" bg='#1A202C'>
|
||||
<CardBody p={0}>
|
||||
<Tabs
|
||||
variant="soft-rounded"
|
||||
@@ -74,8 +73,8 @@ const CompanyTabs = ({ stockCode, onTabChange, bgColor }) => {
|
||||
index={currentIndex}
|
||||
onChange={handleTabChange}
|
||||
>
|
||||
{/* Tab 导航 */}
|
||||
<TabNavigation tabBg="gray.50" activeBg="blue.500" />
|
||||
{/* Tab 导航(黑金主题) */}
|
||||
<TabNavigation />
|
||||
|
||||
<Divider />
|
||||
|
||||
@@ -84,7 +83,7 @@ const CompanyTabs = ({ stockCode, onTabChange, bgColor }) => {
|
||||
{COMPANY_TABS.map((tab) => {
|
||||
const Component = TAB_COMPONENTS[tab.key];
|
||||
return (
|
||||
<TabPanel key={tab.key} p={6}>
|
||||
<TabPanel key={tab.key}>
|
||||
<Component stockCode={stockCode} />
|
||||
</TabPanel>
|
||||
);
|
||||
|
||||
@@ -16,8 +16,12 @@ import {
|
||||
Badge,
|
||||
Progress,
|
||||
Skeleton,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react';
|
||||
import { Share2 } from 'lucide-react';
|
||||
|
||||
import FavoriteButton from '@components/FavoriteButton';
|
||||
import type { StockQuoteCardProps } from './types';
|
||||
import { mockStockQuoteData } from './mockData';
|
||||
|
||||
@@ -50,17 +54,28 @@ const formatNetInflow = (value: number): string => {
|
||||
const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
data = mockStockQuoteData,
|
||||
isLoading = false,
|
||||
isInWatchlist = false,
|
||||
isWatchlistLoading = false,
|
||||
onWatchlistToggle,
|
||||
onShare,
|
||||
}) => {
|
||||
// 颜色配置
|
||||
const cardBg = 'white';
|
||||
const borderColor = 'gray.200';
|
||||
const labelColor = 'gray.500';
|
||||
const valueColor = 'gray.800';
|
||||
const sectionTitleColor = 'gray.600';
|
||||
// 处理分享点击
|
||||
const handleShare = () => {
|
||||
onShare?.();
|
||||
};
|
||||
|
||||
// 涨跌颜色
|
||||
const priceColor = data.changePercent >= 0 ? 'green.500' : 'red.500';
|
||||
const inflowColor = data.mainNetInflow >= 0 ? 'green.500' : 'red.500';
|
||||
// 黑金主题颜色配置
|
||||
const cardBg = '#1A202C';
|
||||
const borderColor = '#C9A961';
|
||||
const labelColor = '#C9A961';
|
||||
const valueColor = '#F4D03F';
|
||||
const sectionTitleColor = '#F4D03F';
|
||||
|
||||
// 涨跌颜色(红涨绿跌)
|
||||
const upColor = '#F44336'; // 涨 - 红色
|
||||
const downColor = '#4CAF50'; // 跌 - 绿色
|
||||
const priceColor = data.changePercent >= 0 ? upColor : downColor;
|
||||
const inflowColor = data.mainNetInflow >= 0 ? upColor : downColor;
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
@@ -74,31 +89,48 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
|
||||
return (
|
||||
<Card bg={cardBg} shadow="sm" borderWidth="1px" borderColor={borderColor}>
|
||||
<CardBody py={4} px={6}>
|
||||
{/* 顶部:股票名称 + 更新时间 */}
|
||||
<CardBody>
|
||||
{/* 顶部:股票名称 + 关注/分享按钮 + 更新时间 */}
|
||||
<Flex justify="space-between" align="center" mb={4}>
|
||||
<HStack spacing={3}>
|
||||
<Text fontSize="xl" fontWeight="bold" color={valueColor}>
|
||||
{data.name}
|
||||
{/* 左侧:名称(代码) | 指数标签 */}
|
||||
<HStack spacing={2}>
|
||||
<Text fontSize="22px" fontWeight="bold" color={valueColor}>
|
||||
{data.name}({data.code})
|
||||
</Text>
|
||||
{data.indexTags.length > 0 && (
|
||||
<>
|
||||
<Text color={labelColor} fontSize="22px" fontWeight="light">|</Text>
|
||||
<Text fontSize="16px" color={labelColor}>
|
||||
{data.indexTags.join('、')}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
{/* 右侧:关注 + 分享 + 时间 */}
|
||||
<HStack spacing={3}>
|
||||
<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={labelColor}
|
||||
size="sm"
|
||||
onClick={handleShare}
|
||||
_hover={{ bg: 'whiteAlpha.100' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Text fontSize="14px" color={labelColor}>
|
||||
{data.updateTime.split(' ')[1]}
|
||||
</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>
|
||||
|
||||
{/* 三栏布局 */}
|
||||
@@ -106,66 +138,85 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
{/* 左栏:价格信息 */}
|
||||
<Box flex="1">
|
||||
<HStack align="baseline" spacing={3} mb={3}>
|
||||
<Text fontSize="3xl" fontWeight="bold" color={priceColor}>
|
||||
<Text fontSize="48px" fontWeight="bold" color={priceColor}>
|
||||
{formatPrice(data.currentPrice)}
|
||||
</Text>
|
||||
<Badge
|
||||
colorScheme={data.changePercent >= 0 ? 'green' : 'red'}
|
||||
fontSize="md"
|
||||
px={2}
|
||||
py={0.5}
|
||||
bg={data.changePercent >= 0 ? upColor : downColor}
|
||||
color="#FFFFFF"
|
||||
fontSize="20px"
|
||||
fontWeight="bold"
|
||||
px={3}
|
||||
py={1}
|
||||
borderRadius="md"
|
||||
>
|
||||
{formatChangePercent(data.changePercent)}
|
||||
</Badge>
|
||||
</HStack>
|
||||
<HStack spacing={6} color={labelColor} fontSize="sm">
|
||||
<Text>
|
||||
{/* 次要行情:今开 | 昨收 | 最高 | 最低 */}
|
||||
<HStack spacing={4} fontSize="14px" flexWrap="wrap">
|
||||
<Text color={labelColor}>
|
||||
今开:
|
||||
<Text as="span" color={valueColor} fontWeight="medium">
|
||||
<Text as="span" color={valueColor} fontWeight="bold">
|
||||
{formatPrice(data.todayOpen)}
|
||||
</Text>
|
||||
</Text>
|
||||
<Text>
|
||||
<Text color={borderColor}>|</Text>
|
||||
<Text color={labelColor}>
|
||||
昨收:
|
||||
<Text as="span" color={valueColor} fontWeight="medium">
|
||||
<Text as="span" color={valueColor} fontWeight="bold">
|
||||
{formatPrice(data.yesterdayClose)}
|
||||
</Text>
|
||||
</Text>
|
||||
<Text color={borderColor}>|</Text>
|
||||
<Text color={labelColor}>
|
||||
最高:
|
||||
<Text as="span" color={upColor} fontWeight="bold">
|
||||
{formatPrice(data.todayHigh)}
|
||||
</Text>
|
||||
</Text>
|
||||
<Text color={borderColor}>|</Text>
|
||||
<Text color={labelColor}>
|
||||
最低:
|
||||
<Text as="span" color={downColor} fontWeight="bold">
|
||||
{formatPrice(data.todayLow)}
|
||||
</Text>
|
||||
</Text>
|
||||
</HStack>
|
||||
</Box>
|
||||
|
||||
{/* 中栏:关键指标 */}
|
||||
<Box flex="1" borderLeftWidth="1px" borderColor={borderColor} pl={8}>
|
||||
<Text
|
||||
fontSize="sm"
|
||||
fontWeight="medium"
|
||||
fontSize="14px"
|
||||
fontWeight="bold"
|
||||
color={sectionTitleColor}
|
||||
mb={3}
|
||||
>
|
||||
关键指标
|
||||
</Text>
|
||||
<VStack align="stretch" spacing={2} fontSize="sm">
|
||||
<VStack align="stretch" spacing={2} fontSize="14px">
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>市盈率(PE):</Text>
|
||||
<Text color={valueColor} fontWeight="medium">
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{data.pe.toFixed(2)}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>市净率(PB):</Text>
|
||||
<Text color={valueColor} fontWeight="medium">
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{data.pb.toFixed(2)}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>流通市值:</Text>
|
||||
<Text color={valueColor} fontWeight="medium">
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{data.marketCap}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>52周波动:</Text>
|
||||
<Text color={valueColor} fontWeight="medium">
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{formatPrice(data.week52Low)}-{formatPrice(data.week52High)}
|
||||
</Text>
|
||||
</HStack>
|
||||
@@ -175,23 +226,23 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
{/* 右栏:主力动态 */}
|
||||
<Box flex="1" borderLeftWidth="1px" borderColor={borderColor} pl={8}>
|
||||
<Text
|
||||
fontSize="sm"
|
||||
fontWeight="medium"
|
||||
fontSize="14px"
|
||||
fontWeight="bold"
|
||||
color={sectionTitleColor}
|
||||
mb={3}
|
||||
>
|
||||
主力动态
|
||||
</Text>
|
||||
<VStack align="stretch" spacing={2} fontSize="sm">
|
||||
<VStack align="stretch" spacing={2} fontSize="14px">
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>主力净流入:</Text>
|
||||
<Text color={inflowColor} fontWeight="medium">
|
||||
<Text color={inflowColor} fontWeight="bold" fontSize="16px">
|
||||
{formatNetInflow(data.mainNetInflow)}
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack justify="space-between">
|
||||
<Text color={labelColor}>机构持仓:</Text>
|
||||
<Text color={valueColor} fontWeight="medium">
|
||||
<Text color={valueColor} fontWeight="bold" fontSize="16px">
|
||||
{data.institutionHolding.toFixed(2)}%
|
||||
</Text>
|
||||
</HStack>
|
||||
@@ -200,13 +251,15 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||
<Progress
|
||||
value={data.buyRatio}
|
||||
size="sm"
|
||||
colorScheme="green"
|
||||
bg="red.400"
|
||||
sx={{
|
||||
'& > div': { bg: upColor },
|
||||
}}
|
||||
bg={downColor}
|
||||
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 justify="space-between" mt={1} fontSize="14px">
|
||||
<Text color={upColor}>买入{data.buyRatio}%</Text>
|
||||
<Text color={downColor}>卖出{data.sellRatio}%</Text>
|
||||
</HStack>
|
||||
</Box>
|
||||
</VStack>
|
||||
|
||||
@@ -14,6 +14,8 @@ export const mockStockQuoteData: StockQuoteCardData = {
|
||||
changePercent: 3.65,
|
||||
todayOpen: 2156.0,
|
||||
yesterdayClose: 2101.0,
|
||||
todayHigh: 2185.0,
|
||||
todayLow: 2150.0,
|
||||
|
||||
// 关键指标
|
||||
pe: 38.62,
|
||||
@@ -30,4 +32,7 @@ export const mockStockQuoteData: StockQuoteCardData = {
|
||||
|
||||
// 更新时间
|
||||
updateTime: '2025-12-03 14:30:25',
|
||||
|
||||
// 自选状态
|
||||
isFavorite: false,
|
||||
};
|
||||
|
||||
@@ -16,6 +16,8 @@ export interface StockQuoteCardData {
|
||||
changePercent: number; // 涨跌幅(百分比,如 3.65 表示 +3.65%)
|
||||
todayOpen: number; // 今开
|
||||
yesterdayClose: number; // 昨收
|
||||
todayHigh: number; // 今日最高
|
||||
todayLow: number; // 今日最低
|
||||
|
||||
// 关键指标
|
||||
pe: number; // 市盈率
|
||||
@@ -32,6 +34,9 @@ export interface StockQuoteCardData {
|
||||
|
||||
// 更新时间
|
||||
updateTime: string; // 格式:YYYY-MM-DD HH:mm:ss
|
||||
|
||||
// 自选状态
|
||||
isFavorite?: boolean; // 是否已加入自选
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,4 +45,10 @@ export interface StockQuoteCardData {
|
||||
export interface StockQuoteCardProps {
|
||||
data?: StockQuoteCardData;
|
||||
isLoading?: boolean;
|
||||
// 自选股相关(与 WatchlistButton 接口保持一致)
|
||||
isInWatchlist?: boolean; // 是否在自选股中
|
||||
isWatchlistLoading?: boolean; // 自选股操作加载中
|
||||
onWatchlistToggle?: () => void; // 自选股切换回调
|
||||
// 分享
|
||||
onShare?: () => void; // 分享回调
|
||||
}
|
||||
|
||||
@@ -64,30 +64,26 @@ const CompanyIndex = () => {
|
||||
}, [stockCode, trackStockSearched]);
|
||||
|
||||
return (
|
||||
<Container maxW="container.xl" py={5}>
|
||||
<VStack align="stretch" spacing={5}>
|
||||
{/* 页面头部:标题、搜索、自选股按钮 */}
|
||||
<Container maxW="container.xl" py={0} bg='#1A202C'>
|
||||
<VStack align="stretch" spacing={0}>
|
||||
{/* 页面头部:标题、搜索 */}
|
||||
<CompanyHeader
|
||||
stockCode={stockCode}
|
||||
inputCode={inputCode}
|
||||
onInputChange={setInputCode}
|
||||
onSearch={handleSearch}
|
||||
onKeyPress={handleKeyPress}
|
||||
bgColor="#1A202C"
|
||||
/>
|
||||
|
||||
{/* 股票行情卡片:价格、关键指标、主力动态、自选股按钮 */}
|
||||
<StockQuoteCard
|
||||
isInWatchlist={isInWatchlist}
|
||||
isWatchlistLoading={isWatchlistLoading}
|
||||
onWatchlistToggle={handleWatchlistToggle}
|
||||
bgColor="white"
|
||||
/>
|
||||
|
||||
{/* 股票行情卡片:价格、关键指标、主力动态 */}
|
||||
<StockQuoteCard />
|
||||
|
||||
{/* Tab 切换区域:概览、行情、财务、预测 */}
|
||||
<CompanyTabs
|
||||
stockCode={stockCode}
|
||||
onTabChange={trackTabChanged}
|
||||
bgColor="white"
|
||||
/>
|
||||
<CompanyTabs stockCode={stockCode} onTabChange={trackTabChanged} bgColor="#1A202C"/>
|
||||
</VStack>
|
||||
</Container>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user