This commit is contained in:
@@ -5,36 +5,42 @@
|
||||
|
||||
<div class="space-y-4">
|
||||
<template v-for="(plan, index) in plans" :key="plan.id">
|
||||
<!-- Special Trial Card -->
|
||||
<!-- Activity Price Card -->
|
||||
<div
|
||||
v-if="index === 0 && trialPlan"
|
||||
@click="$emit('select', trialPlan.id)"
|
||||
v-if="hasActivityPrice(plan, index)"
|
||||
@click="$emit('select', activityPlan(plan, index).id)"
|
||||
class="relative h-[126px] cursor-pointer overflow-hidden rounded-[40px] border-4 border-black bg-[#A8FF53] transition-all"
|
||||
>
|
||||
<!-- Left content (Original Plan but dimmed/struck) -->
|
||||
<div class="py-4 pl-[45px] opacity-60">
|
||||
<div class="py-4 pl-[25px] opacity-60">
|
||||
<div class="text-2xl font-bold text-black">{{ plan.days }}天</div>
|
||||
<div class="relative w-fit text-[40px] leading-none font-semibold text-black">
|
||||
${{ plan.price }}
|
||||
<div class="absolute top-1/2 left-0 h-1 w-full -translate-y-1/2 bg-black/60"></div>
|
||||
<div class="absolute top-1/2 left-0 h-1.5 w-full -translate-y-1/2 bg-black/60"></div>
|
||||
</div>
|
||||
<div class="text-sm text-black">约${{ plan.daily }}/天</div>
|
||||
</div>
|
||||
|
||||
<!-- Right overlay (Trial Info) -->
|
||||
<!-- Right overlay (Activity Info) -->
|
||||
<div
|
||||
class="absolute top-0 right-0 bottom-0 flex h-[120px] w-[126px] flex-col justify-center rounded-bl-[40px] bg-black/60 text-[#ADFF5B]"
|
||||
>
|
||||
<div class="ml-[4px] flex h-full w-full flex-col rounded-bl-[40px] bg-black">
|
||||
<div class="pt-2 pl-1">
|
||||
<div class="text-lg font-bold">新客尝鲜价</div>
|
||||
<div class="mb-1 text-xs">{{ trialCountdown }}</div>
|
||||
<div class="pt-1.5 pl-1 leading-[1.05]">
|
||||
<div class="text-[14px] font-bold">{{ activityTitle(plan, index) }}</div>
|
||||
<div class="mb-0.5 text-[10px]" v-if="activityCountdown(plan, index)">
|
||||
{{ activityCountdown(plan, index) }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex h-full flex-1 items-center justify-center rounded-bl-[40px] border-4 border-black bg-[#ADFF5B] text-4xl font-semibold"
|
||||
:class="isTrialSelected ? 'bg-black text-white' : 'bg-[#ADFF5B] text-black'"
|
||||
class="flex h-full flex-1 items-center justify-center rounded-bl-[40px] border-4 border-black bg-[#ADFF5B] text-[32px] leading-none font-semibold"
|
||||
:class="
|
||||
isActivitySelected(plan, index)
|
||||
? 'bg-black text-white'
|
||||
: 'bg-[#ADFF5B] text-black'
|
||||
"
|
||||
>
|
||||
${{ trialPlan.price }}
|
||||
${{ activityPrice(plan, index) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -51,7 +57,7 @@
|
||||
>
|
||||
<div class="flex items-center gap-2 text-2xl font-bold">
|
||||
<Goods90Icon
|
||||
v-if="plan.days === 90"
|
||||
v-if="plan.days === 90 && !plan.promoPrice"
|
||||
:class="[currentPlanIndex === index ? 'text-[#ADFF5B]' : 'text-black']"
|
||||
/>
|
||||
{{ plan.days }}天
|
||||
@@ -79,7 +85,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import Goods90Icon from './goods-90-icon.svg'
|
||||
const props = defineProps({
|
||||
plans: Array,
|
||||
@@ -90,7 +96,70 @@ const props = defineProps({
|
||||
})
|
||||
defineEmits(['select'])
|
||||
|
||||
const now = ref(Date.now())
|
||||
const countdownStart = Date.now()
|
||||
let timer = null
|
||||
|
||||
const isTrialSelected = computed(() => {
|
||||
return props.trialPlan && props.selectedPlanId === props.trialPlan.id
|
||||
})
|
||||
|
||||
const hasActivityPrice = (plan, index) => {
|
||||
return Boolean(plan?.promoPrice || (index === 0 && props.trialPlan))
|
||||
}
|
||||
|
||||
const activityPlan = (plan, index) => {
|
||||
if (plan?.promoPrice) return plan
|
||||
if (index === 0 && props.trialPlan) return props.trialPlan
|
||||
return plan
|
||||
}
|
||||
|
||||
const activityTitle = (plan, index) => {
|
||||
const promoPlan = activityPlan(plan, index)
|
||||
return promoPlan?.promoTitle || promoPlan?.discount || '新客尝鲜价'
|
||||
}
|
||||
|
||||
const activityPrice = (plan, index) => {
|
||||
const promoPlan = activityPlan(plan, index)
|
||||
return promoPlan?.promoPrice || promoPlan?.price
|
||||
}
|
||||
|
||||
const activityCountdown = (plan, index) => {
|
||||
const promoPlan = activityPlan(plan, index)
|
||||
if (promoPlan?.promoPrice) {
|
||||
return formatPromoCountdown(promoPlan.promoRemainingSeconds)
|
||||
}
|
||||
return props.trialCountdown
|
||||
}
|
||||
|
||||
const isActivitySelected = (plan, index) => {
|
||||
const promoPlan = activityPlan(plan, index)
|
||||
return props.selectedPlanId === promoPlan?.id || (index === 0 && isTrialSelected.value)
|
||||
}
|
||||
|
||||
const formatPromoCountdown = (remainingSeconds) => {
|
||||
if (remainingSeconds === null || remainingSeconds === undefined) return ''
|
||||
|
||||
const elapsedSeconds = Math.floor((now.value - countdownStart) / 1000)
|
||||
const totalSeconds = Math.max(0, Math.floor(remainingSeconds) - elapsedSeconds)
|
||||
if (totalSeconds <= 0) return ''
|
||||
|
||||
const days = Math.floor(totalSeconds / 86400)
|
||||
const hours = Math.floor((totalSeconds % 86400) / 3600)
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60)
|
||||
const seconds = totalSeconds % 60
|
||||
|
||||
if (days > 0) return `${days}d:${hours}h:${minutes}m后失效`
|
||||
return `${hours}h:${minutes}m:${seconds}s后失效`
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
timer = setInterval(() => {
|
||||
now.value = Date.now()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer) clearInterval(timer)
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user