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; background: #fff;
border-right: 1px solid #f0f0f0; border-bottom: 1px solid #f0f0f0;
display: flex; }
flex-direction: column;
.searchBar { .searchBar {
padding: 16px; padding: 16px 16px 8px;
border-bottom: 1px solid #f0f0f0; background: #fff;
background: #fff;
:global(.ant-input) { :global(.ant-input) {
border-radius: 20px; border-radius: 20px;
background: #f5f5f5; background: #f5f5f5;
border: none; border: none;
&:focus { &: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;
background: #fff; background: #fff;
border-bottom: 1px solid #f0f0f0; border: 1px solid #1890ff;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
:global(.ant-tabs-tab) {
padding: 12px 0;
margin: 0 16px 0 0;
}
} }
} }
}
.emptyState {
display: flex; .tabsContainer {
flex-direction: column; display: flex;
align-items: center; padding: 0 16px 8px;
justify-content: center; border-bottom: 1px solid #f0f0f0;
height: 100%;
color: #999; .tabItem {
padding: 20px; display: flex;
text-align: center; 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 React, { useState } from "react";
import { Layout, Input, Tabs } from "antd"; import { Layout as AntLayout, Input, Tabs } from "antd";
import { import {
SearchOutlined, SearchOutlined,
UserOutlined, UserOutlined,
@@ -9,9 +9,10 @@ import {
import { ContactData } from "./data"; import { ContactData } from "./data";
import WechatFriendsModule from "./WechatFriendsModule"; import WechatFriendsModule from "./WechatFriendsModule";
import MessageList from "../MessageList/index"; import MessageList from "../MessageList/index";
import LayoutFiexd from "@/components/Layout/LayoutFiexd";
import styles from "./SidebarMenu.module.scss"; import styles from "./SidebarMenu.module.scss";
const { Sider } = Layout; const { Sider } = AntLayout;
const { TabPane } = Tabs; const { TabPane } = Tabs;
interface SidebarMenuProps { interface SidebarMenuProps {
@@ -54,8 +55,9 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
); );
}; };
return ( // 渲染Header部分包含搜索框和标签页切换
<Sider width={300} className={styles.sidebar}> const renderHeader = () => (
<div className={styles.headerContainer}>
{/* 搜索栏 */} {/* 搜索栏 */}
<div className={styles.searchBar}> <div className={styles.searchBar}>
<Input <Input
@@ -67,58 +69,68 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
/> />
</div> </div>
{/* 标签页 */} {/* 标签页切换 */}
<Tabs <div className={styles.tabsContainer}>
activeKey={activeTab} <div
onChange={setActiveTab} className={`${styles.tabItem} ${activeTab === "chats" ? styles.active : ""}`}
className={styles.tabs} onClick={() => setActiveTab("chats")}
>
<TabPane
tab={
<span>
<MessageOutlined />
</span>
}
key="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 <MessageList
chatSessions={getFilteredSessions()} chatSessions={getFilteredSessions()}
onChatSelect={onChatSelect} onChatSelect={onChatSelect}
currentChat={currentChat} currentChat={currentChat}
/> />
</TabPane> );
<TabPane case "contacts":
tab={ return (
<span>
<UserOutlined />
</span>
}
key="contacts"
>
<WechatFriendsModule <WechatFriendsModule
contacts={getFilteredContacts()} contacts={getFilteredContacts()}
onContactClick={onContactClick} onContactClick={onContactClick}
selectedContactId={currentChat} selectedContactId={currentChat}
/> />
</TabPane> );
<TabPane case "groups":
tab={ return (
<span>
<TeamOutlined />
</span>
}
key="groups"
>
<div className={styles.emptyState}> <div className={styles.emptyState}>
<TeamOutlined style={{ fontSize: 48, color: "#ccc" }} /> <TeamOutlined style={{ fontSize: 48, color: "#ccc" }} />
<p></p> <p></p>
</div> </div>
</TabPane> );
</Tabs> default:
</Sider> return null;
}
};
return (
<LayoutFiexd header={renderHeader()} footer="底部">
{renderContent()}
</LayoutFiexd>
); );
}; };

View File

@@ -1,10 +1,27 @@
.ckboxLayout { .ckboxLayout {
height: 100vh; height: 100vh;
background: #fff; 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; background: #fff;
border-right: 1px solid #f0f0f0; border-right: 1px solid #f0f0f0;
overflow: auto;
}
.sidebar {
height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -87,6 +104,8 @@
background: #f5f5f5; background: #f5f5f5;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 16px;
overflow: auto;
.chatContainer { .chatContainer {
height: 100%; height: 100%;

View File

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