update pay function

This commit is contained in:
2025-12-01 07:48:03 +08:00
parent ff9c68295b
commit ec31801ccd

View File

@@ -96,30 +96,39 @@ const isInTradingTime = () => {
};
/**
* 紧凑型K线指数卡片
* 精美K线指数卡片 - 类似 KLineChartModal 风格
*/
const CompactIndexCard = ({ indexCode, indexName }) => {
const [chartData, setChartData] = useState(null);
const [loading, setLoading] = useState(true);
const [latestData, setLatestData] = useState(null);
const upColor = '#ec0000';
const downColor = '#00da3c';
const upColor = '#ef5350'; // 涨 - 红色
const downColor = '#26a69a'; // 跌 - 绿色
const loadData = useCallback(async () => {
const data = await fetchIndexKline(indexCode);
if (data?.data?.length > 0) {
const latest = data.data[data.data.length - 1];
const prevClose = latest.prev_close || latest.close;
const prevClose = latest.prev_close || data.data[data.data.length - 2]?.close || latest.open;
const changeAmount = latest.close - prevClose;
const changePct = prevClose ? ((changeAmount / prevClose) * 100) : 0;
setLatestData({
close: latest.close,
change: prevClose ? (((latest.close - prevClose) / prevClose) * 100).toFixed(2) : '0.00',
isPositive: latest.close >= prevClose
open: latest.open,
high: latest.high,
low: latest.low,
changeAmount: changeAmount,
changePct: changePct,
isPositive: changeAmount >= 0
});
const recentData = data.data.slice(-40);
const recentData = data.data.slice(-60); // 增加到60天
setChartData({
dates: recentData.map(item => item.time),
klineData: recentData.map(item => [item.open, item.close, item.low, item.high]),
volumes: recentData.map(item => item.volume || 0),
rawData: recentData
});
}
@@ -134,58 +143,204 @@ const CompactIndexCard = ({ indexCode, indexName }) => {
if (!chartData) return {};
return {
backgroundColor: 'transparent',
grid: { left: 5, right: 5, top: 5, bottom: 5, containLabel: false },
grid: [
{ left: 0, right: 0, top: 8, bottom: 28, containLabel: false },
{ left: 0, right: 0, top: '75%', bottom: 4, containLabel: false }
],
tooltip: {
trigger: 'axis',
axisPointer: { type: 'cross', lineStyle: { color: 'rgba(255, 215, 0, 0.5)', width: 1, type: 'dashed' } },
backgroundColor: 'rgba(20, 20, 20, 0.95)',
borderColor: '#FFD700',
axisPointer: {
type: 'cross',
crossStyle: { color: 'rgba(255, 215, 0, 0.6)', width: 1 },
lineStyle: { color: 'rgba(255, 215, 0, 0.4)', width: 1, type: 'dashed' }
},
backgroundColor: 'rgba(15, 15, 25, 0.98)',
borderColor: 'rgba(255, 215, 0, 0.5)',
borderWidth: 1,
textStyle: { color: '#fff', fontSize: 10, fontFamily: 'monospace' },
padding: [6, 10],
borderRadius: 8,
padding: [12, 16],
textStyle: { color: '#e0e0e0', fontSize: 12 },
extraCssText: 'box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);',
formatter: (params) => {
const idx = params[0].dataIndex;
const idx = params[0]?.dataIndex;
if (idx === undefined) return '';
const raw = chartData.rawData[idx];
if (!raw) return '';
const prevClose = raw.prev_close || raw.open;
const changePct = prevClose ? (((raw.close - prevClose) / prevClose) * 100).toFixed(2) : '0.00';
const isUp = raw.close >= prevClose;
const color = isUp ? '#ec0000' : '#00da3c';
return `<div style="font-size:11px"><b>${raw.time}</b><br/>收盘: ${raw.close.toFixed(2)}<br/><span style="color:${color}">${isUp ? '+' : ''}${changePct}%</span></div>`;
// 计算涨跌
const prevClose = raw.prev_close || (idx > 0 ? chartData.rawData[idx - 1]?.close : raw.open) || raw.open;
const changeAmount = raw.close - prevClose;
const changePct = prevClose ? ((changeAmount / prevClose) * 100) : 0;
const isUp = changeAmount >= 0;
const color = isUp ? '#ef5350' : '#26a69a';
const sign = isUp ? '+' : '';
return `
<div style="min-width: 180px;">
<div style="font-weight: bold; color: #FFD700; margin-bottom: 10px; font-size: 13px; border-bottom: 1px solid rgba(255,215,0,0.2); padding-bottom: 8px;">
📅 ${raw.time}
</div>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 6px 16px; font-size: 12px;">
<span style="color: #999;">开盘</span>
<span style="text-align: right; font-family: monospace;">${raw.open.toFixed(2)}</span>
<span style="color: #999;">收盘</span>
<span style="text-align: right; font-weight: bold; color: ${color}; font-family: monospace;">${raw.close.toFixed(2)}</span>
<span style="color: #999;">最高</span>
<span style="text-align: right; color: #ef5350; font-family: monospace;">${raw.high.toFixed(2)}</span>
<span style="color: #999;">最低</span>
<span style="text-align: right; color: #26a69a; font-family: monospace;">${raw.low.toFixed(2)}</span>
</div>
<div style="margin-top: 10px; padding-top: 8px; border-top: 1px solid rgba(255,255,255,0.1); display: flex; justify-content: space-between; align-items: center;">
<span style="color: #999; font-size: 11px;">涨跌幅</span>
<span style="color: ${color}; font-weight: bold; font-size: 14px; font-family: monospace;">
${sign}${changeAmount.toFixed(2)} (${sign}${changePct.toFixed(2)}%)
</span>
</div>
</div>
`;
}
},
xAxis: { type: 'category', data: chartData.dates, show: false },
yAxis: { type: 'value', show: false, scale: true },
series: [{
type: 'candlestick',
data: chartData.klineData,
itemStyle: { color: upColor, color0: downColor, borderColor: upColor, borderColor0: downColor },
barWidth: '70%'
}]
xAxis: [
{
type: 'category',
data: chartData.dates,
gridIndex: 0,
show: false,
boundaryGap: true
},
{
type: 'category',
data: chartData.dates,
gridIndex: 1,
show: false,
boundaryGap: true
}
],
yAxis: [
{
type: 'value',
gridIndex: 0,
show: false,
scale: true
},
{
type: 'value',
gridIndex: 1,
show: false,
scale: true
}
],
dataZoom: [{
type: 'inside',
xAxisIndex: [0, 1],
start: 50,
end: 100,
zoomOnMouseWheel: true,
moveOnMouseMove: true
}],
series: [
{
name: 'K线',
type: 'candlestick',
data: chartData.klineData,
xAxisIndex: 0,
yAxisIndex: 0,
itemStyle: {
color: upColor,
color0: downColor,
borderColor: upColor,
borderColor0: downColor,
borderWidth: 1
},
barWidth: '65%'
},
{
name: '成交量',
type: 'bar',
data: chartData.volumes,
xAxisIndex: 1,
yAxisIndex: 1,
itemStyle: {
color: (params) => {
const idx = params.dataIndex;
const raw = chartData.rawData[idx];
return raw && raw.close >= raw.open ? 'rgba(239,83,80,0.5)' : 'rgba(38,166,154,0.5)';
}
},
barWidth: '65%'
}
]
};
}, [chartData, upColor, downColor]);
if (loading) return <Center h="80px"><Spinner size="sm" color="gold" /></Center>;
if (loading) {
return (
<Center h="100px">
<VStack spacing={2}>
<Spinner size="sm" color="gold" thickness="2px" />
<Text fontSize="10px" color="whiteAlpha.500">加载{indexName}...</Text>
</VStack>
</Center>
);
}
return (
<Flex align="center" gap={4} h="80px">
{/* 左侧数据 */}
<VStack align="start" spacing={0} minW="100px">
<Text fontSize="xs" color="whiteAlpha.600" fontWeight="medium">{indexName}</Text>
<Text fontSize="xl" fontWeight="bold" color="white">
{latestData?.close.toFixed(2)}
</Text>
<Flex direction="column" h="100px">
{/* 顶部:指数名称和数据 */}
<Flex justify="space-between" align="center" mb={1}>
<HStack spacing={2}>
<Box
w="3px"
h="14px"
borderRadius="full"
bg={latestData?.isPositive ? '#ef5350' : '#26a69a'}
/>
<Text fontSize="sm" color="whiteAlpha.800" fontWeight="semibold">
{indexName}
</Text>
</HStack>
<HStack spacing={3}>
<Text fontSize="lg" fontWeight="bold" color="white" fontFamily="monospace">
{latestData?.close?.toFixed(2)}
</Text>
<Box
px={2}
py={0.5}
borderRadius="md"
bg={latestData?.isPositive ? 'rgba(239,83,80,0.15)' : 'rgba(38,166,154,0.15)'}
border="1px solid"
borderColor={latestData?.isPositive ? 'rgba(239,83,80,0.3)' : 'rgba(38,166,154,0.3)'}
>
<Text
fontSize="sm"
fontWeight="bold"
fontFamily="monospace"
color={latestData?.isPositive ? '#ef5350' : '#26a69a'}
>
{latestData?.isPositive ? '▲' : '▼'} {latestData?.isPositive ? '+' : ''}{latestData?.changePct?.toFixed(2)}%
</Text>
</Box>
</HStack>
</Flex>
{/* K线图区域 */}
<Box flex="1" position="relative">
<ReactECharts
option={chartOption}
style={{ height: '100%', width: '100%' }}
opts={{ renderer: 'canvas' }}
/>
{/* 底部提示 */}
<Text
fontSize="sm"
fontWeight="bold"
color={latestData?.isPositive ? '#ec0000' : '#00da3c'}
position="absolute"
bottom={0}
right={1}
fontSize="9px"
color="whiteAlpha.300"
>
{latestData?.isPositive ? '▲' : '▼'} {latestData?.isPositive ? '+' : ''}{latestData?.change}%
滚轮缩放 · 拖动查看
</Text>
</VStack>
{/* 右侧K线图 */}
<Box flex="1" h="70px">
<ReactECharts option={chartOption} style={{ height: '100%', width: '100%' }} opts={{ renderer: 'canvas' }} />
</Box>
</Flex>
);
@@ -377,7 +532,7 @@ const FlowingConcepts = () => {
};
/**
* 极简提示标签 - 悬停显示详情
* 详细使用说明提示框
*/
const InfoTooltip = () => {
const [isOpen, setIsOpen] = useState(false);
@@ -414,16 +569,16 @@ const InfoTooltip = () => {
top="calc(100% + 8px)"
left="0"
zIndex={1000}
minW="320px"
p={4}
w="380px"
p={5}
bg="rgba(10,10,20,0.98)"
borderRadius="lg"
borderRadius="xl"
border="1px solid rgba(255,215,0,0.3)"
boxShadow="0 10px 40px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,215,0,0.1)"
boxShadow="0 15px 50px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,215,0,0.1), inset 0 1px 0 rgba(255,255,255,0.05)"
opacity={isOpen ? 1 : 0}
visibility={isOpen ? 'visible' : 'hidden'}
transform={isOpen ? 'translateY(0)' : 'translateY(-10px)'}
transition="all 0.2s ease"
transition="all 0.25s ease"
onMouseEnter={() => setIsOpen(true)}
onMouseLeave={() => setIsOpen(false)}
>
@@ -440,56 +595,118 @@ const InfoTooltip = () => {
transform="rotate(45deg)"
/>
<VStack align="start" spacing={3}>
{/* SABC说明 */}
<HStack spacing={2} align="start">
<Text color="gold" fontWeight="bold" fontSize="xs" minW="50px">SABC</Text>
<Text fontSize="xs" color="whiteAlpha.800">
基于事件影响力评级非收益预测
</Text>
</HStack>
<VStack align="stretch" spacing={4}>
{/* 标题 */}
<Text fontSize="sm" fontWeight="bold" color="gold" borderBottom="1px solid rgba(255,215,0,0.2)" pb={2}>
📖 事件中心使用指南
</Text>
{/* 涨跌幅说明 */}
<HStack spacing={2} align="start">
<Text color="cyan.400" fontWeight="bold" fontSize="xs" minW="50px">涨跌幅</Text>
<Text fontSize="xs" color="whiteAlpha.800">
新闻发布时股价 当前价格的变化
{/* 事件级别说明 */}
<Box>
<Text fontSize="xs" fontWeight="bold" color="whiteAlpha.900" mb={2}>
🏷 事件重要性等级 (SABC)
</Text>
</HStack>
{/* 延迟提醒 */}
<HStack spacing={2} align="start">
<HStack spacing={1} minW="50px">
<Icon as={Clock} color="orange.400" boxSize={3} />
</HStack>
<Text fontSize="xs" color="whiteAlpha.800">
数据延迟<Text as="span" color="orange.400" fontWeight="bold"> 2-3分钟</Text>
<Text as="span" color="#ec0000" fontWeight="bold">切勿追高</Text>
</Text>
</HStack>
<VStack align="stretch" spacing={1} pl={3}>
<HStack>
<Box px={1.5} py={0.5} bg="rgba(255,0,0,0.2)" borderRadius="sm">
<Text fontSize="10px" color="#ff4d4f" fontWeight="bold">S级</Text>
</Box>
<Text fontSize="11px" color="whiteAlpha.700">重大事件 - 可能引发板块涨停潮</Text>
</HStack>
<HStack>
<Box px={1.5} py={0.5} bg="rgba(255,165,0,0.2)" borderRadius="sm">
<Text fontSize="10px" color="orange.300" fontWeight="bold">A级</Text>
</Box>
<Text fontSize="11px" color="whiteAlpha.700">重要事件 - 龙头股可能涨停</Text>
</HStack>
<HStack>
<Box px={1.5} py={0.5} bg="rgba(30,144,255,0.2)" borderRadius="sm">
<Text fontSize="10px" color="blue.300" fontWeight="bold">B级</Text>
</Box>
<Text fontSize="11px" color="whiteAlpha.700">一般事件 - 相关股票可能异动</Text>
</HStack>
<HStack>
<Box px={1.5} py={0.5} bg="rgba(128,128,128,0.2)" borderRadius="sm">
<Text fontSize="10px" color="gray.400" fontWeight="bold">C级</Text>
</Box>
<Text fontSize="11px" color="whiteAlpha.700">普通事件 - 仅供参考</Text>
</HStack>
</VStack>
</Box>
{/* 分隔线 */}
<Box w="100%" h="1px" bg="rgba(255,255,255,0.1)" />
<Box w="100%" h="1px" bg="rgba(255,255,255,0.08)" />
{/* 盘前新闻 */}
<HStack spacing={2} align="start">
<Icon as={AlertCircle} color="blue.300" boxSize={3} mt={0.5} />
<Text fontSize="xs" color="whiteAlpha.800">
关注<Text as="span" color="blue.300" fontWeight="bold">盘前新闻</Text>
收盘后至次日开盘前的消息
{/* 涨跌幅说明 */}
<Box>
<Text fontSize="xs" fontWeight="bold" color="whiteAlpha.900" mb={2}>
📊 涨跌幅计算方式
</Text>
</HStack>
<VStack align="stretch" spacing={1.5} pl={3}>
<Text fontSize="11px" color="whiteAlpha.700">
<Text as="span" color="cyan.300">相关股涨跌</Text>
</Text>
<Text fontSize="11px" color="whiteAlpha.700">
<Text as="span" color="#ef5350">红色</Text> <Text as="span" color="#26a69a">绿</Text>
</Text>
<Text fontSize="11px" color="whiteAlpha.700">
K线图悬停可查看开盘收盘最高最低涨跌幅
</Text>
</VStack>
</Box>
{/* 利好利空 */}
<HStack spacing={2} align="start">
<Icon as={TrendingUp} color="whiteAlpha.500" boxSize={3} mt={0.5} />
<Text fontSize="xs" color="whiteAlpha.800">
事件含
<Text as="span" color="#ec0000" fontWeight="bold"> 利好</Text>/
<Text as="span" color="#00da3c" fontWeight="bold">利空</Text>
需自行判断
{/* 分隔线 */}
<Box w="100%" h="1px" bg="rgba(255,255,255,0.08)" />
{/* 重要提醒 */}
<Box
p={3}
bg="rgba(255,165,0,0.08)"
border="1px solid rgba(255,165,0,0.2)"
borderRadius="lg"
>
<Text fontSize="xs" fontWeight="bold" color="orange.300" mb={2}>
重要提醒
</Text>
</HStack>
<VStack align="stretch" spacing={1.5}>
<HStack align="start" spacing={2}>
<Icon as={Clock} color="orange.400" boxSize={3} mt={0.5} />
<Text fontSize="11px" color="whiteAlpha.800">
数据延迟 <Text as="span" color="orange.300" fontWeight="bold">2-3分钟</Text><Text as="span" color="#ef5350" fontWeight="bold"></Text>
</Text>
</HStack>
<HStack align="start" spacing={2}>
<Icon as={AlertCircle} color="blue.300" boxSize={3} mt={0.5} />
<Text fontSize="11px" color="whiteAlpha.800">
关注 <Text as="span" color="blue.300" fontWeight="bold">盘前新闻</Text>
</Text>
</HStack>
<HStack align="start" spacing={2}>
<Icon as={TrendingUp} color="whiteAlpha.500" boxSize={3} mt={0.5} />
<Text fontSize="11px" color="whiteAlpha.800">
事件可能含 <Text as="span" color="#ef5350">利好</Text> <Text as="span" color="#26a69a"></Text>
</Text>
</HStack>
</VStack>
</Box>
{/* 操作提示 */}
<Box>
<Text fontSize="xs" fontWeight="bold" color="whiteAlpha.900" mb={2}>
💡 操作提示
</Text>
<VStack align="stretch" spacing={1} pl={3}>
<Text fontSize="11px" color="whiteAlpha.600">
点击事件卡片查看详情和相关股票
</Text>
<Text fontSize="11px" color="whiteAlpha.600">
点击热门概念标签跳转概念详情页
</Text>
<Text fontSize="11px" color="whiteAlpha.600">
K线图支持滚轮缩放和拖动查看
</Text>
</VStack>
</Box>
</VStack>
</Box>
</Box>
@@ -596,14 +813,15 @@ const HeroPanel = () => {
<Box
flex="1"
p={3}
minH="120px"
bg="rgba(255,255,255,0.03)"
borderRadius="xl"
border="1px solid rgba(255,255,255,0.08)"
transition="all 0.3s"
_hover={{
bg: 'rgba(255,255,255,0.05)',
borderColor: 'rgba(236,0,0,0.3)',
boxShadow: '0 4px 20px rgba(236,0,0,0.1)',
borderColor: 'rgba(239,83,80,0.4)',
boxShadow: '0 4px 20px rgba(239,83,80,0.15)',
}}
>
<CompactIndexCard indexCode="000001" indexName="上证指数" />
@@ -613,14 +831,15 @@ const HeroPanel = () => {
<Box
flex="1"
p={3}
minH="120px"
bg="rgba(255,255,255,0.03)"
borderRadius="xl"
border="1px solid rgba(255,255,255,0.08)"
transition="all 0.3s"
_hover={{
bg: 'rgba(255,255,255,0.05)',
borderColor: 'rgba(0,218,60,0.3)',
boxShadow: '0 4px 20px rgba(0,218,60,0.1)',
borderColor: 'rgba(38,166,154,0.4)',
boxShadow: '0 4px 20px rgba(38,166,154,0.15)',
}}
>
<CompactIndexCard indexCode="399001" indexName="深证成指" />