@tencentcloud/ai-desk-customer-vue 1.5.2 → 1.5.4

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +316 -71
  3. package/assets/language_arrow_down.svg +3 -0
  4. package/assets/language_check.svg +3 -0
  5. package/components/CustomerServiceChat/chat-header/index-web.vue +215 -13
  6. package/components/CustomerServiceChat/emoji-config/index.ts +3 -2
  7. package/components/CustomerServiceChat/index-web.vue +87 -25
  8. package/components/CustomerServiceChat/message-input/index-web.vue +9 -2
  9. package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +11 -0
  10. package/components/CustomerServiceChat/message-input/message-input-quote/index.vue +31 -6
  11. package/components/CustomerServiceChat/message-input-toolbar/file-upload/index.vue +14 -4
  12. package/components/CustomerServiceChat/message-input-toolbar/image-upload/index.vue +19 -16
  13. package/components/CustomerServiceChat/message-input-toolbar/index-web.vue +4 -4
  14. package/components/CustomerServiceChat/message-input-toolbar/video-upload/index.vue +10 -3
  15. package/components/CustomerServiceChat/message-list/index-web.vue +27 -14
  16. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-desk.vue +6 -1
  17. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/branch-pc.vue +20 -13
  18. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/index.vue +1 -0
  19. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-robot-welcome.vue +73 -29
  20. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-transfer-with-desc.vue +51 -0
  21. package/components/CustomerServiceChat/message-list/message-elements/message-quote/index-web.vue +18 -9
  22. package/components/CustomerServiceChat/message-toolbar-button/index.vue +13 -2
  23. package/components/CustomerServiceChat/style/web.scss +2 -0
  24. package/components/CustomerServiceChat/utils/sendMessage.ts +5 -0
  25. package/constant.ts +21 -1
  26. package/interface.ts +16 -3
  27. package/locales/en/TUIChat.ts +2 -1
  28. package/locales/en/aidesk.ts +4 -4
  29. package/locales/en/index.ts +2 -2
  30. package/locales/en/time.ts +2 -2
  31. package/locales/fil/TUIChat.ts +1 -0
  32. package/locales/fil/index.ts +2 -2
  33. package/locales/fil/time.ts +2 -2
  34. package/locales/id/TUIChat.ts +161 -160
  35. package/locales/id/index.ts +2 -2
  36. package/locales/id/time.ts +2 -2
  37. package/locales/ja/TUIChat.ts +162 -161
  38. package/locales/ja/index.ts +2 -2
  39. package/locales/ja/time.ts +2 -2
  40. package/locales/ms/TUIChat.ts +162 -161
  41. package/locales/ms/index.ts +2 -2
  42. package/locales/ms/time.ts +2 -2
  43. package/locales/ru/TUIChat.ts +155 -154
  44. package/locales/ru/index.ts +2 -2
  45. package/locales/ru/time.ts +2 -2
  46. package/locales/th/TUIChat.ts +162 -161
  47. package/locales/th/index.ts +2 -2
  48. package/locales/th/time.ts +2 -2
  49. package/locales/vi/TUIChat.ts +153 -152
  50. package/locales/vi/index.ts +2 -2
  51. package/locales/vi/time.ts +2 -2
  52. package/locales/zh_cn/TUIChat.ts +1 -0
  53. package/locales/zh_cn/aidesk.ts +1 -1
  54. package/locales/zh_cn/index.ts +2 -2
  55. package/locales/zh_cn/time.ts +2 -2
  56. package/locales/zh_tw/TUIChat.ts +1 -0
  57. package/locales/zh_tw/aidesk.ts +1 -1
  58. package/locales/zh_tw/index.ts +2 -2
  59. package/locales/zh_tw/time.ts +2 -2
  60. package/package.json +5 -6
  61. package/server.ts +63 -10
  62. package/utils/index.ts +6 -13
  63. package/utils/utils.ts +96 -2
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <ToolbarItemContainer
3
- :iconFile="isH5?fileIconH5:fileIcon"
4
- :title="TUITranslateService.t('文件')"
3
+ :iconFile="isH5 ? fileIconH5 : fileIcon"
4
+ :title="props.title || TUITranslateService.t('文件')"
5
5
  iconWidth='20px'
6
6
  iconHeight='20px'
7
7
  :needDialog="false"
@@ -10,7 +10,7 @@
10
10
  <div :class="['file-upload', !isPC && 'file-upload-h5']">
11
11
  <input
12
12
  ref="inputRef"
13
- :title="TUITranslateService.t('文件')"
13
+ :title="props.title || TUITranslateService.t('文件')"
14
14
  type="file"
15
15
  data-type="file"
16
16
  accept="*"
@@ -39,6 +39,12 @@ import Log from '../../../../utils/logger';
39
39
  import { Toast, TOAST_TYPE } from '../../../common/Toast/index-web';
40
40
  const { ref } = vue;
41
41
 
42
+ const props = defineProps({
43
+ title: {
44
+ type: String,
45
+ },
46
+ });
47
+
42
48
  const inputRef = ref();
43
49
  const currentConversation = ref<IConversationModel>();
44
50
 
@@ -56,11 +62,15 @@ const sendFileMessage = (e: any) => {
56
62
  if (e?.target?.files?.length <= 0) {
57
63
  return;
58
64
  }
65
+ const file = e.target.files[0];
66
+ if (!file || !file.size) {
67
+ return;
68
+ }
59
69
  const options = {
60
70
  to: getTo(currentConversation?.value),
61
71
  conversationType: currentConversation?.value?.type,
62
72
  payload: {
63
- file: e?.target,
73
+ file: e.target,
64
74
  },
65
75
  needReadReceipt: isEnabledMessageReadReceiptGlobal(),
66
76
  } as SendMessageParams;
@@ -13,7 +13,7 @@
13
13
  >
14
14
  <input
15
15
  ref="inputRef"
16
- :title="TUITranslateService.t('图片')"
16
+ :title="props.title || TUITranslateService.t('图片')"
17
17
  type="file"
18
18
  accept="image/gif,image/jpeg,image/jpg,image/png,image/bmp,image/webp,video/mov,video/mp4"
19
19
  @change="sendImageInWeb"
@@ -31,7 +31,6 @@ import {
31
31
  SendMessageOptions,
32
32
  TUITranslateService
33
33
  } from '@tencentcloud/chat-uikit-engine';
34
- import { TUIGlobal } from '@tencentcloud/universal-api';
35
34
  import vue from '../../../../adapter-vue';
36
35
  import { isPC, isH5 } from '../../../../utils/env';
37
36
  import ToolbarItemContainer from '../toolbar-item-container/index.vue';
@@ -50,9 +49,12 @@ const props = defineProps({
50
49
  type: String,
51
50
  default: 'album',
52
51
  },
53
- isH5ToolShow:{
54
- type:Boolean,
55
- default:false,
52
+ isH5ToolShow: {
53
+ type: Boolean,
54
+ default: false,
55
+ },
56
+ title: {
57
+ type: String,
56
58
  }
57
59
  });
58
60
 
@@ -61,11 +63,11 @@ const currentConversation = ref<IConversationModel>();
61
63
  const IMAGE_TOOLBAR_SHOW_MAP = {
62
64
  web_album: {
63
65
  icon: imageIcon,
64
- title: TUITranslateService.t("图片"),
66
+ title: props.title || TUITranslateService.t("图片"),
65
67
  },
66
68
  uni_album: {
67
69
  icon: imageUniIcon,
68
- title: TUITranslateService.t("图片"),
70
+ title: props.title || TUITranslateService.t("图片"),
69
71
  }
70
72
  };
71
73
 
@@ -95,15 +97,16 @@ const sendImageInWeb = (e: any) => {
95
97
  return;
96
98
  }
97
99
  const file = e.target.files[0];
98
- console.log("file")
99
- console.log(file)
100
- if (file.type.startsWith('image/')) {
101
- // 处理图片文件
102
- sendImageMessage(e?.target);
103
- } else if (file.type.startsWith('video/')) {
104
- // 处理视频文件
105
- sendVideoMessage(e?.target);
106
- }
100
+ if (!file || !file.size) {
101
+ return;
102
+ }
103
+ if (file.type.startsWith('image/')) {
104
+ // 处理图片文件
105
+ sendImageMessage(e.target);
106
+ } else if (file.type.startsWith('video/')) {
107
+ // 处理视频文件
108
+ sendVideoMessage(e.target);
109
+ }
107
110
 
108
111
  e.target.value = '';
109
112
  };
@@ -40,10 +40,10 @@
40
40
  :isH5EmojiShow="isH5EmojiShow"
41
41
  @sendMessage="sendMessage"
42
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"/>
43
+ <ImageUpload v-else-if="item.presetId === INPUT_TOOLBAR_TYPE.IMAGE && item.isEnabled === 1" imageSourceType="album" :isH5ToolShow="isH5ToolShow" :title="item.title"/>
44
+ <FileUpload v-else-if="item.presetId === INPUT_TOOLBAR_TYPE.FILE && item.isEnabled === 1" :isH5ToolShow="isH5ToolShow" :title="item.title"/>
45
+ <VideoUpload v-else-if="item.presetId === INPUT_TOOLBAR_TYPE.VIDEO && item.isEnabled === 1" videoSourceType="album" :isH5ToolShow="isH5ToolShow" :title="item.title"/>
46
+ <RatingTool v-else-if="item.presetId === INPUT_TOOLBAR_TYPE.RATING && item.isEnabled === 1 && isInHumanService" :isH5ToolShow="isH5ToolShow" :title="item.title"/>
47
47
  <UserDefineTool
48
48
  v-else-if="item.isEnabled === 1 && item.isPreset === 0 && item.presetId !== INPUT_TOOLBAR_TYPE.EMOJI"
49
49
  :isH5ToolShow="isH5ToolShow"
@@ -10,7 +10,7 @@
10
10
  <div :class="['video-upload', !isPC && 'video-upload-h5']">
11
11
  <input
12
12
  ref="inputRef"
13
- :title="TUITranslateService.t('视频')"
13
+ :title="props.title || TUITranslateService.t('视频')"
14
14
  type="file"
15
15
  data-type="video"
16
16
  accept="video/*"
@@ -47,6 +47,9 @@ const props = defineProps({
47
47
  type: String,
48
48
  default: 'album',
49
49
  },
50
+ title: {
51
+ type: String,
52
+ },
50
53
  });
51
54
 
52
55
  const inputRef = ref();
@@ -63,7 +66,7 @@ const handleIcon = (): string => {
63
66
  };
64
67
 
65
68
  const handleTitle = (): string => {
66
- return TUITranslateService.t('视频');
69
+ return props.title || TUITranslateService.t('视频');
67
70
  };
68
71
 
69
72
  const onIconClick = () => {
@@ -74,7 +77,11 @@ const sendVideoInWeb = (e: any) => {
74
77
  if (e?.target?.files?.length <= 0) {
75
78
  return;
76
79
  }
77
- sendVideoMessage(e?.target);
80
+ const file = e?.target?.files[0];
81
+ if (!file || !file.size) {
82
+ return;
83
+ }
84
+ sendVideoMessage(e.target);
78
85
  e.target.value = '';
79
86
  };
80
87
 
@@ -227,7 +227,7 @@ import {
227
227
  deepCopy,
228
228
  isNonEmptyObject,
229
229
  } from '../../../utils/utils';
230
- import { isMessageInvisible, isThinkingMessage, isThinkingMessageOverTime, JSONToObject } from '../../../utils/index';
230
+ import { isMessageInvisible, isThinkingMessage, isThinkingMessageOverTime, JSONToObject, isTransferMessageWithoutDesc } from '../../../utils/index';
231
231
  import { isCustomerConversation } from '../../../index';
232
232
  import { CUSTOM_MESSAGE_SRC } from '../../../constant';
233
233
  import { QuickOrderModel } from '../../../interface';
@@ -352,21 +352,31 @@ onUnmounted(() => {
352
352
 
353
353
  function onNewMessageList(list: IMessageModel[]) {
354
354
  list.forEach((message:IMessageModel) => {
355
- if (message?.type === TUIChatEngine.TYPES.MSG_CUSTOM) {
356
- const data = JSONToObject(message?.payload?.data);
357
- if (data?.src === CUSTOM_MESSAGE_SRC.SEAT_STATUS) {
358
- if (data?.content.command === "updateSeatStatus") {
359
- if (data.content.content === 'inSeat') {
360
- TUIStore.update(StoreName.CUSTOM, "isInHumanService", true);
361
- } else if (data.content.content === 'outSeat') {
355
+ if (message.type === TUIChatEngine.TYPES.MSG_CUSTOM) {
356
+ const data = JSONToObject(message.payload.data);
357
+ if (data) {
358
+ if (data.src === CUSTOM_MESSAGE_SRC.BOT_STATUS) {
359
+ if (data.content.content === 'inBot') {
362
360
  TUIStore.update(StoreName.CUSTOM, "isInHumanService", false);
363
361
  }
364
- }
365
- } else if (data?.src === CUSTOM_MESSAGE_SRC.TYPING_STATE) {
366
- if (data?.typingStatus === 1) {
367
- TUIStore.update(StoreName.CUSTOM, 'isTyping', true);
368
- } else {
369
- TUIStore.update(StoreName.CUSTOM, 'isTyping', false);
362
+ } else if (data.src === CUSTOM_MESSAGE_SRC.SEAT_STATUS) {
363
+ if (data.content.command === "updateSeatStatus") {
364
+ if (data.content.content === 'inSeat') {
365
+ TUIStore.update(StoreName.CUSTOM, "isInHumanService", true);
366
+ } else if (data.content.content === 'outSeat') {
367
+ TUIStore.update(StoreName.CUSTOM, "isInHumanService", false);
368
+ }
369
+ }
370
+ } else if (data.src === CUSTOM_MESSAGE_SRC.TYPING_STATE) {
371
+ if (data.typingStatus === 1) {
372
+ TUIStore.update(StoreName.CUSTOM, 'isTyping', true);
373
+ } else {
374
+ TUIStore.update(StoreName.CUSTOM, 'isTyping', false);
375
+ }
376
+ } else if (data.src === CUSTOM_MESSAGE_SRC.NO_SEAT_ONLINE || data.src === CUSTOM_MESSAGE_SRC.TIMEOUT || data.src === CUSTOM_MESSAGE_SRC.END) {
377
+ TUIStore.update(StoreName.CUSTOM, "isInSession", false);
378
+ } else if (data.src === CUSTOM_MESSAGE_SRC.SESSION_RESTARTED) {
379
+ TUIStore.update(StoreName.CUSTOM, "isInSession", true);
370
380
  }
371
381
  }
372
382
  }
@@ -391,6 +401,9 @@ async function onMessageListUpdated(list: IMessageModel[]) {
391
401
  if (isThinkingMessage(message)) {
392
402
  return isThinkingMessageOverTime(message);
393
403
  }
404
+ if (isTransferMessageWithoutDesc(message)) {
405
+ return false;
406
+ }
394
407
  return !message.isDeleted && !isMessageInvisible(message as any);
395
408
  });
396
409
 
@@ -71,7 +71,10 @@
71
71
  <div v-if="payload.src === CUSTOM_MESSAGE_SRC.ORDER">
72
72
  <MessageOrder :payload="payload" />
73
73
  </div>
74
- </div>
74
+ <div v-if="payload.src === CUSTOM_MESSAGE_SRC.TRANSFER_TO_HUMAN || payload.src === CUSTOM_MESSAGE_SRC.TRANSFER_TO_TASK_FLOW">
75
+ <MessageTransferWithDesc :payload="payload" />
76
+ </div>
77
+ </div>
75
78
  </div>
76
79
  </template>
77
80
  <script lang="ts">
@@ -91,6 +94,7 @@ import MessageMultiBranch from './message-multi-branch/index.vue';
91
94
  import MessageMultiForm from './message-multi-form/index.vue';
92
95
  import MessageConcurrencyLimit from "./message-concurrency-limit.vue";
93
96
  import MessageOrder from './message-order.vue';
97
+ import MessageTransferWithDesc from './message-transfer-with-desc.vue';
94
98
  import {
95
99
  IMessageModel,
96
100
  TUIChatService,
@@ -112,6 +116,7 @@ export default {
112
116
  MessageRating,
113
117
  MessageConcurrencyLimit,
114
118
  MessageOrder,
119
+ MessageTransferWithDesc
115
120
  },
116
121
  props: {
117
122
  message: {
@@ -23,10 +23,12 @@ import vue from '../../../../../../../adapter-vue';
23
23
  import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
24
24
  import { customerServicePayloadType } from '../../../../../../../interface';
25
25
  import { isPC } from '../../../../../../../utils/env'
26
+ import { openSafeUrl } from '../../../../../../../utils/utils';
26
27
  const { ref } = vue;
27
28
  interface branchItem {
28
29
  content: string;
29
30
  desc: string;
31
+ url?: string;
30
32
  }
31
33
 
32
34
  interface Props {
@@ -47,20 +49,25 @@ export default {
47
49
  if (!branch.content) {
48
50
  return;
49
51
  }
50
- let cloudCustomData;
51
- if (props.payload.optionType === 0) {
52
- cloudCustomData = '';
53
- canSelect.value = false;
54
- } else if (props.payload.optionType === 1) {
55
- cloudCustomData = JSON.stringify({
56
- BranchOptionInfo: {
57
- taskID: props.payload.taskInfo?.taskID,
58
- nodeID: props.payload.taskInfo?.nodeID,
59
- env: props.payload.taskInfo?.env,
60
- }
61
- });
52
+ if (branch.url) {
53
+ openSafeUrl(branch.url);
54
+ } else {
55
+ let cloudCustomData;
56
+ if (props.payload.optionType === 0) {
57
+ cloudCustomData = '';
58
+ canSelect.value = false;
59
+ } else if (props.payload.optionType === 1) {
60
+ cloudCustomData = JSON.stringify({
61
+ BranchOptionInfo: {
62
+ taskID: props.payload.taskInfo?.taskID,
63
+ nodeID: props.payload.taskInfo?.nodeID,
64
+ env: props.payload.taskInfo?.env,
65
+ }
66
+ });
67
+ }
68
+ emit('input-click', branch, cloudCustomData);
62
69
  }
63
- emit('input-click', branch, cloudCustomData);
70
+
64
71
  };
65
72
 
66
73
  return {
@@ -16,6 +16,7 @@ const { computed} = vue;
16
16
  interface branchItem {
17
17
  content: string;
18
18
  desc: string;
19
+ url?: string;
19
20
  }
20
21
 
21
22
  interface Props {
@@ -17,13 +17,18 @@
17
17
  <Icon :src="iconRefresh" />
18
18
  </div>
19
19
  </div>
20
- <div
21
- v-for="(item, index) in showList"
22
- :key="index"
23
- class="welcome-item"
24
- @click="handleContentListItemClick(item)"
25
- >
26
- <div>{{ item.content }}</div>
20
+ <div class="welcome-items-container">
21
+ <div
22
+ v-for="(item, index) in showList"
23
+ :key="index"
24
+ class="welcome-item"
25
+ @click="handleContentListItemClick(item)"
26
+ >
27
+ <div class="item-content">{{ item.content }}</div>
28
+ </div>
29
+ <div class="welcome-item welcome-item-hidden">
30
+ {{ longestContent }}
31
+ </div>
27
32
  </div>
28
33
  </div>
29
34
  </template>
@@ -37,7 +42,7 @@ import Icon from './customer-icon.vue';
37
42
  import iconQuestion from '../../../../../../assets/icon_question.png';
38
43
  import iconRefresh from '../../../../../../assets/icon_refresh.png';
39
44
  import { customerServicePayloadType } from '../../../../../../interface';
40
- const { reactive, toRefs } = vue;
45
+ const { reactive, toRefs, computed } = vue;
41
46
 
42
47
  interface Props {
43
48
  payload: customerServicePayloadType;
@@ -56,7 +61,7 @@ export default {
56
61
  props: {
57
62
  payload: {
58
63
  type: Object as () => customerServicePayloadType,
59
- default: () => ({ content: { title: '', items: [] } }),
64
+ default: () => ({ content: { title: '', items: [] }}),
60
65
  },
61
66
  },
62
67
  emits: ['sendMessage'],
@@ -86,6 +91,19 @@ export default {
86
91
  );
87
92
  data.pageNumber += 1;
88
93
  };
94
+
95
+ const longestContent = computed(() => {
96
+ if (!data.list) {
97
+ return '';
98
+ }
99
+ let longestContent = '';
100
+ data.list.forEach((item) => {
101
+ if (item.content.length > longestContent.length) {
102
+ longestContent = item.content;
103
+ }
104
+ });
105
+ return longestContent;
106
+ });
89
107
 
90
108
  return {
91
109
  ...toRefs(data),
@@ -96,6 +114,7 @@ export default {
96
114
  changeBranchList,
97
115
  iconQuestion,
98
116
  iconRefresh,
117
+ longestContent
99
118
  };
100
119
  },
101
120
  };
@@ -104,6 +123,9 @@ export default {
104
123
  <style lang="scss">
105
124
  .welcome-card {
106
125
  max-width: 400px;
126
+ display: flex;
127
+ flex-direction: column;
128
+ align-items: center;
107
129
 
108
130
  .welcome-title {
109
131
  display: flex;
@@ -111,6 +133,7 @@ export default {
111
133
  margin-bottom: 10px;
112
134
  justify-content: space-between;
113
135
  align-items: center;
136
+ width: 100%;
114
137
  }
115
138
 
116
139
  .welcome-title-left-container {
@@ -151,28 +174,49 @@ export default {
151
174
  cursor: pointer;
152
175
  }
153
176
 
154
- .welcome-item {
155
- padding: 6px;
177
+ .welcome-items-container {
178
+ width: 100%;
156
179
  display: flex;
157
- justify-content: center;
180
+ flex-direction: column;
158
181
  align-items: center;
159
- cursor: pointer;
160
- background-color: #ffffff;
161
- margin-bottom: 10px;
162
- border:1px solid #adcfff;
163
- border-radius: 20px;
164
- font-weight: 500;
165
- color: #1c66e5;
166
- gap: 10px;
167
- word-break: break-word;
168
- }
169
-
170
- .welcome-item:hover {
171
- background: #f2f7ff;
172
- }
173
-
174
- .welcome-item:last-child {
175
- margin-bottom: 0;
182
+ .welcome-item {
183
+ width: 100%;
184
+ padding: 6px 10px;
185
+ display: flex;
186
+ justify-content: center;
187
+ align-items: center;
188
+ cursor: pointer;
189
+ background-color: #ffffff;
190
+ margin-bottom: 10px;
191
+ border:1px solid #adcfff;
192
+ border-radius: 20px;
193
+ font-weight: 500;
194
+ color: #1c66e5;
195
+ gap: 10px;
196
+ box-sizing: border-box;
197
+ .item-content {
198
+ text-align: center;
199
+ overflow-wrap: break-word;
200
+ word-break: normal;
201
+ width: 100%;
202
+ padding: 0 10px;
203
+ }
204
+ }
205
+
206
+ .welcome-item:hover {
207
+ background: #f2f7ff;
208
+ }
209
+
210
+ .welcome-item:last-child {
211
+ margin-bottom: 0;
212
+ }
213
+
214
+ .welcome-item-hidden {
215
+ visibility: hidden;
216
+ padding: 0;
217
+ margin: 0;
218
+ height: 0;
219
+ }
176
220
  }
177
221
  }
178
222
  </style>
@@ -0,0 +1,51 @@
1
+ <template>
2
+ <div :class="['text', isPC && 'text-select']">
3
+ {{ props.payload.description }}
4
+ </div>
5
+ </template>
6
+
7
+ <script lang="ts">
8
+ import vue from '../../../../../../adapter-vue';
9
+ import { customerServicePayloadType } from '../../../../../../interface';
10
+ import { isPC } from '../../../../../../utils/env';
11
+ const { computed } = vue;
12
+
13
+ interface Props {
14
+ payload: customerServicePayloadType;
15
+ }
16
+
17
+ export default {
18
+ props: {
19
+ payload: {
20
+ type: Object as () => customerServicePayloadType,
21
+ default: () => ({}),
22
+ },
23
+ },
24
+ setup(props: Props) {
25
+ const payload = computed<customerServicePayloadType>(() => {
26
+ return props.payload;
27
+ });
28
+ return {
29
+ props,
30
+ isPC,
31
+ };
32
+ },
33
+ };
34
+ </script>
35
+ <style lang="scss" scoped>
36
+ .text-select {
37
+ -webkit-user-select: text;
38
+ -moz-user-select: text;
39
+ -ms-user-select: text;
40
+ user-select: text;
41
+ }
42
+
43
+ .text {
44
+ white-space: pre-wrap;
45
+ font-size: 14px;
46
+ text-size-adjust: none;
47
+ font-family: PingFangSC-Regular;
48
+ overflow-wrap: break-word;
49
+ word-break: normal;
50
+ }
51
+ </style>
@@ -14,18 +14,18 @@
14
14
 
15
15
  <div
16
16
  v-if="isMessageRevoked"
17
- class="revoked-text"
17
+ :class="isPC ? 'revoked-text' : ''"
18
18
  >
19
19
  {{ TUITranslateService.t("TUIChat.引用内容已撤回") }}
20
20
  </div>
21
21
  <div v-else>
22
22
  <div v-if="isH5" class="mobile-quote-sender">
23
- {{ messageQuoteContent.messageSender }}
23
+ {{ quoteMessageSender }}
24
24
  </div>
25
25
  <div
26
26
  class="max-double-line"
27
27
  >
28
- {{ isPC ? messageQuoteContent.messageSender + ": "+ transformTextWithKeysToEmojiNames(messageQuoteText) : transformTextWithKeysToEmojiNames(messageQuoteText)}}
28
+ {{ isPC ? quoteMessageSender + ": "+ transformTextWithKeysToEmojiNames(messageQuoteText) : transformTextWithKeysToEmojiNames(messageQuoteText)}}
29
29
  </div>
30
30
  </div>
31
31
 
@@ -77,6 +77,7 @@ let selfAddValue = 0;
77
77
  const messageQuoteText = ref<string>('');
78
78
  const hasQuoteContent = ref(false);
79
79
  const messageQuoteContent = ref<IQuoteContent>({} as IQuoteContent);
80
+ const quoteMessageSender = ref<string>('');
80
81
 
81
82
  const isMessageRevoked = computed<boolean>(() => {
82
83
  try {
@@ -110,6 +111,7 @@ onMounted(() => {
110
111
  function performQuoteContent(params: IQuoteContent) {
111
112
  let messageKey: string = '';
112
113
  let quoteContent: string = '';
114
+ const quoteMessage = getQuoteMessage(params.messageID);
113
115
  switch (params.messageType) {
114
116
  case MessageQuoteTypeEnum.TYPE_TEXT:
115
117
  messageKey = '[文本]';
@@ -145,18 +147,25 @@ function performQuoteContent(params: IQuoteContent) {
145
147
  messageKey = '[消息]';
146
148
  break;
147
149
  }
148
- if (
149
- [MessageQuoteTypeEnum.TYPE_TEXT, MessageQuoteTypeEnum.TYPE_MERGER].includes(
150
- params.messageType,
151
- )
152
- ) {
150
+ if (params.messageType === MessageQuoteTypeEnum.TYPE_CUSTOM ||
151
+ params.messageType === MessageQuoteTypeEnum.TYPE_TEXT ||
152
+ params.messageType === MessageQuoteTypeEnum.TYPE_MERGER) {
153
153
  quoteContent = params.messageAbstract;
154
154
  }
155
+ quoteMessageSender.value = !quoteMessage ? messageQuoteContent.value.messageSender : (quoteMessage.nick || quoteMessage.from);
155
156
  return quoteContent
156
157
  ? quoteContent
157
158
  : TUITranslateService.t(`TUIChat.${messageKey}`);
158
159
  }
159
160
 
161
+ function getQuoteMessage(messageID: string) {
162
+ const currentMessageList = TUIStore.getData(StoreName.CHAT, 'messageList');
163
+ let quoteMessage = currentMessageList.find(
164
+ message => message.ID === messageID,
165
+ );
166
+ return quoteMessage;
167
+ }
168
+
160
169
  async function scrollToOriginalMessage() {
161
170
  if (isMessageRevoked.value) {
162
171
  return;
@@ -164,7 +173,7 @@ async function scrollToOriginalMessage() {
164
173
  const originMessageID = messageQuoteContent.value?.messageID;
165
174
  const currentMessageList = TUIStore.getData(StoreName.CHAT, 'messageList');
166
175
  const isOriginalMessageInScreen = currentMessageList.some(
167
- msg => msg.ID === originMessageID,
176
+ message => message.ID === originMessageID,
168
177
  );
169
178
  if (originMessageID && isOriginalMessageInScreen) {
170
179
  try {