feat(websocket): 重构WebSocket连接逻辑并添加初始化命令

- 重构WebSocket连接逻辑,使用新的URL参数构建方式
- 添加初始化连接时的CmdSignIn和CmdRequestWechatAccountsAliveStatus命令
- 修改WebSocket消息类型定义,简化消息结构
- 从CkChatStore获取accountId用于连接参数
- 移除Login页面中与WebSocket相关的冗余代码
This commit is contained in:
超级老白兔
2025-08-21 17:44:47 +08:00
parent 8e89c5ba73
commit d0bd7d4cd7
8 changed files with 179 additions and 148 deletions

View File

@@ -8,14 +8,8 @@ import {
} from "antd-mobile-icons";
import { useUserStore } from "@/store/module/user";
import { useCkChatStore } from "@/store/module/ckchat";
import { useWebSocketStore } from "@/store/module/websocket";
import {
loginWithPassword,
loginWithCode,
sendVerificationCode,
loginWithToken,
getChuKeBaoUserInfo,
} from "./api";
import { loginWithPassword, loginWithCode, sendVerificationCode } from "./api";
import style from "./login.module.scss";
const Login: React.FC = () => {
@@ -26,8 +20,7 @@ const Login: React.FC = () => {
const [showPassword, setShowPassword] = useState(false);
const [agreeToTerms, setAgreeToTerms] = useState(false);
const { login, login2 } = useUserStore();
const { setUserInfo, getAccountId } = useCkChatStore();
const { login } = useUserStore();
// 倒计时效果
useEffect(() => {
@@ -97,24 +90,6 @@ const Login: React.FC = () => {
});
};
const getToken2 = () => {
return new Promise((resolve, reject) => {
const params = {
grant_type: "password",
password: "kr123456",
username: "kr_xf3",
};
loginWithToken(params)
.then(res => {
login2(res.access_token);
resolve(res.access_token);
})
.catch(err => {
reject(err);
});
});
};
// 登录处理
const handleLogin = async (values: any) => {
if (!agreeToTerms) {
@@ -127,23 +102,6 @@ const Login: React.FC = () => {
.finally(() => {
setLoading(false);
});
//获取触客宝
getToken2().then((Token: string) => {
getChuKeBaoUserInfo().then(res => {
setUserInfo(res);
// 使用WebSocket store连接
const { connect } = useWebSocketStore.getState();
connect({
accessToken: Token,
accountId: getAccountId()?.toString() || "",
client: "kefu-client",
autoReconnect: true,
reconnectInterval: 3000,
maxReconnectAttempts: 5,
});
});
});
};
// 第三方登录处理

View File

@@ -14,16 +14,31 @@ import {
ChatSettings,
} from "./data";
//触客宝登陆
export function loginWithToken(params: any) {
return request(
"/token",
params,
"POST",
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
},
1000,
);
}
// 获取触客宝用户信息
export function getChuKeBaoUserInfo() {
return request("/api/account/self", {}, "GET");
}
// 获取联系人列表
export const getContactList = (params: { prevId: number; count: number }) => {
return request("/api/wechatFriend/list", params, "GET");
};
// 获取聊天会话列表
export const getChatSessions = (): Promise<ChatSession[]> => {
return request("/v1/chats/sessions", {}, "GET");
};
// 搜索联系人
export const getChatMessage = (params: {
wechatAccountId: number;

View File

@@ -12,7 +12,6 @@ import MessageList from "../MessageList/index";
import styles from "./SidebarMenu.module.scss";
const { Sider } = Layout;
const { TabPane } = Tabs;
interface SidebarMenuProps {
contacts: ContactData[];
@@ -72,52 +71,56 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
activeKey={activeTab}
onChange={setActiveTab}
className={styles.tabs}
>
<TabPane
tab={
<span>
<MessageOutlined />
</span>
}
key="chats"
>
<MessageList
sessions={getFilteredSessions()}
currentChat={currentChat}
onChatSelect={onChatSelect}
/>
</TabPane>
<TabPane
tab={
<span>
<UserOutlined />
</span>
}
key="contacts"
>
<ContactListSimple
contacts={getFilteredContacts()}
onContactClick={onContactClick}
selectedContactId={currentChat?.id.split("_")[1]}
/>
</TabPane>
<TabPane
tab={
<span>
<TeamOutlined />
</span>
}
key="groups"
>
<div className={styles.emptyState}>
<TeamOutlined style={{ fontSize: 48, color: "#ccc" }} />
<p></p>
</div>
</TabPane>
</Tabs>
items={[
{
key: "chats",
label: (
<span>
<MessageOutlined />
</span>
),
children: (
<MessageList
sessions={getFilteredSessions()}
currentChat={currentChat}
onChatSelect={onChatSelect}
/>
),
},
{
key: "contacts",
label: (
<span>
<UserOutlined />
</span>
),
children: (
<ContactListSimple
contacts={getFilteredContacts()}
onContactClick={onContactClick}
selectedContactId={currentChat?.id.split("_")[1]}
/>
),
},
{
key: "groups",
label: (
<span>
<TeamOutlined />
</span>
),
children: (
<div className={styles.emptyState}>
<TeamOutlined style={{ fontSize: 48, color: "#ccc" }} />
<p></p>
</div>
),
},
]}
/>
</Sider>
);
};

View File

@@ -12,9 +12,12 @@ const { Content } = Layout;
import { loginWithToken, getChuKeBaoUserInfo } from "@/pages/login/api";
import { useCkChatStore } from "@/store/module/ckchat";
import { useUserStore } from "@/store/module/user";
import { useWebSocketStore } from "@/store/module/websocket";
import { chatInitAPIdata, getChatInfo } from "./main";
const CkboxPage: React.FC = () => {
const [messageApi, contextHolder] = message.useMessage();
const [contacts, setContacts] = useState<ContactData[]>([]);
const [contacts, setContacts] = useState<any[]>([]);
const [chatSessions, setChatSessions] = useState<ChatSession[]>([]);
const [currentChat, setCurrentChat] = useState<ChatSession | null>(null);
const [loading, setLoading] = useState(false);
@@ -23,16 +26,8 @@ const CkboxPage: React.FC = () => {
const { login2 } = useUserStore();
useEffect(() => {
//获取触客宝
getToken2().then(() => {
getChuKeBaoUserInfo().then(res => {
setUserInfo(res);
setTimeout(() => {
fetchContacts();
fetchChatSessions();
});
});
});
const contactList = chatInitAPIdata();
console.log(contactList);
}, []);
const getToken2 = () => {
@@ -217,6 +212,7 @@ const CkboxPage: React.FC = () => {
return (
<Layout className={styles.ckboxLayout}>
{/* <Button onClick={getChatInfo}>点击</Button> */}
{contextHolder}
{/* 左侧边栏 */}
<SidebarMenu

View File

@@ -1,7 +1,63 @@
import { useCkChatStore } from "@/store/module/ckchat";
import { useWebSocketStore } from "@/store/module/websocket";
import { loginWithToken, getChuKeBaoUserInfo, getContactList } from "./api";
const { sendCommand } = useWebSocketStore.getState();
import { useUserStore } from "@/store/module/user";
const { login2 } = useUserStore.getState();
const { connect } = useWebSocketStore.getState();
//获取微信账户组
export const getWechatAccountGroup = () => {
console.log(connect);
const { setUserInfo, getAccountId } = useCkChatStore.getState();
//获取触客宝基础信息
export const chatInitAPIdata = async () => {
//获取Token
const Token = await getToken();
//获取用户信息
const userInfo = await getChuKeBaoUserInfo();
setUserInfo(userInfo);
//获取用户账号Id
const accountId = getAccountId();
//发起链接
connect({
accessToken: String(Token),
accountId: accountId,
client: "kefu-client",
cmdType: "CmdSignIn",
seq: 1,
});
//获取联系人列表
const contactList = await getContactList({
prevId: userInfo.tenant.tenantType,
count: 100,
});
return contactList;
};
export const getChatInfo = () => {
//获取UserId
sendCommand("CmdRequestWechatAccountsAliveStatus", {
wechatAccountIds: ["300745", "4880930", "32686452"],
seq: 2,
});
console.log("发送链接信息");
};
//获取token
const getToken = () => {
return new Promise((resolve, reject) => {
const params = {
grant_type: "password",
password: "kr123456",
username: "kr_xf3",
};
loginWithToken(params)
.then(res => {
login2(res.access_token);
resolve(res.access_token);
})
.catch(err => {
reject(err);
});
});
};

View File

@@ -44,7 +44,7 @@ export const useCkChatStore = createPersistStore<CkChatState>(
// 获取账户ID
getAccountId: () => {
const state = useCkChatStore.getState();
return state.userInfo?.account?.id || null;
return Number(state.userInfo?.account?.id) || null;
},
// 获取租户ID

View File

@@ -80,7 +80,6 @@ export const useUserStore = createPersistStore<UserState>(
},
login2: token2 => {
localStorage.setItem("token2", token2);
console.log(token2);
set({ token2, isLoggedIn: true });
},

View File

@@ -1,15 +1,15 @@
import { createPersistStore } from "@/store/createPersistStore";
import { Toast } from "antd-mobile";
import { useUserStore } from "./user";
import { useCkChatStore } from "@/store/module/ckchat";
const { getAccountId } = useCkChatStore.getState();
// WebSocket消息类型
export interface WebSocketMessage {
id: string;
type: string;
content: any;
timestamp: number;
sender?: string;
receiver?: string;
cmdType?: string;
seq?: number;
wechatAccountIds?: string[];
[key: string]: any;
}
// WebSocket连接状态
@@ -25,9 +25,11 @@ export enum WebSocketStatus {
interface WebSocketConfig {
url: string;
client: string;
accountId: string;
accountId: number;
accessToken: string;
autoReconnect: boolean;
cmdType: string;
seq: number;
reconnectInterval: number;
maxReconnectAttempts: number;
}
@@ -68,11 +70,13 @@ interface WebSocketState {
// 默认配置
const DEFAULT_CONFIG: WebSocketConfig = {
url: (import.meta as any).env?.VITE_API_WS_URL || "ws://localhost:8080",
url: (import.meta as any).env?.VITE_API_WS_URL,
client: "kefu-client",
accountId: "",
accountId: 0,
accessToken: "",
autoReconnect: true,
cmdType: "", // 添加默认的命令类型
seq: 0, // 添加默认的序列号
reconnectInterval: 3000,
maxReconnectAttempts: 5,
};
@@ -103,24 +107,24 @@ export const useWebSocketStore = createPersistStore<WebSocketState>(
};
// 获取用户信息
const { token, token2, user } = useUserStore.getState();
const accessToken = fullConfig.accessToken || token2 || token;
const { token2 } = useUserStore.getState();
if (!accessToken) {
if (!token2) {
Toast.show({ content: "未找到有效的访问令牌", position: "top" });
return;
}
// 构建WebSocket URL
const params = {
client: fullConfig.client,
accountId: fullConfig.accountId || user?.s2_accountId || "",
accessToken: accessToken,
t: Date.now().toString(),
};
console.log("获取connect参数", getAccountId());
const wsUrl =
fullConfig.url + "?" + new URLSearchParams(params).toString();
// 构建WebSocket URL
const params = new URLSearchParams({
client: fullConfig.client.toString(),
accountId: getAccountId().toString(),
accessToken: token2,
t: Date.now().toString(),
});
const wsUrl = fullConfig.url + "?" + params;
set({
status: WebSocketStatus.CONNECTING,
@@ -166,7 +170,7 @@ export const useWebSocketStore = createPersistStore<WebSocketState>(
},
// 发送消息
sendMessage: (message: Omit<WebSocketMessage, "id" | "timestamp">) => {
sendMessage: message => {
const currentState = get();
if (
@@ -179,8 +183,6 @@ export const useWebSocketStore = createPersistStore<WebSocketState>(
const fullMessage: WebSocketMessage = {
...message,
id: Date.now().toString(),
timestamp: Date.now(),
};
try {
@@ -204,16 +206,8 @@ export const useWebSocketStore = createPersistStore<WebSocketState>(
return;
}
const { user } = useUserStore.getState();
const { token, token2 } = useUserStore.getState();
const accessToken = token2 || token;
const command = {
accessToken: accessToken,
accountId: user?.s2_accountId,
client: currentState.config?.client || "kefu-client",
cmdType: cmdType,
seq: Date.now(),
cmdType,
...data,
};
@@ -255,10 +249,20 @@ export const useWebSocketStore = createPersistStore<WebSocketState>(
});
console.log("WebSocket连接成功");
const { token2 } = useUserStore.getState();
// 发送登录命令
if (currentState.config) {
currentState.sendCommand("CmdSignIn");
currentState.sendCommand("CmdSignIn", {
accessToken: token2,
accountId: Number(getAccountId()),
client: currentState.config?.client || "kefu-client",
seq: currentState.config?.seq || 1,
});
//获取UserId
currentState.sendCommand("CmdRequestWechatAccountsAliveStatus", {
wechatAccountIds: ["300745", "4880930", "32686452"],
seq: 2,
});
}
Toast.show({ content: "WebSocket连接成功", position: "top" });