Files
xk-doctor-wx/subPackages/sub_clinic_admin/components/vip-member-card.vue
2026-08-04 14:53:00 +08:00

155 lines
3.6 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.
<template>
<!-- 会员卡片等级徽标 + 期限丝带叠加绑定整体放大 -->
<view class="vip-card">
<view class="vip-card-inner">
<view class="vip-badge-combo">
<image
v-if="levelBadge"
class="vip-level"
:src="levelBadge"
mode="aspectFit"
/>
<image
v-if="durationBadge"
class="vip-ribbon"
:src="durationBadge"
mode="aspectFit"
/>
<view v-if="!durationBadge && !levelBadge" class="vip-badge-placeholder">
<text class="vip-badge-placeholder-text">V</text>
</view>
</view>
<view class="vip-info">
<text class="vip-title">{{ levelName }}</text>
<text class="vip-sub">{{ durationLabel }} · {{ levelCode }}</text>
<text class="vip-expire">{{ expireText }}</text>
</view>
</view>
</view>
</template>
<script>
/**
* 诊所管理员「我的」页会员卡片
* 期限图为透明丝带,叠在等级徽标上绑定展示
*/
export default {
name: 'VipMemberCard',
props: {
vip: {
type: Object,
default: null,
},
},
computed: {
durationBadge() {
return (this.vip && this.vip.duration_badge_url) || ''
},
levelBadge() {
return (this.vip && this.vip.badge_url) || ''
},
durationLabel() {
return (this.vip && this.vip.duration_label) || '普通会员'
},
levelName() {
return (this.vip && this.vip.level_name) || '普通会员'
},
levelCode() {
return (this.vip && this.vip.level_code) || 'V0'
},
expireText() {
if (!this.vip) return '默认会员'
if (this.vip.is_lifetime) return '永久有效'
const expireAt = Number(this.vip.expire_at || 0)
if (!expireAt) {
if (this.levelCode === 'V0') return '默认会员'
return '永久有效'
}
if (typeof this.vip.expire_at === 'string' && this.vip.expire_at.indexOf('-') > -1) {
return '有效期至 ' + this.vip.expire_at
}
const d = new Date(expireAt * 1000)
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return '有效期至 ' + y + '-' + m + '-' + day
},
},
}
</script>
<style lang="scss" scoped>
.vip-card {
margin: 0 24rpx 24rpx;
}
.vip-card-inner {
display: flex;
align-items: center;
padding: 36rpx 32rpx;
border-radius: 20rpx;
background: linear-gradient(135deg, #2c3e50 0%, #4a6741 55%, #6acdbb 100%);
box-shadow: 0 8rpx 24rpx rgba(44, 62, 80, 0.18);
}
/* 组合徽标容器:等级在下,丝带叠在中下部 */
.vip-badge-combo {
position: relative;
width: 160rpx;
height: 160rpx;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.vip-level {
width: 140rpx;
height: 140rpx;
position: relative;
z-index: 1;
}
.vip-ribbon {
position: absolute;
left: 50%;
bottom: 10rpx;
transform: translateX(-50%);
width: 200rpx;
height: 72rpx;
z-index: 2;
}
.vip-badge-placeholder {
width: 140rpx;
height: 140rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.vip-badge-placeholder-text {
color: #fff;
font-size: 52rpx;
font-weight: 700;
}
.vip-info {
margin-left: 24rpx;
display: flex;
flex-direction: column;
min-width: 0;
flex: 1;
}
.vip-title {
color: #ffffff;
font-size: 34rpx;
font-weight: 700;
margin-bottom: 8rpx;
}
.vip-sub {
color: rgba(255, 255, 255, 0.88);
font-size: 24rpx;
margin-bottom: 8rpx;
}
.vip-expire {
color: rgba(255, 255, 255, 0.75);
font-size: 22rpx;
}
</style>