FEAT => 本次更新项目为:

This commit is contained in:
2025-08-22 17:55:04 +08:00
parent 465c63ed1c
commit 83ae92b2b6
6 changed files with 222 additions and 141 deletions

View File

@@ -0,0 +1,48 @@
import React from "react";
import { SpinLoading } from "antd-mobile";
import styles from "./layout.module.scss";
interface LayoutProps {
loading?: boolean;
children?: React.ReactNode;
header?: React.ReactNode;
footer?: React.ReactNode;
}
const LayoutFiexd: React.FC<LayoutProps> = ({
header,
children,
footer,
loading = false,
}) => {
return (
<div
style={{
height: "100%",
display: "flex",
flexDirection: "column",
}}
>
<div className="header">{header}</div>
<div
className="content"
style={{
flex: 1,
overflow: "auto",
}}
>
{loading ? (
<div className={styles.loadingContainer}>
<SpinLoading color="primary" style={{ fontSize: 32 }} />
<div className={styles.loadingText}>...</div>
</div>
) : (
children
)}
</div>
<div className="footer">{footer}</div>
</div>
);
};
export default LayoutFiexd;

View File

@@ -1,63 +1,61 @@
.sidebar {
.headerContainer {
background: #fff;
border-right: 1px solid #f0f0f0;
display: flex;
flex-direction: column;
border-bottom: 1px solid #f0f0f0;
}
.searchBar {
padding: 16px;
border-bottom: 1px solid #f0f0f0;
background: #fff;
.searchBar {
padding: 16px 16px 8px;
background: #fff;
:global(.ant-input) {
border-radius: 20px;
background: #f5f5f5;
border: none;
:global(.ant-input) {
border-radius: 20px;
background: #f5f5f5;
border: none;
&:focus {
background: #fff;
border: 1px solid #1890ff;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
}
}
.tabs {
flex: 1;
display: flex;
flex-direction: column;
:global(.ant-tabs-content) {
flex: 1;
overflow: hidden;
}
:global(.ant-tabs-tabpane) {
height: 100%;
overflow: hidden;
}
:global(.ant-tabs-nav) {
margin: 0;
padding: 0 16px;
&:focus {
background: #fff;
border-bottom: 1px solid #f0f0f0;
:global(.ant-tabs-tab) {
padding: 12px 0;
margin: 0 16px 0 0;
}
border: 1px solid #1890ff;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
}
.emptyState {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
color: #999;
padding: 20px;
text-align: center;
}
}
.tabsContainer {
display: flex;
padding: 0 16px 8px;
border-bottom: 1px solid #f0f0f0;
.tabItem {
display: flex;
align-items: center;
padding: 8px 12px;
cursor: pointer;
border-radius: 4px;
transition: all 0.3s;
&:hover {
color: #1890ff;
background-color: rgba(24, 144, 255, 0.1);
}
&.active {
color: #1890ff;
background-color: rgba(24, 144, 255, 0.1);
}
span {
margin-left: 4px;
}
}
}
.emptyState {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
color: #999;
padding: 20px;
text-align: center;
}

View File

@@ -1,5 +1,5 @@
import React, { useState } from "react";
import { Layout, Input, Tabs } from "antd";
import { Layout as AntLayout, Input, Tabs } from "antd";
import {
SearchOutlined,
UserOutlined,
@@ -9,9 +9,10 @@ import {
import { ContactData } from "./data";
import WechatFriendsModule from "./WechatFriendsModule";
import MessageList from "../MessageList/index";
import LayoutFiexd from "@/components/Layout/LayoutFiexd";
import styles from "./SidebarMenu.module.scss";
const { Sider } = Layout;
const { Sider } = AntLayout;
const { TabPane } = Tabs;
interface SidebarMenuProps {
@@ -54,8 +55,9 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
);
};
return (
<Sider width={300} className={styles.sidebar}>
// 渲染Header部分包含搜索框和标签页切换
const renderHeader = () => (
<div className={styles.headerContainer}>
{/* 搜索栏 */}
<div className={styles.searchBar}>
<Input
@@ -67,58 +69,68 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
/>
</div>
{/* 标签页 */}
<Tabs
activeKey={activeTab}
onChange={setActiveTab}
className={styles.tabs}
>
<TabPane
tab={
<span>
<MessageOutlined />
</span>
}
key="chats"
{/* 标签页切换 */}
<div className={styles.tabsContainer}>
<div
className={`${styles.tabItem} ${activeTab === "chats" ? styles.active : ""}`}
onClick={() => setActiveTab("chats")}
>
<MessageOutlined />
<span></span>
</div>
<div
className={`${styles.tabItem} ${activeTab === "contacts" ? styles.active : ""}`}
onClick={() => setActiveTab("contacts")}
>
<UserOutlined />
<span></span>
</div>
<div
className={`${styles.tabItem} ${activeTab === "groups" ? styles.active : ""}`}
onClick={() => setActiveTab("groups")}
>
<TeamOutlined />
<span></span>
</div>
</div>
</div>
);
// 渲染内容部分
const renderContent = () => {
switch (activeTab) {
case "chats":
return (
<MessageList
chatSessions={getFilteredSessions()}
onChatSelect={onChatSelect}
currentChat={currentChat}
/>
</TabPane>
<TabPane
tab={
<span>
<UserOutlined />
</span>
}
key="contacts"
>
);
case "contacts":
return (
<WechatFriendsModule
contacts={getFilteredContacts()}
onContactClick={onContactClick}
selectedContactId={currentChat}
/>
</TabPane>
<TabPane
tab={
<span>
<TeamOutlined />
</span>
}
key="groups"
>
);
case "groups":
return (
<div className={styles.emptyState}>
<TeamOutlined style={{ fontSize: 48, color: "#ccc" }} />
<p></p>
</div>
</TabPane>
</Tabs>
</Sider>
);
default:
return null;
}
};
return (
<LayoutFiexd header={renderHeader()} footer="底部">
{renderContent()}
</LayoutFiexd>
);
};

View File

@@ -1,10 +1,27 @@
.ckboxLayout {
height: 100vh;
background: #fff;
display: flex;
flex-direction: column;
.sidebar {
.header {
background: #1890ff;
color: #fff;
height: 64px;
line-height: 64px;
padding: 0 24px;
font-size: 18px;
font-weight: bold;
}
.sider {
background: #fff;
border-right: 1px solid #f0f0f0;
overflow: auto;
}
.sidebar {
height: 100%;
display: flex;
flex-direction: column;
@@ -87,6 +104,8 @@
background: #f5f5f5;
display: flex;
flex-direction: column;
padding: 16px;
overflow: auto;
.chatContainer {
height: 100%;

View File

@@ -7,7 +7,7 @@ import ChatWindow from "./components/ChatWindow/index";
import SidebarMenu from "./components/SidebarMenu/index";
import styles from "./index.module.scss";
const { Content } = Layout;
const { Header, Content, Sider } = Layout;
import { loginWithToken, clearUnreadCount, getMessages } from "./api";
import { useUserStore } from "@/store/module/user";
import { chatInitAPIdata } from "./main";
@@ -85,53 +85,57 @@ const CkboxPage: React.FC = () => {
return (
<Layout className={styles.ckboxLayout}>
{/* <Button onClick={getChatInfo}>点击</Button> */}
{contextHolder}
{/* 左侧边栏 */}
<SidebarMenu
contacts={contacts}
chatSessions={chatSessions}
currentChat={currentChat}
onContactClick={handleContactClick}
onChatSelect={setCurrentChat}
loading={loading}
/>
<Header className={styles.header}></Header>
<Layout>
{/* 左侧边栏 */}
<Sider width={280} className={styles.sider}>
<SidebarMenu
contacts={contacts}
chatSessions={chatSessions}
currentChat={currentChat}
onContactClick={handleContactClick}
onChatSelect={setCurrentChat}
loading={loading}
/>
</Sider>
{/* 主内容区 */}
<Content className={styles.mainContent}>
{currentChat ? (
<div className={styles.chatContainer}>
<div className={styles.chatToolbar}>
<Space>
<Tooltip title={showProfile ? "隐藏资料" : "显示资料"}>
<Button
type={showProfile ? "primary" : "default"}
icon={<InfoCircleOutlined />}
onClick={() => setShowProfile(!showProfile)}
size="small"
>
{showProfile ? "隐藏资料" : "显示资料"}
</Button>
</Tooltip>
</Space>
{/* 主内容区 */}
<Content className={styles.mainContent}>
{currentChat ? (
<div className={styles.chatContainer}>
<div className={styles.chatToolbar}>
<Space>
<Tooltip title={showProfile ? "隐藏资料" : "显示资料"}>
<Button
type={showProfile ? "primary" : "default"}
icon={<InfoCircleOutlined />}
onClick={() => setShowProfile(!showProfile)}
size="small"
>
{showProfile ? "隐藏资料" : "显示资料"}
</Button>
</Tooltip>
</Space>
</div>
<ChatWindow
chat={currentChat}
onSendMessage={handleSendMessage}
showProfile={showProfile}
onToggleProfile={() => setShowProfile(!showProfile)}
/>
</div>
<ChatWindow
chat={currentChat}
onSendMessage={handleSendMessage}
showProfile={showProfile}
onToggleProfile={() => setShowProfile(!showProfile)}
/>
</div>
) : (
<div className={styles.welcomeScreen}>
<div className={styles.welcomeContent}>
<MessageOutlined style={{ fontSize: 64, color: "#1890ff" }} />
<h2>使</h2>
<p></p>
) : (
<div className={styles.welcomeScreen}>
<div className={styles.welcomeContent}>
<MessageOutlined style={{ fontSize: 64, color: "#1890ff" }} />
<h2>使</h2>
<p></p>
</div>
</div>
</div>
)}
</Content>
)}
</Content>
</Layout>
</Layout>
);
};