事件中心UI优化

This commit is contained in:
2025-11-07 11:20:45 +08:00
parent 25d3bf4d95
commit 83cd875690
3 changed files with 147 additions and 92 deletions

View File

@@ -24,6 +24,7 @@ export const IMPORTANCE_LEVELS = {
icon: WarningIcon,
label: '极高',
stampText: '极', // 印章文字
stampFont: "'STKaiti', 'KaiTi', 'SimKai', serif", // 楷体
dotBg: 'red.800',
description: '重大事件,市场影响深远',
antdColor: '#cf1322',
@@ -39,6 +40,7 @@ export const IMPORTANCE_LEVELS = {
icon: WarningTwoIcon,
label: '高',
stampText: '高', // 印章文字
stampFont: "'STXingkai', 'FangSong', 'STFangsong', cursive", // 行楷/草书
dotBg: 'red.600',
description: '重要事件,影响较大',
antdColor: '#ff4d4f',
@@ -54,6 +56,7 @@ export const IMPORTANCE_LEVELS = {
icon: InfoIcon,
label: '中',
stampText: '中', // 印章文字
stampFont: "'STKaiti', 'KaiTi', 'SimKai', serif", // 楷体
dotBg: 'red.500',
description: '普通事件,有一定影响',
antdColor: '#ff7875',
@@ -64,11 +67,12 @@ export const IMPORTANCE_LEVELS = {
bgColor: 'red.50',
borderColor: 'red.100',
colorScheme: 'red',
badgeBg: '#6b7280', // 圆形徽章背景色 - 灰色
badgeBg: '#10b981', // 圆形徽章背景色 - 青绿色(替代灰色
badgeColor: 'white', // 圆形徽章文字颜色 - 白色
icon: CheckCircleIcon,
label: '低',
stampText: '低', // 印章文字
stampFont: "'STKaiti', 'KaiTi', 'SimKai', serif", // 楷体
dotBg: 'red.400',
description: '参考事件,影响有限',
antdColor: '#ffa39e',

View File

@@ -15,7 +15,7 @@ import {
import { getImportanceConfig } from '../../../../constants/importanceLevels';
// 导入子组件
import ImportanceBadge from './ImportanceBadge';
import ImportanceStamp from './ImportanceStamp';
import EventTimeline from './EventTimeline';
import EventFollowButton from './EventFollowButton';
import StockChangeIndicators from '../../../../components/StockChangeIndicators';
@@ -57,6 +57,40 @@ const HorizontalDynamicNewsEventCard = ({
const selectedBorderColor = useColorModeValue('blue.500', 'blue.400');
const linkColor = useColorModeValue('blue.600', 'blue.400');
/**
* 根据平均涨幅计算背景色(分级策略)- 使用毛玻璃效果
* @param {number} avgChange - 平均涨跌幅
* @returns {string} Chakra UI 颜色值
*/
const getChangeBasedBgColor = (avgChange) => {
const numChange = Number(avgChange);
// 如果没有涨跌幅数据,使用半透明背景
if (avgChange == null || isNaN(numChange)) {
return useColorModeValue('rgba(255, 255, 255, 0.8)', 'rgba(26, 32, 44, 0.8)');
}
// 根据涨跌幅分级返回半透明背景色(毛玻璃效果)
const absChange = Math.abs(numChange);
if (numChange > 0) {
// 涨:红色系半透明
if (absChange >= 9) return useColorModeValue('rgba(254, 202, 202, 0.9)', 'rgba(127, 29, 29, 0.9)');
if (absChange >= 7) return useColorModeValue('rgba(254, 202, 202, 0.8)', 'rgba(153, 27, 27, 0.8)');
if (absChange >= 5) return useColorModeValue('rgba(254, 226, 226, 0.8)', 'rgba(185, 28, 28, 0.8)');
if (absChange >= 3) return useColorModeValue('rgba(254, 226, 226, 0.7)', 'rgba(220, 38, 38, 0.7)');
return useColorModeValue('rgba(254, 242, 242, 0.7)', 'rgba(239, 68, 68, 0.7)');
} else if (numChange < 0) {
// 跌:绿色系半透明
if (absChange >= 9) return useColorModeValue('rgba(187, 247, 208, 0.9)', 'rgba(20, 83, 45, 0.9)');
if (absChange >= 7) return useColorModeValue('rgba(187, 247, 208, 0.8)', 'rgba(22, 101, 52, 0.8)');
if (absChange >= 5) return useColorModeValue('rgba(209, 250, 229, 0.8)', 'rgba(21, 128, 61, 0.8)');
if (absChange >= 3) return useColorModeValue('rgba(209, 250, 229, 0.7)', 'rgba(22, 163, 74, 0.7)');
return useColorModeValue('rgba(240, 253, 244, 0.7)', 'rgba(34, 197, 94, 0.7)');
}
return useColorModeValue('rgba(255, 255, 255, 0.8)', 'rgba(26, 32, 44, 0.8)');
};
return (
<HStack align="stretch" spacing={3} w="full">
{/* 左侧时间轴 */}
@@ -67,88 +101,93 @@ const HorizontalDynamicNewsEventCard = ({
minHeight="60px"
/>
{/* 右侧事件卡片 */}
<Card
flex="1"
position="relative"
bg={isSelected
? selectedBg
: (index % 2 === 0 ? cardBg : cardBgAlt)
}
borderWidth={isSelected ? "2px" : "1px"}
borderColor={isSelected
? selectedBorderColor
: borderColor
}
borderRadius="md"
boxShadow={isSelected ? "lg" : "sm"}
overflow="hidden"
_hover={{
boxShadow: 'xl',
transform: 'translateY(-2px)',
borderColor: isSelected ? 'blue.600' : importance.color,
}}
transition="all 0.3s ease"
cursor="pointer"
onClick={() => onEventClick?.(event)}
>
<CardBody p={3} pb={2}>
{/* 左上角:重要性标签 */}
<ImportanceBadge importance={event.importance} />
{/* 右侧事件卡片容器(带印章) */}
<Box flex="1" position="relative" pt={6}>
{/* 右上角:重要性印章(放在卡片外层) */}
<Box position="absolute" top={-2} right={4} zIndex={10}>
<ImportanceStamp importance={event.importance} size="sm" />
</Box>
{/* 右上角:关注按钮 */}
<Box position="absolute" top={2} right={2} zIndex={1}>
<EventFollowButton
isFollowing={isFollowing}
followerCount={followerCount}
onToggle={() => onToggleFollow?.(event.id)}
size="xs"
showCount={false}
/>
</Box>
{/* 事件卡片 */}
<Card
position="relative"
bg={isSelected
? selectedBg
: getChangeBasedBgColor(event.related_avg_chg)
}
backdropFilter="blur(10px)" // 毛玻璃效果
borderWidth={isSelected ? "2px" : "1px"}
borderColor={isSelected
? selectedBorderColor
: borderColor
}
borderRadius="lg"
boxShadow={isSelected ? "xl" : "md"}
overflow="visible"
_hover={{
boxShadow: '2xl',
transform: 'translateY(-2px)',
borderColor: isSelected ? 'blue.600' : importance.color,
}}
transition="all 0.3s ease"
cursor="pointer"
onClick={() => onEventClick?.(event)}
>
<CardBody p={3} pb={2}>
{/* 右上角:关注按钮 */}
<Box position="absolute" top={2} right={2} zIndex={1}>
<EventFollowButton
isFollowing={isFollowing}
followerCount={followerCount}
onToggle={() => onToggleFollow?.(event.id)}
size="xs"
showCount={false}
/>
</Box>
<VStack align="stretch" spacing={1.5}>
{/* 标题 - 最多两行hover 显示完整内容 */}
<Tooltip
label={event.title}
placement="top"
hasArrow
bg="gray.700"
color="white"
fontSize="sm"
p={2}
borderRadius="md"
isDisabled={event.title.length < 40}
>
<Box
cursor="pointer"
onClick={(e) => onTitleClick?.(e, event)}
mt={1}
paddingRight="10px"
<VStack align="stretch" spacing={1.5}>
{/* 标题 - 最多两行hover 显示完整内容 */}
<Tooltip
label={event.title}
placement="top"
hasArrow
bg="gray.700"
color="white"
fontSize="sm"
p={2}
borderRadius="md"
isDisabled={event.title.length < 40}
>
<Text
fontSize="md"
fontWeight="semibold"
color={linkColor}
lineHeight="1.4"
noOfLines={2}
_hover={{ textDecoration: 'underline' }}
<Box
cursor="pointer"
onClick={(e) => onTitleClick?.(e, event)}
mt={1}
paddingRight="10px"
>
{event.title}
</Text>
</Box>
</Tooltip>
<Text
fontSize="md"
fontWeight="semibold"
color={linkColor}
lineHeight="1.4"
noOfLines={2}
_hover={{ textDecoration: 'underline' }}
>
{event.title}
</Text>
</Box>
</Tooltip>
{/* 第二行:涨跌幅数据 */}
<StockChangeIndicators
avgChange={event.related_avg_chg}
maxChange={event.related_max_chg}
weekChange={event.related_week_chg}
size={indicatorSize}
/>
</VStack>
</CardBody>
</Card>
{/* 第二行:涨跌幅数据 */}
<StockChangeIndicators
avgChange={event.related_avg_chg}
maxChange={event.related_max_chg}
weekChange={event.related_week_chg}
size={indicatorSize}
/>
</VStack>
</CardBody>
</Card>
</Box>
</HStack>
);
};

View File

@@ -13,13 +13,23 @@ import { getImportanceConfig } from '../../../../constants/importanceLevels';
* 重要性印章组件(模拟盖章效果)
* @param {Object} props
* @param {string} props.importance - 重要性等级 (S/A/B/C)
* @param {string} props.size - 印章尺寸 ('sm' | 'md' | 'lg')
*/
const ImportanceStamp = ({ importance }) => {
const ImportanceStamp = ({ importance, size = 'md' }) => {
const config = getImportanceConfig(importance);
// 印章颜色
const stampColor = useColorModeValue(config.badgeBg, config.badgeBg);
// 尺寸配置
const sizeConfig = {
sm: { outer: '40px', inner: '34px', fontSize: 'md', borderOuter: '2px', borderInner: '1.5px' },
md: { outer: '50px', inner: '42px', fontSize: 'xl', borderOuter: '3px', borderInner: '2px' },
lg: { outer: '60px', inner: '52px', fontSize: '2xl', borderOuter: '4px', borderInner: '2.5px' },
};
const currentSize = sizeConfig[size];
return (
<Box
position="relative"
@@ -28,41 +38,43 @@ const ImportanceStamp = ({ importance }) => {
{/* 外层圆形边框(双圈) */}
<Box
position="relative"
w="50px"
h="50px"
w={currentSize.outer}
h={currentSize.outer}
borderRadius="50%"
borderWidth="3px"
borderWidth={currentSize.borderOuter}
borderColor={stampColor}
display="flex"
alignItems="center"
justifyContent="center"
transform="rotate(-15deg)"
opacity={0.85}
boxShadow="0 2px 8px rgba(0,0,0,0.15)"
opacity={0.9}
boxShadow="0 3px 12px rgba(0,0,0,0.2)"
bg={useColorModeValue('white', 'gray.800')}
_hover={{
opacity: 1,
transform: "rotate(-15deg) scale(1.1)",
transform: "rotate(-15deg) scale(1.15)",
boxShadow: "0 4px 16px rgba(0,0,0,0.3)",
}}
transition="all 0.3s ease"
>
{/* 内层圆形边框 */}
<Box
position="absolute"
w="42px"
h="42px"
w={currentSize.inner}
h={currentSize.inner}
borderRadius="50%"
borderWidth="2px"
borderWidth={currentSize.borderInner}
borderColor={stampColor}
/>
{/* 印章文字 */}
<Text
fontSize="xl"
fontSize={currentSize.fontSize}
fontWeight="black"
color={stampColor}
fontFamily="'STKaiti', 'KaiTi', 'SimKai', serif"
fontFamily={config.stampFont}
letterSpacing="2px"
textShadow="0 0 1px currentColor"
textShadow="0 0 2px currentColor"
>
{config.stampText}
</Text>