@flexem/chat-box 1.0.0 → 1.0.1

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 CHANGED
@@ -105,12 +105,10 @@ npm run build
105
105
  ```xml
106
106
  <chat-box
107
107
  idsServiceUrl="{{idsServiceUrl}}"
108
- userToken="{{userToken}}"
108
+ isToken="{{isToken}}"
109
+ data="{{data}}"
109
110
  userInfo="{{userInfo}}"
110
- voiceToText="{{voiceToText}}"
111
111
  speechRecognitionManager="{{speechRecognitionManager}}"
112
- textToVoice="{{textToVoice}}"
113
- bind:back="onBack"
114
112
  bind:login="onLogin"
115
113
  />
116
114
  ```
@@ -118,13 +116,21 @@ npm run build
118
116
  #### 3.2 JavaScript
119
117
 
120
118
  ```javascript
119
+ const plugin = requirePlugin('WechatSI');
120
+ const manager = plugin.getRecordRecognitionManager();
121
+
121
122
  Page({
122
123
  data: {
123
124
  // IDS 服务地址(必填)
124
125
  idsServiceUrl: 'https://ids-dev.platform.flexem.net',
125
126
 
126
- // 用户 Token(必填)
127
- userToken: '',
127
+ // 是否为 Token(必填)
128
+ // true: data 是 Token,直接使用
129
+ // false: data 是加密数据,需要组件内部解析
130
+ isToken: false,
131
+
132
+ // Token 或加密数据(必填)
133
+ data: '',
128
134
 
129
135
  // 用户信息(必填)
130
136
  userInfo: {
@@ -132,37 +138,35 @@ Page({
132
138
  avatar: 'https://example.com/avatar.jpg'
133
139
  },
134
140
 
135
- // 语音转文字函数(可选)
136
- voiceToText: null,
137
-
138
- // 语音识别管理器(可选)
139
- speechRecognitionManager: null,
140
-
141
- // 文字转语音函数(可选)
142
- textToVoice: null
141
+ // 语音识别管理器(必填,用于语音输入)
142
+ speechRecognitionManager: null
143
143
  },
144
144
 
145
145
  onLoad() {
146
- // 初始化用户信息和 Token
147
- this.initUserInfo();
146
+ // 初始化语音识别
147
+ if (plugin && manager) {
148
+ this.setData({
149
+ speechRecognitionManager: manager
150
+ });
151
+ }
148
152
 
149
- // 初始化语音功能(可选)
150
- this.initVoiceFeatures();
153
+ // 初始化用户信息
154
+ this.initUserInfo();
151
155
  },
152
156
 
153
157
  // 初始化用户信息
154
158
  initUserInfo() {
155
159
  // 从缓存或登录接口获取用户信息
160
+ const data = wx.getStorageSync('data');
156
161
  const userInfo = wx.getStorageSync('userInfo');
157
- const userToken = wx.getStorageSync('userToken');
158
162
 
159
- if (userInfo && userToken) {
163
+ if (data && userInfo) {
160
164
  this.setData({
165
+ data: data,
161
166
  userInfo: {
162
167
  name: userInfo.nickName || userInfo.name,
163
168
  avatar: userInfo.avatarUrl || userInfo.avatar
164
- },
165
- userToken: userToken
169
+ }
166
170
  });
167
171
  } else {
168
172
  // 未登录,跳转到登录页
@@ -170,70 +174,6 @@ Page({
170
174
  }
171
175
  },
172
176
 
173
- // 初始化语音功能(可选)
174
- initVoiceFeatures() {
175
- // 1. 引入微信同声传译插件(边录边识别)
176
- const plugin = requirePlugin('WechatSI');
177
- const manager = plugin.getRecordRecognitionManager();
178
-
179
- this.setData({
180
- speechRecognitionManager: manager
181
- });
182
-
183
- // 2. 设置语音转文字函数(长按录音后识别)
184
- this.setData({
185
- voiceToText: (options) => {
186
- plugin.textToSpeech({
187
- lang: 'zh_CN',
188
- tts: true,
189
- content: options.content,
190
- success: (res) => {
191
- if (options.success) {
192
- options.success(res);
193
- }
194
- },
195
- fail: (err) => {
196
- if (options.fail) {
197
- options.fail(err);
198
- }
199
- }
200
- });
201
- }
202
- });
203
-
204
- // 3. 设置文字转语音函数(可选,不传则使用内置)
205
- this.setData({
206
- textToVoice: (options) => {
207
- plugin.textToSpeech({
208
- lang: 'zh_CN',
209
- tts: true,
210
- content: options.content,
211
- success: (res) => {
212
- if (options.success) {
213
- options.success({ src: res.filename });
214
- }
215
- },
216
- fail: (err) => {
217
- if (options.fail) {
218
- options.fail(err);
219
- }
220
- }
221
- });
222
- }
223
- });
224
- },
225
-
226
- // 返回事件
227
- onBack() {
228
- wx.navigateBack({
229
- fail: () => {
230
- wx.switchTab({
231
- url: '/pages/index/index'
232
- });
233
- }
234
- });
235
- },
236
-
237
177
  // 登录事件
238
178
  onLogin() {
239
179
  wx.navigateTo({
@@ -248,42 +188,35 @@ Page({
248
188
  | 属性名 | 类型 | 必填 | 默认值 | 说明 |
249
189
  |--------|------|------|--------|------|
250
190
  | idsServiceUrl | String | 是 | - | IDS 服务地址,用于获取 serviceUrls 配置 |
251
- | userToken | String | 是 | - | 用户认证 Token |
191
+ | data | String | 是 | - | Token 或加密数据(根据 isToken 决定) |
192
+ | isToken | Boolean | 否 | true | true: data 是 Token 直接使用;false: data 是加密数据需解析 |
252
193
  | userInfo | Object | 是 | `{name:'', avatar:''}` | 用户信息对象 |
253
- | voiceToText | Function | 否 | null | 语音转文字函数(长按录音后识别) |
254
194
  | speechRecognitionManager | Object | 否 | null | 语音识别管理器(边录边识别) |
255
- | textToVoice | Function | 否 | null | 文字转语音函数,不传则使用内置 TTS |
256
195
 
257
- ### userInfo 对象结构
196
+ ### data 参数说明
197
+
198
+ 组件支持两种传参方式:
258
199
 
200
+ **方式一:直接传 Token(默认)**
259
201
  ```javascript
260
- {
261
- name: '用户昵称', // 用户名称
262
- avatar: 'https://...' // 用户头像 URL
263
- }
202
+ // isToken 默认为 true,data 直接作为 Token 使用
203
+ data: 'your-access-token',
204
+ isToken: true // 可省略
264
205
  ```
265
206
 
266
- ### voiceToText 函数签名
267
-
207
+ **方式二:传加密数据(由组件内部解析)**
268
208
  ```javascript
269
- function voiceToText(options) {
270
- // options: {
271
- // content: '要转换的文本',
272
- // success: (res) => { /* res.src: 音频文件路径 */ },
273
- // fail: (err) => { /* 错误处理 */ }
274
- // }
275
- }
209
+ // isToken 为 false 时,组件会调用 IDS 接口解析 data 获取 Token
210
+ data: 'encrypted-data-string',
211
+ isToken: false
276
212
  ```
277
213
 
278
- ### textToVoice 函数签名
214
+ ### userInfo 对象结构
279
215
 
280
216
  ```javascript
281
- function textToVoice(options) {
282
- // options: {
283
- // content: '要播放的文本',
284
- // success: (res) => { /* res.src: 音频文件路径 */ },
285
- // fail: (err) => { /* 错误处理 */ }
286
- // }
217
+ {
218
+ name: '用户昵称', // 用户名称(必填)
219
+ avatar: 'https://...' // 用户头像 URL(选填)
287
220
  }
288
221
  ```
289
222
 
@@ -381,19 +314,19 @@ X-Access-Token: Bearer {userToken}
381
314
  - 组件使用自定义导航栏,页面必须设置 `"navigationStyle": "custom"`
382
315
  - 组件会自动适配不同机型的状态栏和胶囊按钮位置
383
316
 
384
- ### 2. Token 管理
317
+ ### 2. Token / 数据管理
385
318
 
386
319
  - Token 失效时会触发 `bind:login` 事件
387
320
  - 建议在主程序中统一管理 Token 的刷新和存储
388
- - Token 格式:`Bearer {token}`
321
+ - 支持两种传参方式:
322
+ - `isToken: true` - data 直接作为 Token 使用
323
+ - `isToken: false` - data 是加密数据,组件会调用 IDS 接口解析
389
324
 
390
325
  ### 3. 语音功能
391
326
 
392
- - 语音功能为可选功能,不传相关参数则不显示语音按钮
393
327
  - 使用微信同声传译插件需要在小程序后台添加插件
394
- - `speechRecognitionManager` 用于边录边识别(实时显示)
395
- - `voiceToText` 用于录音完成后识别
396
- - `textToVoice` 用于 AI 回复的语音播放
328
+ - `speechRecognitionManager` 用于边录边识别(实时显示识别结果)
329
+ - 组件内置 TTS 功能用于 AI 回复的语音播放
397
330
 
398
331
  ### 4. 文件上传
399
332
 
@@ -507,7 +440,8 @@ npm install @flexem/chat-box
507
440
  ```xml
508
441
  <chat-box
509
442
  idsServiceUrl="{{idsServiceUrl}}"
510
- userToken="{{userToken}}"
443
+ isToken="{{isToken}}"
444
+ data="{{data}}"
511
445
  userInfo="{{userInfo}}"
512
446
  speechRecognitionManager="{{speechRecognitionManager}}"
513
447
  bind:login="onNeedLogin"
@@ -524,9 +458,11 @@ Page({
524
458
  data: {
525
459
  speechRecognitionManager: null,
526
460
  idsServiceUrl: 'https://ids-dev.platform.flexem.net',
527
- userToken: '',
461
+ isToken: false, // false 表示 data 是加密数据,需要解析
462
+ data: '', // Token 或加密数据
528
463
  userInfo: {
529
- name: ''
464
+ name: '',
465
+ avatar: ''
530
466
  }
531
467
  },
532
468
 
@@ -551,12 +487,12 @@ Page({
551
487
  * 加载用户认证信息
552
488
  */
553
489
  loadUserAuth() {
554
- const token = wx.getStorageSync('userToken') || '';
555
- const userInfo = wx.getStorageSync('userInfo') || { name: '' };
490
+ const data = wx.getStorageSync('data') || '';
491
+ const userInfo = wx.getStorageSync('userInfo') || { name: '', avatar: '' };
556
492
 
557
- if (token) {
493
+ if (data) {
558
494
  this.setData({
559
- userToken: token,
495
+ data: data,
560
496
  userInfo: userInfo
561
497
  });
562
498
  }
@@ -615,8 +551,9 @@ https://blobstorage-dev.platform.flexem.net
615
551
  | 参数 | 说明 | 示例 |
616
552
  |------|------|------|
617
553
  | idsServiceUrl | IDS 认证服务地址 | `https://ids-dev.platform.flexem.net` |
618
- | userToken | 用户登录后的 Token | 从登录接口获取,存储在 `wx.setStorageSync('userToken', token)` |
619
- | userInfo | 用户信息对象 | `{ name: '用户昵称' }` |
554
+ | data | Token 或加密数据 | 从登录接口获取 |
555
+ | isToken | data 类型标识 | `true`(data Token)或 `false`(data 是加密数据) |
556
+ | userInfo | 用户信息对象 | `{ name: '用户昵称', avatar: '头像URL' }` |
620
557
  | speechRecognitionManager | 语音识别管理器 | 通过 `plugin.getRecordRecognitionManager()` 获取 |
621
558
 
622
559
  ### 必须监听的事件
@@ -627,12 +564,15 @@ https://blobstorage-dev.platform.flexem.net
627
564
 
628
565
  ### 完成
629
566
 
630
- 按照以上步骤配置完成后,即可正常使用聊天组件。用户登录后将 Token 存储到本地:
567
+ 按照以上步骤配置完成后,即可正常使用聊天组件。用户登录后将数据存储到本地:
631
568
 
632
569
  ```javascript
633
- // 登录成功后
634
- wx.setStorageSync('userToken', response.token);
635
- wx.setStorageSync('userInfo', { name: response.userName });
570
+ // 登录成功后存储数据
571
+ wx.setStorageSync('data', response.token); // 或加密数据
572
+ wx.setStorageSync('userInfo', {
573
+ name: response.userName,
574
+ avatar: response.avatarUrl
575
+ });
636
576
  ```
637
577
 
638
578
  然后跳转到聊天页面即可开始使用。
@@ -26,11 +26,16 @@ Component({
26
26
  type: String,
27
27
  value: ''
28
28
  },
29
- // 用户 Token
30
- userToken: {
29
+ // 数据(可以是 token 或加密数据)
30
+ data: {
31
31
  type: String,
32
32
  value: ''
33
33
  },
34
+ // 是否为 Token(true: data 是 token,false: data 是加密数据需要解析)
35
+ isToken: {
36
+ type: Boolean,
37
+ value: true
38
+ },
34
39
  // 用户信息
35
40
  userInfo: {
36
41
  type: Object,
@@ -60,6 +65,9 @@ Component({
60
65
  * 组件的初始数据
61
66
  */
62
67
  data: {
68
+ // 用户 Token(从 properties.data 解析或直接使用)
69
+ userToken: '',
70
+
63
71
  // 界面状态
64
72
  showSidebar: false, // 侧边栏显示状态
65
73
  showDropdown: false, // 下拉菜单显示状态
@@ -130,8 +138,11 @@ Component({
130
138
  });
131
139
  });
132
140
 
133
- // 加载服务配置
134
- this.loadServiceUrls();
141
+ // 初始化 Token,完成后再加载服务配置
142
+ this.initToken().then(() => {
143
+ // Token 初始化完成后,加载服务配置
144
+ this.loadServiceUrls();
145
+ });
135
146
  },
136
147
  detached() {
137
148
  // 销毁音频播放器
@@ -172,6 +183,51 @@ Component({
172
183
  });
173
184
  },
174
185
 
186
+ /**
187
+ * 初始化 Token
188
+ * 根据 isToken 参数决定是直接使用 data 还是调用接口解析
189
+ */
190
+ async initToken() {
191
+ const { data, isToken, idsServiceUrl } = this.properties;
192
+
193
+ if (!data) {
194
+ console.log('[ChatBox] 未提供 data 参数');
195
+ return;
196
+ }
197
+
198
+ if (isToken) {
199
+ // data 就是 token,直接使用
200
+ this.setData({ userToken: data });
201
+ console.log('[ChatBox] 使用直接传入的 Token');
202
+ } else {
203
+ // data 是加密数据,需要调用接口解析
204
+ if (!idsServiceUrl) {
205
+ console.error('[ChatBox] isToken 为 false 时必须提供 idsServiceUrl');
206
+ return;
207
+ }
208
+
209
+ try {
210
+ console.log('[ChatBox] 开始解析加密数据...');
211
+ const result = await api.parseData(idsServiceUrl, data);
212
+
213
+ if (result && result.token && result.token.accessToken) {
214
+ const accessToken = result.token.accessToken;
215
+ this.setData({ userToken: accessToken });
216
+ console.log('[ChatBox] Token 解析成功');
217
+
218
+ // 可以在这里保存 token 到本地存储(如果需要)
219
+ // storage.setToken(accessToken);
220
+ } else {
221
+ console.error('[ChatBox] 解析结果中未找到 token');
222
+ this.triggerEvent('login');
223
+ }
224
+ } catch (error) {
225
+ console.error('[ChatBox] 解析加密数据失败:', error);
226
+ this.triggerEvent('login');
227
+ }
228
+ }
229
+ },
230
+
175
231
  /**
176
232
  * 键盘高度变化
177
233
  */
@@ -222,14 +278,14 @@ Component({
222
278
  * 加载服务配置
223
279
  */
224
280
  async loadServiceUrls() {
225
- if (!this.properties.idsServiceUrl || !this.properties.userToken) {
281
+ if (!this.properties.idsServiceUrl || !this.data.userToken) {
226
282
  return;
227
283
  }
228
284
 
229
285
  try {
230
286
  const result = await api.getServiceUrls(
231
287
  this.properties.idsServiceUrl,
232
- this.properties.userToken
288
+ this.data.userToken
233
289
  );
234
290
 
235
291
  this.setData({
@@ -443,7 +499,7 @@ Component({
443
499
  // 获取聊天历史
444
500
  const result = await api.getChatHistories(
445
501
  this.getAiChatUrl(),
446
- this.properties.userToken,
502
+ this.data.userToken,
447
503
  sessionId,
448
504
  1,
449
505
  20
@@ -510,7 +566,7 @@ Component({
510
566
  try {
511
567
  const result = await api.getChatHistories(
512
568
  this.getAiChatUrl(),
513
- this.properties.userToken,
569
+ this.data.userToken,
514
570
  this.data.currentSession.id,
515
571
  this.data.historyPage,
516
572
  20
@@ -627,7 +683,7 @@ Component({
627
683
  if (!content && (!attachments || attachments.length === 0)) return;
628
684
 
629
685
  // 检查登录状态
630
- if (!this.getAiChatUrl() || !this.properties.userToken) {
686
+ if (!this.getAiChatUrl() || !this.data.userToken) {
631
687
  this.triggerEvent('login');
632
688
  return;
633
689
  }
@@ -668,7 +724,7 @@ Component({
668
724
  try {
669
725
  const result = await api.createChatSession(
670
726
  this.getAiChatUrl(),
671
- this.properties.userToken,
727
+ this.data.userToken,
672
728
  firstMessage.substring(0, 20) + (firstMessage.length > 20 ? '...' : ''),
673
729
  {
674
730
  deepThinking: this.data.settings.deepThinking,
@@ -728,7 +784,7 @@ Component({
728
784
 
729
785
  this.currentRequest = api.sendChatMessage({
730
786
  baseUrl: this.getAiChatUrl(),
731
- token: this.properties.userToken,
787
+ token: this.data.userToken,
732
788
  sessionId: this.data.currentSession.id,
733
789
  messages: messagesForApi,
734
790
  settings: {
@@ -853,7 +909,7 @@ Component({
853
909
  try {
854
910
  const result = await api.updateSessionTitle(
855
911
  this.getAiChatUrl(),
856
- this.properties.userToken,
912
+ this.data.userToken,
857
913
  this.data.currentSession.id,
858
914
  userQuestion,
859
915
  aiAnswer
@@ -952,7 +1008,7 @@ Component({
952
1008
  try {
953
1009
  await api.deleteChatHistoriesByTime(
954
1010
  this.getAiChatUrl(),
955
- this.properties.userToken,
1011
+ this.data.userToken,
956
1012
  this.data.currentSession.id,
957
1013
  chatHistoryTime
958
1014
  );
@@ -454,6 +454,23 @@ function searchChats(baseUrl, token, keyword) {
454
454
  });
455
455
  }
456
456
 
457
+ /**
458
+ * 解析加密数据获取 Token
459
+ * @param {string} idsServiceUrl - IDS 服务地址
460
+ * @param {string} encryptedData - 加密的数据
461
+ * @returns {Promise<Object>} - 返回包含 token 信息的对象
462
+ */
463
+ function parseData(idsServiceUrl, encryptedData) {
464
+ return request({
465
+ url: `${idsServiceUrl}/api/noauth/integrated-login/parse-data`,
466
+ method: 'POST',
467
+ data: {
468
+ data: encryptedData,
469
+ token: ''
470
+ }
471
+ });
472
+ }
473
+
457
474
  module.exports = {
458
475
  generateMsgId,
459
476
  getServiceUrls,
@@ -470,5 +487,6 @@ module.exports = {
470
487
  parseFileContent,
471
488
  getChatSetting,
472
489
  updateSessionTitle,
473
- searchChats
490
+ searchChats,
491
+ parseData
474
492
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flexem/chat-box",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "chat box",
5
5
  "main": "miniprogram_dist/index.js",
6
6
  "miniprogram": "miniprogram_dist",