refactor(ckbox): 统一联系人数据结构并简化聊天会话处理

- 将ContactData接口添加索引签名以支持动态属性
- 移除ChatSession接口,直接使用ContactData作为聊天会话类型
- 简化组件间数据传递和状态管理
- 更新相关组件props类型定义
This commit is contained in:
超级老白兔
2025-08-22 15:17:47 +08:00
parent b32e6cac0c
commit 812cb97713
7 changed files with 81 additions and 47 deletions

View File

@@ -0,0 +1,48 @@
// 联系人数据接口
export interface ContactData {
id?: number;
wechatAccountId: number;
wechatId: string;
alias: string;
conRemark: string;
nickname: string;
quanPin: string;
avatar?: string;
gender: number;
region: string;
addFrom: number;
phone: string;
labels: string[];
signature: string;
accountId: number;
extendFields: null;
city?: string;
lastUpdateTime: string;
isPassed: boolean;
tenantId: number;
groupId: number;
thirdParty: null;
additionalPicture: string;
desc: string;
config: null;
lastMessageTime: number;
unreadCount: number;
duplicate: boolean;
[key: string]: any;
}
//聊天会话类型
export type ChatType = "private" | "group";
// 聊天会话接口
export interface ChatSession {
id: number;
type: ChatType;
name: string;
avatar?: string;
lastMessage: string;
lastTime: string;
unreadCount: number;
online: boolean;
members?: string[];
pinned?: boolean;
muted?: boolean;
}

View File

@@ -2,17 +2,17 @@ import React from "react";
import { List, Avatar, Badge } from "antd";
import { UserOutlined, TeamOutlined } from "@ant-design/icons";
import dayjs from "dayjs";
import { ChatSession } from "@/pages/pc/ckbox/data";
import { ContactData } from "./data";
import styles from "./MessageList.module.scss";
interface MessageListProps {
sessions: ChatSession[];
currentChat: ChatSession | null;
onChatSelect: (chat: ChatSession) => void;
chatSessions: ContactData[];
currentChat: ContactData;
onChatSelect: (chat: ContactData) => void;
}
const MessageList: React.FC<MessageListProps> = ({
sessions,
chatSessions,
currentChat,
onChatSelect,
}) => {
@@ -35,7 +35,7 @@ const MessageList: React.FC<MessageListProps> = ({
return (
<div className={styles.messageList}>
<List
dataSource={sessions}
dataSource={chatSessions}
renderItem={session => (
<List.Item
className={`${styles.messageItem} ${
@@ -49,7 +49,7 @@ const MessageList: React.FC<MessageListProps> = ({
size={48}
src={session.avatar}
icon={
session.type === "group" ? (
session?.type === "group" ? (
<TeamOutlined />
) : (
<UserOutlined />
@@ -59,18 +59,15 @@ const MessageList: React.FC<MessageListProps> = ({
</Badge>
<div className={styles.messageDetails}>
<div className={styles.messageHeader}>
<div className={styles.messageName}>{session.name}</div>
<div className={styles.messageName}>{session.nickname}</div>
<div className={styles.messageTime}>
{formatTime(session.lastTime)}
{formatTime(session?.lastTime || "")}
</div>
</div>
<div className={styles.messageContent}>
<div className={styles.lastMessage}>
{session.lastMessage}
{session?.lastMessage}
</div>
{session.online && (
<div className={styles.onlineIndicator}>线</div>
)}
</div>
</div>
</div>

View File

@@ -6,7 +6,7 @@ import styles from "./ContactListSimple.module.scss";
interface ContactListSimpleProps {
contacts: ContactData[];
onContactClick: (contact: ContactData) => void;
selectedContactId?: number;
selectedContactId?: ContactData;
}
const ContactListSimple: React.FC<ContactListSimpleProps> = ({
@@ -24,18 +24,16 @@ const ContactListSimple: React.FC<ContactListSimpleProps> = ({
<List.Item
key={contact.id}
onClick={() => onContactClick(contact)}
className={`${styles.contactItem} ${contact.id === selectedContactId ? styles.selected : ""}`}
className={`${styles.contactItem} ${contact.id === selectedContactId?.id ? styles.selected : ""}`}
>
<div className={styles.avatarContainer}>
<Badge dot={contact.online} color="green" offset={[-5, 5]}>
<Avatar
src={contact.avatar}
icon={
!contact.avatar && <span>{contact.nickname.charAt(0)}</span>
}
className={styles.avatar}
/>
</Badge>
<Avatar
src={contact.avatar}
icon={
!contact.avatar && <span>{contact.nickname.charAt(0)}</span>
}
className={styles.avatar}
/>
</div>
<div className={styles.contactInfo}>
<div className={styles.name}>{contact.nickname}</div>

View File

@@ -28,6 +28,7 @@ export interface ContactData {
lastMessageTime: number;
unreadCount: number;
duplicate: boolean;
[key: string]: any;
}
//聊天会话类型
export type ChatType = "private" | "group";

View File

@@ -6,7 +6,7 @@ import {
TeamOutlined,
MessageOutlined,
} from "@ant-design/icons";
import { ContactData, ChatSession } from "./data";
import { ContactData } from "./data";
import WechatFriendsModule from "./WechatFriendsModule";
import MessageList from "../MessageList/index";
import styles from "./SidebarMenu.module.scss";
@@ -16,10 +16,10 @@ const { TabPane } = Tabs;
interface SidebarMenuProps {
contacts: ContactData[];
chatSessions: ChatSession[];
currentChat: ChatSession | null;
chatSessions: ContactData[];
currentChat: ContactData;
onContactClick: (contact: ContactData) => void;
onChatSelect: (chat: ChatSession) => void;
onChatSelect: (chat: ContactData) => void;
loading?: boolean;
}
@@ -50,7 +50,7 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
const getFilteredSessions = () => {
if (!searchText) return chatSessions;
return chatSessions.filter(session =>
session.name.toLowerCase().includes(searchText.toLowerCase()),
session.nickname.toLowerCase().includes(searchText.toLowerCase()),
);
};
@@ -83,9 +83,9 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
key="chats"
>
<MessageList
sessions={getFilteredSessions()}
currentChat={currentChat}
chatSessions={getFilteredSessions()}
onChatSelect={onChatSelect}
currentChat={currentChat}
/>
</TabPane>
<TabPane
@@ -100,7 +100,7 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
<WechatFriendsModule
contacts={getFilteredContacts()}
onContactClick={onContactClick}
selectedContactId={currentChat?.id.split("_")[1]}
selectedContactId={currentChat}
/>
</TabPane>
<TabPane

View File

@@ -28,6 +28,7 @@ export interface ContactData {
lastMessageTime: number;
unreadCount: number;
duplicate: boolean;
[key: string]: any;
}
/**

View File

@@ -2,8 +2,7 @@ import React, { useState, useEffect } from "react";
import { Layout, Button, Space, message, Tooltip } from "antd";
import { InfoCircleOutlined, MessageOutlined } from "@ant-design/icons";
import dayjs from "dayjs";
import { ChatSession } from "./data";
import { ContactData } from "./components/SidebarMenu/data";
import { ContactData } from "./data";
import ChatWindow from "./components/ChatWindow/index";
import SidebarMenu from "./components/SidebarMenu/index";
import styles from "./index.module.scss";
@@ -16,8 +15,8 @@ import { chatInitAPIdata } from "./main";
const CkboxPage: React.FC = () => {
const [messageApi, contextHolder] = message.useMessage();
const [contacts, setContacts] = useState<any[]>([]);
const [chatSessions, setChatSessions] = useState<ChatSession[]>([]);
const [currentChat, setCurrentChat] = useState<ChatSession | null>(null);
const [chatSessions, setChatSessions] = useState<ContactData[]>([]);
const [currentChat, setCurrentChat] = useState<ContactData | null>(null);
const [loading, setLoading] = useState(false);
const [showProfile, setShowProfile] = useState(true);
const { login2 } = useUserStore();
@@ -55,18 +54,8 @@ const CkboxPage: React.FC = () => {
const handleContactClick = (contact: ContactData) => {
// 查找或创建聊天会话
let session = chatSessions.find(s => s.id === contact.id);
const session = chatSessions.find(s => s.id === contact.id);
if (!session) {
session = {
id: contact.id,
type: "private",
name: contact.nickname,
avatar: contact.avatar,
lastMessage: "",
lastTime: dayjs().toISOString(),
unreadCount: 0,
online: contact.online,
};
setChatSessions(prev => [session!, ...prev]);
}
setCurrentChat(session);