Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-dml
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-dml
Commits
28f4122c
提交
28f4122c
authored
7月 13, 2026
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 增强直播功能,支持动态上传选项和流重启
上级
483b0ac7
隐藏空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
52 行增加
和
13 行删除
+52
-13
Live.vue
src/modules/live/test/components/Live.vue
+34
-9
useLive.ts
src/modules/live/test/composables/useLive.ts
+18
-4
没有找到文件。
src/modules/live/test/components/Live.vue
浏览文件 @
28f4122c
...
...
@@ -31,7 +31,7 @@ watch(
()
=>
{
props
.
onStatsChange
&&
props
.
onStatsChange
({
...
stats
,
viewers
:
viewers
.
value
.
length
})
},
{
immediate
:
true
,
deep
:
true
}
{
immediate
:
true
,
deep
:
true
}
,
)
const
detail
=
inject
(
'detail'
)
...
...
@@ -71,11 +71,13 @@ const { start: startSpeechTranscriber, stop: stopSpeechTranscriber } = useSpeech
const
isOSSUpload
=
true
let
ossResult
=
null
let
totalSize
=
0
const
{
stream
,
start
:
startLive
,
stop
:
stopLive
,
restartStream
,
startTime
,
endTime
,
duration
,
...
...
@@ -83,6 +85,7 @@ const {
switchCamera
,
isMobile
,
}
=
useLive
({
keepChunks
:
props
.
isLocalUpload
,
onStart
:
()
=>
{
console
.
log
(
'开始直播'
)
props
.
onStart
&&
props
.
onStart
()
...
...
@@ -92,6 +95,7 @@ const {
}
},
onRecord
:
async
(
blob
)
=>
{
totalSize
+=
blob
.
size
if
(
props
.
isLocalUpload
)
return
if
(
isOSSUpload
)
{
ossResult
=
await
appendUpload
(
blob
,
{
...
...
@@ -114,7 +118,7 @@ const {
if
(
enabled
.
value
)
return
props
.
onStop
&&
props
.
onStop
(
blob
)
stopChat
()
handleUpdateRecord
({
live_video_size
:
blob
.
size
.
toString
()
})
handleUpdateRecord
({
live_video_size
:
(
props
.
isLocalUpload
?
blob
.
size
:
totalSize
)
.
toString
()
})
// 保存录像到本地
if
(
props
.
isLocalUpload
)
{
saveAs
(
blob
,
`
${
fileName
.
value
}
.mp4`
)
...
...
@@ -201,12 +205,24 @@ const toggleLive = () => {
}
watch
(
enabled
,
toggleLive
)
function
start
()
{
if
(
video
.
value
)
enabled
.
value
=
true
async
function
start
()
{
if
(
!
video
.
value
)
return
if
(
window
.
parent
!==
window
)
{
window
.
parent
.
postMessage
({
action
:
'monitor-pause'
},
'*'
)
// 等父页面释放摄像头后再重新获取
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
500
))
await
restartStream
()
}
enabled
.
value
=
true
}
function
stop
()
{
if
(
video
.
value
)
{
enabled
.
value
=
false
if
(
!
video
.
value
)
return
enabled
.
value
=
false
if
(
window
.
parent
!==
window
)
{
// 等录制完全停止后通知父页面恢复监控
setTimeout
(()
=>
{
window
.
parent
.
postMessage
({
action
:
'monitor-resume'
},
'*'
)
},
500
)
}
}
defineExpose
({
enabled
,
start
,
stop
})
...
...
@@ -228,9 +244,18 @@ defineExpose({ enabled, start, stop })
size=
"small"
@
click=
"switchCamera"
v-if=
"isMobile && !enabled && !recordId"
>
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"16"
height=
"16"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"currentColor"
stroke-width=
"2"
stroke-linecap=
"round"
stroke-linejoin=
"round"
>
<path
d=
"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"
/>
<circle
cx=
"12"
cy=
"13"
r=
"4"
/>
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"16"
height=
"16"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"currentColor"
stroke-width=
"2"
stroke-linecap=
"round"
stroke-linejoin=
"round"
>
<path
d=
"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"
/>
<circle
cx=
"12"
cy=
"13"
r=
"4"
/>
</svg>
</el-button>
</div>
...
...
src/modules/live/test/composables/useLive.ts
浏览文件 @
28f4122c
...
...
@@ -20,12 +20,13 @@ export const readBlobAsBase64 = (blob: Blob): Promise<string> => {
interface
UseLiveProps
{
enabledUserMedia
:
boolean
keepChunks
?:
boolean
onStart
?:
()
=>
void
onRecord
?:
(
data
:
Blob
)
=>
void
onStop
?:
(
blob
:
Blob
)
=>
void
}
export
function
useLive
({
enabledUserMedia
=
true
,
onStart
,
onRecord
,
onStop
}:
UseLiveProps
)
{
export
function
useLive
({
enabledUserMedia
=
true
,
keepChunks
=
true
,
onStart
,
onRecord
,
onStop
}:
UseLiveProps
)
{
const
startTime
=
ref
(
0
)
const
endTime
=
ref
(
0
)
const
duration
=
computed
(()
=>
(
endTime
.
value
-
startTime
.
value
)
/
1000
)
...
...
@@ -52,7 +53,7 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
})
// 创建媒体流
const
{
stream
}
=
useUserMedia
({
const
{
stream
,
restart
:
restartStream
}
=
useUserMedia
({
enabled
:
enabledUserMedia
,
constraints
:
constraints
as
any
,
})
...
...
@@ -75,7 +76,7 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
// 数据可用时处理
const
handleDataAvailable
=
(
event
:
BlobEvent
)
=>
{
if
(
event
.
data
.
size
>
0
)
{
recordedChunks
.
value
.
push
(
event
.
data
)
if
(
keepChunks
)
recordedChunks
.
value
.
push
(
event
.
data
)
onRecord
&&
onRecord
(
event
.
data
)
}
}
...
...
@@ -125,5 +126,18 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
nextTick
(()
=>
initializeMediaRecorder
())
}
return
{
stream
,
start
,
stop
,
startTime
,
endTime
,
duration
,
currentTime
,
switchCamera
,
facingMode
,
isFrontCamera
,
isMobile
}
return
{
stream
,
start
,
stop
,
restartStream
,
startTime
,
endTime
,
duration
,
currentTime
,
switchCamera
,
facingMode
,
isFrontCamera
,
isMobile
,
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论