Files
gym-manage/gym-manage-uniapp/pages/memberInfo/memberInfo.vue
T

419 lines
14 KiB
Vue

<template>
<!-- 滚动内容区域 -->
<scroll-view scroll-y class="scroll-container theme-light">
<view class="member-page">
<MemberInfoHeader
:user-info="userInfo"
:stats="stats"
:isLogin="isLogin"
@user-info="goUserInfo"
@guest-login="handleGuestLogin"
/>
<view class="member-page__body">
<view class="member-page__sections">
<MemberInfoMemberCard
:card-info="cardInfo"
@view-all="goMemberCard"
@renew="onRenewCard"
@purchase="goPurchaseCard"
/>
<MemberInfoQuickActions @action="onQuickAction" />
<MemberInfoBookingList
v-if="isLogin"
:items="bookingPreview"
@view-all="goBooking"
@item-tap="goBooking"
/>
<MemberInfoCheckInList
v-if="isLogin"
:items="checkIns"
@view-all="onCheckInViewAll"
@item-tap="onCheckInTap"
/>
<MemberInfoBodyReport
v-if="isLogin"
:report="bodyReport"
@view-history="onBodyReportHistory"
@view-report="onBodyReportView"
/>
<MemberInfoCouponPoints
v-if="isLogin"
:data="couponPoints"
@view-all="onCouponViewAll"
@use-coupon="onUseCoupon"
@redeem-points="onRedeemPoints"
/>
<MemberInfoReferral
v-if="isLogin"
:data="referral"
@view-rules="onReferralRules"
/>
<MemberInfoSettings v-if="isLogin" @setting="onSetting" />
<MemberInfoLogout v-if="isLogin" @logout="handleLogout" />
</view>
</view>
</view>
</scroll-view>
<!-- 固定 TabBar -->
<view class="tabbar-fixed">
<TabBar />
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { PAGE, navigateToPage } from '@/common/constants/routes.js'
import {
loadMemberStore,
getCenterPageData,
renewMemberCard,
saveMemberStore,
getDefaultStore
} from '@/common/memberInfo/store.js'
import { login as miniappLogin, getUserInfo, getMemberDetail, getCheckInStats, updateUserInfo } from '@/api/main.js'
import { setToken, getToken, clearToken } from '@/utils/request.js'
import MemberInfoHeader from '@/components/memberInfo/MemberInfoHeader.vue'
import MemberInfoMemberCard from '@/components/memberInfo/MemberInfoMemberCard.vue'
import MemberInfoQuickActions from '@/components/memberInfo/MemberInfoQuickActions.vue'
import MemberInfoBookingList from '@/components/memberInfo/MemberInfoBookingList.vue'
import MemberInfoCheckInList from '@/components/memberInfo/MemberInfoCheckInList.vue'
import MemberInfoBodyReport from '@/components/memberInfo/MemberInfoBodyReport.vue'
import MemberInfoCouponPoints from '@/components/memberInfo/MemberInfoCouponPoints.vue'
import MemberInfoReferral from '@/components/memberInfo/MemberInfoReferral.vue'
import MemberInfoSettings from '@/components/memberInfo/MemberInfoSettings.vue'
import MemberInfoLogout from '@/components/memberInfo/MemberInfoLogout.vue'
import TabBar from '@/components/TabBar.vue'
const userInfo = ref({})
const stats = ref({})
const cardInfo = ref({})
const bookingPreview = ref([])
const checkIns = ref([])
const bodyReport = ref({})
const couponPoints = ref({})
const referral = ref({})
const loading = ref(false)
const hasActiveCard = ref(false)
const isLogin = ref(false)
// 页面加载时检查token
onMounted(() => {
const token = getToken()
const isLoginStorage = uni.getStorageSync('isLogin')
if (token || isLoginStorage) {
isLogin.value = true
}
})
async function fetchMemberInfo() {
if (loading.value) return
loading.value = true
console.log('[memberInfo] fetchMemberInfo 开始执行')
try {
const res = await getUserInfo({ cache: false })
console.log('[memberInfo] API返回,res =', res)
const apiData = res.data || res
console.log('[memberInfo] apiData =', apiData)
if (apiData && (apiData.nickname !== undefined || apiData.phone !== undefined || apiData.id !== undefined)) {
console.log('[memberInfo] 收到有效数据,更新store')
const store = loadMemberStore()
// 更新memberProfile
store.memberProfile = {
...store.memberProfile,
id: apiData.id,
name: apiData.nickname || apiData.name,
phone: apiData.phone,
avatar: apiData.avatar,
memberLevel: apiData.memberLevel || '普通会员'
}
// 更新profile
store.profile = {
...store.profile,
id: apiData.id,
name: apiData.nickname || apiData.name,
phone: apiData.phone,
avatar: apiData.avatar,
gender: apiData.gender,
genderDesc: apiData.genderDesc,
birthday: apiData.birthday,
height: apiData.height,
weight: apiData.weight,
hasPhone: apiData.hasPhone,
isSubscribed: apiData.isSubscribed,
memberLevel: apiData.memberLevel || '普通会员'
}
// 获取会员详细信息(会员卡、积分)
try {
const detailRes = await getMemberDetail()
console.log('[memberInfo] getMemberDetail 返回:', JSON.stringify(detailRes, null, 2))
const detailData = detailRes.data || {}
store.card = detailData.memberCards ? detailData.memberCards[0] || {} : {}
store.cardInfo = {
name: detailData.memberCards?.[0]?.memberCardName || '暂无会员卡',
type: detailData.memberCards?.[0]?.memberCardTypeDesc || '',
remainingTimes: detailData.memberCards?.[0]?.memberCardTotalTimes || 0,
status: detailData.memberCards?.[0]?.memberCardStatusDesc || ''
}
hasActiveCard.value = (detailData.activeCardCount || 0) > 0
store.stats = {
...store.stats,
pointsBalance: detailData.pointsBalance || 0
}
} catch (e) {
console.error('[memberInfo] 获取会员详情失败:', e)
}
// 获取签到统计
try {
const statsRes = await getCheckInStats()
console.log('[memberInfo] getCheckInStats 返回:', JSON.stringify(statsRes, null, 2))
const statsData = statsRes.data || {}
store.stats.checkInCount = statsData.totalCount || 0
} catch (e) {
console.error('[memberInfo] 获取签到统计失败:', e)
store.stats.checkInCount = 0
}
saveMemberStore(store)
refreshFromStore()
console.log('[memberInfo] store已更新')
} else {
console.log('[memberInfo] 未登录或数据无效,使用默认空数据')
const store = loadMemberStore()
store.memberProfile = {}
store.profile = {}
store.stats.checkInCount = 0
hasActiveCard.value = false
saveMemberStore(store)
refreshFromStore()
}
} catch (err) {
console.error('[memberInfo] 获取会员信息失败:', err)
// 失败时使用默认空数据
const store = loadMemberStore()
store.memberProfile = {}
store.profile = {}
store.stats.checkInCount = 0
hasActiveCard.value = false
saveMemberStore(store)
refreshFromStore()
} finally {
loading.value = false
console.log('[memberInfo] fetchMemberInfo 执行完成')
}
}
function refreshFromStore() {
const store = loadMemberStore()
const pageData = getCenterPageData(store)
console.log('[memberInfo] refreshFromStore - pageData.userInfo:', JSON.stringify(pageData.userInfo))
userInfo.value = pageData.userInfo
stats.value = pageData.stats
cardInfo.value = pageData.cardInfo
bookingPreview.value = pageData.bookingPreview
checkIns.value = pageData.checkIns
bodyReport.value = pageData.bodyReport
couponPoints.value = pageData.couponPoints
referral.value = pageData.referral
console.log('[memberInfo] refreshFromStore - userInfo.value:', JSON.stringify(userInfo.value))
}
function goMemberCard() {
navigateToPage(PAGE.MEMBER_CARD)
}
function goPurchaseCard() {
navigateToPage(PAGE.PURCHASE_CARD)
}
function goBooking() {
navigateToPage(PAGE.BOOKING)
}
function goUserInfo() {
navigateToPage(PAGE.USER_INFO)
}
function handleGuestLogin() {
console.log('[memberInfo] 用户点击登录区域')
uni.navigateTo({
url: '/pages/memberInfo/login'
})
}
function onRenewCard() {
uni.showModal({
title: '续费会员卡',
content: '确认续费 90 天?',
success: (res) => {
if (!res.confirm) return
const store = loadMemberStore()
renewMemberCard(store, 90)
refreshFromStore()
uni.showToast({ title: '续费成功', icon: 'success' })
}
})
}
function onQuickAction(type) {
const routes = {
booking: PAGE.COURSE_LIST,
bodyTest: PAGE.BODY_TEST_HOME,
bodyReport: PAGE.BODY_TEST_HISTORY,
trainReport: PAGE.TRAIN_REPORT,
coupon: PAGE.COUPONS,
points: PAGE.POINTS,
referral: PAGE.REFERRAL,
course: PAGE.MY_COURSES
}
if (routes[type]) {
navigateToPage(routes[type])
}
}
function onCheckInViewAll() {
navigateToPage(PAGE.CHECK_IN_HISTORY)
}
function onCheckInTap(item) {
uni.showModal({
title: item.title,
content: item.time,
showCancel: false
})
}
function onBodyReportHistory() {
navigateToPage(PAGE.BODY_TEST_HISTORY)
}
function onBodyReportView() {
const id = bodyReport.value?.recordId
const url = id
? `${PAGE.BODY_TEST_REPORT}?id=${id}`
: PAGE.BODY_TEST_HISTORY
navigateToPage(url)
}
function onCouponViewAll() {
navigateToPage(PAGE.COUPONS)
}
function onUseCoupon() {
navigateToPage(PAGE.COUPONS)
}
function onRedeemPoints() {
navigateToPage(PAGE.POINTS)
}
function onReferralRules() {
navigateToPage(PAGE.REFERRAL)
}
function onSetting(key) {
const labels = {
notify: '通知设置',
password: '修改密码',
privacy: '隐私政策',
nfc: 'NFC 门禁卡',
delete: '注销账户'
}
if (key === 'delete') {
uni.showModal({
title: '注销账户',
content: '注销后数据将无法恢复,确定继续吗?',
confirmColor: '#E74C3C'
})
return
}
if (key === 'privacy') {
uni.showModal({
title: '隐私政策',
content: '我们重视您的隐私,详细政策请前往官网查看。',
showCancel: false
})
return
}
uni.showToast({
title: `${labels[key] || '设置'}开发中`,
icon: 'none'
})
}
function handleLogout() {
uni.showModal({
title: '退出登录',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
// 清除token
clearToken()
// 重置登录状态
isLogin.value = false
// 重置store为默认状态
const defaultStore = getDefaultStore()
saveMemberStore(defaultStore)
// 重置页面数据
userInfo.value = {}
stats.value = {}
cardInfo.value = {}
bookingPreview.value = []
checkIns.value = []
bodyReport.value = {}
couponPoints.value = {}
referral.value = {}
hasActiveCard.value = false
refreshFromStore()
uni.showToast({ title: '已退出', icon: 'success' })
}
}
})
}
refreshFromStore()
onShow(() => {
console.log('[memberInfo] onShow 被调用')
// 检查登录状态
const token = getToken()
const isLoginStorage = uni.getStorageSync('isLogin')
if (token || isLoginStorage) {
isLogin.value = true
} else {
isLogin.value = false
}
fetchMemberInfo()
})
</script>
<style lang="scss">
@import '@/common/style/base.css';
@import '@/common/style/memberInfo/member-info-component-reset.css';
@import '@/common/style/memberInfo/member-info-tap.css';
@import '@/common/style/memberInfo/member-info-page.css';
@import '@/common/style/memberInfo/member-info-header.css';
@import '@/common/style/memberInfo/member-info-member-card.css';
@import '@/common/style/memberInfo/member-info-quick-actions.css';
@import '@/common/style/memberInfo/member-info-booking-list.css';
@import '@/common/style/memberInfo/member-info-check-in-list.css';
@import '@/common/style/memberInfo/member-info-body-report.css';
@import '@/common/style/memberInfo/member-info-coupon-points.css';
@import '@/common/style/memberInfo/member-info-referral.css';
@import '@/common/style/memberInfo/member-info-settings.css';
@import '@/common/style/memberInfo/member-info-logout.css';
/* 固定 TabBar */
.tabbar-fixed {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
background-color: transparent;
}
</style>