Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
live-management-web
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
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
haojie
live-management-web
Commits
0d8701a5
Commit
0d8701a5
authored
Aug 02, 2023
by
haojie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
洗稿
parent
8b03221a
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1117 additions
and
428 deletions
+1117
-428
src/components/MultipleUpload/index.less
+4
-0
src/components/MultipleUpload/index.tsx
+53
-15
src/components/ScriptTemplate.vue
+8
-3
src/components/loading.vue
+124
-111
src/components/upload/index.tsx
+70
-33
src/hooks/useConfuse.ts
+68
-0
src/layouts/components/Content.vue
+1
-1
src/pages/VocalCustomization/components/MyDigitalPerson.vue
+1
-1
src/pages/VocalCustomization/components/Record.vue
+1
-1
src/pages/createLive/components/scripts.vue
+145
-6
src/pages/createLive/hooks/scripts.ts
+301
-22
src/pages/createLive/index.vue
+14
-68
src/service/Common.ts
+13
-2
src/service/CreateLive.ts
+1
-0
src/store/modules/live.ts
+2
-2
src/utils/api/userApi.ts
+31
-0
src/utils/audio.ts
+159
-108
src/utils/request.ts
+1
-8
src/utils/tool.ts
+89
-47
src/utils/upLoadRequest.ts
+31
-0
No files found.
src/components/MultipleUpload/index.less
View file @
0d8701a5
...
@@ -91,6 +91,10 @@
...
@@ -91,6 +91,10 @@
.upload-success-box {
.upload-success-box {
.file-name {
.file-name {
margin-top: 4px;
margin-top: 4px;
white-space: nowrap;
max-width: 70px;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
.uploading-title {
.uploading-title {
...
...
src/components/MultipleUpload/index.tsx
View file @
0d8701a5
import
{
defineComponent
,
reactive
,
ref
,
watch
}
from
'vue'
;
import
{
defineComponent
,
onMounted
,
reactive
,
ref
,
watch
}
from
'vue'
;
import
'./index.less'
;
import
'./index.less'
;
import
{
Button
as
TButton
,
Upload
as
TUpload
,
Progress
as
TProgress
,
UploadFile
}
from
'tdesign-vue-next'
;
import
{
Button
as
TButton
,
Upload
as
TUpload
,
Progress
as
TProgress
,
UploadFile
}
from
'tdesign-vue-next'
;
import
{
getUserCookie
}
from
'@/utils/api/userApi'
;
import
{
getUserCookie
}
from
'@/utils/api/userApi'
;
...
@@ -12,6 +12,10 @@ import { alyOssUpload } from '@/utils/tool';
...
@@ -12,6 +12,10 @@ import { alyOssUpload } from '@/utils/tool';
export
default
defineComponent
({
export
default
defineComponent
({
props
:
{
props
:
{
modelValue
:
Array
,
modelValue
:
Array
,
value
:
{
type
:
Array
,
default
:
[],
},
audioTotolTime
:
{
audioTotolTime
:
{
type
:
[
Number
,
null
],
type
:
[
Number
,
null
],
default
:
null
,
default
:
null
,
...
@@ -53,6 +57,28 @@ export default defineComponent({
...
@@ -53,6 +57,28 @@ export default defineComponent({
},
100
);
},
100
);
};
};
// 更新父组件的list
const
submitList
=
(
list
:
any
[],
change
:
boolean
=
true
)
=>
{
if
(
list
.
length
)
{
Curfile
.
status
=
2
;
}
else
{
Curfile
.
status
=
0
;
}
emit
(
'update:modelValue'
,
list
);
// 再提交一份原始list
if
(
change
)
{
emit
(
'change'
,
list
,
fileList
.
value
);
}
};
onMounted
(()
=>
{
//
if
(
props
.
modelValue
.
length
)
{
Curfile
.
status
=
2
;
fileList
.
value
=
props
.
modelValue
;
}
});
// 是否需要计算文件总时长,音频或视频
// 是否需要计算文件总时长,音频或视频
const
computedTotalTime
=
()
=>
{
const
computedTotalTime
=
()
=>
{
return
typeof
props
.
audioTotolTime
===
'number'
;
return
typeof
props
.
audioTotolTime
===
'number'
;
...
@@ -145,8 +171,11 @@ export default defineComponent({
...
@@ -145,8 +171,11 @@ export default defineComponent({
totalSize
+=
item
.
file
.
size
;
totalSize
+=
item
.
file
.
size
;
}
}
}
}
// 更新绑定的值
submitList
(
list
,
false
);
emit
(
'update:modelValue'
,
list
);
if
(
list
.
length
===
fileList
.
value
.
length
)
{
// 全部上传成功才提交change事件
emit
(
'change'
,
list
,
fileList
.
value
);
}
// 文件总大小
// 文件总大小
emit
(
'update:totalSize'
,
totalSize
);
emit
(
'update:totalSize'
,
totalSize
);
};
};
...
@@ -185,7 +214,26 @@ export default defineComponent({
...
@@ -185,7 +214,26 @@ export default defineComponent({
// 状态成功
// 状态成功
if
(
!
v
.
length
)
{
if
(
!
v
.
length
)
{
Curfile
.
status
=
0
;
Curfile
.
status
=
0
;
fileList
.
value
=
[];
}
else
{
// // 要删除的下标
// let deleteIndex = [];
// // 数组对比,没有的就删除
// for (let i = 0; i < fileList.value.length; i++) {
// let item = fileList.value[i];
// let index = v.findIndex((url: string) => item == url);
// if (index === -1) {
// // 没找到,删除
// deleteIndex.push(i);
// }
// }
// console.log(deleteIndex);
// deleteIndex.forEach((index: any) => {
// fileList.value.splice(index, 1);
// });
}
}
}
else
{
Curfile
.
status
=
0
;
}
}
},
},
);
);
...
@@ -199,8 +247,7 @@ export default defineComponent({
...
@@ -199,8 +247,7 @@ export default defineComponent({
const
reStart
=
()
=>
{
const
reStart
=
()
=>
{
// 重置
// 重置
Curfile
.
status
=
0
;
Curfile
.
status
=
0
;
emit
(
'update:modelValue'
,
[]);
submitList
([]);
emit
(
'change'
,
[]);
};
};
const
requestSuccessMethod
=
async
(
file
:
UploadFile
|
UploadFile
[])
=>
{
const
requestSuccessMethod
=
async
(
file
:
UploadFile
|
UploadFile
[])
=>
{
return
ExtranetUpload
(
file
);
return
ExtranetUpload
(
file
);
...
@@ -227,19 +274,10 @@ export default defineComponent({
...
@@ -227,19 +274,10 @@ export default defineComponent({
totalTime
+=
item
.
time
;
totalTime
+=
item
.
time
;
}
}
});
});
emit
(
'update:modelValue'
,
list
);
submitList
(
list
);
emit
(
'update:audioTotolTime'
,
totalTime
);
emit
(
'update:audioTotolTime'
,
totalTime
);
};
};
watch
(
()
=>
props
.
modelValue
,
(
v
)
=>
{
if
(
!
v
)
{
Curfile
.
status
=
0
;
}
},
);
// 未上传
// 未上传
const
notUploadHtml
=
()
=>
{
const
notUploadHtml
=
()
=>
{
return
(
return
(
...
...
src/components/ScriptTemplate.vue
View file @
0d8701a5
...
@@ -6,9 +6,11 @@
...
@@ -6,9 +6,11 @@
}"
}"
>
>
<div
class=
"script-template-tool"
v-if=
"showTool"
>
<div
class=
"script-template-tool"
v-if=
"showTool"
>
<div
class=
"edit-box"
@
click=
"onEdit"
>
<template
v-if=
"showEdit"
>
<img
:src=
"imgs.edit"
alt=
""
/>
<div
class=
"edit-box"
@
click=
"onEdit"
>
</div>
<img
:src=
"imgs.edit"
alt=
""
/>
</div>
</
template
>
<div
class=
"delete-box"
@
click=
"onDelete"
>
<div
class=
"delete-box"
@
click=
"onDelete"
>
<img
:src=
"imgs.delete"
alt=
""
/>
<img
:src=
"imgs.delete"
alt=
""
/>
</div>
</div>
...
@@ -24,10 +26,12 @@ const props = withDefaults(
...
@@ -24,10 +26,12 @@ const props = withDefaults(
defineProps
<
{
defineProps
<
{
height
?:
string
;
height
?:
string
;
showTool
?:
boolean
;
showTool
?:
boolean
;
showEdit
?:
boolean
;
}
>
(),
}
>
(),
{
{
height
:
'175px'
,
height
:
'175px'
,
showTool
:
true
,
showTool
:
true
,
showEdit
:
true
,
},
},
);
);
const
emit
=
defineEmits
([
'edit'
,
'delete'
]);
const
emit
=
defineEmits
([
'edit'
,
'delete'
]);
...
@@ -59,6 +63,7 @@ const onDelete = () => {
...
@@ -59,6 +63,7 @@ const onDelete = () => {
right
:
12px
;
right
:
12px
;
top
:
12px
;
top
:
12px
;
.da();
.da();
z-index
:
100
;
.edit-box,
.edit-box,
.delete-box
{
.delete-box
{
cursor
:
pointer
;
cursor
:
pointer
;
...
...
src/components/loading.vue
View file @
0d8701a5
<
template
>
<
template
>
<div
<div
class=
"custom-loading-two"
class=
"custom-loading-two"
:class=
"
{
'custom-loading-two-mask': mask,
}"
:style="{
:style="{
position: position,
position: position,
}"
}"
...
@@ -22,9 +25,11 @@
...
@@ -22,9 +25,11 @@
const
props
=
withDefaults
(
const
props
=
withDefaults
(
defineProps
<
{
defineProps
<
{
position
?:
string
;
position
?:
string
;
mask
?:
boolean
;
}
>
(),
}
>
(),
{
{
position
:
'absolute'
,
position
:
'absolute'
,
mask
:
false
,
},
},
);
);
</
script
>
</
script
>
...
@@ -35,136 +40,144 @@ const props = withDefaults(
...
@@ -35,136 +40,144 @@ const props = withDefaults(
left
:
50%
;
left
:
50%
;
transform
:
translate
(
-50%
,
-50%
);
transform
:
translate
(
-50%
,
-50%
);
z-index
:
100
;
z-index
:
100
;
}
.loading,
.loading
,
.loading
>
div
{
.loading
>
div
{
position
:
relative
;
position
:
relative
;
box-sizing
:
border-box
;
box-sizing
:
border-box
;
}
}
.loading
{
.loading
{
display
:
block
;
display
:
block
;
font-size
:
0
;
font-size
:
0
;
color
:
#888fa1
;
color
:
#888fa1
;
}
}
.loading.la-dark
{
.loading.la-dark
{
color
:
#333
;
color
:
#333
;
}
}
.loading
>
div
{
.loading
>
div
{
display
:
inline-block
;
display
:
inline-block
;
float
:
none
;
float
:
none
;
background-color
:
currentColor
;
background-color
:
currentColor
;
border
:
0
solid
currentColor
;
border
:
0
solid
currentColor
;
}
}
.loading
{
.loading
{
width
:
58px
;
width
:
58px
;
height
:
58px
;
height
:
58px
;
}
}
.loading
>
div
{
.loading
>
div
{
position
:
absolute
;
position
:
absolute
;
width
:
4px
;
width
:
4px
;
height
:
14px
;
height
:
14px
;
margin
:
2px
;
margin
:
2px
;
margin-top
:
-5px
;
margin-top
:
-5px
;
margin-left
:
-1px
;
margin-left
:
-1px
;
border-radius
:
4px
;
border-radius
:
4px
;
animation
:
line-spin-clockwise-fade
1s
infinite
ease-in-out
;
animation
:
line-spin-clockwise-fade
1s
infinite
ease-in-out
;
}
}
.loading
>
div
:nth-child
(
1
)
{
.loading
>
div
:nth-child
(
1
)
{
top
:
15%
;
top
:
15%
;
left
:
50%
;
left
:
50%
;
transform
:
rotate
(
0deg
);
transform
:
rotate
(
0deg
);
animation-delay
:
-0.875s
;
animation-delay
:
-0.875s
;
}
}
.loading
>
div
:nth-child
(
2
)
{
.loading
>
div
:nth-child
(
2
)
{
top
:
25.2512626585%
;
top
:
25.2512626585%
;
left
:
74.7487373415%
;
left
:
74.7487373415%
;
transform
:
rotate
(
45deg
);
transform
:
rotate
(
45deg
);
animation-delay
:
-0.75s
;
animation-delay
:
-0.75s
;
}
}
.loading
>
div
:nth-child
(
3
)
{
.loading
>
div
:nth-child
(
3
)
{
top
:
50%
;
top
:
50%
;
left
:
85%
;
left
:
85%
;
transform
:
rotate
(
90deg
);
transform
:
rotate
(
90deg
);
animation-delay
:
-0.625s
;
animation-delay
:
-0.625s
;
}
}
.loading
>
div
:nth-child
(
4
)
{
.loading
>
div
:nth-child
(
4
)
{
top
:
74.7487373415%
;
top
:
74.7487373415%
;
left
:
74.7487373415%
;
left
:
74.7487373415%
;
transform
:
rotate
(
135deg
);
transform
:
rotate
(
135deg
);
animation-delay
:
-0.5s
;
animation-delay
:
-0.5s
;
}
}
.loading
>
div
:nth-child
(
5
)
{
.loading
>
div
:nth-child
(
5
)
{
top
:
84.9999999974%
;
top
:
84.9999999974%
;
left
:
50.0000000004%
;
left
:
50.0000000004%
;
transform
:
rotate
(
180deg
);
transform
:
rotate
(
180deg
);
animation-delay
:
-0.375s
;
animation-delay
:
-0.375s
;
}
}
.loading
>
div
:nth-child
(
6
)
{
.loading
>
div
:nth-child
(
6
)
{
top
:
74.7487369862%
;
top
:
74.7487369862%
;
left
:
25.2512627193%
;
left
:
25.2512627193%
;
transform
:
rotate
(
225deg
);
transform
:
rotate
(
225deg
);
animation-delay
:
-0.25s
;
animation-delay
:
-0.25s
;
}
}
.loading
>
div
:nth-child
(
7
)
{
.loading
>
div
:nth-child
(
7
)
{
top
:
49.9999806189%
;
top
:
49.9999806189%
;
left
:
15.0000039834%
;
left
:
15.0000039834%
;
transform
:
rotate
(
270deg
);
transform
:
rotate
(
270deg
);
animation-delay
:
-0.125s
;
animation-delay
:
-0.125s
;
}
}
.loading
>
div
:nth-child
(
8
)
{
.loading
>
div
:nth-child
(
8
)
{
top
:
25.2506949798%
;
top
:
25.2506949798%
;
left
:
25.2513989292%
;
left
:
25.2513989292%
;
transform
:
rotate
(
315deg
);
transform
:
rotate
(
315deg
);
animation-delay
:
0s
;
animation-delay
:
0s
;
}
}
.loading.la-sm
{
.loading.la-sm
{
width
:
16px
;
width
:
16px
;
height
:
16px
;
height
:
16px
;
}
}
.loading.la-sm
>
div
{
.loading.la-sm
>
div
{
width
:
1px
;
width
:
1px
;
height
:
4px
;
height
:
4px
;
margin-top
:
-2px
;
margin-top
:
-2px
;
margin-left
:
0
;
margin-left
:
0
;
}
}
.loading.la-2x
{
.loading.la-2x
{
width
:
64px
;
width
:
64px
;
height
:
64px
;
height
:
64px
;
}
}
.loading.la-2x
>
div
{
.loading.la-2x
>
div
{
width
:
4px
;
width
:
4px
;
height
:
20px
;
height
:
20px
;
margin-top
:
-10px
;
margin-top
:
-10px
;
margin-left
:
-2px
;
margin-left
:
-2px
;
}
}
.loading.la-3x
{
.loading.la-3x
{
width
:
96px
;
width
:
96px
;
height
:
96px
;
height
:
96px
;
}
}
.loading.la-3x
>
div
{
.loading.la-3x
>
div
{
width
:
6px
;
width
:
6px
;
height
:
30px
;
height
:
30px
;
margin-top
:
-15px
;
margin-top
:
-15px
;
margin-left
:
-3px
;
margin-left
:
-3px
;
}
}
.custom-loading-two-mask
{
width
:
100%
;
height
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
background-color
:
rgba
(
255
,
255
,
255
,
0.1
);
}
}
@keyframes
line-spin-clockwise-fade
{
@keyframes
line-spin-clockwise-fade
{
...
...
src/components/upload/index.tsx
View file @
0d8701a5
import
{
defineComponent
,
reactive
,
ref
,
watch
}
from
'vue'
;
import
{
defineComponent
,
onMounted
,
reactive
,
ref
,
watch
}
from
'vue'
;
import
'./index.less'
;
import
'./index.less'
;
import
UploadTip
from
'@/assets/svg/upload/uploadTip2.svg'
;
import
UploadTip
from
'@/assets/svg/upload/uploadTip2.svg'
;
import
{
import
{
...
@@ -36,22 +36,34 @@ export default defineComponent({
...
@@ -36,22 +36,34 @@ export default defineComponent({
type
:
String
,
type
:
String
,
default
:
''
,
default
:
''
,
},
},
id
:
{
type
:
[
Number
,
null
],
default
:
0
,
},
showOldName
:
{
type
:
Boolean
,
default
:
false
,
},
oldName
:
{
type
:
String
,
default
:
''
,
},
},
},
emits
:
[
'update:modelValue'
,
'change'
,
'file'
],
emits
:
[
'update:modelValue'
,
'change'
,
'file'
],
setup
(
props
,
{
emit
})
{
setup
(
props
,
{
emit
})
{
const
files
=
ref
([]);
const
files
=
ref
([]);
// 文件地址
// 文件地址
const
Curfile
=
reactive
({
const
Curfile
=
reactive
({
url
:
''
,
url
:
props
.
modelValue
,
status
:
0
,
status
:
0
,
// 当前上传模块提交的状态
oldName
:
''
,
uploadStatus
:
false
,
});
});
const
actionUrl
=
ref
(
''
);
const
actionUrl
=
ref
(
''
);
// 上传进度条
// 上传进度条
const
percentage
=
ref
(
0
);
const
percentage
=
ref
(
0
);
// 定时器
// 定时器
let
percentageInterval
:
any
=
null
;
let
percentageInterval
:
any
=
null
;
// 上传进度定时器
// 上传进度定时器
const
openpercentage
=
()
=>
{
const
openpercentage
=
()
=>
{
// 开启一个定时器,模拟上传进度
// 开启一个定时器,模拟上传进度
...
@@ -63,6 +75,27 @@ export default defineComponent({
...
@@ -63,6 +75,27 @@ export default defineComponent({
percentage
.
value
+=
1
;
percentage
.
value
+=
1
;
},
100
);
},
100
);
};
};
// 修改上传状态
const
changeUploadStatus
=
(
type
:
'success'
|
'wait'
|
'progress'
=
'success'
)
=>
{
if
(
type
==
'success'
)
{
Curfile
.
url
=
props
.
modelValue
;
Curfile
.
status
=
2
;
}
else
if
(
type
==
'progress'
)
{
Curfile
.
status
=
1
;
}
else
{
Curfile
.
url
=
''
;
Curfile
.
status
=
0
;
files
.
value
=
[];
}
};
// 提交url
const
submitUrl
=
(
url
:
string
)
=>
{
emit
(
'update:modelValue'
,
url
);
emit
(
'change'
,
url
,
props
.
id
,
Curfile
.
oldName
);
};
// 获取文件尺寸
// 获取文件尺寸
const
getFileSize
=
async
(
file
:
any
)
=>
{
const
getFileSize
=
async
(
file
:
any
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
...
@@ -119,21 +152,16 @@ export default defineComponent({
...
@@ -119,21 +152,16 @@ export default defineComponent({
MessagePlugin
.
success
(
'上传成功'
);
MessagePlugin
.
success
(
'上传成功'
);
// 将将完整url传给父组件
// 将将完整url传给父组件
Curfile
.
url
=
url
;
Curfile
.
url
=
url
;
// 成功2
submitUrl
(
Curfile
.
url
);
Curfile
.
status
=
2
;
changeUploadStatus
(
'success'
);
emit
(
'update:modelValue'
,
Curfile
.
url
);
emit
(
'change'
,
Curfile
.
url
);
};
};
// 上传失败回调
// 上传失败回调
const
UploadErrorCallback
=
()
=>
{
const
UploadErrorCallback
=
()
=>
{
// 关闭定时器
// 关闭定时器
window
.
clearInterval
(
percentageInterval
);
window
.
clearInterval
(
percentageInterval
);
Curfile
.
url
=
''
;
submitUrl
(
Curfile
.
url
);
// 失败0
Curfile
.
status
=
0
;
emit
(
'update:modelValue'
,
Curfile
.
url
);
emit
(
'change'
,
Curfile
.
url
);
MessagePlugin
.
warning
(
'上传失败'
);
MessagePlugin
.
warning
(
'上传失败'
);
changeUploadStatus
(
'wait'
);
};
};
// 外网上传-func
// 外网上传-func
const
ExtranetUpload
=
(
file
:
any
)
=>
{
const
ExtranetUpload
=
(
file
:
any
)
=>
{
...
@@ -141,6 +169,9 @@ export default defineComponent({
...
@@ -141,6 +169,9 @@ export default defineComponent({
// 上传中状态
// 上传中状态
Curfile
.
status
=
1
;
Curfile
.
status
=
1
;
return
new
Promise
<
RequestMethodResponse
>
((
resolve
)
=>
{
return
new
Promise
<
RequestMethodResponse
>
((
resolve
)
=>
{
if
(
props
.
showOldName
)
{
Curfile
.
oldName
=
file
.
name
;
}
const
uuid
=
v4
();
const
uuid
=
v4
();
let
url
=
''
;
let
url
=
''
;
const
{
config
}
=
props
;
const
{
config
}
=
props
;
...
@@ -172,15 +203,12 @@ export default defineComponent({
...
@@ -172,15 +203,12 @@ export default defineComponent({
// 外网url
// 外网url
const
url
=
config
.
domain
+
config
.
dir
+
uuid
+
`.
${
fileName
}
`
;
const
url
=
config
.
domain
+
config
.
dir
+
uuid
+
`.
${
fileName
}
`
;
UploadSuccessCallback
(
uuid
,
url
);
UploadSuccessCallback
(
uuid
,
url
);
//
Curfile
.
uploadStatus
=
true
;
resolve
({
resolve
({
status
:
'success'
,
status
:
'success'
,
response
:
{
url
:
Curfile
.
url
},
response
:
{
url
:
Curfile
.
url
},
});
});
}
else
{
}
else
{
UploadErrorCallback
();
UploadErrorCallback
();
Curfile
.
uploadStatus
=
false
;
}
}
})
})
.
catch
((
e
)
=>
{
.
catch
((
e
)
=>
{
...
@@ -190,14 +218,24 @@ export default defineComponent({
...
@@ -190,14 +218,24 @@ export default defineComponent({
});
});
};
};
onMounted
(()
=>
{
// 根据props的value判断上传状态
if
(
props
.
modelValue
)
{
changeUploadStatus
(
'success'
);
}
else
{
changeUploadStatus
(
'wait'
);
}
});
watch
(
watch
(
()
=>
props
.
modelValue
,
()
=>
props
.
modelValue
,
(
v
)
=>
{
(
v
)
=>
{
if
(
v
)
{
if
(
v
)
{
// 状态成功
// 状态成功
Curfile
.
url
=
v
;
Curfile
.
url
=
v
;
// 成功2
changeUploadStatus
(
'success'
);
Curfile
.
status
=
2
;
}
else
{
changeUploadStatus
(
'wait'
);
}
}
},
},
);
);
...
@@ -205,11 +243,8 @@ export default defineComponent({
...
@@ -205,11 +243,8 @@ export default defineComponent({
const
reStart
=
()
=>
{
const
reStart
=
()
=>
{
// 重置
// 重置
files
.
value
=
[];
files
.
value
=
[];
Curfile
.
url
=
''
;
submitUrl
(
''
);
Curfile
.
status
=
0
;
changeUploadStatus
(
'wait'
);
Curfile
.
uploadStatus
=
false
;
emit
(
'update:modelValue'
,
''
);
emit
(
'change'
,
''
);
};
};
const
requestSuccessMethod
=
async
(
file
:
UploadFile
|
UploadFile
[])
=>
{
const
requestSuccessMethod
=
async
(
file
:
UploadFile
|
UploadFile
[])
=>
{
return
ExtranetUpload
(
file
);
return
ExtranetUpload
(
file
);
...
@@ -263,7 +298,7 @@ export default defineComponent({
...
@@ -263,7 +298,7 @@ export default defineComponent({
<
div
class=
"icon"
>
<
div
class=
"icon"
>
{
props
.
uploadInfo
.
successIcon
?
<
img
src=
{
props
.
uploadInfo
.
successIcon
}
alt=
""
/>
:
''
}
{
props
.
uploadInfo
.
successIcon
?
<
img
src=
{
props
.
uploadInfo
.
successIcon
}
alt=
""
/>
:
''
}
</
div
>
</
div
>
<
div
class=
"file-name"
></
div
>
<
div
class=
"file-name"
>
{
Curfile
.
oldName
?
Curfile
.
oldName
:
props
.
oldName
}
</
div
>
<
Button
class=
"reset-submit"
theme=
"green"
onClick=
{
reStart
}
>
<
Button
class=
"reset-submit"
theme=
"green"
onClick=
{
reStart
}
>
{
props
.
uploadInfo
.
successButtonLabel
??
'重新上传'
}
{
props
.
uploadInfo
.
successButtonLabel
??
'重新上传'
}
</
Button
>
</
Button
>
...
@@ -282,18 +317,20 @@ export default defineComponent({
...
@@ -282,18 +317,20 @@ export default defineComponent({
return
UploadSuccess
();
return
UploadSuccess
();
}
}
};
};
watch
(
()
=>
props
.
modelValue
,
(
v
)
=>
{
if
(
!
v
)
{
Curfile
.
status
=
0
;
}
},
);
return
()
=>
(
return
()
=>
(
<
div
class=
"custom-real-upload"
>
<
div
class=
"custom-real-upload"
>
<
div
class=
"real-upload-content"
>
<
div
class=
"real-upload-content"
>
<
div
class=
"custom-real-upload-component"
>
{
currentUploadStatus
()
}
</
div
>
{
/* <div class="custom-real-upload-component">{currentUploadStatus()}</div> */
}
<
div
class=
"custom-real-upload-component"
v
-
show=
{
Curfile
.
status
==
0
}
>
{
notUploadHtml
()
}
</
div
>
<
div
class=
"custom-real-upload-component"
v
-
show=
{
Curfile
.
status
==
1
}
>
{
UploadingHtml
()
}
</
div
>
<
div
class=
"custom-real-upload-component"
v
-
show=
{
Curfile
.
status
==
2
}
>
{
UploadSuccess
()
}
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
);
);
...
...
src/hooks/useConfuse.ts
0 → 100644
View file @
0d8701a5
import
{
show_message
}
from
'@/utils/tool'
;
import
{
liveContentRegenerate
,
liveContentRegenerateCallback
}
from
'@/utils/api/userApi'
;
import
{
onBeforeUnmount
,
ref
}
from
'vue'
;
export
default
function
()
{
// 洗稿次数
const
confuseNum
=
1
;
// 当前洗稿次数
const
currentConfuseNum
=
ref
(
0
);
// 定时器
const
confuseInterval
=
ref
(
null
);
// 洗稿回调列表
const
confuseList
=
ref
([]);
// 洗稿id
const
currentConfuseId
=
ref
(
''
);
const
openConfuseInterval
=
()
=>
{
confuseInterval
.
value
=
window
.
setTimeout
(()
=>
{
currentStartConfuseBack
(
currentConfuseId
.
value
);
},
3000
);
};
// 关闭定时器
const
closeConfuseInterval
=
()
=>
{
window
.
clearInterval
(
confuseInterval
.
value
);
clearInterval
(
confuseInterval
.
value
);
confuseInterval
.
value
=
null
;
};
// 洗稿提交
const
currentStartConfuse
=
async
(
data
:
any
)
=>
{
try
{
//
let
res
:
any
=
await
liveContentRegenerate
(
data
);
if
(
res
.
code
==
0
)
{
// 打开定时器
openConfuseInterval
();
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
// 获取洗稿回调
const
currentStartConfuseBack
=
async
(
id
:
any
)
=>
{
try
{
let
res
:
any
=
await
liveContentRegenerateCallback
({
task_id
:
id
,
});
if
(
res
.
code
==
0
&&
res
.
data
.
length
)
{
closeConfuseInterval
();
confuseList
.
value
=
res
.
data
;
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
onBeforeUnmount
(()
=>
{
closeConfuseInterval
();
});
return
{
confuseList
,
currentConfuseId
,
currentStartConfuse
,
};
}
src/layouts/components/Content.vue
View file @
0d8701a5
...
@@ -20,7 +20,7 @@ import { useRoute } from 'vue-router';
...
@@ -20,7 +20,7 @@ import { useRoute } from 'vue-router';
const
route
=
useRoute
();
const
route
=
useRoute
();
const
getKey
=
()
=>
{
const
getKey
=
()
=>
{
return
route
.
fullPath
;
return
route
.
name
;
};
};
</
script
>
</
script
>
...
...
src/pages/VocalCustomization/components/MyDigitalPerson.vue
View file @
0d8701a5
...
@@ -81,7 +81,7 @@ const confirm = () => {
...
@@ -81,7 +81,7 @@ const confirm = () => {
const
getList
=
async
()
=>
{
const
getList
=
async
()
=>
{
try
{
try
{
loading
.
value
=
true
;
loading
.
value
=
true
;
let
res
:
any
=
await
getTonesList
();
let
res
:
any
=
await
getTonesList
(
false
);
res
.
soundColor
.
forEach
((
item
:
any
)
=>
{
res
.
soundColor
.
forEach
((
item
:
any
)
=>
{
item
.
play_status
=
false
;
item
.
play_status
=
false
;
});
});
...
...
src/pages/VocalCustomization/components/Record.vue
View file @
0d8701a5
...
@@ -42,7 +42,7 @@ const loading = ref(false);
...
@@ -42,7 +42,7 @@ const loading = ref(false);
const
getList
=
async
()
=>
{
const
getList
=
async
()
=>
{
try
{
try
{
loading
.
value
=
true
;
loading
.
value
=
true
;
let
res
:
any
=
await
getTonesList
();
let
res
:
any
=
await
getTonesList
(
false
);
res
.
soundColor
.
forEach
((
item
:
any
)
=>
{
res
.
soundColor
.
forEach
((
item
:
any
)
=>
{
item
.
play_status
=
false
;
item
.
play_status
=
false
;
});
});
...
...
src/pages/createLive/components/scripts.vue
View file @
0d8701a5
...
@@ -3,6 +3,30 @@
...
@@ -3,6 +3,30 @@
<div
class=
"all-select"
>
<div
class=
"all-select"
>
<Select
:options=
"scriptTypeList"
v-model=
"currentOption"
@
change=
"scriptTypeChange"
></Select>
<Select
:options=
"scriptTypeList"
v-model=
"currentOption"
@
change=
"scriptTypeChange"
></Select>
<CheckBox
v-model=
"isDisorganize"
@
change=
"checkboxChange"
>
GPT洗稿
</CheckBox>
<CheckBox
v-model=
"isDisorganize"
@
change=
"checkboxChange"
>
GPT洗稿
</CheckBox>
<template
v-if=
"isDev()"
>
<Button
@
click=
"
doCopy(`
大家好!欢迎来到今天的直播!我是你们的主持人,今天我将为大家带来一场精彩的直播节目。在这里,我们将分享一些有趣的内容,并回答你们的问题。
首先,让我们来聊一聊今天的主题。今天我们将重点聚焦在XX领域(根据直播主题填写),这是一个非常热门、有趣且前沿的领域。我们将了解最新的发展动态、分享一些实用的技巧,并回答你们提出的问题。
对于新加入直播的朋友,特别欢迎你们!如果你们有任何问题或者想要了解更多关于XX的信息,请随时在评论区留言,我将尽力回答你们的问题。
在这里,我们鼓励大家积极互动。请大家在评论区留下你们的想法、观点和问题。我会选择一些与主题相关的问题进行回答,在回答问题时我会尽量深入浅出,以确保每个人都能够理解。
也请大家相互尊重,遵守礼貌。如果有令人不舒服的言论或者不适当的内容,请及时举报,我们会及时处理。
接下来,让我们一起进入今天的正题吧!不管你是刚开始接触XX,还是已经有一定了解,请相信你们在这里能够获得更多知识、更多的收获。
再次感谢大家的到来和支持,让我们一起度过这个精彩的时刻!祝愿大家在本次直播中有所收获,也希望大家能够在评论区互相交流,共同进步。
谢谢大家!现在,让我们开始今天的直播吧!
`)
"
>
测试文案
</Button
>
</
template
>
<div
<div
class=
"right-chose-tones"
class=
"right-chose-tones"
:style=
"{
:style=
"{
...
@@ -119,8 +143,38 @@
...
@@ -119,8 +143,38 @@
<Textarea
v-model=
"textareaValue"
@
change=
"textareaChange"
></Textarea>
<Textarea
v-model=
"textareaValue"
@
change=
"textareaChange"
></Textarea>
</
template
>
</
template
>
</div>
</div>
<div
class=
"script-setting-upload flex1"
v-show=
"currentOption === scriptTypePhonetics"
>
<div
class=
"script-setting-upload flex1 narrow-scrollbar"
v-show=
"currentOption === scriptTypePhonetics"
>
<CustomUpload
v-model=
"mp3Url"
:uploadInfo=
"uploadInfo"
:config=
"ossConfig"
@
change=
"uploadChange"
></CustomUpload>
<!-- edit -->
<
template
v-for=
"(item, index) in audioScriptList"
:key=
"index"
>
<ScriptTemplate
height=
"250px"
:showEdit=
"false"
@
edit=
"uploadAudioEdit(index)"
@
delete=
"onDeleteAudio(index)"
>
<div
class=
"script-template-body__audio-add"
>
<MultipleUpload
v-model=
"item.data"
:config=
"ossConfig"
label=
"选择音频"
@
change=
"uploadEdit"
></MultipleUpload>
</div>
</ScriptTemplate>
</
template
>
<!-- create -->
<ScriptTemplate
:showTool=
"false"
height=
"250px"
>
<div
class=
"script-template-body__audio-add"
>
<MultipleUpload
v-model=
"mp3UrlList"
:config=
"ossConfig"
label=
"选择音频"
@
change=
"createUploadFile"
></MultipleUpload>
<!-- <CustomUpload
v-model="mp3Url"
:showOldName="true"
:uploadInfo="uploadInfo"
:config="ossConfig"
@change="createUploadFile"
></CustomUpload> -->
</div>
</ScriptTemplate>
</div>
</div>
<TextScriptDialog
v-model=
"textScriptVisible"
@
submit=
"textScriptSubmit"
:info=
"editTextInfo"
></TextScriptDialog>
<TextScriptDialog
v-model=
"textScriptVisible"
@
submit=
"textScriptSubmit"
:info=
"editTextInfo"
></TextScriptDialog>
<ConfirmDialog
<ConfirmDialog
...
@@ -128,11 +182,18 @@
...
@@ -128,11 +182,18 @@
title=
"确定要删除该声音吗?"
title=
"确定要删除该声音吗?"
@
confirm=
"confirmDeleteText"
@
confirm=
"confirmDeleteText"
></ConfirmDialog>
></ConfirmDialog>
<ConfirmDialog
v-model=
"confirmDeleteAudioVisible"
title=
"确定要删除该声音吗?"
@
confirm=
"confirmDeleteAudio"
></ConfirmDialog>
</div>
</div>
</template>
</template>
<
script
lang=
"tsx"
setup
>
<
script
lang=
"tsx"
setup
>
import
{
computed
,
onMounted
,
reactive
,
ref
,
watch
}
from
'vue'
;
import
{
computed
,
onMounted
,
reactive
,
ref
,
watch
}
from
'vue'
;
import
Button
from
'@/components/Button.vue'
;
import
MultipleUpload
from
'@/components/MultipleUpload'
;
import
CheckBox
from
'@/components/CheckBox.vue'
;
import
CheckBox
from
'@/components/CheckBox.vue'
;
import
ConfirmDialog
from
'@/components/ConfirmDialog.vue'
;
import
ConfirmDialog
from
'@/components/ConfirmDialog.vue'
;
import
TextScriptDialog
from
'./TextScriptDialog.vue'
;
import
TextScriptDialog
from
'./TextScriptDialog.vue'
;
...
@@ -148,6 +209,8 @@ import { getUploadConfig, getTonesList } from '@/service/Common';
...
@@ -148,6 +209,8 @@ import { getUploadConfig, getTonesList } from '@/service/Common';
import
{
v4
}
from
'uuid'
;
import
{
v4
}
from
'uuid'
;
import
{
useStore
}
from
'vuex'
;
import
{
useStore
}
from
'vuex'
;
import
{
useRoute
}
from
'vue-router'
;
import
{
useRoute
}
from
'vue-router'
;
import
useCopy
from
'@/hooks/useCopy'
;
const
{
doCopy
}
=
useCopy
();
const
[
commitInfo
]
=
useLiveInfoSubmit
();
const
[
commitInfo
]
=
useLiveInfoSubmit
();
const
props
=
withDefaults
(
const
props
=
withDefaults
(
...
@@ -171,6 +234,8 @@ const createLiveInfo = computed(() => store.getters['live/getLiveInfo']);
...
@@ -171,6 +234,8 @@ const createLiveInfo = computed(() => store.getters['live/getLiveInfo']);
// 文本脚本列表
// 文本脚本列表
const
textScriptList
=
ref
([]);
const
textScriptList
=
ref
([]);
// 音频脚本列表
const
audioScriptList
=
ref
([]);
// 文本脚本el
// 文本脚本el
const
scriptSettingText
=
ref
<
HTMLDivElement
>
();
const
scriptSettingText
=
ref
<
HTMLDivElement
>
();
// 文本编辑时的行信息
// 文本编辑时的行信息
...
@@ -179,9 +244,16 @@ const editTextInfo = ref({});
...
@@ -179,9 +244,16 @@ const editTextInfo = ref({});
const
deleteTextId
=
ref
();
const
deleteTextId
=
ref
();
// 确认删除弹窗
// 确认删除弹窗
const
confirmDeleteVisible
=
ref
(
false
);
const
confirmDeleteVisible
=
ref
(
false
);
// 确认删除音频弹窗
const
confirmDeleteAudioVisible
=
ref
(
false
);
// 要删除的音频下标
const
deleteAudioIndex
=
ref
();
// 是否gpt洗稿
// 是否gpt洗稿
const
isDisorganize
=
ref
(
false
);
const
isDisorganize
=
ref
(
false
);
// upload组件的ref
const
uploadRef
=
ref
();
const
lists
=
reactive
({
const
lists
=
reactive
({
tones
:
[],
tones
:
[],
soundColor
:
[],
soundColor
:
[],
...
@@ -207,6 +279,8 @@ const textScriptVisible = ref(false);
...
@@ -207,6 +279,8 @@ const textScriptVisible = ref(false);
const
ossConfig
=
ref
({});
const
ossConfig
=
ref
({});
// 上传的音频文件链接
// 上传的音频文件链接
const
mp3Url
=
ref
(
''
);
const
mp3Url
=
ref
(
''
);
// 多选文件列表
const
mp3UrlList
=
ref
([]);
const
uploadInfo
=
{
const
uploadInfo
=
{
label1
:
'选择音频'
,
label1
:
'选择音频'
,
label2
:
'或拖音频到此处上传'
,
label2
:
'或拖音频到此处上传'
,
...
@@ -225,6 +299,51 @@ const textareaValue = ref('');
...
@@ -225,6 +299,51 @@ const textareaValue = ref('');
const
currentOption
=
ref
(
scriptTypeText
);
const
currentOption
=
ref
(
scriptTypeText
);
// 音频脚本上传后
const
createUploadFile
=
(
list
:
any
[],
oldList
:
any
[])
=>
{
// 添加到数组中
audioScriptList
.
value
.
push
({
data
:
JSON
.
parse
(
JSON
.
stringify
(
oldList
)),
});
// 提交到store
uploadChange
();
setTimeout
(()
=>
{
// 清空当前url
mp3UrlList
.
value
=
[];
},
0
);
};
// 音频脚本编辑后
const
uploadEdit
=
(
url
:
string
,
id
:
number
)
=>
{
uploadChange
();
};
const
confirmDeleteAudio
=
()
=>
{
audioScriptList
.
value
.
splice
(
deleteAudioIndex
.
value
,
1
);
uploadChange
();
};
// 删除音频
const
onDeleteAudio
=
(
index
:
number
)
=>
{
confirmDeleteAudioVisible
.
value
=
true
;
deleteAudioIndex
.
value
=
index
;
};
// 编辑按钮 音频脚本
const
uploadAudioEdit
=
(
index
:
number
)
=>
{
// 调用对应的上传事件
if
(
uploadRef
.
value
&&
uploadRef
.
value
.
length
)
{
let
element
:
HTMLDivElement
=
uploadRef
.
value
[
index
].
$el
;
if
(
element
)
{
// 找到上传元素
let
clickElement
=
element
.
getElementsByClassName
(
'custom-upload-click-box'
);
if
(
clickElement
&&
clickElement
.
length
)
{
clickElement
[
0
].
click
();
}
}
}
};
// 洗稿checkbox变化
// 洗稿checkbox变化
const
checkboxChange
=
(
value
:
boolean
)
=>
{
const
checkboxChange
=
(
value
:
boolean
)
=>
{
commitInfo
({
commitInfo
({
...
@@ -304,7 +423,6 @@ const updateTonesInfo = (tone_id: any, phonetic_timbres_id: any) => {
...
@@ -304,7 +423,6 @@ const updateTonesInfo = (tone_id: any, phonetic_timbres_id: any) => {
};
};
const
updateInfo
=
(
info
:
any
)
=>
{
const
updateInfo
=
(
info
:
any
)
=>
{
console
.
log
(
info
);
let
type
=
''
;
let
type
=
''
;
let
type_content
=
''
;
let
type_content
=
''
;
let
phonetic_timbres_id
=
''
;
let
phonetic_timbres_id
=
''
;
...
@@ -379,9 +497,9 @@ const openSoundColor = () => {
...
@@ -379,9 +497,9 @@ const openSoundColor = () => {
};
};
// 音频文件提交
// 音频文件提交
const
uploadChange
=
(
value
:
string
)
=>
{
const
uploadChange
=
()
=>
{
commitInfo
({
commitInfo
({
[
createLiveKeys
.
phoneticsFile
]:
value
,
[
createLiveKeys
.
audioScriptList
]:
audioScriptList
.
value
,
});
});
};
};
...
@@ -648,8 +766,29 @@ onMounted(async () => {
...
@@ -648,8 +766,29 @@ onMounted(async () => {
}
}
}
}
.script-setting-upload
{
.script-setting-upload
{
.custom-real-upload
{
overflow-y
:
auto
;
overflow-x
:
hidden
;
.script-template-body__audio-add
{
height
:
100%
;
height
:
100%
;
.custom-real-upload
{
height
:
100%
;
background
:
transparent
;
.custom-UploadSuccess-stauts
{
.icon
{
img
{
width
:
40px
;
height
:
40px
;
}
}
.file-name
{
margin-bottom
:
12px
;
}
}
}
.custom-multiple-upload
{
height
:
100%
;
background
:
transparent
;
}
}
}
}
}
}
}
...
...
src/pages/createLive/hooks/scripts.ts
View file @
0d8701a5
import
{
computed
,
onBeforeUnmount
,
ref
}
from
'vue'
;
import
{
computed
,
onBeforeUnmount
,
ref
,
watch
}
from
'vue'
;
import
{
useStore
}
from
'vuex'
;
import
{
useStore
}
from
'vuex'
;
import
{
createLiveKeys
}
from
'@/service/CreateLive'
;
import
{
createLiveKeys
,
scriptTypeText
}
from
'@/service/CreateLive'
;
import
{
getLiveTtsCallback
}
from
'@/utils/api/userApi'
;
import
{
getLiveTtsCallback
,
createLiveTask
,
liveTts
}
from
'@/utils/api/userApi'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
{
alyOssUpload
,
show_message
}
from
'@/utils/tool'
;
import
{
audioMerge
,
splitAudio
}
from
'@/utils/audio'
;
import
{
audioMerge
,
splitAudio
}
from
'@/utils/audio'
;
import
{
useLiveInfoSubmit
}
from
'@/hooks/useStoreCommit'
;
import
{
getUploadConfig
}
from
'@/service/Common'
;
import
{
v4
}
from
'uuid'
;
import
{
useRoute
,
useRouter
}
from
'vue-router'
;
import
routerConfig
from
'@/router/tool'
;
import
useConfuse
from
'@/hooks/useConfuse'
;
// 轮询处理文本脚本语音生成回调
// 轮询处理文本脚本语音生成回调
export
const
processTextCallback
=
()
=>
{
export
const
processTextCallback
=
()
=>
{
const
[
commitInfo
]
=
useLiveInfoSubmit
();
const
{
currentConfuseId
,
confuseList
,
currentStartConfuse
}
=
useConfuse
();
const
store
=
useStore
();
const
store
=
useStore
();
const
router
=
useRouter
();
const
route
=
useRoute
();
//
const
loading
=
ref
(
false
);
const
initNum
=
ref
(
0
);
// 当前模块
const
currentSetp
=
ref
(
1
);
// 文字转音频轮询
const
interval
=
ref
(
null
);
const
interval
=
ref
(
null
);
const
createLiveInfo
=
computed
(()
=>
store
.
getters
[
'live/getLiveInfo'
]);
const
createLiveInfo
=
computed
(()
=>
store
.
getters
[
'live/getLiveInfo'
]);
const
getTaskStatus
=
async
()
=>
{
const
liveName
=
computed
(()
=>
store
.
getters
[
'live/getName'
]);
const
alyList
=
ref
([]);
const
submitAudioTask
=
async
(
list
:
any
[])
=>
{
let
item
=
createLiveInfo
.
value
;
for
(
let
i
=
0
;
i
<
list
.
length
;
i
++
)
{
let
params
=
{
// 音色
phonetic_timbres_id
:
item
[
createLiveKeys
.
textSoundColor
],
// 音调
tone_id
:
item
[
createLiveKeys
.
textTones
],
content
:
list
[
i
].
content
,
uuid
:
getTaskId
(
true
),
};
// 生成音频
let
res
:
any
=
await
liveTts
(
params
);
if
(
res
.
code
==
0
)
{
// 开始轮询
openInterval
(
true
);
}
}
};
// 洗稿列表变化
watch
(
()
=>
confuseList
.
value
,
(
v
)
=>
{
if
(
v
.
length
)
{
// 提交生成音频任务
submitAudioTask
(
v
);
}
},
);
// 提交时过滤必要的字段
const
filterFiled
=
()
=>
{
let
item
=
createLiveInfo
.
value
;
// 过滤必须字段
let
params
:
any
=
{};
params
.
name
=
liveName
.
value
;
// 数字人id
params
.
digital_man_id
=
item
[
createLiveKeys
.
id
];
// 是否洗稿
params
.
is_disorganize
=
item
[
createLiveKeys
.
isDisorganize
];
// 脚本类型
params
.
type
=
item
[
createLiveKeys
.
scriptType
];
// 脚本内容
if
(
item
[
createLiveKeys
.
scriptType
]
==
scriptTypeText
)
{
// 文本
params
.
type_content
=
item
[
createLiveKeys
.
textScriptValue
];
// 音色id
params
.
phonetic_timbres_id
=
item
[
createLiveKeys
.
textSoundColor
];
// 文本内容
params
.
content
=
item
[
createLiveKeys
.
textScriptList
].
map
((
item
:
any
)
=>
{
return
{
title
:
item
.
title
,
content
:
item
.
content
,
};
});
}
else
{
// 音频
params
.
type_content
=
item
[
createLiveKeys
.
audioScriptList
].
map
((
item
:
any
)
=>
{
let
list
=
[];
item
.
data
.
forEach
((
it
:
any
)
=>
{
let
params
=
{
content
:
''
,
};
if
(
typeof
it
===
'string'
)
{
params
.
content
=
it
;
}
else
{
params
.
content
=
it
.
url
;
}
list
.
push
(
params
);
});
return
list
;
});
// 音色id
params
.
phonetic_timbres_id
=
item
[
createLiveKeys
.
phoneticsSoundColor
];
}
// 音调id
params
.
tone_id
=
item
[
createLiveKeys
.
textTones
];
// 互动库
params
.
interaction_ids
=
item
[
createLiveKeys
.
interactiveLibrary
];
return
params
;
};
// 提交后的初始化操作
const
initCreateStore
=
()
=>
{
// 清空name
store
.
commit
(
'live/setName'
,
''
);
// 清空edit
store
.
commit
(
'live/clearEditLive'
);
// 清空createLive
store
.
commit
(
'live/clearCreateLive'
);
store
.
commit
(
'live/initLiveInfo'
);
};
const
backHome
=
()
=>
{
router
.
push
({
path
:
routerConfig
.
home
.
path
,
name
:
routerConfig
.
home
.
name
,
});
};
// 提交后台
const
submit
=
async
()
=>
{
try
{
let
res
:
any
=
await
createLiveTask
(
filterFiled
());
if
(
res
.
code
==
0
)
{
return
true
;
}
return
false
;
}
catch
(
e
)
{
console
.
log
(
e
);
return
false
;
}
};
// 任务提交成功后的回调
const
submitSuccessed
=
(
message
:
string
=
'创建成功'
)
=>
{
show_message
(
message
,
'success'
);
// 回首页
backHome
();
initCreateStore
();
// 通知三个模块清空自己的内容
initNum
.
value
+=
1
;
// 回到模块1
currentSetp
.
value
=
1
;
};
// 获取文件名
const
getFileName
=
(
file
:
any
)
=>
{
if
(
!
file
.
name
)
{
return
v4
();
}
return
file
.
name
;
};
// 洗稿
const
startConfuse
=
async
()
=>
{
currentConfuseId
.
value
=
v4
();
let
content
=
''
;
// 获取所有文章
createLiveInfo
.
value
[
createLiveKeys
.
textScriptList
].
forEach
((
item
:
any
)
=>
{
content
+=
item
.
content
;
});
// 提交洗稿任务
currentStartConfuse
({
content
:
content
,
task_id
:
currentConfuseId
.
value
,
id
:
route
.
query
.
id
,
});
};
// 阿里云上传成功回调
const
uploadSuccess
=
(
name
:
string
,
url
:
string
)
=>
{
alyList
.
value
.
push
({
content
:
url
,
});
};
// 循环上传阿里云
const
uploadToAly
=
async
(
fileList
:
File
[])
=>
{
// 获取阿里云配置
let
config
=
await
getUploadConfig
();
for
(
let
i
=
0
;
i
<
fileList
.
length
;
i
++
)
{
let
file
=
fileList
[
i
];
let
retryNum
=
0
;
while
(
true
)
{
let
uploadStatus
=
null
;
if
(
retryNum
>=
5
)
{
console
.
log
(
'音频块已经重试5次,跳过'
);
break
;
}
if
(
retryNum
)
{
config
=
await
getUploadConfig
();
}
try
{
// 上传阿里云
uploadStatus
=
await
alyOssUpload
(
config
,
file
,
uploadSuccess
,
()
=>
false
,
getFileName
(
file
));
}
catch
(
e
)
{
if
(
e
&&
e
.
status
==
'error'
)
{
// 重新上传
console
.
log
(
'重新上传'
);
retryNum
+=
1
;
continue
;
}
}
break
;
}
}
// 上传完毕
return
alyList
.
value
;
};
// 音频合并切割
const
audioStart
=
async
(
list
:
any
[],
dimensional
:
boolean
=
true
)
=>
{
let
file
=
await
audioMerge
(
list
);
if
(
file
)
{
// 开始切割
let
split_list
=
await
splitAudio
(
file
,
5
*
1024
*
1024
);
if
(
split_list
&&
split_list
.
length
)
{
let
result
=
await
uploadToAly
(
split_list
);
// 是否一维数组
if
(
dimensional
)
{
return
result
;
}
else
{
return
[
result
];
}
}
}
};
// 获取任务id
const
getTaskId
=
(
isConfuse
:
boolean
)
=>
{
if
(
isConfuse
)
{
// 是洗稿任务
return
currentConfuseId
.
value
;
}
return
createLiveInfo
.
value
[
createLiveKeys
.
scriptUuid
];
};
const
getTaskStatus
=
async
(
isConfuse
:
boolean
)
=>
{
try
{
try
{
let
res
:
any
=
await
getLiveTtsCallback
({
let
res
:
any
=
await
getLiveTtsCallback
({
task_id
:
createLiveInfo
.
value
[
createLiveKeys
.
scriptUuid
]
,
task_id
:
getTaskId
(
isConfuse
)
,
});
});
if
(
res
.
code
==
0
)
{
if
(
res
.
code
==
0
)
{
if
(
res
.
data
.
length
>=
createLiveInfo
.
value
[
createLiveKeys
.
textScriptList
].
length
)
{
if
(
res
.
data
.
length
>=
createLiveInfo
.
value
[
createLiveKeys
.
textScriptList
].
length
)
{
...
@@ -21,32 +262,62 @@ export const processTextCallback = () => {
...
@@ -21,32 +262,62 @@ export const processTextCallback = () => {
closeInterval
();
closeInterval
();
let
list
=
JSON
.
parse
(
JSON
.
stringify
(
createLiveInfo
.
value
[
createLiveKeys
.
textScriptList
]));
let
list
=
JSON
.
parse
(
JSON
.
stringify
(
createLiveInfo
.
value
[
createLiveKeys
.
textScriptList
]));
let
audio_list
=
[];
let
audio_list
=
[];
res
.
data
.
forEach
((
item
:
any
)
=>
{
// 本次任务不是洗稿任务才修改store
// 根据task_id更新数组对象
if
(
!
isConfuse
)
{
let
data
=
item
.
data
;
res
.
data
.
forEach
((
item
:
any
)
=>
{
if
(
data
&&
data
.
audio_address
&&
data
.
task_id
)
{
// 根据task_id更新数组对象
audio_list
.
push
(
data
.
audio_address
);
let
data
=
item
.
data
;
if
(
data
&&
data
.
audio_address
&&
data
.
task_id
)
{
audio_list
.
push
(
data
.
audio_address
);
let
index
=
list
.
findIndex
((
it
:
any
)
=>
it
.
task_id
==
data
.
task_id
);
if
(
index
!==
-
1
)
{
list
[
index
].
audio_address
=
data
.
audio_address
;
commitInfo
({
[
createLiveKeys
.
textScriptList
]:
list
,
});
}
}
else
{
show_message
(
'缺少音频或id'
);
}
});
let
resultList
=
await
audioStart
(
audio_list
,
false
);
// 修改store的type_content
commitInfo
({
[
createLiveKeys
.
textScriptValue
]:
resultList
,
});
// 提交
await
submit
();
// 需要洗稿
if
(
createLiveInfo
.
value
[
createLiveKeys
.
isDisorganize
])
{
//
await
startConfuse
();
}
else
{
}
else
{
s
how_message
(
'缺少音频或id'
);
s
ubmitSuccessed
(
);
}
}
});
}
else
{
// 音频合并
// 洗稿任务
let
file
=
await
audioMerge
(
audio_list
);
res
.
data
.
forEach
((
item
:
any
)
=>
{
console
.
log
(
file
);
let
data
=
item
.
data
;
if
(
file
)
{
if
(
data
&&
data
.
audio_address
)
{
// 开始切割
audio_list
.
push
(
data
.
audio_address
);
let
split_list
=
await
splitAudio
(
file
,
5
*
1024
*
1024
);
}
else
{
console
.
log
(
split_list
);
show_message
(
'洗稿缺少参数'
);
}
});
let
resultList
=
await
audioStart
(
audio_list
,
false
);
// 提交
}
}
loading
.
value
=
false
;
}
}
}
}
}
catch
(
e
)
{
}
catch
(
e
)
{
console
.
log
(
e
);
console
.
log
(
e
);
}
}
};
};
const
openInterval
=
()
=>
{
const
openInterval
=
(
isConfuse
:
boolean
)
=>
{
interval
.
value
=
window
.
setInterval
(()
=>
{
interval
.
value
=
window
.
setInterval
(()
=>
{
getTaskStatus
();
getTaskStatus
(
isConfuse
);
},
3000
);
},
3000
);
};
};
...
@@ -61,6 +332,14 @@ export const processTextCallback = () => {
...
@@ -61,6 +332,14 @@ export const processTextCallback = () => {
});
});
return
{
return
{
loading
,
initNum
,
currentSetp
,
openInterval
,
openInterval
,
filterFiled
,
initCreateStore
,
submit
,
submitSuccessed
,
backHome
,
};
};
};
};
src/pages/createLive/index.vue
View file @
0d8701a5
...
@@ -50,7 +50,7 @@
...
@@ -50,7 +50,7 @@
</div>
</div>
</div>
</div>
<ConfirmDialog
v-model=
"confirmVisible"
:title=
"'确定要生成该直播吗?'"
@
confirm=
"confirm"
></ConfirmDialog>
<ConfirmDialog
v-model=
"confirmVisible"
:title=
"'确定要生成该直播吗?'"
@
confirm=
"confirm"
></ConfirmDialog>
<Loading
v-show=
"loading"
></Loading>
<Loading
v-show=
"loading"
:mask=
"true"
></Loading>
</div>
</div>
</template>
</template>
...
@@ -66,7 +66,7 @@ import ChoseDigitalPerson from './components/ChoseDigitalPerson.vue';
...
@@ -66,7 +66,7 @@ import ChoseDigitalPerson from './components/ChoseDigitalPerson.vue';
import
HomeSvg
from
'@/assets/svg/createLive/home.svg'
;
import
HomeSvg
from
'@/assets/svg/createLive/home.svg'
;
import
InteractSvg
from
'@/assets/svg/createLive/interact.svg'
;
import
InteractSvg
from
'@/assets/svg/createLive/interact.svg'
;
import
ScriptsSvg
from
'@/assets/svg/createLive/scripts.svg'
;
import
ScriptsSvg
from
'@/assets/svg/createLive/scripts.svg'
;
import
{
computed
,
onMounted
,
ref
,
onBeforeUnmount
}
from
'vue'
;
import
{
computed
,
onMounted
,
ref
,
onBeforeUnmount
,
onActivated
}
from
'vue'
;
import
{
getElBounding
,
show_message
,
DataType
}
from
'@/utils/tool'
;
import
{
getElBounding
,
show_message
,
DataType
}
from
'@/utils/tool'
;
import
{
useStore
}
from
'vuex'
;
import
{
useStore
}
from
'vuex'
;
import
{
createLiveKeys
,
scriptTypeText
,
scriptTypePhonetics
}
from
'@/service/CreateLive'
;
import
{
createLiveKeys
,
scriptTypeText
,
scriptTypePhonetics
}
from
'@/service/CreateLive'
;
...
@@ -78,7 +78,8 @@ import { createLiveRouteKey } from '@/constants/token';
...
@@ -78,7 +78,8 @@ import { createLiveRouteKey } from '@/constants/token';
import
{
callPyjsInWindow
}
from
'@/utils/pyqt'
;
import
{
callPyjsInWindow
}
from
'@/utils/pyqt'
;
import
{
useLiveInfoSubmit
}
from
'@/hooks/useStoreCommit'
;
import
{
useLiveInfoSubmit
}
from
'@/hooks/useStoreCommit'
;
import
{
processTextCallback
}
from
'./hooks/scripts'
;
import
{
processTextCallback
}
from
'./hooks/scripts'
;
const
{
openInterval
}
=
processTextCallback
();
const
{
loading
,
initNum
,
currentSetp
,
openInterval
,
filterFiled
,
backHome
,
submitSuccessed
,
submit
,
initCreateStore
}
=
processTextCallback
();
const
[
commitInfo
]
=
useLiveInfoSubmit
();
const
[
commitInfo
]
=
useLiveInfoSubmit
();
const
store
=
useStore
();
const
store
=
useStore
();
...
@@ -90,18 +91,11 @@ const liveImage = computed(() => store.getters['live/getLiveimage']);
...
@@ -90,18 +91,11 @@ const liveImage = computed(() => store.getters['live/getLiveimage']);
const
createLiveInfo
=
computed
(()
=>
store
.
getters
[
'live/getLiveInfo'
]);
const
createLiveInfo
=
computed
(()
=>
store
.
getters
[
'live/getLiveInfo'
]);
const
liveName
=
computed
(()
=>
store
.
getters
[
'live/getName'
]);
const
liveName
=
computed
(()
=>
store
.
getters
[
'live/getName'
]);
const
loading
=
ref
(
false
);
const
confirmVisible
=
ref
(
false
);
const
confirmVisible
=
ref
(
false
);
const
publicTool
=
ref
<
HTMLElement
>
();
const
publicTool
=
ref
<
HTMLElement
>
();
const
toolHeight
=
ref
(
0
);
const
toolHeight
=
ref
(
0
);
const
currentSetp
=
ref
(
1
);
// 通知子组件初始化
const
initNum
=
ref
(
1
);
const
videoPlay
=
ref
<
HTMLVideoElement
>
();
const
videoPlay
=
ref
<
HTMLVideoElement
>
();
const
videoCanplay
=
()
=>
{
const
videoCanplay
=
()
=>
{
...
@@ -147,8 +141,8 @@ const setpsList = [
...
@@ -147,8 +141,8 @@ const setpsList = [
{
{
key
:
createLiveKeys
.
scriptType
,
key
:
createLiveKeys
.
scriptType
,
value
:
scriptTypePhonetics
,
value
:
scriptTypePhonetics
,
require
:
[
createLiveKeys
.
phoneticsFile
],
require
:
[
createLiveKeys
.
audioScriptList
],
message
:
'音频文件
必填
'
,
message
:
'音频文件
至少上传一个
'
,
},
},
],
],
},
},
...
@@ -225,13 +219,6 @@ const getEditInfo = async (id: any, type: string) => {
...
@@ -225,13 +219,6 @@ const getEditInfo = async (id: any, type: string) => {
}
}
};
};
const
backHome
=
()
=>
{
router
.
push
({
path
:
routerConfig
.
home
.
path
,
name
:
routerConfig
.
home
.
name
,
});
};
//
//
const
currentModuleField
=
()
=>
{
const
currentModuleField
=
()
=>
{
let
index
=
setpsList
.
findIndex
((
item
:
any
)
=>
item
.
value
===
currentSetp
.
value
);
let
index
=
setpsList
.
findIndex
((
item
:
any
)
=>
item
.
value
===
currentSetp
.
value
);
...
@@ -248,7 +235,6 @@ const currentModuleField = () => {
...
@@ -248,7 +235,6 @@ const currentModuleField = () => {
Object
.
keys
(
createLiveInfo
.
value
).
forEach
((
key
:
string
)
=>
{
Object
.
keys
(
createLiveInfo
.
value
).
forEach
((
key
:
string
)
=>
{
if
(
it
===
key
)
{
if
(
it
===
key
)
{
let
value
=
createLiveInfo
.
value
[
key
];
let
value
=
createLiveInfo
.
value
[
key
];
console
.
log
(
value
);
if
(
DataType
(
value
)
&&
!
value
.
length
)
{
if
(
DataType
(
value
)
&&
!
value
.
length
)
{
// 是数组
// 是数组
status
=
false
;
status
=
false
;
...
@@ -308,35 +294,6 @@ const onSave = () => {
...
@@ -308,35 +294,6 @@ const onSave = () => {
}
}
};
};
// 过滤必要的字段
const
filterFiled
=
()
=>
{
let
item
=
createLiveInfo
.
value
;
// 过滤必须字段
let
params
:
any
=
{};
params
.
name
=
liveName
.
value
;
// 数字人id
params
.
digital_man_id
=
item
[
createLiveKeys
.
id
];
// 脚本类型
params
.
type
=
item
[
createLiveKeys
.
scriptType
];
// 脚本内容
if
(
item
[
createLiveKeys
.
scriptType
]
==
scriptTypeText
)
{
// 文本
params
.
type_content
=
item
[
createLiveKeys
.
textScriptValue
];
// 音色id
params
.
phonetic_timbres_id
=
item
[
createLiveKeys
.
textSoundColor
];
}
else
{
// 音频
params
.
type_content
=
item
[
createLiveKeys
.
phoneticsFile
];
// 音色id
params
.
phonetic_timbres_id
=
item
[
createLiveKeys
.
phoneticsSoundColor
];
}
// 音调id
params
.
tone_id
=
item
[
createLiveKeys
.
textTones
];
// 互动库
params
.
interaction_ids
=
item
[
createLiveKeys
.
interactiveLibrary
];
return
params
;
};
// 保存为草稿
// 保存为草稿
const
onSaveDrafts
=
async
()
=>
{
const
onSaveDrafts
=
async
()
=>
{
let
params
=
filterFiled
();
let
params
=
filterFiled
();
...
@@ -396,7 +353,6 @@ const confirm = async () => {
...
@@ -396,7 +353,6 @@ const confirm = async () => {
if
(
item
[
createLiveKeys
.
scriptType
]
==
scriptTypeText
)
{
if
(
item
[
createLiveKeys
.
scriptType
]
==
scriptTypeText
)
{
// 文本脚本
// 文本脚本
loading
.
value
=
true
;
loading
.
value
=
true
;
for
(
let
i
=
0
;
i
<
item
[
createLiveKeys
.
textScriptList
].
length
;
i
++
)
{
for
(
let
i
=
0
;
i
<
item
[
createLiveKeys
.
textScriptList
].
length
;
i
++
)
{
let
params
=
{
let
params
=
{
// 音色
// 音色
...
@@ -421,27 +377,14 @@ const confirm = async () => {
...
@@ -421,27 +377,14 @@ const confirm = async () => {
}
}
}
}
// 开启轮询
// 开启轮询
openInterval
();
openInterval
(
false
);
}
else
{
}
else
{
// 音频脚本
try
{
try
{
loading
.
value
=
true
;
loading
.
value
=
true
;
let
res
:
any
=
await
createLiveTask
(
filterFiled
());
let
res
=
await
submit
();
if
(
res
.
code
==
0
)
{
if
(
res
)
{
show_message
(
'创建成功'
,
'success'
);
submitSuccessed
();
// 回首页
backHome
();
// 清空name
store
.
commit
(
'live/setName'
,
''
);
// 清空edit
store
.
commit
(
'live/clearEditLive'
);
// 清空createLive
store
.
commit
(
'live/clearCreateLive'
);
store
.
commit
(
'live/initLiveInfo'
);
// 清空信息
// 通知三个模块清空自己的内容
initNum
.
value
+=
1
;
// 回到模块1
currentSetp
.
value
=
1
;
}
}
loading
.
value
=
false
;
loading
.
value
=
false
;
}
catch
(
e
)
{
}
catch
(
e
)
{
...
@@ -467,6 +410,9 @@ onMounted(() => {
...
@@ -467,6 +410,9 @@ onMounted(() => {
query
:
route
.
query
,
query
:
route
.
query
,
});
});
});
});
onActivated
(()
=>
{
store
.
commit
(
'live/setName'
,
route
.
query
.
title
?
route
.
query
.
title
:
''
);
});
onBeforeUnmount
(()
=>
{
onBeforeUnmount
(()
=>
{
// 清空选择的数字人
// 清空选择的数字人
...
...
src/service/Common.ts
View file @
0d8701a5
...
@@ -5,10 +5,14 @@ import {
...
@@ -5,10 +5,14 @@ import {
updateLiveTask
,
updateLiveTask
,
getGroupsInteraction
,
getGroupsInteraction
,
updateDrafts
,
updateDrafts
,
liveContentRegenerate
,
liveContentRegenerateCallback
,
}
from
'@/utils/api/userApi'
;
}
from
'@/utils/api/userApi'
;
import
{
typeTones
,
typeSoundColor
}
from
'@/service/CreateLive'
;
import
{
typeTones
,
typeSoundColor
}
from
'@/service/CreateLive'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
{
LIVE_AUDIT_STATUS
}
from
'./Live'
;
// 阿里云上传配置
export
const
getUploadConfig
=
async
()
=>
{
export
const
getUploadConfig
=
async
()
=>
{
try
{
try
{
let
res
:
any
=
await
getAlyOssConfig
();
let
res
:
any
=
await
getAlyOssConfig
();
...
@@ -43,7 +47,7 @@ export const getDigitalPeopleList = async () => {
...
@@ -43,7 +47,7 @@ export const getDigitalPeopleList = async () => {
};
};
// 获取我的音调
// 获取我的音调
export
const
getTonesList
=
async
()
=>
{
export
const
getTonesList
=
async
(
mustSuccess
:
boolean
=
true
)
=>
{
let
obj
=
{
let
obj
=
{
tones
:
[],
tones
:
[],
soundColor
:
[],
soundColor
:
[],
...
@@ -57,7 +61,14 @@ export const getTonesList = async () => {
...
@@ -57,7 +61,14 @@ export const getTonesList = async () => {
item
.
c_categorie
=
item
.
extend
?.
voice
;
item
.
c_categorie
=
item
.
extend
?.
voice
;
});
});
obj
.
tones
=
res
.
data
.
filter
((
item
:
any
)
=>
item
.
type
==
typeTones
);
obj
.
tones
=
res
.
data
.
filter
((
item
:
any
)
=>
item
.
type
==
typeTones
);
obj
.
soundColor
=
res
.
data
.
filter
((
item
:
any
)
=>
item
.
type
==
typeSoundColor
);
obj
.
soundColor
=
res
.
data
.
filter
((
item
:
any
)
=>
{
if
(
item
.
type
==
typeSoundColor
)
{
if
(
item
.
status
!=
LIVE_AUDIT_STATUS
.
LIVE_AUDIT_STATUS_FINISH
&&
mustSuccess
)
{
return
;
}
return
item
;
}
});
}
}
return
obj
;
return
obj
;
}
catch
(
e
)
{
}
catch
(
e
)
{
...
...
src/service/CreateLive.ts
View file @
0d8701a5
...
@@ -8,6 +8,7 @@ export const createLiveKeys = {
...
@@ -8,6 +8,7 @@ export const createLiveKeys = {
textSoundColor
:
'phonetic_timbres_id'
,
// 文本音色
textSoundColor
:
'phonetic_timbres_id'
,
// 文本音色
textScriptValue
:
'type_content'
,
// 文字脚本的文本
textScriptValue
:
'type_content'
,
// 文字脚本的文本
textScriptList
:
'type_content_list'
,
// 文字脚本列表
textScriptList
:
'type_content_list'
,
// 文字脚本列表
audioScriptList
:
'type_content_audio_list'
,
// 音频脚本文件列表
phoneticsSoundColor
:
'phoneticsSoundColor'
,
// 音频 音色
phoneticsSoundColor
:
'phoneticsSoundColor'
,
// 音频 音色
phoneticsFile
:
'phoneticsFile'
,
// 音频文件
phoneticsFile
:
'phoneticsFile'
,
// 音频文件
commentMethod
:
'commentMethod'
,
// 评论方式
commentMethod
:
'commentMethod'
,
// 评论方式
...
...
src/store/modules/live.ts
View file @
0d8701a5
...
@@ -7,13 +7,14 @@ const initParams = () => {
...
@@ -7,13 +7,14 @@ const initParams = () => {
[
createLiveKeys
.
scriptType
]:
''
,
[
createLiveKeys
.
scriptType
]:
''
,
[
createLiveKeys
.
textTones
]:
''
,
[
createLiveKeys
.
textTones
]:
''
,
[
createLiveKeys
.
textSoundColor
]:
''
,
[
createLiveKeys
.
textSoundColor
]:
''
,
[
createLiveKeys
.
textScriptValue
]:
''
,
[
createLiveKeys
.
textScriptValue
]:
[]
,
[
createLiveKeys
.
phoneticsSoundColor
]:
''
,
[
createLiveKeys
.
phoneticsSoundColor
]:
''
,
[
createLiveKeys
.
phoneticsFile
]:
''
,
[
createLiveKeys
.
phoneticsFile
]:
''
,
[
createLiveKeys
.
commentMethod
]:
''
,
[
createLiveKeys
.
commentMethod
]:
''
,
[
createLiveKeys
.
isDisorganize
]:
false
,
[
createLiveKeys
.
isDisorganize
]:
false
,
[
createLiveKeys
.
interactiveLibrary
]:
[],
[
createLiveKeys
.
interactiveLibrary
]:
[],
[
createLiveKeys
.
textScriptList
]:
[],
[
createLiveKeys
.
textScriptList
]:
[],
[
createLiveKeys
.
audioScriptList
]:
[],
[
createLiveKeys
.
scriptUuid
]:
''
,
[
createLiveKeys
.
scriptUuid
]:
''
,
};
};
};
};
...
@@ -39,7 +40,6 @@ const mutations = {
...
@@ -39,7 +40,6 @@ const mutations = {
Object
.
keys
(
info
).
forEach
((
item
:
any
)
=>
{
Object
.
keys
(
info
).
forEach
((
item
:
any
)
=>
{
state
.
createLive
[
item
]
=
info
[
item
];
state
.
createLive
[
item
]
=
info
[
item
];
});
});
console
.
log
(
state
.
createLive
);
},
},
initLiveInfo
(
state
:
StateType
)
{
initLiveInfo
(
state
:
StateType
)
{
state
.
createLive
=
initParams
();
state
.
createLive
=
initParams
();
...
...
src/utils/api/userApi.ts
View file @
0d8701a5
...
@@ -338,3 +338,34 @@ export const getLiveTtsCallback = (data: any) => {
...
@@ -338,3 +338,34 @@ export const getLiveTtsCallback = (data: any) => {
},
},
});
});
};
};
// 洗稿提交
export
const
liveContentRegenerate
=
async
(
data
:
any
)
=>
{
const
header
=
getHeader
();
return
request
.
post
(
`/api/live/content/regenerate`
,
data
,
{
headers
:
{
...
header
,
},
});
};
// 获取洗稿回调
export
const
liveContentRegenerateCallback
=
(
data
:
any
)
=>
{
const
header
=
getHeader
();
return
request
.
get
(
`/api/live/content/regenerate`
,
{
params
:
data
,
headers
:
{
...
header
,
},
});
};
// 重新生成直播
export
const
liveTaskRegenerate
=
()
=>
{
const
header
=
getHeader
();
return
request
.
post
(
`/api/live/task/{id}/regenerate`
,
''
,
{
headers
:
{
...
header
,
},
});
};
src/utils/audio.ts
View file @
0d8701a5
// 将浮点数音频数据转换为16位PCM数据
import
{
downloadBlobFile
,
show_message
}
from
'./tool'
;
const
floatTo16BitPCM
=
(
output
,
offset
,
input
)
=>
{
import
{
v4
}
from
'uuid'
;
for
(
let
i
=
0
;
i
<
input
.
length
;
i
++
,
offset
+=
2
)
{
export
const
createAudioContext
=
()
=>
{
const
s
=
Math
.
max
(
-
1
,
Math
.
min
(
1
,
input
[
i
]));
return
new
(
window
.
AudioContext
||
window
.
webkitAudioContext
)();
output
.
setInt16
(
offset
,
s
<
0
?
s
*
0x8000
:
s
*
0x7fff
,
true
);
}
};
// 在DataView中写入字符串
const
writeString
=
(
view
,
offset
,
string
)
=>
{
for
(
let
i
=
0
;
i
<
string
.
length
;
i
++
)
{
view
.
setUint8
(
offset
+
i
,
string
.
charCodeAt
(
i
));
}
};
};
// 将AudioBuffer转换为WAVE格式的Blob
export
async
function
decodeAudio
(
blob
:
Blob
)
{
const
bufferToWave
=
(
buffer
)
=>
{
const
audioContext
=
createAudioContext
();
const
arrayBuffer
=
new
ArrayBuffer
(
44
+
buffer
.
length
*
2
);
return
new
Promise
((
resolve
,
reject
)
=>
{
const
view
=
new
DataView
(
arrayBuffer
);
const
fileReader
=
new
FileReader
();
fileReader
.
onloadend
=
function
()
{
// 添加WAVE文件头
const
arrayBuffer
=
fileReader
.
result
;
writeString
(
view
,
0
,
'RIFF'
);
audioContext
.
decodeAudioData
(
view
.
setUint32
(
4
,
32
+
buffer
.
length
*
2
,
true
);
arrayBuffer
,
writeString
(
view
,
8
,
'WAVE'
);
(
audioBuffer
:
any
)
=>
{
writeString
(
view
,
12
,
'fmt '
);
resolve
(
audioBuffer
);
view
.
setUint32
(
16
,
16
,
true
);
},
view
.
setUint16
(
20
,
1
,
true
);
reject
,
view
.
setUint16
(
22
,
buffer
.
numberOfChannels
,
true
);
);
view
.
setUint32
(
24
,
buffer
.
sampleRate
,
true
);
};
view
.
setUint32
(
28
,
buffer
.
sampleRate
*
buffer
.
numberOfChannels
*
2
,
true
);
fileReader
.
onerror
=
reject
;
view
.
setUint16
(
32
,
buffer
.
numberOfChannels
*
2
,
true
);
fileReader
.
readAsArrayBuffer
(
blob
);
view
.
setUint16
(
34
,
16
,
true
);
});
writeString
(
view
,
36
,
'data'
);
}
view
.
setUint32
(
40
,
buffer
.
length
*
2
,
true
);
// 合并音频文件
export
async
function
audioMerge
(
filePaths
)
{
// 将音频数据写入buffer
try
{
floatTo16BitPCM
(
view
,
44
,
buffer
);
// 创建一个新的音频上下文
const
audioContext
=
createAudioContext
();
// 将ArrayBuffer转换为Blob
return
new
Blob
([
view
],
{
type
:
'audio/wav'
});
// 存储每个音频文件的解码后的音频数据
};
const
buffers
=
[];
// 音频合并
// 使用 Promise 依次解码和添加音频数据到 buffers 数组
export
const
audioMerge
=
async
(
audioUrls
:
string
[])
=>
{
await
Promise
.
all
(
// 创建一个新的AudioContext对象
filePaths
.
map
(
async
(
filePath
)
=>
{
const
audioContext
=
new
(
window
.
AudioContext
||
window
.
webkitAudioContext
)();
const
response
=
await
fetch
(
filePath
);
const
arrayBuffer
=
await
response
.
arrayBuffer
();
const
audioBuffers
=
[];
const
loadAudioFile
=
async
(
url
)
=>
{
const
audioBuffer
=
await
audioContext
.
decodeAudioData
(
arrayBuffer
);
const
response
=
await
fetch
(
url
);
return
audioBuffer
;
const
arrayBuffer
=
await
response
.
arrayBuffer
();
}),
return
audioContext
.
decodeAudioData
(
arrayBuffer
);
).
then
((
decodedBuffers
)
=>
{
};
buffers
.
push
(...
decodedBuffers
);
// 将解码后的音频缓冲区按顺序添加到数组中
});
const
loadAllAudioFiles
=
async
()
=>
{
for
(
const
audioUrl
of
audioUrls
)
{
// 计算合并后的音频数据的长度
const
audioBuffer
=
await
loadAudioFile
(
audioUrl
);
const
totalDuration
=
buffers
.
reduce
((
accumulator
,
current
)
=>
accumulator
+
current
.
duration
,
0
);
audioBuffers
.
push
(
audioBuffer
);
const
sampleRate
=
audioContext
.
sampleRate
;
}
const
numberOfChannels
=
buffers
[
0
].
numberOfChannels
;
};
const
channels
=
buffers
[
0
].
numberOfChannels
;
// 创建一个新的音频缓冲区
// 合并音频文件
const
mergeAudioFiles
=
async
()
=>
{
// 创建一个新的AudioBuffer对象来保存合并后的音频
const
mergedBuffer
=
audioContext
.
createBuffer
(
const
mergedBuffer
=
audioContext
.
createBuffer
(
audioBuffers
[
0
].
numberOfChannels
,
numberOfChannels
,
audioBuffers
[
0
].
length
,
Math
.
round
(
sampleRate
*
totalDuration
)
,
audioBuffers
[
0
].
sampleRate
,
sampleRate
,
);
);
// 将每个音频文件的数据复制到合并后的AudioBuffer中
let
offset
=
0
;
for
(
let
i
=
0
;
i
<
audioBuffers
.
length
;
i
++
)
{
const
sourceBuffer
=
audioBuffers
[
i
];
// 合并音频数据
for
(
let
channel
=
0
;
channel
<
sourceBuffer
.
numberOfChannels
;
channel
++
)
{
buffers
.
forEach
((
buffer
,
index
)
=>
{
const
sourceData
=
sourceBuffer
.
getChannelData
(
channel
);
for
(
let
channel
=
0
;
channel
<
channels
;
channel
++
)
{
const
mergedData
=
mergedBuffer
.
getChannelData
(
channel
);
const
sourceData
=
buffer
.
getChannelData
(
channel
);
mergedData
.
set
(
sourceData
,
i
*
sourceBuffer
.
length
);
const
targetData
=
mergedBuffer
.
getChannelData
(
channel
);
targetData
.
set
(
sourceData
,
offset
);
}
}
}
offset
+=
Math
.
round
(
buffer
.
duration
*
sampleRate
);
});
// 导出合并后的音频数据为 WAV 文件
const
mergedData
=
exportBufferAsWav
(
mergedBuffer
);
const
blob
=
new
Blob
([
mergedData
],
{
type
:
'audio/wav'
});
return
blob
;
}
catch
(
error
)
{
console
.
error
(
'音频文件合并失败:'
,
error
);
}
}
// 将合并后的音频写入文件
// 切割音频文件
let
renderedBuffer
=
await
audioContext
.
startRendering
();
export
async
function
splitAudio
(
fileBlob
:
Blob
,
splitSize
:
number
)
{
const
offlineAudioContext
=
new
OfflineAudioContext
(
if
(
fileBlob
.
size
<
splitSize
)
{
mergedBuffer
.
numberOfChannels
,
return
[
fileBlob
];
renderedBuffer
.
length
,
}
renderedBuffer
.
sampleRate
,
);
const
source
=
offlineAudioContext
.
createBufferSource
();
source
.
buffer
=
mergedBuffer
;
source
.
connect
(
offlineAudioContext
.
destination
);
source
.
start
();
let
renderedBufferChild
=
await
offlineAudioContext
.
startRendering
();
return
renderedBufferChild
;
// 将合并后的音频保存为文件
const
audioBlob
=
bufferToWave
(
renderedBufferChild
);
// const audioUrl = URL.createObjectURL(audioBlob);
};
// 加载
await
loadAllAudioFiles
();
// 并合并音频文件
return
mergeAudioFiles
();
};
// 切割音频并保存为Blob对象
try
{
export
const
splitAudio
=
async
(
audioBuffer
,
blockSize
)
=>
{
const
MAX_CHUNK_SIZE
=
splitSize
;
const
numBlocks
=
Math
.
ceil
(
audioBuffer
.
length
/
blockSize
);
const
newChunks
=
[];
const
audioChunks
=
[];
for
(
let
i
=
0
;
i
<
numBlocks
;
i
++
)
{
const
asyncReadFile
=
(
file
,
offset
)
=>
{
const
startOffset
=
i
*
blockSize
;
return
new
Promise
((
resolve
,
reject
)
=>
{
const
endOffset
=
Math
.
min
(
startOffset
+
blockSize
,
audioBuffer
.
length
);
const
reader
=
new
FileReader
(
);
const
bufferChunk
=
audioBuffer
.
slice
(
startOffset
,
endOffset
);
reader
.
onload
=
(
event
)
=>
{
audioChunks
.
push
(
bufferChunk
);
const
binaryData
=
event
.
target
.
result
;
const
chunkName
=
v4
();
const
binaryFile
=
new
File
([
binaryData
],
chunkName
,
{
type
:
file
.
type
});
resolve
(
binaryFile
);
};
reader
.
onerror
=
()
=>
{
reject
(
new
Error
(
'File read error.'
));
};
const
chunk
=
file
.
slice
(
offset
,
offset
+
MAX_CHUNK_SIZE
);
reader
.
readAsArrayBuffer
(
chunk
);
});
};
for
(
const
file
of
[
fileBlob
])
{
const
fileSize
=
file
.
size
;
let
offset
=
0
;
while
(
offset
<
fileSize
)
{
const
chunkSize
=
Math
.
min
(
MAX_CHUNK_SIZE
,
fileSize
-
offset
);
const
binaryFile
=
await
asyncReadFile
(
file
,
offset
);
newChunks
.
push
(
binaryFile
);
offset
+=
chunkSize
;
}
}
return
newChunks
;
}
catch
(
e
)
{
show_message
(
'音频切割失败'
);
}
}
// 导出音频缓冲区为 WAV 文件
function
exportBufferAsWav
(
audioBuffer
)
{
const
numberOfChannels
=
audioBuffer
.
numberOfChannels
;
const
sampleRate
=
audioBuffer
.
sampleRate
;
const
length
=
audioBuffer
.
length
;
const
channels
=
[];
// 将音频缓冲区的数据转化为通道数组
for
(
let
channel
=
0
;
channel
<
numberOfChannels
;
channel
++
)
{
channels
.
push
(
audioBuffer
.
getChannelData
(
channel
));
}
}
// 将切割后的音频块进行合并,并转换为Blob对象
// 创建 WAV 文件头
const
mergedChunks
=
new
Blob
(
audioChunks
,
{
type
:
'audio/wav'
});
const
buffer
=
new
ArrayBuffer
(
44
+
length
*
2
);
const
view
=
new
DataView
(
buffer
);
view
.
setUint32
(
0
,
0x52494646
,
false
);
// RIFF 头部
view
.
setUint32
(
4
,
36
+
length
*
2
,
true
);
// 文件大小
view
.
setUint32
(
8
,
0x57415645
,
false
);
// WAVE 标记
view
.
setUint32
(
12
,
0x666d7420
,
false
);
// fmt 头部
view
.
setUint32
(
16
,
16
,
true
);
// fmt 大小
view
.
setUint16
(
20
,
1
,
true
);
// 格式(1表示 PCM)
view
.
setUint16
(
22
,
numberOfChannels
,
true
);
// 通道数
view
.
setUint32
(
24
,
sampleRate
,
true
);
// 采样率
view
.
setUint32
(
28
,
sampleRate
*
2
*
numberOfChannels
,
true
);
// 数据速率
view
.
setUint16
(
32
,
numberOfChannels
*
2
,
true
);
// 数据块大小
view
.
setUint16
(
34
,
16
,
true
);
// 量化位数
view
.
setUint32
(
36
,
0x64617461
,
false
);
// data 头部
view
.
setUint32
(
40
,
length
*
2
,
true
);
// 数据大小
// 将音频数据写入 WAV 文件
for
(
let
i
=
0
;
i
<
length
;
i
++
)
{
for
(
let
channel
=
0
;
channel
<
numberOfChannels
;
channel
++
)
{
const
sample
=
Math
.
max
(
-
1
,
Math
.
min
(
1
,
channels
[
channel
][
i
]));
const
value
=
sample
<
0
?
sample
*
0x8000
:
sample
*
0x7fff
;
view
.
setInt16
(
44
+
i
*
numberOfChannels
*
2
+
channel
*
2
,
value
,
true
);
}
}
return
mergedChunks
;
return
new
Uint8Array
(
buffer
)
;
}
;
}
src/utils/request.ts
View file @
0d8701a5
...
@@ -33,14 +33,6 @@ instance.interceptors.response.use(
...
@@ -33,14 +33,6 @@ instance.interceptors.response.use(
const
{
data
}
=
response
;
const
{
data
}
=
response
;
if
(
data
.
code
===
0
)
{
if
(
data
.
code
===
0
)
{
return
data
;
return
data
;
}
else
{
//@ts-ignore
if
(
response
.
config
.
needCode
)
{
return
data
;
}
else
{
show_message
(
data
.
msg
||
error_messaage
,
'error'
);
return
Promise
.
reject
(
data
.
msg
);
}
}
}
},
},
(
err
)
=>
{
(
err
)
=>
{
...
@@ -61,6 +53,7 @@ instance.interceptors.response.use(
...
@@ -61,6 +53,7 @@ instance.interceptors.response.use(
// 格式不一致的
// 格式不一致的
let
res
=
err
.
toJSON
();
let
res
=
err
.
toJSON
();
show_message
(
res
.
message
,
'error'
);
show_message
(
res
.
message
,
'error'
);
return
;
}
}
},
},
);
);
...
...
src/utils/tool.ts
View file @
0d8701a5
import
{
MessagePlugin
,
RequestMethodResponse
}
from
'tdesign-vue-next'
;
import
{
MessagePlugin
,
RequestMethodResponse
}
from
'tdesign-vue-next'
;
import
request
from
'@/utils/
other
Request'
;
import
request
from
'@/utils/
upLoad
Request'
;
/**
/**
* 函数节流处理
* 函数节流处理
...
@@ -168,56 +168,98 @@ export const alyOssUpload = (
...
@@ -168,56 +168,98 @@ export const alyOssUpload = (
UploadErrorCallback
:
Function
,
UploadErrorCallback
:
Function
,
fileName
:
string
,
fileName
:
string
,
)
=>
{
)
=>
{
return
new
Promise
<
RequestMethodResponse
>
((
resolve
)
=>
{
return
new
Promise
<
RequestMethodResponse
>
((
resolve
,
reject
)
=>
{
let
url
=
''
;
try
{
url
=
'https://'
+
config
.
host
;
let
url
=
''
;
let
files
:
any
[]
=
[];
url
=
'https://'
+
config
.
host
;
if
(
!
DataType
(
file
))
{
let
files
:
any
[]
=
[];
// 不是数组
if
(
!
DataType
(
file
))
{
files
=
[
file
];
// 不是数组
}
else
{
files
=
[
file
];
files
=
file
;
}
else
{
}
files
=
file
;
for
(
let
i
=
0
;
i
<
files
.
length
;
i
++
)
{
}
let
item
=
files
[
i
];
for
(
let
i
=
0
;
i
<
files
.
length
;
i
++
)
{
const
formData
=
new
FormData
();
let
item
=
files
[
i
];
formData
.
append
(
'key'
,
config
.
dir
+
fileName
+
`.
${
getFileSuffix
(
item
)}
`
);
const
formData
=
new
FormData
();
formData
.
append
(
'policy'
,
config
.
policy
);
formData
.
append
(
'key'
,
config
.
dir
+
fileName
+
`.
${
getFileSuffix
(
item
)}
`
);
formData
.
append
(
'OSSAccessKeyId'
,
config
.
accessid
);
formData
.
append
(
'policy'
,
config
.
policy
);
formData
.
append
(
'success_action_status'
,
'200'
);
formData
.
append
(
'OSSAccessKeyId'
,
config
.
accessid
);
formData
.
append
(
'callback'
,
config
.
callback
);
formData
.
append
(
'success_action_status'
,
'200'
);
formData
.
append
(
'signature'
,
config
.
signature
);
formData
.
append
(
'callback'
,
config
.
callback
);
formData
.
append
(
'file'
,
item
.
raw
);
formData
.
append
(
'signature'
,
config
.
signature
);
request
if
(
item
.
raw
)
{
.
post
(
url
,
formData
,
{
// 存在row
headers
:
{
formData
.
append
(
'file'
,
item
.
raw
);
'Content-Type'
:
'multipart/form-data;charset=utf-8'
,
}
else
{
// Accept: '*/*',
// 另一个格式
},
formData
.
append
(
'file'
,
item
);
})
}
.
then
((
res
:
any
)
=>
{
request
// resolve 参数为关键代码
.
post
(
url
,
formData
,
{
if
(
res
===
''
||
res
==
200
)
{
headers
:
{
// 外网url
'Content-Type'
:
'multipart/form-data;charset=utf-8'
,
const
url
=
config
.
domain
+
config
.
dir
+
fileName
+
`.
${
getFileSuffix
(
item
)}
`
;
// Accept: '*/*',
console
.
log
(
url
);
},
UploadSuccessCallback
(
fileName
,
url
);
})
resolve
({
.
then
((
res
:
any
)
=>
{
status
:
'success'
,
// resolve 参数为关键代码
response
:
{
url
:
url
},
if
(
res
===
''
||
res
==
200
)
{
// 外网url
const
url
=
config
.
domain
+
config
.
dir
+
fileName
+
`.
${
getFileSuffix
(
item
)}
`
;
UploadSuccessCallback
(
fileName
,
url
);
resolve
({
status
:
'success'
,
response
:
{
url
:
url
},
});
}
else
{
UploadErrorCallback
(
fileName
);
reject
({
status
:
'error'
,
response
:
''
,
});
}
})
.
catch
((
e
)
=>
{
console
.
log
(
e
);
reject
({
status
:
'error'
,
response
:
''
,
});
});
}
else
{
});
UploadErrorCallback
(
fileName
);
}
}
}
catch
(
e
)
{
})
console
.
log
(
e
);
.
catch
((
e
)
=>
{
reject
({
console
.
log
(
e
);
status
:
'error'
,
});
response
:
''
,
});
}
}
});
});
};
};
// 获取文件后缀
// 获取文件后缀
export
const
getFileSuffix
=
(
file
:
File
)
=>
{
export
const
getFileSuffix
=
(
file
:
any
)
=>
{
return
file
.
name
.
split
(
'.'
)[
1
];
if
(
file
.
name
&&
file
.
name
.
indexOf
(
'.'
)
!==
-
1
)
{
return
file
.
name
.
split
(
'.'
)[
1
];
}
else
{
return
file
.
type
.
split
(
'/'
)[
1
];
}
};
// 二进制文件下载
export
const
downloadBlobFile
=
(
blob
:
Blob
,
name
:
string
=
'test'
)
=>
{
// 创建下载链接
var
url
=
URL
.
createObjectURL
(
blob
);
// 创建下载链接元素
var
link
=
document
.
createElement
(
'a'
);
link
.
href
=
url
;
link
.
download
=
name
;
// 模拟点击事件下载文件
link
.
click
();
// 清理 Blob URL
URL
.
revokeObjectURL
(
url
);
};
};
src/utils/upLoadRequest.ts
0 → 100644
View file @
0d8701a5
import
axios
from
'axios'
;
import
{
MessagePlugin
}
from
'tdesign-vue-next'
;
const
instance
:
any
=
axios
.
create
({
timeout
:
60
*
60
*
1000
,
withCredentials
:
false
,
});
instance
.
all
=
axios
.
all
;
// 请求头
instance
.
interceptors
.
request
.
use
((
config
:
any
)
=>
{
return
config
;
});
instance
.
interceptors
.
response
.
use
(
(
response
)
=>
{
const
{
data
,
status
}
=
response
;
if
(
status
==
201
||
status
==
200
)
{
return
data
;
}
if
(
data
.
code
===
0
)
{
return
data
;
}
},
(
err
)
=>
{
console
.
log
(
err
);
if
(
'response'
in
err
)
{
return
err
.
response
;
}
},
);
export
default
instance
;
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