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 CompactIndexCard = ({ indexCode, indexName }) => {
const [chartData, setChartData] = useState(null); const [chartData, setChartData] = useState(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [latestData, setLatestData] = useState(null); const [latestData, setLatestData] = useState(null);
const upColor = '#ec0000'; const upColor = '#ef5350'; // 涨 - 红色
const downColor = '#00da3c'; const downColor = '#26a69a'; // 跌 - 绿色
const loadData = useCallback(async () => { const loadData = useCallback(async () => {
const data = await fetchIndexKline(indexCode); const data = await fetchIndexKline(indexCode);
if (data?.data?.length > 0) { if (data?.data?.length > 0) {
const latest = data.data[data.data.length - 1]; 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({ setLatestData({
close: latest.close, close: latest.close,
change: prevClose ? (((latest.close - prevClose) / prevClose) * 100).toFixed(2) : '0.00', open: latest.open,
isPositive: latest.close >= prevClose 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({ setChartData({
dates: recentData.map(item => item.time), dates: recentData.map(item => item.time),
klineData: recentData.map(item => [item.open, item.close, item.low, item.high]), klineData: recentData.map(item => [item.open, item.close, item.low, item.high]),
volumes: recentData.map(item => item.volume || 0),
rawData: recentData rawData: recentData
}); });
} }
@@ -134,58 +143,204 @@ const CompactIndexCard = ({ indexCode, indexName }) => {
if (!chartData) return {}; if (!chartData) return {};
return { return {
backgroundColor: 'transparent', 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: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { type: 'cross', lineStyle: { color: 'rgba(255, 215, 0, 0.5)', width: 1, type: 'dashed' } }, axisPointer: {
backgroundColor: 'rgba(20, 20, 20, 0.95)', type: 'cross',
borderColor: '#FFD700', 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, borderWidth: 1,
textStyle: { color: '#fff', fontSize: 10, fontFamily: 'monospace' }, borderRadius: 8,
padding: [6, 10], padding: [12, 16],
textStyle: { color: '#e0e0e0', fontSize: 12 },
extraCssText: 'box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);',
formatter: (params) => { formatter: (params) => {
const idx = params[0].dataIndex; const idx = params[0]?.dataIndex;
if (idx === undefined) return '';
const raw = chartData.rawData[idx]; const raw = chartData.rawData[idx];
if (!raw) return ''; 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 prevClose = raw.prev_close || (idx > 0 ? chartData.rawData[idx - 1]?.close : raw.open) || raw.open;
const color = isUp ? '#ec0000' : '#00da3c'; const changeAmount = raw.close - prevClose;
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 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 }, xAxis: [
yAxis: { type: 'value', show: false, scale: true }, {
series: [{ type: 'category',
type: 'candlestick', data: chartData.dates,
data: chartData.klineData, gridIndex: 0,
itemStyle: { color: upColor, color0: downColor, borderColor: upColor, borderColor0: downColor }, show: false,
barWidth: '70%' 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]); }, [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 ( return (
<Flex align="center" gap={4} h="80px"> <Flex direction="column" h="100px">
{/* 左侧数据 */} {/* 顶部:指数名称和数据 */}
<VStack align="start" spacing={0} minW="100px"> <Flex justify="space-between" align="center" mb={1}>
<Text fontSize="xs" color="whiteAlpha.600" fontWeight="medium">{indexName}</Text> <HStack spacing={2}>
<Text fontSize="xl" fontWeight="bold" color="white"> <Box
{latestData?.close.toFixed(2)} w="3px"
</Text> 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 <Text
fontSize="sm" position="absolute"
fontWeight="bold" bottom={0}
color={latestData?.isPositive ? '#ec0000' : '#00da3c'} right={1}
fontSize="9px"
color="whiteAlpha.300"
> >
{latestData?.isPositive ? '▲' : '▼'} {latestData?.isPositive ? '+' : ''}{latestData?.change}% 滚轮缩放 · 拖动查看
</Text> </Text>
</VStack>
{/* 右侧K线图 */}
<Box flex="1" h="70px">
<ReactECharts option={chartOption} style={{ height: '100%', width: '100%' }} opts={{ renderer: 'canvas' }} />
</Box> </Box>
</Flex> </Flex>
); );
@@ -377,7 +532,7 @@ const FlowingConcepts = () => {
}; };
/** /**
* 极简提示标签 - 悬停显示详情 * 详细使用说明提示框
*/ */
const InfoTooltip = () => { const InfoTooltip = () => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
@@ -414,16 +569,16 @@ const InfoTooltip = () => {
top="calc(100% + 8px)" top="calc(100% + 8px)"
left="0" left="0"
zIndex={1000} zIndex={1000}
minW="320px" w="380px"
p={4} p={5}
bg="rgba(10,10,20,0.98)" bg="rgba(10,10,20,0.98)"
borderRadius="lg" borderRadius="xl"
border="1px solid rgba(255,215,0,0.3)" 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} opacity={isOpen ? 1 : 0}
visibility={isOpen ? 'visible' : 'hidden'} visibility={isOpen ? 'visible' : 'hidden'}
transform={isOpen ? 'translateY(0)' : 'translateY(-10px)'} transform={isOpen ? 'translateY(0)' : 'translateY(-10px)'}
transition="all 0.2s ease" transition="all 0.25s ease"
onMouseEnter={() => setIsOpen(true)} onMouseEnter={() => setIsOpen(true)}
onMouseLeave={() => setIsOpen(false)} onMouseLeave={() => setIsOpen(false)}
> >
@@ -440,56 +595,118 @@ const InfoTooltip = () => {
transform="rotate(45deg)" transform="rotate(45deg)"
/> />
<VStack align="start" spacing={3}> <VStack align="stretch" spacing={4}>
{/* SABC说明 */} {/* 标题 */}
<HStack spacing={2} align="start"> <Text fontSize="sm" fontWeight="bold" color="gold" borderBottom="1px solid rgba(255,215,0,0.2)" pb={2}>
<Text color="gold" fontWeight="bold" fontSize="xs" minW="50px">SABC</Text> 📖 事件中心使用指南
<Text fontSize="xs" color="whiteAlpha.800"> </Text>
基于事件影响力评级非收益预测
</Text>
</HStack>
{/* 涨跌幅说明 */} {/* 事件级别说明 */}
<HStack spacing={2} align="start"> <Box>
<Text color="cyan.400" fontWeight="bold" fontSize="xs" minW="50px">涨跌幅</Text> <Text fontSize="xs" fontWeight="bold" color="whiteAlpha.900" mb={2}>
<Text fontSize="xs" color="whiteAlpha.800"> 🏷 事件重要性等级 (SABC)
新闻发布时股价 当前价格的变化
</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">
<HStack spacing={2} align="start"> <Text fontSize="10px" color="#ff4d4f" fontWeight="bold">S级</Text>
<HStack spacing={1} minW="50px"> </Box>
<Icon as={Clock} color="orange.400" boxSize={3} /> <Text fontSize="11px" color="whiteAlpha.700">重大事件 - 可能引发板块涨停潮</Text>
</HStack> </HStack>
<Text fontSize="xs" color="whiteAlpha.800"> <HStack>
数据延迟<Text as="span" color="orange.400" fontWeight="bold"> 2-3分钟</Text> <Box px={1.5} py={0.5} bg="rgba(255,165,0,0.2)" borderRadius="sm">
<Text as="span" color="#ec0000" fontWeight="bold">切勿追高</Text> <Text fontSize="10px" color="orange.300" fontWeight="bold">A级</Text>
</Text> </Box>
</HStack> <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"> <Box>
<Icon as={AlertCircle} color="blue.300" boxSize={3} mt={0.5} /> <Text fontSize="xs" fontWeight="bold" color="whiteAlpha.900" mb={2}>
<Text fontSize="xs" color="whiteAlpha.800"> 📊 涨跌幅计算方式
关注<Text as="span" color="blue.300" fontWeight="bold">盘前新闻</Text>
收盘后至次日开盘前的消息
</Text> </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"> <Box w="100%" h="1px" bg="rgba(255,255,255,0.08)" />
<Icon as={TrendingUp} color="whiteAlpha.500" boxSize={3} mt={0.5} />
<Text fontSize="xs" color="whiteAlpha.800"> {/* 重要提醒 */}
事件含 <Box
<Text as="span" color="#ec0000" fontWeight="bold"> 利好</Text>/ p={3}
<Text as="span" color="#00da3c" fontWeight="bold">利空</Text> 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> </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> </VStack>
</Box> </Box>
</Box> </Box>
@@ -596,14 +813,15 @@ const HeroPanel = () => {
<Box <Box
flex="1" flex="1"
p={3} p={3}
minH="120px"
bg="rgba(255,255,255,0.03)" bg="rgba(255,255,255,0.03)"
borderRadius="xl" borderRadius="xl"
border="1px solid rgba(255,255,255,0.08)" border="1px solid rgba(255,255,255,0.08)"
transition="all 0.3s" transition="all 0.3s"
_hover={{ _hover={{
bg: 'rgba(255,255,255,0.05)', bg: 'rgba(255,255,255,0.05)',
borderColor: 'rgba(236,0,0,0.3)', borderColor: 'rgba(239,83,80,0.4)',
boxShadow: '0 4px 20px rgba(236,0,0,0.1)', boxShadow: '0 4px 20px rgba(239,83,80,0.15)',
}} }}
> >
<CompactIndexCard indexCode="000001" indexName="上证指数" /> <CompactIndexCard indexCode="000001" indexName="上证指数" />
@@ -613,14 +831,15 @@ const HeroPanel = () => {
<Box <Box
flex="1" flex="1"
p={3} p={3}
minH="120px"
bg="rgba(255,255,255,0.03)" bg="rgba(255,255,255,0.03)"
borderRadius="xl" borderRadius="xl"
border="1px solid rgba(255,255,255,0.08)" border="1px solid rgba(255,255,255,0.08)"
transition="all 0.3s" transition="all 0.3s"
_hover={{ _hover={{
bg: 'rgba(255,255,255,0.05)', bg: 'rgba(255,255,255,0.05)',
borderColor: 'rgba(0,218,60,0.3)', borderColor: 'rgba(38,166,154,0.4)',
boxShadow: '0 4px 20px rgba(0,218,60,0.1)', boxShadow: '0 4px 20px rgba(38,166,154,0.15)',
}} }}
> >
<CompactIndexCard indexCode="399001" indexName="深证成指" /> <CompactIndexCard indexCode="399001" indexName="深证成指" />