update ui

This commit is contained in:
2025-11-13 17:18:33 +08:00
parent 58d1e6f2ad
commit 4bb37c6e6d
2 changed files with 204 additions and 56 deletions

View File

@@ -2,6 +2,28 @@
// 顶部说明面板组件:产品功能介绍 + 沪深指数折线图 + 热门概念词云图
import React, { useEffect, useState, useMemo, useCallback } from 'react';
// 定义 pulse 动画
const pulseAnimation = `
@keyframes pulse {
0%, 100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.6;
transform: scale(1.1);
}
}
`;
// 注入样式到页面
if (typeof document !== 'undefined') {
const styleSheet = document.createElement('style');
styleSheet.type = 'text/css';
styleSheet.innerText = pulseAnimation;
document.head.appendChild(styleSheet);
}
import {
Box,
Card,
@@ -103,8 +125,9 @@ const MiniIndexChart = ({ indexCode, indexName }) => {
const [currentDate, setCurrentDate] = useState('');
const chartBg = useColorModeValue('transparent', 'transparent');
const upColor = '#00da3c';
const downColor = '#ec0000';
// 中国市场惯例:涨红跌绿
const upColor = '#ec0000'; // 上涨:红色
const downColor = '#00da3c'; // 下跌:绿色
// 加载日线数据
const loadDailyData = useCallback(async () => {
@@ -260,21 +283,21 @@ const MiniIndexChart = ({ indexCode, indexName }) => {
const changePct = prevClose ? ((change / prevClose) * 100).toFixed(2) : '0.00';
const isUp = close >= prevClose;
// Bloomberg 风格格式化
const changeColor = isUp ? '#00da3c' : '#ec0000';
// Bloomberg 风格格式化(涨红跌绿)
const changeColor = isUp ? '#ec0000' : '#00da3c';
const changeSign = isUp ? '+' : '';
return `
<div style="font-weight: bold; border-bottom: 1px solid #FFD700; padding-bottom: 4px; margin-bottom: 6px;">
${rawDataItem.time}
<div style="font-weight: bold; border-bottom: 1px solid #FFD700; padding-bottom: 6px; margin-bottom: 8px; font-size: 12px;">
📅 ${rawDataItem.time}
</div>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; line-height: 1.6;">
<span style="color: #aaa;">开盘</span><span style="font-weight: bold;">${open.toFixed(2)}</span>
<span style="color: #aaa;">最高</span><span style="font-weight: bold; color: #00da3c;">${high.toFixed(2)}</span>
<span style="color: #aaa;">最低</span><span style="font-weight: bold; color: #ec0000;">${low.toFixed(2)}</span>
<span style="color: #aaa;">收盘</span><span style="font-weight: bold;">${close.toFixed(2)}</span>
<span style="color: #aaa;">涨跌</span><span style="font-weight: bold; color: ${changeColor};">${changeSign}${change.toFixed(2)}</span>
<span style="color: #aaa;">涨跌幅</span><span style="font-weight: bold; color: ${changeColor};">${changeSign}${changePct}%</span>
<div style="display: grid; grid-template-columns: auto 1fr; gap: 6px 16px; line-height: 1.8;">
<span style="color: #999;">开盘</span><span style="font-weight: bold; font-size: 13px;">${open.toFixed(2)}</span>
<span style="color: #999;">最高</span><span style="font-weight: bold; font-size: 13px; color: #ec0000;">${high.toFixed(2)}</span>
<span style="color: #999;">最低</span><span style="font-weight: bold; font-size: 13px; color: #00da3c;">${low.toFixed(2)}</span>
<span style="color: #999;">收盘</span><span style="font-weight: bold; font-size: 13px;">${close.toFixed(2)}</span>
<span style="color: #999;">涨跌</span><span style="font-weight: bold; font-size: 13px; color: ${changeColor};">${changeSign}${change.toFixed(2)}</span>
<span style="color: #999;">涨跌幅</span><span style="font-weight: bold; font-size: 14px; color: ${changeColor};">${changeSign}${changePct}%</span>
</div>
`;
}
@@ -315,30 +338,46 @@ const MiniIndexChart = ({ indexCode, indexName }) => {
<VStack spacing={2} align="stretch" h="140px">
<HStack justify="space-between">
<VStack align="start" spacing={0}>
<Text fontSize="xs" color="whiteAlpha.700">{indexName}</Text>
<Text fontSize="lg" fontWeight="bold" color="white">
<Text fontSize="xs" color="whiteAlpha.700" fontWeight="medium">{indexName}</Text>
<Text
fontSize="2xl"
fontWeight="extrabold"
color="white"
textShadow="0 2px 4px rgba(0,0,0,0.3)"
>
{latestData?.close.toFixed(2)}
</Text>
<Text fontSize="xs" color="whiteAlpha.500">
{currentDate}
📅 {currentDate}
</Text>
</VStack>
<VStack align="end" spacing={0}>
<VStack align="end" spacing={1}>
<Text
fontSize="sm"
fontWeight="bold"
color={latestData?.isPositive ? 'green.300' : 'red.300'}
fontSize="lg"
fontWeight="extrabold"
color={latestData?.isPositive ? '#ec0000' : '#00da3c'}
textShadow={latestData?.isPositive ? '0 2px 8px rgba(236, 0, 0, 0.4)' : '0 2px 8px rgba(0, 218, 60, 0.4)'}
>
{latestData?.isPositive ? '' : ''} {latestData?.isPositive ? '+' : ''}{latestData?.change}%
{latestData?.isPositive ? '' : ''} {latestData?.isPositive ? '+' : ''}{latestData?.change}%
</Text>
{isInTradingTime() && (
<Text fontSize="xs" color="green.400">
实时更新
</Text>
<HStack spacing={1}>
<Box
w="6px"
h="6px"
borderRadius="full"
bg="green.400"
animation="pulse 2s infinite"
boxShadow="0 0 6px rgba(72, 187, 120, 0.8)"
/>
<Text fontSize="xs" color="green.400" fontWeight="medium">
实时更新
</Text>
</HStack>
)}
</VStack>
</HStack>
<Box flex="1">
<Box flex="1" position="relative">
<ReactECharts
option={chartOption}
style={{ height: '90px', width: '100%' }}
@@ -405,9 +444,14 @@ const ConceptWordCloud = () => {
const changePct = params.data.change_pct;
const sign = changePct > 0 ? '+' : '';
const color = changePct > 0 ? '#ec0000' : '#00da3c';
const icon = changePct > 0 ? '📈' : '📉';
return `
<div style="font-weight: bold; margin-bottom: 4px;">${params.name}</div>
<div style="color: ${color}; font-weight: bold;">涨跌幅: ${sign}${changePct.toFixed(2)}%</div>
<div style="font-weight: bold; font-size: 14px; margin-bottom: 6px; border-bottom: 1px solid #FFD700; padding-bottom: 4px;">
${icon} ${params.name}
</div>
<div style="color: ${color}; font-weight: bold; font-size: 16px;">
涨跌幅: ${sign}${changePct.toFixed(2)}%
</div>
`;
}
},
@@ -432,23 +476,30 @@ const ConceptWordCloud = () => {
color: function (params) {
// 根据涨跌幅设置颜色(中国市场惯例:涨红跌绿)
const changePct = params.data.change_pct;
if (changePct > 7) return '#ff0000'; // 超大涨:纯红
if (changePct > 5) return '#ff1744'; // 大涨:亮红色
if (changePct > 3) return '#ff4d4f'; // 中涨:红色
if (changePct > 1) return '#ff7875'; // 小涨:浅红
if (changePct > 0) return '#ffa940'; // 微涨:橙色
if (changePct === 0) return '#FFD700'; // 平盘:金色
if (changePct > -1) return '#95de64'; // 微跌:浅绿
if (changePct > -1) return '#73d13d'; // 微跌:浅绿
if (changePct > -3) return '#52c41a'; // 小跌:绿色
if (changePct > -5) return '#00c853'; // 中跌:深绿
return '#00796b'; // 大跌:绿
}
if (changePct > -7) return '#00a152'; // 大跌:更深绿
return '#00796b'; // 超大跌:墨绿
},
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.5)',
shadowOffsetX: 1,
shadowOffsetY: 1
},
emphasis: {
focus: 'self',
textStyle: {
shadowBlur: 12,
shadowBlur: 20,
shadowColor: '#FFD700',
fontSize: 24
fontSize: 28,
fontWeight: 'bolder'
}
},
data: concepts
@@ -525,21 +576,49 @@ const HeroPanel = () => {
bg={gradientBg}
borderColor={borderColor}
borderWidth={cardBorder}
boxShadow="0 8px 32px rgba(0, 0, 0, 0.4)"
boxShadow="0 12px 48px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 215, 0, 0.1) inset"
mb={6}
overflow="hidden"
position="relative"
transition="all 0.3s ease"
_hover={{
boxShadow: "0 16px 64px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 215, 0, 0.2) inset",
transform: "translateY(-2px)"
}}
>
{/* 装饰性背景图案 */}
{/* 装饰性背景图案 - 多层叠加 */}
<Box
position="absolute"
top="-20%"
right="-10%"
width="500px"
height="500px"
top="-30%"
right="-15%"
width="600px"
height="600px"
borderRadius="full"
bg="radial-gradient(circle, rgba(255, 215, 0, 0.1) 0%, transparent 70%)"
bg="radial-gradient(circle, rgba(255, 215, 0, 0.15) 0%, rgba(255, 165, 0, 0.08) 40%, transparent 70%)"
pointerEvents="none"
filter="blur(40px)"
/>
<Box
position="absolute"
bottom="-20%"
left="-10%"
width="400px"
height="400px"
borderRadius="full"
bg="radial-gradient(circle, rgba(236, 0, 0, 0.08) 0%, transparent 60%)"
pointerEvents="none"
filter="blur(50px)"
/>
<Box
position="absolute"
top="50%"
left="50%"
transform="translate(-50%, -50%)"
width="80%"
height="80%"
bg="radial-gradient(circle, rgba(255, 215, 0, 0.02) 0%, transparent 60%)"
pointerEvents="none"
filter="blur(60px)"
/>
<CardBody p={6}>
@@ -586,7 +665,7 @@ const HeroPanel = () => {
</VStack>
</Box>
{/* 中间:沪深指数线图 */}
{/* 中间:沪深指数K线图 */}
<Box>
<VStack spacing={4} h="100%">
<Box
@@ -597,6 +676,14 @@ const HeroPanel = () => {
borderWidth="1px"
borderColor="whiteAlpha.200"
backdropFilter="blur(10px)"
boxShadow="0 4px 16px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.05)"
transition="all 0.3s ease"
_hover={{
bg: "whiteAlpha.150",
borderColor: "whiteAlpha.300",
boxShadow: "0 6px 24px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1)",
transform: "translateY(-1px)"
}}
>
<MiniIndexChart indexCode="000001" indexName="上证指数" />
</Box>
@@ -608,6 +695,14 @@ const HeroPanel = () => {
borderWidth="1px"
borderColor="whiteAlpha.200"
backdropFilter="blur(10px)"
boxShadow="0 4px 16px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.05)"
transition="all 0.3s ease"
_hover={{
bg: "whiteAlpha.150",
borderColor: "whiteAlpha.300",
boxShadow: "0 6px 24px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1)",
transform: "translateY(-1px)"
}}
>
<MiniIndexChart indexCode="399001" indexName="深证成指" />
</Box>
@@ -617,13 +712,37 @@ const HeroPanel = () => {
{/* 右侧:热门概念词云图 */}
<Box>
<VStack align="start" spacing={3} h="100%">
<HStack>
<Text fontSize="md" fontWeight="bold" color="white">
🔥 热门概念
</Text>
<Text fontSize="xs" color="whiteAlpha.600">
实时更新
</Text>
<HStack
spacing={2}
p={2}
borderRadius="md"
bg="whiteAlpha.50"
w="full"
justify="space-between"
>
<HStack spacing={2}>
<Text
fontSize="lg"
fontWeight="extrabold"
bgGradient="linear(to-r, #FFD700, #FFA500, #FF4500)"
bgClip="text"
>
🔥 热门概念
</Text>
</HStack>
<HStack spacing={1}>
<Box
w="6px"
h="6px"
borderRadius="full"
bg="orange.400"
animation="pulse 2s infinite"
boxShadow="0 0 6px rgba(251, 146, 60, 0.8)"
/>
<Text fontSize="xs" color="orange.400" fontWeight="medium">
实时更新
</Text>
</HStack>
</HStack>
<Box
w="100%"
@@ -633,13 +752,24 @@ const HeroPanel = () => {
borderWidth="1px"
borderColor="whiteAlpha.200"
backdropFilter="blur(10px)"
boxShadow="0 4px 16px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.05)"
p={3}
position="relative"
overflow="hidden"
transition="all 0.3s ease"
_hover={{
bg: "whiteAlpha.150",
borderColor: "whiteAlpha.300",
boxShadow: "0 6px 24px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1)"
}}
>
<ConceptWordCloud />
</Box>
<Text fontSize="xs" color="whiteAlpha.600" textAlign="center" w="100%">
字体大小表示热度 · 颜色表示涨跌幅
</Text>
<HStack spacing={2} fontSize="xs" color="whiteAlpha.600" w="100%" justify="center">
<Text>💡 字体大小表示热度</Text>
<Text></Text>
<Text>🎨 颜色表示涨跌幅</Text>
</HStack>
</VStack>
</Box>
</SimpleGrid>

View File

@@ -35,16 +35,34 @@ const HotEventsSection = ({ events, onEventClick }) => {
}
return (
<Card mt={0} bg={cardBg}>
<CardHeader pb={0} display="flex" justifyContent="space-between" alignItems="flex-start">
<Card
mt={6}
mb={8}
bg={cardBg}
boxShadow="lg"
borderWidth="1px"
borderColor={useColorModeValue('gray.200', 'gray.700')}
position="relative"
zIndex={1}
>
<CardHeader pb={3} display="flex" justifyContent="space-between" alignItems="flex-start">
<Box>
<Heading size="md">🔥 热点事件</Heading>
<p className="section-subtitle" style={{paddingTop: '8px'}}>展示最近5天内涨幅最高的事件助您把握市场热点</p>
<Heading
size="lg"
bgGradient="linear(to-r, #FF4500, #FFD700)"
bgClip="text"
fontWeight="extrabold"
>
🔥 热点事件
</Heading>
<p className="section-subtitle" style={{paddingTop: '8px', color: useColorModeValue('#666', '#aaa')}}>
展示最近5天内涨幅最高的事件助您把握市场热点
</p>
</Box>
{/* 页码指示器 */}
{totalPages > 1 && (
<Badge
colorScheme="blue"
colorScheme="orange"
fontSize="sm"
px={3}
py={1}
@@ -55,7 +73,7 @@ const HotEventsSection = ({ events, onEventClick }) => {
</Badge>
)}
</CardHeader>
<CardBody py={0} px={4}>
<CardBody py={4} px={4}>
<HotEvents
events={events}
onPageChange={handlePageChange}