@trtc/calls-uikit-vue2 4.4.2 → 4.4.5

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 (58) hide show
  1. package/README-zh_CN.md +6 -0
  2. package/README.md +6 -0
  3. package/package.json +2 -2
  4. package/src/Components/TUICallKit.vue +1 -1
  5. package/src/Components/assets/aiAssistant/desktop/subtitleSettings.svg +4 -0
  6. package/src/Components/assets/aiAssistant/mobile/close-aiAssistant.svg +7 -0
  7. package/src/Components/assets/aiAssistant/mobile/open-aiAssistant.svg +7 -0
  8. package/src/Components/assets/aiAssistant/mobile/subtitleSettings.svg +3 -0
  9. package/src/Components/components/base/CustomSelect/CustomSelect.ts +45 -0
  10. package/src/Components/components/base/CustomSelect/CustomSelect.vue +199 -0
  11. package/src/Components/components/common/AIAssistant/AISubtitle.vue +155 -37
  12. package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchH5.vue +35 -0
  13. package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchPC.vue +89 -0
  14. package/src/Components/components/common/AIAssistant/components/SubtitleContent.vue +234 -0
  15. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsH5.vue +534 -0
  16. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsPC.vue +294 -0
  17. package/src/Components/components/common/TopBar/TopBar.vue +41 -15
  18. package/src/Components/hooks/index.ts +1 -0
  19. package/src/Components/hooks/useAIAssistant.ts +142 -0
  20. package/src/Components/hooks/useGetVolumeMap.ts +2 -2
  21. package/src/TUICallService/CallService/AIAssistant.ts +285 -39
  22. package/src/TUICallService/CallService/UIKitModal.ts +67 -6
  23. package/src/TUICallService/CallService/bellContext.ts +25 -2
  24. package/src/TUICallService/CallService/engineEventHandler.ts +6 -1
  25. package/src/TUICallService/CallService/index.ts +72 -39
  26. package/src/TUICallService/CallService/miniProgram.ts +0 -12
  27. package/src/TUICallService/TUIStore/callStore.ts +6 -1
  28. package/src/TUICallService/UIKitModal/UIKitModal.ts +117 -0
  29. package/src/TUICallService/UIKitModal/index.ts +2 -0
  30. package/src/TUICallService/UIKitModal/type.ts +15 -0
  31. package/src/TUICallService/const/index.ts +4 -0
  32. package/src/TUICallService/interface/ICallStore.ts +5 -0
  33. package/src/TUICallService/locales/en.ts +15 -0
  34. package/src/TUICallService/locales/ja_JP.ts +15 -0
  35. package/src/TUICallService/locales/zh-cn.ts +15 -0
  36. package/src/TUICallService/utils/common-utils.ts +1 -1
  37. package/src/index.ts +1 -1
  38. package/tuicall-uikit-vue2.es.js +3363 -2692
  39. package/tuicall-uikit-vue2.umd.js +3 -2
  40. package/types/Components/components/base/CustomSelect/CustomSelect.d.ts +41 -0
  41. package/types/Components/hooks/index.d.ts +1 -0
  42. package/types/Components/hooks/useAIAssistant.d.ts +19 -0
  43. package/types/TUICallService/CallService/AIAssistant.d.ts +72 -15
  44. package/types/TUICallService/CallService/bellContext.d.ts +3 -0
  45. package/types/TUICallService/CallService/index.d.ts +4 -3
  46. package/types/TUICallService/CallService/miniProgram.d.ts +0 -1
  47. package/types/TUICallService/UIKitModal/UIKitModal.d.ts +4 -0
  48. package/types/TUICallService/UIKitModal/index.d.ts +2 -0
  49. package/types/TUICallService/UIKitModal/type.d.ts +13 -0
  50. package/types/TUICallService/interface/ICallStore.d.ts +4 -0
  51. package/types/TUICallService/locales/en.d.ts +14 -0
  52. package/types/TUICallService/locales/ja_JP.d.ts +14 -0
  53. package/types/TUICallService/locales/zh-cn.d.ts +14 -0
  54. package/types/tsconfig.tsbuildinfo +1 -1
  55. package/src/Components/components/common/AIAssistant/AIAssistant.ts +0 -130
  56. package/src/Components/components/common/AIAssistant/index.ts +0 -11
  57. package/types/Components/components/common/AIAssistant/AIAssistant.d.ts +0 -40
  58. package/types/Components/components/common/AIAssistant/index.d.ts +0 -4
package/README-zh_CN.md CHANGED
@@ -39,6 +39,12 @@ TUICallKit 支持市面上主流浏览器,详情参考:[浏览器支持情
39
39
  | 56+ | 80+ | 56+ | 11+ | 11+ | 46+ |
40
40
 
41
41
 
42
+ ## 推荐使用更高效的 AI 集成助手
43
+ 我们为您提供了全新的 AI 集成方式,如果您不需要完整的 Demo 工程, 只想快速开始集成,推荐您使用更高效的 AI 集成助手,只需要简单描述您的需求,即可自动生成集成代码,大幅提升开发效率。
44
+
45
+ 点击这里,立即体验 [AI 集成](https://cloud.tencent.com/document/product/647/125504)。
46
+
47
+
42
48
  ## 安装
43
49
  使用 npm:
44
50
  ```
package/README.md CHANGED
@@ -41,6 +41,12 @@ Please be sure to use HTTPS protocol or localhost to deploy your Web App, otherw
41
41
  | 56+ | 80+ | 56+ | 11+ | 11+ | 46+ |
42
42
 
43
43
 
44
+ ## Recommend Using the More Efficient AI Integration Assistant
45
+
46
+ We offer you a brand new method for AI integration. If you don't need the complete demo project and just want to get started with integration quickly, we recommend using the more efficient AI Integration Assistant. Simply describe your requirements, and it will automatically generate the integration code, significantly boosting development efficiency.
47
+
48
+ Click here to experience [AI integration]((https://cloud.tencent.com/document/product/647/125504)) now!
49
+
44
50
 
45
51
  ## Install
46
52
  npm:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trtc/calls-uikit-vue2",
3
- "version": "4.4.2",
3
+ "version": "4.4.5",
4
4
  "main": "./tuicall-uikit-vue2.umd.js",
5
5
  "module": "./tuicall-uikit-vue2.es.js",
6
6
  "types": "./types/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@tencentcloud/tui-core-lite": "1.0.0",
17
- "@trtc/call-engine-lite-js": "~3.5.0",
17
+ "@trtc/call-engine-lite-js": "~3.5.5",
18
18
  "@tencentcloud/lite-chat": "^1.6.3",
19
19
  "@trtc/call-engine-lite-wx": "~3.4.7"
20
20
  },
@@ -14,7 +14,7 @@ import SingleCall from './components/SingleCall/SingleCall.vue';
14
14
  import GroupCall from './components/GroupCall/GroupCall.vue';
15
15
  import { PermitTip } from './components/common/PermitTip/PermitTip';
16
16
  import { Toast } from './components/common/Toast';
17
- import { AISubtitle } from './components/common/AIAssistant';
17
+ import AISubtitle from './components/common/AIAssistant/AISubtitle.vue';
18
18
  import { UIKitModal } from './components/common/UIKitModal';
19
19
  import { TUIGlobal, TUIStore, StoreName, TUICallKitAPI, NAME, CallStatus, CallMediaType, VideoDisplayMode, VideoResolution } from '../TUICallService/index';
20
20
  import {
@@ -0,0 +1,4 @@
1
+ <svg width="13" height="14" viewBox="0 0 13 14" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M9.06218 6.75C9.06218 8.40685 7.71903 9.75 6.06218 9.75C4.40532 9.75 3.06218 8.40685 3.06218 6.75C3.06218 5.09315 4.40532 3.75 6.06218 3.75C7.71903 3.75 9.06218 5.09315 9.06218 6.75ZM8.06218 6.75C8.06218 5.64543 7.16675 4.75 6.06218 4.75C4.95761 4.75 4.06218 5.64543 4.06218 6.75C4.06218 7.85457 4.95761 8.75 6.06218 8.75C7.16675 8.75 8.06218 7.85457 8.06218 6.75Z" fill="white" fill-opacity="0.75"/>
3
+ <path d="M6.06218 0L12.1244 3.375V10.125L6.06218 13.5L0 10.125V3.375L6.06218 0ZM1 3.9628V9.5372L6.06218 12.3555L11.1244 9.5372V3.9628L6.06218 1.14453L1 3.9628Z" fill="white" fill-opacity="0.75"/>
4
+ </svg>
@@ -0,0 +1,7 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M19 12.1182H17.333V3.66699H2.66699V16.333H8.18945V18H1V2H19V12.1182Z" fill="white" fill-opacity="0.9"/>
3
+ <path d="M15.6667 8.02202C15.6667 8.02202 14.9677 7.72533 13.7849 7.77478C13.086 7.82422 12.5484 7.97257 12.172 8.36815C11.7419 8.81319 11.5269 9.35711 11.5269 10.0494C11.5269 10.7417 11.7419 11.2361 12.1183 11.6317C12.4946 11.9779 12.9785 12.1262 13.6237 12.1757C14.4301 12.2745 15.6667 11.9779 15.6667 11.9779V13.2635C15.6667 13.2635 14.7527 13.4613 13.5161 13.4613C12.4946 13.4613 11.6882 13.1152 11.043 12.5218C10.4516 11.879 10.129 11.0878 10.129 10.0988C10.129 9.06043 10.4516 8.17036 11.1505 7.52754C11.8495 6.88471 12.7097 6.53857 13.7849 6.53857C14.7527 6.53857 15.6667 6.73637 15.6667 6.73637V8.02202Z" fill="white" fill-opacity="0.9"/>
4
+ <path d="M9.53763 8.02202C9.53763 8.02202 8.83871 7.72533 7.65592 7.77478C6.95699 7.82422 6.41936 7.97257 6.04301 8.36815C5.6129 8.81319 5.39785 9.35711 5.39785 10.0494C5.39785 10.7417 5.6129 11.2361 5.98925 11.6317C6.36559 11.9779 6.84946 12.1262 7.49462 12.1757C8.30108 12.2745 9.53763 11.9779 9.53763 11.9779V13.2635C9.53763 13.2635 8.62366 13.4613 7.3871 13.4613C6.36559 13.4613 5.55914 13.1152 4.91398 12.5218C4.32258 11.879 4 11.0878 4 10.0988C4 9.06043 4.32258 8.17036 5.02151 7.52754C5.72043 6.88471 6.58065 6.53857 7.65592 6.53857C8.62366 6.53857 9.53763 6.73637 9.53763 6.73637V8.02202Z" fill="white" fill-opacity="0.9"/>
5
+ <rect x="10" y="14.5916" width="10" height="5" rx="2.5" fill="#676A70"/>
6
+ <rect x="10.4997" y="15.0916" width="4" height="4" rx="2" fill="white"/>
7
+ </svg>
@@ -0,0 +1,7 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M19 12.1182H17.333V3.66699H2.66699V16.333H8.18945V18H1V2H19V12.1182Z" fill="white" fill-opacity="0.9"/>
3
+ <path d="M15.6667 8.02202C15.6667 8.02202 14.9677 7.72533 13.7849 7.77478C13.086 7.82422 12.5484 7.97257 12.172 8.36815C11.7419 8.81319 11.5269 9.35711 11.5269 10.0494C11.5269 10.7417 11.7419 11.2361 12.1183 11.6317C12.4946 11.9779 12.9785 12.1262 13.6237 12.1757C14.4301 12.2745 15.6667 11.9779 15.6667 11.9779V13.2635C15.6667 13.2635 14.7527 13.4613 13.5161 13.4613C12.4946 13.4613 11.6882 13.1152 11.043 12.5218C10.4516 11.879 10.129 11.0878 10.129 10.0988C10.129 9.06043 10.4516 8.17036 11.1505 7.52754C11.8495 6.88471 12.7097 6.53857 13.7849 6.53857C14.7527 6.53857 15.6667 6.73637 15.6667 6.73637V8.02202Z" fill="white" fill-opacity="0.9"/>
4
+ <path d="M9.53763 8.02202C9.53763 8.02202 8.83871 7.72533 7.65592 7.77478C6.95699 7.82422 6.41936 7.97257 6.04301 8.36815C5.6129 8.81319 5.39785 9.35711 5.39785 10.0494C5.39785 10.7417 5.6129 11.2361 5.98925 11.6317C6.36559 11.9779 6.84946 12.1262 7.49462 12.1757C8.30108 12.2745 9.53763 11.9779 9.53763 11.9779V13.2635C9.53763 13.2635 8.62366 13.4613 7.3871 13.4613C6.36559 13.4613 5.55914 13.1152 4.91398 12.5218C4.32258 11.879 4 11.0878 4 10.0988C4 9.06043 4.32258 8.17036 5.02151 7.52754C5.72043 6.88471 6.58065 6.53857 7.65592 6.53857C8.62366 6.53857 9.53763 6.73637 9.53763 6.73637V8.02202Z" fill="white" fill-opacity="0.9"/>
5
+ <path d="M10 17.0916C10 15.7108 11.1193 14.5916 12.5 14.5916H17.5C18.8807 14.5916 20 15.7108 20 17.0916C20 18.4723 18.8807 19.5916 17.5 19.5916H12.5C11.1193 19.5916 10 18.4723 10 17.0916Z" fill="#4588F5"/>
6
+ <rect x="15.5042" y="15.0916" width="4" height="4" rx="2" fill="white"/>
7
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="6" height="12" viewBox="0 0 6 12" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M1.84529 9.34448L1.15586 8.65505L3.81114 5.99977L1.15586 3.34448L1.84529 2.65505L5.19 5.99977L1.84529 9.34448Z" fill="white" fill-opacity="0.42"/>
3
+ </svg>
@@ -0,0 +1,45 @@
1
+ export interface SelectOption {
2
+ value: string | number;
3
+ label: string;
4
+ disabled?: boolean;
5
+ }
6
+
7
+ export const CustomSelectProps = {
8
+ // Vue2 compatible: use 'value' instead of 'modelValue'
9
+ value: {
10
+ type: [String, Number],
11
+ default: '',
12
+ },
13
+ options: {
14
+ type: Array as () => SelectOption[],
15
+ default: () => [],
16
+ },
17
+ placeholder: {
18
+ type: String,
19
+ default: 'Please select',
20
+ },
21
+ disabled: {
22
+ type: Boolean,
23
+ default: false,
24
+ },
25
+ clearable: {
26
+ type: Boolean,
27
+ default: false,
28
+ },
29
+ size: {
30
+ type: String,
31
+ values: ['small', 'medium', 'large'],
32
+ default: 'medium',
33
+ },
34
+ width: {
35
+ type: String,
36
+ default: '100%',
37
+ },
38
+ };
39
+
40
+ export const CustomSelectEmits = {
41
+ // Vue2 compatible: use 'input' instead of 'update:modelValue'
42
+ 'input': (value: string | number) => true,
43
+ 'change': (value: string | number) => true,
44
+ 'clear': () => true,
45
+ };
@@ -0,0 +1,199 @@
1
+ <template>
2
+ <div class="custom-select-wrapper" ref="wrapperRef">
3
+ <div
4
+ class="custom-select"
5
+ :class="{ 'is-open': isOpen, 'is-disabled': disabled }"
6
+ @click.stop="toggleDropdown"
7
+ >
8
+ <span class="select-text">{{ displayText }}</span>
9
+ <svg
10
+ class="select-arrow"
11
+ :class="{ 'is-open': isOpen }"
12
+ width="12"
13
+ height="8"
14
+ viewBox="0 0 12 8"
15
+ fill="none"
16
+ >
17
+ <path
18
+ d="M1 1L6 6L11 1"
19
+ stroke="#C0C4CC"
20
+ stroke-width="1.5"
21
+ stroke-linecap="round"
22
+ stroke-linejoin="round"
23
+ />
24
+ </svg>
25
+ </div>
26
+ <div class="custom-options" v-show="isOpen">
27
+ <div
28
+ v-for="option in options"
29
+ :key="option.value"
30
+ class="custom-option"
31
+ :class="{ 'is-selected': value === option.value }"
32
+ @click.stop="selectOption(option.value)"
33
+ >
34
+ {{ option.label }}
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <script setup lang="ts">
41
+ import { ref, computed, onMounted, onUnmounted } from '../../../../adapter-vue';
42
+ import { CustomSelectProps, CustomSelectEmits, type SelectOption } from './CustomSelect';
43
+
44
+ const props = defineProps(CustomSelectProps);
45
+ const emit = defineEmits(CustomSelectEmits);
46
+
47
+ const isOpen = ref(false);
48
+ const wrapperRef = ref<HTMLElement | null>(null);
49
+
50
+ const displayText = computed(() => {
51
+ const selectedOption = props.options.find(option => option.value === props.value);
52
+ return selectedOption ? selectedOption.label : props.placeholder;
53
+ });
54
+
55
+ const toggleDropdown = () => {
56
+ if (props.disabled) return;
57
+ isOpen.value = !isOpen.value;
58
+ };
59
+
60
+ const selectOption = (value: string | number) => {
61
+ // Vue2 compatible: emit 'input' event for v-model
62
+ emit('input', value);
63
+ emit('change', value);
64
+ isOpen.value = false;
65
+ };
66
+
67
+ // Close dropdown when clicking outside
68
+ const handleClickOutside = (event: MouseEvent) => {
69
+ if (!wrapperRef.value) return;
70
+
71
+ const target = event.target as HTMLElement;
72
+ // Check if click is outside the wrapper element
73
+ if (!wrapperRef.value.contains(target)) {
74
+ isOpen.value = false;
75
+ }
76
+ };
77
+
78
+ onMounted(() => {
79
+ document.addEventListener('click', handleClickOutside);
80
+ });
81
+
82
+ onUnmounted(() => {
83
+ document.removeEventListener('click', handleClickOutside);
84
+ });
85
+ </script>
86
+
87
+ <style lang="scss" scoped>
88
+ .custom-select-wrapper {
89
+ position: relative;
90
+ width: 100%;
91
+ }
92
+
93
+ .custom-select {
94
+ height: 36px;
95
+ padding: 0 32px 0 12px;
96
+ border: 1px solid #DCDFE6;
97
+ border-radius: 4px;
98
+ font-size: 14px;
99
+ color: #606266;
100
+ background: #FFFFFF;
101
+ cursor: pointer;
102
+ display: flex;
103
+ align-items: center;
104
+ transition: all 0.3s;
105
+
106
+ &:hover:not(.is-disabled) {
107
+ border-color: #C0C4CC;
108
+ }
109
+
110
+ &.is-open {
111
+ border-color: #409EFF;
112
+ box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
113
+ }
114
+
115
+ &.is-disabled {
116
+ background: #F5F7FA;
117
+ color: #C0C4CC;
118
+ cursor: not-allowed;
119
+ border-color: #E4E7ED;
120
+ }
121
+ }
122
+
123
+ .select-text {
124
+ overflow: hidden;
125
+ text-overflow: ellipsis;
126
+ white-space: nowrap;
127
+ }
128
+
129
+ .select-arrow {
130
+ position: absolute;
131
+ right: 12px;
132
+ top: 50%;
133
+ transform: translateY(-50%);
134
+ pointer-events: none;
135
+ transition: transform 0.3s;
136
+
137
+ &.is-open {
138
+ transform: translateY(-50%) rotate(180deg);
139
+ }
140
+ }
141
+
142
+ .custom-options {
143
+ position: absolute;
144
+ top: 100%;
145
+ left: 0;
146
+ right: 0;
147
+ background: #FFFFFF;
148
+ border: 1px solid #DCDFE6;
149
+ border-radius: 4px;
150
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
151
+ z-index: 1000;
152
+ margin-top: 4px;
153
+ overflow: hidden;
154
+ max-height: 200px;
155
+ overflow-y: auto;
156
+ }
157
+
158
+ .custom-option {
159
+ padding: 8px 12px;
160
+ font-size: 14px;
161
+ color: #606266;
162
+ cursor: pointer;
163
+ transition: all 0.2s;
164
+
165
+ &:hover {
166
+ background: #F5F7FA;
167
+ color: #409EFF;
168
+ }
169
+
170
+ &.is-selected {
171
+ color: #409EFF;
172
+ font-weight: 500;
173
+
174
+ &:hover {
175
+ background: #F5F7FA;
176
+ color: #409EFF;
177
+ }
178
+ }
179
+ }
180
+
181
+ // Scrollbar styling for options
182
+ .custom-options::-webkit-scrollbar {
183
+ width: 6px;
184
+ }
185
+
186
+ .custom-options::-webkit-scrollbar-track {
187
+ background: #F1F1F1;
188
+ border-radius: 3px;
189
+ }
190
+
191
+ .custom-options::-webkit-scrollbar-thumb {
192
+ background: #C0C4CC;
193
+ border-radius: 3px;
194
+
195
+ &:hover {
196
+ background: #A8ABB2;
197
+ }
198
+ }
199
+ </style>
@@ -1,17 +1,40 @@
1
1
  <template>
2
2
  <div
3
- v-show="subtitleInfoList.length"
4
- :class="['ai-subtitle', customClass]"
3
+ v-if="isAITranscriberEnabled"
4
+ :class="[
5
+ isPC ? 'ai-subtitle-pc' : 'ai-subtitle-h5',
6
+ customClass,
7
+ {
8
+ 'ai-subtitle-pc--expanded': showSettingsModal && isPC,
9
+ 'ai-subtitle-h5--expanded': showSettingsModal && !isPC
10
+ }
11
+ ]"
5
12
  :style="[customStyle]"
6
13
  >
7
- <div v-for="(subtitleInfo, index) in subtitleInfoList" :key="subtitleInfo.roundId">
8
- <div v-if="index !== 0" style="height: 16px;"> </div>
9
- <div class="sender-name">{{ `${subtitleInfo?.nick || subtitleInfo?.sender}:` }}</div>
10
- <div>{{ subtitleInfo?.text }}</div>
11
- <div v-for="tranlationContent in subtitleInfo?.translation">
12
- <span>{{ `[${tranlationContent?.language}]: ${tranlationContent?.content}` }}</span>
13
- </div>
14
- </div>
14
+ <!-- Subtitle Content Component -->
15
+ <SubtitleContent
16
+ v-show="!showSettingsModal"
17
+ @open-settings="openSettingsModal"
18
+ :class="isPC ? 'ai-subtitle-pc__content' : 'ai-subtitle-h5__content'"
19
+ />
20
+
21
+ <!-- Settings Modal Component (Same Level) -->
22
+ <SubtitleSettingsPC
23
+ v-if="isPC"
24
+ :visible="showSettingsModal"
25
+ @update:visible="showSettingsModal = $event"
26
+ @confirm="handleSettingsConfirm"
27
+ class="ai-subtitle-pc__settings"
28
+ />
29
+
30
+ <!-- Settings Modal Component (H5) -->
31
+ <SubtitleSettingsH5
32
+ v-else
33
+ :visible="showSettingsModal"
34
+ @update:visible="showSettingsModal = $event"
35
+ @confirm="handleSettingsConfirm"
36
+ class="ai-subtitle-h5__settings"
37
+ />
15
38
  </div>
16
39
  </template>
17
40
 
@@ -24,8 +47,17 @@ export default {
24
47
  </script>
25
48
 
26
49
  <script lang="ts" setup>
27
- import { onMounted, ref, onUnmounted } from '../../../../adapter-vue';
28
- import { aiAssistant, ASREvent } from './index';
50
+ import { ref, onMounted } from '../../../../adapter-vue';
51
+ import SubtitleContent from './components/SubtitleContent.vue';
52
+ import SubtitleSettingsPC from './components/SubtitleSettingsPC.vue';
53
+ import SubtitleSettingsH5 from './components/SubtitleSettingsH5.vue';
54
+ import { TUIGlobal } from '../../../../TUICallService/index';
55
+ import { useAIAssistant } from '../../../hooks/useAIAssistant';
56
+
57
+ const isPC = TUIGlobal.isPC;
58
+
59
+ // Use AI Assistant hook (now includes both status and data)
60
+ const { isAITranscriberEnabled } = useAIAssistant();
29
61
 
30
62
  defineProps({
31
63
  customClass: {
@@ -36,40 +68,126 @@ defineProps({
36
68
  },
37
69
  })
38
70
 
39
- const subtitleInfoList = ref([]);
71
+ const showSettingsModal = ref(false);
40
72
 
41
- const handleAISubtitle = (data: any) => {
42
- if (!data?.subtitleInfoList) return;
43
-
44
- subtitleInfoList.value = JSON.parse(JSON.stringify(data.subtitleInfoList));
73
+ const openSettingsModal = () => {
74
+ showSettingsModal.value = true;
45
75
  };
46
76
 
47
- onMounted(() => {
48
- aiAssistant.on(ASREvent.TRANSCRIPTION, handleAISubtitle);
49
- })
50
-
51
- onUnmounted(() => {
52
- aiAssistant.off(ASREvent.TRANSCRIPTION, handleAISubtitle);
53
- })
77
+ const handleSettingsConfirm = (settings: any) => {
78
+ // Handle settings save logic here
79
+ showSettingsModal.value = false;
80
+ };
54
81
  </script>
55
82
 
56
83
  <style lang="scss" scoped>
57
- .ai-subtitle {
84
+ // PC端样式
85
+ .ai-subtitle-pc {
58
86
  position: absolute;
59
- z-index: 100;
60
- bottom: 110px;
87
+ z-index: 1;
61
88
  left: 50%;
62
- padding: 10px 12px;
63
- color: #fff;
64
- background-color: rgba(79, 88, 107, 0.7);
65
- border-radius: 8px;
66
89
  transform: translateX(-50%);
67
- width: 260px;
68
- max-height: 280px;
69
- overflow-y: auto;
70
- overflow-x: hidden;
90
+ width: auto;
91
+ height: auto;
92
+ bottom: 110px;
93
+
94
+ // PC端展开状态
95
+ &--expanded {
96
+ position: absolute !important;
97
+ top: 0 !important;
98
+ left: 0 !important;
99
+ right: 0 !important;
100
+ bottom: 0 !important;
101
+ width: 100% !important;
102
+ height: 100% !important;
103
+ background-color: transparent;
104
+ transform: none !important;
105
+ z-index: 1000;
106
+ }
107
+
108
+ &__content {
109
+ // PC端内容定位
110
+ .ai-subtitle-pc:not(.ai-subtitle-pc--expanded) & {
111
+ position: relative;
112
+ width: auto;
113
+ height: auto;
114
+ }
115
+
116
+ // PC端展开时隐藏内容
117
+ .ai-subtitle-pc--expanded & {
118
+ display: none;
119
+ }
120
+ }
121
+
122
+ &__settings {
123
+ // PC端设置面板定位
124
+ .ai-subtitle-pc--expanded & {
125
+ position: absolute;
126
+ top: 50%;
127
+ left: 50%;
128
+ transform: translate(-50%, -50%);
129
+ z-index: 1001;
130
+ }
131
+
132
+ // PC端未展开时隐藏设置
133
+ .ai-subtitle-pc:not(.ai-subtitle-pc--expanded) & {
134
+ display: none;
135
+ }
136
+ }
71
137
  }
72
- .sender-name {
73
- color: yellow;
138
+
139
+ // H5端样式
140
+ .ai-subtitle-h5 {
141
+ position: absolute;
142
+ z-index: 100;
143
+ left: 50%;
144
+ transform: translateX(-50%);
145
+ width: auto;
146
+ height: auto;
147
+ bottom: 26%;
148
+
149
+ // H5端展开状态
150
+ &--expanded {
151
+ position: absolute !important;
152
+ top: 0 !important;
153
+ left: 0 !important;
154
+ right: 0 !important;
155
+ bottom: 0 !important;
156
+ width: 100% !important;
157
+ height: 100% !important;
158
+ background-color: transparent;
159
+ transform: none !important;
160
+ z-index: 1000;
161
+ }
162
+
163
+ &__content {
164
+ // H5端内容定位
165
+ .ai-subtitle-h5:not(.ai-subtitle-h5--expanded) & {
166
+ position: relative;
167
+ width: auto;
168
+ height: auto;
169
+ }
170
+
171
+ // H5端展开时隐藏内容
172
+ .ai-subtitle-h5--expanded & {
173
+ display: none;
174
+ }
175
+ }
176
+
177
+ &__settings {
178
+ // H5端设置面板定位
179
+ .ai-subtitle-h5--expanded & {
180
+ position: absolute;
181
+ top: 50%;
182
+ left: 50%;
183
+ transform: translate(-50%, -50%);
184
+ z-index: 1001;
185
+ }
186
+
187
+ // H5端未展开时隐藏设置
188
+ .ai-subtitle-h5:not(.ai-subtitle-h5--expanded) & {
189
+ display: none;
190
+ }
191
+ }
74
192
  }
75
193
  </style>
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <div @click="handleToggle">
3
+ <TKImage v-if="isAITranscriberRunning" :src="openAiAssistantIcon" width="24px" height="24px" />
4
+ <TKImage v-else :src="closeAiAssistantIcon" width="24px" height="24px" />
5
+ </div>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ import { TUICallKitAPI } from "../../../../../TUICallService/index";
10
+ import { useAIAssistant } from '../../../../hooks/useAIAssistant';
11
+ import TKImage from '../../../base/TKImage/TKImage.vue';
12
+ import openAiAssistantIcon from '../../../../assets/aiAssistant/mobile/open-aiAssistant.svg';
13
+ import closeAiAssistantIcon from '../../../../assets/aiAssistant/mobile/close-aiAssistant.svg';
14
+
15
+ // Use AI Transcriber status hook
16
+ const { isAITranscriberRunning } = useAIAssistant();
17
+
18
+ // Toggle AI transcriber
19
+ const handleToggle = async () => {
20
+ try {
21
+ if (isAITranscriberRunning.value) {
22
+ await TUICallKitAPI._aiAssistant.stopRealtimeTranscriber();
23
+ } else {
24
+ await TUICallKitAPI._aiAssistant.startRealtimeTranscriber({
25
+ sourceLanguage: 'zh',
26
+ translationLanguages: ['en']
27
+ });
28
+ }
29
+ } catch (error) {
30
+ console.error('Failed to toggle AI transcriber:', error);
31
+ }
32
+ };
33
+ </script>
34
+
35
+ <style lang="scss" scoped></style>
@@ -0,0 +1,89 @@
1
+ <template>
2
+ <div class="ai-transcriber-switch">
3
+ <span class="ai-transcriber-switch__label">{{ t('ai-subtitle') }}</span>
4
+ <div
5
+ class="ai-transcriber-switch__toggle"
6
+ :class="{ 'ai-transcriber-switch__toggle--active': isAITranscriberRunning }"
7
+ @click="handleToggle"
8
+ >
9
+ <div class="ai-transcriber-switch__slider"></div>
10
+ </div>
11
+ </div>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { TUICallKitAPI } from "../../../../../TUICallService/index";
16
+ import { useAIAssistant } from '../../../../hooks/useAIAssistant';
17
+ import { useTranslate } from '../../../../hooks/useTranslate';
18
+
19
+ // Use i18n translation
20
+ const t = useTranslate();
21
+
22
+ // Use AI Transcriber status hook
23
+ const { isAITranscriberRunning } = useAIAssistant();
24
+
25
+ // Toggle AI transcriber
26
+ const handleToggle = async () => {
27
+ try {
28
+ if (isAITranscriberRunning.value) {
29
+ await TUICallKitAPI._aiAssistant.stopRealtimeTranscriber();
30
+ } else {
31
+ await TUICallKitAPI._aiAssistant.startRealtimeTranscriber({
32
+ sourceLanguage: 'zh',
33
+ translationLanguages: ['en']
34
+ });
35
+ }
36
+ } catch (error) {
37
+ console.error('Failed to toggle AI transcriber:', error);
38
+ }
39
+ };
40
+ </script>
41
+
42
+ <style lang="scss" scoped>
43
+ .ai-transcriber-switch {
44
+ display: flex;
45
+ align-items: center;
46
+ gap: 8px;
47
+ padding: 8px 12px;
48
+ border-radius: 20px;
49
+ color: white;
50
+ font-size: 14px;
51
+ font-weight: 400;
52
+ font-family: PingFang SC;
53
+ cursor: pointer;
54
+
55
+ &__label {
56
+ white-space: nowrap;
57
+ }
58
+
59
+ &__toggle {
60
+ position: relative;
61
+ width: 32px;
62
+ height: 20px;
63
+ background: #FFFFFF4D;
64
+ border-radius: 10px;
65
+ transition: background-color 0.3s ease;
66
+ cursor: pointer;
67
+
68
+ &--active {
69
+ background: #1C66E5;
70
+ }
71
+ }
72
+
73
+ &__slider {
74
+ position: absolute;
75
+ top: 3px;
76
+ left: 2px;
77
+ width: 14px;
78
+ height: 14px;
79
+ border-radius: 50%;
80
+ background: white;
81
+ transition: transform 0.3s ease;
82
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
83
+
84
+ .ai-transcriber-switch__toggle--active & {
85
+ transform: translateX(14px);
86
+ }
87
+ }
88
+ }
89
+ </style>