Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
standalone-anyremote
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
qlintonger xeno
standalone-anyremote
Commits
857a7f32
Commit
857a7f32
authored
May 09, 2024
by
pangchong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 视频通话默认图
parent
0d651b6a
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
137 additions
and
57 deletions
+137
-57
src/App.vue
+1
-1
src/views/remote/videoCall/index.vue
+2
-1
src/views/remote/videoCall/videoChat.vue
+1
-1
src/views/remote/videoCall/videoItem.vue
+45
-27
src/views/remote/videoCall/videoLoader.vue
+48
-0
src/views/remote/videoCall/videoTools.vue
+40
-27
No files found.
src/App.vue
View file @
857a7f32
...
@@ -93,7 +93,7 @@ router.beforeEach(async (to, from, next) => {
...
@@ -93,7 +93,7 @@ router.beforeEach(async (to, from, next) => {
next
({
path
:
'./'
})
next
({
path
:
'./'
})
}
else
{
}
else
{
//视频通话页面
//视频通话页面
if
(
to
.
name
==
'VideoCall'
)
{
if
(
to
.
name
==
'VideoCall
1
'
)
{
if
(
AnyR
.
agora
&&
chatChannelState
.
value
.
currentState
==
CallState
.
calling
)
{
if
(
AnyR
.
agora
&&
chatChannelState
.
value
.
currentState
==
CallState
.
calling
)
{
next
()
next
()
}
else
{
}
else
{
...
...
src/views/remote/videoCall/index.vue
View file @
857a7f32
...
@@ -6,9 +6,10 @@
...
@@ -6,9 +6,10 @@
<a-col
:flex=
"10"
class=
"h-full ml-4"
>
<a-col
:flex=
"10"
class=
"h-full ml-4"
>
<video-info></video-info>
<video-info></video-info>
</a-col>
</a-col>
<a-col
:flex=
"3"
class=
"h-full"
v-
if
=
"!fullScreen"
>
<a-col
:flex=
"3"
class=
"h-full"
v-
show
=
"!fullScreen"
>
<video-chat></video-chat>
<video-chat></video-chat>
</a-col>
</a-col>
<template></
template
>
</a-row>
</a-row>
</template>
</template>
...
...
src/views/remote/videoCall/videoChat.vue
View file @
857a7f32
<
template
>
<
template
>
<div
class=
"g-block ml-4 pb-0"
>
<div
class=
"g-block ml-4 pb-0"
>
<div
class=
"px-4 h-[
300
px]"
>
<div
class=
"px-4 h-[
172
px]"
>
<video-item
:id=
"''"
:is-self=
"true"
></video-item>
<video-item
:id=
"''"
:is-self=
"true"
></video-item>
</div>
</div>
<a-row
class=
"mt-2 px-4"
>
<a-row
class=
"mt-2 px-4"
>
...
...
src/views/remote/videoCall/videoItem.vue
View file @
857a7f32
<
template
>
<
template
>
<div
:id=
"ps.isSelf ? 'LocalVideo' : `RemoteVideo$
{ps.id}`" class="relative h-full video-cont">
<div
:id=
"ps.isSelf ? 'LocalVideo' : `RemoteVideo$
{ps.id}`" class="relative h-full video-cont bg-fill-bg1" ref="remoteVideoRef">
<div
class=
"absolute flex justify-between items-center p-1 top-0 left-0 w-full z-10"
>
<template
v-if=
"isVideoVisible"
>
<div
class=
"text-xs px-2 rounded-sm leading-5 bg-primary-disable text-primary"
v-if=
"userDataForThis.userCallGroup == 1"
>
<div
class=
"absolute flex justify-between items-center p-1 top-0 left-0 w-full z-10"
>
{{
userDataForThis
.
name
}}
<div
class=
"text-xs px-2 rounded-sm leading-5 bg-primary-disable text-primary"
v-if=
"userDataForThis.userCallGroup == 1"
>
</div>
{{
userDataForThis
.
name
}}
<div
class=
"text-xs px-2 rounded-sm leading-5"
style=
"background-color: rgb(var(--success-1)); color: rgb(var(--success-6))"
v-else
>
{{
userDataForThis
.
name
}}
</div>
<a-space
:size=
"4"
>
<div
class=
"rounded-full size-6 flex-center bg-theme-bg1 cursor-pointer"
>
<global-icon
:size=
"12"
icon=
"writing"
></global-icon>
</div>
</div>
<div
class=
"rounded-full size-6 flex-center cursor-pointer"
style=
"background-color: var(--color-border-1)"
>
<div
class=
"text-xs px-2 rounded-sm leading-5"
style=
"background-color: rgb(var(--success-1)); color: rgb(var(--success-6))"
v-else
>
<global-icon
v-if=
"!isThisUserMuted"
:size=
"12"
color=
"rgb(var(--success-6))"
:icon=
"'mic'"
></global-icon>
{{
userDataForThis
.
name
}}
<global-icon
:size=
"12"
v-else
:icon=
"'mic-off'"
></global-icon>
</div>
</div>
</a-space>
<a-space
:size=
"4"
>
</div>
<div
class=
"rounded-full size-6 flex-center bg-theme-bg1 cursor-pointer"
>
<div
v-if=
"isUserHost"
class=
"absolute left-0 bottom-0 z-10 p-1"
>
<global-icon
:size=
"12"
icon=
"writing"
></global-icon>
<div
class=
"flex-center rounded-sm px-2 py-0.5 bg-fill-bg1"
>
</div>
<global-icon
:size=
"12"
icon=
"user"
></global-icon>
<div
class=
"rounded-full size-6 flex-center cursor-pointer"
style=
"background-color: var(--color-border-1)"
>
<span
class=
"text-xs ml-1 text-theme-text1"
>
主持人
</span>
<global-icon
v-if=
"!isThisUserMuted"
:size=
"12"
color=
"rgb(var(--success-6))"
:icon=
"'mic'"
></global-icon>
<global-icon
:size=
"12"
v-else
:icon=
"'mic-off'"
></global-icon>
</div>
</a-space>
</div>
</div>
</div>
<div
v-if=
"isUserHost"
class=
"absolute left-0 bottom-0 z-10 p-1"
>
<div
v-if=
"userDataForThis.calling"
class=
"absolute top-0 left-0 right-0 bottom-0 flex-center flex-col"
>
<div
class=
"flex-center rounded-sm px-2 py-0.5 bg-fill-bg1"
>
<div
class=
"text-base text-theme-text1"
>
呼叫中...
</div>
<global-icon
:size=
"12"
icon=
"user"
></global-icon>
<a-button
shape=
"circle"
status=
"danger"
type=
"primary"
@
click
.
stop=
"cancelCallExact"
>
<span
class=
"text-xs ml-1 text-theme-text1"
>
主持人
</span>
<global-icon
:size=
"20"
color=
"var(--color-bg-white)"
icon=
"phone-hangup"
></global-icon>
</div>
</a-button>
</div>
<div
v-if=
"userDataForThis.calling"
class=
"absolute top-0 left-0 right-0 bottom-0 flex-center flex-col"
>
<div
class=
"text-base text-theme-text1"
>
呼叫中...
</div>
<a-button
shape=
"circle"
status=
"danger"
type=
"primary"
@
click
.
stop=
"cancelCallExact"
>
<global-icon
:size=
"20"
color=
"var(--color-bg-white)"
icon=
"phone-hangup"
></global-icon>
</a-button>
</div>
</
template
>
<div
class=
"absolute w-full h-full flex-center"
v-else
>
<video-loader></video-loader>
</div>
</div>
</div>
</div>
</template>
</template>
...
@@ -37,13 +42,14 @@ import { chatChannelState, isUserHost } from 'AnyR/states/chatChannelStates'
...
@@ -37,13 +42,14 @@ import { chatChannelState, isUserHost } from 'AnyR/states/chatChannelStates'
import
{
userStates
}
from
'AnyR/states/wsStates'
import
{
userStates
}
from
'AnyR/states/wsStates'
import
{
computed
,
onMounted
,
onUpdated
}
from
'vue'
import
{
computed
,
onMounted
,
onUpdated
}
from
'vue'
import
{
useAnyR
}
from
'AnyR/index'
import
{
useAnyR
}
from
'AnyR/index'
import
VideoLoader
from
'./videoLoader.vue'
const
ps
=
defineProps
({
const
ps
=
defineProps
({
isSelf
:
Boolean
,
isSelf
:
Boolean
,
id
:
String
id
:
String
})
})
const
isThisUserMuted
=
computed
(
function
()
{
const
isThisUserMuted
=
computed
(
function
()
{
return
chatChannelState
.
value
.
mutedUserIdSet
.
includes
(
ps
.
id
)
||
chatChannelState
.
value
.
mutedUserIdSet
.
includes
(
userStates
.
value
.
currentUserId
)
return
chatChannelState
.
value
.
mutedUserIdSet
.
includes
(
ps
.
id
)
||
chatChannelState
.
value
.
mutedUserIdSet
.
includes
(
userStates
.
value
.
currentUserId
)
})
})
...
@@ -69,10 +75,19 @@ function cancelCallExact() {
...
@@ -69,10 +75,19 @@ function cancelCallExact() {
AnyR
?.
agora
.
cancelExactCall
(
ps
.
id
)
AnyR
?.
agora
.
cancelExactCall
(
ps
.
id
)
}
}
//监听视频是否渲染成功
const
remoteVideoRef
=
ref
()
const
isVideoVisible
=
ref
(
false
)
const
checkVideoExists
=
()
=>
{
const
video
=
remoteVideoRef
.
value
.
querySelector
(
'video'
)
isVideoVisible
.
value
=
video
?
true
:
false
}
const
observer
=
new
MutationObserver
(
checkVideoExists
)
onMounted
(
function
()
{
onMounted
(
function
()
{
if
(
!
ps
.
isSelf
)
{
if
(
!
ps
.
isSelf
)
{
AnyR
?.
agora
.
forceReplay
(
ps
.
id
)
AnyR
?.
agora
.
forceReplay
(
ps
.
id
)
}
}
observer
.
observe
(
remoteVideoRef
.
value
,
{
childList
:
true
,
subtree
:
true
})
})
})
onUpdated
(
function
()
{
onUpdated
(
function
()
{
...
@@ -80,6 +95,9 @@ onUpdated(function () {
...
@@ -80,6 +95,9 @@ onUpdated(function () {
AnyR
?.
agora
.
forceReplay
(
ps
.
id
)
AnyR
?.
agora
.
forceReplay
(
ps
.
id
)
}
}
})
})
onUnmounted
(()
=>
{
observer
.
disconnect
()
// 停止监听
})
</
script
>
</
script
>
<
style
lang=
"less"
scoped
>
<
style
lang=
"less"
scoped
>
:deep
(
.video-cont
video
)
{
:deep
(
.video-cont
video
)
{
...
...
src/views/remote/videoCall/videoLoader.vue
0 → 100644
View file @
857a7f32
<
template
>
<div
class=
"flex-center flex-col"
>
<div
style=
"height: 70px"
><div
class=
"loader"
></div></div>
<span>
正在通话中...
</span>
</div>
</
template
>
<
script
setup
lang=
"ts"
></
script
>
<
style
lang=
"less"
scoped
>
.loader
{
width
:
8px
;
height
:
40px
;
border-radius
:
4px
;
display
:
block
;
background-color
:
currentColor
;
margin
:
20px
auto
;
position
:
relative
;
color
:
rgb
(
var
(
--primary-6
));
animation
:
animloader
0.3s
0.3s
linear
infinite
alternate
;
}
.loader
::after
,
.loader
::before
{
content
:
''
;
width
:
8px
;
height
:
40px
;
border-radius
:
4px
;
background
:
currentColor
;
position
:
absolute
;
top
:
50%
;
transform
:
translateY
(
-50%
);
left
:
20px
;
animation
:
animloader
0.3s
0.45s
linear
infinite
alternate
;
}
.loader
::before
{
left
:
-20px
;
animation-delay
:
0s
;
}
@keyframes
animloader
{
0
%
{
height
:
48px
;
}
100
%
{
height
:
4px
;
}
}
</
style
>
src/views/remote/videoCall/videoTools.vue
View file @
857a7f32
<
template
>
<
template
>
<div>
<div>
<div
:id=
"`RemoteVideo$
{ps.id}`" class="relative mb-4 flex-auto
" data-self="remote-main" @mousedown.capture="handleBlinkingStart
">
<div
:id=
"`RemoteVideo$
{ps.id}`" class="relative mb-4 flex-auto
bg-fill-bg1" data-self="remote-main" @mousedown.capture="handleBlinkingStart" ref="remoteVideoRef
">
<n-message-provider>
<n-message-provider>
<image-editor
<image-editor
:before-cancel=
"beforeEndMarkHandle"
:before-cancel=
"beforeEndMarkHandle"
...
@@ -26,24 +26,23 @@
...
@@ -26,24 +26,23 @@
class="red-ball absolute z-[999]"
class="red-ball absolute z-[999]"
@animationend="centerEnded"
@animationend="centerEnded"
>
</div>
>
</div>
<div
class=
"absolute flex justify-between items-center p-1 t-0 l-0 w-full z-10"
>
<template
v-if=
"isVideoVisible"
>
<div
v-if=
"userDataForThis.userCallGroup == 1"
class=
"text-xs px-2 rounded-sm leading-5 bg-primary-disable text-primary"
>
<div
class=
"absolute flex justify-between items-center p-1 t-0 l-0 w-full z-10"
>
{{
userDataForThis
.
name
}}
<div
v-if=
"userDataForThis.userCallGroup == 1"
class=
"text-xs px-2 rounded-sm leading-5 bg-primary-disable text-primary"
>
</div>
{{
userDataForThis
.
name
}}
<div
v-else
class=
"text-xs px-2 rounded-sm leading-5"
style=
"background-color: rgb(var(--success-1)); color: rgb(var(--success-6))"
>
</div>
{{
userDataForThis
.
name
}}
<div
v-else
class=
"text-xs px-2 rounded-sm leading-5"
style=
"background-color: rgb(var(--success-1)); color: rgb(var(--success-6))"
>
</div>
{{
userDataForThis
.
name
}}
<div
class=
"rounded-full size-6 flex-center"
style=
"background-color: var(--color-border-1)"
>
</div>
<global-icon
v-if=
"!isCenterUserMuted"
:size=
"12"
color=
"rgb(var(--success-6))"
:icon=
"'mic'"
></global-icon>
<div
class=
"rounded-full size-6 flex-center"
style=
"background-color: var(--color-border-1)"
>
<global-icon
v-else
:size=
"12"
:icon=
"'mic-off'"
></global-icon>
<global-icon
v-if=
"!isCenterUserMuted"
:size=
"12"
color=
"rgb(var(--success-6))"
:icon=
"'mic'"
></global-icon>
<global-icon
v-else
:size=
"12"
:icon=
"'mic-off'"
></global-icon>
</div>
</div>
</div>
</
template
>
<div
class=
"absolute w-full h-full flex-center"
v-else
>
<video-loader></video-loader>
</div>
</div>
<!--
<div
class=
"absolute top-0 left-0 right-0 bottom-0 flex-center flex-col"
>
<div
class=
"text-base text-theme-text1"
>
呼叫中...
</div>
<a-button
shape=
"circle"
status=
"danger"
type=
"primary"
@
click=
"hangupCall"
>
<global-icon
:size=
"20"
color=
"var(--color-bg-white)"
icon=
"phone-hangup"
></global-icon>
</a-button>
</div>
-->
</div>
</div>
<div
class=
"flex justify-center w-full"
>
<div
class=
"flex justify-center w-full"
>
<div
v-if=
"!isUserHost"
class=
"w-[120px] h-[72px] item"
@
click=
"hangupCall"
>
<div
v-if=
"!isUserHost"
class=
"w-[120px] h-[72px] item"
@
click=
"hangupCall"
>
...
@@ -74,7 +73,7 @@
...
@@ -74,7 +73,7 @@
</div>
</div>
<div
class=
"w-[120px] h-[72px] item"
@
click=
"toggleRecording"
>
<div
class=
"w-[120px] h-[72px] item"
@
click=
"toggleRecording"
>
<global-icon
:size=
"21"
icon=
"record"
></global-icon>
<global-icon
:size=
"21"
icon=
"record"
></global-icon>
<span
class=
"mt-1 color-text-2"
>
{{
!
chatChannelState
.
recordingData
.
id
?
'开始录制'
:
'结束录制'
}}
</span>
<span
class=
"mt-1 color-text-2"
>
{{
!chatChannelState.recordingData.id ? '开始录制' : '结束录制'
}}
</span>
</div>
</div>
<div
v-if=
"isUserHost"
class=
"w-[120px] h-[72px] item"
@
click=
"allMute"
>
<div
v-if=
"isUserHost"
class=
"w-[120px] h-[72px] item"
@
click=
"allMute"
>
<global-icon
:size=
"21"
icon=
"mic-off"
></global-icon>
<global-icon
:size=
"21"
icon=
"mic-off"
></global-icon>
...
@@ -97,6 +96,7 @@ import { userStates } from 'AnyR/states/wsStates'
...
@@ -97,6 +96,7 @@ import { userStates } from 'AnyR/states/wsStates'
import
ImageEditor
from
'AnyR/widgets/ImageEditor/imageEditor.vue'
import
ImageEditor
from
'AnyR/widgets/ImageEditor/imageEditor.vue'
import
{
Message
,
Modal
}
from
'@arco-design/web-vue'
import
{
Message
,
Modal
}
from
'@arco-design/web-vue'
import
{
alova
}
from
'@/api/alova-instance.ts'
import
{
alova
}
from
'@/api/alova-instance.ts'
import
VideoLoader
from
'./videoLoader.vue'
const
ps
=
defineProps
<
{
const
ps
=
defineProps
<
{
id
:
any
id
:
any
...
@@ -104,19 +104,19 @@ const ps = defineProps<{
...
@@ -104,19 +104,19 @@ const ps = defineProps<{
async
function
toggleRecording
()
{
async
function
toggleRecording
()
{
if
(
!
chatChannelState
.
value
.
recordingData
.
id
)
{
if
(
!
chatChannelState
.
value
.
recordingData
.
id
)
{
const
resp
=
await
AnyR
?.
agora
.
recordCurrent
()
;
const
resp
=
await
AnyR
?.
agora
.
recordCurrent
()
if
(
resp
)
{
if
(
resp
)
{
Message
.
success
(
"录制成功开始!"
)
Message
.
success
(
'录制成功开始!'
)
}
else
{
}
else
{
Message
.
error
(
"录制失败!"
)
Message
.
error
(
'录制失败!'
)
}
}
}
else
{
}
else
{
const
resp
=
await
AnyR
?.
agora
.
stopRecordCurrent
()
const
resp
=
await
AnyR
?.
agora
.
stopRecordCurrent
()
console
.
log
(
"录制结果提示?"
,
resp
);
console
.
log
(
'录制结果提示?'
,
resp
)
}
}
}
}
const
isCenterUserMuted
=
computed
(
function
()
{
const
isCenterUserMuted
=
computed
(
function
()
{
return
chatChannelState
.
value
.
mutedUserIdSet
.
includes
(
ps
.
id
)
return
chatChannelState
.
value
.
mutedUserIdSet
.
includes
(
ps
.
id
)
})
})
...
@@ -179,16 +179,16 @@ async function beforeEndMarkHandle() {
...
@@ -179,16 +179,16 @@ async function beforeEndMarkHandle() {
return
new
Promise
(
function
(
resolve
)
{
return
new
Promise
(
function
(
resolve
)
{
Modal
.
warning
({
Modal
.
warning
({
title
:
'退出确认'
,
title
:
'退出确认'
,
content
:
"你是截图发起者,退出后将会要求其他用户一同退出,确认?"
,
content
:
'你是截图发起者,退出后将会要求其他用户一同退出,确认?'
,
okText
:
"确认"
,
okText
:
'确认'
,
cancelText
:
"取消"
,
cancelText
:
'取消'
,
hideCancel
:
false
,
hideCancel
:
false
,
onOk
()
{
onOk
()
{
resolve
(
true
)
resolve
(
true
)
},
},
onCancel
()
{
onCancel
()
{
resolve
(
false
)
resolve
(
false
)
}
,
}
})
})
})
})
}
}
...
@@ -239,14 +239,27 @@ const userDataForThis = computed(function () {
...
@@ -239,14 +239,27 @@ const userDataForThis = computed(function () {
}
}
})
})
//监听视频是否渲染成功
const
remoteVideoRef
=
ref
()
const
isVideoVisible
=
ref
(
false
)
const
checkVideoExists
=
()
=>
{
const
video
=
remoteVideoRef
.
value
.
querySelector
(
'video'
)
isVideoVisible
.
value
=
video
?
true
:
false
}
const
observer
=
new
MutationObserver
(
checkVideoExists
)
onMounted
(
function
()
{
onMounted
(
function
()
{
AnyR
?.
agora
.
forceReplay
(
ps
.
id
)
AnyR
?.
agora
.
forceReplay
(
ps
.
id
)
observer
.
observe
(
remoteVideoRef
.
value
,
{
childList
:
true
,
subtree
:
true
})
})
})
onUpdated
(
function
()
{
onUpdated
(
function
()
{
AnyR
?.
agora
.
forceReplay
(
ps
.
id
)
AnyR
?.
agora
.
forceReplay
(
ps
.
id
)
})
})
onUnmounted
(()
=>
{
observer
.
disconnect
()
// 停止监听
})
const
isVoiceChatOnly
=
ref
(
false
)
const
isVoiceChatOnly
=
ref
(
false
)
const
AnyR
=
useAnyR
()
const
AnyR
=
useAnyR
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment