Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
D
digitalPerson-fe
Project
Project
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
digitalPerson
digitalPerson-fe
Commits
7aa80c52
Commit
7aa80c52
authored
Sep 29, 2024
by
Dazzle Wu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 横屏视频生成
parent
eec5ddc5
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
198 additions
and
218 deletions
+198
-218
digital-creation.ts
src/apis/digital-creation.ts
+6
-1
opus.ts
src/apis/opus.ts
+4
-0
template.ts
src/apis/template.ts
+1
-1
creation.ts
src/router/modules/creation.ts
+6
-1
audio-setting.ts
src/store/modules/audio-setting.ts
+5
-0
creation.ts
src/store/types/creation.ts
+1
-0
template.ts
src/store/types/template.ts
+7
-6
digital-human.vue
src/views/creation/components/digital/digital-human.vue
+1
-11
preview-content.vue
src/views/creation/components/preview-content.vue
+40
-15
header-bar.vue
src/views/creation/layout/header-bar.vue
+65
-40
index.vue
src/views/creation/layout/index.vue
+39
-23
recent-creation.vue
src/views/home/components/recent-creation.vue
+0
-108
recent-creation.vue
src/views/workbench/components/recent-creation.vue
+15
-7
recommend-template.vue
src/views/workbench/components/recommend-template.vue
+8
-5
No files found.
src/apis/digital-creation.ts
View file @
7aa80c52
...
...
@@ -56,7 +56,7 @@ export function fetchTimbreByExample<T>(condition: string) {
}
// 根据草稿id获取草稿的配置信息
export
function
fetchDraftConfigById
<
T
>
(
id
:
number
)
{
export
function
fetchDraftConfigById
<
T
>
(
id
:
string
)
{
return
request
.
post
<
T
>
(
`/bizDigitalHumanMemberDraftConfigRest/getById.json?id=
${
id
}
`
)
}
...
...
@@ -65,6 +65,11 @@ export function saveDraftConfig<T>(payload: object) {
return
request
.
post
<
T
>
(
'/bizDigitalHumanMemberDraftConfigRest/saveOrUpdate.json'
,
payload
)
}
// 导出视频需要消耗灵豆
export
function
consumeUniversalCurrency
<
T
>
(
audioUrl
:
string
)
{
return
request
.
post
<
T
>
(
`/aiDigitalHumanTaskRest/consumeUniversalCurrency.json?audioUrl=
${
audioUrl
}
`
)
}
// 导出视频到我的作品
export
function
createDigitalHumanVideoTask
<
T
>
(
payload
:
object
)
{
return
request
.
post
<
T
>
(
'/aiDigitalHumanTaskRest/createDigitalHumanVideoTask.json'
,
payload
,
{
timeout
:
12000
})
...
...
src/apis/opus.ts
View file @
7aa80c52
...
...
@@ -3,3 +3,7 @@ import { request } from '@/utils/request'
export
function
fetchGetTaskList
<
T
>
(
payload
:
object
)
{
return
request
.
post
<
T
>
(
'/bizDigitalHumanMemberTaskStatusRest/getMemberTaskStatusList.json'
,
payload
)
}
export
function
fetchGetTaskConfig
<
T
>
(
taskConfigId
:
string
)
{
return
request
.
post
<
T
>
(
`/bizDigitalHumanMemberTaskConfigRest/getById.json?id=
${
taskConfigId
}
`
)
}
src/apis/template.ts
View file @
7aa80c52
...
...
@@ -6,6 +6,6 @@ export function fetchDigitalHumanTemplateStatusList<T>(payload: object) {
}
// 根据ID获取推荐模板信息
export
function
fetchDigitalHumanTemplateStatus
<
T
>
(
id
:
number
)
{
export
function
fetchDigitalHumanTemplateStatus
<
T
>
(
id
:
string
)
{
return
request
.
post
<
T
>
(
`/aiDigitalHumanTemplateStatusRest/getDigitalHumanTemplateStatus.json?id=
${
id
}
`
)
}
src/router/modules/creation.ts
View file @
7aa80c52
...
...
@@ -3,12 +3,17 @@ import Creation from '@/views/creation/creation.vue'
export
default
[
{
path
:
'/creation
/:templateId/:draftId?
'
,
path
:
'/creation'
,
name
:
'Creation'
,
meta
:
{
rank
:
1001
,
title
:
'数字人创作'
,
},
component
:
Creation
,
props
:
(
route
)
=>
({
templateId
:
route
.
query
.
templateId
,
draftId
:
route
.
query
.
draftId
,
taskConfigId
:
route
.
query
.
taskConfigId
,
}),
},
]
as
RouteRecordRaw
[]
src/store/modules/audio-setting.ts
View file @
7aa80c52
...
...
@@ -5,6 +5,7 @@ function defaultAudioSetting(): AudioConfig {
return
{
langType
:
LangType
.
CANTONESE
,
voiceType
:
VoiceType
.
CANTONESE_FEMALE
,
consumption
:
0
,
}
}
...
...
@@ -24,6 +25,10 @@ export const useAudioSettingStore = defineStore('audio-setting-store', {
this
.
voiceType
=
voiceType
},
setConsumption
(
consumption
:
number
)
{
this
.
consumption
=
consumption
},
updateAUdioSetting
(
audioSetting
:
AudioConfig
)
{
this
.
$state
=
{
...
this
.
$state
,
...
audioSetting
}
},
...
...
src/store/types/creation.ts
View file @
7aa80c52
...
...
@@ -25,6 +25,7 @@ export enum VoiceType {
export
interface
AudioConfig
{
langType
:
LangType
voiceType
:
VoiceType
consumption
:
number
}
export
interface
DigitalImageItem
{
...
...
src/store/types/template.ts
View file @
7aa80c52
...
...
@@ -24,6 +24,7 @@ export interface DigitalTemplate {
templateName
:
string
taskType
:
TaskType
requestId
:
string
|
null
digitalHumanImageUrl
:
string
|
null
inputImageUrl
:
string
|
null
driveType
:
DriveType
text
:
string
...
...
@@ -32,7 +33,7 @@ export interface DigitalTemplate {
speed
:
string
volume
:
string
pitch
:
string
}
}
|
null
inputAudioUrl
:
string
|
null
callbackUrl
:
string
|
null
figureId
:
string
...
...
@@ -40,7 +41,7 @@ export interface DigitalTemplate {
width
:
number
height
:
number
transparent
:
boolean
}
}
|
null
dhParams
:
{
cameraId
:
number
|
null
position
:
{
...
...
@@ -49,11 +50,11 @@ export interface DigitalTemplate {
w
:
number
h
:
number
}
}
}
|
null
subtitleParams
:
{
subtitlePolicy
:
string
enabled
:
boolean
}
}
|
null
backgroundImageUrl
:
string
|
null
autoAnimoji
:
boolean
enablePalindrome
:
boolean
...
...
@@ -61,9 +62,9 @@ export interface DigitalTemplate {
title
:
string
|
null
logoParams
:
{
logoUrl
:
string
|
null
}
}
|
null
bgmParams
:
{
bgmUrl
:
string
|
null
}
}
|
null
materialUrl
:
string
|
null
}
src/views/creation/components/digital/digital-human.vue
View file @
7aa80c52
...
...
@@ -7,7 +7,7 @@ import {
}
from
'@/apis/digital-creation'
import
{
useDigitalCreationStore
}
from
'@/store/modules/creation'
import
{
DigitalImageItem
,
ImageType
}
from
'@/store/types/creation'
import
{
onMounted
,
ref
,
watch
}
from
'vue'
import
{
onMounted
,
ref
}
from
'vue'
import
DigitalCard
from
'./digital-human-card.vue'
const
digitalCreationStore
=
useDigitalCreationStore
()
...
...
@@ -18,16 +18,6 @@ const allImageList = ref<DigitalImageItem[]>([])
const
showAll
=
ref
(
false
)
const
searchName
=
ref
(
''
)
watch
(
()
=>
[
digitalCreationStore
.
figureId
,
allImageList
.
value
.
length
],
([
figureId
,
len
])
=>
{
if
(
!
digitalCreationStore
.
inputImageUrl
&&
figureId
&&
len
)
{
const
imageUrl
=
allImageList
.
value
.
find
((
i
)
=>
i
.
figureId
===
figureId
)?.
imageUrl
imageUrl
&&
digitalCreationStore
.
setInputImageUrl
(
imageUrl
)
}
},
)
onMounted
(()
=>
{
getDigitalImageList
()
})
...
...
src/views/creation/components/preview-content.vue
View file @
7aa80c52
...
...
@@ -21,20 +21,40 @@ const audioSetting = ref<AudioSetting>({
sampleRate
:
16000
,
content
:
''
,
voiceType
:
VoiceType
.
CANTONESE_FEMALE
,
speed
:
5
,
speed
:
-
0.
5
,
volume
:
5
,
pitch
:
5
,
})
const
ttsSpeedMarks
:
{
[
speed
:
string
]:
number
}
=
{
'3'
:
-
1
,
'4'
:
-
0.8
,
'5'
:
-
0.5
,
'6'
:
0
,
'7'
:
1
,
}
const
resizeObserver
=
new
ResizeObserver
((
entries
)
=>
{
const
{
contentRect
}
=
entries
[
0
]
previewContentWidth
.
value
=
contentRect
.
width
previewContentHeight
.
value
=
contentRect
.
height
})
const
digitalHumanWidth
=
computed
(()
=>
(
digitalCreationStore
.
w
*
previewContentWidth
.
value
!
)
/
1080
)
const
digitalHumanHeight
=
computed
(()
=>
(
digitalCreationStore
.
h
*
previewContentHeight
.
value
!
)
/
1920
)
const
digitalHumanLeft
=
computed
(()
=>
(
digitalCreationStore
.
x
*
previewContentWidth
.
value
!
)
/
1080
)
const
digitalHumanTop
=
computed
(()
=>
(
digitalCreationStore
.
y
*
previewContentHeight
.
value
!
)
/
1920
)
const
isLandscape
=
computed
(()
=>
digitalCreationStore
.
width
>
digitalCreationStore
.
height
)
const
digitalHumanWidth
=
computed
(
()
=>
(
digitalCreationStore
.
w
*
previewContentWidth
.
value
)
/
(
isLandscape
.
value
?
1920
:
1080
),
)
const
digitalHumanHeight
=
computed
(
()
=>
(
digitalCreationStore
.
h
*
previewContentHeight
.
value
)
/
(
isLandscape
.
value
?
1080
:
1920
),
)
const
digitalHumanLeft
=
computed
(
()
=>
(
digitalCreationStore
.
x
*
previewContentWidth
.
value
)
/
(
isLandscape
.
value
?
1920
:
1080
),
)
const
digitalHumanTop
=
computed
(
()
=>
(
digitalCreationStore
.
y
*
previewContentHeight
.
value
)
/
(
isLandscape
.
value
?
1080
:
1920
),
)
const
audioUrl
=
computed
({
get
()
{
return
digitalCreationStore
.
inputAudioUrl
||
''
...
...
@@ -87,7 +107,7 @@ function disconnectWebSocket() {
function
sendDataToWebSocket
()
{
audioSetting
.
value
.
content
=
digitalCreationStore
.
text
audioSetting
.
value
.
voiceType
=
audioSettingStore
.
voiceType
audioSetting
.
value
.
speed
=
Number
(
digitalCreationStore
.
speed
)
audioSetting
.
value
.
speed
=
ttsSpeedMarks
[
digitalCreationStore
.
speed
]
audioSetting
.
value
.
volume
=
Number
(
digitalCreationStore
.
volume
)
audioSetting
.
value
.
pitch
=
Number
(
digitalCreationStore
.
pitch
)
websocket
.
send
(
JSON
.
stringify
(
audioSetting
.
value
))
...
...
@@ -106,12 +126,13 @@ function controlAudio() {
if
(
audioSetting
.
value
.
content
!==
digitalCreationStore
.
text
||
audioSetting
.
value
.
voiceType
!==
audioSettingStore
.
voiceType
||
audioSetting
.
value
.
speed
!==
Number
(
digitalCreationStore
.
speed
)
||
audioSetting
.
value
.
speed
!==
ttsSpeedMarks
[
digitalCreationStore
.
speed
]
||
audioSetting
.
value
.
volume
!==
Number
(
digitalCreationStore
.
volume
)
||
(
audioSettingStore
.
langType
===
LangType
.
MANDARIN
&&
audioSetting
.
value
.
pitch
!==
Number
(
digitalCreationStore
.
pitch
))
)
{
audioData
.
value
=
''
audioUrl
.
value
=
''
return
}
...
...
@@ -123,7 +144,11 @@ function controlAudio() {
<
template
>
<div
class=
"flex flex-col overflow-hidden rounded-2xl"
>
<div
class=
"flex-1 overflow-hidden bg-gray-200"
>
<div
ref=
"previewContent"
class=
"relative mx-auto aspect-[9/16] h-full overflow-hidden bg-gray-100"
>
<div
ref=
"previewContent"
class=
"relative mx-auto h-full overflow-hidden bg-gray-100"
:class=
"isLandscape ? 'aspect-[16/9]' : 'aspect-[9/16]'"
>
<img
v-show=
"digitalCreationStore.backgroundImageUrl"
:src=
"digitalCreationStore.backgroundImageUrl!"
...
...
@@ -145,20 +170,20 @@ function controlAudio() {
<div
class=
"flex h-12 bg-white px-4"
>
<!--
<div
class=
"flex flex-1 items-center text-lg"
>
00:11:22
</div>
-->
<div
class=
"flex flex-1 items-center justify-center"
>
<CustomIcon
v-if=
"audioData && audioUrl"
class=
"cursor-pointer text-2xl"
:icon=
"audioPlaying ? 'ph:pause' : 'ph:play'"
@
click=
"controlAudio"
/>
<n-button
v-
if=
"!audioData"
v-
else
type=
"info"
:loading=
"isConnected"
:disabled=
"!digitalCreationStore.text"
@
click=
"generatePreview"
>
生成預覽
</n-button
>
<CustomIcon
v-else
class=
"cursor-pointer text-2xl"
:icon=
"audioPlaying ? 'ph:pause' : 'ph:play'"
@
click=
"controlAudio"
/>
</div>
<!--
<div
class=
"flex flex-1 items-center justify-end gap-4"
>
<CustomIcon
class=
"cursor-pointer text-lg"
icon=
"mingcute:volume-line"
/>
...
...
src/views/creation/layout/header-bar.vue
View file @
7aa80c52
<
script
setup
lang=
"ts"
>
import
{
createDigitalHumanVideoTask
,
saveDraftConfig
}
from
'@/apis/digital-creation'
import
{
c
onsumeUniversalCurrency
,
c
reateDigitalHumanVideoTask
,
saveDraftConfig
}
from
'@/apis/digital-creation'
import
{
fetchUniversalCurrency
}
from
'@/apis/user'
import
{
useAudioSettingStore
}
from
'@/store/modules/audio-setting'
import
{
useDigitalCreationStore
}
from
'@/store/modules/creation'
import
{
BaseVideoTask
,
DraftConfig
}
from
'@/store/types/creation'
import
{
onMounted
,
onUnmounted
,
ref
,
watch
}
from
'vue'
import
{
computed
,
onMounted
,
onUnmounted
,
ref
,
watch
}
from
'vue'
import
{
useRouter
}
from
'vue-router'
const
router
=
useRouter
()
const
audioSettingStore
=
useAudioSettingStore
()
const
digitalCreationStore
=
useDigitalCreationStore
()
const
draftName
=
ref
(
''
)
const
userCurrency
=
ref
(
0
)
const
editDraftName
=
ref
(
false
)
const
autoSaveSuccess
=
ref
(
false
)
const
showExportModal
=
ref
(
false
)
const
isExporting
=
ref
(
false
)
const
ratioValue
=
ref
(
720
)
//
const ratioValue = ref(720)
const
ratioList
=
[
{
value
:
720
,
label
:
'720p'
},
{
value
:
1080
,
label
:
'1080p'
},
...
...
@@ -24,26 +27,52 @@ const transparent = [
]
let
timer
:
any
watch
(
()
=>
ratioValue
.
value
,
(
newVal
)
=>
{
if
(
newVal
===
1080
)
{
digitalCreationStore
.
setWidth
(
1080
)
digitalCreationStore
.
setHeight
(
1920
)
const
isLandscape
=
computed
(()
=>
digitalCreationStore
.
width
>
digitalCreationStore
.
height
)
const
ratioValue
=
computed
({
get
()
{
return
Math
.
max
(
digitalCreationStore
.
width
,
digitalCreationStore
.
height
)
===
1920
?
1080
:
720
},
set
(
value
)
{
if
(
value
===
1080
)
{
digitalCreationStore
.
setWidth
(
isLandscape
.
value
?
1920
:
1080
)
digitalCreationStore
.
setHeight
(
isLandscape
.
value
?
1080
:
1920
)
}
else
{
digitalCreationStore
.
setWidth
(
720
)
digitalCreationStore
.
setHeight
(
1280
)
digitalCreationStore
.
setWidth
(
isLandscape
.
value
?
1280
:
720
)
digitalCreationStore
.
setHeight
(
isLandscape
.
value
?
720
:
1280
)
}
},
})
const
consumption
=
computed
({
get
()
{
return
audioSettingStore
.
consumption
},
set
(
value
)
{
audioSettingStore
.
setConsumption
(
value
)
},
})
const
enableExport
=
computed
(()
=>
{
return
digitalCreationStore
.
id
&&
digitalCreationStore
.
backgroundImageUrl
&&
digitalCreationStore
.
inputAudioUrl
})
watch
(
()
=>
digitalCreationStore
.
inputAudioUrl
,
(
newVal
)
=>
{
newVal
&&
calculateConsumption
()
},
)
onMounted
(()
=>
{
getUniversalCurrency
()
timer
=
setInterval
(()
=>
{
!
isExporting
.
value
&&
saveDraft
()
},
5000
)
})
onUnmounted
(()
=>
{
saveDraft
()
clearInterval
(
timer
)
timer
=
null
})
...
...
@@ -73,59 +102,49 @@ async function saveDraft(autoSave: boolean = true) {
}
}
async
function
calculateConsumption
()
{
const
res
=
await
consumeUniversalCurrency
<
number
>
(
digitalCreationStore
.
inputAudioUrl
!
)
if
(
res
.
code
===
0
)
{
consumption
.
value
=
res
.
data
}
}
// 导出视频
function
confirmExport
()
{
if
(
!
digitalCreationStore
.
videoName
)
{
window
.
$message
.
error
(
'請輸入視頻名稱'
)
return
false
}
if
(
!
userCurrency
.
value
)
{
window
.
$message
.
error
(
'餘額不足'
)
return
false
}
createBaseVideoTask
()
}
async
function
createBaseVideoTask
()
{
isExporting
.
value
=
true
const
balance
=
await
getUniversalCurrency
()
if
(
!
balance
)
{
isExporting
.
value
=
false
window
.
$message
.
error
(
'餘額不足'
)
return
}
if
(
!
digitalCreationStore
.
id
)
{
isExporting
.
value
=
false
window
.
$message
.
error
(
'請先保存視頻為草稿'
)
return
}
if
(
!
digitalCreationStore
.
backgroundImageUrl
)
{
isExporting
.
value
=
false
window
.
$message
.
error
(
'請選擇背景圖片'
)
return
}
if
(
!
digitalCreationStore
.
inputAudioUrl
)
{
isExporting
.
value
=
false
window
.
$message
.
error
(
'請生成預覽音頻'
)
return
}
const
payload
:
BaseVideoTask
=
{
draftId
:
digitalCreationStore
.
id
,
draftId
:
digitalCreationStore
.
id
!
,
videoName
:
digitalCreationStore
.
videoName
,
width
:
ratioValue
.
value
===
720
?
720
:
1080
,
height
:
ratioValue
.
value
===
720
?
1280
:
1920
,
width
:
digitalCreationStore
.
width
,
height
:
digitalCreationStore
.
height
,
transparent
:
digitalCreationStore
.
transparent
,
videoType
:
'mp4'
,
audioUrl
:
digitalCreationStore
.
inputAudioUrl
,
audioUrl
:
digitalCreationStore
.
inputAudioUrl
!
,
}
const
res
=
await
createDigitalHumanVideoTask
(
payload
)
if
(
res
.
code
===
0
)
{
window
.
$message
.
success
(
'導出成功'
)
showExportModal
.
value
=
false
router
.
push
(
'/work/videos'
)
router
.
push
(
{
name
:
'WorkVideos'
}
)
}
}
async
function
getUniversalCurrency
()
{
const
res
=
await
fetchUniversalCurrency
<
number
>
()
if
(
res
.
code
===
0
)
{
return
res
.
data
userCurrency
.
value
=
res
.
data
}
}
</
script
>
...
...
@@ -157,7 +176,7 @@ async function getUniversalCurrency() {
<span>
已自動保存
</span>
</div>
<n-button
class=
"!rounded-md"
@
click=
"saveDraft(false)"
>
保存爲草稿
</n-button>
<n-button
class=
"!rounded-md"
type=
"info"
:disabled=
"!
digitalCreationStore.id
"
@
click=
"showExportModal = true"
>
<n-button
class=
"!rounded-md"
type=
"info"
:disabled=
"!
enableExport
"
@
click=
"showExportModal = true"
>
導出視頻
</n-button>
</div>
...
...
@@ -165,7 +184,7 @@ async function getUniversalCurrency() {
</header>
<n-modal
v-model:show=
"showExportModal"
preset=
"dialog"
title=
"導出視頻"
@
after-leave=
"isExporting = false"
>
<n-form
ref=
"formRef"
:label-width=
"1
2
0"
label-placement=
"left"
>
<n-form
ref=
"formRef"
:label-width=
"1
0
0"
label-placement=
"left"
>
<n-form-item
label=
"視頻名稱"
required
>
<n-input
v-model:value=
"digitalCreationStore.videoName"
placeholder=
"請輸入視頻名稱"
/>
</n-form-item>
...
...
@@ -190,6 +209,12 @@ async function getUniversalCurrency() {
<n-form-item
label=
"視頻格式"
required
>
<n-radio
value=
"mp4"
checked
>
MP4
</n-radio>
</n-form-item>
<n-form-item
label=
"剩餘靈豆"
>
<span>
{{
userCurrency
}}
</span>
</n-form-item>
<n-form-item
label=
"生成視頻消耗靈豆"
>
<span>
{{
consumption
}}
</span>
</n-form-item>
</n-form>
<template
#
action
>
<n-button
@
click=
"showExportModal = false"
>
取消
</n-button>
...
...
src/views/creation/layout/index.vue
View file @
7aa80c52
...
...
@@ -5,23 +5,32 @@ import { useDigitalCreationStore } from '@/store/modules/creation'
import
{
DraftConfig
,
LangType
}
from
'@/store/types/creation'
import
{
DigitalTemplate
}
from
'@/store/types/template'
import
{
onMounted
}
from
'vue'
import
{
useRoute
}
from
'vue-router'
import
HeaderBar
from
'./header-bar.vue'
import
MainContent
from
'./main-content.vue'
import
SideBar
from
'./side-bar.vue'
import
{
fetchGetTaskConfig
}
from
'@/apis/opus'
interface
Props
{
templateId
?:
string
draftId
?:
string
taskConfigId
?:
string
}
const
props
=
defineProps
<
Props
>
()
const
route
=
useRoute
()
const
digitalCreationStore
=
useDigitalCreationStore
()
onMounted
(()
=>
{
if
(
route
.
params
.
draftId
)
{
getDraft
(
Number
(
route
.
params
.
draftId
))
}
else
{
getDigitalTemplate
(
Number
(
route
.
params
.
templateId
))
if
(
props
.
templateId
)
{
getDigitalTemplate
(
props
.
templateId
)
}
else
if
(
props
.
draftId
)
{
getDraft
(
props
.
draftId
)
}
else
if
(
props
.
taskConfigId
)
{
getTaskConfig
(
props
.
taskConfigId
)
}
})
async
function
getDigitalTemplate
(
id
:
number
)
{
async
function
getDigitalTemplate
(
id
:
string
)
{
const
res
=
await
fetchDigitalHumanTemplateStatus
<
DigitalTemplate
>
(
id
)
if
(
res
.
code
===
0
)
{
const
digitalTemplate
=
res
.
data
...
...
@@ -33,26 +42,26 @@ async function getDigitalTemplate(id: number) {
videoDuration
:
null
,
taskType
:
digitalTemplate
.
taskType
,
requestId
:
digitalTemplate
.
requestId
,
inputImageUrl
:
nul
l
,
inputImageUrl
:
digitalTemplate
.
digitalHumanImageUr
l
,
driveType
:
digitalTemplate
.
driveType
,
text
:
digitalTemplate
.
text
,
person
:
digitalTemplate
.
ttsParams
.
person
,
speed
:
digitalTemplate
.
ttsParams
.
speed
,
volume
:
digitalTemplate
.
ttsParams
.
volume
,
pitch
:
digitalTemplate
.
ttsParams
.
pitch
,
person
:
digitalTemplate
.
ttsParams
?.
person
||
null
,
speed
:
digitalTemplate
.
ttsParams
?.
speed
||
'5'
,
volume
:
digitalTemplate
.
ttsParams
?.
volume
||
'5'
,
pitch
:
digitalTemplate
.
ttsParams
?.
pitch
||
'5'
,
inputAudioUrl
:
digitalTemplate
.
inputAudioUrl
,
callbackUrl
:
digitalTemplate
.
callbackUrl
,
figureId
:
digitalTemplate
.
figureId
,
width
:
72
0
,
height
:
128
0
,
transparent
:
digitalTemplate
.
videoParams
.
transparent
?
'Y'
:
'N'
,
cameraId
:
digitalTemplate
.
dhParams
.
cameraId
,
x
:
digitalTemplate
.
dhParams
.
position
.
x
||
0
,
y
:
digitalTemplate
.
dhParams
.
position
.
y
||
0
,
w
:
digitalTemplate
.
dhParams
.
position
.
w
||
0
,
h
:
digitalTemplate
.
dhParams
.
position
.
h
||
0
,
subtitlePolicy
:
digitalTemplate
.
subtitleParams
.
subtitlePolicy
,
enabled
:
digitalTemplate
.
subtitleParams
.
enabled
?
'Y'
:
'N'
,
width
:
digitalTemplate
.
videoParams
?.
width
||
108
0
,
height
:
digitalTemplate
.
videoParams
?.
height
||
192
0
,
transparent
:
digitalTemplate
.
videoParams
?
.
transparent
?
'Y'
:
'N'
,
cameraId
:
digitalTemplate
.
dhParams
?.
cameraId
||
null
,
x
:
digitalTemplate
.
dhParams
?
.
position
.
x
||
0
,
y
:
digitalTemplate
.
dhParams
?
.
position
.
y
||
0
,
w
:
digitalTemplate
.
dhParams
?
.
position
.
w
||
0
,
h
:
digitalTemplate
.
dhParams
?
.
position
.
h
||
0
,
subtitlePolicy
:
digitalTemplate
.
subtitleParams
?.
subtitlePolicy
||
'SRT'
,
enabled
:
digitalTemplate
.
subtitleParams
?
.
enabled
?
'Y'
:
'N'
,
backgroundImageUrl
:
digitalTemplate
.
backgroundImageUrl
,
autoAnimoji
:
digitalTemplate
.
autoAnimoji
?
'Y'
:
'N'
,
enablePalindrome
:
digitalTemplate
.
enablePalindrome
?
'Y'
:
'N'
,
...
...
@@ -67,12 +76,19 @@ async function getDigitalTemplate(id: number) {
}
}
async
function
getDraft
(
id
:
number
)
{
async
function
getDraft
(
id
:
string
)
{
const
res
=
await
fetchDraftConfigById
<
DraftConfig
>
(
id
)
if
(
res
.
code
===
0
)
{
digitalCreationStore
.
updateDigitalCreation
(
res
.
data
)
}
}
async
function
getTaskConfig
(
id
:
string
)
{
const
res
=
await
fetchGetTaskConfig
<
DraftConfig
>
(
id
)
if
(
res
.
code
===
0
)
{
digitalCreationStore
.
updateDigitalCreation
(
res
.
data
)
}
}
</
script
>
<
template
>
...
...
src/views/home/components/recent-creation.vue
deleted
100644 → 0
View file @
eec5ddc5
<
script
setup
lang=
"ts"
>
import
{
fetchDraftsList
}
from
'@/apis/drafts'
import
{
DraftConfig
}
from
'@/store/types/creation'
import
{
TaskType
}
from
'@/store/types/template'
import
{
Right
}
from
'@icon-park/vue-next'
import
{
onMounted
,
ref
}
from
'vue'
import
{
useRouter
}
from
'vue-router'
const
router
=
useRouter
()
const
recentCreationList
=
ref
<
DraftConfig
[]
>
([])
onMounted
(()
=>
{
getDraftsList
()
})
async
function
getDraftsList
()
{
const
res
=
await
fetchDraftsList
<
DraftConfig
[]
>
({
pagingInfo
:
{
pageNo
:
1
,
pageSize
:
7
}
})
if
(
res
.
code
===
0
)
{
recentCreationList
.
value
=
res
.
data
}
}
function
formatTaskType
(
taskType
:
TaskType
)
{
switch
(
taskType
)
{
case
TaskType
.
IMAGE_VIDEO
:
{
return
'照片數字人'
}
case
TaskType
.
BASE_VIDEO
:
{
return
'基礎數字人'
}
case
TaskType
.
ADVANCED_VIDEO
:
{
return
'高級數字人'
}
}
}
function
handleGoToDrafts
()
{
router
.
push
(
'/work/draft'
)
}
function
handleClickDraft
(
item
:
DraftConfig
)
{
router
.
push
(
`/creation/
${
item
.
templateId
}
/
${
item
.
id
}
`
)
}
</
script
>
<
template
>
<div
class=
"rounded-[16px] bg-white px-[24px] pb-[16px] pt-[24px]"
>
<div
class=
"flex justify-between text-[18px] text-[#000]"
>
最近創作
<div
class=
"flex h-[22px] cursor-pointer items-center text-[14px] text-[#5b647a]"
@
click=
"handleGoToDrafts"
>
<div>
查看全部
</div>
<Right
theme=
"outline"
size=
"16"
fill=
"#5b647a"
/>
</div>
</div>
<div
class=
"flex flex-wrap justify-between"
>
<div
v-for=
"(item, index) in recentCreationList"
:key=
"index"
>
<div
class=
"mt-[16px] overflow-hidden rounded-[10px]"
@
click=
"handleClickDraft(item)"
>
<div
class=
"relative flex h-[145px] w-[145px] items-center justify-center bg-[#f0f0f0]"
>
<img
:src=
"item.coverUrl!"
class=
"absolute h-full w-full scale-100 cursor-pointer rounded-[12px] object-cover blur-[32px] filter transition-transform duration-300 ease-in-out"
/>
<img
:src=
"item.coverUrl!"
class=
"hover:scale-104 absolute inset-0 aspect-[1] cursor-pointer object-contain transition-transform duration-300 ease-in-out"
/>
<div
class=
"absolute bottom-[8px] left-[8px] cursor-default rounded-[4px] bg-[#000000]/[.5] px-[6px] py-[2px] text-[12px] text-[#FFFFFF]"
>
{{
formatTaskType
(
item
.
taskType
)
}}
</div>
</div>
</div>
<n-ellipsis
class=
"mt-[12px] cursor-default text-[#151b26]"
style=
"max-width: 150px"
>
{{
item
.
draftName
}}
</n-ellipsis>
</div>
</div>
</div>
</
template
>
<
style
lang=
"scss"
>
.n-card
{
max-width
:
146px
;
}
.n-card
.n-card-cover
{
border-radius
:
12px
!
important
;
}
.n-popover__content
{
font-size
:
12px
;
}
.n-popover
:not
(
.n-popover--raw
)
{
color
:
#000
;
background-color
:
#fff
!
important
;
}
.n-card.n-card--bordered
{
border
:
none
!
important
;
}
.n-popover-shared
.n-popover-arrow-wrapper
.n-popover-arrow
{
background-color
:
#fff
!
important
;
}
</
style
>
src/views/workbench/components/recent-creation.vue
View file @
7aa80c52
<
script
setup
lang=
"ts"
>
import
{
fetchDraftsList
}
from
'@/apis/drafts'
import
{
TaskType
}
from
'@/store/types/template'
import
{
formatDateTime
}
from
'@/utils/date-formatter'
import
{
Right
}
from
'@icon-park/vue-next'
import
{
reactive
,
ref
}
from
'vue'
import
{
useRouter
}
from
'vue-router'
import
{
formatDateTime
}
from
'@/utils/date-formatter'
interface
CreationTemplateInfoItem
{
id
:
number
taskType
:
string
taskType
:
TaskType
coverUrl
:
string
modifiedTime
:
string
draftName
:
string
...
...
@@ -47,13 +48,13 @@ function getRecentCreationList() {
})
}
function
creationTypeFormatter
(
type
:
string
)
{
function
creationTypeFormatter
(
type
:
TaskType
)
{
switch
(
type
)
{
case
'IMAGE_VIDEO'
:
case
TaskType
.
IMAGE_VIDEO
:
return
'圖片視頻'
case
'BASE_VIDEO'
:
case
TaskType
.
BASE_VIDEO
:
return
'基礎視頻'
case
'ADVANCED_VIDEO'
:
case
TaskType
.
ADVANCED_VIDEO
:
return
'精編視頻'
default
:
return
'其他內容'
...
...
@@ -61,9 +62,15 @@ function creationTypeFormatter(type: string) {
}
function
handleGoToDrafts
()
{
// router.push('/work/draft')
router
.
push
({
name
:
'WorkDraft'
})
}
function
handleToCreation
(
draftId
:
number
)
{
router
.
push
({
name
:
'Creation'
,
query
:
{
draftId
},
})
}
</
script
>
<
template
>
...
...
@@ -88,6 +95,7 @@ function handleGoToDrafts() {
>
<div
class=
"relative mb-[12px] h-[145px] w-[145px] cursor-pointer overflow-hidden rounded-[12px] bg-[#f3f4fb]"
@
click=
"handleToCreation(templateInfoItem.id)"
>
<img
class=
"z-1 relative h-full w-full object-contain transition-[scale] duration-300 ease-in-out hover:scale-110"
...
...
src/views/workbench/components/recommend-template.vue
View file @
7aa80c52
<
script
setup
lang=
"ts"
>
import
{
fetchDigitalHumanTemplateStatusList
}
from
'@/apis/template.ts'
import
{
DigitalTemplate
}
from
'@/store/types/template.ts'
import
{
DigitalTemplate
,
TemplateType
}
from
'@/store/types/template.ts'
import
{
useInfiniteScroll
}
from
'@vueuse/core'
import
{
computed
,
onMounted
,
ref
}
from
'vue'
import
{
useRouter
}
from
'vue-router'
...
...
@@ -17,9 +17,9 @@ const templateBottomEl = ref<HTMLElement | null>(null)
const
templateClassify
=
[
{
value
:
''
,
label
:
'熱門'
},
{
value
:
'FINANCIAL_MARKETING'
,
label
:
'理財營銷'
},
{
value
:
'EDUCATION_LEARNING'
,
label
:
'教育學習'
},
{
value
:
'FESTIVAL_HOTS_SPOTS'
,
label
:
'節日熱點'
},
{
value
:
TemplateType
.
FINANCIAL_MARKETING
,
label
:
'理財營銷'
},
{
value
:
TemplateType
.
EDUCATION_LEARNING
,
label
:
'教育學習'
},
{
value
:
TemplateType
.
FESTIVAL_HOTS_SPOTS
,
label
:
'節日熱點'
},
]
const
templateList
=
ref
<
DigitalTemplate
[]
>
([])
...
...
@@ -73,7 +73,10 @@ function handleOpenModal(template: DigitalTemplate) {
}
function
handleToCreation
(
template
:
DigitalTemplate
)
{
router
.
push
(
`/creation/
${
template
.
id
}
`
)
router
.
push
({
name
:
'Creation'
,
query
:
{
templateId
:
template
.
id
},
})
}
</
script
>
...
...
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