feat:【mall】diy editor 的 product-card 优化 50%
This commit is contained in:
@@ -2,63 +2,40 @@ import type { ComponentStyle, DiyComponent } from '../../../util';
|
|||||||
|
|
||||||
/** 商品卡片属性 */
|
/** 商品卡片属性 */
|
||||||
export interface ProductCardProperty {
|
export interface ProductCardProperty {
|
||||||
// 布局类型:单列大图 | 单列小图 | 双列
|
layoutType: 'oneColBigImg' | 'oneColSmallImg' | 'twoCol'; // 布局类型:单列大图 | 单列小图 | 双列
|
||||||
layoutType: 'oneColBigImg' | 'oneColSmallImg' | 'twoCol';
|
|
||||||
// 商品字段
|
|
||||||
fields: {
|
fields: {
|
||||||
// 商品简介
|
introduction: ProductCardFieldProperty; // 商品简介
|
||||||
introduction: ProductCardFieldProperty;
|
marketPrice: ProductCardFieldProperty; // 商品市场价
|
||||||
// 商品市场价
|
name: ProductCardFieldProperty; // 商品名称
|
||||||
marketPrice: ProductCardFieldProperty;
|
price: ProductCardFieldProperty; // 商品价格
|
||||||
// 商品名称
|
salesCount: ProductCardFieldProperty; // 商品销量
|
||||||
name: ProductCardFieldProperty;
|
stock: ProductCardFieldProperty; // 商品库存
|
||||||
// 商品价格
|
}; // 商品字段
|
||||||
price: ProductCardFieldProperty;
|
|
||||||
// 商品销量
|
|
||||||
salesCount: ProductCardFieldProperty;
|
|
||||||
// 商品库存
|
|
||||||
stock: ProductCardFieldProperty;
|
|
||||||
};
|
|
||||||
// 角标
|
|
||||||
badge: {
|
badge: {
|
||||||
// 角标图片
|
imgUrl: string; // 角标图片
|
||||||
imgUrl: string;
|
show: boolean; // 是否显示
|
||||||
// 是否显示
|
}; // 角标
|
||||||
show: boolean;
|
|
||||||
};
|
|
||||||
// 按钮
|
|
||||||
btnBuy: {
|
btnBuy: {
|
||||||
// 文字按钮:背景渐变起始颜色
|
bgBeginColor: string; // 文字按钮:背景渐变起始颜色
|
||||||
bgBeginColor: string;
|
bgEndColor: string; // 文字按钮:背景渐变结束颜色
|
||||||
// 文字按钮:背景渐变结束颜色
|
imgUrl: string; // 图片按钮:图片地址
|
||||||
bgEndColor: string;
|
text: string; // 文字
|
||||||
// 图片按钮:图片地址
|
type: 'img' | 'text'; // 类型:文字 | 图片
|
||||||
imgUrl: string;
|
}; // 按钮
|
||||||
// 文字
|
borderRadiusTop: number; // 上圆角
|
||||||
text: string;
|
borderRadiusBottom: number; // 下圆角
|
||||||
// 类型:文字 | 图片
|
space: number; // 间距
|
||||||
type: 'img' | 'text';
|
spuIds: number[]; // 商品编号列表
|
||||||
};
|
style: ComponentStyle; // 组件样式
|
||||||
// 上圆角
|
|
||||||
borderRadiusTop: number;
|
|
||||||
// 下圆角
|
|
||||||
borderRadiusBottom: number;
|
|
||||||
// 间距
|
|
||||||
space: number;
|
|
||||||
// 商品编号列表
|
|
||||||
spuIds: number[];
|
|
||||||
// 组件样式
|
|
||||||
style: ComponentStyle;
|
|
||||||
}
|
|
||||||
// 商品字段
|
|
||||||
export interface ProductCardFieldProperty {
|
|
||||||
// 是否显示
|
|
||||||
show: boolean;
|
|
||||||
// 颜色
|
|
||||||
color: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义组件
|
/** 商品字段属性 */
|
||||||
|
export interface ProductCardFieldProperty {
|
||||||
|
show: boolean; // 是否显示
|
||||||
|
color: string; // 颜色
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 定义组件 */
|
||||||
export const component = {
|
export const component = {
|
||||||
id: 'ProductCard',
|
id: 'ProductCard',
|
||||||
name: '商品卡片',
|
name: '商品卡片',
|
||||||
|
|||||||
@@ -13,10 +13,11 @@ import * as ProductSpuApi from '#/api/mall/product/spu';
|
|||||||
|
|
||||||
/** 商品卡片 */
|
/** 商品卡片 */
|
||||||
defineOptions({ name: 'ProductCard' });
|
defineOptions({ name: 'ProductCard' });
|
||||||
// 定义属性
|
|
||||||
const props = defineProps<{ property: ProductCardProperty }>();
|
const props = defineProps<{ property: ProductCardProperty }>();
|
||||||
// 商品列表
|
|
||||||
const spuList = ref<MallSpuApi.Spu[]>([]);
|
const spuList = ref<MallSpuApi.Spu[]>([]);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.property.spuIds,
|
() => props.property.spuIds,
|
||||||
async () => {
|
async () => {
|
||||||
@@ -28,28 +29,21 @@ watch(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/** 计算商品的间距 */
|
||||||
* 计算商品的间距
|
function calculateSpace(index: number) {
|
||||||
* @param index 商品索引
|
const columns = props.property.layoutType === 'twoCol' ? 2 : 1; // 商品的列数
|
||||||
*/
|
const marginLeft = index % columns === 0 ? '0' : `${props.property.space}px`; // 第一列没有左边距
|
||||||
const calculateSpace = (index: number) => {
|
const marginTop = index < columns ? '0' : `${props.property.space}px`; // 第一行没有上边距
|
||||||
// 商品的列数
|
|
||||||
const columns = props.property.layoutType === 'twoCol' ? 2 : 1;
|
|
||||||
// 第一列没有左边距
|
|
||||||
const marginLeft = index % columns === 0 ? '0' : `${props.property.space}px`;
|
|
||||||
// 第一行没有上边距
|
|
||||||
const marginTop = index < columns ? '0' : `${props.property.space}px`;
|
|
||||||
|
|
||||||
return { marginLeft, marginTop };
|
return { marginLeft, marginTop };
|
||||||
};
|
}
|
||||||
|
|
||||||
// 容器
|
|
||||||
const containerRef = ref();
|
const containerRef = ref();
|
||||||
// 计算商品的宽度
|
|
||||||
|
/** 计算商品的宽度 */
|
||||||
const calculateWidth = () => {
|
const calculateWidth = () => {
|
||||||
let width = '100%';
|
let width = '100%';
|
||||||
// 双列时每列的宽度为:(总宽度 - 间距)/ 2
|
|
||||||
if (props.property.layoutType === 'twoCol') {
|
if (props.property.layoutType === 'twoCol') {
|
||||||
|
// 双列时每列的宽度为:(总宽度 - 间距)/ 2
|
||||||
width = `${(containerRef.value.offsetWidth - props.property.space) / 2}px`;
|
width = `${(containerRef.value.offsetWidth - props.property.space) / 2}px`;
|
||||||
}
|
}
|
||||||
return { width };
|
return { width };
|
||||||
@@ -136,14 +130,14 @@ const calculateWidth = () => {
|
|||||||
class="text-[16px]"
|
class="text-[16px]"
|
||||||
:style="{ color: property.fields.price.color }"
|
:style="{ color: property.fields.price.color }"
|
||||||
>
|
>
|
||||||
¥{{ fenToYuan(spu.price as any) }}
|
¥{{ fenToYuan(spu.price!) }}
|
||||||
</span>
|
</span>
|
||||||
<!-- 市场价 -->
|
<!-- 市场价 -->
|
||||||
<span
|
<span
|
||||||
v-if="property.fields.marketPrice.show && spu.marketPrice"
|
v-if="property.fields.marketPrice.show && spu.marketPrice"
|
||||||
class="ml-[4px] text-[10px] line-through"
|
class="ml-[4px] text-[10px] line-through"
|
||||||
:style="{ color: property.fields.marketPrice.color }"
|
:style="{ color: property.fields.marketPrice.color }"
|
||||||
>¥{{ fenToYuan(spu.marketPrice) }}
|
>¥{{ fenToYuan(spu.marketPrice!) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-[12px]">
|
<div class="text-[12px]">
|
||||||
@@ -186,5 +180,3 @@ const calculateWidth = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
|
||||||
|
|||||||
@@ -22,11 +22,15 @@ import { ColorInput } from '#/views/mall/promotion/components';
|
|||||||
// TODO: 添加组件
|
// TODO: 添加组件
|
||||||
// import SpuShowcase from '#/views/mall/product/spu/components/spu-showcase.vue';
|
// import SpuShowcase from '#/views/mall/product/spu/components/spu-showcase.vue';
|
||||||
|
|
||||||
// 商品卡片属性面板
|
import ComponentContainerProperty from '../../component-container-property.vue';
|
||||||
|
|
||||||
|
/** 商品卡片属性面板 */
|
||||||
defineOptions({ name: 'ProductCardProperty' });
|
defineOptions({ name: 'ProductCardProperty' });
|
||||||
|
|
||||||
const props = defineProps<{ modelValue: ProductCardProperty }>();
|
const props = defineProps<{ modelValue: ProductCardProperty }>();
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
const formData = useVModel(props, 'modelValue', emit);
|
const formData = useVModel(props, 'modelValue', emit);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -174,5 +178,3 @@ const formData = useVModel(props, 'modelValue', emit);
|
|||||||
</ElForm>
|
</ElForm>
|
||||||
</ComponentContainerProperty>
|
</ComponentContainerProperty>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user