feat本次提交包含的优化

 StockChangeIndicators 组件优化

  - 调整 padding 使布局更紧凑
  - 修复窄卡片中的折行问题
  - 自动根据内容调整宽度

   重要性等级视觉优化

  - 统一使用红色系(S→A→B→C:从深红到浅红)
  - 添加 badgeBg 字段支持新的角标样式

   DynamicNewsEventCard 卡片改版

  - 左上角矩形角标显示重要性(镂空边框样式)
  - 悬浮显示所有等级说明
  - 标题限制两行显示

   Mock 数据完整性

  - 添加缺失的 related_week_chg 字段
  - 确保三个涨跌幅指标数据完整
This commit is contained in:
zdl
2025-11-03 15:38:30 +08:00
parent 9274323151
commit 7e32dda2df
4 changed files with 110 additions and 32 deletions

View File

@@ -127,8 +127,8 @@ const StockChangeIndicators = ({
borderWidth="2px" borderWidth="2px"
borderColor={borderColor} borderColor={borderColor}
borderRadius="md" borderRadius="md"
px={2} px={1.5}
py={1} py={0.5}
display="flex" display="flex"
alignItems="center" alignItems="center"
justifyContent="center" justifyContent="center"

View File

@@ -15,47 +15,55 @@ import {
export const IMPORTANCE_LEVELS = { export const IMPORTANCE_LEVELS = {
'S': { 'S': {
level: 'S', level: 'S',
color: 'purple.600', color: 'red.800',
bgColor: 'purple.50', bgColor: 'red.50',
borderColor: 'purple.200', borderColor: 'red.200',
colorScheme: 'red',
badgeBg: 'red.800', // 角标边框和文字颜色 - 极深红色
icon: WarningIcon, icon: WarningIcon,
label: '极高', label: '极高',
dotBg: 'purple.500', dotBg: 'red.800',
description: '重大事件,市场影响深远', description: '重大事件,市场影响深远',
antdColor: '#722ed1', // 对应 Ant Design 的紫色 antdColor: '#cf1322',
}, },
'A': { 'A': {
level: 'A', level: 'A',
color: 'red.600', color: 'red.600',
bgColor: 'red.50', bgColor: 'red.50',
borderColor: 'red.200', borderColor: 'red.200',
colorScheme: 'red',
badgeBg: 'red.600', // 角标边框和文字颜色 - 深红色
icon: WarningTwoIcon, icon: WarningTwoIcon,
label: '高', label: '高',
dotBg: 'red.500', dotBg: 'red.600',
description: '重要事件,影响较大', description: '重要事件,影响较大',
antdColor: '#ff4d4f', // 对应 Ant Design 的红色 antdColor: '#ff4d4f',
}, },
'B': { 'B': {
level: 'B', level: 'B',
color: 'orange.600', color: 'red.500',
bgColor: 'orange.50', bgColor: 'red.50',
borderColor: 'orange.200', borderColor: 'red.100',
colorScheme: 'red',
badgeBg: 'red.500', // 角标边框和文字颜色 - 中红色
icon: InfoIcon, icon: InfoIcon,
label: '中', label: '中',
dotBg: 'orange.500', dotBg: 'red.500',
description: '普通事件,有一定影响', description: '普通事件,有一定影响',
antdColor: '#faad14', // 对应 Ant Design 的橙色 antdColor: '#ff7875',
}, },
'C': { 'C': {
level: 'C', level: 'C',
color: 'green.600', color: 'red.400',
bgColor: 'green.50', bgColor: 'red.50',
borderColor: 'green.200', borderColor: 'red.100',
colorScheme: 'red',
badgeBg: 'red.400', // 角标边框和文字颜色 - 浅红色
icon: CheckCircleIcon, icon: CheckCircleIcon,
label: '低', label: '低',
dotBg: 'green.500', dotBg: 'red.400',
description: '参考事件,影响有限', description: '参考事件,影响有限',
antdColor: '#52c41a', // 对应 Ant Design 的绿色 antdColor: '#ffa39e',
} }
}; };

View File

@@ -753,6 +753,7 @@ export function generateMockEvents(params = {}) {
const hotScore = Math.max(50, 100 - i); const hotScore = Math.max(50, 100 - i);
const relatedAvgChg = (Math.random() * 20 - 5).toFixed(2); // -5% 到 15% const relatedAvgChg = (Math.random() * 20 - 5).toFixed(2); // -5% 到 15%
const relatedMaxChg = (Math.random() * 30).toFixed(2); // 0% 到 30% const relatedMaxChg = (Math.random() * 30).toFixed(2); // 0% 到 30%
const relatedWeekChg = (Math.random() * 30 - 10).toFixed(2); // -10% 到 20%
// 生成价格走势数据(前一天、当天、后一天) // 生成价格走势数据(前一天、当天、后一天)
const generatePriceTrend = (seed) => { const generatePriceTrend = (seed) => {
@@ -848,6 +849,7 @@ export function generateMockEvents(params = {}) {
view_count: Math.floor(Math.random() * 10000), view_count: Math.floor(Math.random() * 10000),
related_avg_chg: parseFloat(relatedAvgChg), related_avg_chg: parseFloat(relatedAvgChg),
related_max_chg: parseFloat(relatedMaxChg), related_max_chg: parseFloat(relatedMaxChg),
related_week_chg: parseFloat(relatedWeekChg),
keywords: generateKeywords(industry, i), keywords: generateKeywords(industry, i),
is_ai_generated: i % 4 === 0, // 25% 的事件是AI生成 is_ai_generated: i % 4 === 0, // 25% 的事件是AI生成
industry: industry, industry: industry,

View File

@@ -8,10 +8,17 @@ import {
CardBody, CardBody,
Box, Box,
Text, Text,
HStack,
Popover,
PopoverTrigger,
PopoverContent,
PopoverBody,
PopoverArrow,
Portal,
useColorModeValue, useColorModeValue,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import moment from 'moment'; import moment from 'moment';
import { getImportanceConfig } from '../../../../constants/importanceLevels'; import { getImportanceConfig, getAllImportanceLevels } from '../../../../constants/importanceLevels';
// 导入子组件 // 导入子组件
import EventFollowButton from './EventFollowButton'; import EventFollowButton from './EventFollowButton';
@@ -85,6 +92,7 @@ const DynamicNewsEventCard = ({
} }
borderRadius="md" borderRadius="md"
boxShadow={isSelected ? "lg" : "sm"} boxShadow={isSelected ? "lg" : "sm"}
overflow="hidden"
_hover={{ _hover={{
boxShadow: 'xl', boxShadow: 'xl',
transform: 'translateY(-2px)', transform: 'translateY(-2px)',
@@ -95,7 +103,74 @@ const DynamicNewsEventCard = ({
onClick={() => onEventClick?.(event)} onClick={() => onEventClick?.(event)}
> >
<CardBody p={3}> <CardBody p={3}>
{/* 关注按钮 - 绝对定位在右上角 */} {/* 左上角:重要性矩形角标(镂空边框样式) */}
<Popover trigger="hover" placement="right" isLazy>
<PopoverTrigger>
<Box
position="absolute"
top={0}
left={0}
zIndex={1}
bg="transparent"
color={importance.badgeBg}
borderWidth="2px"
borderColor={importance.badgeBg}
fontSize="11px"
fontWeight="bold"
px={1.5}
py={0.5}
minW="auto"
display="flex"
alignItems="center"
justifyContent="center"
lineHeight="1"
borderBottomRightRadius="md"
cursor="help"
>
{importance.label}
</Box>
</PopoverTrigger>
<Portal>
<PopoverContent width="auto" maxW="350px">
<PopoverArrow />
<PopoverBody p={3}>
<VStack align="stretch" spacing={2}>
<Text fontSize="sm" fontWeight="bold" mb={1}>
重要性等级说明
</Text>
{getAllImportanceLevels().map(item => (
<HStack key={item.level} spacing={2} align="flex-start">
<Box
w="20px"
h="20px"
borderWidth="2px"
borderColor={item.badgeBg}
color={item.badgeBg}
fontSize="9px"
fontWeight="bold"
display="flex"
alignItems="center"
justifyContent="center"
borderRadius="sm"
flexShrink={0}
>
{item.level}
</Box>
<Text fontSize="xs" flex={1}>
<Text as="span" fontWeight="bold">
{item.label}
</Text>
{item.description}
</Text>
</HStack>
))}
</VStack>
</PopoverBody>
</PopoverContent>
</Portal>
</Popover>
{/* 右上角:关注按钮 */}
<Box position="absolute" top={2} right={2} zIndex={1}> <Box position="absolute" top={2} right={2} zIndex={1}>
<EventFollowButton <EventFollowButton
isFollowing={isFollowing} isFollowing={isFollowing}
@@ -106,11 +181,12 @@ const DynamicNewsEventCard = ({
/> />
</Box> </Box>
<VStack align="stretch" spacing={2.5}> <VStack align="stretch" spacing={2}>
{/* 第一行:标题 + 重要性(行内文字) */} {/* 标题 - 最多两行,添加上边距避免与角标重叠 */}
<Box <Box
cursor="pointer" cursor="pointer"
onClick={(e) => onTitleClick?.(e, event)} onClick={(e) => onTitleClick?.(e, event)}
mt={1}
paddingRight="10px" paddingRight="10px"
> >
<Text <Text
@@ -118,18 +194,10 @@ const DynamicNewsEventCard = ({
fontWeight="semibold" fontWeight="semibold"
color={linkColor} color={linkColor}
lineHeight="1.4" lineHeight="1.4"
noOfLines={2}
_hover={{ textDecoration: 'underline' }} _hover={{ textDecoration: 'underline' }}
> >
{event.title} {event.title}
<Text
as="span"
fontSize="sm"
fontWeight="bold"
color={importance.color}
ml={2}
>
[{importance.level}]
</Text>
</Text> </Text>
</Box> </Box>