heropanel修改

This commit is contained in:
2026-01-09 07:36:31 +08:00
parent b9672bcef1
commit 30f6346252
2 changed files with 230 additions and 50 deletions

View File

@@ -61,89 +61,175 @@ const getChgColor = (val) => {
};
/**
* 胜率仪表盘组件
* 获取胜率颜色(>50%红色,<50%绿色)
*/
const WinRateGauge = ({ rate }) => {
const getRateColor = (rate) => {
if (rate >= 50) return '#FF4D4F'; // 红色(上涨多)
return '#52C41A'; // 绿色(下跌多)
};
/**
* 半圆仪表盘组件 - 参考用户提供的设计
* 使用渐变色:左侧绿色 -> 中间黄色 -> 右侧红色
*/
const SemiCircleGauge = ({ rate, label, size = 'normal' }) => {
const validRate = Math.min(100, Math.max(0, rate || 0));
const angle = (validRate / 100) * 180;
// 角度0% = -90deg (左), 50% = 0deg (上), 100% = 90deg (右)
const needleAngle = (validRate / 100) * 180 - 90;
const getGaugeColor = (r) => {
if (r >= 70) return '#52C41A';
if (r >= 50) return '#FFD700';
return '#FF4D4F';
};
const gaugeColor = getGaugeColor(validRate);
const gaugeColor = getRateColor(validRate);
const isSmall = size === 'small';
const gaugeWidth = isSmall ? 80 : 100;
const gaugeHeight = gaugeWidth / 2;
const needleLength = isSmall ? 30 : 38;
return (
<Box position="relative" w="100%" h="80px" overflow="hidden">
<Box position="relative" w={`${gaugeWidth}px`} h={`${gaugeHeight + 20}px`}>
{/* 半圆背景(渐变色弧线) */}
<Box
position="absolute"
bottom="0"
left="50%"
transform="translateX(-50%)"
w="120px"
h="60px"
borderTopLeftRadius="60px"
borderTopRightRadius="60px"
bg="rgba(255,255,255,0.05)"
border="3px solid rgba(255,255,255,0.1)"
borderBottom="none"
bottom="16px"
left="0"
w={`${gaugeWidth}px`}
h={`${gaugeHeight}px`}
borderTopLeftRadius={`${gaugeHeight}px`}
borderTopRightRadius={`${gaugeHeight}px`}
bg="transparent"
overflow="hidden"
>
<Box
position="absolute"
bottom="0"
left="0"
w="100%"
h="100%"
bg={`conic-gradient(from 180deg, ${gaugeColor} 0deg, ${gaugeColor} ${angle}deg, transparent ${angle}deg)`}
opacity="0.3"
style={{ transformOrigin: 'center bottom' }}
/>
</Box>
_before={{
content: '""',
position: 'absolute',
top: '0',
left: '0',
right: '0',
bottom: '0',
borderTopLeftRadius: `${gaugeHeight}px`,
borderTopRightRadius: `${gaugeHeight}px`,
border: `${isSmall ? '6px' : '8px'} solid transparent`,
borderBottom: 'none',
background: 'linear-gradient(90deg, #52C41A 0%, #FADB14 50%, #FF4D4F 100%) border-box',
mask: 'linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)',
maskComposite: 'exclude',
WebkitMaskComposite: 'destination-out',
}}
/>
{/* 内部遮罩(让弧线更细) */}
<Box
position="absolute"
bottom="3px"
bottom="16px"
left={`${isSmall ? 10 : 12}px`}
w={`${gaugeWidth - (isSmall ? 20 : 24)}px`}
h={`${gaugeHeight - (isSmall ? 10 : 12)}px`}
borderTopLeftRadius={`${gaugeHeight - (isSmall ? 10 : 12)}px`}
borderTopRightRadius={`${gaugeHeight - (isSmall ? 10 : 12)}px`}
bg="rgba(17, 24, 39, 0.95)"
/>
{/* 指针 */}
<Box
position="absolute"
bottom="16px"
left="50%"
w="2px"
h="42px"
h={`${needleLength}px`}
bg={gaugeColor}
borderRadius="full"
transformOrigin="bottom center"
transform={`translateX(-50%) rotate(${angle - 90}deg)`}
boxShadow={`0 0 10px ${gaugeColor}`}
transform={`translateX(-50%) rotate(${needleAngle}deg)`}
boxShadow={`0 0 6px ${gaugeColor}`}
transition="transform 0.5s ease-out"
/>
{/* 指针中心点 */}
<Box
position="absolute"
bottom="0"
bottom="13px"
left="50%"
transform="translateX(-50%)"
w="10px"
h="10px"
w="6px"
h="6px"
bg={gaugeColor}
borderRadius="full"
boxShadow={`0 0 8px ${gaugeColor}`}
boxShadow={`0 0 4px ${gaugeColor}`}
/>
{/* 刻度标记 */}
<Text
position="absolute"
bottom="16px"
left="0"
fontSize="2xs"
color="gray.600"
transform="translateX(2px)"
>
0
</Text>
<Text
position="absolute"
bottom="16px"
right="0"
fontSize="2xs"
color="gray.600"
transform="translateX(-2px)"
>
100
</Text>
{/* 数值和标签 */}
<VStack
position="absolute"
bottom="12px"
bottom="0"
left="50%"
transform="translateX(-50%)"
spacing={0}
>
<Text fontSize="xl" fontWeight="bold" color={gaugeColor} lineHeight="1">
{validRate.toFixed(0)}%
<Text fontSize={isSmall ? 'sm' : 'md'} fontWeight="bold" color={gaugeColor} lineHeight="1">
{validRate.toFixed(1)}%
</Text>
<Text fontSize="2xs" color="gray.500">胜率</Text>
<Text fontSize="2xs" color="gray.500">{label}</Text>
</VStack>
</Box>
);
};
<Text position="absolute" bottom="0" left="12px" fontSize="2xs" color="gray.600">0</Text>
<Text position="absolute" bottom="0" right="12px" fontSize="2xs" color="gray.600">100</Text>
/**
* 胜率对比组件 - 双仪表盘
*/
const WinRateGauge = ({ eventRate, marketRate, marketStats }) => {
const eventRateVal = eventRate || 0;
const marketRateVal = marketRate || 0;
return (
<Box>
{/* 双仪表盘对比 */}
<HStack spacing={2} justify="center" mb={1}>
<VStack spacing={0}>
<SemiCircleGauge rate={eventRateVal} label="事件胜率" size="small" />
</VStack>
<Box w="1px" h="50px" bg="rgba(255,215,0,0.2)" />
<VStack spacing={0}>
<SemiCircleGauge rate={marketRateVal} label="大盘上涨率" size="small" />
</VStack>
</HStack>
{/* 市场统计 */}
{marketStats && (
<HStack justify="center" spacing={3} mt={1}>
<HStack spacing={1}>
<Box w="6px" h="6px" borderRadius="full" bg="#FF4D4F" />
<Text fontSize="2xs" color="#FF4D4F">{marketStats.risingCount}</Text>
</HStack>
<HStack spacing={1}>
<Box w="6px" h="6px" borderRadius="full" bg="gray.400" />
<Text fontSize="2xs" color="gray.400">{marketStats.flatCount}</Text>
</HStack>
<HStack spacing={1}>
<Box w="6px" h="6px" borderRadius="full" bg="#52C41A" />
<Text fontSize="2xs" color="#52C41A">{marketStats.fallingCount}</Text>
</HStack>
</HStack>
)}
</Box>
);
};
@@ -350,7 +436,7 @@ const EventDailyStats = () => {
);
}
const { summary, topPerformers = [], topStocks = [] } = stats;
const { summary, marketStats, topPerformers = [], topStocks = [] } = stats;
return (
<Box
@@ -423,8 +509,12 @@ const EventDailyStats = () => {
{/* 内容区域 - 使用 flex: 1 填充剩余空间 */}
<VStack spacing={2} align="stretch" flex="1">
{/* 胜率仪表盘 */}
<WinRateGauge rate={summary?.positiveRate || 0} />
{/* 胜率对比仪表盘 */}
<WinRateGauge
eventRate={summary?.positiveRate || 0}
marketRate={marketStats?.risingRate || 0}
marketStats={marketStats}
/>
{/* 核心指标 - 2x2 网格 */}
<Box display="grid" gridTemplateColumns="repeat(2, 1fr)" gap={2}>