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

View File

@@ -15,7 +15,7 @@ import {
import { getImportanceConfig } from '../../../../constants/importanceLevels'; import { getImportanceConfig } from '../../../../constants/importanceLevels';
// 导入子组件 // 导入子组件
import ImportanceBadge from './ImportanceBadge'; import ImportanceStamp from './ImportanceStamp';
import EventTimeline from './EventTimeline'; import EventTimeline from './EventTimeline';
import EventFollowButton from './EventFollowButton'; import EventFollowButton from './EventFollowButton';
import StockChangeIndicators from '../../../../components/StockChangeIndicators'; import StockChangeIndicators from '../../../../components/StockChangeIndicators';
@@ -57,6 +57,40 @@ const HorizontalDynamicNewsEventCard = ({
const selectedBorderColor = useColorModeValue('blue.500', 'blue.400'); const selectedBorderColor = useColorModeValue('blue.500', 'blue.400');
const linkColor = useColorModeValue('blue.600', '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 ( return (
<HStack align="stretch" spacing={3} w="full"> <HStack align="stretch" spacing={3} w="full">
{/* 左侧时间轴 */} {/* 左侧时间轴 */}
@@ -67,88 +101,93 @@ const HorizontalDynamicNewsEventCard = ({
minHeight="60px" minHeight="60px"
/> />
{/* 右侧事件卡片 */} {/* 右侧事件卡片容器(带印章) */}
<Card <Box flex="1" position="relative" pt={6}>
flex="1" {/* 右上角:重要性印章(放在卡片外层) */}
position="relative" <Box position="absolute" top={-2} right={4} zIndex={10}>
bg={isSelected <ImportanceStamp importance={event.importance} size="sm" />
? selectedBg </Box>
: (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 position="absolute" top={2} right={2} zIndex={1}> <Card
<EventFollowButton position="relative"
isFollowing={isFollowing} bg={isSelected
followerCount={followerCount} ? selectedBg
onToggle={() => onToggleFollow?.(event.id)} : getChangeBasedBgColor(event.related_avg_chg)
size="xs" }
showCount={false} backdropFilter="blur(10px)" // 毛玻璃效果
/> borderWidth={isSelected ? "2px" : "1px"}
</Box> 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}> <VStack align="stretch" spacing={1.5}>
{/* 标题 - 最多两行hover 显示完整内容 */} {/* 标题 - 最多两行hover 显示完整内容 */}
<Tooltip <Tooltip
label={event.title} label={event.title}
placement="top" placement="top"
hasArrow hasArrow
bg="gray.700" bg="gray.700"
color="white" color="white"
fontSize="sm" fontSize="sm"
p={2} p={2}
borderRadius="md" borderRadius="md"
isDisabled={event.title.length < 40} isDisabled={event.title.length < 40}
>
<Box
cursor="pointer"
onClick={(e) => onTitleClick?.(e, event)}
mt={1}
paddingRight="10px"
> >
<Text <Box
fontSize="md" cursor="pointer"
fontWeight="semibold" onClick={(e) => onTitleClick?.(e, event)}
color={linkColor} mt={1}
lineHeight="1.4" paddingRight="10px"
noOfLines={2}
_hover={{ textDecoration: 'underline' }}
> >
{event.title} <Text
</Text> fontSize="md"
</Box> fontWeight="semibold"
</Tooltip> color={linkColor}
lineHeight="1.4"
noOfLines={2}
_hover={{ textDecoration: 'underline' }}
>
{event.title}
</Text>
</Box>
</Tooltip>
{/* 第二行:涨跌幅数据 */} {/* 第二行:涨跌幅数据 */}
<StockChangeIndicators <StockChangeIndicators
avgChange={event.related_avg_chg} avgChange={event.related_avg_chg}
maxChange={event.related_max_chg} maxChange={event.related_max_chg}
weekChange={event.related_week_chg} weekChange={event.related_week_chg}
size={indicatorSize} size={indicatorSize}
/> />
</VStack> </VStack>
</CardBody> </CardBody>
</Card> </Card>
</Box>
</HStack> </HStack>
); );
}; };

View File

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