Skip to content

Commit 5f0b0bd

Browse files
YunaiVgitee-org
authored andcommitted
!324 商城装修
Merge pull request !324 from 疯狂的世界/dev
2 parents 526172a + f5d6119 commit 5f0b0bd

File tree

5 files changed

+538
-1
lines changed

5 files changed

+538
-1
lines changed

src/components/DiyEditor/components/mobile/MagicCube/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export interface MagicCubeItemProperty {
3333
export const component = {
3434
id: 'MagicCube',
3535
name: '广告魔方',
36-
icon: 'fluent:puzzle-cube-piece-20-filled',
36+
icon: 'bi:columns',
3737
property: {
3838
borderRadiusTop: 0,
3939
borderRadiusBottom: 0,
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
2+
3+
/** 商品卡片属性 */
4+
export interface ProductCardProperty {
5+
// 布局类型:单列大图 | 单列小图 | 双列
6+
layoutType: 'oneColBigImg' | 'oneColSmallImg' | 'twoCol'
7+
// 商品字段
8+
fields: {
9+
// 商品名称
10+
name: ProductCardFieldProperty
11+
// 商品简介
12+
introduction: ProductCardFieldProperty
13+
// 商品价格
14+
price: ProductCardFieldProperty
15+
// 商品市场价
16+
marketPrice: ProductCardFieldProperty
17+
// 商品销量
18+
salesCount: ProductCardFieldProperty
19+
// 商品库存
20+
stock: ProductCardFieldProperty
21+
}
22+
// 角标
23+
badge: {
24+
// 是否显示
25+
show: boolean
26+
// 角标图片
27+
imgUrl: string
28+
}
29+
// 按钮
30+
btnBuy: {
31+
// 类型:文字 | 图片
32+
type: 'text' | 'img'
33+
// 文字
34+
text: string
35+
// 文字按钮:背景渐变起始颜色
36+
bgBeginColor: string
37+
// 文字按钮:背景渐变结束颜色
38+
bgEndColor: string
39+
// 图片按钮:图片地址
40+
imgUrl: string
41+
}
42+
// 上圆角
43+
borderRadiusTop: number
44+
// 下圆角
45+
borderRadiusBottom: number
46+
// 间距
47+
space: number
48+
// 商品编号列表
49+
spuIds: number[]
50+
// 组件样式
51+
style: ComponentStyle
52+
}
53+
// 商品字段
54+
export interface ProductCardFieldProperty {
55+
// 是否显示
56+
show: boolean
57+
// 颜色
58+
color: string
59+
}
60+
61+
// 定义组件
62+
export const component = {
63+
id: 'ProductCard',
64+
name: '商品卡片',
65+
icon: 'system-uicons:carousel',
66+
property: {
67+
layoutType: 'oneColBigImg',
68+
fields: {
69+
name: { show: true, color: '#000' },
70+
introduction: { show: true, color: '#999' },
71+
price: { show: true, color: '#ff3000' },
72+
marketPrice: { show: true, color: '#c4c4c4' },
73+
salesCount: { show: true, color: '#c4c4c4' },
74+
stock: { show: false, color: '#c4c4c4' }
75+
},
76+
badge: { show: false, imgUrl: '' },
77+
btnBuy: {
78+
type: 'text',
79+
text: '立即购买',
80+
// todo: @owen 根据主题色配置
81+
bgBeginColor: '#FF6000',
82+
bgEndColor: '#FE832A',
83+
imgUrl: ''
84+
},
85+
borderRadiusTop: 8,
86+
borderRadiusBottom: 8,
87+
space: 8,
88+
spuIds: [],
89+
style: {
90+
bgType: 'color',
91+
bgColor: '',
92+
marginLeft: 8,
93+
marginRight: 8,
94+
marginBottom: 8
95+
} as ComponentStyle
96+
}
97+
} as DiyComponent<ProductCardProperty>
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
<template>
2+
<div :class="`box-content min-h-30px w-full flex flex-row flex-wrap`" ref="containerRef">
3+
<div
4+
class="relative box-content flex flex-row flex-wrap overflow-hidden bg-white"
5+
:style="{
6+
...calculateSpace(index),
7+
...calculateWidth(),
8+
borderTopLeftRadius: `${property.borderRadiusTop}px`,
9+
borderTopRightRadius: `${property.borderRadiusTop}px`,
10+
borderBottomLeftRadius: `${property.borderRadiusBottom}px`,
11+
borderBottomRightRadius: `${property.borderRadiusBottom}px`
12+
}"
13+
v-for="(spu, index) in spuList"
14+
:key="index"
15+
>
16+
<!-- 角标 -->
17+
<div v-if="property.badge.show" class="absolute left-0 top-0 z-1 items-center justify-center">
18+
<el-image fit="cover" :src="property.badge.imgUrl" class="h-26px w-38px" />
19+
</div>
20+
<!-- 商品封面图 -->
21+
<div
22+
:class="[
23+
'h-140px',
24+
{
25+
'w-full': property.layoutType !== 'oneColSmallImg',
26+
'w-140px': property.layoutType === 'oneColSmallImg'
27+
}
28+
]"
29+
>
30+
<el-image fit="cover" class="h-full w-full" :src="spu.picUrl" />
31+
</div>
32+
<div
33+
:class="[
34+
' flex flex-col gap-8px p-8px box-border',
35+
{
36+
'w-full': property.layoutType !== 'oneColSmallImg',
37+
'w-[calc(100%-140px-16px)]': property.layoutType === 'oneColSmallImg'
38+
}
39+
]"
40+
>
41+
<!-- 商品名称 -->
42+
<div
43+
v-if="property.fields.name.show"
44+
:class="[
45+
'text-14px ',
46+
{
47+
truncate: property.layoutType !== 'oneColSmallImg',
48+
'overflow-ellipsis line-clamp-2': property.layoutType === 'oneColSmallImg'
49+
}
50+
]"
51+
:style="{ color: property.fields.name.color }"
52+
>
53+
{{ spu.name }}
54+
</div>
55+
<!-- 商品简介 -->
56+
<div
57+
v-if="property.fields.introduction.show"
58+
class="truncate text-12px"
59+
:style="{ color: property.fields.introduction.color }"
60+
>
61+
{{ spu.introduction }}
62+
</div>
63+
<div>
64+
<!-- 价格 -->
65+
<span
66+
v-if="property.fields.price.show"
67+
class="text-16px"
68+
:style="{ color: property.fields.price.color }"
69+
>
70+
¥{{ spu.price }}
71+
</span>
72+
<!-- 市场价 -->
73+
<span
74+
v-if="property.fields.marketPrice.show && spu.marketPrice"
75+
class="ml-4px text-10px line-through"
76+
:style="{ color: property.fields.marketPrice.color }"
77+
>¥{{ spu.marketPrice }}</span
78+
>
79+
</div>
80+
<div class="text-12px">
81+
<!-- 销量 -->
82+
<span
83+
v-if="property.fields.salesCount.show"
84+
:style="{ color: property.fields.salesCount.color }"
85+
>
86+
已售{{ (spu.salesCount || 0) + (spu.virtualSalesCount || 0) }}件
87+
</span>
88+
<!-- 库存 -->
89+
<span v-if="property.fields.stock.show" :style="{ color: property.fields.stock.color }">
90+
库存{{ spu.stock || 0 }}
91+
</span>
92+
</div>
93+
</div>
94+
<!-- 购买按钮 -->
95+
<div class="absolute bottom-8px right-8px">
96+
<!-- 文字按钮 -->
97+
<span
98+
v-if="property.btnBuy.type === 'text'"
99+
class="rounded-full p-x-12px p-y-4px text-12px text-white"
100+
:style="{
101+
background: `linear-gradient(to right, ${property.btnBuy.bgBeginColor}, ${property.btnBuy.bgEndColor}`
102+
}"
103+
>
104+
{{ property.btnBuy.text }}
105+
</span>
106+
<!-- 图片按钮 -->
107+
<el-image
108+
v-else
109+
class="h-28px w-28px rounded-full"
110+
fit="cover"
111+
:src="property.btnBuy.imgUrl"
112+
/>
113+
</div>
114+
</div>
115+
</div>
116+
</template>
117+
<script setup lang="ts">
118+
import { ProductCardProperty } from './config'
119+
import * as ProductSpuApi from '@/api/mall/product/spu'
120+
121+
/** 商品卡片 */
122+
defineOptions({ name: 'ProductCard' })
123+
// 定义属性
124+
const props = defineProps<{ property: ProductCardProperty }>()
125+
// 商品列表
126+
const spuList = ref<ProductSpuApi.Spu[]>([])
127+
watch(
128+
() => props.property.spuIds,
129+
async () => {
130+
spuList.value = await ProductSpuApi.getSpuDetailList(props.property.spuIds)
131+
},
132+
{
133+
immediate: true,
134+
deep: true
135+
}
136+
)
137+
/**
138+
* 计算商品的间距
139+
* @param index 商品索引
140+
*/
141+
const calculateSpace = (index: number) => {
142+
// 商品的列数
143+
const columns = props.property.layoutType === 'twoCol' ? 2 : 1
144+
// 第一列没有左边距
145+
const marginLeft = index % columns === 0 ? '0' : props.property.space + 'px'
146+
// 第一行没有上边距
147+
const marginTop = index < columns ? '0' : props.property.space + 'px'
148+
149+
return { marginLeft, marginTop }
150+
}
151+
152+
// 容器
153+
const containerRef = ref()
154+
// 计算商品的宽度
155+
const calculateWidth = () => {
156+
let width = '100%'
157+
// 双列时每列的宽度为:(总宽度 - 间距)/ 2
158+
if (props.property.layoutType === 'twoCol') {
159+
width = `${(containerRef.value.offsetWidth - props.property.space) / 2}px`
160+
}
161+
return { width }
162+
}
163+
</script>
164+
165+
<style scoped lang="scss"></style>

0 commit comments

Comments
 (0)