@tencentcloud/ai-desk-customer-vue 0.3.0 → 1.0.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.
- package/CHANGELOG.md +5 -3
- package/README.md +153 -50
- package/assets/loading_message.svg +1 -0
- package/components/CustomerServiceChat/chat-header/index-web.vue +2 -2
- package/components/CustomerServiceChat/index-web.vue +77 -11
- package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +7 -1
- package/components/CustomerServiceChat/message-input-toolbar/emoji-dialog-mobile/emoji-dialog-mobile.vue +2 -1
- package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue +2 -1
- package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/index.vue +2 -1
- package/components/CustomerServiceChat/message-input-toolbar/file-upload/index.vue +3 -2
- package/components/CustomerServiceChat/message-input-toolbar/image-upload/index.vue +4 -3
- package/components/CustomerServiceChat/message-input-toolbar/index-web.vue +2 -2
- package/components/CustomerServiceChat/message-input-toolbar/video-upload/index.vue +2 -2
- package/components/CustomerServiceChat/message-list/index-web.vue +16 -7
- package/components/CustomerServiceChat/message-list/message-elements/message-bubble-web.vue +19 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-custom.vue +6 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/marked.ts +4 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-branch.vue +13 -4
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-mobile/input-mobile.vue +4 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-mobile/radios-mobile.vue +4 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-pc/input-pc.vue +4 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-pc/radio-pc.vue +5 -3
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-mobile.vue +6 -4
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-pc.vue +5 -3
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-product-card.vue +21 -11
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-rating/message-rating-number.vue +6 -6
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-rating/message-rating-star.vue +14 -14
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-robot-welcome.vue +2 -6
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-single-form/form-input.vue +6 -4
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-stream.vue +51 -52
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/styles/common.scss +1 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/type-writer.ts +189 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-location.vue +2 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-text.vue +1 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-thinking.vue +59 -0
- package/components/CustomerServiceChat/message-list/message-tool/index-web.vue +1 -1
- package/components/CustomerServiceChat/message-list/message-tool/message-revoked.vue +1 -0
- package/components/CustomerServiceChat/message-list/scroll-button/index.vue +3 -1
- package/components/CustomerServiceChat/message-toolbar-button/index.vue +69 -0
- package/components/common/Dialog/index.vue +2 -2
- package/components/common/ImagePreviewer/index-web.vue +2 -2
- package/constant.ts +15 -0
- package/excluded-list.txt +0 -1
- package/index.ts +1 -6
- package/interface.ts +8 -0
- package/locales/en/TUIChat.ts +158 -0
- package/locales/en/aidesk.ts +16 -0
- package/locales/en/component.ts +6 -0
- package/locales/en/index.ts +26 -0
- package/locales/en/time.ts +37 -0
- package/locales/fil/TUIChat.ts +160 -0
- package/locales/fil/aidesk.ts +16 -0
- package/locales/fil/component.ts +6 -0
- package/locales/fil/index.ts +25 -0
- package/locales/fil/time.ts +18 -0
- package/locales/id/TUIChat.ts +164 -0
- package/locales/id/aidesk.ts +16 -0
- package/locales/id/component.ts +6 -0
- package/locales/id/index.ts +26 -0
- package/locales/id/time.ts +19 -0
- package/locales/index.ts +30 -0
- package/locales/ja/TUIChat.ts +165 -0
- package/locales/ja/aidesk.ts +16 -0
- package/locales/ja/component.ts +6 -0
- package/locales/ja/index.ts +26 -0
- package/locales/ja/time.ts +18 -0
- package/locales/ms/TUIChat.ts +165 -0
- package/locales/ms/aidesk.ts +16 -0
- package/locales/ms/component.ts +6 -0
- package/locales/ms/index.ts +26 -0
- package/locales/ms/time.ts +18 -0
- package/locales/ru/TUIChat.ts +158 -0
- package/locales/ru/aidesk.ts +16 -0
- package/locales/ru/component.ts +7 -0
- package/locales/ru/index.ts +26 -0
- package/locales/ru/time.ts +30 -0
- package/locales/th/TUIChat.ts +165 -0
- package/locales/th/aidesk.ts +16 -0
- package/locales/th/component.ts +6 -0
- package/locales/th/index.ts +26 -0
- package/locales/th/time.ts +18 -0
- package/locales/vi/TUIChat.ts +156 -0
- package/locales/vi/aidesk.ts +16 -0
- package/locales/vi/component.ts +6 -0
- package/locales/vi/index.ts +26 -0
- package/locales/vi/time.ts +18 -0
- package/locales/zh_cn/TUIChat.ts +158 -0
- package/locales/zh_cn/aidesk.ts +17 -0
- package/locales/zh_cn/component.ts +6 -0
- package/locales/zh_cn/index.ts +26 -0
- package/locales/zh_cn/time.ts +37 -0
- package/locales/zh_tw/TUIChat.ts +158 -0
- package/locales/zh_tw/aidesk.ts +16 -0
- package/locales/zh_tw/component.ts +6 -0
- package/locales/zh_tw/index.ts +26 -0
- package/locales/zh_tw/time.ts +37 -0
- package/package.json +2 -2
- package/server.ts +36 -9
- package/utils/index.ts +42 -17
- package/utils/utils.ts +4 -5
|
@@ -14,9 +14,6 @@
|
|
|
14
14
|
class="change-wrapper"
|
|
15
15
|
@click="changeBranchList()"
|
|
16
16
|
>
|
|
17
|
-
<div style="margin-right: 3px;">
|
|
18
|
-
换一换
|
|
19
|
-
</div>
|
|
20
17
|
<Icon :src="iconRefresh" />
|
|
21
18
|
</div>
|
|
22
19
|
</div>
|
|
@@ -98,7 +95,7 @@ export default {
|
|
|
98
95
|
iconRight,
|
|
99
96
|
changeBranchList,
|
|
100
97
|
iconQuestion,
|
|
101
|
-
iconRefresh
|
|
98
|
+
iconRefresh,
|
|
102
99
|
};
|
|
103
100
|
},
|
|
104
101
|
};
|
|
@@ -106,7 +103,6 @@ export default {
|
|
|
106
103
|
|
|
107
104
|
<style lang="scss">
|
|
108
105
|
.welcome-card {
|
|
109
|
-
min-width: 300px;
|
|
110
106
|
max-width: 400px;
|
|
111
107
|
|
|
112
108
|
.welcome-title {
|
|
@@ -125,7 +121,7 @@ export default {
|
|
|
125
121
|
.card-title {
|
|
126
122
|
display: inline-block;
|
|
127
123
|
margin-left: 8px;
|
|
128
|
-
font-size:
|
|
124
|
+
font-size: 14px;
|
|
129
125
|
}
|
|
130
126
|
|
|
131
127
|
.el-link {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
{{ props.title }}
|
|
8
8
|
</div>
|
|
9
9
|
<div class="form-button" @click="showForm">
|
|
10
|
-
|
|
10
|
+
{{ TUITranslateService.t("AIDesk.立即填写") }}
|
|
11
11
|
</div>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<input
|
|
27
27
|
v-model="text"
|
|
28
28
|
class="form-input"
|
|
29
|
-
placeholder="
|
|
29
|
+
:placeholder="TUITranslateService.t('AIDesk.请输入内容')"
|
|
30
30
|
>
|
|
31
31
|
</div>
|
|
32
32
|
</div>
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
</div>
|
|
39
39
|
<div class="form-finish-title-right">
|
|
40
40
|
<Icon :src="iconSucess" style="margin:0px 4px"/>
|
|
41
|
-
|
|
41
|
+
{{ TUITranslateService.t("AIDesk.已提交") }}
|
|
42
42
|
</div>
|
|
43
43
|
</div>
|
|
44
44
|
<div>
|
|
@@ -52,6 +52,7 @@ import vue from '../../../../../../../adapter-vue';
|
|
|
52
52
|
import iconForm from '../../../../../../../assets/icon_form.png';
|
|
53
53
|
import Icon from '../customer-icon.vue';
|
|
54
54
|
import iconSucess from '../../../../../../../assets/icon_success.png';
|
|
55
|
+
import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
|
55
56
|
const { computed, ref} = vue;
|
|
56
57
|
|
|
57
58
|
interface Props {
|
|
@@ -94,7 +95,8 @@ export default {
|
|
|
94
95
|
isShowForm,
|
|
95
96
|
showForm,
|
|
96
97
|
iconSucess,
|
|
97
|
-
isFinish
|
|
98
|
+
isFinish,
|
|
99
|
+
TUITranslateService
|
|
98
100
|
};
|
|
99
101
|
},
|
|
100
102
|
};
|
|
@@ -1,61 +1,74 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="message-stream">
|
|
3
3
|
<pre :class="['message-marked']" v-html="displayedContent" />
|
|
4
|
-
<span
|
|
5
|
-
v-if="!isFinished"
|
|
6
|
-
class="blinking-cursor"
|
|
7
|
-
/>
|
|
8
4
|
</div>
|
|
9
5
|
</template>
|
|
10
6
|
|
|
11
|
-
<script lang="ts">
|
|
7
|
+
<script lang="ts" setup>
|
|
12
8
|
import vue from '../../../../../../adapter-vue';
|
|
13
9
|
import { customerServicePayloadType } from '../../../../../../interface';
|
|
14
10
|
import { parseMarkdown } from './marked'
|
|
11
|
+
import { TypeWriter } from "./type-writer";
|
|
12
|
+
import { JSONToObject } from "../../../../../../utils";
|
|
15
13
|
|
|
16
|
-
const { ref,
|
|
14
|
+
const { ref, computed, withDefaults, defineProps, watch } = vue;
|
|
17
15
|
|
|
18
16
|
interface Props {
|
|
19
17
|
payload: customerServicePayloadType;
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
21
|
+
payload: () => '',
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const isStreaming = ref<boolean>(false);
|
|
25
|
+
const chunks = ref<string>('');
|
|
26
|
+
const isFinished = ref<boolean>(true);
|
|
27
|
+
const prevChunksLength = ref<number>(0);
|
|
28
|
+
const streamContent = ref<string>('');
|
|
29
|
+
const displayedContent = computed(() => parseMarkdown(streamContent.value));
|
|
30
|
+
|
|
31
|
+
const typeWriter = new TypeWriter({
|
|
32
|
+
onTyping: (item: string) => {
|
|
33
|
+
streamContent.value += item;
|
|
34
|
+
// emits('onStreaming', item, streamContent.value);
|
|
35
|
+
},
|
|
36
|
+
onComplete() {
|
|
37
|
+
isStreaming.value = false;
|
|
28
38
|
},
|
|
29
|
-
|
|
30
|
-
const displayedContent = ref<string>('');
|
|
31
|
-
const isFinished = ref<boolean>(false);
|
|
32
|
-
let currentIndex = 0;
|
|
39
|
+
});
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
function startStreaming(content: string[]) {
|
|
42
|
+
if (!isStreaming.value) {
|
|
43
|
+
isStreaming.value = true;
|
|
44
|
+
typeWriter.add(content);
|
|
45
|
+
typeWriter.start();
|
|
46
|
+
} else {
|
|
47
|
+
typeWriter.add(content);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
38
50
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (parsedContent.length > currentIndex) {
|
|
43
|
-
displayedContent.value = parsedContent;
|
|
44
|
-
currentIndex = parsedContent.length;
|
|
51
|
+
watch(() => props.payload, (newValue: string, oldValue: string) => {
|
|
52
|
+
if (newValue === oldValue) {
|
|
53
|
+
return;
|
|
45
54
|
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
watchEffect(() => {
|
|
49
|
-
isFinished.value = props?.payload?.isFinished === 1;
|
|
50
|
-
});
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
isFinished
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
56
|
+
const _payloadObject = JSONToObject(props.payload);
|
|
57
|
+
chunks.value = Array.isArray(_payloadObject.chunks) ? _payloadObject.chunks.join('') : _payloadObject.chunks;
|
|
58
|
+
isFinished.value = _payloadObject.isFinished === 1;
|
|
59
|
+
if (newValue && !oldValue && isFinished.value) {
|
|
60
|
+
// disable typeWriter style or history message first load
|
|
61
|
+
streamContent.value = chunks.value;
|
|
62
|
+
} else {
|
|
63
|
+
const _newChunksToAdd = chunks.value?.slice(prevChunksLength.value);
|
|
64
|
+
startStreaming([_newChunksToAdd]);
|
|
65
|
+
}
|
|
66
|
+
prevChunksLength.value = chunks.value?.length;
|
|
67
|
+
}, {
|
|
68
|
+
deep: true,
|
|
69
|
+
immediate: true,
|
|
70
|
+
},
|
|
71
|
+
);
|
|
59
72
|
</script>
|
|
60
73
|
<style lang="scss" scoped>
|
|
61
74
|
.message-stream {
|
|
@@ -63,19 +76,5 @@ export default {
|
|
|
63
76
|
word-break: keep-all;
|
|
64
77
|
white-space: normal;
|
|
65
78
|
font-size: 14px;
|
|
66
|
-
|
|
67
|
-
.blinking-cursor {
|
|
68
|
-
display: inline-block;
|
|
69
|
-
width: 1px;
|
|
70
|
-
height: 1em;
|
|
71
|
-
background-color: black;
|
|
72
|
-
animation: blink 1s step-end infinite;
|
|
73
|
-
vertical-align: sub;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
@keyframes blink {
|
|
77
|
-
0%, 100% { opacity: 1; }
|
|
78
|
-
50% { opacity: 0; }
|
|
79
|
-
}
|
|
80
79
|
}
|
|
81
80
|
</style>
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
const chineseRegex = /[\u4e00-\u9fa5]/;
|
|
2
|
+
const wordAndNonWordRegex = /\b\w+\b|[^\w]+/g;
|
|
3
|
+
const isStringArray = (test: any): boolean => {
|
|
4
|
+
return Array.isArray(test) && !test.some(value => typeof value !== 'string');
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export class TypeWriter {
|
|
8
|
+
/**
|
|
9
|
+
* @property {array} strings strings to be typed
|
|
10
|
+
*/
|
|
11
|
+
public strings: string[] = [];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @property {boolean} isTyping current typing status
|
|
15
|
+
*/
|
|
16
|
+
public isTyping: boolean = false;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @property {number} typeSpeed type speed in milliseconds. If empty, using dynamic speed.
|
|
20
|
+
*/
|
|
21
|
+
public typeSpeed?: number = 0;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @property {number} curArrayPos current typing string's position of all strings.
|
|
25
|
+
*/
|
|
26
|
+
private curArrayPos: number = 0;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @property {number} curCharPos current typing character's position in current strings.
|
|
30
|
+
*/
|
|
31
|
+
private curCharPos: number = 0;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @property {ReturnType<typeof setTimeout>} timer timer for type writer animation
|
|
35
|
+
*/
|
|
36
|
+
private timer?: ReturnType<typeof setTimeout>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* On string is typing
|
|
40
|
+
* @param {string} curStr
|
|
41
|
+
* @param {number} arrayPos
|
|
42
|
+
* @param {number} characterPos
|
|
43
|
+
* @param {Typed} self
|
|
44
|
+
*/
|
|
45
|
+
public onTyping?: (curStr: string, arrayPos: number, characterPos: number, self: any) => void;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* After start
|
|
49
|
+
* @param {number} arrayPos
|
|
50
|
+
* @param {number} characterPos
|
|
51
|
+
* @param {TypeWriter} self
|
|
52
|
+
*/
|
|
53
|
+
public onStart?: (arrayPos: number, characterPos: number, self: any) => void;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* After stop
|
|
57
|
+
* @param {number} arrayPos
|
|
58
|
+
* @param {number} characterPos
|
|
59
|
+
* @param {TypeWriter} self
|
|
60
|
+
*/
|
|
61
|
+
public onStop?: (arrayPos: number, characterPos: number, self: any) => void;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* All typing is complete
|
|
65
|
+
* @param {Typed} self
|
|
66
|
+
*/
|
|
67
|
+
public onComplete?: (self: any) => void;
|
|
68
|
+
|
|
69
|
+
constructor(options: {
|
|
70
|
+
defaultStrings?: string[];
|
|
71
|
+
typeSpeed?: number;
|
|
72
|
+
onTyping?: (curStr: string, arrayPos: number, characterPos: number, self: any) => void;
|
|
73
|
+
onComplete?: (self: any) => void;
|
|
74
|
+
onStart?: (arrayPos: number, characterPos: number, self: any) => void;
|
|
75
|
+
onStop?: (arrayPos: number, characterPos: number, self: any) => void;
|
|
76
|
+
}) {
|
|
77
|
+
const { defaultStrings, typeSpeed, onTyping, onComplete, onStart, onStop } = options;
|
|
78
|
+
if (defaultStrings && isStringArray(defaultStrings)) {
|
|
79
|
+
this.add(defaultStrings);
|
|
80
|
+
}
|
|
81
|
+
if (typeof typeSpeed === 'number') {
|
|
82
|
+
this.typeSpeed = typeSpeed;
|
|
83
|
+
}
|
|
84
|
+
if (typeof onTyping === 'function') {
|
|
85
|
+
this.onTyping = onTyping;
|
|
86
|
+
}
|
|
87
|
+
if (typeof onComplete === 'function') {
|
|
88
|
+
this.onComplete = onComplete;
|
|
89
|
+
}
|
|
90
|
+
if (typeof onStart === 'function') {
|
|
91
|
+
this.onStart = onStart;
|
|
92
|
+
}
|
|
93
|
+
if (typeof onStop === 'function') {
|
|
94
|
+
this.onStop = onStop;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
add(addStrings: string[]) {
|
|
99
|
+
if (!addStrings || !addStrings.length) return;
|
|
100
|
+
addStrings.forEach((item: string) => {
|
|
101
|
+
if (chineseRegex.test(item)) {
|
|
102
|
+
const newValueArray = item.split('');
|
|
103
|
+
this.strings.push(...newValueArray);
|
|
104
|
+
} else {
|
|
105
|
+
const newValueArray = item.match(wordAndNonWordRegex) || item.split('');
|
|
106
|
+
this.strings.push(...newValueArray);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
start() {
|
|
112
|
+
if (this.isTyping) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
this.isTyping = true;
|
|
116
|
+
this.onStart && this.onStart(this.curArrayPos, this.curCharPos, this);
|
|
117
|
+
this._next();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
stop() {
|
|
121
|
+
if (!this.isTyping) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this.isTyping = false;
|
|
125
|
+
clearTimeout(this.timer);
|
|
126
|
+
this.onStop && this.onStop(this.curArrayPos, this.curCharPos, this);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
done() {
|
|
130
|
+
this.stop();
|
|
131
|
+
let _str = this.strings[this.curArrayPos].slice(this.curCharPos);
|
|
132
|
+
_str += this.strings.slice(this.curArrayPos + 1).join('');
|
|
133
|
+
this.curArrayPos = this.strings.length - 1;
|
|
134
|
+
this.curCharPos = this.strings[this.curArrayPos]?.length - 1;
|
|
135
|
+
this.onTyping && this.onTyping(_str, this.curArrayPos, this.curCharPos, this);
|
|
136
|
+
this.strings = [];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
_consume() {
|
|
140
|
+
if (!this.strings.length) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if ((this.curArrayPos >= this.strings.length)) {
|
|
145
|
+
this.isTyping = false;
|
|
146
|
+
this.onComplete?.(this);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const item = this.strings[this.curArrayPos]?.[this.curCharPos];
|
|
151
|
+
if (item) {
|
|
152
|
+
this.onTyping && this.onTyping(item, this.curArrayPos, this.curCharPos, this);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (this.curCharPos < this.strings[this.curArrayPos]?.length - 1) {
|
|
156
|
+
this.curCharPos++;
|
|
157
|
+
} else {
|
|
158
|
+
this.curArrayPos++;
|
|
159
|
+
this.curCharPos = 0;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
_next() {
|
|
164
|
+
this._consume();
|
|
165
|
+
this.timer = setTimeout(() => {
|
|
166
|
+
this._consume();
|
|
167
|
+
if (this.isTyping) {
|
|
168
|
+
this._next();
|
|
169
|
+
}
|
|
170
|
+
}, this.typeSpeed || this._dynamicSpeed());
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
_dynamicSpeed() {
|
|
174
|
+
let length = 0;
|
|
175
|
+
length += (this.strings[this.curArrayPos]?.length || 0) - this.curCharPos - 1;
|
|
176
|
+
for (let i = this.curArrayPos + 1; i < this.strings.length; i++) {
|
|
177
|
+
length += this.strings[i]?.length || 0;
|
|
178
|
+
}
|
|
179
|
+
if (length <= 0) {
|
|
180
|
+
length = 10;
|
|
181
|
+
}
|
|
182
|
+
const speed = 1500 / length;
|
|
183
|
+
if (speed >= 150) {
|
|
184
|
+
return 150;
|
|
185
|
+
} else {
|
|
186
|
+
return speed;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
class="message-location"
|
|
4
4
|
:href="data.href"
|
|
5
5
|
target="_blank"
|
|
6
|
-
title="
|
|
6
|
+
:title="TUITranslateService.t('AIDesk.跳转')"
|
|
7
7
|
>
|
|
8
8
|
<span class="el-icon-location-outline">{{ data.description }}</span>
|
|
9
9
|
<img :src="data.url">
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
</template>
|
|
12
12
|
|
|
13
13
|
<script lang="ts" setup>
|
|
14
|
+
import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
|
14
15
|
import vue from '../../../../adapter-vue';
|
|
15
16
|
const { watchEffect, ref } = vue;
|
|
16
17
|
const props = defineProps({
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="message-thinking">
|
|
3
|
+
<div v-for="(icon, index) in icons" :key="index">
|
|
4
|
+
<transition name="fade">
|
|
5
|
+
<Icon v-if="icon" :file="loading_message" width="14px" height="14px"/>
|
|
6
|
+
</transition>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import vue from '../../../../adapter-vue';
|
|
12
|
+
import Icon from '../../../common/Icon.vue';
|
|
13
|
+
import loading_message from '../../../../assets/loading_message.svg';
|
|
14
|
+
const { ref, watchEffect,onMounted,onUnmounted} = vue;
|
|
15
|
+
export default {
|
|
16
|
+
components:{
|
|
17
|
+
Icon
|
|
18
|
+
},
|
|
19
|
+
setup() {
|
|
20
|
+
const icons = ref([false, false, false]);
|
|
21
|
+
const index = ref(0);
|
|
22
|
+
|
|
23
|
+
let intervalId:any;
|
|
24
|
+
|
|
25
|
+
onMounted(() => {
|
|
26
|
+
intervalId = setInterval(() => {
|
|
27
|
+
if (index.value < icons.value.length) {
|
|
28
|
+
icons.value = icons.value.map((v, i) => (i === index.value ? true : v));
|
|
29
|
+
index.value += 1;
|
|
30
|
+
} else {
|
|
31
|
+
icons.value = icons.value.map(() => false);
|
|
32
|
+
index.value = 0;
|
|
33
|
+
}
|
|
34
|
+
}, 500);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
onUnmounted(() => {
|
|
38
|
+
intervalId && clearInterval(intervalId)
|
|
39
|
+
intervalId = null;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return { icons,loading_message };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
</script>
|
|
46
|
+
<style lang="scss" scoped>
|
|
47
|
+
.message-thinking{
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: row;
|
|
50
|
+
width: 45px;
|
|
51
|
+
height: 16px;
|
|
52
|
+
}
|
|
53
|
+
.fade-enter-active, .fade-leave-active {
|
|
54
|
+
transition: opacity .5s;
|
|
55
|
+
}
|
|
56
|
+
.fade-enter, .fade-leave-to {
|
|
57
|
+
opacity: 0;
|
|
58
|
+
}
|
|
59
|
+
</style>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="toolbar-button-container">
|
|
3
|
+
<template v-for="(item, index) in props.toolbarButtonList">
|
|
4
|
+
<div v-if="item.renderCondition()" :key="index"
|
|
5
|
+
:class="['toolbar-button', isH5 ? 'toolbar-button-h5' : '']" @click="onClick(index)">
|
|
6
|
+
<Icon v-if="item.icon" class="toolbar-button-icon" :file="item.icon" width="18px" height="18px"/>
|
|
7
|
+
<div class="toolbar-button-text">
|
|
8
|
+
{{ item.title }}
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
<script lang="ts" setup>
|
|
16
|
+
import { isH5 } from '../../../utils/env';
|
|
17
|
+
import { ToolbarButtonModel } from '../../../interface';
|
|
18
|
+
import Icon from '../../common/Icon.vue';
|
|
19
|
+
|
|
20
|
+
interface IProps {
|
|
21
|
+
toolbarButtonList?: ToolbarButtonModel[]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const props = withDefaults(defineProps<IProps>(), {
|
|
25
|
+
toolbarButtonList: () => [] as ToolbarButtonModel[]
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function onClick(index: number) {
|
|
29
|
+
props.toolbarButtonList[index].clickEvent();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
</script>
|
|
33
|
+
<style>
|
|
34
|
+
.toolbar-button-container {
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: row !important;
|
|
37
|
+
margin: 5px !important;
|
|
38
|
+
align-items: center ;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.toolbar-button {
|
|
42
|
+
border: 1px solid #E7EAEF;
|
|
43
|
+
padding: 5px 10px;
|
|
44
|
+
border-radius: 20px;
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
margin-left: 10px;
|
|
49
|
+
white-space: nowrap;
|
|
50
|
+
user-select: none;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.toolbar-button-h5 {
|
|
54
|
+
border: none;
|
|
55
|
+
background-color: #fff;
|
|
56
|
+
box-shadow: 0px 2px 2px 0px rgba(70, 98, 140, 0.06);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.toolbar-button-icon {
|
|
60
|
+
margin-right: 3px;
|
|
61
|
+
}
|
|
62
|
+
.toolbar-button-text {
|
|
63
|
+
font-size: 12px;
|
|
64
|
+
text-overflow: ellipsis;
|
|
65
|
+
max-width: 100px;
|
|
66
|
+
overflow: hidden;
|
|
67
|
+
font-family: PingFangSC-Regular;
|
|
68
|
+
}
|
|
69
|
+
</style>
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
class="btn btn-cancel"
|
|
37
37
|
@click="close"
|
|
38
38
|
>
|
|
39
|
-
{{ TUITranslateService.t(
|
|
39
|
+
{{ TUITranslateService.t('取消') }}
|
|
40
40
|
</button>
|
|
41
41
|
<button
|
|
42
42
|
class="btn btn-default"
|
|
43
43
|
@click="submit"
|
|
44
44
|
>
|
|
45
|
-
{{ TUITranslateService.t(
|
|
45
|
+
{{ TUITranslateService.t('确定') }}
|
|
46
46
|
</button>
|
|
47
47
|
</footer>
|
|
48
48
|
</main>
|
|
@@ -374,7 +374,7 @@ const save = () => {
|
|
|
374
374
|
const imageSrc = imageMessage?.payload?.imageInfoArray[0]?.url;
|
|
375
375
|
if (!imageSrc) {
|
|
376
376
|
Toast({
|
|
377
|
-
message: TUITranslateService.t('
|
|
377
|
+
message: TUITranslateService.t('Component.图片 url 不存在'),
|
|
378
378
|
type: TOAST_TYPE.ERROR,
|
|
379
379
|
});
|
|
380
380
|
return;
|
|
@@ -396,7 +396,7 @@ const downloadImgInWeb = (src: string) => {
|
|
|
396
396
|
const imageFormat: number = imageMessage?.payload?.imageFormat;
|
|
397
397
|
if (!imageFormatMap.has(imageFormat)) {
|
|
398
398
|
Toast({
|
|
399
|
-
message: TUITranslateService.t('
|
|
399
|
+
message: TUITranslateService.t('Component.暂不支持下载此类型图片'),
|
|
400
400
|
type: TOAST_TYPE.ERROR,
|
|
401
401
|
});
|
|
402
402
|
return;
|
package/constant.ts
CHANGED
|
@@ -28,6 +28,7 @@ export const CUSTOM_MESSAGE_SRC = {
|
|
|
28
28
|
STREAM_TEXT: '31',
|
|
29
29
|
MULTI_BRANCH:'32',
|
|
30
30
|
MULTI_FORM:'33',
|
|
31
|
+
THINKING:'35',
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
// im message extra type
|
|
@@ -113,6 +114,7 @@ export const ROBOT_STATUS = {
|
|
|
113
114
|
// message type
|
|
114
115
|
export const TYPES = {
|
|
115
116
|
MSG_CUSTOM: 'TIMCustomElem',
|
|
117
|
+
MSG_GROUP_TIP:'TIMGroupTipElem'
|
|
116
118
|
};
|
|
117
119
|
|
|
118
120
|
export const EMOJI_TYPE = {
|
|
@@ -120,3 +122,16 @@ export const EMOJI_TYPE = {
|
|
|
120
122
|
BIG: 'big',
|
|
121
123
|
CUSTOM: 'CUSTOM',
|
|
122
124
|
};
|
|
125
|
+
|
|
126
|
+
export const WHITE_LIST = [
|
|
127
|
+
CUSTOM_MESSAGE_SRC.MENU,
|
|
128
|
+
CUSTOM_MESSAGE_SRC.BRANCH,
|
|
129
|
+
CUSTOM_MESSAGE_SRC.BRANCH_NUMBER,
|
|
130
|
+
CUSTOM_MESSAGE_SRC.FROM_INPUT,
|
|
131
|
+
CUSTOM_MESSAGE_SRC.PRODUCT_CARD,
|
|
132
|
+
CUSTOM_MESSAGE_SRC.ROBOT_MSG,
|
|
133
|
+
CUSTOM_MESSAGE_SRC.RICH_TEXT,
|
|
134
|
+
CUSTOM_MESSAGE_SRC.STREAM_TEXT,
|
|
135
|
+
CUSTOM_MESSAGE_SRC.MULTI_BRANCH,
|
|
136
|
+
CUSTOM_MESSAGE_SRC.MULTI_FORM,
|
|
137
|
+
];
|