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
Commit
b63e2a9e
authored
Nov 10, 2023
by
Wanwan
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/dev' into dev
parents
59b2d89a
6160c2fa
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
762 additions
and
41 deletions
+762
-41
src/components/ColorInput/index.vue
+2
-22
src/components/DiyEditor/components/ComponentContainer.vue
+21
-10
src/components/DiyEditor/components/mobile/MenuGrid/config.ts
+78
-0
src/components/DiyEditor/components/mobile/MenuGrid/index.vue
+35
-0
src/components/DiyEditor/components/mobile/MenuGrid/property.vue
+96
-0
src/components/DiyEditor/components/mobile/MenuList/config.ts
+47
-0
src/components/DiyEditor/components/mobile/MenuList/index.vue
+31
-0
src/components/DiyEditor/components/mobile/MenuList/property.vue
+75
-0
src/components/DiyEditor/components/mobile/MenuSwiper/config.ts
+66
-0
src/components/DiyEditor/components/mobile/MenuSwiper/index.vue
+119
-0
src/components/DiyEditor/components/mobile/MenuSwiper/property.vue
+106
-0
src/components/DiyEditor/util.ts
+6
-9
src/components/InputWithColor/index.vue
+59
-0
src/utils/color.ts
+21
-0
No files found.
src/components/ColorInput/index.vue
View file @
b63e2a9e
<
template
>
<
template
>
<el-input
v-model=
"color"
>
<el-input
v-model=
"color"
>
<template
#
prepend
>
<template
#
prepend
>
<el-color-picker
v-model=
"color"
:predefine=
"COLORS"
/>
<el-color-picker
v-model=
"color"
:predefine=
"
PREDEFINE_
COLORS"
/>
</
template
>
</
template
>
</el-input>
</el-input>
</template>
</template>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
propTypes
}
from
'@/utils/propTypes'
import
{
propTypes
}
from
'@/utils/propTypes'
import
{
PREDEFINE_COLORS
}
from
'@/utils/color'
// 颜色输入框
// 颜色输入框
defineOptions
({
name
:
'ColorInput'
})
defineOptions
({
name
:
'ColorInput'
})
// 预设颜色
const
COLORS
=
[
'#ff4500'
,
'#ff8c00'
,
'#ffd700'
,
'#90ee90'
,
'#00ced1'
,
'#1e90ff'
,
'#c71585'
,
'#409EFF'
,
'#909399'
,
'#C0C4CC'
,
'#b7390b'
,
'#ff7800'
,
'#fad400'
,
'#5b8c5f'
,
'#00babd'
,
'#1f73c3'
,
'#711f57'
]
const
props
=
defineProps
({
const
props
=
defineProps
({
modelValue
:
propTypes
.
string
.
def
(
''
)
modelValue
:
propTypes
.
string
.
def
(
''
)
})
})
...
...
src/components/DiyEditor/components/ComponentContainer.vue
View file @
b63e2a9e
<
template
>
<
template
>
<div
:class=
"['component',
{ active: active }]">
<div
:class=
"['component',
{ active: active }]">
<div
<div
class=
"component-inner"
:style=
"
{
:style=
"
{
...style
...style
}"
}"
...
@@ -130,23 +131,19 @@ $toolbar-position: -55px;
...
@@ -130,23 +131,19 @@ $toolbar-position: -55px;
.component
{
.component
{
position
:
relative
;
position
:
relative
;
cursor
:
move
;
cursor
:
move
;
.component-inner
{
position
:
relative
;
z-index
:
1
;
}
.component-wrap
{
.component-wrap
{
z-index
:
0
;
pointer-events
:
none
;
display
:
block
;
display
:
block
;
position
:
absolute
;
position
:
absolute
;
left
:
-
$
active-border-width
;
left
:
-
$
active-border-width
;
top
:
0
;
top
:
0
;
width
:
100%
;
width
:
100%
;
height
:
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
{
.component-name
{
display
:
block
;
display
:
block
;
...
@@ -199,6 +196,7 @@ $toolbar-position: -55px;
...
@@ -199,6 +196,7 @@ $toolbar-position: -55px;
margin-bottom
:
4px
;
margin-bottom
:
4px
;
.component-wrap
{
.component-wrap
{
z-index
:
2
;
border
:
$
active-border-width
solid
var
(
--el-color-primary
)
!important
;
border
:
$
active-border-width
solid
var
(
--el-color-primary
)
!important
;
box-shadow
:
0
0
10px
0
rgba
(
24
,
144
,
255
,
0.3
);
box-shadow
:
0
0
10px
0
rgba
(
24
,
144
,
255
,
0.3
);
margin-bottom
:
$
active-border-width
+
$
active-border-width
;
margin-bottom
:
$
active-border-width
+
$
active-border-width
;
...
@@ -218,5 +216,18 @@ $toolbar-position: -55px;
...
@@ -218,5 +216,18 @@ $toolbar-position: -55px;
}
}
}
}
}
}
/* 鼠标放到组件上时 */
&
:hover
{
.component-wrap
{
z-index
:
2
;
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
;
}
}
}
}
}
</
style
>
</
style
>
src/components/DiyEditor/components/mobile/MenuGrid/config.ts
0 → 100644
View file @
b63e2a9e
import
{
ComponentStyle
,
DiyComponent
}
from
'@/components/DiyEditor/util'
import
{
cloneDeep
}
from
'lodash-es'
/** 宫格导航属性 */
export
interface
MenuGridProperty
{
// 列数
column
:
number
// 导航菜单列表
list
:
MenuGridItemProperty
[]
// 组件样式
style
:
ComponentStyle
}
/** 宫格导航项目属性 */
export
interface
MenuGridItemProperty
{
// 图标链接
iconUrl
:
string
// 标题
title
:
string
// 标题颜色
titleColor
:
string
// 副标题
subtitle
:
string
// 副标题颜色
subtitleColor
:
string
// 链接
url
:
string
// 角标
badge
:
{
// 是否显示
show
:
boolean
// 角标文字
text
:
string
// 角标文字颜色
textColor
:
string
// 角标背景颜色
bgColor
:
string
}
}
export
const
EMPTY_MENU_GRID_ITEM_PROPERTY
=
{
title
:
'标题'
,
titleColor
:
'#333'
,
subtitle
:
'副标题'
,
subtitleColor
:
'#bbb'
,
badge
:
{
show
:
false
,
textColor
:
'#fff'
,
bgColor
:
'#FF6000'
}
}
as
MenuGridItemProperty
// 定义组件
export
const
component
=
{
id
:
'MenuGrid'
,
name
:
'宫格导航'
,
icon
:
'bi:grid-3x3-gap'
,
property
:
{
column
:
3
,
list
:
[
cloneDeep
(
EMPTY_MENU_GRID_ITEM_PROPERTY
)],
style
:
{
bgType
:
'color'
,
bgColor
:
'#fff'
,
marginBottom
:
8
,
marginLeft
:
8
,
marginRight
:
8
,
padding
:
8
,
paddingTop
:
8
,
paddingRight
:
8
,
paddingBottom
:
8
,
paddingLeft
:
8
,
borderRadius
:
8
,
borderTopLeftRadius
:
8
,
borderTopRightRadius
:
8
,
borderBottomRightRadius
:
8
,
borderBottomLeftRadius
:
8
}
as
ComponentStyle
}
}
as
DiyComponent
<
MenuGridProperty
>
src/components/DiyEditor/components/mobile/MenuGrid/index.vue
0 → 100644
View file @
b63e2a9e
<
template
>
<div
class=
"flex flex-row flex-wrap"
>
<div
v-for=
"(item, index) in property.list"
:key=
"index"
class=
"relative flex flex-col items-center p-b-14px p-t-20px"
:style=
"
{ width: `${100 * (1 / property.column)}%` }"
>
<!-- 右上角角标 -->
<span
v-if=
"item.badge?.show"
class=
"absolute left-50% top-10px z-1 h-20px rounded-50% p-x-6px text-center text-12px leading-20px"
:style=
"
{ color: item.badge.textColor, backgroundColor: item.badge.bgColor }"
>
{{
item
.
badge
.
text
}}
</span>
<el-image
v-if=
"item.iconUrl"
class=
"h-28px w-28px"
:src=
"item.iconUrl"
/>
<span
class=
"m-t-8px h-16px text-12px leading-16px"
:style=
"
{ color: item.titleColor }">
{{
item
.
title
}}
</span>
<span
class=
"m-t-6px h-12px text-10px leading-12px"
:style=
"
{ color: item.subtitleColor }">
{{
item
.
subtitle
}}
</span>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
MenuGridProperty
}
from
'./config'
/** 宫格导航 */
defineOptions
({
name
:
'MenuGrid'
})
defineProps
<
{
property
:
MenuGridProperty
}
>
()
</
script
>
<
style
scoped
lang=
"scss"
></
style
>
src/components/DiyEditor/components/mobile/MenuGrid/property.vue
0 → 100644
View file @
b63e2a9e
<
template
>
<ComponentContainerProperty
v-model=
"formData.style"
>
<!-- 表单 -->
<el-form
label-width=
"80px"
:model=
"formData"
class=
"m-t-8px"
>
<el-form-item
label=
"每行数量"
prop=
"column"
>
<el-radio-group
v-model=
"formData.column"
>
<el-radio
:label=
"3"
>
3个
</el-radio>
<el-radio
:label=
"4"
>
4个
</el-radio>
</el-radio-group>
</el-form-item>
<el-text
tag=
"p"
>
菜单设置
</el-text>
<el-text
type=
"info"
size=
"small"
>
拖动左侧的小圆点可以调整顺序
</el-text>
<template
v-if=
"formData.list.length"
>
<VueDraggable
class=
"m-t-8px"
:list=
"formData.list"
item-key=
"index"
handle=
".drag-icon"
:forceFallback=
"true"
:animation=
"200"
>
<template
#
item=
"
{ element, index }">
<div
class=
"mb-4px flex flex-col gap-4px rounded bg-gray-100 p-8px"
>
<div
class=
"flex flex-row justify-between"
>
<Icon
icon=
"ic:round-drag-indicator"
class=
"drag-icon cursor-move"
/>
<Icon
icon=
"ep:delete"
class=
"text-red-500"
@
click=
"handleDeleteMenu(index)"
/>
</div>
<el-form-item
label=
"图标"
prop=
"iconUrl"
>
<UploadImg
v-model=
"element.iconUrl"
height=
"80px"
width=
"80px"
>
<template
#
tip
>
建议尺寸:44 * 44
</
template
>
</UploadImg>
</el-form-item>
<el-form-item
label=
"标题"
prop=
"title"
>
<InputWithColor
v-model=
"element.title"
v-model:color=
"element.titleColor"
/>
</el-form-item>
<el-form-item
label=
"副标题"
prop=
"subtitle"
>
<InputWithColor
v-model=
"element.subtitle"
v-model:color=
"element.subtitleColor"
/>
</el-form-item>
<el-form-item
label=
"链接"
prop=
"url"
>
<el-input
v-model=
"element.url"
/>
</el-form-item>
<el-form-item
label=
"显示角标"
prop=
"badge.show"
>
<el-switch
v-model=
"element.badge.show"
/>
</el-form-item>
<
template
v-if=
"element.badge.show"
>
<el-form-item
label=
"角标内容"
prop=
"badge.text"
>
<InputWithColor
v-model=
"element.badge.text"
v-model:color=
"element.badge.textColor"
/>
</el-form-item>
<el-form-item
label=
"背景颜色"
prop=
"badge.bgColor"
>
<ColorInput
v-model=
"element.badge.bgColor"
/>
</el-form-item>
</
template
>
</div>
</template>
</VueDraggable>
</template>
<el-form-item
label-width=
"0"
>
<el-button
@
click=
"handleAddMenu"
type=
"primary"
plain
class=
"m-t-8px w-full"
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
添加菜单
</el-button>
</el-form-item>
</el-form>
</ComponentContainerProperty>
</template>
<
script
setup
lang=
"ts"
>
import
VueDraggable
from
'vuedraggable'
import
{
usePropertyForm
}
from
'@/components/DiyEditor/util'
import
{
EMPTY_MENU_GRID_ITEM_PROPERTY
,
MenuGridProperty
}
from
'@/components/DiyEditor/components/mobile/MenuGrid/config'
import
{
cloneDeep
}
from
'lodash-es'
/** 宫格导航属性面板 */
defineOptions
({
name
:
'MenuGridProperty'
})
const
props
=
defineProps
<
{
modelValue
:
MenuGridProperty
}
>
()
const
emit
=
defineEmits
([
'update:modelValue'
])
const
{
formData
}
=
usePropertyForm
(
props
.
modelValue
,
emit
)
/* 添加菜单 */
const
handleAddMenu
=
()
=>
{
formData
.
value
.
list
.
push
(
cloneDeep
(
EMPTY_MENU_GRID_ITEM_PROPERTY
))
}
/* 删除菜单 */
const
handleDeleteMenu
=
(
index
:
number
)
=>
{
formData
.
value
.
list
.
splice
(
index
,
1
)
}
</
script
>
<
style
scoped
lang=
"scss"
></
style
>
src/components/DiyEditor/components/mobile/MenuList/config.ts
0 → 100644
View file @
b63e2a9e
import
{
ComponentStyle
,
DiyComponent
}
from
'@/components/DiyEditor/util'
import
{
cloneDeep
}
from
'lodash-es'
/** 列表导航属性 */
export
interface
MenuListProperty
{
// 导航菜单列表
list
:
MenuListItemProperty
[]
// 组件样式
style
:
ComponentStyle
}
/** 列表导航项目属性 */
export
interface
MenuListItemProperty
{
// 图标链接
iconUrl
:
string
// 标题
title
:
string
// 标题颜色
titleColor
:
string
// 副标题
subtitle
:
string
// 副标题颜色
subtitleColor
:
string
// 链接
url
:
string
}
export
const
EMPTY_MENU_LIST_ITEM_PROPERTY
=
{
title
:
'标题'
,
titleColor
:
'#333'
,
subtitle
:
'副标题'
,
subtitleColor
:
'#bbb'
}
// 定义组件
export
const
component
=
{
id
:
'MenuList'
,
name
:
'列表导航'
,
icon
:
'fa-solid:list'
,
property
:
{
list
:
[
cloneDeep
(
EMPTY_MENU_LIST_ITEM_PROPERTY
)],
style
:
{
bgType
:
'color'
,
bgColor
:
'#fff'
,
marginBottom
:
8
}
as
ComponentStyle
}
}
as
DiyComponent
<
MenuListProperty
>
src/components/DiyEditor/components/mobile/MenuList/index.vue
0 → 100644
View file @
b63e2a9e
<
template
>
<div
class=
"min-h-42px flex flex-col"
>
<div
v-for=
"(item, index) in property.list"
:key=
"index"
class=
"item h-42px flex flex-row items-center justify-between gap-4px p-x-12px"
>
<div
class=
"flex flex-1 flex-row items-center gap-8px"
>
<el-image
v-if=
"item.iconUrl"
class=
"h-16px w-16px"
:src=
"item.iconUrl"
/>
<span
class=
"text-16px"
:style=
"
{ color: item.titleColor }">
{{
item
.
title
}}
</span>
</div>
<div
class=
"item-center flex flex-row justify-center gap-4px"
>
<span
class=
"text-12px"
:style=
"
{ color: item.subtitleColor }">
{{
item
.
subtitle
}}
</span>
<Icon
icon=
"ep-arrow-right"
color=
"#000"
:size=
"16"
/>
</div>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
MenuListProperty
}
from
'./config'
/** 列表导航 */
defineOptions
({
name
:
'MenuList'
})
defineProps
<
{
property
:
MenuListProperty
}
>
()
</
script
>
<
style
scoped
lang=
"scss"
>
.item
+
.item
{
border-top
:
1px
solid
#eee
;
}
</
style
>
src/components/DiyEditor/components/mobile/MenuList/property.vue
0 → 100644
View file @
b63e2a9e
<
template
>
<ComponentContainerProperty
v-model=
"formData.style"
>
<el-text
tag=
"p"
>
菜单设置
</el-text>
<el-text
type=
"info"
size=
"small"
>
拖动左侧的小圆点可以调整顺序
</el-text>
<!-- 表单 -->
<el-form
label-width=
"60px"
:model=
"formData"
class=
"m-t-8px"
>
<div
v-if=
"formData.list.length"
>
<VueDraggable
:list=
"formData.list"
item-key=
"index"
handle=
".drag-icon"
:forceFallback=
"true"
:animation=
"200"
>
<template
#
item=
"
{ element, index }">
<div
class=
"mb-4px flex flex-col gap-4px rounded bg-gray-100 p-8px"
>
<div
class=
"flex flex-row justify-between"
>
<Icon
icon=
"ic:round-drag-indicator"
class=
"drag-icon cursor-move"
/>
<Icon
icon=
"ep:delete"
class=
"text-red-500"
@
click=
"handleDeleteMenu(index)"
/>
</div>
<el-form-item
label=
"图标"
prop=
"iconUrl"
>
<UploadImg
v-model=
"element.iconUrl"
height=
"80px"
width=
"80px"
>
<template
#
tip
>
建议尺寸:44 * 44
</
template
>
</UploadImg>
</el-form-item>
<el-form-item
label=
"标题"
prop=
"title"
>
<InputWithColor
v-model=
"element.title"
v-model:color=
"element.titleColor"
/>
</el-form-item>
<el-form-item
label=
"副标题"
prop=
"subtitle"
>
<InputWithColor
v-model=
"element.subtitle"
v-model:color=
"element.subtitleColor"
/>
</el-form-item>
<el-form-item
label=
"链接"
prop=
"url"
>
<el-input
v-model=
"element.url"
/>
</el-form-item>
</div>
</template>
</VueDraggable>
</div>
<el-form-item
label-width=
"0"
>
<el-button
@
click=
"handleAddMenu"
type=
"primary"
plain
class=
"m-t-8px w-full"
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
添加菜单
</el-button>
</el-form-item>
</el-form>
</ComponentContainerProperty>
</template>
<
script
setup
lang=
"ts"
>
import
VueDraggable
from
'vuedraggable'
import
{
usePropertyForm
}
from
'@/components/DiyEditor/util'
import
{
EMPTY_MENU_LIST_ITEM_PROPERTY
,
MenuListProperty
}
from
'@/components/DiyEditor/components/mobile/MenuList/config'
import
{
cloneDeep
}
from
'lodash-es'
/** 列表导航属性面板 */
defineOptions
({
name
:
'MenuListProperty'
})
const
props
=
defineProps
<
{
modelValue
:
MenuListProperty
}
>
()
const
emit
=
defineEmits
([
'update:modelValue'
])
const
{
formData
}
=
usePropertyForm
(
props
.
modelValue
,
emit
)
/* 添加菜单 */
const
handleAddMenu
=
()
=>
{
formData
.
value
.
list
.
push
(
cloneDeep
(
EMPTY_MENU_LIST_ITEM_PROPERTY
))
}
/* 删除菜单 */
const
handleDeleteMenu
=
(
index
:
number
)
=>
{
formData
.
value
.
list
.
splice
(
index
,
1
)
}
</
script
>
<
style
scoped
lang=
"scss"
></
style
>
src/components/DiyEditor/components/mobile/MenuSwiper/config.ts
0 → 100644
View file @
b63e2a9e
import
{
ComponentStyle
,
DiyComponent
}
from
'@/components/DiyEditor/util'
import
{
cloneDeep
}
from
'lodash-es'
/** 菜单导航属性 */
export
interface
MenuSwiperProperty
{
// 布局: 图标+文字 | 图标
layout
:
'iconText'
|
'icon'
// 行数
row
:
number
// 列数
column
:
number
// 导航菜单列表
list
:
MenuSwiperItemProperty
[]
// 组件样式
style
:
ComponentStyle
}
/** 菜单导航项目属性 */
export
interface
MenuSwiperItemProperty
{
// 图标链接
iconUrl
:
string
// 标题
title
:
string
// 标题颜色
titleColor
:
string
// 链接
url
:
string
// 角标
badge
:
{
// 是否显示
show
:
boolean
// 角标文字
text
:
string
// 角标文字颜色
textColor
:
string
// 角标背景颜色
bgColor
:
string
}
}
export
const
EMPTY_MENU_SWIPER_ITEM_PROPERTY
=
{
title
:
'标题'
,
titleColor
:
'#333'
,
badge
:
{
show
:
false
,
textColor
:
'#fff'
,
bgColor
:
'#FF6000'
}
}
as
MenuSwiperItemProperty
// 定义组件
export
const
component
=
{
id
:
'MenuSwiper'
,
name
:
'菜单导航'
,
icon
:
'bi:grid-3x2-gap'
,
property
:
{
layout
:
'iconText'
,
row
:
1
,
column
:
3
,
list
:
[
cloneDeep
(
EMPTY_MENU_SWIPER_ITEM_PROPERTY
)],
style
:
{
bgType
:
'color'
,
bgColor
:
'#fff'
,
marginBottom
:
8
}
as
ComponentStyle
}
}
as
DiyComponent
<
MenuSwiperProperty
>
src/components/DiyEditor/components/mobile/MenuSwiper/index.vue
0 → 100644
View file @
b63e2a9e
<
template
>
<el-carousel
:height=
"`$
{carouselHeight}px`"
:autoplay="false"
arrow="hover"
indicator-position="outside"
>
<el-carousel-item
v-for=
"(page, pageIndex) in pages"
:key=
"pageIndex"
>
<div
class=
"flex flex-row flex-wrap"
>
<div
v-for=
"(item, index) in page"
:key=
"index"
class=
"relative flex flex-col items-center justify-center"
:style=
"
{ width: columnWidth, height: `${rowHeight}px` }"
>
<!-- 图标 + 角标 -->
<div
class=
"relative"
:class=
"`h-$
{ICON_SIZE}px w-${ICON_SIZE}px`">
<!-- 右上角角标 -->
<span
v-if=
"item.badge?.show"
class=
"absolute right--10px top--10px z-1 h-20px rounded-10px p-x-6px text-center text-12px leading-20px"
:style=
"
{ color: item.badge.textColor, backgroundColor: item.badge.bgColor }"
>
{{
item
.
badge
.
text
}}
</span>
<el-image
v-if=
"item.iconUrl"
:src=
"item.iconUrl"
class=
"h-full w-full"
/>
</div>
<!-- 标题 -->
<span
v-if=
"property.layout === 'iconText'"
class=
"text-14px"
:style=
"
{
color: item.titleColor,
height: `${TITLE_HEIGHT}px`,
lineHeight: `${TITLE_HEIGHT}px`
}"
>
{{
item
.
title
}}
</span>
</div>
</div>
</el-carousel-item>
</el-carousel>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
MenuSwiperProperty
,
MenuSwiperItemProperty
}
from
'./config'
/** 菜单导航 */
defineOptions
({
name
:
'MenuSwiper'
})
const
props
=
defineProps
<
{
property
:
MenuSwiperProperty
}
>
()
// 标题的高度
const
TITLE_HEIGHT
=
20
// 图标的高度
const
ICON_SIZE
=
50
// 垂直间距:一行上下的间距
const
SPACE_Y
=
16
// 分页
const
pages
=
ref
<
MenuSwiperItemProperty
[][]
>
([])
// 轮播图高度
const
carouselHeight
=
ref
(
0
)
// 行高
const
rowHeight
=
ref
(
0
)
// 列宽
const
columnWidth
=
ref
(
''
)
watch
(
()
=>
props
.
property
,
()
=>
{
// 计算列宽:每一列的百分比
columnWidth
.
value
=
`
${
100
*
(
1
/
props
.
property
.
column
)}
%`
// 计算行高:图标 + 文字(仅显示图片时为0) + 垂直间距 * 2
rowHeight
.
value
=
(
props
.
property
.
layout
===
'iconText'
?
ICON_SIZE
+
TITLE_HEIGHT
:
ICON_SIZE
)
+
SPACE_Y
*
2
// 计算轮播的高度:行数 * 行高
carouselHeight
.
value
=
props
.
property
.
row
*
rowHeight
.
value
// 每页数量:行数 * 列数
const
pageSize
=
props
.
property
.
row
*
props
.
property
.
column
// 清空分页
pages
.
value
=
[]
// 每一页的菜单
let
pageItems
:
MenuSwiperItemProperty
[]
=
[]
for
(
const
item
of
props
.
property
.
list
)
{
// 本页满员,新建下一页
if
(
pageItems
.
length
===
pageSize
)
{
pageItems
=
[]
}
// 增加一页
if
(
pageItems
.
length
===
0
)
{
pages
.
value
.
push
(
pageItems
)
}
// 本页增加一个
pageItems
.
push
(
item
)
}
},
{
immediate
:
true
,
deep
:
true
}
)
</
script
>
<
style
lang=
"scss"
>
//
重写指示器样式,与
APP
保持一致
:root
{
.el-carousel__indicator
{
padding-top
:
0
;
padding-bottom
:
0
;
.el-carousel__button
{
--el-carousel-indicator-height
:
6px
;
--el-carousel-indicator-width
:
6px
;
--el-carousel-indicator-out-color
:
#ff6000
;
border-radius
:
6px
;
}
}
.el-carousel__indicator.is-active
{
.el-carousel__button
{
--el-carousel-indicator-width
:
12px
;
}
}
}
</
style
>
src/components/DiyEditor/components/mobile/MenuSwiper/property.vue
0 → 100644
View file @
b63e2a9e
<
template
>
<ComponentContainerProperty
v-model=
"formData.style"
>
<!-- 表单 -->
<el-form
label-width=
"80px"
:model=
"formData"
class=
"m-t-8px"
>
<el-form-item
label=
"布局"
prop=
"layout"
>
<el-radio-group
v-model=
"formData.layout"
>
<el-radio
label=
"iconText"
>
图标+文字
</el-radio>
<el-radio
label=
"icon"
>
仅图标
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"行数"
prop=
"row"
>
<el-radio-group
v-model=
"formData.row"
>
<el-radio
:label=
"1"
>
1行
</el-radio>
<el-radio
:label=
"2"
>
2行
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"列数"
prop=
"column"
>
<el-radio-group
v-model=
"formData.column"
>
<el-radio
:label=
"3"
>
3列
</el-radio>
<el-radio
:label=
"4"
>
4列
</el-radio>
<el-radio
:label=
"5"
>
5列
</el-radio>
</el-radio-group>
</el-form-item>
<el-text
tag=
"p"
>
菜单设置
</el-text>
<el-text
type=
"info"
size=
"small"
>
拖动左侧的小圆点可以调整顺序
</el-text>
<template
v-if=
"formData.list.length"
>
<VueDraggable
class=
"m-t-8px"
:list=
"formData.list"
item-key=
"index"
handle=
".drag-icon"
:forceFallback=
"true"
:animation=
"200"
>
<template
#
item=
"
{ element, index }">
<div
class=
"mb-4px flex flex-col gap-4px rounded bg-gray-100 p-8px"
>
<div
class=
"flex flex-row justify-between"
>
<Icon
icon=
"ic:round-drag-indicator"
class=
"drag-icon cursor-move"
/>
<Icon
icon=
"ep:delete"
class=
"text-red-500"
@
click=
"handleDeleteMenu(index)"
/>
</div>
<el-form-item
label=
"图标"
prop=
"iconUrl"
>
<UploadImg
v-model=
"element.iconUrl"
height=
"80px"
width=
"80px"
>
<template
#
tip
>
建议尺寸:98 * 98
</
template
>
</UploadImg>
</el-form-item>
<el-form-item
label=
"标题"
prop=
"title"
>
<InputWithColor
v-model=
"element.title"
v-model:color=
"element.titleColor"
/>
</el-form-item>
<el-form-item
label=
"链接"
prop=
"url"
>
<el-input
v-model=
"element.url"
/>
</el-form-item>
<el-form-item
label=
"显示角标"
prop=
"badge.show"
>
<el-switch
v-model=
"element.badge.show"
/>
</el-form-item>
<
template
v-if=
"element.badge.show"
>
<el-form-item
label=
"角标内容"
prop=
"badge.text"
>
<InputWithColor
v-model=
"element.badge.text"
v-model:color=
"element.badge.textColor"
/>
</el-form-item>
<el-form-item
label=
"背景颜色"
prop=
"badge.bgColor"
>
<ColorInput
v-model=
"element.badge.bgColor"
/>
</el-form-item>
</
template
>
</div>
</template>
</VueDraggable>
</template>
<el-form-item
label-width=
"0"
>
<el-button
@
click=
"handleAddMenu"
type=
"primary"
plain
class=
"m-t-8px w-full"
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
添加菜单
</el-button>
</el-form-item>
</el-form>
</ComponentContainerProperty>
</template>
<
script
setup
lang=
"ts"
>
import
VueDraggable
from
'vuedraggable'
import
{
usePropertyForm
}
from
'@/components/DiyEditor/util'
import
{
EMPTY_MENU_SWIPER_ITEM_PROPERTY
,
MenuSwiperProperty
}
from
'@/components/DiyEditor/components/mobile/MenuSwiper/config'
import
{
cloneDeep
}
from
'lodash-es'
/** 菜单导航属性面板 */
defineOptions
({
name
:
'MenuSwiperProperty'
})
const
props
=
defineProps
<
{
modelValue
:
MenuSwiperProperty
}
>
()
const
emit
=
defineEmits
([
'update:modelValue'
])
const
{
formData
}
=
usePropertyForm
(
props
.
modelValue
,
emit
)
/* 添加菜单 */
const
handleAddMenu
=
()
=>
{
formData
.
value
.
list
.
push
(
cloneDeep
(
EMPTY_MENU_SWIPER_ITEM_PROPERTY
))
}
/* 删除菜单 */
const
handleDeleteMenu
=
(
index
:
number
)
=>
{
formData
.
value
.
list
.
splice
(
index
,
1
)
}
</
script
>
<
style
scoped
lang=
"scss"
></
style
>
src/components/DiyEditor/util.ts
View file @
b63e2a9e
...
@@ -100,16 +100,13 @@ export const PAGE_LIBS = [
...
@@ -100,16 +100,13 @@ export const PAGE_LIBS = [
{
{
name
:
'基础组件'
,
name
:
'基础组件'
,
extended
:
true
,
extended
:
true
,
components
:
[
components
:
[
'SearchBar'
,
'NoticeBar'
,
'MenuSwiper'
,
'MenuGrid'
,
'MenuList'
]
'SearchBar'
,
},
'NoticeBar'
,
{
'GridNavigation'
,
name
:
'图文组件'
,
'ListNavigation'
,
extended
:
true
,
'Divider'
,
components
:
[
'ImageBar'
,
'Carousel'
,
'TitleBar'
,
'VideoPlayer'
,
'Divider'
]
'TitleBar'
]
},
},
{
name
:
'图文组件'
,
extended
:
true
,
components
:
[
'ImageBar'
,
'Carousel'
,
'VideoPlayer'
]
},
{
name
:
'商品组件'
,
extended
:
true
,
components
:
[
'ProductCard'
]
},
{
name
:
'商品组件'
,
extended
:
true
,
components
:
[
'ProductCard'
]
},
{
{
name
:
'会员组件'
,
name
:
'会员组件'
,
...
...
src/components/InputWithColor/index.vue
0 → 100644
View file @
b63e2a9e
<
template
>
<el-input
v-model=
"valueRef"
v-bind=
"$attrs"
>
<template
#
append
>
<el-color-picker
v-model=
"colorRef"
:predefine=
"PREDEFINE_COLORS"
/>
</
template
>
</el-input>
</template>
<
script
lang=
"ts"
setup
>
import
{
propTypes
}
from
'@/utils/propTypes'
import
{
PREDEFINE_COLORS
}
from
'@/utils/color'
/**
* 带颜色选择器输入框
*/
defineOptions
({
name
:
'InputWithColor'
})
const
props
=
defineProps
({
modelValue
:
propTypes
.
string
.
def
(
''
).
isRequired
,
color
:
propTypes
.
string
.
def
(
''
).
isRequired
})
watch
(
()
=>
props
.
modelValue
,
(
val
:
string
)
=>
{
if
(
val
===
unref
(
valueRef
))
return
valueRef
.
value
=
val
}
)
const
emit
=
defineEmits
([
'update:modelValue'
,
'update:color'
])
// 输入框的值
const
valueRef
=
ref
(
props
.
modelValue
)
watch
(
()
=>
valueRef
.
value
,
(
val
:
string
)
=>
{
emit
(
'update:modelValue'
,
val
)
}
)
// 颜色
const
colorRef
=
ref
(
props
.
color
)
watch
(
()
=>
colorRef
.
value
,
(
val
:
string
)
=>
{
emit
(
'update:color'
,
val
)
}
)
</
script
>
<
style
scoped
lang=
"scss"
>
:deep
(
.el-input-group__append
)
{
padding
:
0
;
.el-color-picker__trigger
{
padding
:
0
;
border-left
:
none
;
border-radius
:
0
var
(
--el-input-border-radius
)
var
(
--el-input-border-radius
)
0
;
}
}
</
style
>
src/utils/color.ts
View file @
b63e2a9e
...
@@ -151,3 +151,24 @@ const subtractLight = (color: string, amount: number) => {
...
@@ -151,3 +151,24 @@ const subtractLight = (color: string, amount: number) => {
const
c
=
cc
<
0
?
0
:
cc
const
c
=
cc
<
0
?
0
:
cc
return
c
.
toString
(
16
).
length
>
1
?
c
.
toString
(
16
)
:
`0
${
c
.
toString
(
16
)}
`
return
c
.
toString
(
16
).
length
>
1
?
c
.
toString
(
16
)
:
`0
${
c
.
toString
(
16
)}
`
}
}
// 预设颜色
export
const
PREDEFINE_COLORS
=
[
'#ff4500'
,
'#ff8c00'
,
'#ffd700'
,
'#90ee90'
,
'#00ced1'
,
'#1e90ff'
,
'#c71585'
,
'#409EFF'
,
'#909399'
,
'#C0C4CC'
,
'#b7390b'
,
'#ff7800'
,
'#fad400'
,
'#5b8c5f'
,
'#00babd'
,
'#1f73c3'
,
'#711f57'
]
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