update ui

This commit is contained in:
2025-11-13 22:57:24 +08:00
parent f0bb00a2ce
commit 6113a3fefd
5 changed files with 223 additions and 35 deletions

View File

@@ -22,8 +22,8 @@ export const IMPORTANCE_LEVELS = {
badgeBg: '#dc2626', // 圆形徽章背景色 - 红色
badgeColor: 'white', // 圆形徽章文字颜色 - 白色
icon: WarningIcon,
label: '极高',
stampText: '', // 印章文字
label: 'S级',
stampText: 'S', // 印章文字
stampFont: "'STKaiti', 'KaiTi', 'SimKai', serif", // 楷体
dotBg: 'red.800',
description: '重大事件,市场影响深远',
@@ -38,8 +38,8 @@ export const IMPORTANCE_LEVELS = {
badgeBg: '#ea580c', // 圆形徽章背景色 - 橙色
badgeColor: 'white', // 圆形徽章文字颜色 - 白色
icon: WarningTwoIcon,
label: '',
stampText: '', // 印章文字
label: 'A级',
stampText: 'A', // 印章文字
stampFont: "'STXingkai', 'FangSong', 'STFangsong', cursive", // 行楷/草书
dotBg: 'red.600',
description: '重要事件,影响较大',
@@ -54,8 +54,8 @@ export const IMPORTANCE_LEVELS = {
badgeBg: '#2563eb', // 圆形徽章背景色 - 蓝色
badgeColor: 'white', // 圆形徽章文字颜色 - 白色
icon: InfoIcon,
label: '',
stampText: '', // 印章文字
label: 'B级',
stampText: 'B', // 印章文字
stampFont: "'STKaiti', 'KaiTi', 'SimKai', serif", // 楷体
dotBg: 'red.500',
description: '普通事件,有一定影响',
@@ -70,8 +70,8 @@ export const IMPORTANCE_LEVELS = {
badgeBg: '#10b981', // 圆形徽章背景色 - 青绿色(替代灰色)
badgeColor: 'white', // 圆形徽章文字颜色 - 白色
icon: CheckCircleIcon,
label: '',
stampText: '', // 印章文字
label: 'C级',
stampText: 'C', // 印章文字
stampFont: "'STKaiti', 'KaiTi', 'SimKai', serif", // 楷体
dotBg: 'red.400',
description: '参考事件,影响有限',

View File

@@ -497,7 +497,7 @@ const CompactSearchBox = ({
</Tooltip>
{/* 重要性筛选 */}
<Tooltip title="重要性筛选">
<Tooltip title="事件等级筛选">
<AntSelect
mode="multiple"
value={importance}
@@ -506,14 +506,14 @@ const CompactSearchBox = ({
width: 120,
borderRadius: '8px'
}}
placeholder="重要性"
placeholder="事件等级"
maxTagCount={0}
maxTagPlaceholder={(omittedValues) => `已选 ${omittedValues.length}`}
>
<Option value="S">极高</Option>
<Option value="A"></Option>
<Option value="B"></Option>
<Option value="C"></Option>
<Option value="S">S级</Option>
<Option value="A">A级</Option>
<Option value="B">B级</Option>
<Option value="C">C级</Option>
</AntSelect>
</Tooltip>

View File

@@ -1,6 +1,6 @@
// src/views/Community/components/EventCard/EventTimeline.js
import React from 'react';
import { Box, VStack, Text, useColorModeValue } from '@chakra-ui/react';
import { Box, VStack, Text, useColorModeValue, Badge } from '@chakra-ui/react';
import moment from 'moment';
/**
@@ -10,10 +10,11 @@ import moment from 'moment';
* @param {Object} props.timelineStyle - 时间轴样式配置
* @param {string} props.borderColor - 竖线边框颜色
* @param {string} props.minHeight - 竖线最小高度(例如:'40px' 或 '80px'
* @param {Object} props.importance - 重要性配置对象(包含 level, badgeBg, badgeColor 等)
*/
const EventTimeline = ({ createdAt, timelineStyle, borderColor, minHeight = '40px' }) => {
const EventTimeline = ({ createdAt, timelineStyle, borderColor, minHeight = '40px', importance }) => {
return (
<VStack spacing={0} align="center" minW="65px">
<VStack spacing={0} align="center" minW="65px" position="relative">
{/* 时间长方形卡片 - 更紧凑 */}
<Box
{...(timelineStyle.bgGradient ? { bgGradient: timelineStyle.bgGradient } : { bg: timelineStyle.bg })}
@@ -26,7 +27,28 @@ const EventTimeline = ({ createdAt, timelineStyle, borderColor, minHeight = '40p
textAlign="center"
boxShadow={timelineStyle.boxShadow}
transition="all 0.3s ease"
position="relative"
>
{/* 重要性等级徽章 - 左上角 */}
{importance && (
<Badge
position="absolute"
top="-6px"
left="-6px"
bg={importance.badgeBg}
color={importance.badgeColor}
fontSize="10px"
fontWeight="bold"
borderRadius="full"
px={1.5}
py={0.5}
boxShadow="md"
zIndex={2}
>
{importance.level}
</Badge>
)}
{/* 日期 MM-DD */}
<Text
fontSize="10px"

View File

@@ -19,6 +19,7 @@ import ImportanceStamp from './ImportanceStamp';
import EventTimeline from './EventTimeline';
import EventFollowButton from './EventFollowButton';
import StockChangeIndicators from '../../../../components/StockChangeIndicators';
import KeywordsCarousel from './KeywordsCarousel';
/**
* 横向布局的动态新闻事件卡片组件
@@ -101,16 +102,12 @@ const HorizontalDynamicNewsEventCard = ({
timelineStyle={timelineStyle}
borderColor={borderColor}
minHeight={layout === 'four-row' ? '60px' : 0}
importance={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 flex="1" position="relative">
{/* 事件卡片 - 增强美化效果 */}
<Card
position="relative"
bg={isSelected
@@ -123,15 +120,27 @@ const HorizontalDynamicNewsEventCard = ({
? selectedBorderColor
: borderColor
}
borderRadius="lg"
borderRadius="xl"
boxShadow={isSelected ? "xl" : "md"}
overflow="visible"
_hover={{
boxShadow: '2xl',
transform: 'translateY(-2px)',
transform: 'translateY(-3px)',
borderColor: isSelected ? 'blue.600' : importance.color,
}}
transition="all 0.3s ease"
_before={{
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: '4px',
bgGradient: `linear(to-r, ${importance.color}, ${importance.borderColor})`,
borderTopLeftRadius: 'xl',
borderTopRightRadius: 'xl',
opacity: isSelected ? 1 : 0.7,
}}
transition="all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
cursor="pointer"
onClick={() => onEventClick?.(event)}
>
@@ -179,13 +188,37 @@ const HorizontalDynamicNewsEventCard = ({
</Box>
</Tooltip>
{/* 第二行:涨跌幅数据 */}
{/* 第二行:涨跌幅数据 + Keywords轮播 */}
<HStack spacing={3} align="center" justify="space-between" w="full">
{/* 左侧:涨跌幅数据 */}
<StockChangeIndicators
avgChange={event.related_avg_chg}
maxChange={event.related_max_chg}
weekChange={event.related_week_chg}
size={indicatorSize}
/>
{/* 右侧Keywords轮播半透明效果 */}
{event.keywords && event.keywords.length > 0 && (
<Box
flex="1"
minW={0}
opacity={0.85}
_hover={{ opacity: 1 }}
transition="opacity 0.2s"
>
<KeywordsCarousel
keywords={event.keywords}
displayCount={3}
interval={3500}
onKeywordClick={(keyword) => {
console.log('Keyword clicked:', keyword);
// TODO: 实现关键词筛选功能
}}
/>
</Box>
)}
</HStack>
</VStack>
</CardBody>
</Card>

View File

@@ -0,0 +1,133 @@
// src/views/Community/components/EventCard/KeywordsCarousel.js
// Keywords标签轮播组件
import React, { useState, useEffect } from 'react';
import { Box, Tag, HStack, useColorModeValue, Tooltip } from '@chakra-ui/react';
import { motion, AnimatePresence } from 'framer-motion';
const MotionBox = motion(Box);
/**
* Keywords标签轮播组件
* @param {Array} keywords - 关键词数组
* @param {number} displayCount - 显示的标签数量默认3个
* @param {number} interval - 轮播间隔毫秒默认3000ms
* @param {Function} onKeywordClick - 关键词点击回调
*/
const KeywordsCarousel = ({
keywords = [],
displayCount = 3,
interval = 3000,
onKeywordClick
}) => {
const [currentIndex, setCurrentIndex] = useState(0);
const [isPaused, setIsPaused] = useState(false);
// 颜色配置
const tagBg = useColorModeValue('rgba(66, 153, 225, 0.1)', 'rgba(66, 153, 225, 0.2)');
const tagColor = useColorModeValue('blue.600', 'blue.300');
const tagBorder = useColorModeValue('blue.200', 'blue.600');
// 如果没有keywords不渲染
if (!keywords || keywords.length === 0) {
return null;
}
// 自动轮播
useEffect(() => {
if (isPaused || keywords.length <= displayCount) return;
const timer = setInterval(() => {
setCurrentIndex((prev) => (prev + 1) % keywords.length);
}, interval);
return () => clearInterval(timer);
}, [isPaused, keywords.length, displayCount, interval]);
// 获取当前显示的关键词
const getVisibleKeywords = () => {
if (keywords.length <= displayCount) {
return keywords;
}
const visible = [];
for (let i = 0; i < displayCount; i++) {
const index = (currentIndex + i) % keywords.length;
visible.push(keywords[index]);
}
return visible;
};
const visibleKeywords = getVisibleKeywords();
return (
<Box
onMouseEnter={() => setIsPaused(true)}
onMouseLeave={() => setIsPaused(false)}
position="relative"
>
<HStack spacing={1.5} flexWrap="wrap">
<AnimatePresence mode="wait">
{visibleKeywords.map((keyword, index) => (
<MotionBox
key={`${keyword}-${currentIndex}-${index}`}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.3 }}
>
<Tooltip
label={`点击筛选"${keyword}"`}
placement="top"
hasArrow
>
<Tag
size="sm"
variant="subtle"
bg={tagBg}
color={tagColor}
borderWidth="1px"
borderColor={tagBorder}
cursor="pointer"
fontSize="10px"
fontWeight="medium"
px={2}
py={0.5}
borderRadius="full"
_hover={{
bg: useColorModeValue('blue.100', 'blue.700'),
transform: 'scale(1.05)',
boxShadow: 'md'
}}
transition="all 0.2s"
onClick={(e) => {
e.stopPropagation();
onKeywordClick?.(keyword);
}}
>
#{keyword}
</Tag>
</Tooltip>
</MotionBox>
))}
</AnimatePresence>
</HStack>
{/* 如果有更多关键词,显示指示器 */}
{keywords.length > displayCount && (
<Box
position="absolute"
right={-2}
top="50%"
transform="translateY(-50%)"
fontSize="10px"
color="gray.400"
fontWeight="bold"
>
+{keywords.length - displayCount}
</Box>
)}
</Box>
);
};
export default KeywordsCarousel;