@syfei49/mini-dynamic-renderer 1.0.7 → 1.2.0

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.
@@ -1,297 +1,497 @@
1
- var requestAdapter = require('../adapters/request');
2
- var parser = require('./parser');
3
- var event = require('../event');
4
- var configModule = require('../config');
5
-
6
- var state = {
7
- messages: [],
8
- conversationId: '',
9
- loading: false,
10
- uploading: false,
11
- iconPickMode: false,
12
- pendingIconCategory: null,
13
- pendingImageUrl: '',
14
- inputText: ''
15
- };
16
-
17
- var quickQuestions = [
18
- '你好,你能帮我做什么?',
19
- '在「保健品」下新增二级分类:维生素,排序0',
20
- '帮我新增一级分类 保健品3'
21
- ];
22
-
23
- function reset() {
24
- state.messages = [];
25
- state.conversationId = '';
26
- state.loading = false;
27
- state.uploading = false;
28
- state.iconPickMode = false;
29
- state.pendingIconCategory = null;
30
- state.pendingImageUrl = '';
31
- state.inputText = '';
32
- }
33
-
34
- function ensureLogin() {
35
- var config = configModule.getConfig();
36
- if (!config.requireLogin) {
37
- return true;
38
- }
39
- var token = typeof config.getToken === 'function' ? config.getToken() : '';
40
- if (token) {
41
- return true;
42
- }
43
- uni.showToast({
44
- title: '请先登录',
45
- icon: 'none'
46
- });
47
- setTimeout(function () {
48
- uni.navigateTo({
49
- url: config.loginPage
50
- });
51
- }, 800);
52
- return false;
53
- }
54
-
55
- function notifyUpdate() {
56
- event.emit('chat:update', getSnapshot());
57
- }
58
-
59
- function getSnapshot() {
60
- return {
61
- messages: state.messages.slice(),
62
- loading: state.loading,
63
- uploading: state.uploading,
64
- iconPickMode: state.iconPickMode,
65
- pendingIconCategory: state.pendingIconCategory,
66
- pendingImageUrl: state.pendingImageUrl,
67
- inputText: state.inputText,
68
- quickQuestions: quickQuestions.slice()
69
- };
70
- }
71
-
72
- function createAssistantMessage(content) {
73
- var parsed = parser.parseAssistantMessage(content);
74
- return {
75
- role: 'assistant',
76
- content: parsed.content,
77
- imageUrls: parsed.imageUrls
78
- };
79
- }
80
-
81
- function handleAssistantAnswer(answer) {
82
- var needIcon = parser.parseNeedIcon(answer);
83
- if (needIcon) {
84
- state.pendingIconCategory = {
85
- name: needIcon.name,
86
- sort: needIcon.sort
87
- };
88
- state.iconPickMode = true;
89
- state.messages.push({
90
- role: 'assistant',
91
- content: needIcon.msg,
92
- imageUrls: []
93
- });
94
- notifyUpdate();
95
- return;
96
- }
97
- state.iconPickMode = false;
98
- state.pendingIconCategory = null;
99
- state.messages.push(createAssistantMessage(answer));
100
- notifyUpdate();
101
- }
102
-
103
- function setInputText(text) {
104
- state.inputText = text;
105
- notifyUpdate();
106
- }
107
-
108
- function clearPendingImage() {
109
- state.pendingImageUrl = '';
110
- notifyUpdate();
111
- }
112
-
113
- function chooseImage() {
114
- if (state.loading || state.uploading || state.iconPickMode) {
115
- return Promise.resolve();
116
- }
117
- return new Promise(function (resolve, reject) {
118
- uni.chooseImage({
119
- count: 1,
120
- sizeType: ['compressed'],
121
- sourceType: ['album', 'camera'],
122
- success: function (chooseRes) {
123
- var filePath = chooseRes.tempFilePaths && chooseRes.tempFilePaths[0];
124
- if (!filePath) {
125
- reject(new Error('未选择图片'));
126
- return;
127
- }
128
- state.uploading = true;
129
- notifyUpdate();
130
- requestAdapter.uploadImage(filePath)
131
- .then(function (imageUrl) {
132
- state.pendingImageUrl = imageUrl;
133
- state.uploading = false;
134
- notifyUpdate();
135
- resolve(imageUrl);
136
- })
137
- .catch(function (error) {
138
- state.uploading = false;
139
- notifyUpdate();
140
- reject(error);
141
- });
142
- },
143
- fail: function (err) {
144
- reject(err || new Error('选择图片失败'));
145
- }
146
- });
147
- });
148
- }
149
-
150
- function pickCategoryIcon(source) {
151
- if (state.loading || state.uploading || !state.pendingIconCategory) {
152
- return Promise.resolve();
153
- }
154
- if (!ensureLogin()) {
155
- return Promise.resolve();
156
- }
157
- var sourceType = source === 'camera' ? ['camera'] : ['album'];
158
- return new Promise(function (resolve, reject) {
159
- uni.chooseImage({
160
- count: 1,
161
- sizeType: ['compressed'],
162
- sourceType: sourceType,
163
- success: function (chooseRes) {
164
- var filePath = chooseRes.tempFilePaths && chooseRes.tempFilePaths[0];
165
- if (!filePath) {
166
- reject(new Error('未选择图片'));
167
- return;
168
- }
169
- state.uploading = true;
170
- notifyUpdate();
171
- requestAdapter.uploadImage(filePath)
172
- .then(function (imageUrl) {
173
- var category = state.pendingIconCategory;
174
- var query = '新增一级分类:' + category.name + ',排序' + category.sort + ',图标 ' + imageUrl;
175
- state.iconPickMode = false;
176
- state.pendingIconCategory = null;
177
- state.uploading = false;
178
- notifyUpdate();
179
- return sendMessage(query, imageUrl, '[图片] ' + category.name);
180
- })
181
- .then(function () {
182
- resolve();
183
- })
184
- .catch(function (error) {
185
- state.uploading = false;
186
- notifyUpdate();
187
- reject(error);
188
- });
189
- },
190
- fail: function (err) {
191
- reject(err || new Error('选择图片失败'));
192
- }
193
- });
194
- });
195
- }
196
-
197
- function cancelIconPick() {
198
- state.iconPickMode = false;
199
- state.pendingIconCategory = null;
200
- notifyUpdate();
201
- }
202
-
203
- function sendQuick(text) {
204
- state.inputText = text;
205
- notifyUpdate();
206
- return handleSend();
207
- }
208
-
209
- function sendMessage(query, imageUrl, displayContent) {
210
- if (!ensureLogin()) {
211
- return Promise.resolve();
212
- }
213
- state.messages.push({
214
- role: 'user',
215
- content: displayContent || query,
216
- imageUrls: imageUrl ? [imageUrl] : []
217
- });
218
- state.loading = true;
219
- notifyUpdate();
220
-
221
- return requestAdapter.sendChat({
222
- conversationId: state.conversationId || undefined,
223
- query: query || undefined,
224
- imageUrl: imageUrl || undefined
225
- })
226
- .then(function (res) {
227
- var data = res && res.data ? res.data : res;
228
- if (data.conversationId) {
229
- state.conversationId = data.conversationId;
230
- }
231
- state.loading = false;
232
- handleAssistantAnswer(data.answer || '暂无回复');
233
- })
234
- .catch(function (error) {
235
- state.loading = false;
236
- state.messages.push(createAssistantMessage(error && (error.msg || error.message) ? (error.msg || error.message) : '发送失败,请稍后重试'));
237
- notifyUpdate();
238
- });
239
- }
240
-
241
- function handleSend() {
242
- var query = (state.inputText || '').trim();
243
- var imageUrl = state.pendingImageUrl;
244
- if ((!query && !imageUrl) || state.loading || state.uploading || state.iconPickMode) {
245
- return Promise.resolve();
246
- }
247
- var displayContent = query || (imageUrl ? '[图片]' : '');
248
- state.inputText = '';
249
- state.pendingImageUrl = '';
250
- notifyUpdate();
251
- return sendMessage(query, imageUrl, displayContent);
252
- }
253
-
254
- function openConversation() {
255
- if (!ensureLogin()) {
256
- return false;
257
- }
258
- event.emit('chat:open');
259
- return true;
260
- }
261
-
262
- function closeConversation() {
263
- event.emit('chat:close');
264
- }
265
-
266
- module.exports = {
267
- quickQuestions: quickQuestions,
268
- reset: reset,
269
- getSnapshot: getSnapshot,
270
- setInputText: setInputText,
271
- clearPendingImage: clearPendingImage,
272
- chooseImage: chooseImage,
273
- pickCategoryIcon: pickCategoryIcon,
274
- cancelIconPick: cancelIconPick,
275
- sendQuick: sendQuick,
276
- handleSend: handleSend,
277
- openConversation: openConversation,
278
- closeConversation: closeConversation,
279
- onUpdate: function (handler) {
280
- event.on('chat:update', handler);
281
- },
282
- offUpdate: function (handler) {
283
- event.off('chat:update', handler);
284
- },
285
- onOpen: function (handler) {
286
- event.on('chat:open', handler);
287
- },
288
- offOpen: function (handler) {
289
- event.off('chat:open', handler);
290
- },
291
- onClose: function (handler) {
292
- event.on('chat:close', handler);
293
- },
294
- offClose: function (handler) {
295
- event.off('chat:close', handler);
296
- }
297
- };
1
+ var requestAdapter = require('../adapters/request');
2
+ var parser = require('./parser');
3
+ var event = require('../event');
4
+ var configModule = require('../config');
5
+
6
+ var state = {
7
+ messages: [],
8
+ conversationId: '',
9
+ loading: false,
10
+ uploading: false,
11
+ iconPickMode: false,
12
+ pendingIconCategory: null,
13
+ pendingImageUrl: '',
14
+ inputText: '',
15
+ renderConfig: null,
16
+ pendingInputs: {},
17
+ lastUserQuery: ''
18
+ };
19
+
20
+ var quickQuestions = [
21
+ '你好,你能帮我做什么?',
22
+ '帮我新增商品',
23
+ '上架商品:杏',
24
+ '在「保健品」下新增二级分类:维生素,排序0'
25
+ ];
26
+
27
+ function reset() {
28
+ state.messages = [];
29
+ state.conversationId = '';
30
+ state.loading = false;
31
+ state.uploading = false;
32
+ state.iconPickMode = false;
33
+ state.pendingIconCategory = null;
34
+ state.pendingImageUrl = '';
35
+ state.inputText = '';
36
+ state.renderConfig = null;
37
+ state.pendingInputs = {};
38
+ state.lastUserQuery = '';
39
+ }
40
+
41
+ function ensureLogin() {
42
+ var config = configModule.getConfig();
43
+ if (!config.requireLogin) {
44
+ return true;
45
+ }
46
+ var token = typeof config.getToken === 'function' ? config.getToken() : '';
47
+ if (token) {
48
+ return true;
49
+ }
50
+ uni.showToast({
51
+ title: '请先登录',
52
+ icon: 'none'
53
+ });
54
+ setTimeout(function () {
55
+ uni.navigateTo({
56
+ url: config.loginPage
57
+ });
58
+ }, 800);
59
+ return false;
60
+ }
61
+
62
+ function notifyUpdate() {
63
+ event.emit('chat:update', getSnapshot());
64
+ }
65
+
66
+ function getSnapshot() {
67
+ return {
68
+ messages: state.messages.slice(),
69
+ loading: state.loading,
70
+ uploading: state.uploading,
71
+ iconPickMode: state.iconPickMode,
72
+ pendingIconCategory: state.pendingIconCategory,
73
+ pendingImageUrl: state.pendingImageUrl,
74
+ inputText: state.inputText,
75
+ renderConfig: state.renderConfig,
76
+ pendingInputs: Object.assign({}, state.pendingInputs),
77
+ quickQuestions: quickQuestions.slice()
78
+ };
79
+ }
80
+
81
+ function createAssistantMessage(content) {
82
+ var parsed = parser.parseAssistantMessage(content);
83
+ return {
84
+ role: 'assistant',
85
+ content: parsed.content,
86
+ imageUrls: parsed.imageUrls
87
+ };
88
+ }
89
+
90
+ function appendActionResultMessage(actionResult) {
91
+ if (!actionResult) {
92
+ return;
93
+ }
94
+ var text = '';
95
+ try {
96
+ var result = typeof actionResult === 'string' ? JSON.parse(actionResult) : actionResult;
97
+ if (result && (result.code === 200 || result.success === true)) {
98
+ text = result.msg || result.message || '操作已成功完成';
99
+ } else if (result && (result.msg || result.message)) {
100
+ text = result.msg || result.message;
101
+ }
102
+ } catch (error) {
103
+ text = String(actionResult);
104
+ }
105
+ if (text) {
106
+ state.messages.push(createAssistantMessage(text));
107
+ }
108
+ }
109
+
110
+ function handleAssistantAnswer(answer, apiRenderConfig) {
111
+ var needIcon = parser.parseNeedIcon(answer);
112
+ if (needIcon) {
113
+ state.pendingIconCategory = {
114
+ name: needIcon.name,
115
+ sort: needIcon.sort
116
+ };
117
+ state.iconPickMode = true;
118
+ state.renderConfig = null;
119
+ state.messages.push({
120
+ role: 'assistant',
121
+ content: needIcon.msg,
122
+ imageUrls: []
123
+ });
124
+ notifyUpdate();
125
+ return;
126
+ }
127
+
128
+ var renderConfig = apiRenderConfig || parser.parseRenderConfig(answer);
129
+ if (renderConfig) {
130
+ state.iconPickMode = false;
131
+ state.pendingIconCategory = null;
132
+ state.renderConfig = renderConfig;
133
+ if (renderConfig.inputs && typeof renderConfig.inputs === 'object') {
134
+ state.pendingInputs = Object.assign({}, renderConfig.inputs);
135
+ } else if (renderConfig.type === 'confirm') {
136
+ state.pendingInputs = Object.assign({}, state.pendingInputs);
137
+ }
138
+ var cleanedAnswer = parser.stripMarkers(answer);
139
+ var formHint = renderConfig.title || renderConfig.description || '请填写以下信息';
140
+ state.messages.push(createAssistantMessage(cleanedAnswer || formHint));
141
+ notifyUpdate();
142
+ return;
143
+ }
144
+
145
+ state.iconPickMode = false;
146
+ state.pendingIconCategory = null;
147
+ state.renderConfig = null;
148
+ state.messages.push(createAssistantMessage(parser.stripMarkers(answer) || answer));
149
+ notifyUpdate();
150
+ }
151
+
152
+ function handleAssistantResponse(data) {
153
+ var apiRenderConfig = parser.parseApiRenderConfig(data && data.renderConfig);
154
+ var answer = (data && data.answer) ? data.answer : '';
155
+ if (!answer && apiRenderConfig) {
156
+ answer = apiRenderConfig.title || apiRenderConfig.description || apiRenderConfig.message || '';
157
+ }
158
+ if (!answer && !(data && data.actionResult)) {
159
+ answer = '暂无回复';
160
+ }
161
+ var actionResult = data && data.actionResult;
162
+ if (actionResult) {
163
+ state.renderConfig = null;
164
+ state.iconPickMode = false;
165
+ state.pendingIconCategory = null;
166
+ appendActionResultMessage(actionResult);
167
+ notifyUpdate();
168
+ return;
169
+ }
170
+ handleAssistantAnswer(answer, apiRenderConfig);
171
+ }
172
+
173
+ function setInputText(text) {
174
+ state.inputText = text;
175
+ notifyUpdate();
176
+ }
177
+
178
+ function clearPendingImage() {
179
+ state.pendingImageUrl = '';
180
+ notifyUpdate();
181
+ }
182
+
183
+ function chooseImage() {
184
+ if (state.loading || state.uploading || state.iconPickMode) {
185
+ return Promise.resolve();
186
+ }
187
+ return new Promise(function (resolve, reject) {
188
+ uni.chooseImage({
189
+ count: 1,
190
+ sizeType: ['compressed'],
191
+ sourceType: ['album', 'camera'],
192
+ success: function (chooseRes) {
193
+ var filePath = chooseRes.tempFilePaths && chooseRes.tempFilePaths[0];
194
+ if (!filePath) {
195
+ reject(new Error('未选择图片'));
196
+ return;
197
+ }
198
+ state.uploading = true;
199
+ notifyUpdate();
200
+ requestAdapter.uploadImage(filePath)
201
+ .then(function (imageUrl) {
202
+ state.pendingImageUrl = imageUrl;
203
+ state.uploading = false;
204
+ notifyUpdate();
205
+ resolve(imageUrl);
206
+ })
207
+ .catch(function (error) {
208
+ state.uploading = false;
209
+ notifyUpdate();
210
+ reject(error);
211
+ });
212
+ },
213
+ fail: function (err) {
214
+ reject(err || new Error('选择图片失败'));
215
+ }
216
+ });
217
+ });
218
+ }
219
+
220
+ function pickCategoryIcon(source) {
221
+ if (state.loading || state.uploading || !state.pendingIconCategory) {
222
+ return Promise.resolve();
223
+ }
224
+ if (!ensureLogin()) {
225
+ return Promise.resolve();
226
+ }
227
+ var sourceType = source === 'camera' ? ['camera'] : ['album'];
228
+ return new Promise(function (resolve, reject) {
229
+ uni.chooseImage({
230
+ count: 1,
231
+ sizeType: ['compressed'],
232
+ sourceType: sourceType,
233
+ success: function (chooseRes) {
234
+ var filePath = chooseRes.tempFilePaths && chooseRes.tempFilePaths[0];
235
+ if (!filePath) {
236
+ reject(new Error('未选择图片'));
237
+ return;
238
+ }
239
+ state.uploading = true;
240
+ notifyUpdate();
241
+ requestAdapter.uploadImage(filePath)
242
+ .then(function (imageUrl) {
243
+ var category = state.pendingIconCategory;
244
+ var query = '新增一级分类:' + category.name + ',排序' + category.sort + ',图标 ' + imageUrl;
245
+ state.iconPickMode = false;
246
+ state.pendingIconCategory = null;
247
+ state.uploading = false;
248
+ notifyUpdate();
249
+ return sendMessage(query, imageUrl, '[图片] ' + category.name);
250
+ })
251
+ .then(function () {
252
+ resolve();
253
+ })
254
+ .catch(function (error) {
255
+ state.uploading = false;
256
+ notifyUpdate();
257
+ reject(error);
258
+ });
259
+ },
260
+ fail: function (err) {
261
+ reject(err || new Error('选择图片失败'));
262
+ }
263
+ });
264
+ });
265
+ }
266
+
267
+ function cancelIconPick() {
268
+ state.iconPickMode = false;
269
+ state.pendingIconCategory = null;
270
+ notifyUpdate();
271
+ }
272
+
273
+ function sendQuick(text) {
274
+ state.inputText = text;
275
+ notifyUpdate();
276
+ return handleSend();
277
+ }
278
+
279
+ var DIFY_TEXT_INPUT_KEYS = ['confirmed', 'intent', 'name', 'parent_name', 'icon', 'productName', 'mainImg', 'unit'];
280
+ var DIFY_NUMBER_INPUT_KEYS = ['level', 'pid', 'sort', 'threeCategoryId', 'price', 'stock', 'productId'];
281
+
282
+ function normalizeDifyInputs(inputs) {
283
+ if (!inputs || typeof inputs !== 'object') {
284
+ return {};
285
+ }
286
+ var normalized = Object.assign({}, inputs);
287
+ DIFY_TEXT_INPUT_KEYS.forEach(function (key) {
288
+ if (normalized[key] === undefined || normalized[key] === null) {
289
+ return;
290
+ }
291
+ if (key === 'confirmed') {
292
+ normalized[key] = normalized[key] === true || normalized[key] === 'true' ? 'true' : 'false';
293
+ return;
294
+ }
295
+ normalized[key] = String(normalized[key]);
296
+ });
297
+ DIFY_NUMBER_INPUT_KEYS.forEach(function (key) {
298
+ if (normalized[key] === undefined || normalized[key] === null || normalized[key] === '') {
299
+ return;
300
+ }
301
+ var num = Number(normalized[key]);
302
+ if (!isNaN(num)) {
303
+ normalized[key] = num;
304
+ }
305
+ });
306
+ return normalized;
307
+ }
308
+
309
+ function doSendChat(payload) {
310
+ state.loading = true;
311
+ notifyUpdate();
312
+ if (payload && payload.inputs) {
313
+ payload.inputs = normalizeDifyInputs(payload.inputs);
314
+ }
315
+
316
+ return requestAdapter.sendChat(payload)
317
+ .then(function (res) {
318
+ var data = res && res.data ? res.data : res;
319
+ if (data.conversationId) {
320
+ state.conversationId = data.conversationId;
321
+ }
322
+ state.loading = false;
323
+ handleAssistantResponse(data);
324
+ notifyUpdate();
325
+ })
326
+ .catch(function (error) {
327
+ state.loading = false;
328
+ state.messages.push(createAssistantMessage(error && (error.msg || error.message) ? (error.msg || error.message) : '发送失败,请稍后重试'));
329
+ notifyUpdate();
330
+ });
331
+ }
332
+
333
+ function sendMessage(query, imageUrl, displayContent) {
334
+ if (!ensureLogin()) {
335
+ return Promise.resolve();
336
+ }
337
+ state.lastUserQuery = displayContent || query || '';
338
+ state.messages.push({
339
+ role: 'user',
340
+ content: displayContent || query,
341
+ imageUrls: imageUrl ? [imageUrl] : []
342
+ });
343
+
344
+ return doSendChat({
345
+ conversationId: state.conversationId || undefined,
346
+ query: query || undefined,
347
+ imageUrl: imageUrl || undefined,
348
+ inputs: state.pendingInputs || {}
349
+ }).then(function () {
350
+ state.pendingInputs = {};
351
+ });
352
+ }
353
+
354
+ function validateFormFields(fields, inputs) {
355
+ var missing = [];
356
+ (fields || []).forEach(function (field) {
357
+ if (!field || field.type === 'hidden' || !field.required) {
358
+ return;
359
+ }
360
+ var val = inputs[field.name];
361
+ if (val === undefined || val === null || val === '') {
362
+ missing.push(field.label || field.name);
363
+ }
364
+ });
365
+ return missing;
366
+ }
367
+
368
+ function submitInputs(inputs) {
369
+ inputs = inputs || {};
370
+ if (state.renderConfig && state.renderConfig.type === 'form' && state.renderConfig.fields) {
371
+ var intent = inputs.intent || (state.pendingInputs && state.pendingInputs.intent);
372
+ if (intent === 'product_online' || intent === 'product_offline') {
373
+ if (!inputs.productName && !inputs.productId) {
374
+ uni.showToast({
375
+ title: '请填写商品名称或商品ID',
376
+ icon: 'none'
377
+ });
378
+ return Promise.resolve();
379
+ }
380
+ } else {
381
+ var missing = validateFormFields(state.renderConfig.fields, inputs);
382
+ if (missing.length) {
383
+ uni.showToast({
384
+ title: '请填写:' + missing.join('、'),
385
+ icon: 'none'
386
+ });
387
+ return Promise.resolve();
388
+ }
389
+ }
390
+ }
391
+ var hasOwn = Object.prototype.hasOwnProperty;
392
+ for (var key in inputs) {
393
+ if (hasOwn.call(inputs, key)) {
394
+ state.pendingInputs[key] = inputs[key];
395
+ }
396
+ }
397
+ state.renderConfig = null;
398
+ state.pendingImageUrl = '';
399
+ notifyUpdate();
400
+
401
+ if (!ensureLogin()) {
402
+ return Promise.resolve();
403
+ }
404
+
405
+ return doSendChat({
406
+ conversationId: state.conversationId || undefined,
407
+ query: state.lastUserQuery || undefined,
408
+ inputs: state.pendingInputs
409
+ }).then(function () {
410
+ state.pendingInputs = {};
411
+ });
412
+ }
413
+
414
+ function cancelForm() {
415
+ state.renderConfig = null;
416
+ state.pendingInputs = {};
417
+ state.pendingImageUrl = '';
418
+ notifyUpdate();
419
+ }
420
+
421
+ function submitConfirm(confirmed) {
422
+ if (!state.renderConfig || state.renderConfig.type !== 'confirm') {
423
+ return Promise.resolve();
424
+ }
425
+ if (!confirmed) {
426
+ cancelForm();
427
+ return Promise.resolve();
428
+ }
429
+ var inputs = Object.assign(
430
+ {},
431
+ state.pendingInputs,
432
+ state.renderConfig.inputs || {},
433
+ { confirmed: 'true' }
434
+ );
435
+ return submitInputs(inputs);
436
+ }
437
+
438
+ function handleSend() {
439
+ var query = (state.inputText || '').trim();
440
+ var imageUrl = state.pendingImageUrl;
441
+ if ((!query && !imageUrl) || state.loading || state.uploading || state.iconPickMode || state.renderConfig) {
442
+ return Promise.resolve();
443
+ }
444
+ var displayContent = query || (imageUrl ? '[图片]' : '');
445
+ state.inputText = '';
446
+ state.pendingImageUrl = '';
447
+ notifyUpdate();
448
+ return sendMessage(query, imageUrl, displayContent);
449
+ }
450
+
451
+ function openConversation() {
452
+ if (!ensureLogin()) {
453
+ return false;
454
+ }
455
+ event.emit('chat:open');
456
+ return true;
457
+ }
458
+
459
+ function closeConversation() {
460
+ event.emit('chat:close');
461
+ }
462
+
463
+ module.exports = {
464
+ quickQuestions: quickQuestions,
465
+ reset: reset,
466
+ getSnapshot: getSnapshot,
467
+ setInputText: setInputText,
468
+ clearPendingImage: clearPendingImage,
469
+ chooseImage: chooseImage,
470
+ pickCategoryIcon: pickCategoryIcon,
471
+ cancelIconPick: cancelIconPick,
472
+ submitInputs: submitInputs,
473
+ cancelForm: cancelForm,
474
+ submitConfirm: submitConfirm,
475
+ sendQuick: sendQuick,
476
+ handleSend: handleSend,
477
+ openConversation: openConversation,
478
+ closeConversation: closeConversation,
479
+ onUpdate: function (handler) {
480
+ event.on('chat:update', handler);
481
+ },
482
+ offUpdate: function (handler) {
483
+ event.off('chat:update', handler);
484
+ },
485
+ onOpen: function (handler) {
486
+ event.on('chat:open', handler);
487
+ },
488
+ offOpen: function (handler) {
489
+ event.off('chat:open', handler);
490
+ },
491
+ onClose: function (handler) {
492
+ event.on('chat:close', handler);
493
+ },
494
+ offClose: function (handler) {
495
+ event.off('chat:close', handler);
496
+ }
497
+ };