fix(Navbar): 优化用户头像悬停交互和订阅信息显示

- 将 Tooltip 改为 Popover 组件,支持鼠标悬停到弹出内容上
- 用户现在可以正常悬停到"点击头像管理订阅"提示
- 订阅信息新增到期日期显示,用户无需自己计算到期时间

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-15 16:23:29 +08:00
parent cbef50c3e5
commit f304268af9
3 changed files with 62 additions and 30 deletions

View File

@@ -2,7 +2,13 @@
// 桌面版用户菜单 - 头像点击跳转到订阅页面 // 桌面版用户菜单 - 头像点击跳转到订阅页面
import React, { memo } from 'react'; import React, { memo } from 'react';
import { Tooltip, useColorModeValue } from '@chakra-ui/react'; import {
Popover,
PopoverTrigger,
PopoverContent,
PopoverArrow,
useColorModeValue
} from '@chakra-ui/react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import UserAvatar from './UserAvatar'; import UserAvatar from './UserAvatar';
import { TooltipContent } from '../../../Subscription/CrownTooltip'; import { TooltipContent } from '../../../Subscription/CrownTooltip';
@@ -19,25 +25,22 @@ const DesktopUserMenu = memo(({ user }) => {
const navigate = useNavigate(); const navigate = useNavigate();
const { subscriptionInfo } = useSubscription(); const { subscriptionInfo } = useSubscription();
const tooltipBg = useColorModeValue('white', 'gray.800'); const popoverBg = useColorModeValue('white', 'gray.800');
const tooltipBorderColor = useColorModeValue('gray.200', 'gray.600'); const popoverBorderColor = useColorModeValue('gray.200', 'gray.600');
const handleAvatarClick = () => { const handleAvatarClick = () => {
navigate('/home/pages/account/subscription'); navigate('/home/pages/account/subscription');
}; };
return ( return (
<Tooltip <Popover
label={<TooltipContent subscriptionInfo={subscriptionInfo} />} trigger="hover"
placement="bottom" placement="bottom-end"
hasArrow openDelay={100}
bg={tooltipBg} closeDelay={200}
borderRadius="lg" gutter={8}
border="1px solid"
borderColor={tooltipBorderColor}
boxShadow="lg"
p={3}
> >
<PopoverTrigger>
<span> <span>
<UserAvatar <UserAvatar
user={user} user={user}
@@ -45,7 +48,21 @@ const DesktopUserMenu = memo(({ user }) => {
onClick={handleAvatarClick} onClick={handleAvatarClick}
/> />
</span> </span>
</Tooltip> </PopoverTrigger>
<PopoverContent
bg={popoverBg}
borderRadius="lg"
border="1px solid"
borderColor={popoverBorderColor}
boxShadow="lg"
p={3}
w="auto"
_focus={{ outline: 'none' }}
>
<PopoverArrow bg={popoverBg} />
<TooltipContent subscriptionInfo={subscriptionInfo} />
</PopoverContent>
</Popover>
); );
}); });

View File

@@ -17,7 +17,23 @@ import PropTypes from 'prop-types';
export const TooltipContent = ({ subscriptionInfo }) => { export const TooltipContent = ({ subscriptionInfo }) => {
const tooltipText = useColorModeValue('gray.700', 'gray.100'); const tooltipText = useColorModeValue('gray.700', 'gray.100');
const dividerColor = useColorModeValue('gray.200', 'gray.600'); const dividerColor = useColorModeValue('gray.200', 'gray.600');
const { type, days_left, is_active } = subscriptionInfo; const { type, days_left, is_active, end_date } = subscriptionInfo;
// 格式化到期日期
const formatEndDate = (dateStr) => {
if (!dateStr) return null;
try {
const date = new Date(dateStr);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
} catch {
return null;
}
};
const formattedEndDate = formatEndDate(end_date);
// 基础版用户 // 基础版用户
if (type === 'free') { if (type === 'free') {
@@ -72,7 +88,12 @@ export const TooltipContent = ({ subscriptionInfo }) => {
还有 <Text as="span" fontWeight="600" color={isUrgent ? 'red.500' : isWarning ? 'orange.500' : tooltipText}>{days_left}</Text> 还有 <Text as="span" fontWeight="600" color={isUrgent ? 'red.500' : isWarning ? 'orange.500' : tooltipText}>{days_left}</Text>
</Text> </Text>
</HStack> </HStack>
<Text fontSize="xs" color={tooltipText} opacity={0.7} pl={6}> {formattedEndDate && (
<Text fontSize="xs" color={tooltipText} opacity={0.8} pl={6}>
到期日<Text as="span" fontWeight="500">{formattedEndDate}</Text>
</Text>
)}
<Text fontSize="xs" color={tooltipText} opacity={0.6} pl={6}>
享受全部高级功能 享受全部高级功能
</Text> </Text>
</VStack> </VStack>
@@ -133,5 +154,6 @@ TooltipContent.propTypes = {
type: PropTypes.oneOf(['free', 'pro', 'max']).isRequired, type: PropTypes.oneOf(['free', 'pro', 'max']).isRequired,
days_left: PropTypes.number, days_left: PropTypes.number,
is_active: PropTypes.bool, is_active: PropTypes.bool,
end_date: PropTypes.string,
}).isRequired, }).isRequired,
}; };

View File

@@ -620,13 +620,6 @@ export default function ProfilePage() {
{user?.last_seen ? new Date(user.last_seen).toLocaleDateString() : '未知'} {user?.last_seen ? new Date(user.last_seen).toLocaleDateString() : '未知'}
</Text> </Text>
</HStack> </HStack>
<HStack justify="space-between" w="full">
<Text fontSize="sm" color="gray.600">账户状态</Text>
<Badge colorScheme={user?.status === 'active' ? 'green' : 'gray'}>
{user?.status === 'active' ? '正常' : '未激活'}
</Badge>
</HStack>
</VStack> </VStack>
</CardBody> </CardBody>
</Card> </Card>