│ │
│ 1. src/services/socketService.js - 指数退避 + 无限重试 │
│ 2. src/components/ConnectionStatusBar/index.js - UI 优化 + 自动消失 │
│ 3. src/App.js - handleClose 实现 + dismissed 状态管理 │
│ 4. src/contexts/NotificationContext.js - 添加成功状态检测 │
│ 5. NOTIFICATION_SYSTEM.md - v2.11.0 文档更新
145 lines
4.5 KiB
JavaScript
145 lines
4.5 KiB
JavaScript
// src/components/ConnectionStatusBar/index.js
|
||
/**
|
||
* Socket 连接状态栏组件
|
||
* 显示 Socket 连接状态并提供重试功能
|
||
*/
|
||
|
||
import React from 'react';
|
||
import {
|
||
Alert,
|
||
AlertIcon,
|
||
AlertTitle,
|
||
AlertDescription,
|
||
Button,
|
||
CloseButton,
|
||
Box,
|
||
HStack,
|
||
useColorModeValue,
|
||
Slide,
|
||
} from '@chakra-ui/react';
|
||
import { MdRefresh } from 'react-icons/md';
|
||
|
||
/**
|
||
* 连接状态枚举
|
||
*/
|
||
export const CONNECTION_STATUS = {
|
||
CONNECTED: 'connected', // 已连接
|
||
DISCONNECTED: 'disconnected', // 已断开
|
||
RECONNECTING: 'reconnecting', // 重连中
|
||
FAILED: 'failed', // 连接失败
|
||
RECONNECTED: 'reconnected', // 重连成功(显示2秒后自动消失)
|
||
};
|
||
|
||
/**
|
||
* 连接状态栏组件
|
||
*/
|
||
const ConnectionStatusBar = ({
|
||
status = CONNECTION_STATUS.CONNECTED,
|
||
reconnectAttempt = 0,
|
||
maxReconnectAttempts = 5,
|
||
onRetry,
|
||
onClose,
|
||
isDismissed = false, // 用户是否手动关闭
|
||
}) => {
|
||
// 显示条件:非正常状态 且 用户未手动关闭
|
||
const shouldShow = status !== CONNECTION_STATUS.CONNECTED && !isDismissed;
|
||
|
||
// 状态配置
|
||
const statusConfig = {
|
||
[CONNECTION_STATUS.DISCONNECTED]: {
|
||
status: 'warning',
|
||
title: '连接已断开',
|
||
description: '正在尝试重新连接...',
|
||
},
|
||
[CONNECTION_STATUS.RECONNECTING]: {
|
||
status: 'warning',
|
||
title: '正在重新连接',
|
||
description: maxReconnectAttempts === Infinity
|
||
? `尝试重连中 (第 ${reconnectAttempt} 次)`
|
||
: `尝试重连中 (第 ${reconnectAttempt}/${maxReconnectAttempts} 次)`,
|
||
},
|
||
[CONNECTION_STATUS.FAILED]: {
|
||
status: 'error',
|
||
title: '连接失败',
|
||
description: '无法连接到服务器,请检查网络连接',
|
||
},
|
||
[CONNECTION_STATUS.RECONNECTED]: {
|
||
status: 'success',
|
||
title: '已重新连接',
|
||
description: '连接已恢复',
|
||
},
|
||
};
|
||
|
||
const config = statusConfig[status] || statusConfig[CONNECTION_STATUS.DISCONNECTED];
|
||
|
||
// 颜色配置
|
||
const bg = useColorModeValue(
|
||
{
|
||
warning: 'orange.50',
|
||
error: 'red.50',
|
||
success: 'green.50',
|
||
}[config.status],
|
||
{
|
||
warning: 'rgba(251, 146, 60, 0.15)', // orange with transparency
|
||
error: 'rgba(239, 68, 68, 0.15)', // red with transparency
|
||
success: 'rgba(34, 197, 94, 0.15)', // green with transparency
|
||
}[config.status]
|
||
);
|
||
|
||
return (
|
||
<Slide
|
||
direction="top"
|
||
in={shouldShow}
|
||
style={{ zIndex: 1050 }} // 降低 zIndex,避免遮挡 modal
|
||
>
|
||
<Alert
|
||
status={config.status}
|
||
variant="subtle"
|
||
bg={bg}
|
||
borderBottom="1px solid"
|
||
borderColor={useColorModeValue('gray.200', 'gray.700')}
|
||
py={2} // 减小高度,更紧凑
|
||
px={{ base: 4, md: 6 }}
|
||
opacity={0.95} // 半透明
|
||
>
|
||
<AlertIcon />
|
||
<Box flex="1">
|
||
<HStack spacing={2} align="center" flexWrap="wrap">
|
||
<AlertTitle fontSize="sm" fontWeight="bold" mb={0}>
|
||
{config.title}
|
||
</AlertTitle>
|
||
<AlertDescription fontSize="sm" mb={0}>
|
||
{config.description}
|
||
</AlertDescription>
|
||
</HStack>
|
||
</Box>
|
||
|
||
{/* 重试按钮(仅失败状态显示) */}
|
||
{status === CONNECTION_STATUS.FAILED && onRetry && (
|
||
<Button
|
||
size="sm"
|
||
colorScheme="red"
|
||
leftIcon={<MdRefresh />}
|
||
onClick={onRetry}
|
||
mr={2}
|
||
flexShrink={0}
|
||
>
|
||
立即重试
|
||
</Button>
|
||
)}
|
||
|
||
{/* 关闭按钮(所有非正常状态都显示) */}
|
||
{status !== CONNECTION_STATUS.CONNECTED && onClose && (
|
||
<CloseButton
|
||
onClick={onClose}
|
||
size="sm"
|
||
flexShrink={0}
|
||
/>
|
||
)}
|
||
</Alert>
|
||
</Slide>
|
||
);
|
||
};
|
||
|
||
export default ConnectionStatusBar;
|