208 lines
7.8 KiB
Vue
208 lines
7.8 KiB
Vue
<template>
|
||
<view class="scroll-container theme-light">
|
||
<view class="member-card-page">
|
||
<MemberInfoSubNav title="我的会员卡" @back="goBack" />
|
||
<view class="member-card-page__body">
|
||
<view class="mc-hero">
|
||
<view class="mc-hero__top">
|
||
<view class="mc-hero__title-row">
|
||
<image
|
||
class="mc-hero__crown"
|
||
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/crown.png"
|
||
mode="aspectFit"
|
||
/>
|
||
<text class="mc-hero__name">{{ card.name }}</text>
|
||
</view>
|
||
<view class="mc-hero__badge">
|
||
<text class="mc-hero__badge-text">{{ card.status }}</text>
|
||
</view>
|
||
</view>
|
||
<text class="mc-hero__validity">有效期:{{ card.validity }}</text>
|
||
<view class="mc-hero__bottom">
|
||
<view class="mc-hero__days">
|
||
<text class="mc-hero__days-num">{{ remainingDays }}</text>
|
||
<text class="mc-hero__days-unit">天</text>
|
||
</view>
|
||
<view
|
||
class="mc-hero__renew"
|
||
hover-class="mi-tap-btn--hover"
|
||
:hover-stay-time="150"
|
||
@tap="renewCard"
|
||
>
|
||
<image
|
||
class="mc-hero__renew-icon"
|
||
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/refreshcw.png"
|
||
mode="aspectFit"
|
||
/>
|
||
<text class="mc-hero__renew-text">立即续费</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="mc-records">
|
||
<view class="mc-records__header">
|
||
<text class="mc-records__title">使用记录</text>
|
||
<view class="mc-records__tabs">
|
||
<view
|
||
v-for="tab in recordTabs"
|
||
:key="tab.key"
|
||
class="mc-records__tab"
|
||
:class="{ 'mc-records__tab--active': activeFilter === tab.key }"
|
||
hover-class="mi-tap-tab--hover"
|
||
:hover-stay-time="150"
|
||
@tap="switchFilter(tab.key)"
|
||
>
|
||
<text
|
||
class="mc-records__tab-text"
|
||
:class="{ 'mc-records__tab-text--active': activeFilter === tab.key }"
|
||
>
|
||
{{ tab.label }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="mc-records__divider"></view>
|
||
<view
|
||
v-for="(item, index) in filteredRecords"
|
||
:key="item.id"
|
||
class="mc-records__item"
|
||
>
|
||
<view v-if="index > 0" class="mc-records__divider"></view>
|
||
<view
|
||
class="mc-records__item-inner"
|
||
hover-class="mi-tap-row--hover"
|
||
:hover-stay-time="150"
|
||
@tap="showRecordDetail(item)"
|
||
>
|
||
<view
|
||
class="mc-records__icon-wrap"
|
||
:class="'mc-records__icon-wrap--' + item.iconTheme"
|
||
>
|
||
<image
|
||
class="mc-records__icon"
|
||
:src="item.icon"
|
||
mode="aspectFit"
|
||
/>
|
||
</view>
|
||
<view class="mc-records__info">
|
||
<text class="mc-records__item-title">{{ item.title }}</text>
|
||
<text class="mc-records__item-time">{{ item.time }}</text>
|
||
</view>
|
||
<text
|
||
class="mc-records__value"
|
||
:class="'mc-records__value--' + item.valueType"
|
||
>
|
||
{{ item.value }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
<view v-if="!filteredRecords.length" class="mc-records__empty">
|
||
<text class="mc-records__empty-text">暂无记录</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="mc-rules">
|
||
<text class="mc-rules__title">使用规则</text>
|
||
<view
|
||
v-for="(rule, index) in rules"
|
||
:key="index"
|
||
class="mc-rules__item"
|
||
>
|
||
<view class="mc-rules__bullet"></view>
|
||
<text class="mc-rules__text">{{ rule }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed } from 'vue'
|
||
import MemberInfoSubNav from '@/components/memberInfo/MemberInfoSubNav.vue'
|
||
import {
|
||
loadMemberStore,
|
||
computeRemainingDays,
|
||
renewMemberCard
|
||
} from '@/common/memberInfo/store.js'
|
||
import { backToMemberCenter } from '@/common/constants/routes.js'
|
||
|
||
const card = ref({})
|
||
const recordTabs = ref([])
|
||
const records = ref([])
|
||
const rules = ref([])
|
||
const activeFilter = ref('all')
|
||
|
||
const filteredRecords = computed(() => {
|
||
if (activeFilter.value === 'all') {
|
||
return records.value
|
||
}
|
||
return records.value.filter((item) => item.type === activeFilter.value)
|
||
})
|
||
|
||
const remainingDays = computed(() => {
|
||
return computeRemainingDays(card.value.validityEnd)
|
||
})
|
||
|
||
function refreshFromStore() {
|
||
const store = loadMemberStore()
|
||
card.value = { ...store.card }
|
||
records.value = store.records.map((item) => ({ ...item }))
|
||
}
|
||
|
||
function goBack() {
|
||
backToMemberCenter()
|
||
}
|
||
|
||
function switchFilter(filter) {
|
||
activeFilter.value = filter
|
||
}
|
||
|
||
function renewCard() {
|
||
uni.showModal({
|
||
title: '续费会员卡',
|
||
content: '确认续费 90 天?',
|
||
success: (res) => {
|
||
if (!res.confirm) return
|
||
const store = loadMemberStore()
|
||
renewMemberCard(store, 90)
|
||
activeFilter.value = 'all'
|
||
refreshFromStore()
|
||
uni.showToast({ title: '续费成功', icon: 'success' })
|
||
}
|
||
})
|
||
}
|
||
|
||
function showRecordDetail(item) {
|
||
uni.showModal({
|
||
title: item.title,
|
||
content: `${item.time}\n变动:${item.value}`,
|
||
showCancel: false
|
||
})
|
||
}
|
||
|
||
refreshFromStore()
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
@import '@/common/style/base.css';
|
||
@import '@/common/style/memberInfo/pages/page-reset.css';
|
||
@import '@/common/style/memberInfo/pages/sub-page-base.css';
|
||
@import '@/common/style/memberInfo/member-info-component-reset.css';
|
||
@import '@/common/style/memberInfo/member-info-sub-nav.css';
|
||
@import '@/common/style/memberInfo/member-info-tap.css';
|
||
@import '@/common/style/memberInfo/pages/member-card-page.css';
|
||
|
||
.mc-records__empty {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 32px 16px;
|
||
}
|
||
|
||
.mc-records__empty-text {
|
||
font-size: 14px;
|
||
color: #8A99B4;
|
||
}
|
||
</style>
|