centaline-data-driven-v3 0.0.79 → 0.0.81
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/dist/centaline-data-driven-v3.umd.js +111 -109
- package/package.json +1 -1
- package/src/components/web/AIChat.vue +60 -31
- package/src/components/web/Form.vue +32 -34
- package/src/loader/src/AIChat.js +24 -2
- package/src/loader/src/Form.js +16 -33
package/package.json
CHANGED
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
</div>
|
|
10
10
|
<div class="header-item" v-if="model.controlLabel">
|
|
11
11
|
<h3 style="line-height: 25px;">
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
{{ model.controlLabel }}</h3>
|
|
13
|
+
</div>
|
|
14
14
|
</div>
|
|
15
15
|
<!-- 消息列表 -->
|
|
16
16
|
<div class="messages" ref="messagesContainer">
|
|
17
17
|
<template v-for="message in model.messages">
|
|
18
18
|
<div :key="message.id" class="message" v-if="message.content"
|
|
19
19
|
:class="{ 'user-message': message.sender === 'user', 'ai-message': message.sender === 'ai' }">
|
|
20
|
-
<div class="chat-message" v-html="htmlContent(message)">
|
|
20
|
+
<div class="chat-message" :style="{color:message.type=='error'?'red':''}" v-html="htmlContent(message)">
|
|
21
21
|
</div>
|
|
22
22
|
</div>
|
|
23
23
|
<div v-else class="loading-container">
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<div class="chat-editor" v-if="showAI">
|
|
31
31
|
<div class="chat-input-editor-container">
|
|
32
32
|
<textarea ref="textareaRef" class="chat-input" v-model="inputMessage" @keydown="handleKeydown"
|
|
33
|
-
placeholder="
|
|
33
|
+
:placeholder="model.placeholder"></textarea>
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
</div>
|
|
@@ -56,16 +56,17 @@
|
|
|
56
56
|
|
|
57
57
|
<script setup lang="ts">
|
|
58
58
|
import { ref, reactive, nextTick, watch, computed } from 'vue'
|
|
59
|
+
import AIChat from '../../loader/src/AIChat'
|
|
59
60
|
import common from '../../utils/common'
|
|
60
61
|
import { marked } from 'marked';
|
|
61
62
|
import DOMPurify from 'dompurify'
|
|
62
63
|
|
|
63
64
|
|
|
64
|
-
const emit = defineEmits(['loaded', "
|
|
65
|
+
const emit = defineEmits(['loaded', "getRefFieldPara", "hideAI"])
|
|
65
66
|
const props = defineProps({
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
field: Object,
|
|
68
|
+
router: Object,
|
|
69
|
+
actionRouters: Array,
|
|
69
70
|
form: Object,
|
|
70
71
|
})
|
|
71
72
|
interface StreamEventData {
|
|
@@ -73,6 +74,7 @@ interface StreamEventData {
|
|
|
73
74
|
conversation_id?: string
|
|
74
75
|
answer?: string
|
|
75
76
|
task_id?: string
|
|
77
|
+
message?: string
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
const model = ref({});
|
|
@@ -89,7 +91,7 @@ let scrollPending = false;//滚动输入
|
|
|
89
91
|
const headers = computed(() => {
|
|
90
92
|
return {
|
|
91
93
|
'Content-Type': 'application/json',
|
|
92
|
-
Authorization: "Bearer " + props.
|
|
94
|
+
Authorization: "Bearer " + props.field?.code2,
|
|
93
95
|
};
|
|
94
96
|
})
|
|
95
97
|
|
|
@@ -97,8 +99,8 @@ init()
|
|
|
97
99
|
//初始化数据
|
|
98
100
|
function init() {
|
|
99
101
|
nextTick(function () {
|
|
100
|
-
if (props.
|
|
101
|
-
load(props
|
|
102
|
+
if (props.field) {
|
|
103
|
+
load(AIChat.AIModel(props));
|
|
102
104
|
emit("loaded");
|
|
103
105
|
}
|
|
104
106
|
});
|
|
@@ -111,8 +113,8 @@ function action() {
|
|
|
111
113
|
showAI.value = true;
|
|
112
114
|
rtn = model.value.action;
|
|
113
115
|
}
|
|
114
|
-
else if (props.
|
|
115
|
-
var router = props.
|
|
116
|
+
else if (props.actionRouters) {
|
|
117
|
+
var router = props.actionRouters.find((v1) => {
|
|
116
118
|
return v1.key === model.value.fieldName1;
|
|
117
119
|
});
|
|
118
120
|
rtn = router.action;
|
|
@@ -189,9 +191,9 @@ const sendMessage = async () => {
|
|
|
189
191
|
// 添加AI消息
|
|
190
192
|
addMessage({
|
|
191
193
|
content: "",
|
|
192
|
-
sender: 'ai'
|
|
194
|
+
sender: 'ai',
|
|
195
|
+
type: ''
|
|
193
196
|
})
|
|
194
|
-
|
|
195
197
|
// AI回复
|
|
196
198
|
await fetchAIResponse({
|
|
197
199
|
"query": inputMessage.value
|
|
@@ -204,7 +206,7 @@ const addMessage = (message) => {
|
|
|
204
206
|
...message,
|
|
205
207
|
timestamp: new Date()
|
|
206
208
|
})
|
|
207
|
-
scheduleScroll()
|
|
209
|
+
scheduleScroll(true);
|
|
208
210
|
}
|
|
209
211
|
// 添加消息通用方法
|
|
210
212
|
const appendMessage = (message) => {
|
|
@@ -212,14 +214,20 @@ const appendMessage = (message) => {
|
|
|
212
214
|
scheduleScroll()
|
|
213
215
|
}
|
|
214
216
|
|
|
217
|
+
const UpdateMessageType = (type) => {
|
|
218
|
+
if (model.value.messages[model.value.messages.length - 1].type != 'error') {
|
|
219
|
+
model.value.messages[model.value.messages.length - 1].type = type;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
215
223
|
// 防抖滚动
|
|
216
|
-
const scheduleScroll = () => {
|
|
224
|
+
const scheduleScroll = (flagScroll) => {
|
|
217
225
|
if (!scrollPending) {
|
|
218
226
|
if (messagesContainer.value) {
|
|
219
227
|
const container = messagesContainer.value;
|
|
220
|
-
|
|
228
|
+
|
|
221
229
|
const distanceToBottom = container.scrollHeight - (container.scrollTop + container.clientHeight);
|
|
222
|
-
if (distanceToBottom <= 20) {
|
|
230
|
+
if (flagScroll||distanceToBottom <= 20) {
|
|
223
231
|
scrollPending = true
|
|
224
232
|
nextTick(() => {
|
|
225
233
|
if (messagesContainer.value) {
|
|
@@ -235,14 +243,27 @@ const scheduleScroll = () => {
|
|
|
235
243
|
//获取关联列返回对象
|
|
236
244
|
function getRefFieldJson() {
|
|
237
245
|
let rtn = {};
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
246
|
+
let router = props.router;
|
|
247
|
+
if (router.refFieldName) {
|
|
248
|
+
let refFieldName = router.refFieldName.split(',');
|
|
249
|
+
let submitData = props.form.getFormObj();
|
|
250
|
+
if (refFieldName.length > 0 && submitData) {
|
|
251
|
+
rtn = getRefFieldPara(submitData, refFieldName);
|
|
242
252
|
}
|
|
243
253
|
}
|
|
244
254
|
return JSON.stringify(rtn);
|
|
245
255
|
}
|
|
256
|
+
//绑定联动参数组件
|
|
257
|
+
function getRefFieldPara(tempFormData, refFieldNameArr) {
|
|
258
|
+
let submitData = {};
|
|
259
|
+
if (tempFormData) {
|
|
260
|
+
refFieldNameArr.forEach((v) => {
|
|
261
|
+
submitData[v] = common.getDataOfUpperLower(tempFormData, v);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return submitData;
|
|
265
|
+
}
|
|
266
|
+
|
|
246
267
|
|
|
247
268
|
//获取Token
|
|
248
269
|
function getToken() {
|
|
@@ -336,11 +357,14 @@ const fetchAIResponse = async (params) => {
|
|
|
336
357
|
});
|
|
337
358
|
}).then(() => {
|
|
338
359
|
// 在所有行处理完毕后执行 startTypingEffect
|
|
339
|
-
|
|
340
|
-
|
|
360
|
+
if (outtext.value == '') {
|
|
361
|
+
outtext.value = ' ';
|
|
362
|
+
}
|
|
363
|
+
UpdateMessageType('message');
|
|
341
364
|
startTypingEffect(outtext.value);
|
|
342
365
|
outtext.value = '';
|
|
343
366
|
}).catch(error => {
|
|
367
|
+
UpdateMessageType('error');
|
|
344
368
|
if (error.name === 'AbortError') {
|
|
345
369
|
console.log('Request aborted');
|
|
346
370
|
} else {
|
|
@@ -407,6 +431,11 @@ const handleStreamEvent = (eventData: StreamEventData) => {
|
|
|
407
431
|
if (eventData.conversation_id) {
|
|
408
432
|
conversationId.value = eventData.conversation_id
|
|
409
433
|
}
|
|
434
|
+
if (eventData.event == 'error') {
|
|
435
|
+
UpdateMessageType('error');
|
|
436
|
+
outtext.value += '\n\n' + eventData.message;
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
410
439
|
|
|
411
440
|
if (eventData.answer) {
|
|
412
441
|
const lastMessage = model.value.messages[model.value.messages.length - 1]
|
|
@@ -420,7 +449,7 @@ const handleStreamEvent = (eventData: StreamEventData) => {
|
|
|
420
449
|
}
|
|
421
450
|
}
|
|
422
451
|
|
|
423
|
-
const getTemplateType= (fullText)=>{
|
|
452
|
+
const getTemplateType = (fullText) => {
|
|
424
453
|
|
|
425
454
|
|
|
426
455
|
|
|
@@ -436,8 +465,8 @@ function startTypingEffect(fullText) {
|
|
|
436
465
|
return;
|
|
437
466
|
}
|
|
438
467
|
|
|
439
|
-
|
|
440
|
-
|
|
468
|
+
// 随机生成3到10之间的字符数
|
|
469
|
+
const randomChars = Math.floor(Math.random() * 8) + 3; // 3到10(包括3和10)
|
|
441
470
|
const charsToLoad = Math.min(randomChars, fullText.length - index);
|
|
442
471
|
|
|
443
472
|
// 获取当前要加载的字符
|
|
@@ -477,12 +506,12 @@ function hideAI() {
|
|
|
477
506
|
background-color: #fff;
|
|
478
507
|
display: flex;
|
|
479
508
|
flex-direction: row;
|
|
480
|
-
/* 子元素水平排列
|
|
481
|
-
gap: 5px;
|
|
509
|
+
/* 子元素水平排列
|
|
510
|
+
gap: 5px; */
|
|
482
511
|
|
|
483
512
|
/* 子元素之间的间距为5像素 */
|
|
484
513
|
.header-item {
|
|
485
|
-
padding: 10px;
|
|
514
|
+
padding: 10px 0px 10px 10px;
|
|
486
515
|
}
|
|
487
516
|
}
|
|
488
517
|
|
|
@@ -156,14 +156,14 @@
|
|
|
156
156
|
|
|
157
157
|
|
|
158
158
|
</div>
|
|
159
|
-
<template v-if="model?.
|
|
160
|
-
<div :style="{ flex: ' 0 0 ' + model.
|
|
159
|
+
<template v-if="model?.aiAttr?.showAI">
|
|
160
|
+
<div :style="{ flex: ' 0 0 ' + model.aiAttr.width + 'px', position: 'sticky', top: '0' ,'margin-left': '10px'}"
|
|
161
161
|
v-show="showAI">
|
|
162
162
|
<div
|
|
163
163
|
:style="{ position: 'sticky', top: '0', height: dialogHeight + 'px', overflow: 'hidden', 'border-bottom-right-radius': '4px' }">
|
|
164
164
|
<AIChat :height="dialogHeight"
|
|
165
165
|
:style="{ position: 'sticky', top: '0', height: dialogHeight + 'px' }"
|
|
166
|
-
:
|
|
166
|
+
:field="model.aiChat" :router="model.aiRouter" :actionRouter="model.actionRouters" :form="model"
|
|
167
167
|
@hideAI="AIToggle">
|
|
168
168
|
|
|
169
169
|
</AIChat>
|
|
@@ -172,17 +172,11 @@
|
|
|
172
172
|
</template>
|
|
173
173
|
|
|
174
174
|
</div>
|
|
175
|
-
<template v-if="model?.
|
|
176
|
-
<div class="btn-avatar" @click="AIToggle"
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
:title="model?.AIRouter.controlLabel">
|
|
175
|
+
<template v-if="model?.aiAttr?.showAI && !showAI">
|
|
176
|
+
<div class="btn-avatar" @click="AIToggle">
|
|
177
|
+
<img class="avatar-img" :src="util.getAssetsImage('AIChat.png')" :alt="model?.aiRouter.controlLabel"
|
|
178
|
+
:title="model?.aiRouter.controlLabel">
|
|
180
179
|
</div>
|
|
181
|
-
|
|
182
|
-
<!-- <component :is="model.AIRouter.is" :vmodel="model.AIRouter"
|
|
183
|
-
v-if="model.AIRouter.show" @fieldClick="AIToggle"
|
|
184
|
-
:style="{ 'float': model.AIRouter.isCheckbox ? model.AIRouter.alignCss : '' }">
|
|
185
|
-
</component> -->
|
|
186
180
|
</template>
|
|
187
181
|
<div style="min-height:200px" v-if="loading"></div>
|
|
188
182
|
<iframe :src="downloadUrl" style="height:0px;width:0px;border-width: 0px;display: none;"> </iframe>
|
|
@@ -262,6 +256,9 @@ const refForm = ref()
|
|
|
262
256
|
const qrtimer = ref(null)
|
|
263
257
|
const downloadUrl = ref('')
|
|
264
258
|
const minHeight = ref('auto')
|
|
259
|
+
const showAI = ref(false);
|
|
260
|
+
const dialogHeight = ref(props.dialogHeight || (window.innerHeight - 60));
|
|
261
|
+
|
|
265
262
|
onUpdated(() => {
|
|
266
263
|
nextTick(() => {
|
|
267
264
|
qrtimer.value = setTimeout(getisScroll, 100);
|
|
@@ -321,28 +318,7 @@ function load(data) {
|
|
|
321
318
|
function failLoad() {
|
|
322
319
|
emit('failLoad', model.value);
|
|
323
320
|
}
|
|
324
|
-
const showAI = ref(false);
|
|
325
|
-
const dialogHeight = ref(props.dialogHeight || (window.innerHeight - 60));
|
|
326
321
|
|
|
327
|
-
function AIToggle() {
|
|
328
|
-
showAI.value = !showAI.value;
|
|
329
|
-
let width = model.value.AIattr.width;
|
|
330
|
-
dialogHeight.value = (props.dialogHeight || (window.innerHeight - 60));
|
|
331
|
-
emit('AIToggle', (showAI.value ? width : -width));
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
function buttonsWidth() {
|
|
336
|
-
let rtn = '100%';
|
|
337
|
-
if (showAI.value) {
|
|
338
|
-
rtn = props.dialoWidth - model.value.AIattr.width - 4 + 'px';
|
|
339
|
-
}
|
|
340
|
-
else if (props.pageWidth) {
|
|
341
|
-
rtn = props.pageWidth - 20 + 'px';
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
return rtn;
|
|
345
|
-
}
|
|
346
322
|
|
|
347
323
|
//获取关联数据
|
|
348
324
|
function getFileData(field) {
|
|
@@ -649,6 +625,28 @@ function setCss() {
|
|
|
649
625
|
minHeight.value = (document.documentElement.clientHeight - props.topHeight - 20) + 'px';
|
|
650
626
|
}
|
|
651
627
|
}
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
function AIToggle() {
|
|
631
|
+
showAI.value = !showAI.value;
|
|
632
|
+
let width = model.value.aiAttr.width;
|
|
633
|
+
dialogHeight.value = (props.dialogHeight || (window.innerHeight - 60));
|
|
634
|
+
emit('AIToggle', (showAI.value ? width : -width));
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
function buttonsWidth() {
|
|
639
|
+
let rtn = '100%';
|
|
640
|
+
if (showAI.value) {
|
|
641
|
+
rtn = props.dialoWidth - model.value.aiAttr.width - 4 + 'px';
|
|
642
|
+
}
|
|
643
|
+
else if (props.pageWidth) {
|
|
644
|
+
rtn = props.pageWidth - 20 + 'px';
|
|
645
|
+
|
|
646
|
+
}
|
|
647
|
+
return rtn;
|
|
648
|
+
}
|
|
649
|
+
|
|
652
650
|
</script>
|
|
653
651
|
|
|
654
652
|
<style scoped>
|
package/src/loader/src/AIChat.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import base from '../index';
|
|
2
2
|
import valid from '../../utils/validate';
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
function loadFromModel(source, messages, router) {
|
|
5
6
|
|
|
6
7
|
var init = function (data) {
|
|
7
8
|
var rtn = {
|
|
8
|
-
|
|
9
|
+
get placeholder() {
|
|
10
|
+
return source.placeholder1 || '输入你的消息...';
|
|
11
|
+
},
|
|
9
12
|
messages:messages,
|
|
10
13
|
get action() {
|
|
11
14
|
return router && router.action ? router.action : "";//上传完整地址
|
|
@@ -13,6 +16,7 @@ function loadFromModel(source, messages, router) {
|
|
|
13
16
|
set action(v) {
|
|
14
17
|
router.action = v;
|
|
15
18
|
},
|
|
19
|
+
|
|
16
20
|
getFormObj() {
|
|
17
21
|
var rtnFormObj = {};
|
|
18
22
|
var that = this;
|
|
@@ -42,9 +46,27 @@ function selfValidExcute(eventName, model) {
|
|
|
42
46
|
model.valid = true;
|
|
43
47
|
return model.valid;
|
|
44
48
|
}
|
|
49
|
+
|
|
50
|
+
function AIModel(source) {
|
|
51
|
+
let airtn = null
|
|
52
|
+
if (source.field) {
|
|
53
|
+
|
|
54
|
+
let field = source.field;
|
|
55
|
+
|
|
56
|
+
var messages = [];
|
|
57
|
+
if (Array.isArray(field.code1)) {
|
|
58
|
+
messages = field.code1;
|
|
59
|
+
} else {
|
|
60
|
+
messages = field.code1 && field.code1 != "[]" ? JSON.parse(field.code1) : [];
|
|
61
|
+
}
|
|
62
|
+
airtn = loadFromModel(field, messages, source.router);
|
|
63
|
+
}
|
|
64
|
+
return airtn;
|
|
65
|
+
}
|
|
45
66
|
|
|
46
67
|
const AI = {
|
|
47
68
|
loadFromModel,//获取有效文件数量
|
|
48
|
-
selfValidExcute
|
|
69
|
+
selfValidExcute,
|
|
70
|
+
AIModel
|
|
49
71
|
};
|
|
50
72
|
export default AI;
|
package/src/loader/src/Form.js
CHANGED
|
@@ -3,9 +3,7 @@ import LibFunction from './LibFunction';
|
|
|
3
3
|
import Router from './Router';
|
|
4
4
|
import Enum from '../../utils/Enum';
|
|
5
5
|
import common from '../../utils/common';
|
|
6
|
-
import request from '../../utils/request';
|
|
7
|
-
import Field from './Field';
|
|
8
|
-
import AIChat from './AIChat';
|
|
6
|
+
import request from '../../utils/request';
|
|
9
7
|
|
|
10
8
|
function loadFormApi(api, callBack, apiParam, failCallBack, isFormList) {
|
|
11
9
|
if (api) {
|
|
@@ -722,10 +720,10 @@ function loadFromModel(source, isFormList) {
|
|
|
722
720
|
return source.flagAlertCloseWindowAfterSave === true;
|
|
723
721
|
},
|
|
724
722
|
|
|
725
|
-
|
|
726
|
-
get
|
|
727
|
-
if (rtn.
|
|
728
|
-
return rtn.
|
|
723
|
+
_aiAttr: null,
|
|
724
|
+
get aiAttr() {
|
|
725
|
+
if (rtn._aiAttr !== null) {
|
|
726
|
+
return rtn._aiAttr;
|
|
729
727
|
}
|
|
730
728
|
else {
|
|
731
729
|
let aiattr = { showAI: false, width: 0 };
|
|
@@ -733,14 +731,14 @@ function loadFromModel(source, isFormList) {
|
|
|
733
731
|
aiattr.showAI = true;
|
|
734
732
|
aiattr.width = parseFloat(source.aiChat.width || 300);
|
|
735
733
|
}
|
|
736
|
-
rtn.
|
|
737
|
-
return rtn.
|
|
734
|
+
rtn._aiAttr = aiattr;
|
|
735
|
+
return rtn._aiAttr;
|
|
738
736
|
}
|
|
739
737
|
},
|
|
740
|
-
|
|
741
|
-
get
|
|
742
|
-
if (rtn.
|
|
743
|
-
return rtn.
|
|
738
|
+
_aiRouter: null,
|
|
739
|
+
get aiRouter() {
|
|
740
|
+
if (rtn._aiRouter !== null) {
|
|
741
|
+
return rtn._aiRouter;
|
|
744
742
|
}
|
|
745
743
|
else {
|
|
746
744
|
var router = {};
|
|
@@ -750,28 +748,13 @@ function loadFromModel(source, isFormList) {
|
|
|
750
748
|
return v1.key === field.fieldName1;
|
|
751
749
|
});
|
|
752
750
|
}
|
|
753
|
-
rtn.
|
|
754
|
-
return rtn.
|
|
751
|
+
rtn._aiRouter= router;
|
|
752
|
+
return rtn._aiRouter;
|
|
755
753
|
}
|
|
754
|
+
},
|
|
755
|
+
get aiChat() {
|
|
756
|
+
return source.aiChat;
|
|
756
757
|
},
|
|
757
|
-
get AIModel() {
|
|
758
|
-
let airtn = null
|
|
759
|
-
if (source.aiChat) {
|
|
760
|
-
|
|
761
|
-
let field = source.aiChat;
|
|
762
|
-
let item = Field(field, []);
|
|
763
|
-
|
|
764
|
-
var messages = [];
|
|
765
|
-
if (Array.isArray(field.code1)) {
|
|
766
|
-
messages = field.code1;
|
|
767
|
-
} else {
|
|
768
|
-
messages = field.code1 && field.code1 != "[]" ? JSON.parse(field.code1) : [];
|
|
769
|
-
}
|
|
770
|
-
airtn = AIChat.loadFromModel(item, messages, rtn.AIRouter);
|
|
771
|
-
}
|
|
772
|
-
return airtn;
|
|
773
|
-
|
|
774
|
-
},
|
|
775
758
|
//获取表单数据
|
|
776
759
|
getFormObj() {
|
|
777
760
|
var rtnFormObj = {};
|