@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.
Files changed (100) hide show
  1. package/CHANGELOG.md +5 -3
  2. package/README.md +153 -50
  3. package/assets/loading_message.svg +1 -0
  4. package/components/CustomerServiceChat/chat-header/index-web.vue +2 -2
  5. package/components/CustomerServiceChat/index-web.vue +77 -11
  6. package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +7 -1
  7. package/components/CustomerServiceChat/message-input-toolbar/emoji-dialog-mobile/emoji-dialog-mobile.vue +2 -1
  8. package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue +2 -1
  9. package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/index.vue +2 -1
  10. package/components/CustomerServiceChat/message-input-toolbar/file-upload/index.vue +3 -2
  11. package/components/CustomerServiceChat/message-input-toolbar/image-upload/index.vue +4 -3
  12. package/components/CustomerServiceChat/message-input-toolbar/index-web.vue +2 -2
  13. package/components/CustomerServiceChat/message-input-toolbar/video-upload/index.vue +2 -2
  14. package/components/CustomerServiceChat/message-list/index-web.vue +16 -7
  15. package/components/CustomerServiceChat/message-list/message-elements/message-bubble-web.vue +19 -0
  16. package/components/CustomerServiceChat/message-list/message-elements/message-custom.vue +6 -2
  17. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/marked.ts +4 -0
  18. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-branch.vue +13 -4
  19. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-mobile/input-mobile.vue +4 -2
  20. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-mobile/radios-mobile.vue +4 -2
  21. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-pc/input-pc.vue +4 -2
  22. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-pc/radio-pc.vue +5 -3
  23. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-mobile.vue +6 -4
  24. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-pc.vue +5 -3
  25. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-product-card.vue +21 -11
  26. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-rating/message-rating-number.vue +6 -6
  27. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-rating/message-rating-star.vue +14 -14
  28. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-robot-welcome.vue +2 -6
  29. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-single-form/form-input.vue +6 -4
  30. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-stream.vue +51 -52
  31. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/styles/common.scss +1 -1
  32. package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/type-writer.ts +189 -0
  33. package/components/CustomerServiceChat/message-list/message-elements/message-location.vue +2 -1
  34. package/components/CustomerServiceChat/message-list/message-elements/message-text.vue +1 -1
  35. package/components/CustomerServiceChat/message-list/message-elements/message-thinking.vue +59 -0
  36. package/components/CustomerServiceChat/message-list/message-tool/index-web.vue +1 -1
  37. package/components/CustomerServiceChat/message-list/message-tool/message-revoked.vue +1 -0
  38. package/components/CustomerServiceChat/message-list/scroll-button/index.vue +3 -1
  39. package/components/CustomerServiceChat/message-toolbar-button/index.vue +69 -0
  40. package/components/common/Dialog/index.vue +2 -2
  41. package/components/common/ImagePreviewer/index-web.vue +2 -2
  42. package/constant.ts +15 -0
  43. package/excluded-list.txt +0 -1
  44. package/index.ts +1 -6
  45. package/interface.ts +8 -0
  46. package/locales/en/TUIChat.ts +158 -0
  47. package/locales/en/aidesk.ts +16 -0
  48. package/locales/en/component.ts +6 -0
  49. package/locales/en/index.ts +26 -0
  50. package/locales/en/time.ts +37 -0
  51. package/locales/fil/TUIChat.ts +160 -0
  52. package/locales/fil/aidesk.ts +16 -0
  53. package/locales/fil/component.ts +6 -0
  54. package/locales/fil/index.ts +25 -0
  55. package/locales/fil/time.ts +18 -0
  56. package/locales/id/TUIChat.ts +164 -0
  57. package/locales/id/aidesk.ts +16 -0
  58. package/locales/id/component.ts +6 -0
  59. package/locales/id/index.ts +26 -0
  60. package/locales/id/time.ts +19 -0
  61. package/locales/index.ts +30 -0
  62. package/locales/ja/TUIChat.ts +165 -0
  63. package/locales/ja/aidesk.ts +16 -0
  64. package/locales/ja/component.ts +6 -0
  65. package/locales/ja/index.ts +26 -0
  66. package/locales/ja/time.ts +18 -0
  67. package/locales/ms/TUIChat.ts +165 -0
  68. package/locales/ms/aidesk.ts +16 -0
  69. package/locales/ms/component.ts +6 -0
  70. package/locales/ms/index.ts +26 -0
  71. package/locales/ms/time.ts +18 -0
  72. package/locales/ru/TUIChat.ts +158 -0
  73. package/locales/ru/aidesk.ts +16 -0
  74. package/locales/ru/component.ts +7 -0
  75. package/locales/ru/index.ts +26 -0
  76. package/locales/ru/time.ts +30 -0
  77. package/locales/th/TUIChat.ts +165 -0
  78. package/locales/th/aidesk.ts +16 -0
  79. package/locales/th/component.ts +6 -0
  80. package/locales/th/index.ts +26 -0
  81. package/locales/th/time.ts +18 -0
  82. package/locales/vi/TUIChat.ts +156 -0
  83. package/locales/vi/aidesk.ts +16 -0
  84. package/locales/vi/component.ts +6 -0
  85. package/locales/vi/index.ts +26 -0
  86. package/locales/vi/time.ts +18 -0
  87. package/locales/zh_cn/TUIChat.ts +158 -0
  88. package/locales/zh_cn/aidesk.ts +17 -0
  89. package/locales/zh_cn/component.ts +6 -0
  90. package/locales/zh_cn/index.ts +26 -0
  91. package/locales/zh_cn/time.ts +37 -0
  92. package/locales/zh_tw/TUIChat.ts +158 -0
  93. package/locales/zh_tw/aidesk.ts +16 -0
  94. package/locales/zh_tw/component.ts +6 -0
  95. package/locales/zh_tw/index.ts +26 -0
  96. package/locales/zh_tw/time.ts +37 -0
  97. package/package.json +2 -2
  98. package/server.ts +36 -9
  99. package/utils/index.ts +42 -17
  100. 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: 16px;
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, watchEffect, onMounted } = vue;
14
+ const { ref, computed, withDefaults, defineProps, watch } = vue;
17
15
 
18
16
  interface Props {
19
17
  payload: customerServicePayloadType;
20
18
  }
21
19
 
22
- export default {
23
- props: {
24
- payload: {
25
- type: Object as () => customerServicePayloadType,
26
- default: () => ({}),
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
- setup(props: Props) {
30
- const displayedContent = ref<string>('');
31
- const isFinished = ref<boolean>(false);
32
- let currentIndex = 0;
39
+ });
33
40
 
34
- onMounted(() => {
35
- displayedContent.value = parseMarkdown(props?.payload?.chunks?.join('') ?? '');
36
- currentIndex = displayedContent.value.length;
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
- watchEffect(() => {
40
- const newContent = props?.payload?.chunks?.join('') ?? '';
41
- const parsedContent = parseMarkdown(newContent);
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
- return {
53
- props,
54
- isFinished,
55
- displayedContent,
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>
@@ -118,7 +118,7 @@
118
118
  .message-marked {
119
119
  overflow: hidden;
120
120
  word-break: break-word;
121
- white-space: normal;
121
+ white-space: pre-wrap;
122
122
  display: flex;
123
123
  flex-direction: column;
124
124
  justify-content: flex-start;
@@ -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({
@@ -98,6 +98,6 @@ watchEffect(() => {
98
98
  text-size-adjust: none;
99
99
  font-family: PingFangSC-Regular;
100
100
  overflow-wrap: break-word;
101
- word-break: keep-all;
101
+ word-break: normal;
102
102
  }
103
103
  </style>
@@ -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>
@@ -120,7 +120,7 @@ const actionItems = ref([
120
120
  clickEvent: quoteMessage,
121
121
  },{
122
122
  key:'download',
123
- text: '下载',
123
+ text: TUITranslateService.t('TUIChat.下载'),
124
124
  iconUrl: downloadIcon,
125
125
  renderCondition(){
126
126
  if (!message.value) return false;
@@ -54,6 +54,7 @@ const messageEdit = () => {
54
54
  color: #999;
55
55
  font-size: 12px;
56
56
  margin-bottom: 10px;
57
+ white-space: pre;
57
58
 
58
59
  .edit {
59
60
  padding: 0 5px;
@@ -178,7 +178,9 @@ defineExpose({
178
178
  position: absolute;
179
179
  bottom: 10px;
180
180
  right: 10px;
181
- width: 92px;
181
+ width: auto;
182
+ min-width: 92px;
183
+ max-width: 115px;
182
184
  height: 28px;
183
185
  background: #fff;
184
186
  border: 1px solid #e0e0e0;
@@ -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("component.取消") }}
39
+ {{ TUITranslateService.t('取消') }}
40
40
  </button>
41
41
  <button
42
42
  class="btn btn-default"
43
43
  @click="submit"
44
44
  >
45
- {{ TUITranslateService.t("component.确定") }}
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('component.图片 url 不存在'),
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('component.暂不支持下载此类型图片'),
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
+ ];
package/excluded-list.txt CHANGED
@@ -1,5 +1,4 @@
1
1
  .\node_modules\@tencentcloud\ai-desk-customer-vue\node_modules
2
- .\node_modules\@tencentcloud\ai-desk-customer-vue\package.json
3
2
  .\node_modules\@tencentcloud\ai-desk-customer-vue\excluded-list.txt
4
3
 
5
4