refactor(MarketDataView): 使用通用 SubTabContainer 简化代码

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-16 15:29:05 +08:00
parent 91ed649220
commit 00f2937a34

View File

@@ -1,37 +1,31 @@
// src/views/Company/components/MarketDataView/index.tsx
// MarketDataView 主组件 - 股票市场数据综合展示
import React, { useState, useEffect, ReactNode } from 'react';
import React, { useState, useEffect, ReactNode, useMemo, useCallback } from 'react';
import {
Box,
Container,
Tabs,
TabList,
TabPanels,
Tab,
TabPanel,
Text,
CardBody,
Spinner,
Center,
VStack,
HStack,
Select,
Button,
Icon,
Text,
useDisclosure,
} from '@chakra-ui/react';
import {
ChevronUpIcon,
RepeatIcon,
ArrowUpIcon,
StarIcon,
LockIcon,
UnlockIcon,
} from '@chakra-ui/icons';
ChevronUp,
Unlock,
ArrowUp,
Star,
Lock,
} from 'lucide-react';
// 通用组件
import SubTabContainer from '@components/SubTabContainer';
import type { SubTabConfig } from '@components/SubTabContainer';
// 内部模块导入
import { themes, DEFAULT_PERIOD, PERIOD_OPTIONS } from './constants';
import { themes, DEFAULT_PERIOD } from './constants';
import { useMarketData } from './hooks/useMarketData';
import {
ThemedCard,
@@ -88,22 +82,67 @@ const MarketDataView: React.FC<MarketDataViewProps> = ({ stockCode: propStockCod
}, [propStockCode, stockCode]);
// 处理图表点击事件
const handleChartClick = (params: { seriesName?: string; data?: [number, number] }) => {
if (params.seriesName === '涨幅分析' && params.data) {
const dataIndex = params.data[0];
const analysis = analysisMap[dataIndex];
const handleChartClick = useCallback(
(params: { seriesName?: string; data?: [number, number] }) => {
if (params.seriesName === '涨幅分析' && params.data) {
const dataIndex = params.data[0];
const analysis = analysisMap[dataIndex];
if (analysis) {
setModalContent(<AnalysisContent analysis={analysis} theme={theme} />);
onOpen();
if (analysis) {
setModalContent(<AnalysisContent analysis={analysis} theme={theme} />);
onOpen();
}
}
}
};
},
[analysisMap, theme, onOpen]
);
// Tab 配置 - 使用通用 SubTabContainer
const tabConfigs: SubTabConfig[] = [
{ key: 'trade', name: '交易数据', icon: ChevronUp, component: TradeDataPanel },
{ key: 'funding', name: '融资融券', icon: Unlock, component: FundingPanel },
{ key: 'bigDeal', name: '大宗交易', icon: ArrowUp, component: BigDealPanel },
{ key: 'unusual', name: '龙虎榜', icon: Star, component: UnusualPanel },
{ key: 'pledge', name: '股权质押', icon: Lock, component: PledgePanel },
];
// 传递给 Tab 组件的 props
const componentProps = useMemo(
() => ({
theme,
tradeData,
minuteData,
minuteLoading,
analysisMap,
onLoadMinuteData: loadMinuteData,
onChartClick: handleChartClick,
selectedPeriod,
onPeriodChange: setSelectedPeriod,
fundingData,
bigDealData,
unusualData,
pledgeData,
}),
[
theme,
tradeData,
minuteData,
minuteLoading,
analysisMap,
loadMinuteData,
handleChartClick,
selectedPeriod,
fundingData,
bigDealData,
unusualData,
pledgeData,
]
);
return (
<Box bg={theme.bgMain} minH="100vh" color={theme.textPrimary}>
<Box bg={'#1A202C'} minH="100vh" color={theme.textPrimary}>
<Container maxW="container.xl" py={6}>
<VStack spacing={6} align="stretch">
<VStack align="stretch">
{/* 股票概览 */}
{summary && <StockSummaryCard summary={summary} theme={theme} />}
@@ -126,152 +165,14 @@ const MarketDataView: React.FC<MarketDataViewProps> = ({ stockCode: propStockCod
</CardBody>
</ThemedCard>
) : (
<Tabs
variant="soft-rounded"
colorScheme="blue"
<SubTabContainer
tabs={tabConfigs}
componentProps={componentProps}
themePreset="blackGold"
index={activeTab}
onChange={setActiveTab}
>
{/* Tab 导航栏 */}
<Box
bg={theme.bgCard}
p={4}
borderRadius="xl"
border="1px solid"
borderColor={theme.border}
>
<HStack justify="space-between" align="center" spacing={4}>
<TabList overflowX="auto" border="none" flex="1">
<Tab
color={theme.textMuted}
_selected={{ color: 'white', bg: theme.primary }}
fontSize="sm"
px={3}
>
<HStack spacing={1}>
<Icon as={ChevronUpIcon} boxSize={4} />
<Text></Text>
</HStack>
</Tab>
<Tab
color={theme.textMuted}
_selected={{ color: 'white', bg: theme.primary }}
fontSize="sm"
px={3}
>
<HStack spacing={1}>
<Icon as={UnlockIcon} boxSize={4} />
<Text></Text>
</HStack>
</Tab>
<Tab
color={theme.textMuted}
_selected={{ color: 'white', bg: theme.primary }}
fontSize="sm"
px={3}
>
<HStack spacing={1}>
<Icon as={ArrowUpIcon} boxSize={4} />
<Text></Text>
</HStack>
</Tab>
<Tab
color={theme.textMuted}
_selected={{ color: 'white', bg: theme.primary }}
fontSize="sm"
px={3}
>
<HStack spacing={1}>
<Icon as={StarIcon} boxSize={4} />
<Text></Text>
</HStack>
</Tab>
<Tab
color={theme.textMuted}
_selected={{ color: 'white', bg: theme.primary }}
fontSize="sm"
px={3}
>
<HStack spacing={1}>
<Icon as={LockIcon} boxSize={4} />
<Text></Text>
</HStack>
</Tab>
</TabList>
{/* 时间范围选择和刷新按钮 */}
<HStack spacing={2} flexShrink={0} ml="auto">
<Text color={theme.textPrimary} whiteSpace="nowrap" fontSize="sm">
</Text>
<Select
size="sm"
value={selectedPeriod}
onChange={(e) => setSelectedPeriod(Number(e.target.value))}
bg={theme.bgDark}
borderColor={theme.border}
color={theme.textPrimary}
maxW="120px"
>
{PERIOD_OPTIONS.map((option) => (
<option
key={option.value}
value={option.value}
style={{ background: theme.bgDark }}
>
{option.label}
</option>
))}
</Select>
<Button
leftIcon={<RepeatIcon />}
variant="outline"
colorScheme="blue"
onClick={refetch}
isLoading={loading}
size="sm"
>
</Button>
</HStack>
</HStack>
</Box>
<TabPanels>
{/* 交易数据 Tab */}
<TabPanel px={0}>
<TradeDataPanel
theme={theme}
tradeData={tradeData}
minuteData={minuteData}
minuteLoading={minuteLoading}
analysisMap={analysisMap}
onLoadMinuteData={loadMinuteData}
onChartClick={handleChartClick}
/>
</TabPanel>
{/* 融资融券 Tab */}
<TabPanel px={0}>
<FundingPanel theme={theme} fundingData={fundingData} />
</TabPanel>
{/* 大宗交易 Tab */}
<TabPanel px={0}>
<BigDealPanel theme={theme} bigDealData={bigDealData} />
</TabPanel>
{/* 龙虎榜 Tab */}
<TabPanel px={0}>
<UnusualPanel theme={theme} unusualData={unusualData} />
</TabPanel>
{/* 股权质押 Tab */}
<TabPanel px={0}>
<PledgePanel theme={theme} pledgeData={pledgeData} />
</TabPanel>
</TabPanels>
</Tabs>
onTabChange={(index) => setActiveTab(index)}
isLazy
/>
)}
</VStack>
</Container>