paul-ai-assistant 1.0.4 → 1.0.6
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.
- package/README.md +48 -0
- package/es/AssistantChat/AssistantChatApp/index.js +4 -2
- package/es/AssistantChat/AssistantChatCard/OperationCard/FeedBack/index.js +21 -1
- package/es/AssistantChat/AssistantChatInput/index.scss +5 -0
- package/es/components/InspectionCard/index.js +1 -2
- package/es/utils/apushAssistant.js +11 -9
- package/es/utils/im.js +386 -0
- package/es/utils/request.js +16 -12
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -43,6 +43,54 @@ function App() {
|
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
## API 参数
|
|
47
|
+
|
|
48
|
+
### customFeedbackRender
|
|
49
|
+
|
|
50
|
+
自定义点赞点踩组件渲染函数。如果不传入此参数,将使用默认的点赞点踩组件。
|
|
51
|
+
|
|
52
|
+
**类型定义:**
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
customFeedbackRender?: (props: {
|
|
56
|
+
feedbackValue?: { feedback: 'helpful' | 'unhelpful' };
|
|
57
|
+
onFeedback: (feedback: 'helpful' | 'unhelpful') => void;
|
|
58
|
+
message: any;
|
|
59
|
+
}) => ReactNode;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**参数说明:**
|
|
63
|
+
|
|
64
|
+
| 参数 | 说明 | 类型 |
|
|
65
|
+
|------|------|------|
|
|
66
|
+
| feedbackValue | 当前反馈值 | `{ feedback: 'helpful' \| 'unhelpful' } \| undefined` |
|
|
67
|
+
| onFeedback | 反馈回调函数,调用后会提交反馈到服务端 | `(feedback: 'helpful' \| 'unhelpful') => void` |
|
|
68
|
+
| message | 当前消息的完整数据 | `any` |
|
|
69
|
+
|
|
70
|
+
**使用示例:**
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<PaulAiAssistant
|
|
74
|
+
bizId="your-biz-id"
|
|
75
|
+
customFeedbackRender={({ feedbackValue, onFeedback }) => (
|
|
76
|
+
<div>
|
|
77
|
+
<button
|
|
78
|
+
onClick={() => onFeedback('helpful')}
|
|
79
|
+
style={{ color: feedbackValue?.feedback === 'helpful' ? 'green' : 'gray' }}
|
|
80
|
+
>
|
|
81
|
+
有帮助
|
|
82
|
+
</button>
|
|
83
|
+
<button
|
|
84
|
+
onClick={() => onFeedback('unhelpful')}
|
|
85
|
+
style={{ color: feedbackValue?.feedback === 'unhelpful' ? 'red' : 'gray' }}
|
|
86
|
+
>
|
|
87
|
+
没帮助
|
|
88
|
+
</button>
|
|
89
|
+
</div>
|
|
90
|
+
)}
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
46
94
|
## 开发
|
|
47
95
|
|
|
48
96
|
### 环境要求
|
|
@@ -28,7 +28,8 @@ var AssistantChatApp = function AssistantChatApp(_, ref) {
|
|
|
28
28
|
toggleMessageSelection = _useContext.toggleMessageSelection,
|
|
29
29
|
isMessageSelected = _useContext.isMessageSelected,
|
|
30
30
|
canCancelSelection = _useContext.canCancelSelection,
|
|
31
|
-
enterShareMode = _useContext.enterShareMode
|
|
31
|
+
enterShareMode = _useContext.enterShareMode,
|
|
32
|
+
customFeedbackRender = _useContext.customFeedbackRender;
|
|
32
33
|
var chatListRef = useRef(null);
|
|
33
34
|
var stopScrollToEndRef = useRef(false);
|
|
34
35
|
var messageWidth = (MESSAGE_CARD_WIDTH === null || MESSAGE_CARD_WIDTH === void 0 ? void 0 : MESSAGE_CARD_WIDTH[messageCardWidth]) || messageCardWidth;
|
|
@@ -174,7 +175,8 @@ var AssistantChatApp = function AssistantChatApp(_, ref) {
|
|
|
174
175
|
meta: {
|
|
175
176
|
originData: message
|
|
176
177
|
}
|
|
177
|
-
}
|
|
178
|
+
},
|
|
179
|
+
customFeedbackRender: customFeedbackRender
|
|
178
180
|
})), /*#__PURE__*/React.createElement(AigcTipsRender, {
|
|
179
181
|
ctx: {
|
|
180
182
|
meta: {
|
|
@@ -14,7 +14,8 @@ export var FEEDBACK_TYPE = /*#__PURE__*/function (FEEDBACK_TYPE) {
|
|
|
14
14
|
}({}); // 点踩
|
|
15
15
|
var FeedBack = function FeedBack(props) {
|
|
16
16
|
var _ctx$meta, _headerInfo$props;
|
|
17
|
-
var ctx = props.ctx
|
|
17
|
+
var ctx = props.ctx,
|
|
18
|
+
customFeedbackRender = props.customFeedbackRender;
|
|
18
19
|
var _ref = (ctx === null || ctx === void 0 || (_ctx$meta = ctx.meta) === null || _ctx$meta === void 0 ? void 0 : _ctx$meta.originData) || {},
|
|
19
20
|
dialogId = _ref.dialogId,
|
|
20
21
|
subjectId = _ref.subjectId,
|
|
@@ -52,6 +53,25 @@ var FeedBack = function FeedBack(props) {
|
|
|
52
53
|
}
|
|
53
54
|
});
|
|
54
55
|
};
|
|
56
|
+
|
|
57
|
+
// 如果传入了自定义渲染函数,使用自定义组件
|
|
58
|
+
if (typeof customFeedbackRender === 'function') {
|
|
59
|
+
var _ctx$meta2;
|
|
60
|
+
return customFeedbackRender({
|
|
61
|
+
feedbackValue: feedBackValue,
|
|
62
|
+
onFeedback: function onFeedback(feedback) {
|
|
63
|
+
setFeedBackValue({
|
|
64
|
+
feedback: feedback
|
|
65
|
+
});
|
|
66
|
+
onChange({
|
|
67
|
+
feedback: feedback
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
message: ctx === null || ctx === void 0 || (_ctx$meta2 = ctx.meta) === null || _ctx$meta2 === void 0 ? void 0 : _ctx$meta2.originData
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 默认渲染逻辑
|
|
55
75
|
return /*#__PURE__*/React.createElement(React.Fragment, null, feedBackValue && (feedBackValue === null || feedBackValue === void 0 ? void 0 : feedBackValue.feedback) === FEEDBACK_TYPE.HELPFUL ? /*#__PURE__*/React.createElement(CSECustomIcon, {
|
|
56
76
|
type: "icondianzan-mianxing",
|
|
57
77
|
size: "small",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
.assistant-chat-paul-ai-bottom-reply {
|
|
13
13
|
width: 100%;
|
|
14
|
+
box-sizing: border-box;
|
|
14
15
|
background-color: #fff;
|
|
15
16
|
border: 1px solid #d4d6db;
|
|
16
17
|
border-radius: 6px;
|
|
@@ -32,6 +33,10 @@
|
|
|
32
33
|
box-shadow: none !important;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
textarea:focus-visible {
|
|
37
|
+
outline: none;
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
.ant-input:focus {
|
|
36
41
|
box-shadow: none !important;
|
|
37
42
|
}
|
|
@@ -6,7 +6,6 @@ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
|
6
6
|
* @file 智能辅助-巡检报告卡片
|
|
7
7
|
*/
|
|
8
8
|
import React, { useContext, useState } from 'react';
|
|
9
|
-
import { Message } from '@alifd/next';
|
|
10
9
|
import { message } from 'antd';
|
|
11
10
|
import _ from 'lodash';
|
|
12
11
|
import AgentCardRender from "../../AssistantChat/AssistantChatCard/AgentCardRender";
|
|
@@ -84,7 +83,7 @@ var InspectionCard = function InspectionCard(props) {
|
|
|
84
83
|
setFormData(values);
|
|
85
84
|
setIsSubmitted(true);
|
|
86
85
|
} else {
|
|
87
|
-
|
|
86
|
+
message.error(response.message || '表单提交失败,请重试');
|
|
88
87
|
enableSubmit === null || enableSubmit === void 0 || enableSubmit(); // 重新启用提交按钮
|
|
89
88
|
}
|
|
90
89
|
_context.next = 13;
|
|
@@ -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
|
|
|
@@ -191,15 +192,16 @@ export var startAssistantWs = function startAssistantWs(wsProps) {
|
|
|
191
192
|
// const url = window.location.host.includes('aliyun.com') ? Landlord.paulAiAliyunCom : 'paul-ai.aliyun.work';
|
|
192
193
|
|
|
193
194
|
var serverDomain = function serverDomain() {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
195
|
+
return 'ai-space.work';
|
|
196
|
+
// if (isThirdEmbed) {
|
|
197
|
+
// return 'paul.aliyun.com';
|
|
198
|
+
// }
|
|
199
|
+
// if (window.location.host === 'pre.gts.work') {
|
|
200
|
+
// return 'pre-paul-ai.aliyun.work';
|
|
201
|
+
// } else if (window.location.host === 'gts.work') {
|
|
202
|
+
// return 'paul-ai.aliyun.work';
|
|
203
|
+
// }
|
|
204
|
+
// return window.location.host;
|
|
203
205
|
};
|
|
204
206
|
var url = "wss://".concat(serverDomain(), "/paulWebPush/ws");
|
|
205
207
|
var webPushTokenUrl = '/sso/webpush/getToken';
|
package/es/utils/im.js
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
3
|
+
import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
|
|
4
|
+
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
5
|
+
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
|
6
|
+
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
|
7
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
8
|
+
/**
|
|
9
|
+
* @file WebSocket IM 客户端
|
|
10
|
+
* 本地实现,替代 @alife/magic-chat-im
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { logger } from "./websocketLogger";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* IM 配置选项
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 事件类型
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 事件回调类型
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 重连配置
|
|
29
|
+
*/
|
|
30
|
+
var RECONNECT_INTERVAL_BASE = 1000; // 基础重连间隔 1 秒
|
|
31
|
+
var RECONNECT_INTERVAL_MAX = 30000; // 最大重连间隔 30 秒
|
|
32
|
+
var HEARTBEAT_INTERVAL = 30000; // 心跳间隔 30 秒
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* IM WebSocket 客户端
|
|
36
|
+
*/
|
|
37
|
+
var IM = /*#__PURE__*/function () {
|
|
38
|
+
function IM(options) {
|
|
39
|
+
_classCallCheck(this, IM);
|
|
40
|
+
_defineProperty(this, "url", void 0);
|
|
41
|
+
_defineProperty(this, "appKey", void 0);
|
|
42
|
+
_defineProperty(this, "commonParams", void 0);
|
|
43
|
+
_defineProperty(this, "connectCallback", void 0);
|
|
44
|
+
_defineProperty(this, "token", void 0);
|
|
45
|
+
_defineProperty(this, "getToken", void 0);
|
|
46
|
+
_defineProperty(this, "ws", null);
|
|
47
|
+
_defineProperty(this, "eventListeners", new Map());
|
|
48
|
+
_defineProperty(this, "reconnectAttempts", 0);
|
|
49
|
+
_defineProperty(this, "reconnectTimer", null);
|
|
50
|
+
_defineProperty(this, "heartbeatTimer", null);
|
|
51
|
+
_defineProperty(this, "isManualClose", false);
|
|
52
|
+
_defineProperty(this, "isConnecting", false);
|
|
53
|
+
this.url = options.url;
|
|
54
|
+
this.appKey = options.appKey;
|
|
55
|
+
this.commonParams = options.commonParams;
|
|
56
|
+
this.connectCallback = options.connectCallback;
|
|
57
|
+
this.token = options.token;
|
|
58
|
+
this.getToken = options.getToken;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 注册事件监听器
|
|
63
|
+
*/
|
|
64
|
+
_createClass(IM, [{
|
|
65
|
+
key: "on",
|
|
66
|
+
value: function on(event, callback) {
|
|
67
|
+
if (!this.eventListeners.has(event)) {
|
|
68
|
+
this.eventListeners.set(event, []);
|
|
69
|
+
}
|
|
70
|
+
this.eventListeners.get(event).push(callback);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 触发事件
|
|
75
|
+
*/
|
|
76
|
+
}, {
|
|
77
|
+
key: "emit",
|
|
78
|
+
value: function emit(event, data) {
|
|
79
|
+
var listeners = this.eventListeners.get(event);
|
|
80
|
+
if (listeners) {
|
|
81
|
+
listeners.forEach(function (callback) {
|
|
82
|
+
try {
|
|
83
|
+
callback(data);
|
|
84
|
+
} catch (e) {
|
|
85
|
+
logger.error("\u4E8B\u4EF6 ".concat(event, " \u56DE\u8C03\u6267\u884C\u5931\u8D25"), e);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 建立连接
|
|
93
|
+
*/
|
|
94
|
+
}, {
|
|
95
|
+
key: "connect",
|
|
96
|
+
value: (function () {
|
|
97
|
+
var _connect = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
|
|
98
|
+
var _this = this;
|
|
99
|
+
var token, wsUrl;
|
|
100
|
+
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
101
|
+
while (1) switch (_context.prev = _context.next) {
|
|
102
|
+
case 0:
|
|
103
|
+
if (!this.isConnecting) {
|
|
104
|
+
_context.next = 3;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
logger.warn('正在连接中,跳过重复连接请求');
|
|
108
|
+
return _context.abrupt("return");
|
|
109
|
+
case 3:
|
|
110
|
+
this.isConnecting = true;
|
|
111
|
+
this.isManualClose = false;
|
|
112
|
+
_context.prev = 5;
|
|
113
|
+
// 获取 token
|
|
114
|
+
token = this.token;
|
|
115
|
+
if (!(!token && this.getToken)) {
|
|
116
|
+
_context.next = 11;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
_context.next = 10;
|
|
120
|
+
return this.getToken();
|
|
121
|
+
case 10:
|
|
122
|
+
token = _context.sent;
|
|
123
|
+
case 11:
|
|
124
|
+
// 构建 WebSocket URL
|
|
125
|
+
wsUrl = this.buildUrl(token);
|
|
126
|
+
logger.info('开始建立 WebSocket 连接', {
|
|
127
|
+
url: this.url
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// 创建 WebSocket 连接
|
|
131
|
+
this.ws = new WebSocket(wsUrl);
|
|
132
|
+
this.ws.onopen = function () {
|
|
133
|
+
var _this$connectCallback;
|
|
134
|
+
logger.info('WebSocket 连接已建立');
|
|
135
|
+
_this.isConnecting = false;
|
|
136
|
+
_this.reconnectAttempts = 0;
|
|
137
|
+
|
|
138
|
+
// 发送鉴权消息
|
|
139
|
+
_this.sendAuth(token);
|
|
140
|
+
|
|
141
|
+
// 启动心跳
|
|
142
|
+
_this.startHeartbeat();
|
|
143
|
+
|
|
144
|
+
// 触发连接回调
|
|
145
|
+
(_this$connectCallback = _this.connectCallback) === null || _this$connectCallback === void 0 || _this$connectCallback.call(_this);
|
|
146
|
+
};
|
|
147
|
+
this.ws.onmessage = function (event) {
|
|
148
|
+
try {
|
|
149
|
+
var _data = JSON.parse(event.data);
|
|
150
|
+
|
|
151
|
+
// 处理心跳响应
|
|
152
|
+
if (_data.type === 'pong' || _data.msgType === 'pong') {
|
|
153
|
+
logger.debug('收到心跳响应');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 触发消息事件
|
|
158
|
+
_this.emit('message', _data);
|
|
159
|
+
} catch (e) {
|
|
160
|
+
logger.error('消息解析失败', e);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
this.ws.onclose = function (event) {
|
|
164
|
+
logger.info('WebSocket 连接已关闭', {
|
|
165
|
+
code: event.code,
|
|
166
|
+
reason: event.reason,
|
|
167
|
+
wasClean: event.wasClean
|
|
168
|
+
});
|
|
169
|
+
_this.isConnecting = false;
|
|
170
|
+
_this.stopHeartbeat();
|
|
171
|
+
var closeInfo = {
|
|
172
|
+
code: event.wasClean ? 'CONNECTION_CLOSED_CLEANLY' : event.code,
|
|
173
|
+
reason: event.reason
|
|
174
|
+
};
|
|
175
|
+
_this.emit('close', closeInfo);
|
|
176
|
+
|
|
177
|
+
// 非手动关闭时尝试重连
|
|
178
|
+
if (!_this.isManualClose) {
|
|
179
|
+
_this.scheduleReconnect();
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
this.ws.onerror = function (error) {
|
|
183
|
+
logger.error('WebSocket 连接错误', error);
|
|
184
|
+
_this.isConnecting = false;
|
|
185
|
+
_this.emit('error', error);
|
|
186
|
+
};
|
|
187
|
+
_context.next = 26;
|
|
188
|
+
break;
|
|
189
|
+
case 20:
|
|
190
|
+
_context.prev = 20;
|
|
191
|
+
_context.t0 = _context["catch"](5);
|
|
192
|
+
this.isConnecting = false;
|
|
193
|
+
logger.error('建立连接失败', _context.t0);
|
|
194
|
+
this.emit('error', _context.t0);
|
|
195
|
+
this.scheduleReconnect();
|
|
196
|
+
case 26:
|
|
197
|
+
case "end":
|
|
198
|
+
return _context.stop();
|
|
199
|
+
}
|
|
200
|
+
}, _callee, this, [[5, 20]]);
|
|
201
|
+
}));
|
|
202
|
+
function connect() {
|
|
203
|
+
return _connect.apply(this, arguments);
|
|
204
|
+
}
|
|
205
|
+
return connect;
|
|
206
|
+
}()
|
|
207
|
+
/**
|
|
208
|
+
* 构建 WebSocket URL
|
|
209
|
+
*/
|
|
210
|
+
)
|
|
211
|
+
}, {
|
|
212
|
+
key: "buildUrl",
|
|
213
|
+
value: function buildUrl(token) {
|
|
214
|
+
var url = new URL(this.url);
|
|
215
|
+
|
|
216
|
+
// 添加通用参数
|
|
217
|
+
if (this.commonParams) {
|
|
218
|
+
Object.entries(this.commonParams).forEach(function (_ref) {
|
|
219
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
220
|
+
key = _ref2[0],
|
|
221
|
+
value = _ref2[1];
|
|
222
|
+
if (value !== undefined && value !== null) {
|
|
223
|
+
url.searchParams.set(key, String(value));
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 添加 appKey
|
|
229
|
+
if (this.appKey) {
|
|
230
|
+
url.searchParams.set('appKey', this.appKey);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// 添加 token
|
|
234
|
+
if (token) {
|
|
235
|
+
url.searchParams.set('token', token);
|
|
236
|
+
}
|
|
237
|
+
return url.toString();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 发送鉴权消息
|
|
242
|
+
*/
|
|
243
|
+
}, {
|
|
244
|
+
key: "sendAuth",
|
|
245
|
+
value: function sendAuth(token) {
|
|
246
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
var authMessage = _objectSpread({
|
|
250
|
+
type: 'auth',
|
|
251
|
+
appKey: this.appKey,
|
|
252
|
+
token: token
|
|
253
|
+
}, this.commonParams);
|
|
254
|
+
this.ws.send(JSON.stringify(authMessage));
|
|
255
|
+
logger.debug('已发送鉴权消息');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* 启动心跳
|
|
260
|
+
*/
|
|
261
|
+
}, {
|
|
262
|
+
key: "startHeartbeat",
|
|
263
|
+
value: function startHeartbeat() {
|
|
264
|
+
var _this2 = this;
|
|
265
|
+
this.stopHeartbeat();
|
|
266
|
+
this.heartbeatTimer = setInterval(function () {
|
|
267
|
+
if (_this2.ws && _this2.ws.readyState === WebSocket.OPEN) {
|
|
268
|
+
_this2.ws.send(JSON.stringify({
|
|
269
|
+
type: 'ping'
|
|
270
|
+
}));
|
|
271
|
+
logger.debug('发送心跳');
|
|
272
|
+
}
|
|
273
|
+
}, HEARTBEAT_INTERVAL);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* 停止心跳
|
|
278
|
+
*/
|
|
279
|
+
}, {
|
|
280
|
+
key: "stopHeartbeat",
|
|
281
|
+
value: function stopHeartbeat() {
|
|
282
|
+
if (this.heartbeatTimer) {
|
|
283
|
+
clearInterval(this.heartbeatTimer);
|
|
284
|
+
this.heartbeatTimer = null;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* 安排重连
|
|
290
|
+
*/
|
|
291
|
+
}, {
|
|
292
|
+
key: "scheduleReconnect",
|
|
293
|
+
value: function scheduleReconnect() {
|
|
294
|
+
var _this3 = this;
|
|
295
|
+
if (this.isManualClose) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// 计算重连间隔(指数退避)
|
|
300
|
+
var interval = Math.min(RECONNECT_INTERVAL_BASE * Math.pow(2, this.reconnectAttempts), RECONNECT_INTERVAL_MAX);
|
|
301
|
+
this.reconnectAttempts++;
|
|
302
|
+
logger.info("\u5C06\u5728 ".concat(interval, "ms \u540E\u5C1D\u8BD5\u7B2C ").concat(this.reconnectAttempts, " \u6B21\u91CD\u8FDE"));
|
|
303
|
+
|
|
304
|
+
// 触发重连事件
|
|
305
|
+
this.emit('reconnect', {
|
|
306
|
+
code: 'RECONNECTING',
|
|
307
|
+
err: null,
|
|
308
|
+
attempt: this.reconnectAttempts
|
|
309
|
+
});
|
|
310
|
+
this.reconnectTimer = setTimeout(function () {
|
|
311
|
+
_this3.connect();
|
|
312
|
+
}, interval);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* 关闭连接
|
|
317
|
+
*/
|
|
318
|
+
}, {
|
|
319
|
+
key: "close",
|
|
320
|
+
value: function close() {
|
|
321
|
+
this.isManualClose = true;
|
|
322
|
+
|
|
323
|
+
// 清除重连定时器
|
|
324
|
+
if (this.reconnectTimer) {
|
|
325
|
+
clearTimeout(this.reconnectTimer);
|
|
326
|
+
this.reconnectTimer = null;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// 停止心跳
|
|
330
|
+
this.stopHeartbeat();
|
|
331
|
+
|
|
332
|
+
// 关闭 WebSocket
|
|
333
|
+
if (this.ws) {
|
|
334
|
+
try {
|
|
335
|
+
this.ws.close(1000, 'Manual close');
|
|
336
|
+
} catch (e) {
|
|
337
|
+
logger.error('关闭 WebSocket 失败', e);
|
|
338
|
+
}
|
|
339
|
+
this.ws = null;
|
|
340
|
+
}
|
|
341
|
+
logger.info('WebSocket 连接已手动关闭');
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* 发送消息
|
|
346
|
+
*/
|
|
347
|
+
}, {
|
|
348
|
+
key: "send",
|
|
349
|
+
value: function send(data) {
|
|
350
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
351
|
+
logger.warn('WebSocket 未连接,无法发送消息');
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
var message = typeof data === 'string' ? data : JSON.stringify(data);
|
|
356
|
+
this.ws.send(message);
|
|
357
|
+
return true;
|
|
358
|
+
} catch (e) {
|
|
359
|
+
logger.error('发送消息失败', e);
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* 获取连接状态
|
|
366
|
+
*/
|
|
367
|
+
}, {
|
|
368
|
+
key: "getReadyState",
|
|
369
|
+
value: function getReadyState() {
|
|
370
|
+
var _this$ws$readyState, _this$ws;
|
|
371
|
+
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;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* 是否已连接
|
|
376
|
+
*/
|
|
377
|
+
}, {
|
|
378
|
+
key: "isConnected",
|
|
379
|
+
value: function isConnected() {
|
|
380
|
+
var _this$ws2;
|
|
381
|
+
return ((_this$ws2 = this.ws) === null || _this$ws2 === void 0 ? void 0 : _this$ws2.readyState) === WebSocket.OPEN;
|
|
382
|
+
}
|
|
383
|
+
}]);
|
|
384
|
+
return IM;
|
|
385
|
+
}();
|
|
386
|
+
export default IM;
|
package/es/utils/request.js
CHANGED
|
@@ -11,14 +11,18 @@ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
|
11
11
|
* @param options 请求配置
|
|
12
12
|
* @returns Promise<any>
|
|
13
13
|
*/
|
|
14
|
+
var DEFAULT_BASE_URL = 'https://api.ai-space.work';
|
|
14
15
|
export var customRequest = /*#__PURE__*/function () {
|
|
15
16
|
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(options) {
|
|
16
17
|
var method, url, query, _options$headers, headers, requestUrl, requestOptions, searchParams, queryString, response, data;
|
|
17
18
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
18
19
|
while (1) switch (_context.prev = _context.next) {
|
|
19
20
|
case 0:
|
|
20
|
-
method = options.method, url = options.url, query = options.query, _options$headers = options.headers, headers = _options$headers === void 0 ? {} : _options$headers;
|
|
21
|
+
method = options.method, url = options.url, query = options.query, _options$headers = options.headers, headers = _options$headers === void 0 ? {} : _options$headers; // 如果 URL 是相对路径,添加默认前缀
|
|
21
22
|
requestUrl = url;
|
|
23
|
+
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
|
24
|
+
requestUrl = "".concat(DEFAULT_BASE_URL).concat(url.startsWith('/') ? '' : '/').concat(url);
|
|
25
|
+
}
|
|
22
26
|
requestOptions = {
|
|
23
27
|
method: method,
|
|
24
28
|
credentials: 'include',
|
|
@@ -39,7 +43,7 @@ export var customRequest = /*#__PURE__*/function () {
|
|
|
39
43
|
}
|
|
40
44
|
});
|
|
41
45
|
queryString = searchParams.toString();
|
|
42
|
-
requestUrl =
|
|
46
|
+
requestUrl = requestUrl.includes('?') ? "".concat(requestUrl, "&").concat(queryString) : "".concat(requestUrl, "?").concat(queryString);
|
|
43
47
|
}
|
|
44
48
|
} else {
|
|
45
49
|
// POST/PUT/DELETE 请求:将 query 作为请求体
|
|
@@ -47,26 +51,26 @@ export var customRequest = /*#__PURE__*/function () {
|
|
|
47
51
|
requestOptions.body = JSON.stringify(query);
|
|
48
52
|
}
|
|
49
53
|
}
|
|
50
|
-
_context.prev =
|
|
51
|
-
_context.next =
|
|
54
|
+
_context.prev = 5;
|
|
55
|
+
_context.next = 8;
|
|
52
56
|
return fetch(requestUrl, requestOptions);
|
|
53
|
-
case
|
|
57
|
+
case 8:
|
|
54
58
|
response = _context.sent;
|
|
55
|
-
_context.next =
|
|
59
|
+
_context.next = 11;
|
|
56
60
|
return response.json();
|
|
57
|
-
case
|
|
61
|
+
case 11:
|
|
58
62
|
data = _context.sent;
|
|
59
63
|
return _context.abrupt("return", data);
|
|
60
|
-
case
|
|
61
|
-
_context.prev =
|
|
62
|
-
_context.t0 = _context["catch"](
|
|
64
|
+
case 15:
|
|
65
|
+
_context.prev = 15;
|
|
66
|
+
_context.t0 = _context["catch"](5);
|
|
63
67
|
console.error('Request failed:', _context.t0);
|
|
64
68
|
throw _context.t0;
|
|
65
|
-
case
|
|
69
|
+
case 19:
|
|
66
70
|
case "end":
|
|
67
71
|
return _context.stop();
|
|
68
72
|
}
|
|
69
|
-
}, _callee, null, [[
|
|
73
|
+
}, _callee, null, [[5, 15]]);
|
|
70
74
|
}));
|
|
71
75
|
return function customRequest(_x) {
|
|
72
76
|
return _ref.apply(this, arguments);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paul-ai-assistant",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Paul AI 智能辅助组件",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Magic Workbench",
|
|
@@ -124,6 +124,7 @@
|
|
|
124
124
|
"@types/react": "~16.14.56",
|
|
125
125
|
"@types/react-dom": "~16.9.24",
|
|
126
126
|
"@umijs/plugins": "^4.3.1",
|
|
127
|
+
"axios": "^1.13.2",
|
|
127
128
|
"babel-plugin-import": "^1.13.8",
|
|
128
129
|
"dumi": "^2.4.3",
|
|
129
130
|
"enzyme": "^3.11.0",
|