feat(NavCommon): 重构导航栏样式并添加消息中心和用户菜单功能
- 重新设计用户信息区域样式,增加间距和悬停效果 - 添加消息中心抽屉组件,包含消息列表和操作按钮 - 实现用户下拉菜单,包含个人资料和退出登录选项 - 统一PC端和移动端的导航栏样式
This commit is contained in:
@@ -43,33 +43,91 @@
|
||||
.headerRight {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.userInfo {
|
||||
cursor: pointer;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 8px 0;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.suanli {
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
padding: 6px 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 20px;
|
||||
border: 1px solid #e9ecef;
|
||||
|
||||
.suanliIcon {
|
||||
font-size: 24px;
|
||||
font-size: 16px;
|
||||
color: #ffc107;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border: 2px solid #f0f0f0;
|
||||
.messageButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 50%;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid #e9ecef;
|
||||
background: #fff;
|
||||
|
||||
&:hover {
|
||||
background-color: #f8f9fa;
|
||||
border-color: #1890ff;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
|
||||
}
|
||||
|
||||
.anticon {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.userSection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
padding: 8px 16px;
|
||||
border-radius: 24px;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid #e9ecef;
|
||||
background: #fff;
|
||||
|
||||
&:hover {
|
||||
background-color: #f8f9fa;
|
||||
border-color: #1890ff;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.userNickname {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
max-width: 100px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border: 2px solid #e9ecef;
|
||||
transition: all 0.3s;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.username {
|
||||
|
||||
@@ -43,32 +43,173 @@
|
||||
.headerRight {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.userInfo {
|
||||
cursor: pointer;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 8px 0;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.suanli {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
|
||||
.suanliIcon {
|
||||
font-size: 24px;
|
||||
font-size: 20px;
|
||||
color: #ffc107;
|
||||
}
|
||||
&:hover {
|
||||
color: #52c41a;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
}
|
||||
}
|
||||
.bell {
|
||||
cursor: pointer;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.messageButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 80px;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid #e9ecef;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: #f8f9fa;
|
||||
border-color: #1890ff;
|
||||
box-shadow: 0 0px 12px rgba(24, 144, 255, 0.15);
|
||||
}
|
||||
|
||||
.anticon {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.userSection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
.userNickname {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
max-width: 100px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border: 2px solid #f0f0f0;
|
||||
border: 2px solid #e9ecef;
|
||||
transition: all 0.3s;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
// 消息抽屉样式
|
||||
.messageDrawer {
|
||||
:global(.ant-drawer-header) {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
:global(.ant-drawer-body) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.messageContent {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.messageItem {
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
border-color: #1890ff;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.messageAvatar {
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.messageInfo {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.messageTitle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.messageType {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
.messageStatus {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background-color: #1890ff;
|
||||
}
|
||||
|
||||
.messageText {
|
||||
font-size: 13px;
|
||||
color: #595959;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 8px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.messageTime {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
|
||||
.messageActions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
|
||||
:global(.ant-btn) {
|
||||
height: 24px;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import React, { useState } from "react";
|
||||
import { Layout, Drawer, Avatar, Space, Button } from "antd";
|
||||
import { MenuOutlined, UserOutlined } from "@ant-design/icons";
|
||||
import { Layout, Drawer, Avatar, Space, Button, Badge, Dropdown } from "antd";
|
||||
import {
|
||||
MenuOutlined,
|
||||
UserOutlined,
|
||||
BellOutlined,
|
||||
UserSwitchOutlined,
|
||||
LogoutOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useUserStore } from "@/store/module/user";
|
||||
import { useCkChatStore } from "@/store/module/ckchat/ckchat";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
@@ -19,9 +25,12 @@ const NavCommon: React.FC<NavCommonProps> = ({
|
||||
onMenuClick,
|
||||
}) => {
|
||||
const [drawerVisible, setDrawerVisible] = useState(false);
|
||||
const [messageDrawerVisible, setMessageDrawerVisible] = useState(false);
|
||||
const [messageCount] = useState(3); // 模拟消息数量
|
||||
const navigate = useNavigate();
|
||||
const { userInfo } = useCkChatStore();
|
||||
const { user } = useUserStore();
|
||||
console.log(user);
|
||||
|
||||
// 处理菜单图标点击
|
||||
const handleMenuClick = () => {
|
||||
@@ -34,6 +43,49 @@ const NavCommon: React.FC<NavCommonProps> = ({
|
||||
setDrawerVisible(false);
|
||||
};
|
||||
|
||||
// 处理消息中心点击
|
||||
const handleMessageClick = () => {
|
||||
setMessageDrawerVisible(true);
|
||||
};
|
||||
|
||||
// 处理消息抽屉关闭
|
||||
const handleMessageDrawerClose = () => {
|
||||
setMessageDrawerVisible(false);
|
||||
};
|
||||
|
||||
// 处理退出登录
|
||||
const handleLogout = () => {
|
||||
console.log("退出登录");
|
||||
// TODO: 实现退出登录逻辑
|
||||
};
|
||||
|
||||
// 用户菜单项
|
||||
const userMenuItems = [
|
||||
{
|
||||
key: "userInfo",
|
||||
label: (
|
||||
<div style={{ fontWeight: "bold", color: "#188eee" }}>
|
||||
{user.username}({user.account})
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "profile",
|
||||
icon: <UserSwitchOutlined style={{ fontSize: 16 }} />,
|
||||
label: "个人资料",
|
||||
onClick: () => {
|
||||
console.log("个人资料点击");
|
||||
// TODO: 跳转到个人资料页面
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "logout",
|
||||
icon: <LogoutOutlined style={{ fontSize: 14 }} />,
|
||||
label: "退出登录",
|
||||
onClick: handleLogout,
|
||||
},
|
||||
];
|
||||
|
||||
// 默认抽屉内容
|
||||
const defaultDrawerContent = (
|
||||
<div className={styles.drawerContent}>
|
||||
@@ -106,12 +158,28 @@ const NavCommon: React.FC<NavCommonProps> = ({
|
||||
<span className={styles.suanliIcon}>⚡</span>
|
||||
9307.423
|
||||
</span>
|
||||
<Avatar
|
||||
size={40}
|
||||
icon={<UserOutlined />}
|
||||
src={user?.avatar}
|
||||
className={styles.avatar}
|
||||
/>
|
||||
<Dropdown
|
||||
menu={{ items: userMenuItems }}
|
||||
placement="bottomRight"
|
||||
trigger={["click"]}
|
||||
>
|
||||
<div className={styles.userSection}>
|
||||
<Avatar
|
||||
size={40}
|
||||
icon={<UserOutlined />}
|
||||
src={user?.avatar}
|
||||
className={styles.avatar}
|
||||
/>
|
||||
</div>
|
||||
</Dropdown>
|
||||
<Badge count={messageCount} size="small">
|
||||
<div
|
||||
className={styles.messageButton}
|
||||
onClick={handleMessageClick}
|
||||
>
|
||||
<BellOutlined style={{ fontSize: 18 }} />
|
||||
</div>
|
||||
</Badge>
|
||||
</Space>
|
||||
</div>
|
||||
</Header>
|
||||
@@ -126,6 +194,86 @@ const NavCommon: React.FC<NavCommonProps> = ({
|
||||
>
|
||||
{defaultDrawerContent}
|
||||
</Drawer>
|
||||
|
||||
<Drawer
|
||||
title="通知中心"
|
||||
placement="right"
|
||||
onClose={handleMessageDrawerClose}
|
||||
open={messageDrawerVisible}
|
||||
width={400}
|
||||
className={styles.messageDrawer}
|
||||
extra={
|
||||
<Space>
|
||||
<Button type="text" size="small">
|
||||
全部已读
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<div className={styles.messageContent}>
|
||||
<div className={styles.messageItem}>
|
||||
<div className={styles.messageAvatar}>
|
||||
<Avatar size={40} style={{ backgroundColor: "#87d068" }}>
|
||||
林
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className={styles.messageInfo}>
|
||||
<div className={styles.messageTitle}>
|
||||
<span className={styles.messageType}>新消息</span>
|
||||
<div className={styles.messageStatus}></div>
|
||||
</div>
|
||||
<div className={styles.messageText}>
|
||||
林秀杰:关于自由主时间特惠,原价1999元,现在只需1699元
|
||||
</div>
|
||||
<div className={styles.messageTime}>
|
||||
03-05
|
||||
<Button type="link" size="small">
|
||||
回复
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.messageItem}>
|
||||
<div className={styles.messageAvatar}>
|
||||
<Avatar size={40} style={{ backgroundColor: "#f56a00" }}>
|
||||
E
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className={styles.messageInfo}>
|
||||
<div className={styles.messageTitle}>
|
||||
<span className={styles.messageType}>群提醒</span>
|
||||
<div className={styles.messageStatus}></div>
|
||||
</div>
|
||||
<div className={styles.messageText}>
|
||||
Eric在「云归营私域银行项目群」中@了您
|
||||
</div>
|
||||
<div className={styles.messageTime}>03-05</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.messageItem}>
|
||||
<div className={styles.messageAvatar}>
|
||||
<Avatar size={40} style={{ backgroundColor: "#1890ff" }}>
|
||||
李
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className={styles.messageInfo}>
|
||||
<div className={styles.messageTitle}>
|
||||
<span className={styles.messageType}>好友申请</span>
|
||||
</div>
|
||||
<div className={styles.messageText}>李翔想请求添加您为好友</div>
|
||||
<div className={styles.messageTime}>03-04</div>
|
||||
<div className={styles.messageActions}>
|
||||
<Button type="primary" size="small">
|
||||
接受
|
||||
</Button>
|
||||
<Button size="small">拒绝</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user