Files
medical-mall/components/consumer/PddWaterfallCard.uvue
2026-05-14 15:28:09 +08:00

258 lines
5.4 KiB
Plaintext

<template>
<view class="pdd-card" @tap="handleTap">
<image
class="pdd-card-image"
:src="cover"
mode="aspectFill"
lazy-load="true"
@error="handleImageError"
/>
<view class="pdd-card-body">
<view class="pdd-title-wrap">
<view v-if="promoTags.length > 0" class="pdd-inline-tags">
<text
v-for="(tag, index) in promoTags"
:key="tag.code + '-' + index"
:class="['pdd-inline-tag', getTagClass(tag.code)]"
>
{{ tag.label }}
</text>
</view>
<text class="pdd-title-text">{{ product.title }}</text>
</view>
<view class="pdd-price-row">
<text class="pdd-price-symbol">{{ currencySymbol }}</text>
<text class="pdd-price-int">{{ priceInteger }}</text>
<text class="pdd-price-decimal">.{{ priceDecimal }}</text>
</view>
<view class="pdd-sales-wrap">
<text class="pdd-sales-text">{{ product.salesText }}</text>
<text class="pdd-sales-text">{{ product.seedText }}</text>
</view>
</view>
</view>
</template>
<script lang="uts">
type PddProductCardData = {
id: string
title: string
image: string
tags: string[]
price: number
salesText: string
seedText: string
}
export default {
props: {
product: {
type: Object,
default: () => ({
id: '',
title: '',
image: '',
tags: [] as string[],
price: 0,
salesText: '',
seedText: ''
})
}
},
data() {
return {
cover: '',
currencySymbol: '\u00A5',
priceInteger: '0',
priceDecimal: '00',
promoTags: [] as Array<{ code: string, label: string }>
}
},
created() {
this.syncViewData()
},
watch: {
product: {
handler() {
this.syncViewData()
},
deep: true
}
},
methods: {
syncViewData() {
const product = this.product as PddProductCardData
const image = product.image != null && product.image !== '' ? product.image : '/static/images/default-product.png'
this.cover = image
const price = product.price != null ? product.price : 0
const priceText = Number(price).toFixed(2)
const segments = priceText.split('.')
this.priceInteger = segments.length > 0 ? segments[0] : '0'
this.priceDecimal = segments.length > 1 ? segments[1] : '00'
const tags = Array.isArray(product.tags) ? product.tags : []
const nextTags: Array<{ code: string, label: string }> = []
for (let i = 0; i < tags.length && i < 2; i++) {
const code = tags[i]
nextTags.push({
code,
label: this.getTagLabel(code)
})
}
this.promoTags = nextTags
},
getTagLabel(tagCode: string): string {
if (tagCode == 'billion_subsidy') return '\u767E\u4EBF\u8865\u8D34'
if (tagCode == 'official_subsidy') return '\u5B98\u65B9\u8865\u8D34'
if (tagCode == 'pay_later') return '\u5148\u7528\u540E\u4ED8'
if (tagCode == 'delivery_48h') return '\u540E\u5929\u8FBE'
return '\u70ED\u5356'
},
getTagClass(tagCode: string): string {
if (tagCode == 'billion_subsidy') return 'tag-billion'
if (tagCode == 'official_subsidy') return 'tag-official'
if (tagCode == 'pay_later') return 'tag-pay-later'
if (tagCode == 'delivery_48h') return 'tag-delivery'
return 'tag-default'
},
handleImageError() {
this.cover = '/static/images/default-product.png'
},
handleTap() {
this.$emit('select', this.product)
}
}
}
</script>
<style scoped>
.pdd-card {
background: #ffffff;
border-radius: 18rpx;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 2rpx 10rpx rgba(237, 42, 69, 0.06);
}
.pdd-card-image {
width: 100%;
height: 344rpx;
background: #f1f1f1;
}
.pdd-card-body {
padding: 10rpx 10rpx 12rpx;
}
.pdd-title-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-start;
height: 72rpx;
overflow: hidden;
margin-bottom: 6rpx;
}
.pdd-inline-tags {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-right: 6rpx;
}
.pdd-inline-tag {
height: 28rpx;
line-height: 28rpx;
padding: 0 8rpx;
border-radius: 8rpx;
font-size: 18rpx;
font-weight: 700;
margin-right: 6rpx;
margin-bottom: 4rpx;
}
.tag-billion {
background: linear-gradient(90deg, #ff2d55 0%, #ff7a00 100%);
color: #fff7d1;
}
.tag-official {
background: #ff4d00;
color: #fff2b3;
}
.tag-pay-later {
background: #ffd84d;
color: #9c1f00;
}
.tag-delivery {
background: #22c55e;
color: #ffffff;
}
.tag-default {
background: #ffedd5;
color: #c2410c;
}
.pdd-title-text {
flex: 1;
font-size: 24rpx;
line-height: 32rpx;
color: #222222;
min-width: 0;
}
.pdd-price-row {
display: flex;
flex-direction: row;
align-items: flex-end;
margin-top: 2rpx;
margin-bottom: 4rpx;
}
.pdd-price-symbol {
font-size: 20rpx;
line-height: 1;
color: #ff1030;
font-weight: 700;
margin-right: 2rpx;
margin-bottom: 6rpx;
}
.pdd-price-int {
font-size: 40rpx;
line-height: 1;
color: #ff1030;
font-weight: 800;
letter-spacing: -1rpx;
}
.pdd-price-decimal {
font-size: 22rpx;
line-height: 1;
color: #ff1030;
font-weight: 700;
margin-left: 2rpx;
margin-bottom: 4rpx;
}
.pdd-sales-wrap {
display: flex;
flex-direction: column;
}
.pdd-sales-text {
font-size: 20rpx;
line-height: 28rpx;
color: #8f8f8f;
}
</style>