@tencentcloud/ai-desk-customer-vue 1.1.0 → 1.4.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 +16 -3
- package/assets/customer_avatar.png +0 -0
- package/assets/face.svg +10 -0
- package/assets/files.svg +5 -0
- package/assets/image.svg +8 -0
- package/assets/rating_tool_icon.svg +5 -0
- package/assets/rating_tool_icon_h5.svg +1 -0
- package/assets/video.svg +8 -0
- package/assets/video_h5.svg +1 -0
- package/components/CustomerServiceChat/chat-header/index-web.vue +16 -14
- package/components/CustomerServiceChat/index-web.vue +72 -16
- package/components/CustomerServiceChat/message-input/index-web.vue +31 -5
- package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +24 -0
- package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue +1 -1
- package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/index.vue +1 -1
- package/components/CustomerServiceChat/message-input-toolbar/file-upload/index.vue +6 -8
- package/components/CustomerServiceChat/message-input-toolbar/image-upload/index.vue +11 -16
- package/components/CustomerServiceChat/message-input-toolbar/index-web.vue +61 -18
- package/components/CustomerServiceChat/message-input-toolbar/rating-tool/index.vue +72 -0
- package/components/CustomerServiceChat/message-input-toolbar/toolbar-item-container/style/h5.scss +10 -1
- package/components/CustomerServiceChat/message-input-toolbar/user-define-input-tool.vue +80 -0
- package/components/CustomerServiceChat/message-input-toolbar/video-upload/index.vue +9 -14
- package/components/CustomerServiceChat/message-list/index-web.vue +34 -6
- package/components/CustomerServiceChat/message-list/message-elements/message-bubble-web.vue +65 -19
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/marked.ts +1 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-branch.vue +30 -11
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-concurrency-limit.vue +40 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-desk.vue +29 -7
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/branch-pc.vue +107 -73
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/index.vue +53 -52
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-mobile/input-mobile.vue +73 -80
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-mobile/label-mobile.vue +21 -24
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-mobile/radios-mobile.vue +115 -116
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-pc/input-pc.vue +69 -73
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-pc/label-pc.vue +21 -25
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-pc/radio-pc.vue +87 -77
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-mobile.vue +213 -200
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-pc.vue +122 -113
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/index.vue +7 -7
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-order.vue +141 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-rich-text.vue +5 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-stream.vue +25 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-file.vue +1 -1
- package/components/CustomerServiceChat/message-list/scroll-button/index.vue +18 -6
- package/components/CustomerServiceChat/message-list/style/web.scss +2 -1
- package/components/CustomerServiceChat/message-toolbar-button/index.vue +111 -42
- package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-end-human-service.vue +59 -0
- package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-human-service.vue +55 -0
- package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-service-rating.vue +59 -0
- package/components/common/BottomPopup/index.vue +1 -1
- package/constant.ts +25 -4
- package/interface.ts +35 -5
- package/locales/en/aidesk.ts +6 -3
- package/locales/fil/aidesk.ts +4 -1
- package/locales/id/aidesk.ts +7 -4
- package/locales/ja/aidesk.ts +5 -2
- package/locales/ms/aidesk.ts +5 -2
- package/locales/ru/aidesk.ts +6 -3
- package/locales/th/aidesk.ts +4 -1
- package/locales/vi/aidesk.ts +5 -2
- package/locales/zh_cn/aidesk.ts +5 -3
- package/locales/zh_tw/aidesk.ts +4 -1
- package/package.json +1 -1
- package/server.ts +11 -2
- package/utils/state.js +30 -0
- package/utils/utils.ts +48 -1
- package/assets/face.png +0 -0
- package/assets/files.png +0 -0
- package/assets/image.png +0 -0
- package/assets/video.png +0 -0
|
@@ -11,20 +11,48 @@
|
|
|
11
11
|
!isPC && 'message-input-toolbar-h5-list',
|
|
12
12
|
]"
|
|
13
13
|
>
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
<template v-if="props.inputToolbarList === undefined">
|
|
15
|
+
<EmojiPicker
|
|
16
|
+
v-if="isPC"
|
|
17
|
+
ref="emojiPickerRef"
|
|
18
|
+
@insertEmoji="insertEmoji"
|
|
19
|
+
@dialogShowInH5="dialogShowInH5"
|
|
20
|
+
@dialogCloseInH5="dialogCloseInH5"
|
|
21
|
+
@changeToolbarDisplayType="
|
|
22
|
+
(type) => emits('changeToolbarDisplayType', type)
|
|
23
|
+
"
|
|
24
|
+
:isH5EmojiShow="isH5EmojiShow"
|
|
25
|
+
@sendMessage="sendMessage"
|
|
26
|
+
/>
|
|
27
|
+
<ImageUpload imageSourceType="album" :isH5ToolShow="isH5ToolShow"/>
|
|
28
|
+
<FileUpload :isH5ToolShow="isH5ToolShow"/>
|
|
29
|
+
</template>
|
|
30
|
+
<template v-else v-for="(item, index) in props.inputToolbarList" :key="index">
|
|
31
|
+
<EmojiPicker
|
|
32
|
+
v-if="isPC && item.presetId === INPUT_TOOLBAR_TYPE.EMOJI && item.isEnabled === 1"
|
|
33
|
+
ref="emojiPickerRef"
|
|
34
|
+
@insertEmoji="insertEmoji"
|
|
35
|
+
@dialogShowInH5="dialogShowInH5"
|
|
36
|
+
@dialogCloseInH5="dialogCloseInH5"
|
|
37
|
+
@changeToolbarDisplayType="
|
|
38
|
+
(type) => emits('changeToolbarDisplayType', type)
|
|
39
|
+
"
|
|
40
|
+
:isH5EmojiShow="isH5EmojiShow"
|
|
41
|
+
@sendMessage="sendMessage"
|
|
42
|
+
/>
|
|
43
|
+
<ImageUpload v-else-if="item.presetId === INPUT_TOOLBAR_TYPE.IMAGE && item.isEnabled === 1" imageSourceType="album" :isH5ToolShow="isH5ToolShow"/>
|
|
44
|
+
<FileUpload v-else-if="item.presetId === INPUT_TOOLBAR_TYPE.FILE && item.isEnabled === 1" :isH5ToolShow="isH5ToolShow"/>
|
|
45
|
+
<VideoUpload v-else-if="item.presetId === INPUT_TOOLBAR_TYPE.VIDEO && item.isEnabled === 1" videoSourceType="album" :isH5ToolShow="isH5ToolShow"/>
|
|
46
|
+
<RatingTool v-else-if="item.presetId === INPUT_TOOLBAR_TYPE.RATING && item.isEnabled === 1 && isInHumanService" :isH5ToolShow="isH5ToolShow"/>
|
|
47
|
+
<UserDefineTool
|
|
48
|
+
v-else-if="item.isEnabled === 1 && item.isPreset === 0 && item.presetId !== INPUT_TOOLBAR_TYPE.EMOJI"
|
|
49
|
+
:isH5ToolShow="isH5ToolShow"
|
|
50
|
+
:title="item.title"
|
|
51
|
+
:icon="item.icon"
|
|
52
|
+
:type="item.type"
|
|
53
|
+
:content="item.content"
|
|
54
|
+
/>
|
|
55
|
+
</template>
|
|
28
56
|
</div>
|
|
29
57
|
<div
|
|
30
58
|
v-if="isH5"
|
|
@@ -44,14 +72,18 @@ import EmojiPicker from './emoji-picker/index.vue';
|
|
|
44
72
|
import ImageUpload from './image-upload/index.vue';
|
|
45
73
|
import FileUpload from './file-upload/index.vue';
|
|
46
74
|
import VideoUpload from './video-upload/index.vue';
|
|
75
|
+
import RatingTool from './rating-tool/index.vue';
|
|
47
76
|
import { isPC, isH5 } from '../../../utils/env';
|
|
48
|
-
import { ToolbarDisplayType } from '../../../interface';
|
|
77
|
+
import { ToolbarDisplayType, InputToolbarModel } from '../../../interface';
|
|
78
|
+
import UserDefineTool from './user-define-input-tool.vue'
|
|
79
|
+
import { INPUT_TOOLBAR_TYPE } from '../../../constant';
|
|
49
80
|
const { ref, onMounted, onUnmounted, watch } = vue;
|
|
50
81
|
|
|
51
82
|
interface IProps {
|
|
52
83
|
displayType: ToolbarDisplayType;
|
|
53
|
-
isH5EmojiShow?:boolean;
|
|
54
|
-
isH5ToolShow?:boolean;
|
|
84
|
+
isH5EmojiShow?: boolean;
|
|
85
|
+
isH5ToolShow?: boolean;
|
|
86
|
+
inputToolbarList?: InputToolbarModel[];
|
|
55
87
|
}
|
|
56
88
|
interface IEmits {
|
|
57
89
|
(e: 'scrollToLatestMessage'): void;
|
|
@@ -70,17 +102,24 @@ const h5Dialog = ref<HTMLElement>();
|
|
|
70
102
|
const currentConversation = ref<IConversationModel>();
|
|
71
103
|
const isGroup = ref<boolean>(false);
|
|
72
104
|
const emojiPickerRef = ref<InstanceType<typeof EmojiPicker>>();
|
|
105
|
+
const isInHumanService = ref(false);
|
|
73
106
|
|
|
74
107
|
onMounted(() => {
|
|
75
108
|
TUIStore.watch(StoreName.CONV, {
|
|
76
109
|
currentConversation: onCurrentConversationUpdate,
|
|
77
110
|
});
|
|
111
|
+
TUIStore.watch(StoreName.CUSTOM, {
|
|
112
|
+
isInHumanService: onInHumanServiceUpdate,
|
|
113
|
+
});
|
|
78
114
|
});
|
|
79
115
|
|
|
80
116
|
onUnmounted(() => {
|
|
81
117
|
TUIStore.unwatch(StoreName.CONV, {
|
|
82
118
|
currentConversation: onCurrentConversationUpdate,
|
|
83
119
|
});
|
|
120
|
+
TUIStore.unwatch(StoreName.CUSTOM, {
|
|
121
|
+
isInHumanService: onInHumanServiceUpdate,
|
|
122
|
+
});
|
|
84
123
|
});
|
|
85
124
|
|
|
86
125
|
watch(
|
|
@@ -99,7 +138,7 @@ watch(
|
|
|
99
138
|
(newValue) => {
|
|
100
139
|
if (newValue === false) {
|
|
101
140
|
emojiPickerRef.value?.closeEmojiPicker();
|
|
102
|
-
}
|
|
141
|
+
}
|
|
103
142
|
},
|
|
104
143
|
);
|
|
105
144
|
|
|
@@ -109,6 +148,10 @@ const onCurrentConversationUpdate = (conversation: IConversationModel) => {
|
|
|
109
148
|
= currentConversation?.value?.type === TUIChatEngine.TYPES.CONV_GROUP;
|
|
110
149
|
};
|
|
111
150
|
|
|
151
|
+
const onInHumanServiceUpdate = (value: boolean) => {
|
|
152
|
+
isInHumanService.value = value;
|
|
153
|
+
};
|
|
154
|
+
|
|
112
155
|
const insertEmoji = (emojiObj: object) => {
|
|
113
156
|
emits('insertEmoji', emojiObj);
|
|
114
157
|
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ToolbarItemContainer
|
|
3
|
+
:iconFile="getIcon()"
|
|
4
|
+
:title="props.title"
|
|
5
|
+
:iconWidth="isPC ? '20px' : '25px'"
|
|
6
|
+
:iconHeight="isPC ? '20px' : '25px'"
|
|
7
|
+
:needDialog="false"
|
|
8
|
+
@onIconClick="onIconClick"
|
|
9
|
+
:isH5ToolShow="isH5ToolShow"
|
|
10
|
+
/>
|
|
11
|
+
</template>
|
|
12
|
+
<script lang="ts" setup>
|
|
13
|
+
import {
|
|
14
|
+
TUIChatService,
|
|
15
|
+
TUIStore,
|
|
16
|
+
StoreName,
|
|
17
|
+
IConversationModel,
|
|
18
|
+
TUITranslateService,
|
|
19
|
+
} from '@tencentcloud/chat-uikit-engine';
|
|
20
|
+
import vue from '../../../../adapter-vue';
|
|
21
|
+
import { isPC, isH5 } from '../../../../utils/env';
|
|
22
|
+
import ToolbarItemContainer from '../toolbar-item-container/index.vue';
|
|
23
|
+
import ratingToolIcon from '../../../../assets/rating_tool_icon.svg'
|
|
24
|
+
import ratingToolIconH5 from '../../../../assets/rating_tool_icon_h5.svg';
|
|
25
|
+
import { getTo } from '../../../../utils/utils';
|
|
26
|
+
import { CUSTOM_MESSAGE_SRC } from '../../../../constant';
|
|
27
|
+
const { ref, onMounted, onUnmounted } = vue;
|
|
28
|
+
|
|
29
|
+
const props = defineProps({
|
|
30
|
+
isH5ToolShow:{
|
|
31
|
+
type: Boolean,
|
|
32
|
+
default: false,
|
|
33
|
+
},
|
|
34
|
+
title: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: TUITranslateService.t('AIDesk.提交评价')
|
|
37
|
+
},
|
|
38
|
+
icon: {
|
|
39
|
+
type: String,
|
|
40
|
+
default: '',
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const currentConversation = ref<IConversationModel>();
|
|
45
|
+
|
|
46
|
+
TUIStore.watch(StoreName.CONV, {
|
|
47
|
+
currentConversation: (conversation: IConversationModel) => {
|
|
48
|
+
currentConversation.value = conversation;
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const getIcon = (): string => {
|
|
53
|
+
return isH5 ? ratingToolIconH5 : ratingToolIcon;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const onIconClick = () => {
|
|
57
|
+
TUIChatService.sendCustomMessage({
|
|
58
|
+
to: getTo(currentConversation?.value),
|
|
59
|
+
conversationType: currentConversation?.value?.type,
|
|
60
|
+
payload:{
|
|
61
|
+
data:JSON.stringify({
|
|
62
|
+
src: CUSTOM_MESSAGE_SRC.USER_SATISFACTION,
|
|
63
|
+
customerServicePlugin: 0,
|
|
64
|
+
}),
|
|
65
|
+
},
|
|
66
|
+
},{ onlineUserOnly: true })
|
|
67
|
+
};
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<style lang="scss" scoped>
|
|
71
|
+
@import "../../style/common";
|
|
72
|
+
</style>
|
package/components/CustomerServiceChat/message-input-toolbar/toolbar-item-container/style/h5.scss
CHANGED
|
@@ -6,11 +6,20 @@
|
|
|
6
6
|
margin-right:15px;
|
|
7
7
|
&-title {
|
|
8
8
|
margin-top:5px;
|
|
9
|
+
font-size: 14px;
|
|
10
|
+
white-space: nowrap;
|
|
11
|
+
max-width: 85px;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
text-overflow: ellipsis;
|
|
9
14
|
}
|
|
10
15
|
&-icon{
|
|
11
16
|
background-color: #fff;
|
|
12
|
-
|
|
17
|
+
width: 40px;
|
|
13
18
|
border-radius: 10px;
|
|
19
|
+
height: 40px;
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
14
23
|
}
|
|
15
24
|
&-dialog {
|
|
16
25
|
position: static !important;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ToolbarItemContainer
|
|
3
|
+
:iconFile="getIcon()"
|
|
4
|
+
:title="props.title"
|
|
5
|
+
:iconWidth="isPC ? '20px' : '25px'"
|
|
6
|
+
:iconHeight="isPC ? '20px' : '25px'"
|
|
7
|
+
:needDialog="false"
|
|
8
|
+
@onIconClick="onIconClick"
|
|
9
|
+
:isH5ToolShow="isH5ToolShow">
|
|
10
|
+
<div :class="['image-upload', !isPC && 'image-upload-h5', 'image-video']">
|
|
11
|
+
</div>
|
|
12
|
+
</ToolbarItemContainer>
|
|
13
|
+
</template>
|
|
14
|
+
<script lang="ts" setup>
|
|
15
|
+
import {
|
|
16
|
+
TUIChatService,
|
|
17
|
+
TUIStore,
|
|
18
|
+
StoreName,
|
|
19
|
+
IConversationModel,
|
|
20
|
+
} from '@tencentcloud/chat-uikit-engine';
|
|
21
|
+
import vue from '../../../adapter-vue';
|
|
22
|
+
import { isPC } from '../../../utils/env';
|
|
23
|
+
import ToolbarItemContainer from './toolbar-item-container/index.vue';
|
|
24
|
+
import { isEnabledMessageReadReceiptGlobal, openSafeUrl, getTo } from '../../../utils/utils';
|
|
25
|
+
const { ref } = vue;
|
|
26
|
+
|
|
27
|
+
const props = defineProps({
|
|
28
|
+
isH5ToolShow: {
|
|
29
|
+
type: Boolean,
|
|
30
|
+
default: false,
|
|
31
|
+
},
|
|
32
|
+
title: {
|
|
33
|
+
type: String,
|
|
34
|
+
default: ''
|
|
35
|
+
},
|
|
36
|
+
icon: {
|
|
37
|
+
type: String,
|
|
38
|
+
default: '',
|
|
39
|
+
},
|
|
40
|
+
type: {
|
|
41
|
+
type: Number,
|
|
42
|
+
default: 1
|
|
43
|
+
},
|
|
44
|
+
content: {
|
|
45
|
+
type: String,
|
|
46
|
+
default: ''
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const currentConversation = ref<IConversationModel>();
|
|
51
|
+
|
|
52
|
+
TUIStore.watch(StoreName.CONV, {
|
|
53
|
+
currentConversation: (conversation: IConversationModel) => {
|
|
54
|
+
currentConversation.value = conversation;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const getIcon = (): string => {
|
|
59
|
+
return props.icon;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const onIconClick = () => {
|
|
63
|
+
if (props.type === 1 && props.content) {
|
|
64
|
+
TUIChatService.sendTextMessage({
|
|
65
|
+
to: getTo(currentConversation?.value),
|
|
66
|
+
conversationType: currentConversation?.value?.type,
|
|
67
|
+
payload: {
|
|
68
|
+
text: props.content
|
|
69
|
+
},
|
|
70
|
+
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
|
|
71
|
+
});
|
|
72
|
+
} else if (props.type === 2 && props.content) {
|
|
73
|
+
openSafeUrl(props.content);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<style lang="scss" scoped>
|
|
79
|
+
@import "../style/common";
|
|
80
|
+
</style>
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
:iconFile="handleIcon()"
|
|
4
4
|
:title="handleTitle()"
|
|
5
5
|
:needDialog="false"
|
|
6
|
-
iconWidth='
|
|
7
|
-
iconHeight='
|
|
6
|
+
iconWidth='20px'
|
|
7
|
+
iconHeight='20px'
|
|
8
8
|
@onIconClick="onIconClick"
|
|
9
9
|
>
|
|
10
10
|
<div :class="['video-upload', !isPC && 'video-upload-h5']">
|
|
@@ -32,8 +32,9 @@ import {
|
|
|
32
32
|
import vue from '../../../../adapter-vue';
|
|
33
33
|
import { isPC } from '../../../../utils/env';
|
|
34
34
|
import ToolbarItemContainer from '../toolbar-item-container/index.vue';
|
|
35
|
-
import videoIcon from '../../../../assets/video.
|
|
36
|
-
import
|
|
35
|
+
import videoIcon from '../../../../assets/video.svg';
|
|
36
|
+
import videoIconH5 from '../../../../assets/video_h5.svg'
|
|
37
|
+
import { isEnabledMessageReadReceiptGlobal, getTo } from '../../../../utils/utils';
|
|
37
38
|
const { ref } = vue;
|
|
38
39
|
|
|
39
40
|
const props = defineProps({
|
|
@@ -56,19 +57,15 @@ TUIStore.watch(StoreName.CONV, {
|
|
|
56
57
|
});
|
|
57
58
|
|
|
58
59
|
const handleIcon = (): string => {
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
return isPC ? videoIcon : videoIconH5;
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
const handleTitle = (): string => {
|
|
64
|
-
|
|
65
|
-
return '视频';
|
|
66
|
-
|
|
64
|
+
return TUITranslateService.t('视频');
|
|
67
65
|
};
|
|
68
66
|
|
|
69
67
|
const onIconClick = () => {
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
inputRef?.value?.click && inputRef?.value?.click();
|
|
72
69
|
};
|
|
73
70
|
|
|
74
71
|
const sendVideoInWeb = (e: any) => {
|
|
@@ -84,9 +81,7 @@ const sendVideoMessage = (file: any) => {
|
|
|
84
81
|
return;
|
|
85
82
|
}
|
|
86
83
|
const options = {
|
|
87
|
-
to:
|
|
88
|
-
currentConversation?.value?.groupProfile?.groupID
|
|
89
|
-
|| currentConversation?.value?.userProfile?.userID,
|
|
84
|
+
to: getTo(currentConversation?.value),
|
|
90
85
|
conversationType: currentConversation?.value?.type,
|
|
91
86
|
payload: {
|
|
92
87
|
file,
|
|
@@ -217,8 +217,9 @@ import {
|
|
|
217
217
|
isEnabledMessageReadReceiptGlobal,
|
|
218
218
|
deepCopy,
|
|
219
219
|
} from '../../../utils/utils';
|
|
220
|
-
import { isMessageInvisible, isThinkingMessage, isThinkingMessageOverTime } from '../../../utils/index';
|
|
220
|
+
import { isMessageInvisible, isThinkingMessage, isThinkingMessageOverTime, JSONToObject } from '../../../utils/index';
|
|
221
221
|
import { isCustomerConversation } from '../../../index';
|
|
222
|
+
import { CUSTOM_MESSAGE_SRC } from '../../../constant';
|
|
222
223
|
|
|
223
224
|
interface ScrollConfig {
|
|
224
225
|
scrollToMessage?: IMessageModel;
|
|
@@ -290,9 +291,9 @@ onMounted(() => {
|
|
|
290
291
|
messageList: onMessageListUpdated,
|
|
291
292
|
messageSource: onMessageSourceUpdated,
|
|
292
293
|
isCompleted: isCompletedUpdated,
|
|
294
|
+
newMessageList: onNewMessageList,
|
|
293
295
|
});
|
|
294
296
|
|
|
295
|
-
|
|
296
297
|
TUIStore.watch(StoreName.CUSTOM, {
|
|
297
298
|
isShowMessagePopMenu: isShowMessagePopMenuUpdated,
|
|
298
299
|
});
|
|
@@ -329,6 +330,29 @@ onUnmounted(() => {
|
|
|
329
330
|
observer = null;
|
|
330
331
|
});
|
|
331
332
|
|
|
333
|
+
function onNewMessageList(list: IMessageModel[]) {
|
|
334
|
+
list.forEach((message:IMessageModel) => {
|
|
335
|
+
if (message?.type === TUIChatEngine.TYPES.MSG_CUSTOM) {
|
|
336
|
+
const data = JSONToObject(message?.payload?.data);
|
|
337
|
+
if (data?.src === CUSTOM_MESSAGE_SRC.SEAT_STATUS) {
|
|
338
|
+
if (data?.content.command === "updateSeatStatus") {
|
|
339
|
+
if (data.content.content === 'inSeat') {
|
|
340
|
+
TUIStore.update(StoreName.CUSTOM, "isInHumanService", true);
|
|
341
|
+
} else if (data.content.content === 'outSeat') {
|
|
342
|
+
TUIStore.update(StoreName.CUSTOM, "isInHumanService", false);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
} else if (data?.src === CUSTOM_MESSAGE_SRC.TYPING_STATE) {
|
|
346
|
+
if (data?.typingStatus === 1) {
|
|
347
|
+
TUIStore.update(StoreName.CUSTOM, 'isTyping', true);
|
|
348
|
+
} else {
|
|
349
|
+
TUIStore.update(StoreName.CUSTOM, 'isTyping', false);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
332
356
|
async function onMessageListUpdated(list: IMessageModel[]) {
|
|
333
357
|
if (!isCustomerConversation(currentConversationID.value)) {
|
|
334
358
|
return;
|
|
@@ -370,7 +394,6 @@ async function onMessageListUpdated(list: IMessageModel[]) {
|
|
|
370
394
|
await scrollToPosition({
|
|
371
395
|
scrollToOffset: { bottom: beforeHistoryGetScrollHeight.value },
|
|
372
396
|
});
|
|
373
|
-
beforeHistoryGetScrollHeight.value = 0;
|
|
374
397
|
} else if (
|
|
375
398
|
scrollButtonInstanceRef.value?.isScrollButtonVisible
|
|
376
399
|
&& newLastMessage?.flow === 'in'
|
|
@@ -425,8 +448,7 @@ async function scrollToPosition(config: ScrollConfig = {}): Promise<void> {
|
|
|
425
448
|
if (config.scrollToOffset?.top) {
|
|
426
449
|
container!.scrollTop = config.scrollToOffset.top;
|
|
427
450
|
} else if (config.scrollToOffset?.bottom) {
|
|
428
|
-
container!.scrollTop
|
|
429
|
-
= container!.scrollHeight - config.scrollToOffset.bottom;
|
|
451
|
+
container!.scrollTop = container!.scrollHeight - config.scrollToOffset.bottom;
|
|
430
452
|
}
|
|
431
453
|
}
|
|
432
454
|
resolve();
|
|
@@ -574,6 +596,11 @@ const handleH5LongPress = (e: any, message: IMessageModel, type: string) => {
|
|
|
574
596
|
};
|
|
575
597
|
|
|
576
598
|
function onHeightChanged() {
|
|
599
|
+
// 如果 view more 导致了子组件派发了 heightChanged 事件,不滚动到最底部,保留原来的滚动位置
|
|
600
|
+
if (beforeHistoryGetScrollHeight.value > 0) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
|
|
577
604
|
scrollToLatestMessage();
|
|
578
605
|
}
|
|
579
606
|
|
|
@@ -616,6 +643,8 @@ async function scrollToLatestMessage() {
|
|
|
616
643
|
if (messageListRef.value) {
|
|
617
644
|
messageListRef.value.scrollTop = scrollHeight - height;
|
|
618
645
|
}
|
|
646
|
+
scrollButtonInstanceRef.value?.hideScrollButton();
|
|
647
|
+
beforeHistoryGetScrollHeight.value = 0;
|
|
619
648
|
}
|
|
620
649
|
|
|
621
650
|
const handelScrollListScroll = throttle(
|
|
@@ -708,7 +737,6 @@ function setAudioPlayed(messageID: string) {
|
|
|
708
737
|
};
|
|
709
738
|
}
|
|
710
739
|
|
|
711
|
-
|
|
712
740
|
defineExpose({
|
|
713
741
|
scrollToLatestMessage,
|
|
714
742
|
});
|
|
@@ -12,21 +12,19 @@
|
|
|
12
12
|
:class="[message.flow === 'in' ? '' : 'reverse']"
|
|
13
13
|
>
|
|
14
14
|
<Avatar
|
|
15
|
-
|
|
15
|
+
v-if="isPC && showAvatar === 1"
|
|
16
16
|
useSkeletonAnimation
|
|
17
|
-
:url="
|
|
17
|
+
:url="avatarUrl"
|
|
18
18
|
/>
|
|
19
19
|
<main
|
|
20
20
|
:class="['message-body',message.flow==='out' && 'message-body-reverse']"
|
|
21
21
|
@click.stop
|
|
22
22
|
>
|
|
23
23
|
<div
|
|
24
|
-
v-if="
|
|
25
|
-
isPC
|
|
26
|
-
"
|
|
24
|
+
v-if="isPC && showNickName === 1"
|
|
27
25
|
class="message-body-nick-name"
|
|
28
26
|
>
|
|
29
|
-
{{
|
|
27
|
+
{{ nickName }}
|
|
30
28
|
</div>
|
|
31
29
|
<div
|
|
32
30
|
:class="[
|
|
@@ -44,7 +42,7 @@
|
|
|
44
42
|
isNoPadding && isBlink ? 'blink-shadow' : '',
|
|
45
43
|
!isNoPadding && isBlink ? 'blink-content' : '',
|
|
46
44
|
isMultiBranchMsg?'multi-branch-message':'',
|
|
47
|
-
(
|
|
45
|
+
(isProductCardOrOrderMessage && isH5) ? 'product-order-message-bubble-h5' : (isProductCardOrOrderMessage ? 'product-order-message-bubble' : ''),
|
|
48
46
|
isPC ? '':'body-mobile',
|
|
49
47
|
]"
|
|
50
48
|
>
|
|
@@ -142,6 +140,8 @@ import loadingIcon from '../../../../assets/loading.png';
|
|
|
142
140
|
import customerAvatar from '../../../../assets/customer_avatar.png';
|
|
143
141
|
import { shallowCopyMessage } from '../../../../utils/utils';
|
|
144
142
|
import { isPC,isH5 } from '../../../../utils/env';
|
|
143
|
+
import { JSONToObject } from '../../../../utils/index';
|
|
144
|
+
import state from '../../../../utils/state.js';
|
|
145
145
|
import { CUSTOM_MESSAGE_SRC } from '../../../../constant';
|
|
146
146
|
const { computed, toRefs } = vue;
|
|
147
147
|
|
|
@@ -182,6 +182,16 @@ const needLoadingIconMessageType = [
|
|
|
182
182
|
];
|
|
183
183
|
|
|
184
184
|
const { blinkMessageIDList, messageItem: message } = toRefs(props);
|
|
185
|
+
const {
|
|
186
|
+
showAvatar,
|
|
187
|
+
showNickName,
|
|
188
|
+
robotAvatar,
|
|
189
|
+
staffAvatar,
|
|
190
|
+
userAvatar,
|
|
191
|
+
robotNickName,
|
|
192
|
+
staffNickName,
|
|
193
|
+
userNickName,
|
|
194
|
+
} = state.get('avatarNickName');
|
|
185
195
|
|
|
186
196
|
const isDisplayUnplayMark = computed<boolean>(() => {
|
|
187
197
|
return (
|
|
@@ -204,20 +214,56 @@ const hasEmojiReaction = computed(() => {
|
|
|
204
214
|
});
|
|
205
215
|
|
|
206
216
|
const isMultiBranchMsg = computed(()=>{
|
|
207
|
-
if(message.value?.type == "TIMCustomElem"){
|
|
208
|
-
|
|
209
|
-
|
|
217
|
+
if (message.value?.type == "TIMCustomElem") {
|
|
218
|
+
const src = JSON.parse(message.value.payload.data).src;
|
|
219
|
+
if (src === CUSTOM_MESSAGE_SRC.MULTI_BRANCH || src === CUSTOM_MESSAGE_SRC.BRANCH || src === CUSTOM_MESSAGE_SRC.BRANCH_NUMBER) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
210
222
|
}
|
|
223
|
+
return false;
|
|
224
|
+
});
|
|
211
225
|
|
|
226
|
+
function isFromRobot(cloudCustomData: string) {
|
|
227
|
+
try {
|
|
228
|
+
const jsonObj = JSONToObject(cloudCustomData);
|
|
229
|
+
return jsonObj.hasOwnProperty("role") && jsonObj.role === "robot";
|
|
230
|
+
} catch (e) {
|
|
231
|
+
return false;
|
|
212
232
|
}
|
|
213
|
-
|
|
214
|
-
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const avatarUrl = computed(() => {
|
|
236
|
+
let url = '';
|
|
237
|
+
if (message.value?.flow === 'in') {
|
|
238
|
+
if (isFromRobot(message.value?.cloudCustomData)) {
|
|
239
|
+
url = robotAvatar || customerAvatar;
|
|
240
|
+
} else {
|
|
241
|
+
url = staffAvatar || message.value?.avatar;
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
url = userAvatar || message.value?.avatar || '';
|
|
245
|
+
}
|
|
246
|
+
return url;
|
|
215
247
|
});
|
|
216
248
|
|
|
249
|
+
const nickName = computed(() => {
|
|
250
|
+
let nick = '';
|
|
251
|
+
if (message.value?.flow === 'in') {
|
|
252
|
+
if (isFromRobot(message.value?.cloudCustomData)) {
|
|
253
|
+
nick = robotNickName || props.content.showName;
|
|
254
|
+
} else {
|
|
255
|
+
nick = staffNickName || props.content.showName;
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
nick = userNickName || props.content.showName;
|
|
259
|
+
}
|
|
260
|
+
return nick;
|
|
261
|
+
});
|
|
217
262
|
|
|
218
|
-
const
|
|
263
|
+
const isProductCardOrOrderMessage = computed(() => {
|
|
219
264
|
if (message.value?.type == "TIMCustomElem") {
|
|
220
|
-
|
|
265
|
+
const src = JSON.parse(message.value.payload.data).src;
|
|
266
|
+
if (src === CUSTOM_MESSAGE_SRC.PRODUCT_CARD || src === CUSTOM_MESSAGE_SRC.ORDER) {
|
|
221
267
|
return true;
|
|
222
268
|
}
|
|
223
269
|
}
|
|
@@ -395,8 +441,8 @@ function scrollTo(scrollHeight: number) {
|
|
|
395
441
|
padding-top: 5px;
|
|
396
442
|
}
|
|
397
443
|
}
|
|
398
|
-
|
|
399
|
-
|
|
444
|
+
|
|
445
|
+
|
|
400
446
|
.content-in {
|
|
401
447
|
background: #f3f4f7;
|
|
402
448
|
border-radius: 0 10px 10px;
|
|
@@ -411,12 +457,12 @@ function scrollTo(scrollHeight: number) {
|
|
|
411
457
|
border-radius: 0 10px 10px;
|
|
412
458
|
padding: 0px;
|
|
413
459
|
}
|
|
414
|
-
|
|
415
|
-
.product-message-bubble {
|
|
460
|
+
|
|
461
|
+
.product-order-message-bubble {
|
|
416
462
|
background: #f3f4f7 !important ;
|
|
417
463
|
}
|
|
418
464
|
|
|
419
|
-
.product-message-bubble-h5 {
|
|
465
|
+
.product-order-message-bubble-h5 {
|
|
420
466
|
background: #fff !important ;
|
|
421
467
|
}
|
|
422
468
|
|
|
@@ -10,7 +10,7 @@ export const marked = new Marked(
|
|
|
10
10
|
class="image-container"
|
|
11
11
|
onclick="onMarkdownImageClicked('${safeHref}')"
|
|
12
12
|
style="cursor:pointer;" >
|
|
13
|
-
<img src="${href}" alt="${text}"/>
|
|
13
|
+
<img src="${href}" alt="${text}" onload="onMarkdownImageLoad()"/>
|
|
14
14
|
</div>
|
|
15
15
|
`;
|
|
16
16
|
},
|