refactor(ckbox): 统一将contact重命名为contract

将代码中所有的contact变量和类名统一改为contract,包括API路径、组件属性、CSS类名等
更新相关路由配置和文档中的API接口说明
This commit is contained in:
2025-08-26 14:19:19 +08:00
parent c7b15896ac
commit a26b465ff6
14 changed files with 181 additions and 132 deletions

View File

@@ -46,7 +46,7 @@ const About: React.FC = () => {
]; ];
// 联系信息 // 联系信息
const contactInfo = [ const contractInfo = [
{ {
id: "email", id: "email",
title: "邮箱支持", title: "邮箱支持",
@@ -125,7 +125,7 @@ const About: React.FC = () => {
{/* <Card className={style["setting-group"]}> {/* <Card className={style["setting-group"]}>
<div className={style["group-title"]}>联系我们</div> <div className={style["group-title"]}>联系我们</div>
<List> <List>
{contactInfo.map(item => ( {contractInfo.map(item => (
<List.Item <List.Item
key={item.id} key={item.id}
prefix={item.icon} prefix={item.icon}

View File

@@ -169,7 +169,7 @@ export default ckboxRoutes;
确保后端提供以下API接口 确保后端提供以下API接口
- `GET /v1/contacts` - 获取联系人列表 - `GET /v1/contracts` - 获取联系人列表
- `GET /v1/chats/sessions` - 获取聊天会话列表 - `GET /v1/chats/sessions` - 获取聊天会话列表
- `GET /v1/chats/:id/messages` - 获取聊天历史 - `GET /v1/chats/:id/messages` - 获取聊天历史
- `POST /v1/chats/:id/messages` - 发送消息 - `POST /v1/chats/:id/messages` - 发送消息

View File

@@ -322,8 +322,8 @@
} }
} }
.contactInfo { .contractInfo {
.contactItem { .contractItem {
align-items: center; align-items: center;
margin-bottom: 12px; margin-bottom: 12px;
font-size: 14px; font-size: 14px;
@@ -339,7 +339,7 @@
width: 16px; width: 16px;
} }
.contactItemText { .contractItemText {
padding-left: 10px; padding-left: 10px;
} }
} }
@@ -487,8 +487,12 @@
} }
@keyframes spin { @keyframes spin {
0% { transform: rotate(0deg); } 0% {
100% { transform: rotate(360deg); } transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
} }
} }
@@ -709,8 +713,8 @@
} }
} }
.contactInfo { .contractInfo {
.contactItem { .contractItem {
font-size: 13px; font-size: 13px;
margin-bottom: 10px; margin-bottom: 10px;
} }

View File

@@ -48,8 +48,6 @@ import { ChatRecord, ContractData } from "@/pages/pc/ckbox/data";
import { clearUnreadCount, getMessages } from "@/pages/pc/ckbox/api"; import { clearUnreadCount, getMessages } from "@/pages/pc/ckbox/api";
import styles from "./ChatWindow.module.scss"; import styles from "./ChatWindow.module.scss";
import { useWebSocketStore } from "@/store/module/websocket"; import { useWebSocketStore } from "@/store/module/websocket";
const { sendCommand } = useWebSocketStore.getState();
const { Header, Content, Footer, Sider } = Layout; const { Header, Content, Footer, Sider } = Layout;
const { TextArea } = Input; const { TextArea } = Input;
@@ -71,6 +69,9 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
const [inputValue, setInputValue] = useState(""); const [inputValue, setInputValue] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [showMaterialModal, setShowMaterialModal] = useState(false); const [showMaterialModal, setShowMaterialModal] = useState(false);
const [pendingVideoRequests, setPendingVideoRequests] = useState<
Record<string, string>
>({});
const messagesEndRef = useRef<HTMLDivElement>(null); const messagesEndRef = useRef<HTMLDivElement>(null);
useEffect(() => { useEffect(() => {
@@ -92,6 +93,64 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
scrollToBottom(); scrollToBottom();
}, [messages]); }, [messages]);
// 添加 WebSocket 消息订阅
useEffect(() => {
// 订阅 WebSocket 消息变化
const unsubscribe = useWebSocketStore.subscribe(
state => state.messages,
(messages, previousMessages) => {
// 只处理新消息
if (messages.length > previousMessages.length) {
// 获取最新的消息
const newMessages = messages.slice(previousMessages.length);
// 处理新消息
newMessages.forEach(message => {
const content = message.content;
// 检查是否是视频下载响应
if (content && content.cmdType === "CmdDownloadVideoResponse") {
// 获取视频URL
const videoUrl = content.videoUrl;
const requestId = content.requestId || content.seq;
// 查找对应的消息ID
const messageId = pendingVideoRequests[requestId];
if (messageId && videoUrl) {
// 更新消息内容,将预览图替换为实际视频
setMessages(prevMessages => {
return prevMessages.map(msg => {
if (msg.id === messageId) {
return {
...msg,
content: videoUrl,
};
}
return msg;
});
});
// 从待处理请求中移除
setPendingVideoRequests(prev => {
const newRequests = { ...prev };
delete newRequests[requestId];
return newRequests;
});
messageApi.success("视频加载成功");
}
}
});
}
},
);
// 组件卸载时取消订阅
return () => {
unsubscribe();
};
}, [pendingVideoRequests, messageApi]);
const scrollToBottom = () => { const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}; };
@@ -179,15 +238,22 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
// 处理视频播放请求发送socket请求获取真实视频地址 // 处理视频播放请求发送socket请求获取真实视频地址
const handleVideoPlayRequest = (tencentUrl: string, messageId: string) => { const handleVideoPlayRequest = (tencentUrl: string, messageId: string) => {
// 生成请求ID (可以使用 seq 或其他唯一标识)
// 构建socket请求数据 // 构建socket请求数据
sendCommand("CmdDownloadVideo", { useWebSocketStore.getState().sendCommand("CmdDownloadVideo", {
chatroomMessageId: contract.chatroomId ? contract.chatroomId : 0, chatroomMessageId: contract.chatroomId ? contract.chatroomId : 0,
friendMessageId: contract.chatroomId ? 0 : contract.id, friendMessageId: contract.chatroomId ? 0 : contract.id,
seq: 9, seq: 9, // 使用唯一的请求ID
tencentUrl: tencentUrl, tencentUrl: tencentUrl,
wechatAccountId: contract.wechatAccountId, wechatAccountId: contract.wechatAccountId,
}); });
// 记录待处理的视频请求
setPendingVideoRequests(prev => ({
...prev,
}));
// 更新消息状态为加载中 // 更新消息状态为加载中
setMessages(prevMessages => { setMessages(prevMessages => {
return prevMessages.map(msg => { return prevMessages.map(msg => {
@@ -205,32 +271,6 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
return msg; return msg;
}); });
}); });
// TODO: 这里应该实现实际的socket请求发送逻辑
console.log("发送视频请求:", socketData);
// 模拟获取视频地址后的处理
// 实际应用中这里应该是socket响应的回调处理
setTimeout(() => {
// 模拟获取到视频地址
const videoUrl = "https://example.com/video.mp4";
// 更新消息内容,将预览图替换为实际视频
setMessages(prevMessages => {
return prevMessages.map(msg => {
if (msg.id === messageId) {
// 创建新的视频消息内容
return {
...msg,
content: videoUrl,
};
}
return msg;
});
});
messageApi.success("视频加载成功");
}, 1500);
}; };
// 解析消息内容,判断消息类型并返回对应的渲染内容 // 解析消息内容,判断消息类型并返回对应的渲染内容

View File

@@ -1,8 +1,8 @@
.contactList { .contractList {
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
.contactItem { .contractItem {
padding: 12px 16px; padding: 12px 16px;
cursor: pointer; cursor: pointer;
border-bottom: 1px solid #f0f0f0; border-bottom: 1px solid #f0f0f0;
@@ -16,17 +16,17 @@
border-bottom: none; border-bottom: none;
} }
.contactInfo { .contractInfo {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12px; gap: 12px;
width: 100%; width: 100%;
.contactDetails { .contractDetails {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
.contactName { .contractName {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: #262626; color: #262626;
@@ -36,13 +36,13 @@
white-space: nowrap; white-space: nowrap;
} }
.contactPhone { .contractPhone {
font-size: 12px; font-size: 12px;
color: #8c8c8c; color: #8c8c8c;
margin-bottom: 2px; margin-bottom: 2px;
} }
.contactStatus { .contractStatus {
font-size: 11px; font-size: 11px;
color: #bfbfbf; color: #bfbfbf;
overflow: hidden; overflow: hidden;
@@ -56,19 +56,19 @@
// 响应式设计 // 响应式设计
@media (max-width: 768px) { @media (max-width: 768px) {
.contactList { .contractList {
.contactItem { .contractItem {
padding: 10px 12px; padding: 10px 12px;
.contactInfo { .contractInfo {
gap: 10px; gap: 10px;
.contactDetails { .contractDetails {
.contactName { .contractName {
font-size: 13px; font-size: 13px;
} }
.contactPhone { .contractPhone {
font-size: 11px; font-size: 11px;
} }
} }

View File

@@ -5,36 +5,36 @@ import { ContractData } from "../../data";
import styles from "./ContactList.module.scss"; import styles from "./ContactList.module.scss";
interface ContactListProps { interface ContactListProps {
contacts: ContractData[]; contracts: ContractData[];
onContactClick: (contact: ContractData) => void; onContactClick: (contract: ContractData) => void;
} }
const ContactList: React.FC<ContactListProps> = ({ const ContactList: React.FC<ContactListProps> = ({
contacts, contracts,
onContactClick, onContactClick,
}) => { }) => {
return ( return (
<div className={styles.contactList}> <div className={styles.contractList}>
<List <List
dataSource={contacts} dataSource={contracts}
renderItem={contact => ( renderItem={contract => (
<List.Item <List.Item
className={styles.contactItem} className={styles.contractItem}
onClick={() => onContactClick(contact)} onClick={() => onContactClick(contract)}
> >
<div className={styles.contactInfo}> <div className={styles.contractInfo}>
<Badge dot={contact.online} color="#52c41a" offset={[-2, 2]}> <Badge dot={contract.online} color="#52c41a" offset={[-2, 2]}>
<Avatar <Avatar
size={40} size={40}
src={contact.avatar} src={contract.avatar}
icon={<UserOutlined />} icon={<UserOutlined />}
/> />
</Badge> </Badge>
<div className={styles.contactDetails}> <div className={styles.contractDetails}>
<div className={styles.contactName}>{contact.name}</div> <div className={styles.contractName}>{contract.name}</div>
<div className={styles.contactPhone}>{contact.phone}</div> <div className={styles.contractPhone}>{contract.phone}</div>
{contact.status && ( {contract.status && (
<div className={styles.contactStatus}>{contact.status}</div> <div className={styles.contractStatus}>{contract.status}</div>
)} )}
</div> </div>
</div> </div>

View File

@@ -2,13 +2,13 @@ import React from "react";
import { List, Avatar, Badge } from "antd"; import { List, Avatar, Badge } from "antd";
import { UserOutlined, TeamOutlined } from "@ant-design/icons"; import { UserOutlined, TeamOutlined } from "@ant-design/icons";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { ContractData } from "./data"; import { ContractData, GroupData } from "@/pages/pc/ckbox/data";
import styles from "./MessageList.module.scss"; import styles from "./MessageList.module.scss";
interface MessageListProps { interface MessageListProps {
chatSessions: ContractData[]; chatSessions: ContractData[];
currentChat: ContractData; currentChat: ContractData;
onChatSelect: (chat: ContractData) => void; onChatSelect: (chat: ContractData | GroupData) => void;
} }
const MessageList: React.FC<MessageListProps> = ({ const MessageList: React.FC<MessageListProps> = ({

View File

@@ -1,4 +1,4 @@
.contactListSimple { .contractListSimple {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
@@ -26,7 +26,7 @@
} }
} }
.contactItem { .contractItem {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 8px 15px; padding: 8px 15px;
@@ -44,7 +44,7 @@
background-color: #1890ff; background-color: #1890ff;
} }
.contactInfo { .contractInfo {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }

View File

@@ -1,43 +1,43 @@
import React from "react"; import React from "react";
import { List, Avatar } from "antd"; import { List, Avatar } from "antd";
import { ContractData } from "./data"; import { ContractData } from "@/pages/pc/ckbox/data";
import styles from "./WechatFriends.module.scss"; import styles from "./WechatFriends.module.scss";
interface WechatFriendsProps { interface WechatFriendsProps {
contacts: ContractData[]; contracts: ContractData[];
onContactClick: (contact: ContractData) => void; onContactClick: (contract: ContractData) => void;
selectedContactId?: ContractData; selectedContactId?: ContractData;
} }
const ContactListSimple: React.FC<WechatFriendsProps> = ({ const ContactListSimple: React.FC<WechatFriendsProps> = ({
contacts, contracts,
onContactClick, onContactClick,
selectedContactId, selectedContactId,
}) => { }) => {
return ( return (
<div className={styles.contactListSimple}> <div className={styles.contractListSimple}>
<div className={styles.header}></div> <div className={styles.header}></div>
<List <List
className={styles.list} className={styles.list}
dataSource={contacts} dataSource={contracts}
renderItem={contact => ( renderItem={contract => (
<List.Item <List.Item
key={contact.id} key={contract.id}
onClick={() => onContactClick(contact)} onClick={() => onContactClick(contract)}
className={`${styles.contactItem} ${contact.id === selectedContactId?.id ? styles.selected : ""}`} className={`${styles.contractItem} ${contract.id === selectedContactId?.id ? styles.selected : ""}`}
> >
<div className={styles.avatarContainer}> <div className={styles.avatarContainer}>
<Avatar <Avatar
src={contact.avatar} src={contract.avatar}
icon={ icon={
!contact.avatar && <span>{contact.nickname.charAt(0)}</span> !contract.avatar && <span>{contract.nickname.charAt(0)}</span>
} }
className={styles.avatar} className={styles.avatar}
/> />
</div> </div>
<div className={styles.contactInfo}> <div className={styles.contractInfo}>
<div className={styles.name}> <div className={styles.name}>
{contact.conRemark || contact.nickname} {contract.conRemark || contract.nickname}
</div> </div>
</div> </div>
</List.Item> </List.Item>

View File

@@ -14,15 +14,15 @@ import styles from "./SidebarMenu.module.scss";
import { getChatSessions } from "@/store/module/ckchat"; import { getChatSessions } from "@/store/module/ckchat";
interface SidebarMenuProps { interface SidebarMenuProps {
contacts: ContractData[]; contracts: ContractData[];
currentChat: ContractData; currentChat: ContractData;
onContactClick: (contact: ContractData) => void; onContactClick: (contract: ContractData) => void;
onChatSelect: (chat: ContractData) => void; onChatSelect: (chat: ContractData) => void;
loading?: boolean; loading?: boolean;
} }
const SidebarMenu: React.FC<SidebarMenuProps> = ({ const SidebarMenu: React.FC<SidebarMenuProps> = ({
contacts, contracts,
currentChat, currentChat,
onContactClick, onContactClick,
onChatSelect, onChatSelect,
@@ -31,18 +31,18 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
const chatSessions = getChatSessions(); const chatSessions = getChatSessions();
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");
const [activeTab, setActiveTab] = useState("contacts"); const [activeTab, setActiveTab] = useState("contracts");
const handleSearch = (value: string) => { const handleSearch = (value: string) => {
setSearchText(value); setSearchText(value);
}; };
const getFilteredContacts = () => { const getFilteredContacts = () => {
if (!searchText) return contacts; if (!searchText) return contracts;
return contacts.filter( return contracts.filter(
contact => contract =>
contact.nickname.toLowerCase().includes(searchText.toLowerCase()) || contract.nickname.toLowerCase().includes(searchText.toLowerCase()) ||
contact.phone.includes(searchText), contract.phone.includes(searchText),
); );
}; };
@@ -77,8 +77,8 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
<span></span> <span></span>
</div> </div>
<div <div
className={`${styles.tabItem} ${activeTab === "contacts" ? styles.active : ""}`} className={`${styles.tabItem} ${activeTab === "contracts" ? styles.active : ""}`}
onClick={() => setActiveTab("contacts")} onClick={() => setActiveTab("contracts")}
> >
<UserOutlined /> <UserOutlined />
<span></span> <span></span>
@@ -105,10 +105,10 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
currentChat={currentChat} currentChat={currentChat}
/> />
); );
case "contacts": case "contracts":
return ( return (
<WechatFriendsModule <WechatFriendsModule
contacts={getFilteredContacts()} contracts={getFilteredContacts()}
onContactClick={onContactClick} onContactClick={onContactClick}
selectedContactId={currentChat} selectedContactId={currentChat}
/> />

View File

@@ -11,7 +11,7 @@ const { Header, Content, Sider } = Layout;
import { chatInitAPIdata } from "./main"; import { chatInitAPIdata } from "./main";
const CkboxPage: React.FC = () => { const CkboxPage: React.FC = () => {
const [messageApi, contextHolder] = message.useMessage(); const [messageApi, contextHolder] = message.useMessage();
const [contacts, setContacts] = useState<any[]>([]); const [contracts, setContacts] = useState<any[]>([]);
const [currentChat, setCurrentChat] = useState<ContractData | null>(null); const [currentChat, setCurrentChat] = useState<ContractData | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -21,10 +21,10 @@ const CkboxPage: React.FC = () => {
// 方法一:使用 Promise 链式调用处理异步函数 // 方法一:使用 Promise 链式调用处理异步函数
setLoading(true); setLoading(true);
chatInitAPIdata() chatInitAPIdata()
.then((response: { contactList: any[]; chatRoomList: any[] }) => { .then((response: { contractList: any[]; chatRoomList: any[] }) => {
const { contactList, chatRoomList } = response; const { contractList, chatRoomList } = response;
//找出已经在聊天的 //找出已经在聊天的
const isChatList = contactList.filter( const isChatList = contractList.filter(
v => (v?.config && v.config?.chat) || false, v => (v?.config && v.config?.chat) || false,
); );
isChatList.forEach(v => { isChatList.forEach(v => {
@@ -41,9 +41,9 @@ const CkboxPage: React.FC = () => {
}); });
}, []); }, []);
const handleContactClick = (contact: ContractData) => { const handleContactClick = (contract: ContractData) => {
addChatSession(contact); addChatSession(contract);
setCurrentChat(contact); setCurrentChat(contract);
}; };
const handleSendMessage = async (message: string) => { const handleSendMessage = async (message: string) => {
@@ -74,7 +74,7 @@ const CkboxPage: React.FC = () => {
{/* 左侧边栏 */} {/* 左侧边栏 */}
<Sider width={280} className={styles.sider}> <Sider width={280} className={styles.sider}>
<SidebarMenu <SidebarMenu
contacts={contacts} contracts={contracts}
currentChat={currentChat} currentChat={currentChat}
onContactClick={handleContactClick} onContactClick={handleContactClick}
onChatSelect={setCurrentChat} onChatSelect={setCurrentChat}
@@ -101,7 +101,7 @@ const CkboxPage: React.FC = () => {
</Space> </Space>
</div> </div>
<ChatWindow <ChatWindow
contact={currentChat} contract={currentChat}
onSendMessage={handleSendMessage} onSendMessage={handleSendMessage}
showProfile={showProfile} showProfile={showProfile}
onToggleProfile={() => setShowProfile(!showProfile)} onToggleProfile={() => setShowProfile(!showProfile)}

View File

@@ -33,11 +33,11 @@ export const chatInitAPIdata = async () => {
seq: 1, seq: 1,
}); });
//获取联系人列表 //获取联系人列表
const contactList = await getAllContactList(); const contractList = await getAllContactList();
//获取群列表 //获取群列表
const chatRoomList = await getAllChatRoomList(); const chatRoomList = await getAllChatRoomList();
return { return {
contactList, contractList,
chatRoomList, chatRoomList,
}; };
} catch (error) { } catch (error) {
@@ -56,28 +56,28 @@ export const getAllContactList = async () => {
while (hasMore) { while (hasMore) {
console.log(`获取联系人列表prevId: ${prevId}, count: ${count}`); console.log(`获取联系人列表prevId: ${prevId}, count: ${count}`);
const contactList = await getContactList({ const contractList = await getContactList({
prevId, prevId,
count, count,
}); });
if ( if (
!contactList || !contractList ||
!Array.isArray(contactList) || !Array.isArray(contractList) ||
contactList.length === 0 contractList.length === 0
) { ) {
hasMore = false; hasMore = false;
break; break;
} }
allContacts = [...allContacts, ...contactList]; allContacts = [...allContacts, ...contractList];
// 如果返回的数据少于请求的数量,说明已经没有更多数据了 // 如果返回的数据少于请求的数量,说明已经没有更多数据了
if (contactList.length < count) { if (contractList.length < count) {
hasMore = false; hasMore = false;
} else { } else {
// 获取最后一条数据的id作为下一次请求的prevId // 获取最后一条数据的id作为下一次请求的prevId
const lastContact = contactList[contactList.length - 1]; const lastContact = contractList[contractList.length - 1];
prevId = lastContact.id; prevId = lastContact.id;
} }
} }
@@ -99,28 +99,28 @@ export const getAllChatRoomList = async () => {
while (hasMore) { while (hasMore) {
console.log(`获取群列表prevId: ${prevId}, count: ${count}`); console.log(`获取群列表prevId: ${prevId}, count: ${count}`);
const contactList = await getChatRoomList({ const contractList = await getChatRoomList({
prevId, prevId,
count, count,
}); });
if ( if (
!contactList || !contractList ||
!Array.isArray(contactList) || !Array.isArray(contractList) ||
contactList.length === 0 contractList.length === 0
) { ) {
hasMore = false; hasMore = false;
break; break;
} }
allContacts = [...allContacts, ...contactList]; allContacts = [...allContacts, ...contractList];
// 如果返回的数据少于请求的数量,说明已经没有更多数据了 // 如果返回的数据少于请求的数量,说明已经没有更多数据了
if (contactList.length < count) { if (contractList.length < count) {
hasMore = false; hasMore = false;
} else { } else {
// 获取最后一条数据的id作为下一次请求的prevId // 获取最后一条数据的id作为下一次请求的prevId
const lastContact = contactList[contactList.length - 1]; const lastContact = contractList[contractList.length - 1];
prevId = lastContact.id; prevId = lastContact.id;
} }
} }

View File

@@ -95,7 +95,7 @@ export const routeGroups = {
"/plans", "/plans",
"/plans/:planId", "/plans/:planId",
"/orders", "/orders",
"/contact-import", "/contract-import",
], ],
}, },
}; };
@@ -126,7 +126,7 @@ export const routePermissions = {
"/plans", "/plans",
"/plans/:planId", "/plans/:planId",
"/orders", "/orders",
"/contact-import", "/contract-import",
], ],
// 访客权限 // 访客权限
@@ -150,7 +150,7 @@ export const routeTitles: Record<string, string> = {
"/profile": "个人中心", "/profile": "个人中心",
"/plans": "计划管理", "/plans": "计划管理",
"/orders": "订单管理", "/orders": "订单管理",
"/contact-import": "联系人导入", "/contract-import": "联系人导入",
}; };
// 获取路由标题 // 获取路由标题

View File

@@ -120,6 +120,11 @@ export const getCkTenantId = () => useCkChatStore.getState().getTenantId();
export const getCkAccountName = () => export const getCkAccountName = () =>
useCkChatStore.getState().getAccountName(); useCkChatStore.getState().getAccountName();
export const getCkTenantName = () => useCkChatStore.getState().getTenantName(); export const getCkTenantName = () => useCkChatStore.getState().getTenantName();
export const getChatSessions = () => useCkChatStore.getState().chatSessions; export const getChatSessions = () =>
useCkChatStore.getState().getChatSessions();
export const addChatSession = (session: ContractData | GroupData) => export const addChatSession = (session: ContractData | GroupData) =>
useCkChatStore.getState().addChatSession(session); useCkChatStore.getState().addChatSession(session);
export const updateChatSession = (session: ContractData | GroupData) =>
useCkChatStore.getState().updateChatSession(session);
export const deleteChatSession = (sessionId: string) =>
useCkChatStore.getState().deleteChatSession(sessionId);