All checks were successful
site-dist-deploy / build-and-deploy (push) Successful in 1m44s
160 lines
4.9 KiB
Vue
160 lines
4.9 KiB
Vue
<template>
|
|
<!-- Main Neon Green Card -->
|
|
<div class="flex h-[678px] justify-center">
|
|
<div
|
|
class="flex w-[345px] flex-col justify-between rounded-4xl border-5 border-white py-[32px] pb-[22px]"
|
|
>
|
|
<div>
|
|
<div class="mb-3 flex min-h-[88px] flex-col items-center">
|
|
<Transition name="fade" mode="out-in">
|
|
<UserCenterSkeleton v-if="isUserLoading" type="header" layout="desktop" />
|
|
<div v-else class="flex flex-col items-center">
|
|
<img src="../avatar.png" class="size-[60px]" alt="" />
|
|
<div class="flex flex-col justify-center text-white">
|
|
<div class="pt-3 text-xl font-semibold">{{ userInfo.email }}</div>
|
|
</div>
|
|
</div>
|
|
</Transition>
|
|
</div>
|
|
<div class="mb-5 px-[20px] text-white">
|
|
<Transition name="fade" mode="out-in">
|
|
<UserCenterSkeleton v-if="isUserLoading" type="devices" layout="desktop" />
|
|
<DeviceList v-else :devices="devices" @refresh="emit('refresh')" />
|
|
</Transition>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="px-6 pt-8 pb-9">
|
|
<Button
|
|
variant="outline"
|
|
@click="$emit('show-order-details')"
|
|
class="mb-[10px] h-[50px] w-full rounded-[32px] border-2 border-[#ADFF5B] bg-transparent text-xl font-bold text-[#ADFF5B] transition-all hover:bg-[#ADFF5B]/90 active:scale-[0.98]"
|
|
>
|
|
订单详情
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
@click="logout"
|
|
class="h-[50px] w-full rounded-[32px] border-2 border-white bg-transparent text-xl font-bold text-white transition-all hover:bg-white/90 active:scale-[0.98]"
|
|
>
|
|
退出登录
|
|
</Button>
|
|
</div>
|
|
|
|
<div
|
|
class="text-center text-xs text-white tabular-nums"
|
|
:class="{ 'text-[#FF00B7]': expireDateInfo.highlight }"
|
|
>
|
|
{{ expireDateInfo.text }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="ml-2.5 flex items-center overflow-hidden rounded-4xl bg-[#A8FF53] pt-[32px] pb-[22px]"
|
|
>
|
|
<div class="h-full w-[345px]">
|
|
<Transition name="fade" mode="out-in">
|
|
<div v-if="isPlansLoading" class="p-8">
|
|
<UserCenterSkeleton type="plans" layout="desktop" />
|
|
</div>
|
|
<PlanCard
|
|
v-else
|
|
:plans="plans"
|
|
:trial-plan="trialPlan"
|
|
:trial-countdown="trialCountdown"
|
|
:currentPlanIndex="currentPlanIndex"
|
|
:selectedPlanId="selectedPlanId"
|
|
@select="handlePlanSelect"
|
|
/>
|
|
</Transition>
|
|
</div>
|
|
<div
|
|
class="mx-[5px] h-[624px] w-[1px] bg-[url(@/pages/UserCenter/DesktopLayout/Line-8.png)]"
|
|
></div>
|
|
<div class="h-full w-[345px]">
|
|
<Transition name="fade" mode="out-in">
|
|
<div v-if="isPaymentsLoading" class="p-8">
|
|
<UserCenterSkeleton type="payments" layout="desktop" />
|
|
</div>
|
|
<PaymentMethod
|
|
v-else
|
|
:methods="payments"
|
|
:selectedPlan="selectedPlan"
|
|
:is-paying="isPaying"
|
|
@pay="(id: number | string) => $emit('pay', id)"
|
|
/>
|
|
</Transition>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import PlanCard from '@/components/user-center/PlanCard.vue'
|
|
import DeviceList from '@/components/user-center/DeviceList.vue'
|
|
import PaymentMethod from '@/components/user-center/PaymentMethod.vue'
|
|
import UserCenterSkeleton from '@/components/user-center/UserCenterSkeleton.vue'
|
|
import { Button } from '@/components/ui/button'
|
|
import { formatExpireDate } from '../subscription'
|
|
import { toast } from 'vue-sonner'
|
|
import { useRouter } from 'vue-router'
|
|
const router = useRouter()
|
|
const props = defineProps<{
|
|
devices: any[]
|
|
plans: any[]
|
|
payments: any[]
|
|
alreadySubscribed: any[]
|
|
userInfo: { email: string }
|
|
selectedPlanId: string
|
|
selectedPlan: any
|
|
isPaying: boolean
|
|
isUserLoading: boolean
|
|
isPlansLoading: boolean
|
|
isPaymentsLoading: boolean
|
|
trialPlan: any
|
|
trialCountdown: string
|
|
}>()
|
|
|
|
const emit = defineEmits(['select-plan', 'pay', 'refresh', 'show-order-details'])
|
|
|
|
// --- Handlers ---
|
|
const handlePlanSelect = (id: string) => {
|
|
emit('select-plan', id)
|
|
}
|
|
const currentPlanIndex = computed(() => {
|
|
return props.plans.findIndex((p) => p.id === props.selectedPlanId)
|
|
})
|
|
|
|
const expireDateInfo = computed(() => {
|
|
const first = props.alreadySubscribed[0]
|
|
return formatExpireDate(first)
|
|
})
|
|
|
|
function logout() {
|
|
router.push('/')
|
|
localStorage.removeItem('Authorization')
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* Simplified layout font */
|
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700;900&display=swap');
|
|
|
|
.tracking-tight {
|
|
font-family: 'Inter', 'PingFang SC', sans-serif;
|
|
}
|
|
|
|
.fade-enter-active,
|
|
.fade-leave-active {
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.fade-enter-from,
|
|
.fade-leave-to {
|
|
opacity: 0;
|
|
}
|
|
</style>
|