paul-ai-assistant 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,95 @@
1
+ import { useCallback, useRef, useEffect } from 'react';
2
+ import { assistantChat } from "../service/conversation";
3
+ import { getAssistantWsStatus, reconnectAssistantWs } from "../utils/apushAssistant";
4
+ import { REQUEST_SUCCESS_CODE } from "../constants/common";
5
+ /**
6
+ * 内置自动发送消息逻辑的 Hook
7
+ * 如果用户传入了 onSend,直接返回用户的 onSend
8
+ * 否则返回内置的发送逻辑
9
+ */
10
+ export function useAutoSend(props) {
11
+ var bizId = props.bizId,
12
+ _props$bizDomain = props.bizDomain,
13
+ bizDomain = _props$bizDomain === void 0 ? 'CHAT' : _props$bizDomain,
14
+ userOnSend = props.onSend,
15
+ onSendSuccess = props.onSendSuccess,
16
+ onSendError = props.onSendError;
17
+ var pendingSendRef = useRef(null);
18
+
19
+ // 监听 WebSocket 连接状态,处理待发送消息
20
+ useEffect(function () {
21
+ if (pendingSendRef.current) {
22
+ var _getAssistantWsStatus;
23
+ var status = (getAssistantWsStatus === null || getAssistantWsStatus === void 0 || (_getAssistantWsStatus = getAssistantWsStatus()) === null || _getAssistantWsStatus === void 0 ? void 0 : _getAssistantWsStatus.status) || 'disconnected';
24
+ if (status === 'connected') {
25
+ var pendingSend = pendingSendRef.current;
26
+ pendingSendRef.current = null;
27
+ pendingSend();
28
+ }
29
+ }
30
+ }, [bizId]);
31
+
32
+ // 内置 onSend 逻辑
33
+ var internalOnSend = useCallback(function (data, onSuccessCallback) {
34
+ var _getAssistantWsStatus2;
35
+ var _ref = (data === null || data === void 0 ? void 0 : data.params) || {},
36
+ query = _ref.query;
37
+ if (!bizId) {
38
+ console.warn('useAutoSend: bizId is required for sending message');
39
+ onSendError === null || onSendError === void 0 || onSendError(new Error('bizId is required'));
40
+ return;
41
+ }
42
+ var doSend = function doSend() {
43
+ var _data$params;
44
+ assistantChat({
45
+ subjectId: String(bizId),
46
+ content: query,
47
+ featureConfig: (data === null || data === void 0 ? void 0 : data.featureConfig) || {},
48
+ attachments: (data === null || data === void 0 || (_data$params = data.params) === null || _data$params === void 0 ? void 0 : _data$params.attachments) || []
49
+ }).then(function (res) {
50
+ if ((res === null || res === void 0 ? void 0 : res.code) === REQUEST_SUCCESS_CODE) {
51
+ onSuccessCallback === null || onSuccessCallback === void 0 || onSuccessCallback(res);
52
+ onSendSuccess === null || onSendSuccess === void 0 || onSendSuccess(res);
53
+ } else {
54
+ onSendError === null || onSendError === void 0 || onSendError(res);
55
+ }
56
+ }).catch(function (error) {
57
+ console.error('useAutoSend: send message failed', error);
58
+ onSendError === null || onSendError === void 0 || onSendError(error);
59
+ });
60
+ };
61
+
62
+ // 检查 WebSocket 连接状态
63
+ var status = (getAssistantWsStatus === null || getAssistantWsStatus === void 0 || (_getAssistantWsStatus2 = getAssistantWsStatus()) === null || _getAssistantWsStatus2 === void 0 ? void 0 : _getAssistantWsStatus2.status) || 'disconnected';
64
+ if (status === 'connected') {
65
+ doSend();
66
+ } else {
67
+ // 保存待发送消息
68
+ pendingSendRef.current = doSend;
69
+
70
+ // 如果连接断开,触发重连
71
+ if (status === 'disconnected') {
72
+ reconnectAssistantWs === null || reconnectAssistantWs === void 0 || reconnectAssistantWs({
73
+ bizId: String(bizId),
74
+ bizDomain: bizDomain
75
+ });
76
+ }
77
+
78
+ // 设置超时,避免无限等待
79
+ setTimeout(function () {
80
+ if (pendingSendRef.current === doSend) {
81
+ pendingSendRef.current = null;
82
+ // 超时后直接尝试发送
83
+ doSend();
84
+ }
85
+ }, 5000);
86
+ }
87
+ }, [bizId, bizDomain, onSendSuccess, onSendError]);
88
+
89
+ // 如果用户传入了 onSend,直接返回用户的
90
+ if (userOnSend) {
91
+ return userOnSend;
92
+ }
93
+ return internalOnSend;
94
+ }
95
+ export default useAutoSend;
package/es/index.js CHANGED
@@ -25,6 +25,9 @@ import { ASSIST_CHAT_EVENT } from "./constants/assistChatEvent";
25
25
  import { BIZ_DOMAIN_TYPE } from "./constants/common";
26
26
  import ErrorBoundary from "./ErrorBoundary";
27
27
  import { parseLlmComponentUrl } from "./utils/parseUrl";
28
+ // 开箱即用相关导出
29
+ import { getConversationConnection, assistantChat } from "./service/conversation";
30
+ import { useAutoSend } from "./hooks/useAutoSend";
28
31
  import "./index.scss";
29
32
 
30
33
  // 导出大模型卡片组件
@@ -60,4 +63,8 @@ registerAssistChatForm,
60
63
  // 表单组件
61
64
  PaulButtonGroupProps, SelectBlurry, ArrayInput,
62
65
  // utils
63
- parseLlmComponentUrl, ShareContent };
66
+ parseLlmComponentUrl, ShareContent,
67
+ // 开箱即用相关
68
+ getConversationConnection, assistantChat, useAutoSend };
69
+
70
+ // 导出开箱即用相关类型
@@ -0,0 +1,74 @@
1
+ import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
2
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
3
+ import { customRequest } from "../utils/request";
4
+
5
+ /**
6
+ * 会话连接信息
7
+ */
8
+
9
+ /**
10
+ * 获取会话连接 API 响应
11
+ */
12
+
13
+ /**
14
+ * 获取会话连接信息
15
+ * 用于自动创建或获取现有会话
16
+ * @param params 请求参数
17
+ * @returns Promise<IConversationConnectionResponse>
18
+ */
19
+ export function getConversationConnection(_x) {
20
+ return _getConversationConnection.apply(this, arguments);
21
+ }
22
+
23
+ /**
24
+ * 发送聊天消息
25
+ * @param params 消息参数
26
+ * @returns Promise<any>
27
+ */
28
+ function _getConversationConnection() {
29
+ _getConversationConnection = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(params) {
30
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
31
+ while (1) switch (_context.prev = _context.next) {
32
+ case 0:
33
+ return _context.abrupt("return", customRequest({
34
+ method: 'GET',
35
+ url: '/cognipilot/api/conversation/connection',
36
+ query: {
37
+ bizDomain: params.bizDomain || 'CHAT',
38
+ subjectId: params.subjectId
39
+ }
40
+ }));
41
+ case 1:
42
+ case "end":
43
+ return _context.stop();
44
+ }
45
+ }, _callee);
46
+ }));
47
+ return _getConversationConnection.apply(this, arguments);
48
+ }
49
+ export function assistantChat(_x2) {
50
+ return _assistantChat.apply(this, arguments);
51
+ }
52
+ function _assistantChat() {
53
+ _assistantChat = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(params) {
54
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
55
+ while (1) switch (_context2.prev = _context2.next) {
56
+ case 0:
57
+ return _context2.abrupt("return", customRequest({
58
+ method: 'POST',
59
+ url: '/cognipilot/api/assistant/chat',
60
+ query: {
61
+ subjectId: params.subjectId,
62
+ content: params.content,
63
+ featureConfig: params.featureConfig || {},
64
+ attachments: params.attachments || []
65
+ }
66
+ }));
67
+ case 1:
68
+ case "end":
69
+ return _context2.stop();
70
+ }
71
+ }, _callee2);
72
+ }));
73
+ return _assistantChat.apply(this, arguments);
74
+ }
@@ -0,0 +1 @@
1
+ export { getConversationConnection, assistantChat } from "./conversation";
@@ -4,6 +4,7 @@ import { customRequest } from "./request";
4
4
  import { JsonParse } from "./formatData";
5
5
  import { AesCustomLogEventEnum } from "./log";
6
6
  import { logger } from "./websocketLogger";
7
+ import IM from "./im";
7
8
 
8
9
  // 扩展 Window 接口,声明全局属性
9
10
 
@@ -50,29 +51,38 @@ var msgCallback = function msgCallback(v) {
50
51
  return;
51
52
  }
52
53
 
53
- // 检查 ticketId 是否匹配
54
+ // 检查 ticketId 或 subjectId 是否匹配
55
+ // STREAM 消息使用 subjectId,其他消息使用 ticketId
54
56
  var ticketId = argJson === null || argJson === void 0 ? void 0 : argJson.ticketId;
55
- var isMatch = ticketId === bizId;
57
+ var subjectId = argJson === null || argJson === void 0 ? void 0 : argJson.subjectId;
58
+ var isMatch = ticketId === bizId || subjectId === bizId;
56
59
  if (isMatch) {
57
60
  event.emit(msgType, argJson);
58
61
  logger.debug('消息已分发', {
59
62
  msgType: msgType,
60
- ticketId: ticketId
63
+ ticketId: ticketId,
64
+ subjectId: subjectId
61
65
  });
62
66
  } else {
63
67
  // 消息被过滤,记录调试日志
64
- logger.debug('消息 ticketId 不匹配,已过滤', {
68
+ logger.debug('消息 ticketId/subjectId 不匹配,已过滤', {
65
69
  expected: bizId,
66
- received: ticketId,
70
+ receivedTicketId: ticketId,
71
+ receivedSubjectId: subjectId,
67
72
  msgType: msgType
68
73
  });
69
74
  }
70
75
  };
71
- var callback = function callback(msgBody, bizId) {
76
+ var callback = function callback(message, bizId) {
72
77
  try {
78
+ // message 是完整的 WebSocket 消息对象,真正的消息体在 message.msgBody 中
79
+ var msgBody = (message === null || message === void 0 ? void 0 : message.msgBody) || message;
73
80
  var _ref3 = msgBody || {},
74
- version = _ref3.version,
75
- msgDetail = _ref3.msgDetail;
81
+ msgVersion = _ref3.msgVersion,
82
+ msgDetail = _ref3.msgDetail,
83
+ msgType = _ref3.msgType;
84
+ // 兼容旧版本的 version 字段
85
+ var version = msgVersion || (msgBody === null || msgBody === void 0 ? void 0 : msgBody.version);
76
86
  if (version === '1.0.0') {
77
87
  var _msgDetail$, _msgDetail$2;
78
88
  if (msgDetail !== null && msgDetail !== void 0 && (_msgDetail$ = msgDetail[0]) !== null && _msgDetail$ !== void 0 && _msgDetail$.arg && msgDetail !== null && msgDetail !== void 0 && (_msgDetail$2 = msgDetail[0]) !== null && _msgDetail$2 !== void 0 && _msgDetail$2.app) {
@@ -93,8 +103,8 @@ var callback = function callback(msgBody, bizId) {
93
103
  } else if (version === '2.0.0' || !version) {
94
104
  // version 不传默认为 2.0.0
95
105
  msgCallback({
96
- msgType: msgBody === null || msgBody === void 0 ? void 0 : msgBody.msgType,
97
- arg: msgBody === null || msgBody === void 0 ? void 0 : msgBody.msgDetail,
106
+ msgType: msgType,
107
+ arg: msgDetail,
98
108
  bizId: bizId
99
109
  });
100
110
  }
@@ -191,15 +201,16 @@ export var startAssistantWs = function startAssistantWs(wsProps) {
191
201
  // const url = window.location.host.includes('aliyun.com') ? Landlord.paulAiAliyunCom : 'paul-ai.aliyun.work';
192
202
 
193
203
  var serverDomain = function serverDomain() {
194
- if (isThirdEmbed) {
195
- return 'paul.aliyun.com';
196
- }
197
- if (window.location.host === 'pre.gts.work') {
198
- return 'pre-paul-ai.aliyun.work';
199
- } else if (window.location.host === 'gts.work') {
200
- return 'paul-ai.aliyun.work';
201
- }
202
- return window.location.host;
204
+ return 'ai-space.work';
205
+ // if (isThirdEmbed) {
206
+ // return 'paul.aliyun.com';
207
+ // }
208
+ // if (window.location.host === 'pre.gts.work') {
209
+ // return 'pre-paul-ai.aliyun.work';
210
+ // } else if (window.location.host === 'gts.work') {
211
+ // return 'paul-ai.aliyun.work';
212
+ // }
213
+ // return window.location.host;
203
214
  };
204
215
  var url = "wss://".concat(serverDomain(), "/paulWebPush/ws");
205
216
  var webPushTokenUrl = '/sso/webpush/getToken';
@@ -239,11 +250,11 @@ export var startAssistantWs = function startAssistantWs(wsProps) {
239
250
  });
240
251
  }
241
252
  };
253
+ console.log(appId, userId, '=====');
242
254
  var im = new IM(_objectSpread({
243
255
  url: url,
244
256
  appKey: "".concat(appId, ",").concat(userId),
245
257
  // appKey: `${appId},1000`,
246
-
247
258
  commonParams: {
248
259
  appId: appId,
249
260
  userId: userId
package/es/utils/im.js ADDED
@@ -0,0 +1,395 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
3
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
4
+ import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
5
+ import _createClass from "@babel/runtime/helpers/esm/createClass";
6
+ import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
7
+ /**
8
+ * @file WebSocket IM 客户端
9
+ * 本地实现,替代 @alife/magic-chat-im
10
+ */
11
+
12
+ import { logger } from "./websocketLogger";
13
+
14
+ /**
15
+ * IM 配置选项
16
+ */
17
+
18
+ /**
19
+ * 事件类型
20
+ */
21
+
22
+ /**
23
+ * 事件回调类型
24
+ */
25
+
26
+ /**
27
+ * 重连配置
28
+ */
29
+ var RECONNECT_INTERVAL_BASE = 1000; // 基础重连间隔 1 秒
30
+ var RECONNECT_INTERVAL_MAX = 30000; // 最大重连间隔 30 秒
31
+ var HEARTBEAT_INTERVAL = 30000; // 心跳间隔 30 秒
32
+
33
+ /**
34
+ * IM WebSocket 客户端
35
+ */
36
+ var IM = /*#__PURE__*/function () {
37
+ function IM(options) {
38
+ _classCallCheck(this, IM);
39
+ _defineProperty(this, "url", void 0);
40
+ _defineProperty(this, "appKey", void 0);
41
+ _defineProperty(this, "commonParams", void 0);
42
+ _defineProperty(this, "connectCallback", void 0);
43
+ _defineProperty(this, "token", void 0);
44
+ _defineProperty(this, "getToken", void 0);
45
+ _defineProperty(this, "ws", null);
46
+ _defineProperty(this, "eventListeners", new Map());
47
+ _defineProperty(this, "reconnectAttempts", 0);
48
+ _defineProperty(this, "reconnectTimer", null);
49
+ _defineProperty(this, "heartbeatTimer", null);
50
+ _defineProperty(this, "isManualClose", false);
51
+ _defineProperty(this, "isConnecting", false);
52
+ this.url = options.url;
53
+ this.appKey = options.appKey;
54
+ this.commonParams = options.commonParams;
55
+ this.connectCallback = options.connectCallback;
56
+ this.token = options.token;
57
+ this.getToken = options.getToken;
58
+ }
59
+
60
+ /**
61
+ * 注册事件监听器
62
+ */
63
+ _createClass(IM, [{
64
+ key: "on",
65
+ value: function on(event, callback) {
66
+ if (!this.eventListeners.has(event)) {
67
+ this.eventListeners.set(event, []);
68
+ }
69
+ this.eventListeners.get(event).push(callback);
70
+ }
71
+
72
+ /**
73
+ * 触发事件
74
+ */
75
+ }, {
76
+ key: "emit",
77
+ value: function emit(event, data) {
78
+ var listeners = this.eventListeners.get(event);
79
+ if (listeners) {
80
+ listeners.forEach(function (callback) {
81
+ try {
82
+ callback(data);
83
+ } catch (e) {
84
+ logger.error("\u4E8B\u4EF6 ".concat(event, " \u56DE\u8C03\u6267\u884C\u5931\u8D25"), e);
85
+ }
86
+ });
87
+ }
88
+ }
89
+
90
+ /**
91
+ * 建立连接
92
+ */
93
+ }, {
94
+ key: "connect",
95
+ value: (function () {
96
+ var _connect = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
97
+ var _this = this;
98
+ var token, wsUrl;
99
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
100
+ while (1) switch (_context.prev = _context.next) {
101
+ case 0:
102
+ if (!this.isConnecting) {
103
+ _context.next = 3;
104
+ break;
105
+ }
106
+ logger.warn('正在连接中,跳过重复连接请求');
107
+ return _context.abrupt("return");
108
+ case 3:
109
+ this.isConnecting = true;
110
+ this.isManualClose = false;
111
+ _context.prev = 5;
112
+ // 获取 token
113
+ token = this.token;
114
+ if (!(!token && this.getToken)) {
115
+ _context.next = 11;
116
+ break;
117
+ }
118
+ _context.next = 10;
119
+ return this.getToken();
120
+ case 10:
121
+ token = _context.sent;
122
+ case 11:
123
+ // 构建 WebSocket URL
124
+ wsUrl = this.buildUrl(token);
125
+ logger.info('开始建立 WebSocket 连接', {
126
+ url: this.url
127
+ });
128
+
129
+ // 创建 WebSocket 连接
130
+ this.ws = new WebSocket(wsUrl);
131
+ this.ws.onopen = function () {
132
+ var _this$connectCallback;
133
+ logger.info('WebSocket 连接已建立');
134
+ _this.isConnecting = false;
135
+ _this.reconnectAttempts = 0;
136
+
137
+ // 发送鉴权消息
138
+ _this.sendAuth(token);
139
+
140
+ // 启动心跳
141
+ _this.startHeartbeat();
142
+
143
+ // 触发连接回调
144
+ (_this$connectCallback = _this.connectCallback) === null || _this$connectCallback === void 0 || _this$connectCallback.call(_this);
145
+ };
146
+ this.ws.onmessage = function (event) {
147
+ try {
148
+ var _data = JSON.parse(event.data);
149
+
150
+ // 处理心跳响应
151
+ if (_data.type === 'pong' || _data.msgType === 'pong') {
152
+ logger.debug('收到心跳响应');
153
+ return;
154
+ }
155
+
156
+ // 触发消息事件
157
+ _this.emit('message', _data);
158
+ } catch (e) {
159
+ logger.error('消息解析失败', e);
160
+ }
161
+ };
162
+ this.ws.onclose = function (event) {
163
+ logger.info('WebSocket 连接已关闭', {
164
+ code: event.code,
165
+ reason: event.reason,
166
+ wasClean: event.wasClean
167
+ });
168
+ _this.isConnecting = false;
169
+ _this.stopHeartbeat();
170
+ var closeInfo = {
171
+ code: event.wasClean ? 'CONNECTION_CLOSED_CLEANLY' : event.code,
172
+ reason: event.reason
173
+ };
174
+ _this.emit('close', closeInfo);
175
+
176
+ // 非手动关闭时尝试重连
177
+ if (!_this.isManualClose) {
178
+ _this.scheduleReconnect();
179
+ }
180
+ };
181
+ this.ws.onerror = function (error) {
182
+ logger.error('WebSocket 连接错误', error);
183
+ _this.isConnecting = false;
184
+ _this.emit('error', error);
185
+ };
186
+ _context.next = 26;
187
+ break;
188
+ case 20:
189
+ _context.prev = 20;
190
+ _context.t0 = _context["catch"](5);
191
+ this.isConnecting = false;
192
+ logger.error('建立连接失败', _context.t0);
193
+ this.emit('error', _context.t0);
194
+ this.scheduleReconnect();
195
+ case 26:
196
+ case "end":
197
+ return _context.stop();
198
+ }
199
+ }, _callee, this, [[5, 20]]);
200
+ }));
201
+ function connect() {
202
+ return _connect.apply(this, arguments);
203
+ }
204
+ return connect;
205
+ }()
206
+ /**
207
+ * 解析 JWT token 的 payload
208
+ */
209
+ )
210
+ }, {
211
+ key: "parseJwtPayload",
212
+ value: function parseJwtPayload(token) {
213
+ try {
214
+ var parts = token.split('.');
215
+ if (parts.length !== 3) {
216
+ return null;
217
+ }
218
+ // Base64Url 解码
219
+ var payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');
220
+ var decoded = atob(payload);
221
+ return JSON.parse(decoded);
222
+ } catch (e) {
223
+ logger.error('JWT 解析失败', e);
224
+ return null;
225
+ }
226
+ }
227
+
228
+ /**
229
+ * 构建 WebSocket URL
230
+ * 格式:wss://domain/paulWebPush/ws?param={bizDomain},{userId},{token}
231
+ * 其中 userId 从 token 的 payload 中获取
232
+ */
233
+ }, {
234
+ key: "buildUrl",
235
+ value: function buildUrl(token) {
236
+ var _this$commonParams;
237
+ var bizDomain = ((_this$commonParams = this.commonParams) === null || _this$commonParams === void 0 ? void 0 : _this$commonParams.appId) || '';
238
+
239
+ // 从 token 中解析 userId
240
+ var userId = '';
241
+ if (token) {
242
+ var payload = this.parseJwtPayload(token);
243
+ userId = (payload === null || payload === void 0 ? void 0 : payload.userId) || '';
244
+ }
245
+ var param = "".concat(bizDomain, ",").concat(userId, ",").concat(token || '');
246
+ return "".concat(this.url, "?param=").concat(param);
247
+ }
248
+
249
+ /**
250
+ * 发送鉴权消息
251
+ */
252
+ }, {
253
+ key: "sendAuth",
254
+ value: function sendAuth(token) {
255
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
256
+ return;
257
+ }
258
+ var authMessage = _objectSpread({
259
+ type: 'auth',
260
+ appKey: this.appKey,
261
+ token: token
262
+ }, this.commonParams);
263
+ this.ws.send(JSON.stringify(authMessage));
264
+ logger.debug('已发送鉴权消息');
265
+ }
266
+
267
+ /**
268
+ * 启动心跳
269
+ */
270
+ }, {
271
+ key: "startHeartbeat",
272
+ value: function startHeartbeat() {
273
+ var _this2 = this;
274
+ this.stopHeartbeat();
275
+ this.heartbeatTimer = setInterval(function () {
276
+ if (_this2.ws && _this2.ws.readyState === WebSocket.OPEN) {
277
+ _this2.ws.send(JSON.stringify({
278
+ type: 'ping'
279
+ }));
280
+ logger.debug('发送心跳');
281
+ }
282
+ }, HEARTBEAT_INTERVAL);
283
+ }
284
+
285
+ /**
286
+ * 停止心跳
287
+ */
288
+ }, {
289
+ key: "stopHeartbeat",
290
+ value: function stopHeartbeat() {
291
+ if (this.heartbeatTimer) {
292
+ clearInterval(this.heartbeatTimer);
293
+ this.heartbeatTimer = null;
294
+ }
295
+ }
296
+
297
+ /**
298
+ * 安排重连
299
+ */
300
+ }, {
301
+ key: "scheduleReconnect",
302
+ value: function scheduleReconnect() {
303
+ var _this3 = this;
304
+ if (this.isManualClose) {
305
+ return;
306
+ }
307
+
308
+ // 计算重连间隔(指数退避)
309
+ var interval = Math.min(RECONNECT_INTERVAL_BASE * Math.pow(2, this.reconnectAttempts), RECONNECT_INTERVAL_MAX);
310
+ this.reconnectAttempts++;
311
+ logger.info("\u5C06\u5728 ".concat(interval, "ms \u540E\u5C1D\u8BD5\u7B2C ").concat(this.reconnectAttempts, " \u6B21\u91CD\u8FDE"));
312
+
313
+ // 触发重连事件
314
+ this.emit('reconnect', {
315
+ code: 'RECONNECTING',
316
+ err: null,
317
+ attempt: this.reconnectAttempts
318
+ });
319
+ this.reconnectTimer = setTimeout(function () {
320
+ _this3.connect();
321
+ }, interval);
322
+ }
323
+
324
+ /**
325
+ * 关闭连接
326
+ */
327
+ }, {
328
+ key: "close",
329
+ value: function close() {
330
+ this.isManualClose = true;
331
+
332
+ // 清除重连定时器
333
+ if (this.reconnectTimer) {
334
+ clearTimeout(this.reconnectTimer);
335
+ this.reconnectTimer = null;
336
+ }
337
+
338
+ // 停止心跳
339
+ this.stopHeartbeat();
340
+
341
+ // 关闭 WebSocket
342
+ if (this.ws) {
343
+ try {
344
+ this.ws.close(1000, 'Manual close');
345
+ } catch (e) {
346
+ logger.error('关闭 WebSocket 失败', e);
347
+ }
348
+ this.ws = null;
349
+ }
350
+ logger.info('WebSocket 连接已手动关闭');
351
+ }
352
+
353
+ /**
354
+ * 发送消息
355
+ */
356
+ }, {
357
+ key: "send",
358
+ value: function send(data) {
359
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
360
+ logger.warn('WebSocket 未连接,无法发送消息');
361
+ return false;
362
+ }
363
+ try {
364
+ var message = typeof data === 'string' ? data : JSON.stringify(data);
365
+ this.ws.send(message);
366
+ return true;
367
+ } catch (e) {
368
+ logger.error('发送消息失败', e);
369
+ return false;
370
+ }
371
+ }
372
+
373
+ /**
374
+ * 获取连接状态
375
+ */
376
+ }, {
377
+ key: "getReadyState",
378
+ value: function getReadyState() {
379
+ var _this$ws$readyState, _this$ws;
380
+ return (_this$ws$readyState = (_this$ws = this.ws) === null || _this$ws === void 0 ? void 0 : _this$ws.readyState) !== null && _this$ws$readyState !== void 0 ? _this$ws$readyState : WebSocket.CLOSED;
381
+ }
382
+
383
+ /**
384
+ * 是否已连接
385
+ */
386
+ }, {
387
+ key: "isConnected",
388
+ value: function isConnected() {
389
+ var _this$ws2;
390
+ return ((_this$ws2 = this.ws) === null || _this$ws2 === void 0 ? void 0 : _this$ws2.readyState) === WebSocket.OPEN;
391
+ }
392
+ }]);
393
+ return IM;
394
+ }();
395
+ export default IM;