feat(websocket): 重构WebSocket连接逻辑并添加初始化命令
- 重构WebSocket连接逻辑,使用新的URL参数构建方式 - 添加初始化连接时的CmdSignIn和CmdRequestWechatAccountsAliveStatus命令 - 修改WebSocket消息类型定义,简化消息结构 - 从CkChatStore获取accountId用于连接参数 - 移除Login页面中与WebSocket相关的冗余代码
This commit is contained in:
@@ -8,14 +8,8 @@ import {
|
|||||||
} from "antd-mobile-icons";
|
} from "antd-mobile-icons";
|
||||||
import { useUserStore } from "@/store/module/user";
|
import { useUserStore } from "@/store/module/user";
|
||||||
import { useCkChatStore } from "@/store/module/ckchat";
|
import { useCkChatStore } from "@/store/module/ckchat";
|
||||||
import { useWebSocketStore } from "@/store/module/websocket";
|
|
||||||
import {
|
import { loginWithPassword, loginWithCode, sendVerificationCode } from "./api";
|
||||||
loginWithPassword,
|
|
||||||
loginWithCode,
|
|
||||||
sendVerificationCode,
|
|
||||||
loginWithToken,
|
|
||||||
getChuKeBaoUserInfo,
|
|
||||||
} from "./api";
|
|
||||||
import style from "./login.module.scss";
|
import style from "./login.module.scss";
|
||||||
|
|
||||||
const Login: React.FC = () => {
|
const Login: React.FC = () => {
|
||||||
@@ -26,8 +20,7 @@ const Login: React.FC = () => {
|
|||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const [agreeToTerms, setAgreeToTerms] = useState(false);
|
const [agreeToTerms, setAgreeToTerms] = useState(false);
|
||||||
|
|
||||||
const { login, login2 } = useUserStore();
|
const { login } = useUserStore();
|
||||||
const { setUserInfo, getAccountId } = useCkChatStore();
|
|
||||||
|
|
||||||
// 倒计时效果
|
// 倒计时效果
|
||||||
useEffect(() => {
|
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) => {
|
const handleLogin = async (values: any) => {
|
||||||
if (!agreeToTerms) {
|
if (!agreeToTerms) {
|
||||||
@@ -127,23 +102,6 @@ const Login: React.FC = () => {
|
|||||||
.finally(() => {
|
.finally(() => {
|
||||||
setLoading(false);
|
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,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 第三方登录处理
|
// 第三方登录处理
|
||||||
|
|||||||
@@ -14,16 +14,31 @@ import {
|
|||||||
ChatSettings,
|
ChatSettings,
|
||||||
} from "./data";
|
} 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 }) => {
|
export const getContactList = (params: { prevId: number; count: number }) => {
|
||||||
return request("/api/wechatFriend/list", params, "GET");
|
return request("/api/wechatFriend/list", params, "GET");
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取聊天会话列表
|
|
||||||
export const getChatSessions = (): Promise<ChatSession[]> => {
|
|
||||||
return request("/v1/chats/sessions", {}, "GET");
|
|
||||||
};
|
|
||||||
|
|
||||||
// 搜索联系人
|
// 搜索联系人
|
||||||
export const getChatMessage = (params: {
|
export const getChatMessage = (params: {
|
||||||
wechatAccountId: number;
|
wechatAccountId: number;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import MessageList from "../MessageList/index";
|
|||||||
import styles from "./SidebarMenu.module.scss";
|
import styles from "./SidebarMenu.module.scss";
|
||||||
|
|
||||||
const { Sider } = Layout;
|
const { Sider } = Layout;
|
||||||
const { TabPane } = Tabs;
|
|
||||||
|
|
||||||
interface SidebarMenuProps {
|
interface SidebarMenuProps {
|
||||||
contacts: ContactData[];
|
contacts: ContactData[];
|
||||||
@@ -72,52 +71,56 @@ const SidebarMenu: React.FC<SidebarMenuProps> = ({
|
|||||||
activeKey={activeTab}
|
activeKey={activeTab}
|
||||||
onChange={setActiveTab}
|
onChange={setActiveTab}
|
||||||
className={styles.tabs}
|
className={styles.tabs}
|
||||||
>
|
items={[
|
||||||
<TabPane
|
{
|
||||||
tab={
|
key: "chats",
|
||||||
<span>
|
label: (
|
||||||
<MessageOutlined />
|
<span>
|
||||||
聊天
|
<MessageOutlined />
|
||||||
</span>
|
聊天
|
||||||
}
|
</span>
|
||||||
key="chats"
|
),
|
||||||
>
|
children: (
|
||||||
<MessageList
|
<MessageList
|
||||||
sessions={getFilteredSessions()}
|
sessions={getFilteredSessions()}
|
||||||
currentChat={currentChat}
|
currentChat={currentChat}
|
||||||
onChatSelect={onChatSelect}
|
onChatSelect={onChatSelect}
|
||||||
/>
|
/>
|
||||||
</TabPane>
|
),
|
||||||
<TabPane
|
},
|
||||||
tab={
|
{
|
||||||
<span>
|
key: "contacts",
|
||||||
<UserOutlined />
|
label: (
|
||||||
联系人
|
<span>
|
||||||
</span>
|
<UserOutlined />
|
||||||
}
|
联系人
|
||||||
key="contacts"
|
</span>
|
||||||
>
|
),
|
||||||
<ContactListSimple
|
children: (
|
||||||
contacts={getFilteredContacts()}
|
<ContactListSimple
|
||||||
onContactClick={onContactClick}
|
contacts={getFilteredContacts()}
|
||||||
selectedContactId={currentChat?.id.split("_")[1]}
|
onContactClick={onContactClick}
|
||||||
/>
|
selectedContactId={currentChat?.id.split("_")[1]}
|
||||||
</TabPane>
|
/>
|
||||||
<TabPane
|
),
|
||||||
tab={
|
},
|
||||||
<span>
|
{
|
||||||
<TeamOutlined />
|
key: "groups",
|
||||||
群组
|
label: (
|
||||||
</span>
|
<span>
|
||||||
}
|
<TeamOutlined />
|
||||||
key="groups"
|
群组
|
||||||
>
|
</span>
|
||||||
<div className={styles.emptyState}>
|
),
|
||||||
<TeamOutlined style={{ fontSize: 48, color: "#ccc" }} />
|
children: (
|
||||||
<p>暂无群组</p>
|
<div className={styles.emptyState}>
|
||||||
</div>
|
<TeamOutlined style={{ fontSize: 48, color: "#ccc" }} />
|
||||||
</TabPane>
|
<p>暂无群组</p>
|
||||||
</Tabs>
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</Sider>
|
</Sider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,9 +12,12 @@ const { Content } = Layout;
|
|||||||
import { loginWithToken, getChuKeBaoUserInfo } from "@/pages/login/api";
|
import { loginWithToken, getChuKeBaoUserInfo } from "@/pages/login/api";
|
||||||
import { useCkChatStore } from "@/store/module/ckchat";
|
import { useCkChatStore } from "@/store/module/ckchat";
|
||||||
import { useUserStore } from "@/store/module/user";
|
import { useUserStore } from "@/store/module/user";
|
||||||
|
import { useWebSocketStore } from "@/store/module/websocket";
|
||||||
|
import { chatInitAPIdata, getChatInfo } from "./main";
|
||||||
|
|
||||||
const CkboxPage: React.FC = () => {
|
const CkboxPage: React.FC = () => {
|
||||||
const [messageApi, contextHolder] = message.useMessage();
|
const [messageApi, contextHolder] = message.useMessage();
|
||||||
const [contacts, setContacts] = useState<ContactData[]>([]);
|
const [contacts, setContacts] = useState<any[]>([]);
|
||||||
const [chatSessions, setChatSessions] = useState<ChatSession[]>([]);
|
const [chatSessions, setChatSessions] = useState<ChatSession[]>([]);
|
||||||
const [currentChat, setCurrentChat] = useState<ChatSession | null>(null);
|
const [currentChat, setCurrentChat] = useState<ChatSession | null>(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -23,16 +26,8 @@ const CkboxPage: React.FC = () => {
|
|||||||
const { login2 } = useUserStore();
|
const { login2 } = useUserStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
//获取触客宝
|
const contactList = chatInitAPIdata();
|
||||||
getToken2().then(() => {
|
console.log(contactList);
|
||||||
getChuKeBaoUserInfo().then(res => {
|
|
||||||
setUserInfo(res);
|
|
||||||
setTimeout(() => {
|
|
||||||
fetchContacts();
|
|
||||||
fetchChatSessions();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getToken2 = () => {
|
const getToken2 = () => {
|
||||||
@@ -217,6 +212,7 @@ const CkboxPage: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout className={styles.ckboxLayout}>
|
<Layout className={styles.ckboxLayout}>
|
||||||
|
{/* <Button onClick={getChatInfo}>点击</Button> */}
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
{/* 左侧边栏 */}
|
{/* 左侧边栏 */}
|
||||||
<SidebarMenu
|
<SidebarMenu
|
||||||
|
|||||||
@@ -1,7 +1,63 @@
|
|||||||
import { useCkChatStore } from "@/store/module/ckchat";
|
import { useCkChatStore } from "@/store/module/ckchat";
|
||||||
import { useWebSocketStore } from "@/store/module/websocket";
|
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();
|
const { connect } = useWebSocketStore.getState();
|
||||||
//获取微信账户组
|
const { setUserInfo, getAccountId } = useCkChatStore.getState();
|
||||||
export const getWechatAccountGroup = () => {
|
//获取触客宝基础信息
|
||||||
console.log(connect);
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export const useCkChatStore = createPersistStore<CkChatState>(
|
|||||||
// 获取账户ID
|
// 获取账户ID
|
||||||
getAccountId: () => {
|
getAccountId: () => {
|
||||||
const state = useCkChatStore.getState();
|
const state = useCkChatStore.getState();
|
||||||
return state.userInfo?.account?.id || null;
|
return Number(state.userInfo?.account?.id) || null;
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取租户ID
|
// 获取租户ID
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ export const useUserStore = createPersistStore<UserState>(
|
|||||||
},
|
},
|
||||||
login2: token2 => {
|
login2: token2 => {
|
||||||
localStorage.setItem("token2", token2);
|
localStorage.setItem("token2", token2);
|
||||||
console.log(token2);
|
|
||||||
|
|
||||||
set({ token2, isLoggedIn: true });
|
set({ token2, isLoggedIn: true });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { createPersistStore } from "@/store/createPersistStore";
|
import { createPersistStore } from "@/store/createPersistStore";
|
||||||
import { Toast } from "antd-mobile";
|
import { Toast } from "antd-mobile";
|
||||||
import { useUserStore } from "./user";
|
import { useUserStore } from "./user";
|
||||||
|
import { useCkChatStore } from "@/store/module/ckchat";
|
||||||
|
const { getAccountId } = useCkChatStore.getState();
|
||||||
|
|
||||||
// WebSocket消息类型
|
// WebSocket消息类型
|
||||||
export interface WebSocketMessage {
|
export interface WebSocketMessage {
|
||||||
id: string;
|
cmdType?: string;
|
||||||
type: string;
|
seq?: number;
|
||||||
content: any;
|
wechatAccountIds?: string[];
|
||||||
timestamp: number;
|
[key: string]: any;
|
||||||
sender?: string;
|
|
||||||
receiver?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebSocket连接状态
|
// WebSocket连接状态
|
||||||
@@ -25,9 +25,11 @@ export enum WebSocketStatus {
|
|||||||
interface WebSocketConfig {
|
interface WebSocketConfig {
|
||||||
url: string;
|
url: string;
|
||||||
client: string;
|
client: string;
|
||||||
accountId: string;
|
accountId: number;
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
autoReconnect: boolean;
|
autoReconnect: boolean;
|
||||||
|
cmdType: string;
|
||||||
|
seq: number;
|
||||||
reconnectInterval: number;
|
reconnectInterval: number;
|
||||||
maxReconnectAttempts: number;
|
maxReconnectAttempts: number;
|
||||||
}
|
}
|
||||||
@@ -68,11 +70,13 @@ interface WebSocketState {
|
|||||||
|
|
||||||
// 默认配置
|
// 默认配置
|
||||||
const DEFAULT_CONFIG: WebSocketConfig = {
|
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",
|
client: "kefu-client",
|
||||||
accountId: "",
|
accountId: 0,
|
||||||
accessToken: "",
|
accessToken: "",
|
||||||
autoReconnect: true,
|
autoReconnect: true,
|
||||||
|
cmdType: "", // 添加默认的命令类型
|
||||||
|
seq: 0, // 添加默认的序列号
|
||||||
reconnectInterval: 3000,
|
reconnectInterval: 3000,
|
||||||
maxReconnectAttempts: 5,
|
maxReconnectAttempts: 5,
|
||||||
};
|
};
|
||||||
@@ -103,24 +107,24 @@ export const useWebSocketStore = createPersistStore<WebSocketState>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
const { token, token2, user } = useUserStore.getState();
|
const { token2 } = useUserStore.getState();
|
||||||
const accessToken = fullConfig.accessToken || token2 || token;
|
|
||||||
|
|
||||||
if (!accessToken) {
|
if (!token2) {
|
||||||
Toast.show({ content: "未找到有效的访问令牌", position: "top" });
|
Toast.show({ content: "未找到有效的访问令牌", position: "top" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建WebSocket URL
|
console.log("获取connect参数", getAccountId());
|
||||||
const params = {
|
|
||||||
client: fullConfig.client,
|
|
||||||
accountId: fullConfig.accountId || user?.s2_accountId || "",
|
|
||||||
accessToken: accessToken,
|
|
||||||
t: Date.now().toString(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const wsUrl =
|
// 构建WebSocket URL
|
||||||
fullConfig.url + "?" + new URLSearchParams(params).toString();
|
const params = new URLSearchParams({
|
||||||
|
client: fullConfig.client.toString(),
|
||||||
|
accountId: getAccountId().toString(),
|
||||||
|
accessToken: token2,
|
||||||
|
t: Date.now().toString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const wsUrl = fullConfig.url + "?" + params;
|
||||||
|
|
||||||
set({
|
set({
|
||||||
status: WebSocketStatus.CONNECTING,
|
status: WebSocketStatus.CONNECTING,
|
||||||
@@ -166,7 +170,7 @@ export const useWebSocketStore = createPersistStore<WebSocketState>(
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 发送消息
|
// 发送消息
|
||||||
sendMessage: (message: Omit<WebSocketMessage, "id" | "timestamp">) => {
|
sendMessage: message => {
|
||||||
const currentState = get();
|
const currentState = get();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -179,8 +183,6 @@ export const useWebSocketStore = createPersistStore<WebSocketState>(
|
|||||||
|
|
||||||
const fullMessage: WebSocketMessage = {
|
const fullMessage: WebSocketMessage = {
|
||||||
...message,
|
...message,
|
||||||
id: Date.now().toString(),
|
|
||||||
timestamp: Date.now(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -204,16 +206,8 @@ export const useWebSocketStore = createPersistStore<WebSocketState>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = useUserStore.getState();
|
|
||||||
const { token, token2 } = useUserStore.getState();
|
|
||||||
const accessToken = token2 || token;
|
|
||||||
|
|
||||||
const command = {
|
const command = {
|
||||||
accessToken: accessToken,
|
cmdType,
|
||||||
accountId: user?.s2_accountId,
|
|
||||||
client: currentState.config?.client || "kefu-client",
|
|
||||||
cmdType: cmdType,
|
|
||||||
seq: Date.now(),
|
|
||||||
...data,
|
...data,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -255,10 +249,20 @@ export const useWebSocketStore = createPersistStore<WebSocketState>(
|
|||||||
});
|
});
|
||||||
|
|
||||||
console.log("WebSocket连接成功");
|
console.log("WebSocket连接成功");
|
||||||
|
const { token2 } = useUserStore.getState();
|
||||||
// 发送登录命令
|
// 发送登录命令
|
||||||
if (currentState.config) {
|
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" });
|
Toast.show({ content: "WebSocket连接成功", position: "top" });
|
||||||
|
|||||||
Reference in New Issue
Block a user