feat(NavCommon): 重构导航组件并优化样式结构

- 新增图标组件并替换原有emoji图标
- 重构导航菜单数据结构并移除无用代码
- 实现菜单项激活状态高亮效果
- 完善用户退出登录功能
- 优化样式文件结构并添加详细注释
- 更新构建产物文件版本
This commit is contained in:
超级老白兔
2025-09-12 17:49:23 +08:00
parent d3ee0bde5a
commit f2fb543f93
6 changed files with 453 additions and 377 deletions

View File

@@ -1,8 +1,9 @@
import { BarChartOutlined, RobotOutlined } from "@ant-design/icons";
// 菜单项接口
export interface MenuItem {
id: string;
title: string;
icon: string;
icon: React.ReactNode;
path?: string;
}
@@ -10,22 +11,16 @@ export interface MenuItem {
export const menuList: MenuItem[] = [
{
id: "wechat",
title: "微信管理",
icon: "💬",
title: "AI智能客服",
icon: <RobotOutlined className="menuIcon" style={{ fontSize: 20 }} />,
path: "/pc/weChat",
},
{
id: "powerCenter",
title: "功能中心",
icon: "📊",
icon: <BarChartOutlined className="menuIcon" style={{ fontSize: 20 }} />,
path: "/pc/powerCenter",
},
{
id: "dashboard",
title: "数据面板",
icon: "📊",
path: "/pc/dashboard",
},
];
// 抽屉菜单配置数据

View File

@@ -1,3 +1,32 @@
/**
* NavCommon 组件样式文件
*
* 文件结构说明:
* 1. Header 区域样式 - 顶部导航栏相关样式
* - headerLeft: 左侧菜单按钮和标题
* - headerRight: 右侧用户信息、算力显示、消息按钮等
*
* 2. Drawer 抽屉区域样式 - 左侧菜单抽屉相关样式
* - drawerContent: 抽屉内容容器
* - drawerHeader: 抽屉头部Logo区域
* - drawerBody: 抽屉主体(主要按钮和菜单项)
* - drawerFooter: 抽屉底部(余额显示)
*
* 3. 消息抽屉区域样式 - 右侧消息中心抽屉相关样式
* - messageContent: 消息列表容器
* - messageItem: 单个消息项样式
*
* 4. 兼容样式 - 保持向后兼容的独立样式类
*
* 5. 响应式设计 - 移动端适配样式
*
* 样式组织原则:
* - 按照 tsx 文件中的嵌套结构组织样式
* - 使用 SCSS 嵌套语法体现 DOM 层级关系
* - 相关样式就近放置,便于维护
*/
// ===== Header 区域样式 =====
.header {
background: #fff;
padding: 0 16px;
@@ -7,212 +36,129 @@
justify-content: space-between;
height: 64px;
border-bottom: 1px solid #f0f0f0;
}
.headerLeft {
display: flex;
align-items: center;
gap: 12px;
}
.menuButton {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 6px;
transition: all 0.3s;
&:hover {
background-color: #f5f5f5;
}
.anticon {
font-size: 18px;
color: #666;
}
}
.title {
font-size: 18px;
color: #333;
margin: 0;
}
.headerRight {
display: flex;
align-items: center;
gap: 16px;
padding-right: 10px;
}
.userInfo {
display: flex;
align-items: center;
gap: 16px;
padding: 8px 0;
.suanli {
// Header 左侧区域
.headerLeft {
display: flex;
align-items: center;
gap: 4px;
font-size: 16px;
color: #666;
font-weight: 500;
cursor: pointer;
gap: 12px;
.suanliIcon {
font-size: 20px;
color: #ffc107;
}
&:hover {
color: #52c41a;
.menuButton {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 6px;
transition: all 0.3s;
&:hover {
background-color: #f5f5f5;
}
.anticon {
font-size: 18px;
color: #666;
}
}
.title {
font-size: 18px;
color: #333;
margin: 0;
}
}
// Header 右侧区域
.headerRight {
display: flex;
align-items: center;
gap: 16px;
padding-right: 10px;
.userInfo {
display: flex;
align-items: center;
gap: 16px;
padding: 8px 0;
.suanli {
display: flex;
align-items: center;
gap: 4px;
font-size: 16px;
color: #666;
font-weight: 500;
cursor: pointer;
.suanliIcon {
font-size: 20px;
color: #ffc107;
}
&:hover {
color: #52c41a;
transition: all 0.3s;
}
}
.avatar {
border: 2px solid #e9ecef;
transition: all 0.3s;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
}
.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;
}
}
}
// 兼容旧样式(避免破坏性更改)
.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 #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 {
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;
}
}
.username {
font-size: 14px;
color: #333;
@@ -220,7 +166,8 @@
margin-left: 8px;
}
// 抽屉样式
// ===== Drawer 抽屉区域样式 =====
// 左侧菜单抽屉
.drawer {
:global(.ant-drawer-header) {
background: #fafafa;
@@ -230,141 +177,259 @@
:global(.ant-drawer-body) {
padding: 0;
}
}
.drawerContent {
height: 100%;
display: flex;
flex-direction: column;
background: #f8f9fa;
}
.drawerHeader {
padding: 20px;
background: #fff;
border-bottom: none;
}
.logoSection {
display: flex;
align-items: center;
gap: 12px;
}
.logoIcon {
width: 48px;
height: 48px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: white;
}
.logoText {
display: flex;
flex-direction: column;
}
.appName {
font-size: 18px;
font-weight: 600;
color: #333;
margin: 0;
}
.appDesc {
font-size: 12px;
color: #999;
margin: 2px 0 0 0;
}
.drawerBody {
flex: 1;
display: flex;
flex-direction: column;
gap: 16px;
}
.primaryButton {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
padding: 16px 20px;
display: flex;
align-items: center;
gap: 12px;
cursor: pointer;
transition: all 0.3s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
}
.buttonIcon {
font-size: 20px;
}
span {
font-size: 16px;
font-weight: 600;
color: white;
}
}
.menuSection {
margin-top: 8px;
}
.menuItem {
display: flex;
align-items: center;
padding: 16px 20px;
cursor: pointer;
transition: all 0.3s;
border-radius: 8px;
&:hover {
background-color: #f0f0f0;
}
span {
font-size: 16px;
color: #333;
font-weight: 500;
}
}
.menuIcon {
font-size: 20px;
margin-right: 12px;
width: 20px;
text-align: center;
}
.drawerFooter {
padding: 20px;
background: #fff;
border-top: 1px solid #f0f0f0;
.balanceSection {
// 抽屉内容容器
.drawerContent {
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.balanceIcon {
color: #666;
.suanliIcon {
font-size: 20px;
flex-direction: column;
background: #f8f9fa;
// 抽屉头部
.drawerHeader {
padding: 20px;
background: #fff;
border-bottom: none;
.logoSection {
display: flex;
align-items: center;
gap: 12px;
.logoIcon {
width: 48px;
height: 48px;
background: linear-gradient(135deg, #3b81f6 0%, #9035ea 100%);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: white;
}
.logoText {
display: flex;
flex-direction: column;
.appName {
font-size: 18px;
font-weight: 600;
color: #333;
margin: 0;
}
.appDesc {
font-size: 12px;
color: #999;
margin: 2px 0 0 0;
}
}
}
}
.balanceText {
color: #3d9c0d;
// 抽屉主体内容
.drawerBody {
flex: 1;
display: flex;
flex-direction: column;
gap: 16px;
.primaryButton {
background: linear-gradient(135deg, #3d80f6 0%, #764ba2 100%);
border-radius: 12px;
padding: 16px 20px;
display: flex;
align-items: center;
gap: 12px;
cursor: pointer;
transition: all 0.3s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
}
.buttonIcon {
font-size: 20px;
}
span {
font-size: 16px;
font-weight: 600;
color: white;
}
}
// 菜单区域
.menuSection {
padding: 0px 20px;
.menuItem {
display: flex;
align-items: center;
padding: 8px 20px;
cursor: pointer;
transition: all 0.3s;
border-radius: 8px;
margin: 4px 0;
&:hover {
background-color: #f0f0f0;
}
.menuIcon {
font-size: 20px;
margin-right: 12px;
width: 20px;
text-align: center;
}
span {
font-size: 16px;
color: #333;
font-weight: 500;
}
&.menuItemActive {
background: linear-gradient(to right, #3b82f6, #9333ea);
color: white;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
span {
color: white;
font-weight: 600;
}
.menuIcon {
color: white;
}
&:hover {
background: linear-gradient(to right, #3b82f6, #9333ea);
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
}
}
}
}
}
// 抽屉底部
.drawerFooter {
padding: 20px;
background: #fff;
border-top: 1px solid #f0f0f0;
.balanceSection {
display: flex;
justify-content: space-between;
align-items: center;
.balanceIcon {
color: #666;
.suanliIcon {
font-size: 20px;
}
}
.balanceText {
color: #3d9c0d;
}
}
}
}
}
// ===== 消息抽屉区域样式 =====
.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 {
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;
}
}
}
}
}
}
// ===== 兼容样式 =====
.balanceLabel {
font-size: 12px;
color: #999;
@@ -378,18 +443,24 @@
margin: 2px 0 0 0;
}
// 响应式设计
// ===== 响应式设计 =====
@media (max-width: 768px) {
.header {
padding: 0 12px;
}
.title {
font-size: 16px;
}
.headerLeft {
.title {
font-size: 16px;
}
}
.username {
display: none;
.headerRight {
.userInfo {
.username {
display: none;
}
}
}
}
.drawer {

View File

@@ -7,9 +7,10 @@ import {
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";
// import { useCkChatStore } from "@/store/module/ckchat/ckchat";
import { useNavigate, useLocation } from "react-router-dom";
import { drawerMenuData, menuList } from "./index.data";
import styles from "./index.module.scss";
@@ -28,9 +29,9 @@ const NavCommon: React.FC<NavCommonProps> = ({
const [messageDrawerVisible, setMessageDrawerVisible] = useState(false);
const [messageCount] = useState(3); // 模拟消息数量
const navigate = useNavigate();
const { userInfo } = useCkChatStore();
const { user } = useUserStore();
console.log(user);
const location = useLocation();
// const { userInfo } = useCkChatStore();
const { user, logout } = useUserStore();
// 处理菜单图标点击
const handleMenuClick = () => {
@@ -55,8 +56,8 @@ const NavCommon: React.FC<NavCommonProps> = ({
// 处理退出登录
const handleLogout = () => {
console.log("退出登录");
// TODO: 实现退出登录逻辑
logout(); // 清除localStorage中的token和用户状态
navigate("/login"); // 跳转到登录页面
};
// 用户菜单项
@@ -106,21 +107,24 @@ const NavCommon: React.FC<NavCommonProps> = ({
</div>
<div className={styles.drawerBody}>
<div className={styles.menuSection}>
{menuList.map((item, index) => (
<div
key={index}
className={styles.menuItem}
onClick={() => {
if (item.path) {
navigate(item.path);
setDrawerVisible(false);
}
}}
>
<div className={styles.menuIcon}>{item.icon}</div>
<span>{item.title}</span>
</div>
))}
{menuList.map((item, index) => {
const isActive = location.pathname === item.path;
return (
<div
key={index}
className={`${styles.menuItem} ${isActive ? styles.menuItemActive : ""}`}
onClick={() => {
if (item.path) {
navigate(item.path);
setDrawerVisible(false);
}
}}
>
<div className={styles.menuIcon}>{item.icon}</div>
<span>{item.title}</span>
</div>
);
})}
</div>
</div>
<div className={styles.drawerFooter}>
@@ -185,7 +189,6 @@ const NavCommon: React.FC<NavCommonProps> = ({
</Header>
<Drawer
title="菜单"
placement="left"
onClose={handleDrawerClose}
open={drawerVisible}