Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mengchangaigc
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
姚珂
mengchangaigc
Commits
96e60a33
Commit
96e60a33
authored
Aug 28, 2026
by
黄同智
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
快速创作的首页内容
parent
9c61bde6
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1429 additions
and
2 deletions
+1429
-2
common.scss
apps/web-vue/public/styles/common.scss
+5
-0
index.vue
apps/web-vue/src/layout/index.vue
+2
-2
index.ts
apps/web-vue/src/router/index.ts
+13
-0
CreativeComposer.vue
...e/src/views/quickCreation/components/CreativeComposer.vue
+586
-0
InspirationGallery.vue
...src/views/quickCreation/components/InspirationGallery.vue
+306
-0
InspirationPreviewDialog.vue
...ews/quickCreation/components/InspirationPreviewDialog.vue
+313
-0
ToolGroup.vue
.../web-vue/src/views/quickCreation/components/ToolGroup.vue
+133
-0
index.vue
apps/web-vue/src/views/quickCreation/index.vue
+70
-0
types.ts
apps/web-vue/src/views/quickCreation/types.ts
+1
-0
No files found.
apps/web-vue/public/styles/common.scss
View file @
96e60a33
...
...
@@ -233,3 +233,7 @@ $spacing-values: ();
display
:
none
!
important
;
}
}
.
hide-scroll
:
:-
webkit-scrollbar
{
display
:
none
;
}
\ No newline at end of file
apps/web-vue/src/layout/index.vue
View file @
96e60a33
...
...
@@ -81,7 +81,7 @@ const menus = [
},
{
name
:
'快速创作'
,
path
:
'/'
,
path
:
'/
quickCreation
'
,
icon
:
'add'
,
},
{
...
...
@@ -106,7 +106,7 @@ const menus = [
},
{
name
:
'画布'
,
path
:
'/'
,
path
:
'/
vueFlow
'
,
icon
:
'redraw'
,
},
{
...
...
apps/web-vue/src/router/index.ts
View file @
96e60a33
...
...
@@ -9,6 +9,7 @@ import VideoOutMp4 from '@/views/vue-flow/components/VideoOutMp4.vue'
import
ThreeD
from
'@/views/vue-flow/3d.vue'
import
Layout
from
'@/layout/index.vue'
import
Task
from
'@/views/task/index.vue'
import
QuickCreation
from
'@/views/quickCreation/index.vue'
const
routes
=
[
{
...
...
@@ -42,6 +43,18 @@ const routes = [
]
},
{
path
:
'/quickCreation'
,
component
:
Layout
,
children
:
[
{
path
:
''
,
name
:
'QuickCreation'
,
component
:
QuickCreation
,
meta
:
{
title
:
'快速创作'
,
icon
:
'add'
,
affix
:
true
}
}
]
},
{
path
:
'/zhibo'
,
component
:
Layout
,
children
:
[
...
...
apps/web-vue/src/views/quickCreation/components/CreativeComposer.vue
0 → 100644
View file @
96e60a33
<
template
>
<div>
<section
class=
"creation-box bg-fff round-24"
>
<div
class=
"composer-input p-24"
>
<div
class=
"flex-items-center gap-12 mb-8"
>
<el-button
v-if=
"currentScene"
class=
"scene-tag flex-center px-10 gap-6"
@
click=
"emit('clearScene')"
>
<el-icon>
<component
:is=
"sceneIcons[currentScene.key]"
/>
</el-icon>
<span>
{{
currentScene
.
label
}}
</span>
<el-icon>
<Close
/>
</el-icon>
</el-button>
</div>
<el-input
v-model=
"prompt"
class=
"prompt-input"
type=
"textarea"
resize=
"none"
:rows=
"8"
:placeholder=
"currentScene ? '补充创作要求,例如画面风格、卖点、人群或投放场景' : '参考已上传的图片/视频,生成相关的产品素材。'"
/>
</div>
<div
class=
"relative flex-between gap-16 px-24 py-10"
>
<div
class=
"flex-items-center gap-10 flex-wrap"
>
<template
v-if=
"currentScene"
>
<el-button
v-for=
"action in currentScene.uploads"
:key=
"action"
class=
"tool-btn flex-center gap-6 h-34 px-14"
plain
>
<el-icon>
<Upload
/>
</el-icon>
<span>
{{
action
}}
</span>
</el-button>
<div
v-if=
"currentScene.key === 'product'"
class=
"target-toggle flex-items-center h-34 px-8 round-6 gap-4"
>
<span
class=
" color-888 mr-10"
>
输出目标:
</span>
<el-button
v-for=
"item in outputOptions"
:key=
"item.value"
class=
"target-btn flex-center gap-6 h-28 px-12 round-4"
:class=
"
{ active: outputTarget === item.value }" text
@click="outputTarget = item.value">
<el-icon>
<component
:is=
"item.icon"
/>
</el-icon>
<span>
{{
item
.
label
}}
</span>
</el-button>
</div>
</
template
>
<
template
v-else
>
<el-button
class=
"tool-btn flex-center gap-6 h-34 px-14"
plain
>
<el-icon>
<Link
/>
</el-icon>
<span>
商品 URL/ID
</span>
</el-button>
<el-button
class=
"tool-btn flex-center gap-6 h-34 px-14"
plain
@
click=
"mediaVisible = true"
>
<el-icon>
<Picture
/>
</el-icon>
<span>
媒体素材
</span>
</el-button>
</
template
>
<el-popover
v-model:visible=
"settingVisible"
trigger=
"click"
placement=
"bottom-start"
width=
"334"
popper-class=
"quick-creation-popover"
:teleported=
"false"
:show-arrow=
"false"
:hide-after=
"0"
>
<
template
#
reference
>
<el-button
class=
"tool-btn flex-center gap-6 h-34 px-14"
:class=
"
{ active: settingVisible }"
plain>
<el-icon>
<Operation
/>
</el-icon>
<span>
设置
</span>
<el-icon>
<ArrowDown
/>
</el-icon>
</el-button>
</
template
>
<div
class=
"popover-card bg-fff round-18 p-16"
>
<div
class=
"flex-between"
>
<h3
class=
"lh-20 color-000"
>
视频输出参数设置
</h3>
<span
class=
"soft-pill h-22 lh-22 px-10 round-12 color-888"
>
画质与格式
</span>
</div>
<div
class=
"mt-18"
>
<div
class=
" lh-20 color-000"
>
1. 视频长度 (20 - 120 秒)
</div>
<div
class=
"flex-items-center gap-10 mt-10"
>
<el-button
v-for=
"item in durationOptions"
:key=
"item"
class=
"flex-center h-30 px-20"
:class=
"{ active: duration === item }"
plain
@
click=
"duration = item"
>
{{ item }}s
</el-button>
</div>
<el-slider
v-model=
"duration"
class=
"duration-slider mt-14"
:min=
"20"
:max=
"120"
:step=
"10"
:show-tooltip=
"false"
/>
<p
class=
"mt-4 color-888"
>
当前:
<strong
class=
"color-main"
>
{{ duration }} 秒
</strong></p>
</div>
<div
class=
"mt-18"
>
<div
class=
" lh-20 color-000"
>
2. 视频画面比例
</div>
<div
class=
"flex-items-center gap-10 mt-10"
>
<el-button
class=
"ratio-btn flex-center h-34 px-20"
:class=
"{ active: ratio === 'portrait' }"
plain
@
click=
"ratio = 'portrait'"
>
<span
class=
"phone-icon w-8 h-16 mr-4"
></span>
<span>
9:16 竖屏
</span>
</el-button>
<el-button
class=
"flex-center h-34 px-20"
:class=
"{ active: ratio === 'landscape' }"
plain
@
click=
"ratio = 'landscape'"
>
<span
class=
"screen-icon w-16 h-10 mr-4"
></span>
<span>
16:9 横屏
</span>
</el-button>
</div>
</div>
<div
class=
"setting-row flex-between mt-16 pt-14"
>
<span
class=
" color-000"
>
3. 是否自动去水印并补足
</span>
<el-switch
v-model=
"autoFix"
active-color=
"#9022fd"
/>
</div>
</div>
</el-popover>
<el-popover
v-model:visible=
"modeVisible"
trigger=
"click"
placement=
"bottom-start"
width=
"334"
popper-class=
"quick-creation-popover"
:teleported=
"false"
:show-arrow=
"false"
:hide-after=
"0"
>
<
template
#
reference
>
<el-button
class=
"tool-btn flex-center gap-6 h-34 px-14 round-6 pointer"
:class=
"
{ active: modeVisible }" plain>
<el-icon>
<MagicStick
/>
</el-icon>
<span>
{{
activeMode
.
label
}}
</span>
<el-icon>
<ArrowDown
/>
</el-icon>
</el-button>
</
template
>
<div
class=
"popover-card bg-fff round-18 p-16"
>
<div
class=
"flex-between"
>
<h3
class=
"flex-items-center gap-6 color-000"
>
<el-icon
class=
"color-main"
>
<MagicStick
/>
</el-icon>
<span>
AI大模型模式选择
</span>
</h3>
<span
class=
"soft-pill h-22 lh-22 px-10 round-12 color-main "
>
运算算力
</span>
</div>
<el-button
v-for=
"item in modeOptions"
:key=
"item.value"
class=
"mode-option relative w-full mt-10 p-12 round-6 text-left pointer"
:class=
"{ active: activeMode.value === item.value }"
plain
@
click=
"activeMode = item"
>
<div
class=
"w-full"
>
<div
class=
"lh-20 color-000"
>
{{ item.label }}
<em
class=
"ml-8 "
>
{{ item.badge }}
</em>
</div>
<div
class=
"mt-4 color-888"
>
{{ item.desc }}
</div>
</div>
<span
v-if=
"activeMode.value === item.value"
class=
"mode-dot absolute wh-8 round"
></span>
</el-button>
</div>
</el-popover>
</div>
<el-button
class=
"generate-btn flex-center border-none pointer"
size=
"large"
circle
:icon=
"StarFilled"
/>
</div>
</section>
<div
class=
"flex-center gap-14 flex-wrap mt-18"
>
<el-button
v-for=
"item in scenes"
:key=
"item.key"
class=
"scene-btn flex-center gap-8 h-38 px-20 round-20 bg-fff pointer"
:class=
"{ active: activeScene === item.key }"
plain
@
click=
"emit('selectScene', item.key)"
>
<el-icon
:style=
"{ color: item.color }"
>
<component
:is=
"sceneIcons[item.key]"
/>
</el-icon>
<span>
{{ item.label }}
</span>
</el-button>
</div>
<el-dialog
v-model=
"mediaVisible"
width=
"672"
align-center
append-to-body
class=
"quick-media-dialog"
>
<div
class=
"media-dialog hidden round-12"
>
<div
class=
"flex-between px-18 py-16"
>
<div
class=
"flex-items-center gap-8"
>
<el-icon
class=
"color-main fs-18"
>
<Picture
/>
</el-icon>
<h3
class=
"fs-16 lh-24 color-000"
>
选择参考素材
</h3>
<span
class=
"soft-pill h-22 lh-22 px-10 round-12 color-888"
>
最多选择 5 项
</span>
</div>
<el-button
class=
"close-btn wh-28 p-0 border-none bg-none color-888 pointer"
circle
@
click=
"mediaVisible = false"
>
<el-icon>
<Close
/>
</el-icon>
</el-button>
</div>
<div
class=
"flex-between px-14 pb-14"
>
<div
class=
"media-tabs flex-items-center h-32 p-4 round-8"
>
<el-button
v-for=
"item in mediaTabs"
:key=
"item"
class=
"h-26 px-16 round-6 border-none bg-none pointer"
:class=
"{ active: mediaTab === item }"
text
@
click=
"mediaTab = item"
>
{{ item }}
</el-button>
</div>
<div
class=
"flex-items-center gap-8"
>
<div
class=
"search-mini flex-items-center h-32 w-194 px-10 round-8 bg-fff"
>
<el-icon
class=
"color-888"
>
<Search
/>
</el-icon>
<el-input
v-model=
"mediaKeyword"
class=
"media-search flex-1 minw-0 ml-8 "
placeholder=
"搜索资产..."
/>
</div>
<el-button
class=
"upload-local flex-center gap-6 h-32 px-14 round-8 border-none color-fff pointer"
>
<el-icon>
<Upload
/>
</el-icon>
<span>
本地上传
</span>
</el-button>
</div>
</div>
<div
class=
"media-grid flex flex-wrap gap-12 px-14 pt-14 minh-300"
>
<el-card
v-for=
"item in filteredMaterials"
:key=
"item.id"
class=
"media-card relative w-150 h-152 round-8 hidden border-none pointer text-left"
:class=
"{ selected: selectedMaterials.includes(item.id) }"
shadow=
"never"
@
click=
"toggleMaterial(item.id)"
>
<img
v-if=
"item.image"
:src=
"item.image"
:alt=
"item.name"
class=
"w-full h-full cover"
/>
<span
v-else
class=
"video-placeholder flex-center w-full h-full color-888"
>
VIDEO
</span>
<span
v-if=
"item.kind === '视频'"
class=
"video-tag absolute top-8 right-8 h-18 lh-18 px-6 round-4 color-fff fs-10 "
>
VIDEO
</span>
<span
class=
"media-mask absolute bottom-0 left-0 w-full px-8 py-8 color-fff"
>
<span
class=
"media-name lh-18 ellipsis"
>
{{ item.name }}
</span>
<span
class=
"media-size fs-10"
>
{{ item.size }}
</span>
</span>
</el-card>
</div>
<div
class=
"media-footer flex-between px-18 py-16 mt-18"
>
<span
class=
" color-888"
>
已选择
<strong
class=
"color-main"
>
{{ selectedMaterials.length }}
</strong>
/ 5
个素材
</span>
<div
class=
"flex-items-center gap-10"
>
<el-button
class=
"footer-btn h-36 px-20 round-12 bg-fff pointer"
@
click=
"mediaVisible = false"
>
取消
</el-button>
<el-button
class=
"footer-btn confirm h-36 px-20 round-12 border-none pointer"
type=
"primary"
@
click=
"mediaVisible = false"
>
确认选择
</el-button>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<
script
setup
lang=
"ts"
>
import
{
computed
,
ref
}
from
'vue'
;
import
type
{
Component
}
from
'vue'
;
import
{
ArrowDown
,
Box
,
Close
,
Link
,
StarFilled
,
Monitor
,
Operation
,
Picture
,
Search
,
Upload
,
User
,
VideoCamera
,
}
from
'@element-plus/icons-vue'
;
import
productImg
from
'@/static/image/huaban.png'
;
import
peopleImg
from
'@/static/image/meinv.png'
;
import
detailImg
from
'@/static/image/long.png'
;
import
type
{
SceneKey
}
from
'../types'
;
type
SceneItem
=
{
key
:
SceneKey
;
label
:
string
;
desc
:
string
;
color
:
string
;
uploads
:
string
[];
};
type
ModeOption
=
{
value
:
'light'
|
'standard'
|
'expert'
;
label
:
string
;
badge
:
string
;
desc
:
string
;
};
const
props
=
defineProps
<
{
activeScene
?:
SceneKey
;
}
>
();
const
emit
=
defineEmits
<
{
selectScene
:
[
value
:
SceneKey
];
clearScene
:
[];
}
>
();
const
defaultDesc
=
'参考已上传的图片/视频,生成相关的产品素材。'
;
const
prompt
=
ref
(
''
);
const
mediaVisible
=
ref
(
false
);
const
settingVisible
=
ref
(
false
);
const
modeVisible
=
ref
(
false
);
const
duration
=
ref
(
30
);
const
ratio
=
ref
<
'portrait'
|
'landscape'
>
(
'portrait'
);
const
autoFix
=
ref
(
true
);
const
outputTarget
=
ref
<
'image'
|
'video'
>
(
'video'
);
const
mediaTab
=
ref
(
'全部'
);
const
mediaKeyword
=
ref
(
''
);
const
selectedMaterials
=
ref
<
string
[]
>
([]);
const
scenes
:
SceneItem
[]
=
[
{
key
:
'product'
,
label
:
'产品素材'
,
desc
:
'参考已上传的图片/视频,生成相关的产品素材。'
,
color
:
'#1877ff'
,
uploads
:
[
'上传图片/视频素材'
]
},
{
key
:
'pain'
,
label
:
'痛点对比'
,
desc
:
'参考已上传的图片,生成痛点对比素材。'
,
color
:
'#ff3b55'
,
uploads
:
[
'上传痛点素材'
,
'上传解决痛点素材'
]
},
{
key
:
'process'
,
label
:
'使用过程'
,
desc
:
'参考已上传的图片/视频,生成使用过程视频。'
,
color
:
'#10c887'
,
uploads
:
[
'上传商品图片'
,
'上传使用过程视频'
]
},
{
key
:
'koc'
,
label
:
'koc口播'
,
desc
:
'输入产品卖点与人群场景,生成达人口播素材。'
,
color
:
'#8b1cff'
,
uploads
:
[
'上传商品图片'
,
'上传口播参考'
]
},
{
key
:
'story'
,
label
:
'剧情素材'
,
desc
:
'参考商品素材和目标人群,生成剧情化短视频素材。'
,
color
:
'#ff8200'
,
uploads
:
[
'上传商品素材'
,
'上传剧情参考'
]
},
];
const
sceneIcons
:
Record
<
SceneKey
,
Component
>
=
{
product
:
Box
,
pain
:
Monitor
,
process
:
VideoCamera
,
koc
:
User
,
story
:
VideoCamera
,
};
const
outputOptions
=
[
{
value
:
'image'
as
const
,
label
:
'图片'
,
icon
:
Picture
},
{
value
:
'video'
as
const
,
label
:
'视频'
,
icon
:
VideoCamera
},
];
const
durationOptions
=
[
20
,
30
,
60
,
120
];
const
modeOptions
:
ModeOption
[]
=
[
{
value
:
'light'
,
label
:
'轻量模式'
,
badge
:
'省积分'
,
desc
:
'响应极快,节省50%算力积分(推荐)'
},
{
value
:
'standard'
,
label
:
'标准模式'
,
badge
:
'均衡'
,
desc
:
'高清顺滑,兼顾生成速度与画质'
},
{
value
:
'expert'
,
label
:
'专家高清模式'
,
badge
:
'极高画质'
,
desc
:
'极清画质与细腻质感,适合商业展示'
},
];
const
activeMode
=
ref
<
ModeOption
>
(
modeOptions
[
0
]);
const
materials
=
[
{
id
:
'm1'
,
name
:
'雅诗兰黛精华空瓶主图主体.png'
,
kind
:
'图片'
,
size
:
'1.2 MB'
,
image
:
productImg
},
{
id
:
'm2'
,
name
:
'智能蓝牙音箱白色高对比展示.jpg'
,
kind
:
'图片'
,
size
:
'980 KB'
,
image
:
detailImg
},
{
id
:
'm3'
,
name
:
'模特红裙走秀素材_原画.mp4'
,
kind
:
'视频'
,
size
:
'18.4 MB'
,
image
:
''
},
{
id
:
'm4'
,
name
:
'七夕美妆礼盒_烫礼场景成片.mp4'
,
kind
:
'视频'
,
size
:
'42.6 MB'
,
image
:
''
},
{
id
:
'm5'
,
name
:
'AI生成 精华液晨间护肤场景.jpg'
,
kind
:
'图片'
,
size
:
'2.3 MB'
,
image
:
peopleImg
},
];
const
mediaTabs
=
[
'全部'
,
'图片'
,
'视频'
];
const
currentScene
=
computed
(()
=>
scenes
.
find
((
item
)
=>
item
.
key
===
props
.
activeScene
));
const
filteredMaterials
=
computed
(()
=>
{
const
keyword
=
mediaKeyword
.
value
.
trim
().
toLowerCase
();
return
materials
.
filter
((
item
)
=>
{
const
matchTab
=
mediaTab
.
value
===
'全部'
||
item
.
kind
===
mediaTab
.
value
;
const
matchKeyword
=
!
keyword
||
item
.
name
.
toLowerCase
().
includes
(
keyword
);
return
matchTab
&&
matchKeyword
;
});
});
const
toggleMaterial
=
(
id
:
string
)
=>
{
if
(
selectedMaterials
.
value
.
includes
(
id
))
{
selectedMaterials
.
value
=
selectedMaterials
.
value
.
filter
((
item
)
=>
item
!==
id
);
return
;
}
if
(
selectedMaterials
.
value
.
length
<
5
)
{
selectedMaterials
.
value
=
[...
selectedMaterials
.
value
,
id
];
}
};
</
script
>
<
style
lang=
"scss"
scoped
>
.creation-box
{
border
:
1px
solid
#e3eaf3
;
box-shadow
:
0
2px
8px
rgba
(
15
,
35
,
70
,
.08
);
}
:deep
(
.el-button
+
.el-button
)
{
margin-left
:
0
;
}
:deep
(
.prompt-input
.el-textarea__inner
)
{
min-height
:
72px
!
important
;
padding
:
0
;
border
:
0
;
box-shadow
:
none
;
color
:
#183151
;
background
:
transparent
;
resize
:
none
;
}
:deep
(
.prompt-input
.el-textarea__inner
::placeholder
)
{
color
:
#7890ae
;
}
:deep
(
.quick-creation-popover
)
{
padding
:
0
;
border
:
0
;
border-radius
:
18px
;
background
:
transparent
;
box-shadow
:
none
;
}
:deep
(
.media-search
.el-input__wrapper
)
{
padding
:
0
;
box-shadow
:
none
;
background
:
transparent
;
}
:deep
(
.media-search
.el-input__inner
)
{
height
:
30px
;
font-size
:
12px
;
}
:deep
(
.media-card
.el-card__body
)
{
width
:
100%
;
height
:
100%
;
padding
:
0
;
}
.tool-btn
,
.scene-btn
,
.duration-btn
,
.ratio-btn
,
.footer-btn
{
border
:
1px
solid
#dfe7f2
;
color
:
#183151
;
box-shadow
:
0
2px
6px
rgba
(
21
,
44
,
76
,
.06
);
}
.tool-btn.active
,
.tool-btn
:hover
,
.scene-btn.active
,
.scene-btn
:hover
{
border-color
:
#cf9dff
;
color
:
rgba
(
var
(
--
main-color
)
,
1
);
background
:
#fbf4ff
;
}
.upload-btn
{
border
:
1px
solid
#e2bcff
;
background
:
#fbebff
;
}
.target-toggle
,
.soft-pill
,
.media-tabs
{
background
:
#f3f7fc
;
}
.target-btn
{
color
:
#516986
;
background
:
transparent
;
}
.target-btn.active
{
color
:
rgba
(
var
(
--
main-color
)
,
1
);
background
:
#fff
;
box-shadow
:
0
0
0
1px
#e4c4ff
;
}
.generate-btn
{
color
:
#4c42ff
;
background
:
#eff1ff
;
box-shadow
:
0
2px
6px
rgba
(
77
,
66
,
255
,
.5
);
}
.popover-card
{
border
:
1px
solid
#dfe7f2
;
box-shadow
:
0
14px
36px
rgba
(
20
,
38
,
70
,
.14
);
}
.duration-btn
,
.ratio-btn
{
background
:
#f8fbff
;
}
.duration-btn.active
,
.ratio-btn.active
,
.mode-option.active
{
border-color
:
rgba
(
var
(
--
main-color
)
,
1
);
color
:
rgba
(
var
(
--
main-color
)
,
1
);
background
:
#fbf4ff
;
}
.duration-slider
{
accent-color
:
rgba
(
var
(
--
main-color
)
,
1
);
}
.phone-icon
{
border
:
2px
solid
currentColor
;
}
.screen-icon
{
border
:
2px
solid
currentColor
;
}
.setting-row
{
border-top
:
1px
solid
#edf2f7
;
}
.mode-option
{
height
:
auto
;
justify-content
:
flex-start
;
white-space
:
normal
;
border
:
1px
solid
#dfe7f2
;
background
:
#fbfdff
;
}
:deep
(
.mode-option
>
span
)
{
width
:
100%
;
}
.mode-option
em
{
color
:
#7894b4
;
font-style
:
normal
;
}
.mode-dot
{
top
:
24px
;
right
:
12px
;
background
:
rgba
(
var
(
--
main-color
)
,
1
);
}
.search-mini
{
border
:
1px
solid
#dfe7f2
;
}
.media-tabs
button
.active
{
color
:
#183151
;
background
:
#fff
;
box-shadow
:
0
1px
4px
rgba
(
17
,
36
,
62
,
.08
);
}
.upload-local
,
.footer-btn.confirm
{
color
:
#fff
;
background
:
rgba
(
var
(
--
main-color
)
,
1
);
}
.media-card
{
background
:
#eef3f8
;
}
.media-card.selected
{
box-shadow
:
0
0
0
2px
rgba
(
var
(
--
main-color
)
,
1
);
}
.video-placeholder
{
background
:
linear-gradient
(
180deg
,
#f4f7fb
0%
,
#dce5ee
100%
);
}
.video-tag
{
background
:
rgba
(
34
,
44
,
58
,
.72
);
}
.media-mask
{
background
:
linear-gradient
(
180deg
,
transparent
0%
,
rgba
(
18
,
25
,
38
,
.72
)
35%
,
rgba
(
18
,
25
,
38
,
.9
)
100%
);
}
.media-name
,
.media-size
{
display
:
block
;
}
.media-footer
{
border-top
:
1px
solid
#edf2f7
;
}
.footer-btn
{
border
:
1px
solid
#dfe7f2
;
}
</
style
>
<
style
lang=
"scss"
>
.quick-media-dialog
{
padding
:
0
;
border-radius
:
12px
;
overflow
:
hidden
;
.el-dialog__header
{
display
:
none
;
}
.el-dialog__body
{
padding
:
0
;
}
}
</
style
>
apps/web-vue/src/views/quickCreation/components/InspirationGallery.vue
0 → 100644
View file @
96e60a33
<
template
>
<section>
<div
class=
"flex-between mb-16"
>
<h2
class=
"fs-18 lh-28 fw-700"
>
电商爆款灵感画廊
</h2>
<div
class=
"category-tabs flex-items-center gap-4 h-34 p-4 round-10 bg-fff"
>
<el-button
v-for=
"item in categories"
:key=
"item"
class=
"tab-btn h-26 px-12 round-8 border-none fs-12 fw-700"
:class=
"
{ active: activeCategory === item }"
text
@click="activeCategory = item"
>
{{
item
}}
</el-button>
</div>
</div>
<div
class=
"gallery-list flex flex-wrap gap-20"
>
<el-card
v-for=
"(item, index) in filteredList"
:key=
"item.title"
class=
"gallery-card flex-item round-14 hidden pointer"
shadow=
"never"
@
click=
"openPreview(index)"
>
<div
class=
"image-wrap relative h-240 hidden"
>
<img
:src=
"item.cover"
:alt=
"item.title"
class=
"w-full h-full cover"
/>
<span
class=
"play-btn absolute flex-center wh-50 round color-fff fs-24"
>
<el-icon><VideoPlay
/></el-icon>
</span>
<span
class=
"copy-btn absolute flex-center gap-6 h-30 px-12 round-8 color-fff fs-12 fw-700"
>
<el-icon><MagicStick
/></el-icon>
<span>
一键同款
</span>
</span>
<span
class=
"duration absolute h-20 lh-20 px-6 round-4 color-fff fs-10 fw-700"
>
{{
item
.
duration
}}
</span>
</div>
<div
class=
"p-16"
>
<h3
class=
"fs-14 lh-22 fw-700 ellipsis"
>
{{
item
.
title
}}
</h3>
<div
class=
"flex-between mt-12"
>
<div
class=
"flex-items-center minw-0"
>
<span
class=
"avatar flex-center wh-18 round mr-6 color-fff fs-10"
>
{{
item
.
author
.
slice
(
0
,
1
)
}}
</span>
<span
class=
"fs-12 color-789 ellipsis"
>
{{
item
.
author
}}
</span>
</div>
<div
class=
"flex-items-center gap-10 fs-12 color-789"
>
<span
class=
"flex-items-center gap-4"
>
<el-icon
class=
"like-icon"
><Star
/></el-icon>
{{
item
.
likes
}}
</span>
<span
class=
"flex-items-center gap-4"
>
<el-icon><View
/></el-icon>
{{
item
.
views
}}
</span>
</div>
</div>
</div>
</el-card>
</div>
<InspirationPreviewDialog
v-model=
"previewVisible"
:items=
"filteredList"
:index=
"previewIndex"
/>
</section>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
computed
,
ref
}
from
'vue'
;
import
{
MagicStick
,
Star
,
VideoPlay
,
View
}
from
'@element-plus/icons-vue'
;
import
productImg
from
'@/static/image/huaban.png'
;
import
peopleImg
from
'@/static/image/meinv.png'
;
import
detailImg
from
'@/static/image/long.png'
;
import
InspirationPreviewDialog
from
'./InspirationPreviewDialog.vue'
;
type
GalleryCategory
=
'全部爆款'
|
'日化美妆'
|
'数码科技'
|
'鞋履服饰'
;
type
GalleryItem
=
{
title
:
string
;
author
:
string
;
category
:
GalleryCategory
;
cover
:
string
;
duration
:
string
;
likes
:
number
;
views
:
number
;
heat
:
number
;
prompt
:
string
;
tags
:
string
[];
};
const
categories
:
GalleryCategory
[]
=
[
'全部爆款'
,
'日化美妆'
,
'数码科技'
,
'鞋履服饰'
];
const
activeCategory
=
ref
<
GalleryCategory
>
(
'全部爆款'
);
const
previewVisible
=
ref
(
false
);
const
previewIndex
=
ref
(
0
);
const
galleryList
:
GalleryItem
[]
=
[
{
title
:
'极简日系高奢美妆主视觉视频'
,
author
:
'Mika_Design'
,
category
:
'日化美妆'
,
cover
:
productImg
,
duration
:
'12s'
,
likes
:
1240
,
views
:
8900
,
heat
:
2630
,
prompt
:
'A bottle of luxury cosmetic serum on a minimalist beige sand surface, soft studio lighting, organic shadows, high-end editorial product video.'
,
tags
:
[
'美妆'
,
'日化'
,
'极简高奢'
,
'大理石晨光'
],
},
{
title
:
'时尚轻奢真丝吊带裙模特视频'
,
author
:
'电商爆款制造机'
,
category
:
'鞋履服饰'
,
cover
:
peopleImg
,
duration
:
'10s'
,
likes
:
852
,
views
:
12400
,
heat
:
2280
,
prompt
:
'Fashion model wearing a silk dress in a modern corridor, cinematic walking shot, soft contrast, premium apparel campaign.'
,
tags
:
[
'服饰'
,
'模特'
,
'轻奢'
,
'街拍'
],
},
{
title
:
'多功能不粘锅户外场景画质增强'
,
author
:
'Chef_Creative'
,
category
:
'日化美妆'
,
cover
:
detailImg
,
duration
:
'15s'
,
likes
:
412
,
views
:
3100
,
heat
:
1860
,
prompt
:
'Outdoor cooking scene with non-stick pan, natural daylight, joyful lifestyle composition, clean product close-up.'
,
tags
:
[
'厨具'
,
'户外'
,
'画质增强'
,
'生活方式'
],
},
{
title
:
'智能运动手表多机位动态展示视频'
,
author
:
'Tech_Reviewer'
,
category
:
'数码科技'
,
cover
:
productImg
,
duration
:
'8s'
,
likes
:
981
,
views
:
6540
,
heat
:
1988
,
prompt
:
'Smart sports watch rotating on a clean gray surface, multi-angle product showcase, premium tech lighting.'
,
tags
:
[
'数码'
,
'手表'
,
'动态展示'
,
'科技感'
],
},
{
title
:
'法式复古高帮帆布鞋户外场景视频'
,
author
:
'SoleMate'
,
category
:
'鞋履服饰'
,
cover
:
peopleImg
,
duration
:
'15s'
,
likes
:
1540
,
views
:
11000
,
heat
:
2960
,
prompt
:
'Red canvas sneaker on vivid red background, dynamic product hero shot, energetic streetwear commercial.'
,
tags
:
[
'鞋履'
,
'红色视觉'
,
'户外'
,
'潮流'
],
},
{
title
:
'暮华金箔高脚杯澄澈饮品倾倒视频'
,
author
:
'Mika_Design'
,
category
:
'日化美妆'
,
cover
:
detailImg
,
duration
:
'10s'
,
likes
:
672
,
views
:
4200
,
heat
:
1740
,
prompt
:
'Refreshing drink poured into a glass with mint and lime, dark moody background, crisp bubbles, summer beverage video.'
,
tags
:
[
'饮品'
,
'清爽'
,
'慢动作'
,
'暗调'
],
},
{
title
:
'蓝牙耳机通勤痛点对比短视频'
,
author
:
'Tech_Reviewer'
,
category
:
'数码科技'
,
cover
:
productImg
,
duration
:
'11s'
,
likes
:
736
,
views
:
7820
,
heat
:
2050
,
prompt
:
'Wireless earbuds commute pain point comparison, split scene, clean tech product lighting, fast-paced social video.'
,
tags
:
[
'数码科技'
,
'痛点对比'
,
'通勤'
,
'蓝牙耳机'
],
},
{
title
:
'夏季防晒衣户外试穿种草视频'
,
author
:
'SoleMate'
,
category
:
'鞋履服饰'
,
cover
:
peopleImg
,
duration
:
'13s'
,
likes
:
1188
,
views
:
9340
,
heat
:
2410
,
prompt
:
'Summer sun-protection jacket try-on in outdoor daylight, lightweight fabric detail, natural model movement.'
,
tags
:
[
'服饰'
,
'防晒衣'
,
'试穿'
,
'户外'
],
},
];
const
filteredList
=
computed
(()
=>
{
if
(
activeCategory
.
value
===
'全部爆款'
)
{
return
galleryList
;
}
return
galleryList
.
filter
((
item
)
=>
item
.
category
===
activeCategory
.
value
);
});
const
openPreview
=
(
index
:
number
)
=>
{
previewIndex
.
value
=
index
;
previewVisible
.
value
=
true
;
};
</
script
>
<
style
lang=
"scss"
scoped
>
.category-tabs
,
.gallery-card
{
border
:
1px
solid
#dfe7f2
;
box-shadow
:
0
2px
6px
rgba
(
21
,
44
,
76
,
.05
);
}
:deep
(
.el-button
+
.el-button
)
{
margin-left
:
0
;
}
.tab-btn
{
color
:
#4c6583
;
}
.tab-btn.active
{
color
:
#001a3d
;
background
:
#fff
;
box-shadow
:
0
1px
4px
rgba
(
17
,
36
,
62
,
.1
);
}
.gallery-card
{
flex
:
0
0
calc
((
100%
-
60px
)
/
4
);
background
:
#fff
;
transition
:
border-color
.24s
,
box-shadow
.24s
,
transform
.24s
;
}
:deep
(
.gallery-card
.el-card__body
)
{
padding
:
0
;
}
.image-wrap
img
{
transition
:
transform
.42s
ease
,
filter
.42s
ease
;
}
.gallery-card
:hover
{
border-color
:
rgba
(
var
(
--
main-color
)
,
.55
);
box-shadow
:
0
14px
30px
rgba
(
28
,
46
,
76
,
.14
);
transform
:
translateY
(
-3px
);
}
.gallery-card
:hover
.image-wrap
img
{
filter
:
brightness
(
.88
);
transform
:
scale
(
1
.08
);
}
.play-btn
{
top
:
50%
;
left
:
50%
;
background
:
rgba
(
var
(
--
main-color
)
,
1
);
box-shadow
:
0
10px
24px
rgba
(
var
(
--
main-color
)
,
.34
);
transform
:
translate
(
-50%
,
-50%
);
transition
:
transform
.24s
,
box-shadow
.24s
;
}
.gallery-card
:hover
.play-btn
{
box-shadow
:
0
14px
30px
rgba
(
var
(
--
main-color
)
,
.46
);
transform
:
translate
(
-50%
,
-50%
)
scale
(
1
.12
);
}
.copy-btn
{
left
:
14px
;
bottom
:
12px
;
background
:
rgba
(
var
(
--
main-color
)
,
1
);
box-shadow
:
0
6px
16px
rgba
(
var
(
--
main-color
)
,
.3
);
}
.duration
{
right
:
10px
;
bottom
:
12px
;
background
:
rgba
(
9
,
16
,
28
,
.72
);
}
.avatar
{
flex
:
0
0
auto
;
background
:
linear-gradient
(
135deg
,
#9d19ff
,
#ff8a00
);
}
h3
{
color
:
#001a3d
;
}
.color-789
{
color
:
#7890ae
;
}
.like-icon
{
color
:
#ff4ca0
;
}
@media
(
max-width
:
1280px
)
{
.gallery-card
{
flex-basis
:
calc
((
100%
-
40px
)
/
3
);
}
}
@media
(
max-width
:
900px
)
{
.gallery-card
{
flex-basis
:
calc
((
100%
-
20px
)
/
2
);
}
}
</
style
>
apps/web-vue/src/views/quickCreation/components/InspirationPreviewDialog.vue
0 → 100644
View file @
96e60a33
<
template
>
<Dialog
v-model=
"dialogVisible"
bg-color=
"#fff"
width=
"900"
>
<div
v-if=
"currentItem"
class=
"preview-dialog flex bg-fff hidden"
>
<aside
class=
"preview-aside flex-col items-center justify-between py-18"
>
<div
class=
"nav-btn wh-24 flex-center pointer"
@
click=
"prevItem"
>
<el-icon>
<ArrowUp
/>
</el-icon>
</div>
<div
class=
"thumb-list flex-col gap-10"
>
<div
v-for=
"(item, index) in items"
:key=
"item.title"
class=
"thumb-btn w-46 h-58 p-0 round-8 hidden pointer"
:class=
"
{ active: index === activeIndex }" text @click="activeIndex = index">
<img
:src=
"item.cover"
:alt=
"item.title"
class=
"w-full h-full cover"
/>
</div>
</div>
<div
class=
"nav-btn wh-24 flex-center pointer"
@
click=
"nextItem"
>
<el-icon>
<ArrowDown
/>
</el-icon>
</div>
</aside>
<section
class=
"preview-stage relative flex-1 hidden"
>
<img
:src=
"currentItem.cover"
:alt=
"currentItem.title"
class=
"stage-cover w-full h-full cover"
/>
<div
class=
"stage-shade absolute top-0 left-0 w-full h-full"
></div>
<span
class=
"video-badge absolute top-14 left-14 h-22 lh-22 px-8 round-6 color-fff fs-12"
>
{{
currentItem
.
duration
}}
VIDEO
</span>
<span
class=
"play-large absolute flex-center wh-64 round color-fff fs-30"
>
<el-icon>
<VideoPlay
/>
</el-icon>
</span>
<!--
<div
class=
"fake-controls absolute left-16 right-16 bottom-18"
>
<div
class=
"flex-between color-fff mb-10"
>
<div
class=
"flex-items-center gap-18"
>
<el-icon
class=
"fs-20"
>
<VideoPlay
/>
</el-icon>
<span
class=
"fs-16"
>
0:00
</span>
</div>
<div
class=
"flex-items-center gap-20 fs-18"
>
<span>
◔
</span>
<span>
□
</span>
<span>
⋮
</span>
</div>
</div>
<div
class=
"progress-line h-4 round-4"
></div>
</div>
-->
</section>
<section
class=
"preview-info flex-col p-20"
style=
"max-width: 380px;min-width: 380px;"
>
<div
class=
"flex-1 over-y-auto hide-scroll"
>
<div
class=
"flex-items-center gap-10 fs-12 color-789"
>
<span>
创意详情
</span>
<span>
|
</span>
<span
class=
"heat flex-items-center gap-4"
>
<span>
🔥
</span>
<span>
热度
</span>
<strong>
{{
currentItem
.
heat
}}
</strong>
</span>
</div>
<h2
class=
"mt-10 fs-16 lh-30 color-001"
>
{{
currentItem
.
title
}}
</h2>
<div
class=
"flex-items-center gap-8 mt-6"
>
<span
class=
"avatar flex-center wh-22 round color-fff fs-12"
>
{{
currentItem
.
author
.
slice
(
0
,
1
)
}}
</span>
<span
class=
"fs-12 color-334"
>
{{
currentItem
.
author
}}
</span>
<span
class=
"dot wh-4 round"
></span>
<span
class=
"type-tag h-22 lh-22 px-10 round-6 fs-12"
>
视频
</span>
</div>
<div
class=
"flex-between mt-10"
>
<span
class=
"fs-12 color-789"
>
视频提示词
</span>
<el-button
class=
"copy-text h-24 p-0 border-none fs-12 color-main"
text
>
<el-icon>
<CopyDocument
/>
</el-icon>
<span>
复制
</span>
</el-button>
</div>
<div
class=
"prompt-box mt-4 p-10 round-6 fs-12 lh-22 color-334"
>
{{
currentItem
.
prompt
}}
</div>
<div
class=
"mt-20"
>
<div
class=
"fs-12 color-789 mb-10"
>
视频参考图
</div>
<div
class=
"reference-img relative w-96 h-96 round-12 hidden"
>
<img
:src=
"currentItem.cover"
:alt=
"currentItem.title"
class=
"w-full h-full cover"
/>
<span
class=
"source-tag absolute top-8 left-8 h-20 lh-20 px-8 round-6 color-fff fs-10"
>
参考
</span>
</div>
</div>
</div>
<div
class=
"mt-20"
>
<div
class=
"fs-12 color-789 mb-12"
>
视频标签
</div>
<div
class=
"flex-items-center flex-wrap gap-10"
>
<span
v-for=
"tag in currentItem.tags"
:key=
"tag"
class=
"tag-pill h-28 lh-28 px-12 round-14 fs-12 color-main"
>
{{
tag
}}
</span>
</div>
</div>
<div
class=
"dialog-footer flex-items-center mt-20 pt-16"
>
<el-button
class=
"footer-icon wh-32 p-0"
plain
>
<el-icon>
<Star
/>
</el-icon>
</el-button>
<el-button
class=
"footer-icon wh-32 p-0"
plain
>
<el-icon>
<Share
/>
</el-icon>
</el-button>
<el-button
type=
"primary"
class=
"same-btn flex-1"
>
<el-icon>
<MagicStick
/>
</el-icon>
<span>
一键同款
</span>
</el-button>
</div>
</section>
</div>
</Dialog>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
computed
,
ref
,
watch
}
from
'vue'
;
import
{
ArrowDown
,
ArrowUp
,
CopyDocument
,
MagicStick
,
Share
,
Star
,
VideoPlay
}
from
'@element-plus/icons-vue'
;
export
type
InspirationPreviewItem
=
{
title
:
string
;
author
:
string
;
cover
:
string
;
duration
:
string
;
heat
:
number
;
prompt
:
string
;
tags
:
string
[];
};
const
props
=
defineProps
<
{
modelValue
:
boolean
;
items
:
InspirationPreviewItem
[];
index
:
number
;
}
>
();
const
emit
=
defineEmits
<
{
'update:modelValue'
:
[
value
:
boolean
];
}
>
();
const
activeIndex
=
ref
(
0
);
const
dialogVisible
=
computed
({
get
:
()
=>
props
.
modelValue
,
set
:
(
value
)
=>
emit
(
'update:modelValue'
,
value
),
});
const
currentItem
=
computed
(()
=>
props
.
items
[
activeIndex
.
value
]);
watch
(
()
=>
props
.
index
,
(
value
)
=>
{
activeIndex
.
value
=
Math
.
max
(
0
,
Math
.
min
(
value
,
props
.
items
.
length
-
1
));
},
{
immediate
:
true
},
);
const
prevItem
=
()
=>
{
if
(
!
props
.
items
.
length
)
return
;
activeIndex
.
value
=
activeIndex
.
value
===
0
?
props
.
items
.
length
-
1
:
activeIndex
.
value
-
1
;
};
const
nextItem
=
()
=>
{
if
(
!
props
.
items
.
length
)
return
;
activeIndex
.
value
=
activeIndex
.
value
===
props
.
items
.
length
-
1
?
0
:
activeIndex
.
value
+
1
;
};
</
script
>
<
style
lang=
"scss"
scoped
>
.preview-dialog
{
height
:
572px
;
border-radius
:
10px
;
}
.preview-aside
{
flex
:
0
0
74px
;
background
:
#02091d
;
}
.nav-btn
{
&
:hover
{
background-color
:
#ffffff
13
;
border-radius
:
6px
;
}
}
.thumb-list
{
max-height
:
390px
;
overflow
:
hidden
;
}
.thumb-btn
{
border
:
2px
solid
transparent
!
important
;
opacity
:
.58
;
}
.thumb-btn.active
{
border-color
:
rgba
(
var
(
--
main-color
)
,
1
)
!
important
;
opacity
:
1
;
}
:deep
(
.thumb-btn
>
span
)
{
width
:
100%
;
height
:
100%
;
}
.preview-stage
{
background
:
#2f2f2f
;
}
.stage-cover
{
opacity
:
.32
;
filter
:
grayscale
(
.08
);
}
.stage-shade
{
background
:
rgba
(
0
,
0
,
0
,
.36
);
}
.video-badge
,
.source-tag
{
background
:
rgba
(
9
,
13
,
22
,
.76
);
}
.play-large
{
top
:
50%
;
left
:
50%
;
background
:
rgba
(
var
(
--
main-color
)
,
1
);
transform
:
translate
(
-50%
,
-50%
);
}
.fake-controls
{
z-index
:
1
;
}
.progress-line
{
background
:
rgba
(
255
,
255
,
255
,
.36
);
}
.preview-info
{
background
:
#fff
;
}
.heat
{
color
:
#ff8200
;
}
.avatar
{
background
:
linear-gradient
(
135deg
,
#1877ff
,
#9d19ff
);
}
.dot
{
background
:
#d4deeb
;
}
.type-tag
{
color
:
#526f91
;
background
:
#edf3fb
;
}
.prompt-box
{
background
:
#f8fbff
;
border
:
1px
solid
#e6edf5
;
}
.reference-img
{
border
:
1px
solid
#e6edf5
;
}
.tag-pill
{
background
:
#fbf0ff
;
border
:
1px
solid
#ead0ff
;
}
.dialog-footer
{
border-top
:
1px
solid
#edf2f7
;
}
.footer-icon
{
color
:
#526f91
;
border-color
:
#dfe7f2
;
}
.same-btn
{
background
:
rgba
(
var
(
--
main-color
)
,
1
);
border-color
:
rgba
(
var
(
--
main-color
)
,
1
);
}
.color-001
{
color
:
#001a3d
;
}
.color-334
{
color
:
#334b68
;
}
.color-789
{
color
:
#7890ae
;
}
</
style
>
apps/web-vue/src/views/quickCreation/components/ToolGroup.vue
0 → 100644
View file @
96e60a33
<
template
>
<section>
<div
class=
"fs-18 lh-28 fw-700 mb-16"
>
电商核心创意工具组
</div>
<div
class=
"tool-grid flex gap-16"
>
<div
v-for=
"item in tools"
:key=
"item.title"
class=
"core-card flex-col justify-between flex-1 minh-160 p-16 round-14 bg-fff text-left pointer"
:style=
"
{ '--accent': item.color, '--soft': item.bgColor }">
<div>
<span
class=
"core-icon flex-center wh-36 round-10 mb-12 fs-20"
>
<el-icon>
<component
:is=
"item.icon"
/>
</el-icon>
</span>
<div
class=
"lh-22 fw-700"
>
{{
item
.
title
}}
</div>
<p
class=
"fs-12 lh-20"
>
{{
item
.
desc
}}
</p>
</div>
<div
class=
"card-action flex-items-center gap-4 fs-12 fw-700"
>
{{
item
.
action
}}
<el-icon>
<ArrowRight
/>
</el-icon>
</div>
</div>
</div>
</section>
</
template
>
<
script
setup
lang=
"ts"
>
import
type
{
Component
}
from
'vue'
;
import
{
ArrowRight
,
Edit
,
Picture
,
Scissor
,
User
,
ZoomIn
}
from
'@element-plus/icons-vue'
;
type
ToolItem
=
{
title
:
string
;
desc
:
string
;
action
:
string
;
color
:
string
;
bgColor
:
string
;
icon
:
Component
;
};
const
tools
:
ToolItem
[]
=
[
{
title
:
'视频去水印'
,
desc
:
'智能擦除视频水印与遮挡元素'
,
action
:
'立即擦除'
,
color
:
'#ff1f82'
,
bgColor
:
'#fff0f7'
,
icon
:
Edit
,
},
{
title
:
'字幕擦除'
,
desc
:
'一键去除视频字幕与画面文字'
,
action
:
'立即清除'
,
color
:
'#1877ff'
,
bgColor
:
'#edf5ff'
,
icon
:
Scissor
,
},
{
title
:
'画质增强'
,
desc
:
'提升视频清晰度与画作多倍质感'
,
action
:
'立即增强'
,
color
:
'#ff9900'
,
bgColor
:
'#fff8e8'
,
icon
:
ZoomIn
,
},
{
title
:
'数字人分身'
,
desc
:
'高保真克隆音容姿态,输入文本即产出主播视频'
,
action
:
'极速制作'
,
color
:
'#f2187d'
,
bgColor
:
'#fff0f7'
,
icon
:
User
,
},
{
title
:
'模特换衣'
,
desc
:
'上传服装图搭配不同肤色AI模特和逼真场景'
,
action
:
'AI试穿'
,
color
:
'#1877ff'
,
bgColor
:
'#edf5ff'
,
icon
:
Picture
,
},
];
</
script
>
<
style
lang=
"scss"
scoped
>
.core-card
{
height
:
auto
;
white-space
:
normal
;
border
:
1px
solid
#e4ebf4
;
transition
:
border-color
.2s
,
box-shadow
.2s
,
transform
.2s
;
}
:deep
(
.core-card
>
span
)
{
display
:
flex
;
flex
:
1
;
flex-direction
:
column
;
align-items
:
stretch
;
justify-content
:
space-between
;
width
:
100%
;
height
:
100%
;
}
.core-card
p
,
.card-action
{
color
:
#86a0bd
;
}
.core-icon
{
color
:
var
(
--
accent
);
background
:
var
(
--
soft
);
}
.core-card
:hover
{
border-color
:
var
(
--
accent
);
box-shadow
:
0
10px
24px
rgba
(
22
,
37
,
67
,
.1
);
transform
:
translateY
(
-2px
);
}
.core-card
:hover
h3
,
.core-card
:hover
.card-action
{
color
:
var
(
--
accent
);
}
@media
(
max-width
:
1100px
)
{
.tool-grid
{
flex-wrap
:
wrap
;
}
.core-card
{
flex
:
0
0
calc
((
100%
-
16px
)
/
2
);
}
}
</
style
>
apps/web-vue/src/views/quickCreation/index.vue
0 → 100644
View file @
96e60a33
<
template
>
<div
class=
"quick-page h-full over-y-auto py-40"
>
<div
class=
"card-box"
>
<header
class=
"quick-header"
>
<div
class=
"premium-chip items-center gap-6 h-26 px-12 round-14 fs-12 fw-700"
>
<el-icon>
<StarFilled
/>
</el-icon>
<span>
PREMIUM PLATFORM
</span>
</div>
<h1
class=
"mt-8 fs-24 lh-44 fw-700"
>
<span>
梦畅AIGC,
</span>
<span
class=
"gradient-title"
>
为电商而生的 AIGC 平台
</span>
</h1>
</header>
<CreativeComposer
class=
"mt-30"
:active-scene=
"activeScene"
@
select-scene=
"activeScene = $event"
@
clear-scene=
"activeScene = undefined"
/>
</div>
<div
class=
"content"
>
<ToolGroup
class=
"mt-86"
/>
<InspirationGallery
class=
"mt-36"
/>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
;
import
{
StarFilled
}
from
'@element-plus/icons-vue'
;
import
CreativeComposer
from
'./components/CreativeComposer.vue'
;
import
ToolGroup
from
'./components/ToolGroup.vue'
;
import
InspirationGallery
from
'./components/InspirationGallery.vue'
;
import
type
{
SceneKey
}
from
'./types'
;
const
activeScene
=
ref
<
SceneKey
>
();
</
script
>
<
style
scoped
lang=
"scss"
>
.card-box
{
width
:
1400px
;
margin
:
auto
;
}
.content
{
width
:
1600px
;
margin
:
auto
;
}
.quick-page
{
background
:
#f6f9fc
;
}
.quick-header
h1
{
color
:
#001a3d
;
letter-spacing
:
0
;
}
.premium-chip
{
display
:
inline-flex
;
color
:
rgba
(
var
(
--
main-color
)
,
1
);
background
:
#fbf1ff
;
border
:
1px
solid
#efd6ff
;
letter-spacing
:
1
.4px
;
}
.gradient-title
{
background
:
linear-gradient
(
90deg
,
#9d19ff
0%
,
#e01892
48%
,
#ff8a00
100%
);
background-clip
:
text
;
-webkit-background-clip
:
text
;
color
:
transparent
;
}
</
style
>
apps/web-vue/src/views/quickCreation/types.ts
0 → 100644
View file @
96e60a33
export
type
SceneKey
=
'product'
|
'pain'
|
'process'
|
'koc'
|
'story'
;
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