update pay ui
This commit is contained in:
@@ -26,15 +26,22 @@ import { FaTable } from 'react-icons/fa';
|
||||
import marketService from '@services/marketService';
|
||||
import { logger } from '@utils/logger';
|
||||
|
||||
// 股票信息类型
|
||||
// 股票信息类型 - 兼容新旧API格式
|
||||
interface StockInfo {
|
||||
stock_code: string;
|
||||
stock_name: string;
|
||||
stock_code?: string;
|
||||
stock_name?: string;
|
||||
code?: string; // 新API格式
|
||||
name?: string; // 新API格式
|
||||
reason?: string;
|
||||
change_pct?: number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
// 获取股票代码(兼容新旧API)
|
||||
const getStockCode = (stock: StockInfo): string => stock.code || stock.stock_code || '';
|
||||
// 获取股票名称(兼容新旧API)
|
||||
const getStockName = (stock: StockInfo): string => stock.name || stock.stock_name || '未知';
|
||||
|
||||
// 概念信息类型
|
||||
export interface ConceptInfo {
|
||||
concept_id?: string;
|
||||
@@ -69,9 +76,12 @@ const ConceptStocksModal: React.FC<ConceptStocksModalProps> = ({
|
||||
const [stockMarketData, setStockMarketData] = useState<Record<string, MarketData>>({});
|
||||
const [loadingStockData, setLoadingStockData] = useState(false);
|
||||
|
||||
// 颜色主题
|
||||
const cardBg = useColorModeValue('white', '#1a1a1a');
|
||||
const hoverBg = useColorModeValue('gray.50', '#2a2a2a');
|
||||
// 深色主题颜色
|
||||
const cardBg = 'rgba(15, 23, 42, 0.95)';
|
||||
const hoverBg = 'whiteAlpha.100';
|
||||
const textColor = 'white';
|
||||
const subTextColor = 'whiteAlpha.700';
|
||||
const borderColor = 'whiteAlpha.100';
|
||||
|
||||
// 响应式配置 - 添加 fallback 避免首次渲染时返回 undefined 导致弹窗异常
|
||||
const isMobile = useBreakpointValue({ base: true, md: false }, { fallback: 'md' });
|
||||
@@ -91,13 +101,14 @@ const ConceptStocksModal: React.FC<ConceptStocksModalProps> = ({
|
||||
for (let i = 0; i < stocks.length; i += batchSize) {
|
||||
const batch = stocks.slice(i, i + batchSize);
|
||||
const promises = batch.map(async (stock) => {
|
||||
if (!stock.stock_code) return null;
|
||||
const seccode = stock.stock_code.substring(0, 6);
|
||||
const stockCode = getStockCode(stock);
|
||||
if (!stockCode) return null;
|
||||
const seccode = stockCode.substring(0, 6);
|
||||
try {
|
||||
const response = await marketService.getTradeData(seccode, 1);
|
||||
if (response.success && response.data?.length > 0) {
|
||||
const latestData = response.data[response.data.length - 1];
|
||||
return { stock_code: stock.stock_code, ...latestData };
|
||||
return { stock_code: stockCode, ...latestData };
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn('ConceptStocksModal', '获取股票行情失败', { stockCode: seccode });
|
||||
@@ -168,16 +179,18 @@ const ConceptStocksModal: React.FC<ConceptStocksModalProps> = ({
|
||||
<Table variant="simple" size="sm" minW={isMobile ? '600px' : undefined}>
|
||||
<Thead position="sticky" top={0} bg={cardBg} zIndex={1}>
|
||||
<Tr>
|
||||
<Th whiteSpace="nowrap">股票名称</Th>
|
||||
<Th whiteSpace="nowrap">股票代码</Th>
|
||||
<Th isNumeric whiteSpace="nowrap">现价</Th>
|
||||
<Th isNumeric whiteSpace="nowrap">当日涨跌幅</Th>
|
||||
<Th whiteSpace="nowrap" minW="200px">板块原因</Th>
|
||||
<Th whiteSpace="nowrap" color={subTextColor} borderColor={borderColor}>股票名称</Th>
|
||||
<Th whiteSpace="nowrap" color={subTextColor} borderColor={borderColor}>股票代码</Th>
|
||||
<Th isNumeric whiteSpace="nowrap" color={subTextColor} borderColor={borderColor}>现价</Th>
|
||||
<Th isNumeric whiteSpace="nowrap" color={subTextColor} borderColor={borderColor}>当日涨跌幅</Th>
|
||||
<Th whiteSpace="nowrap" minW="200px" color={subTextColor} borderColor={borderColor}>板块原因</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{stocks.map((stock, idx) => {
|
||||
const marketData = stockMarketData[stock.stock_code];
|
||||
const stockCode = getStockCode(stock);
|
||||
const stockName = getStockName(stock);
|
||||
const marketData = stockMarketData[stockCode];
|
||||
const changePercent = marketData?.change_percent;
|
||||
|
||||
return (
|
||||
@@ -185,15 +198,15 @@ const ConceptStocksModal: React.FC<ConceptStocksModalProps> = ({
|
||||
key={idx}
|
||||
_hover={{ bg: hoverBg }}
|
||||
cursor="pointer"
|
||||
onClick={() => handleStockClick(stock.stock_code)}
|
||||
onClick={() => handleStockClick(stockCode)}
|
||||
>
|
||||
<Td color="blue.500" fontWeight="medium">
|
||||
{stock.stock_name}
|
||||
<Td color="cyan.400" fontWeight="medium" borderColor={borderColor}>
|
||||
{stockName}
|
||||
</Td>
|
||||
<Td>{stock.stock_code}</Td>
|
||||
<Td isNumeric>
|
||||
<Td color={subTextColor} borderColor={borderColor}>{stockCode}</Td>
|
||||
<Td isNumeric color={textColor} borderColor={borderColor}>
|
||||
{loadingStockData ? (
|
||||
<Spinner size="xs" />
|
||||
<Spinner size="xs" color="purple.400" />
|
||||
) : marketData?.close ? (
|
||||
`¥${marketData.close.toFixed(2)}`
|
||||
) : (
|
||||
@@ -203,23 +216,24 @@ const ConceptStocksModal: React.FC<ConceptStocksModalProps> = ({
|
||||
<Td
|
||||
isNumeric
|
||||
fontWeight="bold"
|
||||
borderColor={borderColor}
|
||||
color={
|
||||
changePercent && changePercent > 0
|
||||
? 'red.500'
|
||||
? 'red.400'
|
||||
: changePercent && changePercent < 0
|
||||
? 'green.500'
|
||||
: 'gray.500'
|
||||
? 'green.400'
|
||||
: 'whiteAlpha.500'
|
||||
}
|
||||
>
|
||||
{loadingStockData ? (
|
||||
<Spinner size="xs" />
|
||||
<Spinner size="xs" color="purple.400" />
|
||||
) : changePercent !== undefined ? (
|
||||
`${changePercent > 0 ? '+' : ''}${changePercent.toFixed(2)}%`
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</Td>
|
||||
<Td fontSize="xs" color="gray.600" maxW="300px">
|
||||
<Td fontSize="xs" color={subTextColor} maxW="300px" borderColor={borderColor}>
|
||||
<Text noOfLines={2}>{stock.reason || '-'}</Text>
|
||||
</Td>
|
||||
</Tr>
|
||||
|
||||
Reference in New Issue
Block a user