Files
xk-admin/apps/web-antd/src/components/vip/StoreVipMemberCard.vue

154 lines
4.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts" setup>
/**
* 诊所设置「基础资料」会员卡片
* 大尺寸等级徽标 + 期限丝带叠加,展示等级名与到期时间
*/
import { computed } from 'vue';
import VipBadgeCombo from './VipBadgeCombo.vue';
const props = defineProps<{
vip?: Record<string, any> | null;
}>();
const hasVipVisual = computed(() => {
const v = props.vip;
return !!(v && (v.badge_url || v.duration_badge_url));
});
const expireText = computed(() => {
const v = props.vip;
if (!v) return '默认会员';
if (v.is_lifetime) return '永久有效';
const expireAt = Number(v.expire_at || 0);
if (!expireAt) {
if ((v.level_code || 'V0') === 'V0') return '默认会员';
return '永久有效';
}
if (typeof v.expire_at === 'string' && String(v.expire_at).includes('-')) {
return `有效期至 ${v.expire_at}`;
}
const d = new Date(expireAt * 1000);
const pad = (n: number) => String(n).padStart(2, '0');
return `有效期至 ${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
});
</script>
<template>
<!-- 黑金会员卡与小程序端 vip-member-card 同一套视觉语言深色卡面亮暗主题通用 -->
<div class="store-vip-card">
<div class="store-vip-card__glow"></div>
<div class="store-vip-card__sheen"></div>
<VipBadgeCombo
v-if="hasVipVisual"
size="xl"
:badge-url="vip?.badge_url"
:duration-badge-url="vip?.duration_badge_url"
:level-name="vip?.level_name"
:duration-label="vip?.duration_label"
/>
<div v-else class="store-vip-card__placeholder">V</div>
<div class="store-vip-card__info">
<div class="store-vip-card__title-row">
<span class="store-vip-card__title">{{ vip?.level_name || '普通会员' }}</span>
<span class="store-vip-card__chip">{{ vip?.duration_label || '普通会员' }}</span>
</div>
<div class="store-vip-card__expire">{{ expireText }}</div>
</div>
</div>
</template>
<style scoped>
.store-vip-card {
position: relative;
display: flex;
align-items: center;
gap: 24px;
padding: 20px 28px;
margin-bottom: 24px;
overflow: hidden;
border-radius: 18px;
/* 深色曜石底 + 右上暗金光晕,比单一渐变更有实体卡层次 */
background:
radial-gradient(120% 160% at 100% 0%, rgba(212, 175, 55, 0.22) 0%, rgba(212, 175, 55, 0) 45%),
linear-gradient(135deg, #23201a 0%, #12100c 55%, #1f1a12 100%);
border: 1px solid rgba(220, 186, 110, 0.35);
box-shadow:
0 12px 32px rgba(0, 0, 0, 0.28),
0 2px 8px rgba(212, 175, 55, 0.12);
}
/* 右上金色光晕:模拟灯光打在卡面的高光 */
.store-vip-card__glow {
position: absolute;
top: -70px;
right: -50px;
width: 220px;
height: 220px;
border-radius: 50%;
background: radial-gradient(circle, rgba(240, 217, 168, 0.26) 0%, rgba(240, 217, 168, 0) 70%);
pointer-events: none;
}
/* 斜切静态流光条:金属光泽感 */
.store-vip-card__sheen {
position: absolute;
top: 0;
bottom: 0;
left: 32%;
width: 90px;
transform: skewX(-24deg);
background: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.05) 50%,
rgba(255, 255, 255, 0) 100%
);
pointer-events: none;
}
.store-vip-card__placeholder {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 120px;
height: 120px;
font-size: 48px;
font-weight: 700;
color: #f0d9a8;
text-shadow: 0 2px 8px rgba(212, 175, 55, 0.4);
background: radial-gradient(circle, rgba(212, 175, 55, 0.16) 0%, rgba(212, 175, 55, 0.04) 100%);
border: 1px solid rgba(220, 186, 110, 0.4);
border-radius: 50%;
box-shadow: inset 0 0 16px rgba(212, 175, 55, 0.15);
}
.store-vip-card__info {
position: relative;
min-width: 0;
}
.store-vip-card__title-row {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
}
.store-vip-card__title {
font-size: 22px;
font-weight: 700;
line-height: 1.3;
color: #f5e3bd;
letter-spacing: 1px;
text-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
}
/* 期限徽章:金字描边小胶囊 */
.store-vip-card__chip {
flex-shrink: 0;
padding: 1px 10px;
font-size: 12px;
color: #e8cf9a;
background: rgba(212, 175, 55, 0.1);
border: 1px solid rgba(232, 207, 154, 0.5);
border-radius: 999px;
}
.store-vip-card__expire {
font-size: 13px;
color: rgba(240, 224, 190, 0.75);
}
</style>