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
3198688e
authored
Nov 19, 2023
by
owen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
营销:适配商城装修组件【商品栏】
parent
ebb19cfe
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
292 additions
and
2 deletions
+292
-2
src/components/DiyEditor/components/mobile/ProductList/config.ts
+64
-0
src/components/DiyEditor/components/mobile/ProductList/index.vue
+128
-0
src/components/DiyEditor/components/mobile/ProductList/property.vue
+99
-0
src/components/DiyEditor/util.ts
+1
-1
src/views/mall/product/spu/components/SpuShowcase.vue
+0
-1
No files found.
src/components/DiyEditor/components/mobile/ProductList/config.ts
0 → 100644
View file @
3198688e
import
{
ComponentStyle
,
DiyComponent
}
from
'@/components/DiyEditor/util'
/** 商品卡片属性 */
export
interface
ProductListProperty
{
// 布局类型:双列 | 三列 | 水平滑动
layoutType
:
'twoCol'
|
'threeCol'
|
'horizSwiper'
// 商品字段
fields
:
{
// 商品名称
name
:
ProductListFieldProperty
// 商品价格
price
:
ProductListFieldProperty
}
// 角标
badge
:
{
// 是否显示
show
:
boolean
// 角标图片
imgUrl
:
string
}
// 上圆角
borderRadiusTop
:
number
// 下圆角
borderRadiusBottom
:
number
// 间距
space
:
number
// 商品编号列表
spuIds
:
number
[]
// 组件样式
style
:
ComponentStyle
}
// 商品字段
export
interface
ProductListFieldProperty
{
// 是否显示
show
:
boolean
// 颜色
color
:
string
}
// 定义组件
export
const
component
=
{
id
:
'ProductList'
,
name
:
'商品栏'
,
icon
:
'system-uicons:carousel'
,
property
:
{
layoutType
:
'twoCol'
,
fields
:
{
name
:
{
show
:
true
,
color
:
'#000'
},
price
:
{
show
:
true
,
color
:
'#ff3000'
}
},
badge
:
{
show
:
false
,
imgUrl
:
''
},
borderRadiusTop
:
8
,
borderRadiusBottom
:
8
,
space
:
8
,
spuIds
:
[],
style
:
{
bgType
:
'color'
,
bgColor
:
''
,
marginLeft
:
8
,
marginRight
:
8
,
marginBottom
:
8
}
as
ComponentStyle
}
}
as
DiyComponent
<
ProductListProperty
>
src/components/DiyEditor/components/mobile/ProductList/index.vue
0 → 100644
View file @
3198688e
<
template
>
<el-scrollbar
class=
"z-1 min-h-30px"
wrap-class=
"w-full"
ref=
"containerRef"
>
<!-- 商品网格 -->
<div
class=
"grid overflow-x-auto"
:style=
"
{
gridGap: `${property.space}px`,
gridTemplateColumns,
width: scrollbarWidth,
}"
>
<!-- 商品 -->
<div
class=
"relative box-content flex flex-row flex-wrap overflow-hidden bg-white"
:style=
"
{
borderTopLeftRadius: `${property.borderRadiusTop}px`,
borderTopRightRadius: `${property.borderRadiusTop}px`,
borderBottomLeftRadius: `${property.borderRadiusBottom}px`,
borderBottomRightRadius: `${property.borderRadiusBottom}px`
}"
v-for="(spu, index) in spuList"
:key="index"
>
<!-- 角标 -->
<div
v-if=
"property.badge.show"
class=
"absolute left-0 top-0 z-1 items-center justify-center"
>
<el-image
fit=
"cover"
:src=
"property.badge.imgUrl"
class=
"h-26px w-38px"
/>
</div>
<!-- 商品封面图 -->
<el-image
fit=
"cover"
:src=
"spu.picUrl"
:style=
"
{ width: imageSize, height: imageSize }" />
<div
:class=
"[
'flex flex-col gap-8px p-8px box-border',
{
'w-[calc(100%-64px)]': columns === 2,
'w-full': columns === 3
}
]"
>
<!-- 商品名称 -->
<div
v-if=
"property.fields.name.show"
class=
"truncate text-12px"
:style=
"
{ color: property.fields.name.color }"
>
{{
spu
.
name
}}
</div>
<div>
<!-- 商品价格 -->
<span
v-if=
"property.fields.price.show"
class=
"text-12px"
:style=
"
{ color: property.fields.price.color }"
>
¥
{{
spu
.
price
}}
</span>
</div>
</div>
</div>
</div>
</el-scrollbar>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ProductListProperty
}
from
"./config"
import
*
as
ProductSpuApi
from
"@/api/mall/product/spu"
/** 商品卡片 */
defineOptions
({
name
:
"ProductList"
})
// 定义属性
const
props
=
defineProps
<
{
property
:
ProductListProperty
}
>
()
// 商品列表
const
spuList
=
ref
<
ProductSpuApi
.
Spu
[]
>
([])
watch
(
()
=>
props
.
property
.
spuIds
,
async
()
=>
{
spuList
.
value
=
await
ProductSpuApi
.
getSpuDetailList
(
props
.
property
.
spuIds
)
},
{
immediate
:
true
,
deep
:
true
}
)
// 手机宽度
const
phoneWidth
=
ref
(
375
)
// 容器
const
containerRef
=
ref
()
// 商品的列数
const
columns
=
ref
(
2
)
// 滚动条宽度
const
scrollbarWidth
=
ref
(
"100%"
)
// 商品图大小
const
imageSize
=
ref
(
"0"
)
// 商品网络列数
const
gridTemplateColumns
=
ref
(
""
)
// 计算布局参数
watch
(
()
=>
[
props
.
property
,
phoneWidth
,
spuList
.
value
.
length
],
()
=>
{
// 计算列数
columns
.
value
=
props
.
property
.
layoutType
===
"twoCol"
?
2
:
3
// 提取手机宽度
// 每列的宽度为:(总宽度 - 间距 * (列数 - 1))/ 列数
const
productWidth
=
(
phoneWidth
.
value
-
props
.
property
.
space
*
(
columns
.
value
-
1
))
/
columns
.
value
// 商品图布局:2列时,左右布局 3列时,上下布局
imageSize
.
value
=
columns
.
value
===
2
?
"64px"
:
`
${
productWidth
}
px`
// 根据布局类型,计算行数、列数
if
(
props
.
property
.
layoutType
===
"horizSwiper"
)
{
// 单行显示
gridTemplateColumns
.
value
=
`repeat(auto-fill,
${
productWidth
}
px)`
// 显示滚动条
scrollbarWidth
.
value
=
`
${
productWidth
*
spuList
.
value
.
length
+
props
.
property
.
space
*
(
spuList
.
value
.
length
-
1
)}
px`
}
else
{
// 指定列数
gridTemplateColumns
.
value
=
`repeat(
${
columns
.
value
}
, auto)`
// 不滚动
scrollbarWidth
.
value
=
"100%"
}
},
{
immediate
:
true
,
deep
:
true
}
)
onMounted
(()
=>
{
phoneWidth
.
value
=
containerRef
.
value
?.
wrapRef
?.
offsetWidth
||
375
;
})
</
script
>
<
style
scoped
lang=
"scss"
></
style
>
src/components/DiyEditor/components/mobile/ProductList/property.vue
0 → 100644
View file @
3198688e
<
template
>
<ComponentContainerProperty
v-model=
"formData.style"
>
<el-form
label-width=
"80px"
:model=
"formData"
>
<el-card
header=
"商品列表"
class=
"property-group"
shadow=
"never"
>
<SpuShowcase
v-model=
"formData.spuIds"
/>
</el-card>
<el-card
header=
"商品样式"
class=
"property-group"
shadow=
"never"
>
<el-form-item
label=
"布局"
prop=
"type"
>
<el-radio-group
v-model=
"formData.layoutType"
>
<el-tooltip
class=
"item"
content=
"双列"
placement=
"bottom"
>
<el-radio-button
label=
"twoCol"
>
<Icon
icon=
"fluent:text-column-two-24-filled"
/>
</el-radio-button>
</el-tooltip>
<el-tooltip
class=
"item"
content=
"三列"
placement=
"bottom"
>
<el-radio-button
label=
"threeCol"
>
<Icon
icon=
"fluent:text-column-three-24-filled"
/>
</el-radio-button>
</el-tooltip>
<el-tooltip
class=
"item"
content=
"水平滑动"
placement=
"bottom"
>
<el-radio-button
label=
"horizSwiper"
>
<Icon
icon=
"system-uicons:carousel"
/>
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"商品名称"
prop=
"fields.name.show"
>
<div
class=
"flex gap-8px"
>
<ColorInput
v-model=
"formData.fields.name.color"
/>
<el-checkbox
v-model=
"formData.fields.name.show"
/>
</div>
</el-form-item>
<el-form-item
label=
"商品价格"
prop=
"fields.price.show"
>
<div
class=
"flex gap-8px"
>
<ColorInput
v-model=
"formData.fields.price.color"
/>
<el-checkbox
v-model=
"formData.fields.price.show"
/>
</div>
</el-form-item>
</el-card>
<el-card
header=
"角标"
class=
"property-group"
shadow=
"never"
>
<el-form-item
label=
"角标"
prop=
"badge.show"
>
<el-switch
v-model=
"formData.badge.show"
/>
</el-form-item>
<el-form-item
label=
"角标"
prop=
"badge.imgUrl"
v-if=
"formData.badge.show"
>
<UploadImg
v-model=
"formData.badge.imgUrl"
height=
"44px"
width=
"72px"
>
<template
#
tip
>
建议尺寸:36 * 22
</
template
>
</UploadImg>
</el-form-item>
</el-card>
<el-card
header=
"商品样式"
class=
"property-group"
shadow=
"never"
>
<el-form-item
label=
"上圆角"
prop=
"borderRadiusTop"
>
<el-slider
v-model=
"formData.borderRadiusTop"
:max=
"100"
:min=
"0"
show-input
input-size=
"small"
:show-input-controls=
"false"
/>
</el-form-item>
<el-form-item
label=
"下圆角"
prop=
"borderRadiusBottom"
>
<el-slider
v-model=
"formData.borderRadiusBottom"
:max=
"100"
:min=
"0"
show-input
input-size=
"small"
:show-input-controls=
"false"
/>
</el-form-item>
<el-form-item
label=
"间隔"
prop=
"space"
>
<el-slider
v-model=
"formData.space"
:max=
"100"
:min=
"0"
show-input
input-size=
"small"
:show-input-controls=
"false"
/>
</el-form-item>
</el-card>
</el-form>
</ComponentContainerProperty>
</template>
<
script
setup
lang=
"ts"
>
import
{
ProductListProperty
}
from
'./config'
import
{
usePropertyForm
}
from
'@/components/DiyEditor/util'
import
SpuShowcase
from
'@/views/mall/product/spu/components/SpuShowcase.vue'
// 商品卡片属性面板
defineOptions
({
name
:
'ProductListProperty'
})
const
props
=
defineProps
<
{
modelValue
:
ProductListProperty
}
>
()
const
emit
=
defineEmits
([
'update:modelValue'
])
const
{
formData
}
=
usePropertyForm
(
props
.
modelValue
,
emit
)
</
script
>
<
style
scoped
lang=
"scss"
></
style
>
src/components/DiyEditor/util.ts
View file @
3198688e
...
...
@@ -107,7 +107,7 @@ export const PAGE_LIBS = [
extended
:
true
,
components
:
[
'ImageBar'
,
'Carousel'
,
'TitleBar'
,
'VideoPlayer'
,
'Divider'
,
'MagicCube'
]
},
{
name
:
'商品组件'
,
extended
:
true
,
components
:
[
'ProductCard'
]
},
{
name
:
'商品组件'
,
extended
:
true
,
components
:
[
'ProductCard'
,
'ProductList'
]
},
{
name
:
'会员组件'
,
extended
:
true
,
...
...
src/views/mall/product/spu/components/SpuShowcase.vue
View file @
3198688e
...
...
@@ -59,7 +59,6 @@ watch(
productSpus
.
value
.
length
===
0
||
productSpus
.
value
.
some
((
spu
)
=>
!
props
.
modelValue
.
includes
(
spu
.
id
))
)
{
debugger
productSpus
.
value
=
await
ProductSpuApi
.
getSpuDetailList
(
props
.
modelValue
)
}
},
...
...
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