feat: 添加消息推送能力,添加新闻催化分析页的合规提示

This commit is contained in:
zdl
2025-10-21 10:59:52 +08:00
parent 6c96299b8f
commit 5a3a3ad42b
15 changed files with 1800 additions and 125 deletions

View File

@@ -0,0 +1,189 @@
// src/components/NotificationContainer/index.js
/**
* 通知容器组件 - 右下角层叠显示实时通知
*/
import React from 'react';
import {
Box,
VStack,
HStack,
Text,
IconButton,
Icon,
useColorModeValue,
Slide,
ScaleFade,
} from '@chakra-ui/react';
import { MdClose, MdCheckCircle, MdError, MdWarning, MdInfo } from 'react-icons/md';
import { useNotification } from '../../contexts/NotificationContext';
// 通知类型对应的图标和颜色
const NOTIFICATION_STYLES = {
success: {
icon: MdCheckCircle,
colorScheme: 'green',
bg: 'green.50',
borderColor: 'green.400',
iconColor: 'green.500',
},
error: {
icon: MdError,
colorScheme: 'red',
bg: 'red.50',
borderColor: 'red.400',
iconColor: 'red.500',
},
warning: {
icon: MdWarning,
colorScheme: 'orange',
bg: 'orange.50',
borderColor: 'orange.400',
iconColor: 'orange.500',
},
info: {
icon: MdInfo,
colorScheme: 'blue',
bg: 'blue.50',
borderColor: 'blue.400',
iconColor: 'blue.500',
},
};
/**
* 单个通知项组件
*/
const NotificationItem = ({ notification, onClose, isNewest = false }) => {
const { id, severity = 'info', title, message } = notification;
const style = NOTIFICATION_STYLES[severity] || NOTIFICATION_STYLES.info;
const bgColor = useColorModeValue(style.bg, `${style.colorScheme}.900`);
const borderColor = useColorModeValue(style.borderColor, `${style.colorScheme}.500`);
const textColor = useColorModeValue('gray.800', 'white');
const subTextColor = useColorModeValue('gray.600', 'gray.300');
return (
<ScaleFade initialScale={0.9} in={true}>
<Box
bg={bgColor}
borderLeft="4px solid"
borderColor={borderColor}
borderRadius="md"
boxShadow={isNewest ? '2xl' : 'lg'} // 最新消息更强的阴影
p={4}
minW="350px"
maxW="450px"
position="relative"
_hover={{
boxShadow: 'xl',
transform: 'translateX(-4px)',
}}
transition="all 0.2s"
// 最新消息添加微妙的高亮边框
{...(isNewest && {
borderRight: '1px solid',
borderRightColor: borderColor,
borderTop: '1px solid',
borderTopColor: useColorModeValue(`${style.colorScheme}.100`, `${style.colorScheme}.700`),
})}
>
<HStack spacing={3} align="start">
{/* 图标 */}
<Icon
as={style.icon}
w={6}
h={6}
color={style.iconColor}
mt={0.5}
flexShrink={0}
/>
{/* 内容 */}
<VStack align="start" spacing={1} flex={1} mr={6}>
<Text
fontSize="md"
fontWeight="bold"
color={textColor}
lineHeight="short"
>
{title}
</Text>
{message && (
<Text
fontSize="sm"
color={subTextColor}
lineHeight="short"
>
{message}
</Text>
)}
</VStack>
{/* 关闭按钮 */}
<IconButton
icon={<MdClose />}
size="sm"
variant="ghost"
colorScheme={style.colorScheme}
aria-label="关闭通知"
onClick={() => onClose(id)}
position="absolute"
top={2}
right={2}
_hover={{
bg: useColorModeValue(`${style.colorScheme}.100`, `${style.colorScheme}.800`),
}}
/>
</HStack>
</Box>
</ScaleFade>
);
};
/**
* 通知容器组件 - 主组件
*/
const NotificationContainer = () => {
const { notifications, removeNotification } = useNotification();
// 如果没有通知,不渲染
if (notifications.length === 0) {
return null;
}
return (
<Box
position="fixed"
bottom={6}
right={6}
zIndex={9999}
pointerEvents="none"
>
<VStack
spacing={3} // 消息之间间距 12px
align="flex-end"
pointerEvents="auto"
>
{notifications.map((notification, index) => (
<Slide
key={notification.id}
direction="right"
in={true}
style={{
position: 'relative',
zIndex: 9999 - index, // 最新消息index=0z-index最高
}}
>
<NotificationItem
notification={notification}
onClose={removeNotification}
isNewest={index === 0} // 第一条消息是最新的
/>
</Slide>
))}
</VStack>
</Box>
);
};
export default NotificationContainer;