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
5d52de8c
Commit
5d52de8c
authored
Sep 24, 2024
by
nick zheng
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
https://gitlab.gsstcloud.com/digitalperson/digitalperson-fe
parents
f34da68a
d26ee41a
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
948 additions
and
0 deletions
+948
-0
digital-creation.ts
src/apis/digital-creation.ts
+46
-0
horizontal-tabs.vue
src/components/horizontal-tabs/horizontal-tabs.vue
+37
-0
vertical-tabs.vue
src/components/vertical-tabs/vertical-tabs.vue
+35
-0
creation.ts
src/router/modules/creation.ts
+14
-0
creation.ts
src/store/modules/creation.ts
+76
-0
creation.ts
src/store/types/creation.ts
+60
-0
background-images.vue
...iews/creation/components/background/background-images.vue
+94
-0
background-position.vue
...ws/creation/components/background/background-position.vue
+33
-0
background-setting.vue
...ews/creation/components/background/background-setting.vue
+15
-0
caption-setting.vue
src/views/creation/components/caption/caption-setting.vue
+16
-0
digital-audio.vue
src/views/creation/components/digital/digital-audio.vue
+85
-0
digital-card.vue
src/views/creation/components/digital/digital-card.vue
+35
-0
digital-human.vue
src/views/creation/components/digital/digital-human.vue
+116
-0
digital-position.vue
src/views/creation/components/digital/digital-position.vue
+28
-0
digital-setting.vue
src/views/creation/components/digital/digital-setting.vue
+19
-0
preview-content.vue
src/views/creation/components/preview-content.vue
+29
-0
script-content.vue
src/views/creation/components/script-content.vue
+19
-0
creation.vue
src/views/creation/creation.vue
+7
-0
header-bar.vue
src/views/creation/layout/header-bar.vue
+87
-0
index.vue
src/views/creation/layout/index.vue
+48
-0
main-content.vue
src/views/creation/layout/main-content.vue
+11
-0
side-bar.vue
src/views/creation/layout/side-bar.vue
+38
-0
No files found.
src/apis/digital-creation.ts
0 → 100644
View file @
5d52de8c
import
{
request
}
from
'@/utils/request'
// 根据ID获取推荐模板信息
export
function
fetchDigitalHumanTemplateStatus
<
T
>
(
id
:
number
)
{
return
request
.
post
<
T
>
(
`/aiDigitalHumanTemplateStatusRest/getDigitalHumanTemplateStatus.json?id=
${
id
}
`
)
}
// 获取3D数字人形象信息
export
function
fetch3DImageList
<
T
>
()
{
return
request
.
post
<
T
>
(
'/bizDigitalHumanImageRest/get3DImageList.json'
)
}
// 获取2D精品数字人形象信息
export
function
fetch2DBoutiqueImageList
<
T
>
()
{
return
request
.
post
<
T
>
(
'/bizDigitalHumanImageRest/get2DBoutiqueImageList.json'
)
}
// 获取2D小样本数字人形象信息
export
function
fetch2DFewShotImageList
<
T
>
()
{
return
request
.
post
<
T
>
(
'/bizDigitalHumanImageRest/get2DFewShotImageList.json'
)
}
// 获取背景图
export
function
fetchBackgroundImage
<
T
>
()
{
return
request
.
post
<
T
>
(
'/bizDigitalHumanImageRest/getBackgroundImage.json'
)
}
// 根据人物名称分页获取人物信息
export
function
fetchInfoByImageName
<
T
>
(
imageName
:
string
)
{
return
request
.
post
<
T
>
(
`/bizDigitalHumanImageRest/findByImageName.json?imageName=
${
imageName
}
`
)
}
// 根据音色ID主键获取音色
export
function
fetchDigitalHumanTimbreById
<
T
>
()
{
return
request
.
post
<
T
>
(
'/bizDigitalHumanTimbreRest/getDigitalHumanTimbreById.json'
)
}
// 获取音色列表
export
function
fetchDigitalHumanTimbreList
<
T
>
()
{
return
request
.
post
<
T
>
(
'/bizDigitalHumanTimbreRest/getDigitalHumanTimbreList.json'
)
}
// 模糊查询音色
export
function
fetchTimbreByExample
<
T
>
(
condition
:
string
)
{
return
request
.
post
<
T
>
(
`/bizDigitalHumanTimbreRest/getByExample.json?condition=
${
condition
}
`
)
}
src/components/horizontal-tabs/horizontal-tabs.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
interface
TabItem
{
key
:
number
label
:
string
}
interface
Props
{
value
:
number
list
:
TabItem
[]
}
interface
Emits
{
(
e
:
'update:value'
,
value
:
number
):
void
}
defineProps
<
Props
>
()
const
emit
=
defineEmits
<
Emits
>
()
</
script
>
<
template
>
<div
class=
"border-gray relative flex rounded-full border"
>
<div
v-for=
"(item, index) in list"
:key=
"index"
class=
"z-10 flex h-8 w-20 cursor-pointer items-center justify-center rounded-full"
:class=
"
{ 'text-white': item.key === value }"
@click="emit('update:value', item.key)"
>
{{
item
.
label
}}
</div>
<div
class=
"absolute h-8 w-20 rounded-full bg-blue-500 transition-transform duration-300"
:class=
"`translate-x-$
{value * 20}`"
>
</div>
</div>
</
template
>
src/components/vertical-tabs/vertical-tabs.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
interface
TabItem
{
key
:
string
icon
:
string
label
:
string
}
interface
Props
{
value
:
string
list
:
TabItem
[]
}
interface
Emits
{
(
e
:
'update:value'
,
value
:
string
):
void
}
defineProps
<
Props
>
()
const
emit
=
defineEmits
<
Emits
>
()
</
script
>
<
template
>
<div
class=
"w-20 p-2"
>
<div
v-for=
"(item, index) in list"
:key=
"index"
class=
"mb-2 flex h-16 w-16 cursor-pointer flex-col items-center justify-center rounded-lg"
:class=
"
{ 'bg-blue-100': item.key === value }"
@click="emit('update:value', item.key)"
>
<CustomIcon
class=
"text-2xl"
:icon=
"item.icon"
/>
<div>
{{
item
.
label
}}
</div>
</div>
</div>
</
template
>
src/router/modules/creation.ts
0 → 100644
View file @
5d52de8c
import
{
type
RouteRecordRaw
}
from
'vue-router'
import
Creation
from
'@/views/creation/creation.vue'
export
default
[
{
path
:
'/fe/creation'
,
name
:
'Creation'
,
meta
:
{
rank
:
1001
,
title
:
'数字人创作'
,
},
component
:
Creation
,
},
]
as
RouteRecordRaw
[]
src/store/modules/creation.ts
0 → 100644
View file @
5d52de8c
import
{
defineStore
}
from
'pinia'
import
{
DigitalTemplate
}
from
'@/store/types/creation'
function
defaultDigitalCreation
():
DigitalTemplate
{
return
{
id
:
1
,
templateType
:
'产品营销'
,
videoName
:
'营销视频'
,
taskType
:
'BASE_VIDEO'
,
requestId
:
undefined
,
inputImageUrl
:
undefined
,
driveType
:
'TEXT'
,
text
:
'嗨!我是挥手问候家'
,
ttsParams
:
{
person
:
'5153'
,
speed
:
'5'
,
volume
:
'5'
,
pitch
:
'5'
,
},
inputAudioUrl
:
undefined
,
callbackUrl
:
undefined
,
figureId
:
''
,
videoParams
:
{
width
:
1920
,
height
:
0
,
transparent
:
false
,
},
dhParams
:
{
cameraId
:
undefined
,
position
:
{
x
:
100
,
y
:
111
,
w
:
undefined
,
h
:
undefined
,
},
},
subtitleParams
:
{
subtitlePolicy
:
'SRT'
,
enabled
:
true
,
},
backgroundImageUrl
:
undefined
,
autoAnimoji
:
true
,
enablePalindrome
:
false
,
templateId
:
null
,
title
:
undefined
,
logoParams
:
null
,
bgmParams
:
null
,
materialUrl
:
undefined
,
}
}
function
getLocalState
():
DigitalTemplate
{
return
defaultDigitalCreation
()
}
export
const
useDigitalCreationStore
=
defineStore
(
'digital-creation-store'
,
{
state
:
():
DigitalTemplate
=>
getLocalState
(),
actions
:
{
setFigureId
(
figureId
:
string
|
null
)
{
this
.
figureId
=
figureId
},
setBackgroundImageUrl
(
backgroundImageUrl
:
string
)
{
this
.
backgroundImageUrl
=
backgroundImageUrl
},
updateDigitalCreation
(
digitalCreation
:
DigitalTemplate
)
{
this
.
$state
=
{
...
this
.
$state
,
...
digitalCreation
}
},
resetDigitalCreation
()
{
this
.
$state
=
defaultDigitalCreation
()
},
},
})
src/store/types/creation.ts
0 → 100644
View file @
5d52de8c
export
interface
DigitalTemplate
{
id
:
number
templateType
:
string
videoName
:
string
taskType
:
string
requestId
?:
string
inputImageUrl
?:
string
driveType
:
string
text
:
string
ttsParams
:
{
person
:
string
speed
:
string
volume
:
string
pitch
:
string
}
inputAudioUrl
?:
string
callbackUrl
?:
string
figureId
:
string
|
null
videoParams
:
{
width
:
number
height
:
number
transparent
:
boolean
}
dhParams
:
{
cameraId
?:
number
position
:
{
x
:
number
y
:
number
w
?:
number
h
?:
number
}
}
subtitleParams
:
{
subtitlePolicy
:
string
enabled
:
boolean
}
backgroundImageUrl
?:
string
autoAnimoji
:
boolean
enablePalindrome
:
boolean
templateId
?:
any
title
?:
string
logoParams
?:
any
bgmParams
?:
any
materialUrl
?:
string
}
export
interface
ImageItem
{
id
:
number
imageType
:
ImageType
imageName
:
string
|
null
figureId
:
string
|
null
imageUrl
:
string
}
export
enum
ImageType
{
THREE_D
=
'THREE_D'
,
TWO_D_BOUTIQUE
=
'TWO_D_BOUTIQUE'
,
TWO_D_FEW_SHOT
=
'TWO_D_FEW_SHOT'
,
BACKGROUND
=
'BACKGROUND'
,
}
src/views/creation/components/background/background-images.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
fetchBackgroundImage
}
from
'@/apis/digital-creation'
import
{
useDigitalCreationStore
}
from
'@/store/modules/creation'
import
{
ImageItem
}
from
'@/store/types/creation'
import
{
ref
}
from
'vue'
const
digitalCreationStore
=
useDigitalCreationStore
()
const
imageList
=
ref
<
ImageItem
[]
>
([])
const
uploadLoading
=
ref
(
false
)
const
showCropModal
=
ref
(
false
)
const
loaded
=
ref
(
Array
(
imageList
.
value
.
length
).
fill
(
false
))
getBackgroundImageList
()
async
function
getBackgroundImageList
()
{
const
res
=
await
fetchBackgroundImage
<
ImageItem
[]
>
()
if
(
res
.
code
===
0
)
{
imageList
.
value
=
res
.
data
.
map
((
i
)
=>
({
...
i
,
checked
:
i
.
imageUrl
===
digitalCreationStore
.
backgroundImageUrl
}))
loaded
.
value
=
Array
(
res
.
data
.
length
).
fill
(
false
)
}
}
function
uploadImage
()
{
showCropModal
.
value
=
true
}
function
handleClickImage
(
image
:
ImageItem
)
{
digitalCreationStore
.
setBackgroundImageUrl
(
image
.
imageUrl
)
}
function
handleDelete
()
{
window
.
$dialog
.
warning
({
title
:
'刪除圖片'
,
content
:
'是否刪除該圖片?'
,
positiveText
:
'是'
,
negativeText
:
'否'
,
onPositiveClick
:
()
=>
{
window
.
$message
.
success
(
'刪除成功'
)
},
onNegativeClick
:
()
=>
{
window
.
$message
.
error
(
'刪除失敗'
)
},
})
}
function
onImageLoaded
(
index
:
number
)
{
loaded
.
value
[
index
]
=
true
}
</
script
>
<
template
>
<n-input
round
placeholder=
"搜索"
>
<template
#
prefix
>
<CustomIcon
class=
"text-lg"
icon=
"mingcute:search-line"
/>
</
template
>
</n-input>
<div
class=
"h-4"
></div>
<n-grid
:x-gap=
"12"
:y-gap=
"12"
:cols=
"3"
>
<n-gi>
<n-spin
:show=
"uploadLoading"
>
<label
class=
"h-22 w-22 hover:border-blue flex cursor-pointer flex-col items-center justify-center rounded-lg border border-gray-200"
for=
"upload"
>
<CustomIcon
class=
"text-lg"
icon=
"mingcute:add-line"
/>
</label>
<input
id=
"upload"
type=
"file"
accept=
"image/*"
class=
"hidden"
@
change=
"uploadImage"
/>
<
template
#
description
>
上傳中
</
template
>
</n-spin>
</n-gi>
<n-gi
v-for=
"(image, index) in imageList"
:key=
"index"
>
<n-spin
:show=
"!loaded[index]"
>
<div
class=
"h-22 w-22 group relative cursor-pointer overflow-hidden rounded-lg border border-2"
:class=
"image.imageUrl === digitalCreationStore.backgroundImageUrl ? 'border-blue' : 'border-transparent'"
@
click=
"handleClickImage(image)"
>
<img
class=
"h-full w-full object-contain"
:src=
"image.imageUrl"
@
load=
"onImageLoaded(index)"
/>
<div
class=
"from-gray absolute bottom-0 h-5 w-full bg-gradient-to-t px-1 text-xs leading-5 text-white"
>
{{ image.imageName }}
</div>
<div
class=
"absolute right-1 top-1 hidden h-7 w-7 cursor-pointer items-center justify-center rounded-md bg-black/40 p-1 group-hover:flex"
@
click
.
stop=
"handleDelete"
>
<CustomIcon
icon=
"mi:delete"
class=
"text-lg text-white"
/>
</div>
</div>
</n-spin>
</n-gi>
</n-grid>
<n-modal
v-model:show=
"showCropModal"
preset=
"card"
title=
"裁剪圖片"
>
内容
</n-modal>
</template>
src/views/creation/components/background/background-position.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
const
x
=
ref
(
0
)
const
y
=
ref
(
0
)
const
w
=
ref
(
0
)
const
h
=
ref
(
0
)
const
isLock
=
ref
(
false
)
</
script
>
<
template
>
<div>
背景位置
</div>
<div
class=
"mt-4 flex gap-4"
>
<n-input-number
v-model:value=
"x"
>
<template
#
prefix
>
X
</
template
>
</n-input-number>
<n-input-number
v-model:value=
"y"
>
<
template
#
prefix
>
Y
</
template
>
</n-input-number>
</div>
<div
class=
"mt-4 flex gap-4"
>
<n-input-number
v-model:value=
"w"
>
<
template
#
prefix
>
W
</
template
>
</n-input-number>
<n-input-number
v-model:value=
"h"
>
<
template
#
prefix
>
H
</
template
>
</n-input-number>
</div>
<div
class=
"mt-4 flex items-center justify-between"
>
<span>
鎖定背景
</span>
<n-switch
v-model:value=
"isLock"
/>
</div>
</template>
src/views/creation/components/background/background-setting.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
BackgroundImages
from
'./background-images.vue'
// import BackgroundPosition from './background-position.vue'
</
script
>
<
template
>
<n-tabs
type=
"line"
animated
>
<n-tab-pane
name=
"images"
tab=
"圖片"
>
<BackgroundImages
/>
</n-tab-pane>
<!--
<n-tab-pane
name=
"position"
tab=
"位置"
>
<BackgroundPosition
/>
</n-tab-pane>
-->
</n-tabs>
</
template
>
src/views/creation/components/caption/caption-setting.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
const
active
=
ref
(
false
)
</
script
>
<
template
>
<n-tabs
type=
"line"
animated
>
<n-tab-pane
name=
"caption"
tab=
"字幕"
>
<div
class=
"flex items-center justify-between"
>
<span>
是否開啓
</span>
<n-switch
v-model:value=
"active"
/>
</div>
</n-tab-pane>
</n-tabs>
</
template
>
src/views/creation/components/digital/digital-audio.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
const
pace
=
ref
(
1
)
const
intonation
=
ref
(
1
)
const
showAll
=
ref
(
false
)
const
tabValue
=
ref
(
0
)
const
tablist
=
[
{
label
:
'女性'
,
key
:
0
},
{
label
:
'男性'
,
key
:
1
},
]
</
script
>
<
template
>
<div
v-if=
"!showAll"
>
<div
class=
"relative flex items-center gap-2 rounded-2xl border p-2"
>
<div
class=
"h-16 w-16 rounded-lg bg-gray-200"
></div>
<div
class=
"flex-1 overflow-hidden"
>
<div
class=
"mb-2 flex items-center gap-2"
>
<div
class=
"max-w-24 truncate"
>
度清風
</div>
<CustomIcon
class=
"cursor-pointer text-lg"
icon=
"mingcute:volume-line"
/>
</div>
<div
class=
"flex gap-2"
>
<n-tag
type=
"warning"
round
>
知性大方
</n-tag>
<n-tag
type=
"success"
round
>
客服助理
</n-tag>
<n-tag
type=
"success"
round
>
知性大方
</n-tag>
<n-tag
type=
"warning"
round
>
客服助理
</n-tag>
</div>
</div>
<div
class=
"absolute right-2 top-2"
>
<CustomIcon
class=
"cursor-pointer text-lg"
icon=
"ant-design:swap-outlined"
@
click=
"showAll = true"
/>
</div>
</div>
<div
class=
"mt-4 text-lg"
>
聲音
</div>
<div
class=
"mt-4 flex items-center gap-2"
>
<div
class=
"w-12"
>
語速:
</div>
<n-slider
v-model:value=
"pace"
class=
"flex-1"
:max=
"1.5"
:min=
"0.5"
:step=
"0.25"
/>
<div
class=
"w-10"
>
{{
pace
}}
x
</div>
</div>
<div
class=
"mt-4 flex items-center gap-2"
>
<div
class=
"w-12"
>
語調:
</div>
<n-slider
v-model:value=
"intonation"
class=
"flex-1"
:max=
"5"
:min=
"1"
:step=
"1"
/>
<div
class=
"w-10"
>
{{
intonation
}}
</div>
</div>
</div>
<div
v-else
>
<div
class=
"flex items-center gap-4 pb-3"
>
<n-button
text
@
click=
"showAll = false"
>
<template
#
icon
>
<CustomIcon
class=
"text-lg"
icon=
"mingcute:left-line"
/>
</
template
>
返回
</n-button>
<n-input
round
placeholder=
"搜索"
>
<
template
#
prefix
>
<CustomIcon
class=
"text-lg"
icon=
"mingcute:search-line"
/>
</
template
>
</n-input>
</div>
<div
class=
"flex justify-end pb-3"
>
<HorizontalTabs
v-model:value=
"tabValue"
:list=
"tablist"
/>
</div>
<div>
<div
class=
"flex items-center gap-2 rounded-2xl border p-2"
>
<div
class=
"h-16 w-16 rounded-lg bg-gray-200"
></div>
<div
class=
"flex-1 overflow-hidden"
>
<div
class=
"mb-2 flex items-center gap-2"
>
<div
class=
"max-w-24 truncate"
>
度清風
</div>
<CustomIcon
class=
"cursor-pointer text-lg"
icon=
"mingcute:volume-line"
/>
</div>
<div
class=
"flex gap-2"
>
<n-tag
type=
"warning"
round
>
知性大方
</n-tag>
<n-tag
type=
"success"
round
>
客服助理
</n-tag>
<n-tag
type=
"success"
round
>
知性大方
</n-tag>
<n-tag
type=
"warning"
round
>
客服助理
</n-tag>
</div>
</div>
</div>
</div>
</div>
</template>
src/views/creation/components/digital/digital-card.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
ImageItem
}
from
'@/store/types/creation'
import
{
useDigitalCreationStore
}
from
'@/store/modules/creation'
interface
Props
{
value
:
ImageItem
}
interface
Emits
{
(
e
:
'click'
,
id
:
string
|
null
):
void
}
defineProps
<
Props
>
()
const
emit
=
defineEmits
<
Emits
>
()
const
digitalCreationStore
=
useDigitalCreationStore
()
</
script
>
<
template
>
<div
class=
"hover:border-blue relative h-28 w-16 cursor-pointer overflow-hidden rounded border border-2"
:class=
"digitalCreationStore.figureId === value.figureId ? 'border-blue' : 'border-transparent'"
@
click=
"emit('click', value.figureId)"
>
<img
:src=
"value.imageUrl"
/>
<div
class=
"from-gray absolute bottom-0 h-5 w-full bg-gradient-to-t px-1 text-xs leading-5 text-white"
>
{{
value
.
imageName
}}
</div>
<!--
<CustomIcon
v-if=
"digitalCreationStore.figureId === value.figureId"
icon=
"teenyicons:tick-circle-solid"
class=
"text-blue absolute -left-2 -top-2 text-lg"
/>
-->
</div>
</
template
>
src/views/creation/components/digital/digital-human.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
fetch2DBoutiqueImageList
,
fetch2DFewShotImageList
,
fetch3DImageList
}
from
'@/apis/digital-creation'
import
{
ImageItem
,
ImageType
}
from
'@/store/types/creation'
import
{
onMounted
,
ref
}
from
'vue'
import
DigitalCard
from
'./digital-card.vue'
import
{
useDigitalCreationStore
}
from
'@/store/modules/creation'
const
digitalCreationStore
=
useDigitalCreationStore
()
const
threeDImageList
=
ref
<
ImageItem
[]
>
([])
const
twoDBoutiqueImageList
=
ref
<
ImageItem
[]
>
([])
const
twoDFewShotImageList
=
ref
<
ImageItem
[]
>
([])
const
allImageList
=
ref
<
ImageItem
[]
>
([])
const
showAll
=
ref
(
false
)
onMounted
(()
=>
{
getDigitalImageList
()
})
async
function
getDigitalImageList
()
{
const
[
res1
,
res2
,
res3
]
=
await
Promise
.
all
([
fetch3DImageList
<
ImageItem
[]
>
(),
fetch2DBoutiqueImageList
<
ImageItem
[]
>
(),
fetch2DFewShotImageList
<
ImageItem
[]
>
(),
])
res1
.
code
===
0
&&
(
threeDImageList
.
value
=
res1
.
data
)
res2
.
code
===
0
&&
(
twoDBoutiqueImageList
.
value
=
res2
.
data
)
res3
.
code
===
0
&&
(
twoDFewShotImageList
.
value
=
res3
.
data
)
}
function
handleClickDigitalImage
(
id
:
string
|
null
)
{
digitalCreationStore
.
setFigureId
(
id
)
}
function
handleClickAll
(
imageType
:
ImageType
)
{
switch
(
imageType
)
{
case
ImageType
.
THREE_D
:
allImageList
.
value
=
threeDImageList
.
value
break
case
ImageType
.
TWO_D_BOUTIQUE
:
allImageList
.
value
=
twoDBoutiqueImageList
.
value
break
case
ImageType
.
TWO_D_FEW_SHOT
:
allImageList
.
value
=
twoDFewShotImageList
.
value
break
}
showAll
.
value
=
true
}
</
script
>
<
template
>
<div
v-if=
"!showAll"
>
<div
class=
"pb-4"
>
<div
class=
"flex items-center justify-between pb-3"
>
<span>
3D數字人
</span>
<span
class=
"text-gray cursor-pointer text-xs"
@
click=
"handleClickAll(ImageType.THREE_D)"
>
全部
</span>
</div>
<div
class=
"flex flex-wrap gap-3"
>
<DigitalCard
v-for=
"item in threeDImageList.slice(0, 4)"
:key=
"item.id"
:value=
"item"
@
click=
"handleClickDigitalImage"
/>
</div>
</div>
<div
class=
"pb-4"
>
<div
class=
"flex items-center justify-between pb-3"
>
<span>
2D精品數字人
</span>
<span
class=
"text-gray cursor-pointer text-xs"
@
click=
"handleClickAll(ImageType.TWO_D_BOUTIQUE)"
>
全部
</span>
</div>
<div
class=
"flex flex-wrap gap-3"
>
<DigitalCard
v-for=
"item in twoDBoutiqueImageList.slice(0, 4)"
:key=
"item.id"
:value=
"item"
@
click=
"handleClickDigitalImage"
/>
</div>
</div>
<div
class=
"pb-4"
>
<div
class=
"flex items-center justify-between pb-3"
>
<span>
2D小樣本數字人
</span>
<span
class=
"text-gray cursor-pointer text-xs"
@
click=
"handleClickAll(ImageType.TWO_D_FEW_SHOT)"
>
全部
</span>
</div>
<div
class=
"flex flex-wrap gap-3"
>
<DigitalCard
v-for=
"item in twoDFewShotImageList.slice(0, 4)"
:key=
"item.id"
:value=
"item"
@
click=
"handleClickDigitalImage"
/>
</div>
</div>
</div>
<div
v-else
>
<div
class=
"flex items-center gap-4 pb-3"
>
<n-button
text
@
click=
"showAll = false"
>
<template
#
icon
>
<CustomIcon
class=
"text-lg"
icon=
"mingcute:left-line"
/>
</
template
>
返回
</n-button>
<n-input
round
placeholder=
"搜索"
>
<
template
#
prefix
>
<CustomIcon
class=
"text-lg"
icon=
"mingcute:search-line"
/>
</
template
>
</n-input>
</div>
<div
class=
"flex flex-wrap gap-3"
>
<DigitalCard
v-for=
"item in allImageList"
:key=
"item.id"
:value=
"item"
@
click=
"handleClickDigitalImage"
/>
</div>
</div>
</template>
src/views/creation/components/digital/digital-position.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
const
x
=
ref
(
0
)
const
y
=
ref
(
0
)
const
w
=
ref
(
0
)
const
h
=
ref
(
0
)
</
script
>
<
template
>
<div>
數字人位置
</div>
<div
class=
"mt-4 flex gap-4"
>
<n-input-number
v-model:value=
"x"
>
<template
#
prefix
>
X
</
template
>
</n-input-number>
<n-input-number
v-model:value=
"y"
>
<
template
#
prefix
>
Y
</
template
>
</n-input-number>
</div>
<div
class=
"mt-4 flex gap-4"
>
<n-input-number
v-model:value=
"w"
>
<
template
#
prefix
>
W
</
template
>
</n-input-number>
<n-input-number
v-model:value=
"h"
>
<
template
#
prefix
>
H
</
template
>
</n-input-number>
</div>
</template>
src/views/creation/components/digital/digital-setting.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
DigitalAudio
from
'./digital-audio.vue'
import
DigitalHuman
from
'./digital-human.vue'
import
DigitalPosition
from
'./digital-position.vue'
</
script
>
<
template
>
<n-tabs
type=
"line"
animated
>
<n-tab-pane
name=
"human"
tab=
"選擇"
>
<DigitalHuman
/>
</n-tab-pane>
<n-tab-pane
name=
"position"
tab=
"位置"
>
<DigitalPosition
/>
</n-tab-pane>
<n-tab-pane
name=
"audio"
tab=
"聲音"
>
<DigitalAudio
/>
</n-tab-pane>
</n-tabs>
</
template
>
src/views/creation/components/preview-content.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
useDigitalCreationStore
}
from
'@/store/modules/creation'
const
digitalCreationStore
=
useDigitalCreationStore
()
</
script
>
<
template
>
<div
class=
"flex flex-col overflow-hidden rounded-2xl"
>
<div
class=
"flex-1 overflow-hidden bg-gray-200"
>
<div
class=
"relative mx-auto aspect-[9/16] h-full bg-green-50"
>
<img
v-show=
"digitalCreationStore.backgroundImageUrl"
:src=
"digitalCreationStore.backgroundImageUrl"
class=
"absolute h-full w-full object-cover"
/>
</div>
</div>
<div
class=
"flex bg-white p-4"
>
<div
class=
"flex-1 text-lg"
>
00:11:22
</div>
<div
class=
"flex flex-1 justify-center"
>
<CustomIcon
class=
"cursor-pointer text-2xl"
icon=
"ph:play"
/>
</div>
<div
class=
"flex flex-1 items-center justify-end gap-4"
>
<CustomIcon
class=
"cursor-pointer text-lg"
icon=
"mingcute:volume-line"
/>
<CustomIcon
class=
"cursor-pointer text-lg"
icon=
"mingcute:fullscreen-line"
/>
</div>
</div>
</div>
</
template
>
src/views/creation/components/script-content.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
const
value
=
ref
(
''
)
</
script
>
<
template
>
<div
class=
"rounded-2xl bg-white p-6"
>
<div
class=
"pb-2"
>
脚本
</div>
<n-input
v-model:value=
"value"
type=
"textarea"
:maxlength=
"2000"
show-count
clearable
:autosize=
"
{ minRows: 1, maxRows: 10 }"
/>
</div>
</
template
>
src/views/creation/creation.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
Layout
from
'./layout/index.vue'
</
script
>
<
template
>
<Layout
/>
</
template
>
src/views/creation/layout/header-bar.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
const
showExportModal
=
ref
(
false
)
const
exportForm
=
ref
({
name
:
''
,
ratio
:
''
,
range
:
''
,
format
:
''
,
})
const
ratioList
=
[
{
value
:
'720'
,
label
:
'720p'
},
{
value
:
'1080'
,
label
:
'1080p'
},
]
const
rangeList
=
[
{
value
:
'all'
,
label
:
'全部'
},
{
value
:
'digital'
,
label
:
'僅數字人(透明背景)'
},
]
const
formatList
=
[{
value
:
'mp4'
,
label
:
'MP4'
}]
function
confirmExport
()
{
showExportModal
.
value
=
false
}
</
script
>
<
template
>
<header
class=
"flex h-14 items-center justify-between bg-white px-4"
>
<div
class=
"flex cursor-pointer items-center"
>
<CustomIcon
class=
"text-lg"
icon=
"mingcute:left-line"
/>
<span>
返回
</span>
</div>
<div
class=
"flex items-center"
>
<div
class=
"flex items-center gap-4"
>
<div
class=
"flex items-center gap-2"
>
<CustomIcon
class=
"text-green"
icon=
"ep:success-filled"
/>
<span>
已自動保存
</span>
</div>
<n-button
class=
"!rounded-md"
>
保存爲草稿
</n-button>
<n-button
class=
"!rounded-md"
type=
"info"
@
click=
"showExportModal = true"
>
導出視頻
</n-button>
</div>
</div>
</header>
<n-modal
v-model:show=
"showExportModal"
preset=
"dialog"
title=
"導出視頻"
positive-text=
"導出"
negative-text=
"取消"
@
positive-click=
"confirmExport"
@
negative-click=
"showExportModal = false"
>
<n-form
ref=
"formRef"
:label-width=
"120"
:model=
"exportForm"
label-placement=
"left"
>
<n-form-item
label=
"視頻名稱"
required
>
<n-input
v-model:value=
"exportForm.name"
placeholder=
"請輸入視頻名稱"
/>
</n-form-item>
<n-form-item
label=
"視頻分辨率"
required
>
<n-radio-group
v-model:value=
"exportForm.ratio"
name=
"ratio"
>
<n-space>
<n-radio
v-for=
"ratio in ratioList"
:key=
"ratio.value"
:value=
"ratio.value"
>
{{
ratio
.
label
}}
</n-radio>
</n-space>
</n-radio-group>
</n-form-item>
<n-form-item
label=
"導出範圍"
required
>
<n-radio-group
v-model:value=
"exportForm.range"
name=
"range"
>
<n-space>
<n-radio
v-for=
"range in rangeList"
:key=
"range.value"
:value=
"range.value"
>
{{
range
.
label
}}
</n-radio>
</n-space>
</n-radio-group>
</n-form-item>
<n-form-item
label=
"視頻格式"
required
>
<n-radio-group
v-model:value=
"exportForm.format"
name=
"format"
>
<n-space>
<n-radio
v-for=
"format in formatList"
:key=
"format.value"
:value=
"format.value"
>
{{
format
.
label
}}
</n-radio>
</n-space>
</n-radio-group>
</n-form-item>
</n-form>
</n-modal>
</
template
>
src/views/creation/layout/index.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
fetchDigitalHumanTemplateStatus
}
from
'@/apis/digital-creation'
import
{
DigitalTemplate
}
from
'@/store/types/creation'
import
HeaderBar
from
'./header-bar.vue'
import
MainContent
from
'./main-content.vue'
import
SideBar
from
'./side-bar.vue'
import
{
onMounted
}
from
'vue'
import
{
useDigitalCreationStore
}
from
'@/store/modules/creation'
const
digitalCreationStore
=
useDigitalCreationStore
()
onMounted
(()
=>
{
getDigitalImageList
(
1
)
})
async
function
getDigitalImageList
(
id
:
number
)
{
const
res
=
await
fetchDigitalHumanTemplateStatus
<
DigitalTemplate
>
(
id
)
if
(
res
.
code
===
0
)
{
digitalCreationStore
.
updateDigitalCreation
(
res
.
data
)
}
}
</
script
>
<
template
>
<div
class=
"h-screen bg-[#f3f4fb]"
>
<n-layout
content-class=
"layout-wrapper-content"
class=
"h-full !bg-transparent"
>
<n-layout-header
class=
"!bg-transparent"
>
<HeaderBar
/>
</n-layout-header>
<n-layout
has-sider
class=
"flex-1 !bg-transparent p-4"
>
<n-layout-content
class=
"rounded-2xl !bg-transparent"
>
<MainContent
/>
</n-layout-content>
<n-layout-sider
class=
"!bg-transparent"
width=
"420"
>
<SideBar
/>
</n-layout-sider>
</n-layout>
</n-layout>
</div>
</
template
>
<
style
lang=
"scss"
scoped
>
:deep
(
.layout-wrapper-content
)
{
@apply
flex
flex-col
;
}
</
style
>
src/views/creation/layout/main-content.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
PriviewContent
from
'../components/preview-content.vue'
import
ScriptContent
from
'../components/script-content.vue'
</
script
>
<
template
>
<main
class=
"flex h-full flex-col gap-4"
>
<PriviewContent
class=
"flex-1"
/>
<ScriptContent
/>
</main>
</
template
>
src/views/creation/layout/side-bar.vue
0 → 100644
View file @
5d52de8c
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
import
BackgroundSetting
from
'../components/background/background-setting.vue'
import
CaptionSetting
from
'../components/caption/caption-setting.vue'
import
DigitalSetting
from
'../components/digital/digital-setting.vue'
const
value
=
ref
(
''
)
const
barList
=
[
{
key
:
'digital'
,
label
:
'數字人'
,
icon
:
'icon-park-outline:robot'
,
},
{
key
:
'background'
,
label
:
'背景'
,
icon
:
'icon-park-outline:background-color'
,
},
{
key
:
'caption'
,
label
:
'字幕'
,
icon
:
'icon-park-outline:text-message'
,
},
]
</
script
>
<
template
>
<section
class=
"h-full pl-4"
>
<div
class=
"flex h-full rounded-2xl bg-white"
>
<div
class=
"flex-1 overflow-hidden px-4 py-2"
>
<DigitalSetting
v-if=
"value === 'digital'"
/>
<BackgroundSetting
v-if=
"value === 'background'"
/>
<CaptionSetting
v-if=
"value === 'caption'"
/>
</div>
<VerticalTabs
v-model:value=
"value"
class=
"border-l"
:list=
"barList"
></VerticalTabs>
</div>
</section>
</
template
>
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