feat: 修复数据获取bug
This commit is contained in:
@@ -473,6 +473,16 @@ const FinancialPanorama = ({ stockCode: propStockCode }) => {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 数组安全检查
|
||||||
|
if (!Array.isArray(balanceSheet) || balanceSheet.length === 0) {
|
||||||
|
return (
|
||||||
|
<Alert status="info">
|
||||||
|
<AlertIcon />
|
||||||
|
暂无资产负债表数据
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const maxColumns = Math.min(balanceSheet.length, 6);
|
const maxColumns = Math.min(balanceSheet.length, 6);
|
||||||
const displayData = balanceSheet.slice(0, maxColumns);
|
const displayData = balanceSheet.slice(0, maxColumns);
|
||||||
|
|
||||||
@@ -707,6 +717,16 @@ const FinancialPanorama = ({ stockCode: propStockCode }) => {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 数组安全检查
|
||||||
|
if (!Array.isArray(incomeStatement) || incomeStatement.length === 0) {
|
||||||
|
return (
|
||||||
|
<Alert status="info">
|
||||||
|
<AlertIcon />
|
||||||
|
暂无利润表数据
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const maxColumns = Math.min(incomeStatement.length, 6);
|
const maxColumns = Math.min(incomeStatement.length, 6);
|
||||||
const displayData = incomeStatement.slice(0, maxColumns);
|
const displayData = incomeStatement.slice(0, maxColumns);
|
||||||
|
|
||||||
@@ -866,6 +886,16 @@ const FinancialPanorama = ({ stockCode: propStockCode }) => {
|
|||||||
{ name: '自由现金流', key: 'free_cash_flow', path: 'key_metrics.free_cash_flow' },
|
{ name: '自由现金流', key: 'free_cash_flow', path: 'key_metrics.free_cash_flow' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 数组安全检查
|
||||||
|
if (!Array.isArray(cashflow) || cashflow.length === 0) {
|
||||||
|
return (
|
||||||
|
<Alert status="info">
|
||||||
|
<AlertIcon />
|
||||||
|
暂无现金流量表数据
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const maxColumns = Math.min(cashflow.length, 8);
|
const maxColumns = Math.min(cashflow.length, 8);
|
||||||
const displayData = cashflow.slice(0, maxColumns);
|
const displayData = cashflow.slice(0, maxColumns);
|
||||||
|
|
||||||
@@ -1069,6 +1099,16 @@ const FinancialPanorama = ({ stockCode: propStockCode }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 数组安全检查
|
||||||
|
if (!Array.isArray(financialMetrics) || financialMetrics.length === 0) {
|
||||||
|
return (
|
||||||
|
<Alert status="info">
|
||||||
|
<AlertIcon />
|
||||||
|
暂无财务指标数据
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const maxColumns = Math.min(financialMetrics.length, 6);
|
const maxColumns = Math.min(financialMetrics.length, 6);
|
||||||
const displayData = financialMetrics.slice(0, maxColumns);
|
const displayData = financialMetrics.slice(0, maxColumns);
|
||||||
const currentCategory = metricsCategories[selectedCategory];
|
const currentCategory = metricsCategories[selectedCategory];
|
||||||
@@ -1426,7 +1466,8 @@ const FinancialPanorama = ({ stockCode: propStockCode }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack spacing={4} align="stretch">
|
<VStack spacing={4} align="stretch">
|
||||||
{industryRank.map((periodData, periodIdx) => (
|
{Array.isArray(industryRank) && industryRank.length > 0 ? (
|
||||||
|
industryRank.map((periodData, periodIdx) => (
|
||||||
<Card key={periodIdx}>
|
<Card key={periodIdx}>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<HStack justify="space-between">
|
<HStack justify="space-between">
|
||||||
@@ -1486,7 +1527,16 @@ const FinancialPanorama = ({ stockCode: propStockCode }) => {
|
|||||||
))}
|
))}
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<Card>
|
||||||
|
<CardBody>
|
||||||
|
<Text textAlign="center" color="gray.500" py={8}>
|
||||||
|
暂无行业排名数据
|
||||||
|
</Text>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -1738,7 +1788,7 @@ const FinancialPanorama = ({ stockCode: propStockCode }) => {
|
|||||||
|
|
||||||
// 综合对比分析
|
// 综合对比分析
|
||||||
const ComparisonAnalysis = () => {
|
const ComparisonAnalysis = () => {
|
||||||
if (!comparison || comparison.length === 0) return null;
|
if (!Array.isArray(comparison) || comparison.length === 0) return null;
|
||||||
|
|
||||||
const revenueData = comparison.map(item => ({
|
const revenueData = comparison.map(item => ({
|
||||||
period: formatUtils.getReportType(item.period),
|
period: formatUtils.getReportType(item.period),
|
||||||
|
|||||||
@@ -1471,7 +1471,7 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
</HStack>
|
</HStack>
|
||||||
</StatLabel>
|
</StatLabel>
|
||||||
<StatNumber color={theme.textPrimary} fontSize="lg">
|
<StatNumber color={theme.textPrimary} fontSize="lg">
|
||||||
{minuteData.data[0]?.open.toFixed(2)}
|
{minuteData.data[0]?.open != null ? minuteData.data[0].open.toFixed(2) : '-'}
|
||||||
</StatNumber>
|
</StatNumber>
|
||||||
</Stat>
|
</Stat>
|
||||||
<Stat>
|
<Stat>
|
||||||
@@ -1485,13 +1485,15 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
color={minuteData.data[minuteData.data.length - 1]?.close >= minuteData.data[0]?.open ? theme.success : theme.danger}
|
color={minuteData.data[minuteData.data.length - 1]?.close >= minuteData.data[0]?.open ? theme.success : theme.danger}
|
||||||
fontSize="lg"
|
fontSize="lg"
|
||||||
>
|
>
|
||||||
{minuteData.data[minuteData.data.length - 1]?.close.toFixed(2)}
|
{minuteData.data[minuteData.data.length - 1]?.close != null ? minuteData.data[minuteData.data.length - 1].close.toFixed(2) : '-'}
|
||||||
</StatNumber>
|
</StatNumber>
|
||||||
<StatHelpText fontSize="xs">
|
<StatHelpText fontSize="xs">
|
||||||
<StatArrow
|
<StatArrow
|
||||||
type={minuteData.data[minuteData.data.length - 1]?.close >= minuteData.data[0]?.open ? 'increase' : 'decrease'}
|
type={minuteData.data[minuteData.data.length - 1]?.close >= minuteData.data[0]?.open ? 'increase' : 'decrease'}
|
||||||
/>
|
/>
|
||||||
{Math.abs(((minuteData.data[minuteData.data.length - 1]?.close - minuteData.data[0]?.open) / minuteData.data[0]?.open * 100)).toFixed(2)}%
|
{(minuteData.data[minuteData.data.length - 1]?.close != null && minuteData.data[0]?.open != null)
|
||||||
|
? Math.abs(((minuteData.data[minuteData.data.length - 1].close - minuteData.data[0].open) / minuteData.data[0].open * 100)).toFixed(2)
|
||||||
|
: '0.00'}%
|
||||||
</StatHelpText>
|
</StatHelpText>
|
||||||
</Stat>
|
</Stat>
|
||||||
<Stat>
|
<Stat>
|
||||||
@@ -1502,7 +1504,10 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
</HStack>
|
</HStack>
|
||||||
</StatLabel>
|
</StatLabel>
|
||||||
<StatNumber color={theme.success} fontSize="lg">
|
<StatNumber color={theme.success} fontSize="lg">
|
||||||
{Math.max(...minuteData.data.map(item => item.high)).toFixed(2)}
|
{(() => {
|
||||||
|
const highs = minuteData.data.map(item => item.high).filter(h => h != null);
|
||||||
|
return highs.length > 0 ? Math.max(...highs).toFixed(2) : '-';
|
||||||
|
})()}
|
||||||
</StatNumber>
|
</StatNumber>
|
||||||
</Stat>
|
</Stat>
|
||||||
<Stat>
|
<Stat>
|
||||||
@@ -1513,7 +1518,10 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
</HStack>
|
</HStack>
|
||||||
</StatLabel>
|
</StatLabel>
|
||||||
<StatNumber color={theme.danger} fontSize="lg">
|
<StatNumber color={theme.danger} fontSize="lg">
|
||||||
{Math.min(...minuteData.data.map(item => item.low)).toFixed(2)}
|
{(() => {
|
||||||
|
const lows = minuteData.data.map(item => item.low).filter(l => l != null);
|
||||||
|
return lows.length > 0 ? Math.min(...lows).toFixed(2) : '-';
|
||||||
|
})()}
|
||||||
</StatNumber>
|
</StatNumber>
|
||||||
</Stat>
|
</Stat>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
@@ -1558,7 +1566,10 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
平均价格
|
平均价格
|
||||||
</Text>
|
</Text>
|
||||||
<Text fontSize="sm" color={theme.textPrimary}>
|
<Text fontSize="sm" color={theme.textPrimary}>
|
||||||
{(minuteData.data.reduce((sum, item) => sum + item.close, 0) / minuteData.data.length).toFixed(2)}
|
{(() => {
|
||||||
|
const closes = minuteData.data.map(item => item.close).filter(c => c != null);
|
||||||
|
return closes.length > 0 ? (closes.reduce((sum, c) => sum + c, 0) / closes.length).toFixed(2) : '-';
|
||||||
|
})()}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -1744,7 +1755,7 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
成交额: {formatUtils.formatNumber(dayStats.total_amount)}万元
|
成交额: {formatUtils.formatNumber(dayStats.total_amount)}万元
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge colorScheme="purple" fontSize="md">
|
<Badge colorScheme="purple" fontSize="md">
|
||||||
均价: {dayStats.avg_price.toFixed(2)}元
|
均价: {dayStats.avg_price != null ? dayStats.avg_price.toFixed(2) : '-'}元
|
||||||
</Badge>
|
</Badge>
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
@@ -1766,23 +1777,23 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
{dayStats.deals.map((deal, i) => (
|
{dayStats.deals.map((deal, i) => (
|
||||||
<Tr key={i} _hover={{ bg: colorMode === 'light' ? 'rgba(43, 108, 176, 0.05)' : 'rgba(255, 215, 0, 0.1)' }}>
|
<Tr key={i} _hover={{ bg: colorMode === 'light' ? 'rgba(43, 108, 176, 0.05)' : 'rgba(255, 215, 0, 0.1)' }}>
|
||||||
<Td color={theme.textPrimary} fontSize="xs" maxW="200px" isTruncated>
|
<Td color={theme.textPrimary} fontSize="xs" maxW="200px" isTruncated>
|
||||||
<Tooltip label={deal.buyer_dept} placement="top">
|
<Tooltip label={deal.buyer_dept || '-'} placement="top">
|
||||||
<Text>{deal.buyer_dept}</Text>
|
<Text>{deal.buyer_dept || '-'}</Text>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Td>
|
</Td>
|
||||||
<Td color={theme.textPrimary} fontSize="xs" maxW="200px" isTruncated>
|
<Td color={theme.textPrimary} fontSize="xs" maxW="200px" isTruncated>
|
||||||
<Tooltip label={deal.seller_dept} placement="top">
|
<Tooltip label={deal.seller_dept || '-'} placement="top">
|
||||||
<Text>{deal.seller_dept}</Text>
|
<Text>{deal.seller_dept || '-'}</Text>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textPrimary} fontWeight="bold">
|
<Td isNumeric color={theme.textPrimary} fontWeight="bold">
|
||||||
{deal.price.toFixed(2)}
|
{deal.price != null ? deal.price.toFixed(2) : '-'}
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textPrimary}>
|
<Td isNumeric color={theme.textPrimary}>
|
||||||
{deal.volume.toFixed(2)}
|
{deal.volume != null ? deal.volume.toFixed(2) : '-'}
|
||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textSecondary} fontWeight="bold">
|
<Td isNumeric color={theme.textSecondary} fontWeight="bold">
|
||||||
{deal.amount.toFixed(2)}
|
{deal.amount != null ? deal.amount.toFixed(2) : '-'}
|
||||||
</Td>
|
</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
))}
|
))}
|
||||||
@@ -1845,7 +1856,8 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
买入前五
|
买入前五
|
||||||
</Text>
|
</Text>
|
||||||
<VStack spacing={1} align="stretch">
|
<VStack spacing={1} align="stretch">
|
||||||
{dayData.buyers.slice(0, 5).map((buyer, i) => (
|
{dayData.buyers && dayData.buyers.length > 0 ? (
|
||||||
|
dayData.buyers.slice(0, 5).map((buyer, i) => (
|
||||||
<HStack
|
<HStack
|
||||||
key={i}
|
key={i}
|
||||||
justify="space-between"
|
justify="space-between"
|
||||||
@@ -1860,7 +1872,10 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
{formatUtils.formatNumber(buyer.buy_amount)}
|
{formatUtils.formatNumber(buyer.buy_amount)}
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<Text fontSize="sm" color={theme.textMuted}>暂无数据</Text>
|
||||||
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -1869,7 +1884,8 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
卖出前五
|
卖出前五
|
||||||
</Text>
|
</Text>
|
||||||
<VStack spacing={1} align="stretch">
|
<VStack spacing={1} align="stretch">
|
||||||
{dayData.sellers.slice(0, 5).map((seller, i) => (
|
{dayData.sellers && dayData.sellers.length > 0 ? (
|
||||||
|
dayData.sellers.slice(0, 5).map((seller, i) => (
|
||||||
<HStack
|
<HStack
|
||||||
key={i}
|
key={i}
|
||||||
justify="space-between"
|
justify="space-between"
|
||||||
@@ -1884,7 +1900,10 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
{formatUtils.formatNumber(seller.sell_amount)}
|
{formatUtils.formatNumber(seller.sell_amount)}
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<Text fontSize="sm" color={theme.textMuted}>暂无数据</Text>
|
||||||
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -1948,7 +1967,8 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody>
|
<Tbody>
|
||||||
{pledgeData.map((item, idx) => (
|
{Array.isArray(pledgeData) && pledgeData.length > 0 ? (
|
||||||
|
pledgeData.map((item, idx) => (
|
||||||
<Tr key={idx} _hover={{ bg: colorMode === 'light' ? theme.bgDark : 'rgba(255, 215, 0, 0.1)' }}>
|
<Tr key={idx} _hover={{ bg: colorMode === 'light' ? theme.bgDark : 'rgba(255, 215, 0, 0.1)' }}>
|
||||||
<Td color={theme.textPrimary}>{item.end_date}</Td>
|
<Td color={theme.textPrimary}>{item.end_date}</Td>
|
||||||
<Td isNumeric color={theme.textPrimary}>{formatUtils.formatNumber(item.unrestricted_pledge, 0)}</Td>
|
<Td isNumeric color={theme.textPrimary}>{formatUtils.formatNumber(item.unrestricted_pledge, 0)}</Td>
|
||||||
@@ -1960,7 +1980,14 @@ const MarketDataView = ({ stockCode: propStockCode }) => {
|
|||||||
</Td>
|
</Td>
|
||||||
<Td isNumeric color={theme.textPrimary}>{item.pledge_count}</Td>
|
<Td isNumeric color={theme.textPrimary}>{item.pledge_count}</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<Tr>
|
||||||
|
<Td colSpan={7} textAlign="center" py={8}>
|
||||||
|
<Text fontSize="sm" color={theme.textMuted}>暂无数据</Text>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
)}
|
||||||
</Tbody>
|
</Tbody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
|
|||||||
Reference in New Issue
Block a user