Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
ead30e8c
authored
Nov 06, 2023
by
芋道源码
Committed by
Gitee
Nov 06, 2023
Browse files
Options
Browse Files
Download
Plain Diff
!312 商城装修
Merge pull request !312 from 疯狂的世界/dev
parents
47bb88d8
4253173a
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
1111 additions
and
589 deletions
+1111
-589
src/components/DiyEditor/components/ComponentContainer.vue
+222
-0
src/components/DiyEditor/components/ComponentContainerProperty.vue
+163
-0
src/components/DiyEditor/components/ComponentLibrary.vue
+2
-1
src/components/DiyEditor/components/mobile/Carousel/config.ts
+32
-26
src/components/DiyEditor/components/mobile/Carousel/index.vue
+27
-59
src/components/DiyEditor/components/mobile/Carousel/property.vue
+116
-99
src/components/DiyEditor/components/mobile/ImageBar/config.ts
+27
-0
src/components/DiyEditor/components/mobile/ImageBar/index.vue
+24
-0
src/components/DiyEditor/components/mobile/ImageBar/property.vue
+34
-0
src/components/DiyEditor/components/mobile/NavigationBar/config.ts
+1
-1
src/components/DiyEditor/components/mobile/SearchBar/config.ts
+14
-6
src/components/DiyEditor/components/mobile/SearchBar/index.vue
+1
-6
src/components/DiyEditor/components/mobile/SearchBar/property.vue
+72
-73
src/components/DiyEditor/components/mobile/VideoPlayer/config.ts
+37
-0
src/components/DiyEditor/components/mobile/VideoPlayer/index.vue
+30
-0
src/components/DiyEditor/components/mobile/VideoPlayer/property.vue
+55
-0
src/components/DiyEditor/index.vue
+108
-249
src/components/DiyEditor/util.ts
+62
-1
src/components/UploadFile/src/UploadFile.vue
+39
-16
src/components/VerticalButtonGroup/index.vue
+40
-0
src/layout/components/Footer/src/Footer.vue
+1
-1
src/views/mall/promotion/diy/page/decorate.vue
+2
-26
src/views/mall/promotion/diy/template/decorate.vue
+2
-25
No files found.
src/components/DiyEditor/components/ComponentContainer.vue
0 → 100644
View file @
ead30e8c
<
template
>
<div
:class=
"['component',
{ active: active }]">
<div
:style=
"
{
...style
}"
>
<component
:is=
"component.id"
:property=
"component.property"
/>
</div>
<div
class=
"component-wrap"
>
<!-- 左侧组件名 -->
<div
class=
"component-name"
v-if=
"component.name"
>
{{
component
.
name
}}
</div>
<!-- 左侧:组件操作工具栏 -->
<div
class=
"component-toolbar"
v-if=
"showToolbar && component.name && active"
>
<VerticalButtonGroup
type=
"primary"
>
<el-tooltip
content=
"上移"
placement=
"right"
>
<el-button
:disabled=
"!canMoveUp"
@
click
.
stop=
"handleMoveComponent(-1)"
>
<Icon
icon=
"ep:arrow-up"
/>
</el-button>
</el-tooltip>
<el-tooltip
content=
"下移"
placement=
"right"
>
<el-button
:disabled=
"!canMoveDown"
@
click
.
stop=
"handleMoveComponent(1)"
>
<Icon
icon=
"ep:arrow-down"
/>
</el-button>
</el-tooltip>
<el-tooltip
content=
"复制"
placement=
"right"
>
<el-button
@
click
.
stop=
"handleCopyComponent()"
>
<Icon
icon=
"ep:copy-document"
/>
</el-button>
</el-tooltip>
<el-tooltip
content=
"删除"
placement=
"right"
>
<el-button
@
click
.
stop=
"handleDeleteComponent()"
>
<Icon
icon=
"ep:delete"
/>
</el-button>
</el-tooltip>
</VerticalButtonGroup>
</div>
</div>
</div>
</
template
>
<
script
lang=
"ts"
>
// 注册所有的组件
import
{
components
}
from
'../components/mobile/index'
export
default
{
components
:
{
...
components
}
}
</
script
>
<
script
setup
lang=
"ts"
>
import
{
ComponentStyle
,
DiyComponent
}
from
'@/components/DiyEditor/util'
import
{
propTypes
}
from
'@/utils/propTypes'
import
{
object
}
from
'vue-types'
/**
* 组件容器
* 用于包裹组件,为组件提供 背景、外边距、内边距、边框等样式
*/
defineOptions
({
name
:
'ComponentContainer'
})
type
DiyComponentWithStyle
=
DiyComponent
<
any
>
&
{
property
:
{
style
?:
ComponentStyle
}
}
const
props
=
defineProps
({
component
:
object
<
DiyComponentWithStyle
>
().
isRequired
,
active
:
propTypes
.
bool
.
def
(
false
),
canMoveUp
:
propTypes
.
bool
.
def
(
false
),
canMoveDown
:
propTypes
.
bool
.
def
(
false
),
showToolbar
:
propTypes
.
bool
.
def
(
true
)
})
/**
* 组件样式
*/
const
style
=
computed
(()
=>
{
let
componentStyle
=
props
.
component
.
property
.
style
if
(
!
componentStyle
)
{
return
{}
}
return
{
marginTop
:
`
${
componentStyle
.
marginTop
||
0
}
px`
,
marginBottom
:
`
${
componentStyle
.
marginBottom
||
0
}
px`
,
marginLeft
:
`
${
componentStyle
.
marginLeft
||
0
}
px`
,
marginRight
:
`
${
componentStyle
.
marginRight
||
0
}
px`
,
paddingTop
:
`
${
componentStyle
.
paddingTop
||
0
}
px`
,
paddingRight
:
`
${
componentStyle
.
paddingRight
||
0
}
px`
,
paddingBottom
:
`
${
componentStyle
.
paddingBottom
||
0
}
px`
,
paddingLeft
:
`
${
componentStyle
.
paddingLeft
||
0
}
px`
,
borderTopLeftRadius
:
`
${
componentStyle
.
borderTopLeftRadius
||
0
}
px`
,
borderTopRightRadius
:
`
${
componentStyle
.
borderTopRightRadius
||
0
}
px`
,
borderBottomRightRadius
:
`
${
componentStyle
.
borderBottomRightRadius
||
0
}
px`
,
borderBottomLeftRadius
:
`
${
componentStyle
.
borderBottomLeftRadius
||
0
}
px`
,
overflow
:
'hidden'
,
background
:
componentStyle
.
bgType
===
'color'
?
componentStyle
.
bgColor
:
`url(
${
componentStyle
.
bgImg
}
)`
}
})
const
emits
=
defineEmits
<
{
(
e
:
'move'
,
direction
:
number
):
void
(
e
:
'copy'
):
void
(
e
:
'delete'
):
void
}
>
()
/**
* 移动组件
* @param direction 移动方向
*/
const
handleMoveComponent
=
(
direction
:
number
)
=>
{
emits
(
'move'
,
direction
)
}
/**
* 复制组件
*/
const
handleCopyComponent
=
()
=>
{
emits
(
'copy'
)
}
/**
* 删除组件
*/
const
handleDeleteComponent
=
()
=>
{
emits
(
'delete'
)
}
</
script
>
<
style
scoped
lang=
"scss"
>
$
active-border-width
:
2px
;
$
hover-border-width
:
1px
;
$
name-position
:
-85px
;
$
toolbar-position
:
-55px
;
/* 组件 */
.component
{
position
:
relative
;
cursor
:
move
;
.component-wrap
{
display
:
block
;
position
:
absolute
;
left
:
-
$
active-border-width
;
top
:
0
;
width
:
100%
;
height
:
100%
;
/* 鼠标放到组件上时 */
&:hover
{
border
:
$
hover-border-width
dashed
var
(
--el-color-primary
);
box-shadow
:
0
0
5px
0
rgba
(
24
,
144
,
255
,
0.3
);
.component-name
{
/* 防止加了边框之后,位置移动 */
left
:
$
name-position
-
$
hover-border-width
;
top
:
$
hover-border-width
;
}
}
/* 左侧:组件名称 */
.component-name
{
display
:
block
;
position
:
absolute
;
width
:
80px
;
text-align
:
center
;
line-height
:
25px
;
height
:
25px
;
background
:
#fff
;
font-size
:
12px
;
left
:
$
name-position
;
top
:
$
active-border-width
;
box-shadow
:
0
0
4px
#00000014
,
0
2px
6px
#0000000
f
,
0
4px
8px
2px
#0000000
a
;
/* 右侧小三角 */
&:after
{
position
:
absolute
;
top
:
7.5px
;
right
:
-10px
;
content
:
' '
;
height
:
0
;
width
:
0
;
border
:
5px
solid
transparent
;
border-left-color
:
#fff
;
}
}
/* 右侧:组件操作工具栏 */
.component-toolbar
{
display
:
none
;
position
:
absolute
;
top
:
0
;
right
:
$
toolbar-position
;
/* 左侧小三角 */
&:before
{
position
:
absolute
;
top
:
10px
;
left
:
-10px
;
content
:
' '
;
height
:
0
;
width
:
0
;
border
:
5px
solid
transparent
;
border-right-color
:
#2d8cf0
;
}
}
}
/* 组件选中时 */
&
.active
{
margin-bottom
:
4px
;
.component-wrap
{
border
:
$
active-border-width
solid
var
(
--el-color-primary
)
!important
;
box-shadow
:
0
0
10px
0
rgba
(
24
,
144
,
255
,
0.3
);
margin-bottom
:
$
active-border-width
+
$
active-border-width
;
.component-name
{
background
:
var
(
--el-color-primary
);
color
:
#fff
;
/* 防止加了边框之后,位置移动 */
left
:
$
name-position
-
$
active-border-width
!important
;
top
:
0
!important
;
&:after
{
border-left-color
:
var
(
--el-color-primary
);
}
}
.component-toolbar
{
display
:
block
;
}
}
}
}
</
style
>
src/components/DiyEditor/components/ComponentContainerProperty.vue
0 → 100644
View file @
ead30e8c
<
template
>
<el-tabs
stretch
>
<el-tab-pane
label=
"内容"
>
<slot></slot>
</el-tab-pane>
<el-tab-pane
label=
"样式"
lazy
>
<el-card
header=
"组件样式"
class=
"property-group"
>
<el-form
:model=
"formData"
label-width=
"80px"
>
<el-form-item
label=
"组件背景"
prop=
"bgType"
>
<el-radio-group
v-model=
"formData.bgType"
>
<el-radio
label=
"color"
>
纯色
</el-radio>
<el-radio
label=
"img"
>
图片
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"选择颜色"
prop=
"bgColor"
v-if=
"formData.bgType === 'color'"
>
<ColorInput
v-model=
"formData.bgColor"
/>
</el-form-item>
<el-form-item
label=
"上传图片"
prop=
"bgImg"
v-else
>
<UploadImg
v-model=
"formData.bgImg"
:limit=
"1"
>
<template
#
tip
>
建议宽度 750px
</
template
>
</UploadImg>
</el-form-item>
<el-tree
:data=
"treeData"
:expand-on-click-node=
"false"
>
<
template
#
default=
"{ node, data }"
>
<el-form-item
:label=
"data.label"
:prop=
"data.prop"
:label-width=
"node.level === 1 ? '80px' : '62px'"
class=
"w-full m-b-0!"
>
<el-slider
v-model=
"formData[data.prop]"
:max=
"100"
:min=
"0"
show-input
input-size=
"small"
:show-input-controls=
"false"
@
input=
"handleSliderChange(data.prop)"
/>
</el-form-item>
</
template
>
</el-tree>
<slot
name=
"style"
:formData=
"formData"
></slot>
</el-form>
</el-card>
</el-tab-pane>
</el-tabs>
</template>
<
script
setup
lang=
"ts"
>
import
{
ComponentStyle
,
usePropertyForm
}
from
'@/components/DiyEditor/util'
/**
* 组件容器属性
* 用于包裹组件,为组件提供 背景、外边距、内边距、边框等样式
*/
defineOptions
({
name
:
'ComponentContainer'
})
const
props
=
defineProps
<
{
modelValue
:
ComponentStyle
}
>
()
const
emit
=
defineEmits
([
'update:modelValue'
])
const
{
formData
}
=
usePropertyForm
(
props
.
modelValue
,
emit
)
const
treeData
=
[
{
label
:
'外部边距'
,
prop
:
'margin'
,
children
:
[
{
label
:
'上'
,
prop
:
'marginTop'
},
{
label
:
'右'
,
prop
:
'marginRight'
},
{
label
:
'下'
,
prop
:
'marginBottom'
},
{
label
:
'左'
,
prop
:
'marginLeft'
}
]
},
{
label
:
'内部边距'
,
prop
:
'padding'
,
children
:
[
{
label
:
'上'
,
prop
:
'paddingTop'
},
{
label
:
'右'
,
prop
:
'paddingRight'
},
{
label
:
'下'
,
prop
:
'paddingBottom'
},
{
label
:
'左'
,
prop
:
'paddingLeft'
}
]
},
{
label
:
'边框圆角'
,
prop
:
'borderRadius'
,
children
:
[
{
label
:
'上左'
,
prop
:
'borderTopLeftRadius'
},
{
label
:
'上右'
,
prop
:
'borderTopRightRadius'
},
{
label
:
'下右'
,
prop
:
'borderBottomRightRadius'
},
{
label
:
'下左'
,
prop
:
'borderBottomLeftRadius'
}
]
}
]
const
handleSliderChange
=
(
prop
:
string
)
=>
{
switch
(
prop
)
{
case
'margin'
:
formData
.
value
.
marginTop
=
formData
.
value
.
margin
formData
.
value
.
marginRight
=
formData
.
value
.
margin
formData
.
value
.
marginBottom
=
formData
.
value
.
margin
formData
.
value
.
marginLeft
=
formData
.
value
.
margin
break
case
'padding'
:
formData
.
value
.
paddingTop
=
formData
.
value
.
padding
formData
.
value
.
paddingRight
=
formData
.
value
.
padding
formData
.
value
.
paddingBottom
=
formData
.
value
.
padding
formData
.
value
.
paddingLeft
=
formData
.
value
.
padding
break
case
'borderRadius'
:
formData
.
value
.
borderTopLeftRadius
=
formData
.
value
.
borderRadius
formData
.
value
.
borderTopRightRadius
=
formData
.
value
.
borderRadius
formData
.
value
.
borderBottomRightRadius
=
formData
.
value
.
borderRadius
formData
.
value
.
borderBottomLeftRadius
=
formData
.
value
.
borderRadius
break
}
}
</
script
>
<
style
scoped
lang=
"scss"
>
:deep
(
.el-slider__runway
)
{
margin-right
:
16px
;
}
:deep
(
.el-input-number
)
{
width
:
50px
;
}
</
style
>
src/components/DiyEditor/components/ComponentLibrary.vue
View file @
ead30e8c
<
template
>
<el-aside
class=
"editor-left"
width=
"26
0
px"
>
<el-aside
class=
"editor-left"
width=
"26
1
px"
>
<el-scrollbar>
<el-collapse
v-model=
"extendGroups"
>
<el-collapse-item
...
...
@@ -11,6 +11,7 @@
<draggable
class=
"component-container"
ghost-class=
"draggable-ghost"
item-key=
"index"
:list=
"group.components"
:sort=
"false"
:group=
"
{ name: 'component', pull: 'clone', put: false }"
...
...
src/components/DiyEditor/components/mobile/Carousel/config.ts
View file @
ead30e8c
import
{
DiyComponent
}
from
'@/components/DiyEditor/util'
import
{
ComponentStyle
,
DiyComponent
}
from
'@/components/DiyEditor/util'
/** 轮播图属性 */
export
interface
CarouselProperty
{
// 选择模板
swiperType
:
number
// 图片圆角
borderRadius
:
number
// 页面边距
pageMargin
:
number
// 图片边距
imageMargin
:
number
// 分页类型
pagingType
:
'bullets'
|
'fraction'
|
'progressbar'
// 一行个数
rowIndividual
:
number
// 添加图片
// 类型:默认 | 卡片
type
:
'default'
|
'card'
// 指示器样式:点 | 数字
indicator
:
'dot'
|
'number'
// 是否自动播放
autoplay
:
boolean
// 播放间隔
interval
:
number
// 轮播内容
items
:
CarouselItemProperty
[]
// 组件样式
style
:
ComponentStyle
}
// 轮播内容属性
export
interface
CarouselItemProperty
{
title
:
string
// 类型:图片 | 视频
type
:
'img'
|
'video'
// 图片链接
imgUrl
:
string
link
:
string
// 视频链接
videoUrl
:
string
// 跳转链接
url
:
string
}
// 定义组件
...
...
@@ -30,15 +33,18 @@ export const component = {
name
:
'轮播图'
,
icon
:
'system-uicons:carousel'
,
property
:
{
swiperType
:
0
,
// 选择模板
borderRadius
:
0
,
// 图片圆角
pageMargin
:
0
,
// 页面边距
imageMargin
:
0
,
// 图片边距
pagingType
:
'bullets'
,
// 分页类型
rowIndividual
:
2
,
// 一行个数
type
:
'default'
,
indicator
:
'dot'
,
autoplay
:
false
,
interval
:
3
,
items
:
[
{
imgUrl
:
'https://static.iocoder.cn/mall/banner-01.jpg'
},
{
imgUrl
:
'https://static.iocoder.cn/mall/banner-02.jpg'
}
]
as
CarouselItemProperty
[]
{
type
:
'img'
,
imgUrl
:
'https://static.iocoder.cn/mall/banner-01.jpg'
,
videoUrl
:
''
},
{
type
:
'img'
,
imgUrl
:
'https://static.iocoder.cn/mall/banner-02.jpg'
,
videoUrl
:
''
}
]
as
CarouselItemProperty
[],
style
:
{
bgType
:
'color'
,
bgColor
:
'#fff'
,
marginBottom
:
8
}
as
ComponentStyle
}
}
as
DiyComponent
<
CarouselProperty
>
src/components/DiyEditor/components/mobile/Carousel/index.vue
View file @
ead30e8c
...
...
@@ -6,70 +6,38 @@
>
<Icon
icon=
"tdesign:image"
class=
"text-gray-8 text-120px!"
/>
</div>
<!-- 一行一个 -->
<div
v-if=
"property.swiperType === 0"
class=
"flex flex-col"
:style=
"
{
paddingLeft: property.pageMargin + 'px',
paddingRight: property.pageMargin + 'px'
}"
>
<div
v-for=
"(item, index) in property.items"
:key=
"index"
>
<div
class=
"img-item"
:style=
"
{
marginBottom: property.imageMargin + 'px',
borderRadius: property.borderRadius + 'px'
}"
>
<img
alt=
""
:src=
"item.imgUrl"
/>
<div
v-if=
"item.title"
class=
"title"
>
{{
item
.
title
}}
</div>
</div>
</div>
<div
v-else
class=
"relative"
>
<el-carousel
height=
"174px"
:type=
"property.type === 'card' ? 'card' : ''"
:autoplay=
"property.autoplay"
:interval=
"property.interval * 1000"
:indicator-position=
"property.indicator === 'number' ? 'none' : undefined"
@
change=
"handleIndexChange"
>
<el-carousel-item
v-for=
"(item, index) in property.items"
:key=
"index"
>
<el-image
class=
"h-full w-full"
:src=
"item.imgUrl"
/>
</el-carousel-item>
</el-carousel>
<div
v-if=
"property.indicator === 'number'"
class=
"absolute p-y-2px bottom-10px right-10px rounded-xl bg-black p-x-8px text-10px text-white opacity-40"
>
{{
currentIndex
}}
/
{{
property
.
items
.
length
}}
</div
>
</div>
<el-carousel
height=
"174px"
v-else
:type=
"property.swiperType === 3 ? 'card' : ''"
>
<el-carousel-item
v-for=
"(item, index) in property.items"
:key=
"index"
>
<div
class=
"img-item"
:style=
"
{ borderRadius: property.borderRadius + 'px' }">
<img
alt=
""
:src=
"item.imgUrl"
/>
<div
v-if=
"item.title"
class=
"title"
>
{{
item
.
title
}}
</div>
</div>
</el-carousel-item>
</el-carousel>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
CarouselProperty
}
from
'./config'
/**
页面顶部导航栏
*/
defineOptions
({
name
:
'
NavigationBar
'
})
/**
轮播图
*/
defineOptions
({
name
:
'
Carousel
'
})
const
props
=
defineProps
<
{
property
:
CarouselProperty
}
>
()
</
script
>
defineProps
<
{
property
:
CarouselProperty
}
>
()
<
style
scoped
lang=
"scss"
>
.img-item
{
width
:
100%
;
position
:
relative
;
overflow
:
hidden
;
&:last-child
{
margin
:
0
!important
;
}
/* 图片 */
img
{
width
:
100%
;
height
:
100%
;
display
:
block
;
}
.title
{
height
:
36px
;
width
:
100%
;
background-color
:
rgba
(
51
,
51
,
51
,
0.8
);
text-align
:
center
;
line-height
:
36px
;
color
:
#fff
;
position
:
absolute
;
bottom
:
0
;
left
:
0
;
}
const
currentIndex
=
ref
(
0
)
const
handleIndexChange
=
(
index
:
number
)
=>
{
currentIndex
.
value
=
index
+
1
}
</
style
>
</
script
>
<
style
scoped
lang=
"scss"
></
style
>
src/components/DiyEditor/components/mobile/Carousel/property.vue
View file @
ead30e8c
<
template
>
<el-form
label-width=
"80px"
:model=
"formData"
>
<el-form-item
label=
"选择模板"
prop=
"swiperType"
>
<el-radio-group
v-model=
"formData.swiperType"
>
<el-tooltip
class=
"item"
content=
"一行一个"
placement=
"bottom"
>
<el-radio-button
:label=
"0"
>
<Icon
icon=
"icon-park-twotone:multi-picture-carousel"
/>
</el-radio-button>
</el-tooltip>
<el-tooltip
class=
"item"
content=
"轮播海报"
placement=
"bottom"
>
<el-radio-button
:label=
"1"
>
<Icon
icon=
"system-uicons:carousel"
/>
</el-radio-button>
</el-tooltip>
<el-tooltip
class=
"item"
content=
"多图单行"
placement=
"bottom"
>
<el-radio-button
:label=
"2"
>
<Icon
icon=
"icon-park-twotone:carousel"
/>
</el-radio-button>
</el-tooltip>
<el-tooltip
class=
"item"
content=
"立体轮播"
placement=
"bottom"
>
<el-radio-button
:label=
"3"
>
<Icon
icon=
"ic:round-view-carousel"
/>
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-text
tag=
"p"
>
添加图片
</el-text>
<el-text
type=
"info"
size=
"small"
>
拖动左上角的小圆点可对其排序
</el-text>
<!-- 图片广告 -->
<div
v-if=
"formData.items[0]"
>
<draggable
:list=
"formData.items"
:force-fallback=
"true"
:animation=
"200"
handle=
".drag-icon"
class=
"m-t-8px"
>
<template
#
item=
"
{ element, index }">
<div
class=
"mb-4px flex flex-row gap-4px rounded bg-gray-100 p-8px"
>
<div
class=
"flex flex-col items-start justify-between"
>
<Icon
icon=
"ic:round-drag-indicator"
class=
"drag-icon cursor-move"
/>
<Icon
icon=
"ep:delete"
class=
"cursor-pointer text-red-5"
@
click=
"handleDeleteImage(index)"
v-if=
"formData.items.length > 1"
/>
</div>
<div
class=
"flex flex-1 flex-col items-center justify-between gap-8px"
>
<UploadImg
v-model=
"element.imgUrl"
draggable=
"false"
height=
"80px"
width=
"100%"
class=
"min-w-80px"
/>
<!-- 标题 -->
<el-input
v-model=
"element.title"
placeholder=
"标题,选填"
/>
<!-- 输入链接 -->
<el-input
placeholder=
"链接,选填"
v-model=
"element.link"
/>
</div>
</div>
<ComponentContainerProperty
v-model=
"formData.style"
>
<el-form
label-width=
"80px"
:model=
"formData"
>
<el-card
header=
"样式设置"
class=
"property-group"
shadow=
"never"
>
<el-form-item
label=
"样式"
prop=
"type"
>
<el-radio-group
v-model=
"formData.type"
>
<el-tooltip
class=
"item"
content=
"默认"
placement=
"bottom"
>
<el-radio-button
label=
"default"
>
<Icon
icon=
"system-uicons:carousel"
/>
</el-radio-button>
</el-tooltip>
<el-tooltip
class=
"item"
content=
"卡片"
placement=
"bottom"
>
<el-radio-button
label=
"card"
>
<Icon
icon=
"ic:round-view-carousel"
/>
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"指示器"
prop=
"indicator"
>
<el-radio-group
v-model=
"formData.indicator"
>
<el-radio
label=
"dot"
>
小圆点
</el-radio>
<el-radio
label=
"number"
>
数字
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"是否轮播"
prop=
"autoplay"
>
<el-switch
v-model=
"formData.autoplay"
/>
</el-form-item>
<el-form-item
label=
"播放间隔"
prop=
"interval"
v-if=
"formData.autoplay"
>
<el-slider
v-model=
"formData.interval"
:max=
"10"
:min=
"0.5"
:step=
"0.5"
show-input
input-size=
"small"
:show-input-controls=
"false"
/>
<el-text
type=
"info"
>
单位:秒
</el-text>
</el-form-item>
</el-card>
<el-card
header=
"内容设置"
class=
"property-group"
shadow=
"never"
>
<el-text
type=
"info"
size=
"small"
>
拖动左上角的小圆点可对其排序
</el-text>
<template
v-if=
"formData.items[0]"
>
<draggable
:list=
"formData.items"
:force-fallback=
"true"
:animation=
"200"
handle=
".drag-icon"
class=
"m-t-8px"
item-key=
"index"
>
<template
#
item=
"
{ element, index }">
<div
class=
"content mb-4px flex flex-col gap-4px rounded bg-gray-50 p-8px"
>
<div
class=
"m--8px m-b-8px flex flex-row items-center justify-between bg-gray-100 p-8px"
>
<Icon
icon=
"ic:round-drag-indicator"
class=
"drag-icon cursor-move"
/>
<Icon
icon=
"ep:delete"
class=
"cursor-pointer text-red-5"
@
click=
"handleDeleteImage(index)"
v-if=
"formData.items.length > 1"
/>
</div>
<el-form-item
label=
"类型"
prop=
"type"
class=
"m-b-8px!"
label-width=
"50px"
>
<el-radio-group
v-model=
"element.type"
>
<el-radio
label=
"img"
>
图片
</el-radio>
<el-radio
label=
"video"
>
视频
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"图片"
class=
"m-b-8px!"
label-width=
"50px"
v-if=
"element.type === 'img'"
>
<UploadImg
v-model=
"element.imgUrl"
draggable=
"false"
height=
"80px"
width=
"100%"
class=
"min-w-80px"
/>
</el-form-item>
<template
v-else
>
<el-form-item
label=
"封面"
class=
"m-b-8px!"
label-width=
"50px"
>
<UploadImg
v-model=
"element.imgUrl"
draggable=
"false"
height=
"80px"
width=
"100%"
class=
"min-w-80px"
/>
</el-form-item>
<el-form-item
label=
"视频"
class=
"m-b-8px!"
label-width=
"50px"
>
<UploadFile
v-model=
"element.videoUrl"
:file-type=
"['mp4']"
:limit=
"1"
:file-size=
"100"
class=
"min-w-80px"
/>
</el-form-item>
</
template
>
<el-form-item
label=
"链接"
class=
"m-b-8px!"
label-width=
"50px"
>
<el-input
placeholder=
"链接"
v-model=
"element.url"
/>
</el-form-item>
</div>
</template>
</draggable>
</template>
</draggable>
</div>
<el-button
@
click=
"handleAddImage"
type=
"primary"
plain
class=
"w-full"
>
添加图片
</el-button>
<el-form-item
label=
"一行个数"
prop=
"rowIndividual"
v-show=
"formData.swiperType === 2"
>
<!-- 单选框 -->
<el-radio-group
v-model=
"formData.rowIndividual"
>
<el-radio
:label=
"2"
>
2个
</el-radio>
<el-radio
:label=
"3"
>
3个
</el-radio>
<el-radio
:label=
"4"
>
4个
</el-radio>
<el-radio
:label=
"5"
>
5个
</el-radio>
<el-radio
:label=
"6"
>
6个
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"分页类型"
prop=
"pagingType"
>
<el-radio-group
v-model=
"formData.pagingType"
>
<el-radio
:label=
"0"
>
不显示
</el-radio>
<el-radio
label=
"bullets"
>
样式一
</el-radio>
<el-radio
label=
"fraction"
>
样式二
</el-radio>
<el-radio
label=
"progressbar"
>
样式三
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"图片圆角"
prop=
"borderRadius"
>
<el-slider
v-model=
"formData.borderRadius"
:max=
"30"
/>
</el-form-item>
<el-form-item
label=
"页面边距"
prop=
"pageMargin"
v-show=
"formData.swiperType === 0"
>
<el-slider
v-model=
"formData.pageMargin"
:max=
"20"
/>
</el-form-item>
<el-form-item
label=
"图片边距"
prop=
"imageMargin"
v-show=
"formData.swiperType === 0 || formData.swiperType === 2"
>
<el-slider
v-model=
"formData.imageMargin"
:max=
"20"
/>
</el-form-item>
</el-form>
<el-button
@
click=
"handleAddImage"
type=
"primary"
plain
class=
"w-full"
>
添加图片
</el-button>
</el-card>
</el-form>
</ComponentContainerProperty>
</template>
<
script
setup
lang=
"ts"
>
...
...
@@ -117,7 +134,7 @@ const handleAddImage = () => {
formData
.
value
.
items
.
push
({}
as
CarouselItemProperty
)
}
// 删除图片
const
handleDeleteImage
=
(
index
)
=>
{
const
handleDeleteImage
=
(
index
:
number
)
=>
{
formData
.
value
.
items
.
splice
(
index
,
1
)
}
</
script
>
...
...
src/components/DiyEditor/components/mobile/ImageBar/config.ts
0 → 100644
View file @
ead30e8c
import
{
ComponentStyle
,
DiyComponent
}
from
'@/components/DiyEditor/util'
/** 图片展示属性 */
export
interface
ImageBarProperty
{
// 图片链接
imgUrl
:
string
// 跳转链接
url
:
string
// 组件样式
style
:
ComponentStyle
}
// 定义组件
export
const
component
=
{
id
:
'ImageBar'
,
name
:
'图片展示'
,
icon
:
'ep:picture'
,
property
:
{
imgUrl
:
''
,
url
:
''
,
style
:
{
bgType
:
'color'
,
bgColor
:
'#fff'
,
marginBottom
:
8
}
as
ComponentStyle
}
}
as
DiyComponent
<
ImageBarProperty
>
src/components/DiyEditor/components/mobile/ImageBar/index.vue
0 → 100644
View file @
ead30e8c
<
template
>
<!-- 无图片 -->
<div
class=
"h-50px flex items-center justify-center bg-gray-3"
v-if=
"!property.imgUrl"
>
<Icon
icon=
"ep:picture"
class=
"text-gray-8 text-30px!"
/>
</div>
<el-image
class=
"min-h-30px"
v-else
:src=
"property.imgUrl"
/>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ImageBarProperty
}
from
'./config'
/** 图片展示 */
defineOptions
({
name
:
'ImageBar'
})
defineProps
<
{
property
:
ImageBarProperty
}
>
()
</
script
>
<
style
scoped
lang=
"scss"
>
/* 图片 */
img
{
width
:
100%
;
height
:
100%
;
display
:
block
;
}
</
style
>
src/components/DiyEditor/components/mobile/ImageBar/property.vue
0 → 100644
View file @
ead30e8c
<
template
>
<ComponentContainerProperty
v-model=
"formData.style"
>
<el-form
label-width=
"80px"
:model=
"formData"
>
<el-form-item
label=
"上传图片"
prop=
"imgUrl"
>
<UploadImg
v-model=
"formData.imgUrl"
draggable=
"false"
height=
"80px"
width=
"100%"
class=
"min-w-80px"
>
<template
#
tip
>
建议宽度750
</
template
>
</UploadImg>
</el-form-item>
<el-form-item
label=
"链接"
prop=
"url"
>
<el-input
placeholder=
"链接"
v-model=
"formData.url"
/>
</el-form-item>
</el-form>
</ComponentContainerProperty>
</template>
<
script
setup
lang=
"ts"
>
import
{
ImageBarProperty
}
from
'./config'
import
{
usePropertyForm
}
from
'@/components/DiyEditor/util'
// 图片展示属性面板
defineOptions
({
name
:
'ImageBarProperty'
})
const
props
=
defineProps
<
{
modelValue
:
ImageBarProperty
}
>
()
const
emit
=
defineEmits
([
'update:modelValue'
])
const
{
formData
}
=
usePropertyForm
(
props
.
modelValue
,
emit
)
</
script
>
<
style
scoped
lang=
"scss"
></
style
>
src/components/DiyEditor/components/mobile/NavigationBar/config.ts
View file @
ead30e8c
...
...
@@ -29,7 +29,7 @@ export const component = {
title
:
'页面标题'
,
description
:
''
,
navBarHeight
:
35
,
backgroundColor
:
'#f
5f5f5
'
,
backgroundColor
:
'#f
ff
'
,
backgroundImage
:
''
,
styleType
:
'default'
,
alwaysShow
:
true
,
...
...
src/components/DiyEditor/components/mobile/SearchBar/config.ts
View file @
ead30e8c
import
{
DiyComponent
}
from
'@/components/DiyEditor/util'
import
{
ComponentStyle
,
DiyComponent
}
from
'@/components/DiyEditor/util'
/** 搜索框属性 */
export
interface
SearchProperty
{
...
...
@@ -7,10 +7,10 @@ export interface SearchProperty {
borderRadius
:
number
// 框体样式
placeholder
:
string
// 占位文字
placeholderPosition
:
PlaceholderPosition
// 占位文字位置
backgroundColor
:
string
// 背景颜色
borderColor
:
string
// 框体颜色
backgroundColor
:
string
// 框体颜色
textColor
:
string
// 字体颜色
hotKeywords
:
string
[]
// 热词
style
:
ComponentStyle
}
// 文字位置
...
...
@@ -27,9 +27,17 @@ export const component = {
borderRadius
:
0
,
placeholder
:
'搜索商品'
,
placeholderPosition
:
'left'
,
backgroundColor
:
'rgb(249, 249, 249)'
,
borderColor
:
'rgb(255, 255, 255)'
,
backgroundColor
:
'rgb(238, 238, 238)'
,
textColor
:
'rgb(150, 151, 153)'
,
hotKeywords
:
[]
hotKeywords
:
[],
style
:
{
bgType
:
'color'
,
bgColor
:
'#fff'
,
marginBottom
:
8
,
paddingTop
:
8
,
paddingRight
:
8
,
paddingBottom
:
8
,
paddingLeft
:
8
}
as
ComponentStyle
}
}
as
DiyComponent
<
SearchProperty
>
src/components/DiyEditor/components/mobile/SearchBar/index.vue
View file @
ead30e8c
...
...
@@ -2,8 +2,6 @@
<div
class=
"search-bar"
:style=
"
{
background: property.backgroundColor,
border: `1px solid ${property.backgroundColor}`,
color: property.textColor
}"
>
...
...
@@ -12,7 +10,7 @@
class=
"inner"
:style=
"
{
height: `${property.height}px`,
background: property.b
order
Color,
background: property.b
ackground
Color,
borderRadius: `${property.borderRadius}px`
}"
>
...
...
@@ -44,13 +42,10 @@ defineProps<{ property: SearchProperty }>()
<
style
scoped
lang=
"scss"
>
.search-bar
{
position
:
relative
;
/* 搜索框 */
.inner
{
position
:
relative
;
width
:
calc
(
100%
-
16px
);
min-height
:
28px
;
margin
:
5px
auto
;
display
:
flex
;
align-items
:
center
;
font-size
:
14px
;
...
...
src/components/DiyEditor/components/mobile/SearchBar/property.vue
View file @
ead30e8c
<
template
>
<el-text
tag=
"p"
>
搜索热词
</el-text>
<el-text
type=
"info"
size=
"small"
>
拖动左侧的小圆点可以调整热词顺序
</el-text>
<ComponentContainerProperty
v-model=
"formData.style"
>
<el-text
tag=
"p"
>
搜索热词
</el-text>
<el-text
type=
"info"
size=
"small"
>
拖动左侧的小圆点可以调整热词顺序
</el-text>
<!-- 表单 -->
<el-form
label-width=
"80px"
:model=
"formData"
class=
"m-t-8px"
>
<div
v-if=
"formData.hotKeywords.length"
>
<VueDraggable
:list=
"formData.hotKeywords"
item-key=
"index"
handle=
".drag-icon"
:forceFallback=
"true"
:animation=
"200"
>
<template
#
item=
"
{ index }">
<div
class=
"mb-4px flex flex-row items-center gap-4px rounded bg-gray-100 p-8px"
>
<Icon
icon=
"ic:round-drag-indicator"
class=
"drag-icon cursor-move"
/>
<el-input
v-model=
"formData.hotKeywords[index]"
placeholder=
"请输入热词"
/>
<Icon
icon=
"ep:delete"
class=
"text-red-500"
@
click=
"deleteHotWord(index)"
/>
</div>
</
template
>
</VueDraggable>
</div>
<el-form-item
label-width=
"0"
>
<el-button
@
click=
"handleAddHotWord"
type=
"primary"
plain
class=
"m-t-8px w-full"
>
添加热词
</el-button>
</el-form-item>
<el-form-item
label=
"框体样式"
>
<el-radio-group
v-model=
"formData!.borderRadius"
>
<el-tooltip
content=
"方形"
placement=
"top"
>
<el-radio-button
:label=
"0"
>
<Icon
icon=
"tabler:input-search"
/>
</el-radio-button>
</el-tooltip>
<el-tooltip
content=
"圆形"
placement=
"top"
>
<el-radio-button
:label=
"10"
>
<Icon
icon=
"iconoir:input-search"
/>
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"提示文字"
prop=
"placeholder"
>
<el-input
v-model=
"formData.placeholder"
/>
</el-form-item>
<el-form-item
label=
"文本位置"
prop=
"placeholderPosition"
>
<el-radio-group
v-model=
"formData!.placeholderPosition"
>
<el-tooltip
content=
"居左"
placement=
"top"
>
<el-radio-button
label=
"left"
>
<Icon
icon=
"ant-design:align-left-outlined"
/>
</el-radio-button>
</el-tooltip>
<el-tooltip
content=
"居中"
placement=
"top"
>
<el-radio-button
label=
"center"
>
<Icon
icon=
"ant-design:align-center-outlined"
/>
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"扫一扫"
prop=
"showScan"
>
<el-switch
v-model=
"formData!.showScan"
/>
</el-form-item>
<el-form-item
label=
"框体高度"
prop=
"height"
>
<el-slider
v-model=
"formData!.height"
:max=
"50"
:min=
"28"
show-input
input-size=
"small"
/>
</el-form-item>
<el-form-item
label=
"背景颜色"
prop=
"backgroundColor"
>
<ColorInput
v-model=
"formData.backgroundColor"
/>
</el-form-item>
<el-form-item
label=
"框体颜色"
prop=
"borderColor"
>
<ColorInput
v-model=
"formData.borderColor"
/>
</el-form-item>
<el-form-item
class=
"lef"
label=
"文本颜色"
prop=
"textColor"
>
<ColorInput
v-model=
"formData.textColor"
/>
</el-form-item>
</el-form>
<!-- 表单 -->
<el-form
label-width=
"80px"
:model=
"formData"
class=
"m-t-8px"
>
<div
v-if=
"formData.hotKeywords.length"
>
<VueDraggable
:list=
"formData.hotKeywords"
item-key=
"index"
handle=
".drag-icon"
:forceFallback=
"true"
:animation=
"200"
>
<template
#
item=
"
{ index }">
<div
class=
"mb-4px flex flex-row items-center gap-4px rounded bg-gray-100 p-8px"
>
<Icon
icon=
"ic:round-drag-indicator"
class=
"drag-icon cursor-move"
/>
<el-input
v-model=
"formData.hotKeywords[index]"
placeholder=
"请输入热词"
/>
<Icon
icon=
"ep:delete"
class=
"text-red-500"
@
click=
"deleteHotWord(index)"
/>
</div>
</
template
>
</VueDraggable>
</div>
<el-form-item
label-width=
"0"
>
<el-button
@
click=
"handleAddHotWord"
type=
"primary"
plain
class=
"m-t-8px w-full"
>
添加热词
</el-button>
</el-form-item>
<el-form-item
label=
"框体样式"
>
<el-radio-group
v-model=
"formData!.borderRadius"
>
<el-tooltip
content=
"方形"
placement=
"top"
>
<el-radio-button
:label=
"0"
>
<Icon
icon=
"tabler:input-search"
/>
</el-radio-button>
</el-tooltip>
<el-tooltip
content=
"圆形"
placement=
"top"
>
<el-radio-button
:label=
"10"
>
<Icon
icon=
"iconoir:input-search"
/>
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"提示文字"
prop=
"placeholder"
>
<el-input
v-model=
"formData.placeholder"
/>
</el-form-item>
<el-form-item
label=
"文本位置"
prop=
"placeholderPosition"
>
<el-radio-group
v-model=
"formData!.placeholderPosition"
>
<el-tooltip
content=
"居左"
placement=
"top"
>
<el-radio-button
label=
"left"
>
<Icon
icon=
"ant-design:align-left-outlined"
/>
</el-radio-button>
</el-tooltip>
<el-tooltip
content=
"居中"
placement=
"top"
>
<el-radio-button
label=
"center"
>
<Icon
icon=
"ant-design:align-center-outlined"
/>
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"扫一扫"
prop=
"showScan"
>
<el-switch
v-model=
"formData!.showScan"
/>
</el-form-item>
<el-form-item
label=
"框体高度"
prop=
"height"
>
<el-slider
v-model=
"formData!.height"
:max=
"50"
:min=
"28"
show-input
input-size=
"small"
/>
</el-form-item>
<el-form-item
label=
"框体颜色"
prop=
"backgroundColor"
>
<ColorInput
v-model=
"formData.backgroundColor"
/>
</el-form-item>
<el-form-item
class=
"lef"
label=
"文本颜色"
prop=
"textColor"
>
<ColorInput
v-model=
"formData.textColor"
/>
</el-form-item>
</el-form>
</ComponentContainerProperty>
</template>
<
script
setup
lang=
"ts"
>
...
...
src/components/DiyEditor/components/mobile/VideoPlayer/config.ts
0 → 100644
View file @
ead30e8c
import
{
ComponentStyle
,
DiyComponent
}
from
'@/components/DiyEditor/util'
/** 视频播放属性 */
export
interface
VideoPlayerProperty
{
// 视频链接
videoUrl
:
string
// 封面链接
posterUrl
:
string
// 是否自动播放
autoplay
:
boolean
// 组件样式
style
:
VideoPlayerStyle
}
// 视频播放样式
export
interface
VideoPlayerStyle
extends
ComponentStyle
{
// 视频高度
height
:
number
}
// 定义组件
export
const
component
=
{
id
:
'VideoPlayer'
,
name
:
'视频播放'
,
icon
:
'ep:video-play'
,
property
:
{
videoUrl
:
''
,
posterUrl
:
''
,
autoplay
:
false
,
style
:
{
bgType
:
'color'
,
bgColor
:
'#fff'
,
marginBottom
:
8
,
height
:
300
}
as
ComponentStyle
}
}
as
DiyComponent
<
VideoPlayerProperty
>
src/components/DiyEditor/components/mobile/VideoPlayer/index.vue
0 → 100644
View file @
ead30e8c
<
template
>
<div
class=
"w-full"
:style=
"
{ height: `${property.style.height}px` }">
<el-image
class=
"w-full w-full"
:src=
"property.posterUrl"
v-if=
"property.posterUrl"
/>
<video
v-else
class=
"w-full w-full"
:src=
"property.videoUrl"
:poster=
"property.posterUrl"
:autoplay=
"property.autoplay"
controls
></video>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
VideoPlayerProperty
}
from
'./config'
/** 视频播放 */
defineOptions
({
name
:
'VideoPlayer'
})
defineProps
<
{
property
:
VideoPlayerProperty
}
>
()
</
script
>
<
style
scoped
lang=
"scss"
>
/* 图片 */
img
{
width
:
100%
;
height
:
100%
;
display
:
block
;
}
</
style
>
src/components/DiyEditor/components/mobile/VideoPlayer/property.vue
0 → 100644
View file @
ead30e8c
<
template
>
<ComponentContainerProperty
v-model=
"formData.style"
>
<template
#
style=
"
{ formData }">
<el-form-item
label=
"高度"
prop=
"height"
>
<el-slider
v-model=
"formData.height"
:max=
"500"
:min=
"100"
show-input
input-size=
"small"
:show-input-controls=
"false"
/>
</el-form-item>
</
template
>
<el-form
label-width=
"80px"
:model=
"formData"
>
<el-form-item
label=
"上传视频"
prop=
"videoUrl"
>
<UploadFile
v-model=
"formData.videoUrl"
:file-type=
"['mp4']"
:limit=
"1"
:file-size=
"100"
class=
"min-w-80px"
/>
</el-form-item>
<el-form-item
label=
"上传封面"
prop=
"posterUrl"
>
<UploadImg
v-model=
"formData.posterUrl"
draggable=
"false"
height=
"80px"
width=
"100%"
class=
"min-w-80px"
>
<
template
#
tip
>
建议宽度750
</
template
>
</UploadImg>
</el-form-item>
<el-form-item
label=
"自动播放"
prop=
"autoplay"
>
<el-switch
v-model=
"formData.autoplay"
/>
</el-form-item>
</el-form>
</ComponentContainerProperty>
</template>
<
script
setup
lang=
"ts"
>
import
{
VideoPlayerProperty
}
from
'./config'
import
{
usePropertyForm
}
from
'@/components/DiyEditor/util'
// 视频播放属性面板
defineOptions
({
name
:
'VideoPlayerProperty'
})
const
props
=
defineProps
<
{
modelValue
:
VideoPlayerProperty
}
>
()
const
emit
=
defineEmits
([
'update:modelValue'
])
const
{
formData
}
=
usePropertyForm
(
props
.
modelValue
,
emit
)
</
script
>
<
style
scoped
lang=
"scss"
></
style
>
src/components/DiyEditor/index.vue
View file @
ead30e8c
...
...
@@ -33,111 +33,63 @@
<ComponentLibrary
ref=
"componentLibrary"
:list=
"libs"
v-if=
"libs && libs.length > 0"
/>
<!-- 中心设计区域 -->
<div
class=
"editor-center page-prop-area"
@
click=
"handlePageSelected"
>
<div
class=
"editor-design"
>
<!-- 手机顶部 -->
<div
class=
"editor-design-top"
>
<!-- 手机顶部状态栏 -->
<img
src=
"@/assets/imgs/diy/statusBar.png"
alt=
""
class=
"status-bar"
/>
<!-- 手机顶部导航栏 -->
<NavigationBar
v-if=
"showNavigationBar"
:property=
"navigationBarComponent.property"
@
click=
"handleNavigationBarSelected"
:class=
"[
'component',
'cursor-pointer!',
{ active: selectedComponent?.id === navigationBarComponent.id }
]"
/>
</div>
<!-- 手机页面编辑区域 -->
<el-scrollbar
class=
"editor-design-center"
height=
"100%"
view-class=
"page-prop-area"
>
<div
class=
"phone-container"
:style=
"
{
backgroundColor: pageConfigComponent.property.backgroundColor,
backgroundImage: `url(${pageConfigComponent.property.backgroundImage})`
}"
>
<draggable
class=
"page-prop-area drag-area"
v-model=
"pageComponents"
item-key=
"index"
:animation=
"200"
filter=
".component-toolbar"
ghost-class=
"draggable-ghost"
:force-fallback=
"true"
group=
"component"
@
change=
"handleComponentChange"
>
<template
#
item=
"
{ element, index }">
<div
class=
"component-container"
@
click=
"handleComponentSelected(element, index)"
>
<!-- 左侧组件名 -->
<div
:class=
"['component-name',
{ active: selectedComponentIndex === index }]"
v-if="element.name"
>
{{
element
.
name
}}
</div>
<!-- 组件内容区 -->
<div
:class=
"['component',
{ active: selectedComponentIndex === index }]">
<component
:is=
"element.id"
:property=
"element.property"
:data-type=
"element.id"
/>
</div>
<!-- 左侧:组件操作工具栏 -->
<div
class=
"component-toolbar"
v-if=
"element.name && selectedComponentIndex === index"
>
<el-button-group
type=
"primary"
>
<el-tooltip
content=
"上移"
placement=
"right"
>
<el-button
:disabled=
"index === 0"
@
click
.
stop=
"handleMoveComponent(index, -1)"
>
<Icon
icon=
"ep:arrow-up"
/>
</el-button>
</el-tooltip>
<el-tooltip
content=
"下移"
placement=
"right"
>
<el-button
:disabled=
"index === pageComponents.length - 1"
@
click
.
stop=
"handleMoveComponent(index, 1)"
>
<Icon
icon=
"ep:arrow-down"
/>
</el-button>
</el-tooltip>
<el-tooltip
content=
"复制"
placement=
"right"
>
<el-button
@
click
.
stop=
"handleCopyComponent(index)"
>
<Icon
icon=
"ep:copy-document"
/>
</el-button>
</el-tooltip>
<el-tooltip
content=
"删除"
placement=
"right"
>
<el-button
@
click
.
stop=
"handleDeleteComponent(index)"
>
<Icon
icon=
"ep:delete"
/>
</el-button>
</el-tooltip>
</el-button-group>
</div>
</div>
</
template
>
</draggable>
</div>
</el-scrollbar>
<!-- 手机底部导航 -->
<div
v-if=
"showTabBar"
:class=
"[
'editor-design-bottom',
'component',
'cursor-pointer!',
{ active: selectedComponent?.id === tabBarComponent.id }
]"
<!-- 手机顶部 -->
<div
class=
"editor-design-top"
>
<!-- 手机顶部状态栏 -->
<img
src=
"@/assets/imgs/diy/statusBar.png"
alt=
""
class=
"status-bar"
/>
<!-- 手机顶部导航栏 -->
<ComponentContainer
v-if=
"showNavigationBar"
:component=
"navigationBarComponent"
:show-toolbar=
"false"
:active=
"selectedComponent?.id === navigationBarComponent.id"
@
click=
"handleNavigationBarSelected"
class=
"cursor-pointer!"
/>
</div>
<!-- 手机页面编辑区域 -->
<el-scrollbar
height=
"100%"
wrap-class=
"editor-design-center page-prop-area"
view-class=
"phone-container"
:view-style=
"
{
backgroundColor: pageConfigComponent.property.backgroundColor,
backgroundImage: `url(${pageConfigComponent.property.backgroundImage})`
}"
>
<draggable
class=
"page-prop-area drag-area"
v-model=
"pageComponents"
item-key=
"index"
:animation=
"200"
filter=
".component-toolbar"
ghost-class=
"draggable-ghost"
:force-fallback=
"true"
group=
"component"
@
change=
"handleComponentChange"
>
<TabBar
:property=
"tabBarComponent.property"
@
click=
"handleTabBarSelected"
/>
</div>
<template
#
item=
"
{ element, index }">
<ComponentContainer
:component=
"element"
:active=
"selectedComponentIndex === index"
:can-move-up=
"index > 0"
:can-move-down=
"index
<
pageComponents
.
length
-
1
"
@
move=
"(direction) => handleMoveComponent(index, direction)"
@
copy=
"handleCopyComponent(index)"
@
delete=
"handleDeleteComponent(index)"
@
click=
"handleComponentSelected(element, index)"
/>
</
template
>
</draggable>
</el-scrollbar>
<!-- 手机底部导航 -->
<div
v-if=
"showTabBar"
:class=
"['editor-design-bottom', 'component', 'cursor-pointer!']"
>
<ComponentContainer
:component=
"tabBarComponent"
:show-toolbar=
"false"
:active=
"selectedComponent?.id === tabBarComponent.id"
@
click=
"handleTabBarSelected"
/>
</div>
</div>
<!-- 右侧属性面板 -->
...
...
@@ -178,8 +130,6 @@ export default {
<
script
lang=
"ts"
setup
>
import
draggable
from
'vuedraggable'
import
ComponentLibrary
from
'./components/ComponentLibrary.vue'
import
NavigationBar
from
'./components/mobile/NavigationBar/index.vue'
import
TabBar
from
'./components/mobile/TabBar/index.vue'
import
{
cloneDeep
,
includes
}
from
'lodash-es'
import
{
component
as
PAGE_CONFIG_COMPONENT
}
from
'@/components/DiyEditor/components/mobile/PageConfig/config'
import
{
component
as
NAVIGATION_BAR_COMPONENT
}
from
'./components/mobile/NavigationBar/config'
...
...
@@ -256,6 +206,9 @@ const handleSave = () => {
return
{
id
:
component
.
id
,
property
:
component
.
property
}
})
}
as
PageConfig
if
(
!
props
.
showTabBar
)
{
delete
pageConfig
.
tabBar
}
// 发送数据更新通知
const
modelValue
=
isString
(
props
.
modelValue
)
?
JSON
.
stringify
(
pageConfig
)
:
pageConfig
emits
(
'update:modelValue'
,
modelValue
)
...
...
@@ -383,6 +336,7 @@ onMounted(() => setDefaultSelectedComponent())
<
style
lang=
"scss"
scoped
>
/* 手机宽度 */
$
phone-width
:
375px
;
$
toolbar-height
:
42px
;
/* 根节点样式 */
.editor
{
height
:
100%
;
...
...
@@ -394,7 +348,7 @@ $phone-width: 375px;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
height
:
auto
;
height
:
$
toolbar-height
;
padding
:
0
;
border-bottom
:
solid
1px
var
(
--el-border-color
);
background-color
:
var
(
--el-bg-color
);
...
...
@@ -416,176 +370,81 @@ $phone-width: 375px;
/* 中心操作区 */
.editor-container
{
height
:
calc
(
100vh
-
var
(
--top-tool-height
)
-
var
(
--tags-view-height
)
-
var
(
--app-footer-height
)
-
42px
100vh
-
var
(
--top-tool-height
)
-
var
(
--tags-view-height
)
-
var
(
--app-footer-height
)
-
$
toolbar-height
);
/* 右侧属性面板 */
.editor-right
{
flex-shrink
:
0
;
box-shadow
:
-8px
0
8px
-8px
rgba
(
0
,
0
,
0
,
0.12
);
overflow
:
hidden
;
/* 属性面板顶部:减少内边距 */
:deep(.el-card__header)
{
padding
:
8px
16px
;
}
/* 属性面板分组 */
.property-group
{
/* 属性分组 */
:deep(.el-card__header)
{
:deep
(
.property-group
)
{
margin
:
0
-20px
;
&.el-card
{
border
:
none
;
}
/* 属性分组名称 */
.el-card__header
{
border
:
none
;
background
:
var
(
--el-bg-color-page
);
padding
:
8px
32px
;
}
.el-card__body
{
border
:
none
;
}
}
}
/* 中心区域 */
.editor-center
{
position
:
relative
;
flex
:
1
1
0
;
padding
:
16px
0
;
background-color
:
var
(
--app-content-bg-color
);
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
/* 中心设计区域 */
.editor-design
{
position
:
relative
;
height
:
100%
;
width
:
100%
;
margin
:
16px
0
0
0
;
overflow
:
hidden
;
width
:
100%
;
/* 手机顶部 */
.editor-design-top
{
width
:
$
phone-width
;
margin
:
0
auto
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
overflow
:
hidden
;
/* 组件 */
.component
{
border
:
1px
solid
#fff
;
width
:
$
phone-width
;
cursor
:
move
;
/* 鼠标放到组件上时 */
&:hover
{
border
:
1px
dashed
var
(
--el-color-primary
);
}
}
/* 组件选中 */
.component.active
{
border
:
2px
solid
var
(
--el-color-primary
);
}
/* 手机顶部 */
.editor-design-top
{
width
:
$
phone-width
;
/* 手机顶部状态栏 */
.status-bar
{
height
:
20px
;
width
:
$
phone-width
;
background-color
:
#fff
;
}
}
/* 手机底部导航 */
.editor-design-bottom
{
/* 手机顶部状态栏 */
.status-bar
{
height
:
20px
;
width
:
$
phone-width
;
background-color
:
#fff
;
}
/* 手机页面编辑区域 */
.editor-design-center
{
width
:
100%
;
flex
:
1
1
0
;
:deep(.el-scrollbar__view)
{
height
:
100%
;
}
}
/* 手机底部导航 */
.editor-design-bottom
{
width
:
$
phone-width
;
margin
:
0
auto
;
}
/* 手机页面编辑区域 */
:deep
(
.editor-design-center
)
{
width
:
100%
;
/* 主体内容 */
.phone-container
{
/* 主体内容 */
.phone-container
{
position
:
relative
;
background-repeat
:
no-repeat
;
background-size
:
100%
100%
;
height
:
100%
;
width
:
$
phone-width
;
margin
:
0
auto
;
.drag-area
{
height
:
100%
;
box-sizing
:
border-box
;
position
:
relative
;
background-repeat
:
no-repeat
;
background-size
:
100%
100%
;
width
:
$
phone-width
;
margin
:
0
auto
;
.drag-area
{
height
:
100%
;
}
/* 组件容器(左侧:组件名称,中间:组件,右侧:操作工具栏) */
.component-container
{
width
:
100%
;
position
:
relative
;
/* 左侧:组件名称 */
.component-name
{
position
:
absolute
;
width
:
80px
;
text-align
:
center
;
line-height
:
25px
;
height
:
25px
;
background
:
#fff
;
font-size
:
12px
;
left
:
-85px
;
top
:
0
;
box-shadow
:
0
0
4px
#00000014
,
0
2px
6px
#0000000
f
,
0
4px
8px
2px
#0000000
a
;
/* 右侧小三角 */
&:after
{
position
:
absolute
;
top
:
7.5px
;
right
:
-10px
;
content
:
' '
;
height
:
0
;
width
:
0
;
border
:
5px
solid
transparent
;
border-left-color
:
#fff
;
}
}
/* 组件选中按钮 */
.component-name.active
{
background
:
var
(
--el-color-primary
);
color
:
#fff
;
&:after
{
border-left-color
:
var
(
--el-color-primary
);
}
}
/* 右侧:组件操作工具栏 */
.component-toolbar
{
position
:
absolute
;
top
:
0
;
right
:
-57px
;
/* 左侧小三角 */
&:before
{
position
:
absolute
;
top
:
10px
;
left
:
-10px
;
content
:
' '
;
height
:
0
;
width
:
0
;
border
:
5px
solid
transparent
;
border-right-color
:
#2d8cf0
;
}
/* 重写 Element 按钮组的样式(官方只支持水平显示,增加垂直显示的样式) */
.el-button-group
{
display
:
inline-flex
;
flex-direction
:
column
;
}
.el-button-group
>
.el-button
:first-child
{
border-bottom-left-radius
:
0
;
border-bottom-right-radius
:
0
;
border-top-right-radius
:
var
(
--el-border-radius-base
);
border-bottom-color
:
var
(
--el-button-divide-border-color
);
}
.el-button-group
>
.el-button
:last-child
{
border-top-left-radius
:
0
;
border-top-right-radius
:
0
;
border-bottom-left-radius
:
var
(
--el-border-radius-base
);
border-top-color
:
var
(
--el-button-divide-border-color
);
}
.el-button-group
.el-button--primary
:not
(
:first-child
)
:not
(
:last-child
)
{
border-top-color
:
var
(
--el-button-divide-border-color
);
border-bottom-color
:
var
(
--el-button-divide-border-color
);
}
.el-button-group
>
.el-button
:not
(
:last-child
)
{
margin-bottom
:
-1px
;
margin-right
:
0
;
}
}
}
width
:
100%
;
}
}
}
...
...
src/components/DiyEditor/util.ts
View file @
ead30e8c
...
...
@@ -3,19 +3,56 @@ import { PageConfigProperty } from '@/components/DiyEditor/components/mobile/Pag
import
{
NavigationBarProperty
}
from
'@/components/DiyEditor/components/mobile/NavigationBar/config'
import
{
TabBarProperty
}
from
'@/components/DiyEditor/components/mobile/TabBar/config'
// 页面装修组件
export
interface
DiyComponent
<
T
>
{
// 组件唯一标识
id
:
string
// 组件名称
name
:
string
// 组件图标
icon
:
string
// 组件属性
property
:
T
}
// 页面装修组件库
export
interface
DiyComponentLibrary
{
// 组件库名称
name
:
string
// 是否展开
extended
:
boolean
// 组件列表
components
:
string
[]
}
// 组件样式
export
interface
ComponentStyle
{
// 背景类型
bgType
:
'color'
|
'img'
// 背景颜色
bgColor
:
string
// 背景图片
bgImg
:
string
// 外边距
margin
:
number
marginTop
:
number
marginRight
:
number
marginBottom
:
number
marginLeft
:
number
// 内边距
padding
:
number
paddingTop
:
number
paddingRight
:
number
paddingBottom
:
number
paddingLeft
:
number
// 边框圆角
borderRadius
:
number
borderTopLeftRadius
:
number
borderTopRightRadius
:
number
borderBottomRightRadius
:
number
borderBottomLeftRadius
:
number
}
// 页面配置
export
interface
PageConfig
{
// 页面属性
...
...
@@ -23,7 +60,7 @@ export interface PageConfig {
// 顶部导航栏属性
navigationBar
:
NavigationBarProperty
// 底部导航菜单属性
tabBar
:
TabBarProperty
tabBar
?
:
TabBarProperty
// 页面组件列表
components
:
PageComponent
[]
}
...
...
@@ -57,3 +94,27 @@ export function usePropertyForm<T>(modelValue: T, emit: Function): { formData: R
return
{
formData
}
}
// 页面组件库
export
const
PAGE_LIBS
=
[
{
name
:
'基础组件'
,
extended
:
true
,
components
:
[
'SearchBar'
,
'NoticeBar'
,
'GridNavigation'
,
'ListNavigation'
,
'Divider'
,
'TitleBar'
]
},
{
name
:
'图文组件'
,
extended
:
true
,
components
:
[
'ImageBar'
,
'Carousel'
,
'VideoPlayer'
]
},
{
name
:
'商品组件'
,
extended
:
true
,
components
:
[
'ProductCard'
]
},
{
name
:
'会员组件'
,
extended
:
true
,
components
:
[
'UserCard'
,
'OrderCard'
,
'WalletCard'
,
'CouponCard'
]
},
{
name
:
'营销组件'
,
extended
:
true
,
components
:
[
'Combination'
,
'Seckill'
,
'Point'
,
'Coupon'
]
}
]
as
DiyComponentLibrary
[]
src/components/UploadFile/src/UploadFile.vue
View file @
ead30e8c
...
...
@@ -33,11 +33,10 @@
</div>
</template>
<
script
lang=
"ts"
setup
>
import
{
PropType
}
from
'vue'
import
{
propTypes
}
from
'@/utils/propTypes'
import
{
getAccessToken
,
getTenantId
}
from
'@/utils/auth'
import
type
{
UploadInstance
,
UploadUserFile
,
UploadProps
,
UploadRawFile
}
from
'element-plus'
import
{
isArray
,
isString
}
from
'@/utils/is'
defineOptions
({
name
:
'UploadFile'
})
...
...
@@ -45,10 +44,7 @@ const message = useMessage() // 消息弹窗
const
emit
=
defineEmits
([
'update:modelValue'
])
const
props
=
defineProps
({
modelValue
:
{
type
:
Array
as
PropType
<
UploadUserFile
[]
>
,
required
:
true
},
modelValue
:
propTypes
.
oneOfType
<
string
|
string
[]
>
([
String
,
Array
<
String
>
]).
isRequired
,
title
:
propTypes
.
string
.
def
(
'文件上传'
),
updateUrl
:
propTypes
.
string
.
def
(
import
.
meta
.
env
.
VITE_UPLOAD_URL
),
fileType
:
propTypes
.
array
.
def
([
'doc'
,
'xls'
,
'ppt'
,
'txt'
,
'pdf'
]),
// 文件类型, 例如['png', 'jpg', 'jpeg']
...
...
@@ -62,7 +58,7 @@ const props = defineProps({
const
valueRef
=
ref
(
props
.
modelValue
)
const
uploadRef
=
ref
<
UploadInstance
>
()
const
uploadList
=
ref
<
UploadUserFile
[]
>
([])
const
fileList
=
ref
<
UploadUserFile
[]
>
(
props
.
modelValue
)
const
fileList
=
ref
<
UploadUserFile
[]
>
(
[]
)
const
uploadNumber
=
ref
<
number
>
(
0
)
const
uploadHeaders
=
ref
({
Authorization
:
'Bearer '
+
getAccessToken
(),
...
...
@@ -109,7 +105,7 @@ const handleFileSuccess: UploadProps['onSuccess'] = (res: any): void => {
fileList
.
value
=
fileList
.
value
.
concat
(
uploadList
.
value
)
uploadList
.
value
=
[]
uploadNumber
.
value
=
0
emit
(
'update:modelValue'
,
listToString
(
fileList
.
value
)
)
emit
UpdateModelValue
(
)
}
}
// 文件数超出提示
...
...
@@ -125,20 +121,47 @@ const handleRemove = (file) => {
const
findex
=
fileList
.
value
.
map
((
f
)
=>
f
.
name
).
indexOf
(
file
.
name
)
if
(
findex
>
-
1
)
{
fileList
.
value
.
splice
(
findex
,
1
)
emit
(
'update:modelValue'
,
listToString
(
fileList
.
value
)
)
emit
UpdateModelValue
(
)
}
}
const
handlePreview
:
UploadProps
[
'onPreview'
]
=
(
uploadFile
)
=>
{
console
.
log
(
uploadFile
)
}
// 对象转成指定字符串分隔
const
listToString
=
(
list
:
UploadUserFile
[],
separator
?:
string
)
=>
{
let
strs
=
''
separator
=
separator
||
','
for
(
let
i
in
list
)
{
strs
+=
list
[
i
].
url
+
separator
// 监听模型绑定值变动
watch
(
()
=>
props
.
modelValue
,
()
=>
{
const
files
:
string
[]
=
[]
// 情况1:字符串
if
(
isString
(
props
.
modelValue
))
{
// 情况1.1:逗号分隔的多值
if
(
props
.
modelValue
.
includes
(
','
))
{
files
.
concat
(
props
.
modelValue
.
split
(
','
))
}
else
if
(
props
.
modelValue
.
length
>
0
)
{
files
.
push
(
props
.
modelValue
)
}
}
else
if
(
isArray
(
props
.
modelValue
))
{
// 情况2:字符串
files
.
concat
(
props
.
modelValue
)
}
else
{
throw
new
Error
(
'不支持的 modelValue 类型'
)
}
fileList
.
value
=
files
.
map
((
url
:
string
)
=>
{
return
{
url
,
name
:
url
.
substring
(
url
.
lastIndexOf
(
'/'
)
+
1
)
}
as
UploadUserFile
})
},
{
immediate
:
true
}
)
// 发送文件链接列表更新
const
emitUpdateModelValue
=
()
=>
{
// 情况1:数组结果
let
result
:
string
|
string
[]
=
fileList
.
value
.
map
((
file
)
=>
file
.
url
!
)
// 情况2:逗号分隔的字符串
if
(
isString
(
props
.
modelValue
))
{
result
=
result
.
join
(
','
)
}
return
strs
!=
''
?
strs
.
substr
(
0
,
strs
.
length
-
1
)
:
''
emit
(
'update:modelValue'
,
result
)
}
</
script
>
<
style
scoped
lang=
"scss"
>
...
...
src/components/VerticalButtonGroup/index.vue
0 → 100644
View file @
ead30e8c
<
template
>
<el-button-group
v-bind=
"$attrs"
>
<slot></slot>
</el-button-group>
</
template
>
<
script
setup
lang=
"ts"
>
/**
* 垂直按钮组
* Element官方的按钮组只支持水平显示,通过重写样式实现垂直布局
*/
defineOptions
({
name
:
'VerticalButtonGroup'
})
</
script
>
<
style
scoped
lang=
"scss"
>
.el-button-group
{
display
:
inline-flex
;
flex-direction
:
column
;
}
.el-button-group
>
:deep
(
.el-button
:first-child
)
{
border-bottom-left-radius
:
0
;
border-bottom-right-radius
:
0
;
border-top-right-radius
:
var
(
--el-border-radius-base
);
border-bottom-color
:
var
(
--el-button-divide-border-color
);
}
.el-button-group
>
:deep
(
.el-button
:last-child
)
{
border-top-left-radius
:
0
;
border-top-right-radius
:
0
;
border-bottom-left-radius
:
var
(
--el-border-radius-base
);
border-top-color
:
var
(
--el-button-divide-border-color
);
}
.el-button-group
:deep
(
.el-button--primary
:not
(
:first-child
)
:not
(
:last-child
))
{
border-top-color
:
var
(
--el-button-divide-border-color
);
border-bottom-color
:
var
(
--el-button-divide-border-color
);
}
.el-button-group
>
:deep
(
.el-button
:not
(
:last-child
))
{
margin-bottom
:
-1px
;
margin-right
:
0
;
}
</
style
>
src/layout/components/Footer/src/Footer.vue
View file @
ead30e8c
...
...
@@ -19,6 +19,6 @@ const title = computed(() => appStore.getTitle)
:class=
"prefixCls"
class=
"h-[var(--app-footer-height)] bg-[var(--app-content-bg-color)] text-center leading-[var(--app-footer-height)] text-[var(--el-text-color-placeholder)] dark:bg-[var(--el-bg-color)]"
>
<
p
style=
"font-size: 14px"
>
Copyright ©2022-
{{
title
}}
</p
>
<
span
class=
"text-14px"
>
Copyright ©2022-
{{
title
}}
</span
>
</div>
</
template
>
src/views/mall/promotion/diy/page/decorate.vue
View file @
ead30e8c
...
...
@@ -3,7 +3,7 @@
v-if=
"formData && !formLoading"
v-model=
"formData.property"
:title=
"formData.name"
:libs=
"
componentLibs
"
:libs=
"
PAGE_LIBS
"
:show-page-config=
"true"
:show-navigation-bar=
"true"
:show-tab-bar=
"false"
...
...
@@ -13,35 +13,11 @@
<
script
setup
lang=
"ts"
>
import
*
as
DiyPageApi
from
'@/api/mall/promotion/diy/page'
import
{
useTagsViewStore
}
from
'@/store/modules/tagsView'
import
{
DiyComponentLibrary
}
from
'@/components/DiyEditor/util'
import
{
PAGE_LIBS
}
from
'@/components/DiyEditor/util'
/** 装修页面表单 */
defineOptions
({
name
:
'DiyPageDecorate'
})
// 组件库
const
componentLibs
=
[
{
name
:
'基础组件'
,
extended
:
true
,
components
:
[
'SearchBar'
,
'NoticeBar'
,
'GridNavigation'
,
'ListNavigation'
,
'Divider'
,
'TitleBar'
]
},
{
name
:
'图文组件'
,
extended
:
true
,
components
:
[
'Carousel'
]
},
{
name
:
'商品组件'
,
extended
:
true
,
components
:
[
'ProductCard'
]
},
{
name
:
'会员组件'
,
extended
:
true
,
components
:
[
'UserCard'
,
'OrderCard'
,
'WalletCard'
,
'CouponCard'
]
},
{
name
:
'营销组件'
,
extended
:
true
,
components
:
[
'Combination'
,
'Seckill'
,
'Point'
,
'Coupon'
]
}
]
as
DiyComponentLibrary
[]
const
message
=
useMessage
()
// 消息弹窗
const
formLoading
=
ref
(
false
)
// 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
...
...
src/views/mall/promotion/diy/template/decorate.vue
View file @
ead30e8c
...
...
@@ -28,7 +28,7 @@
import
*
as
DiyTemplateApi
from
'@/api/mall/promotion/diy/template'
import
*
as
DiyPageApi
from
'@/api/mall/promotion/diy/page'
import
{
useTagsViewStore
}
from
'@/store/modules/tagsView'
import
{
DiyComponentLibrary
}
from
'@/components/DiyEditor/util'
import
{
DiyComponentLibrary
,
PAGE_LIBS
}
from
'@/components/DiyEditor/util'
/** 装修模板表单 */
defineOptions
({
name
:
'DiyTemplateDecorate'
})
...
...
@@ -62,29 +62,6 @@ const getPageDetail = async (id: any) => {
// 模板组件库
const
templateLibs
=
[]
as
DiyComponentLibrary
[]
// 页面组件库
const
pageLibs
=
[
{
name
:
'基础组件'
,
extended
:
true
,
components
:
[
'SearchBar'
,
'NoticeBar'
,
'GridNavigation'
,
'ListNavigation'
,
'Divider'
,
'TitleBar'
]
},
{
name
:
'图文组件'
,
extended
:
true
,
components
:
[
'Carousel'
]
},
{
name
:
'商品组件'
,
extended
:
true
,
components
:
[
'ProductCard'
]
},
{
name
:
'会员组件'
,
extended
:
true
,
components
:
[
'UserCard'
,
'OrderCard'
,
'WalletCard'
,
'CouponCard'
]
},
{
name
:
'营销组件'
,
extended
:
true
,
components
:
[
'Combination'
,
'Seckill'
,
'Point'
,
'Coupon'
]
}
]
as
DiyComponentLibrary
[]
// 当前组件库
const
libs
=
ref
<
DiyComponentLibrary
[]
>
(
templateLibs
)
// 模板选项切换
...
...
@@ -97,7 +74,7 @@ const handleTemplateItemChange = () => {
}
// 编辑页面
libs
.
value
=
pageLibs
libs
.
value
=
PAGE_LIBS
currentFormData
.
value
=
formData
.
value
!
.
pages
.
find
(
(
page
:
DiyPageApi
.
DiyPageVO
)
=>
page
.
name
===
templateItems
[
selectedTemplateItem
.
value
].
name
)
...
...
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