bl-trtc-callkit-vue 1.0.4 → 1.1.1
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/README.md +229 -51
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# bl-trtc-callkit-vue
|
|
2
2
|
|
|
3
|
-
基于腾讯云 TRTC SDK 开发的 Vue 3
|
|
4
|
-
|
|
3
|
+
基于腾讯云 TRTC SDK 开发的 Vue 3 通话组件,支持一对一音视频通话、网络质量监测、动态视频质量调整等功能。
|
|
4
|
+
(内部使用、userSig不安全)
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
7
7
|
```bash
|
|
@@ -13,42 +13,244 @@ npm install bl-trtc-callkit-vue
|
|
|
13
13
|
### 基本用法
|
|
14
14
|
|
|
15
15
|
```vue
|
|
16
|
+
<script setup>
|
|
17
|
+
import { ref, onMounted } from 'vue'
|
|
18
|
+
import BlTRTCCallKit from 'bl-trtc-callkit-vue';
|
|
19
|
+
|
|
20
|
+
const callKitRef = ref(null)
|
|
21
|
+
|
|
22
|
+
const targetId = ref('')
|
|
23
|
+
const localUserId = ref(String(Math.floor(Math.random() * 900 + 100)))
|
|
24
|
+
|
|
25
|
+
const remoteUsers = ref([])
|
|
26
|
+
|
|
27
|
+
function onNotify({ type, text }) {
|
|
28
|
+
showToast(text, type)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 处理远端用户状态变化
|
|
32
|
+
function onRemoteUserStatusChange({ userId, action, userList }) {
|
|
33
|
+
console.log('远端用户状态变化:', { userId, action, userList })
|
|
34
|
+
|
|
35
|
+
if (action === 'enter') {
|
|
36
|
+
// 检查用户是否已在列表中
|
|
37
|
+
const existingIndex = remoteUsers.value.findIndex(u => u.userId === userId)
|
|
38
|
+
if (existingIndex === -1) {
|
|
39
|
+
remoteUsers.value.push({
|
|
40
|
+
userId,
|
|
41
|
+
status: 'online',
|
|
42
|
+
})
|
|
43
|
+
} else {
|
|
44
|
+
// 更新现有用户状态
|
|
45
|
+
remoteUsers.value[existingIndex].status = 'online'
|
|
46
|
+
}
|
|
47
|
+
} else if (action === 'exit') {
|
|
48
|
+
const existingIndex = remoteUsers.value.findIndex(u => u.userId === userId)
|
|
49
|
+
if (existingIndex !== -1) {
|
|
50
|
+
remoteUsers.value[existingIndex].status = 'offline'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
onMounted(() => {
|
|
56
|
+
// 初始化:传入 userId、sdkAppId、sdkSecretKey
|
|
57
|
+
callKitRef.value.init({
|
|
58
|
+
userId: localUserId.value,
|
|
59
|
+
sdkAppId: "YOUR_SDK_APP_ID",
|
|
60
|
+
sdkSecretKey: "YOUR_SDK_SECRET_KEY"
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// 主动呼叫某用户
|
|
65
|
+
function callSomeone() {
|
|
66
|
+
callKitRef.value.handleCall(targetId.value)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function handleRemoteUserClick(user) {
|
|
70
|
+
if (user.status === 'online') {
|
|
71
|
+
callKitRef.value.handleCall(user.userId)
|
|
72
|
+
} else {
|
|
73
|
+
alert('对方已离线')
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const toastList = ref([]);
|
|
78
|
+
// 生成唯一ID
|
|
79
|
+
function generateId() {
|
|
80
|
+
return Date.now() + Math.random()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 显示 Toast
|
|
84
|
+
function showToast(text, type = 'info') {
|
|
85
|
+
const id = generateId()
|
|
86
|
+
const toast = {
|
|
87
|
+
id,
|
|
88
|
+
text,
|
|
89
|
+
type
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
toastList.value.push(toast)
|
|
93
|
+
|
|
94
|
+
// 3秒后自动移除
|
|
95
|
+
setTimeout(() => {
|
|
96
|
+
const index = toastList.value.findIndex(item => item.id === id)
|
|
97
|
+
if (index !== -1) {
|
|
98
|
+
toastList.value.splice(index, 1)
|
|
99
|
+
}
|
|
100
|
+
}, 3000)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 获取图标
|
|
104
|
+
function getIcon(type) {
|
|
105
|
+
switch (type) {
|
|
106
|
+
case 'error':
|
|
107
|
+
return '❌'
|
|
108
|
+
case 'info':
|
|
109
|
+
default:
|
|
110
|
+
return 'ℹ️'
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
</script>
|
|
114
|
+
|
|
16
115
|
<template>
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
116
|
+
<div class="wrapper">
|
|
117
|
+
<div style="font-size: 1rem;">当前 userId:<strong>{{ localUserId }}</strong></div>
|
|
118
|
+
|
|
119
|
+
<div class="remote-user-call">
|
|
120
|
+
<input v-model="targetId" placeholder="输入要呼叫的用户ID" style="height: 36px;" />
|
|
121
|
+
<button @click="callSomeone" style="height: 36px;padding: 0 8px;">呼叫 {{ targetId || '目标用户' }}</button>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div style="margin-top:12px; border:1px solid #ccc; padding:10px; border-radius:4px;">
|
|
125
|
+
<h4>远端用户列表</h4>
|
|
126
|
+
<ul>
|
|
127
|
+
<li v-for="user in remoteUsers" :key="user.userId"
|
|
128
|
+
:style="{ color: user.status === 'online' ? 'green' : 'gray' }" @click="handleRemoteUserClick(user)">
|
|
129
|
+
{{ user.userId }} ({{ user.status === 'online' ? '在线' : '离线' }})
|
|
130
|
+
</li>
|
|
131
|
+
</ul>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<BlTrtcCallkit ref="callKitRef" @notify="onNotify" @remote-user-status-change="onRemoteUserStatusChange" />
|
|
135
|
+
|
|
136
|
+
<!-- Toast 通知组件 -->
|
|
137
|
+
<div class="toast-container">
|
|
138
|
+
<transition-group name="toast">
|
|
139
|
+
<div v-for="toast in toastList" :key="toast.id" :class="['toast-item', `toast-${toast.type}`]">
|
|
140
|
+
<span class="toast-icon">{{ getIcon(toast.type) }}</span>
|
|
141
|
+
<span class="toast-text">{{ toast.text }}</span>
|
|
142
|
+
</div>
|
|
143
|
+
</transition-group>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
20
146
|
</template>
|
|
21
147
|
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
148
|
+
<style scoped>
|
|
149
|
+
.wrapper {
|
|
150
|
+
max-width: 1200px;
|
|
151
|
+
margin: 0 auto;
|
|
152
|
+
padding: 12px;
|
|
153
|
+
display: flex;
|
|
154
|
+
flex-direction: column;
|
|
155
|
+
gap: 8px;
|
|
156
|
+
box-sizing: border-box;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.wrapper .remote-user-call {
|
|
160
|
+
margin-top: 12px;
|
|
161
|
+
display: flex;
|
|
162
|
+
gap: 8px;
|
|
163
|
+
align-items: center;
|
|
164
|
+
}
|
|
25
165
|
|
|
26
|
-
|
|
166
|
+
.wrapper ul {
|
|
167
|
+
margin-top: 12px;
|
|
168
|
+
}
|
|
27
169
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
170
|
+
.wrapper li {
|
|
171
|
+
height: 32px;
|
|
172
|
+
display: flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
background: #eee;
|
|
175
|
+
border-radius: 4px;
|
|
176
|
+
padding: 6px 8px;
|
|
177
|
+
margin-bottom: 12px;
|
|
178
|
+
cursor: pointer;
|
|
35
179
|
}
|
|
36
180
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
181
|
+
.toast-container {
|
|
182
|
+
position: fixed;
|
|
183
|
+
top: 20px;
|
|
184
|
+
right: 20px;
|
|
185
|
+
z-index: 9999;
|
|
186
|
+
display: flex;
|
|
187
|
+
flex-direction: column;
|
|
188
|
+
gap: 10px;
|
|
189
|
+
max-width: 300px;
|
|
40
190
|
}
|
|
41
191
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
192
|
+
.toast-item {
|
|
193
|
+
display: flex;
|
|
194
|
+
align-items: center;
|
|
195
|
+
padding: 12px 16px;
|
|
196
|
+
border-radius: 8px;
|
|
197
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
198
|
+
animation: slideInRight 0.3s ease;
|
|
199
|
+
min-width: 250px;
|
|
200
|
+
max-width: 100%;
|
|
45
201
|
}
|
|
46
202
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
203
|
+
.toast-info {
|
|
204
|
+
background-color: #e3f2fd;
|
|
205
|
+
color: #1976d2;
|
|
206
|
+
border-left: 4px solid #2196f3;
|
|
50
207
|
}
|
|
51
|
-
|
|
208
|
+
|
|
209
|
+
.toast-error {
|
|
210
|
+
background-color: #ffebee;
|
|
211
|
+
color: #d32f2f;
|
|
212
|
+
border-left: 4px solid #f44336;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.toast-icon {
|
|
216
|
+
margin-right: 10px;
|
|
217
|
+
font-size: 18px;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.toast-text {
|
|
221
|
+
flex: 1;
|
|
222
|
+
word-break: break-word;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* 动画效果 */
|
|
226
|
+
.toast-enter-active,
|
|
227
|
+
.toast-leave-active {
|
|
228
|
+
transition: all 0.3s ease;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.toast-enter-from {
|
|
232
|
+
opacity: 0;
|
|
233
|
+
transform: translateX(100%);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.toast-leave-to {
|
|
237
|
+
opacity: 0;
|
|
238
|
+
transform: translateX(100%);
|
|
239
|
+
position: absolute;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@keyframes slideInRight {
|
|
243
|
+
from {
|
|
244
|
+
transform: translateX(100%);
|
|
245
|
+
opacity: 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
to {
|
|
249
|
+
transform: translateX(0);
|
|
250
|
+
opacity: 1;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
</style>
|
|
52
254
|
```
|
|
53
255
|
|
|
54
256
|
## API 说明
|
|
@@ -79,7 +281,7 @@ function handleRemoteUserStatusChange(data: { userId: string; action: string; us
|
|
|
79
281
|
|
|
80
282
|
## 功能特性
|
|
81
283
|
|
|
82
|
-
1.
|
|
284
|
+
1. **音视频通话**:仅支持一对一音视频通话
|
|
83
285
|
2. **网络质量监测**:实时监测网络质量,动态调整视频质量
|
|
84
286
|
3. **设备控制**:支持开启/关闭麦克风、摄像头
|
|
85
287
|
4. **扬声器控制**:支持切换扬声器/听筒
|
|
@@ -91,27 +293,3 @@ function handleRemoteUserStatusChange(data: { userId: string; action: string; us
|
|
|
91
293
|
2. 确保在 HTTPS 环境下使用,否则可能无法正常访问摄像头和麦克风
|
|
92
294
|
3. 首次使用时需要用户授权摄像头和麦克风权限
|
|
93
295
|
4. 建议在组件销毁前调用 `hangup` 方法关闭所有媒体流
|
|
94
|
-
|
|
95
|
-
## 开发
|
|
96
|
-
|
|
97
|
-
### 安装依赖
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
npm install
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### 启动开发服务器
|
|
104
|
-
|
|
105
|
-
```bash
|
|
106
|
-
npm run dev
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### 构建生产版本
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
npm run build
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## 许可证
|
|
116
|
-
|
|
117
|
-
MIT
|