350 lines
10 KiB
Vue
350 lines
10 KiB
Vue
<template>
|
|
<view class="member-info-page">
|
|
<!-- 滚动内容区域 -->
|
|
<view class="member-scroll-wrap">
|
|
<scroll-view scroll-y class="member-scroll">
|
|
<view class="member-page">
|
|
<MemberInfoHeader
|
|
:user-info="userInfo"
|
|
:stats="stats"
|
|
:is-login="isLogin"
|
|
@user-info="goUserInfo"
|
|
@guest-login="handleGuestLogin"
|
|
/>
|
|
<view class="member-page__body">
|
|
<view class="member-page__sections">
|
|
<MemberInfoMemberCard
|
|
v-if="isLogin"
|
|
: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"
|
|
/>
|
|
<MemberInfoCouponPoints
|
|
v-if="isLogin"
|
|
:data="couponPoints"
|
|
@view-all="onCouponViewAll"
|
|
@use-coupon="onUseCoupon"
|
|
@redeem-points="onRedeemPoints"
|
|
/>
|
|
<MemberInfoSettings v-if="isLogin" @setting="onSetting" />
|
|
<MemberInfoLogout v-if="isLogin" @logout="handleLogout" />
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<!-- 固定 TabBar -->
|
|
<view class="tabbar-fixed">
|
|
<TabBar />
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue'
|
|
import { onShow } from '@dcloudio/uni-app'
|
|
import { PAGE, navigateToPage } from '@/common/constants/routes.js'
|
|
import {
|
|
getCenterPageData,
|
|
renewMemberCard,
|
|
saveMemberStore,
|
|
getDefaultStore
|
|
} from '@/common/memberInfo/store.js'
|
|
import { getMemberId } from '@/utils/request.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 MemberInfoCouponPoints from '@/components/memberInfo/MemberInfoCouponPoints.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 couponPoints = ref({})
|
|
const loading = ref(false)
|
|
const hasActiveCard = ref(false)
|
|
const isLogin = ref(false)
|
|
|
|
onMounted(() => {
|
|
const token = uni.getStorageSync('token')
|
|
const loginMember = uni.getStorageSync('loginMemberInfo')
|
|
if (token || loginMember) {
|
|
isLogin.value = true
|
|
}
|
|
})
|
|
|
|
// 处理访客登录点击(跳转到登录页面)
|
|
function handleGuestLogin() {
|
|
console.log('[memberInfo] 用户点击登录区域')
|
|
uni.navigateTo({
|
|
url: '/pages/memberInfo/login'
|
|
})
|
|
}
|
|
|
|
async function fetchMemberInfo() {
|
|
if (loading.value) return
|
|
loading.value = true
|
|
console.log('[memberInfo] fetchMemberInfo 开始执行')
|
|
try {
|
|
// 先从 loginMemberInfo 获取用户信息
|
|
const loginMember = uni.getStorageSync('loginMemberInfo')
|
|
if (loginMember?.userInfo) {
|
|
console.log('[memberInfo] 从loginMemberInfo获取用户信息:', loginMember.userInfo)
|
|
const apiData = loginMember.userInfo
|
|
// 更新userInfo
|
|
userInfo.value = {
|
|
id: apiData.id,
|
|
name: apiData.nickname || apiData.name,
|
|
phone: apiData.phone,
|
|
avatar: apiData.avatar,
|
|
memberLevel: apiData.memberLevel || '普通会员'
|
|
}
|
|
}
|
|
|
|
// 获取积分信息
|
|
try {
|
|
const detailRes = await getMemberDetail()
|
|
const detailData = detailRes.data || {}
|
|
stats.value = {
|
|
...stats.value,
|
|
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 || {}
|
|
stats.value.checkInCount = statsData.totalCount || 0
|
|
} catch (e) {
|
|
console.error('[memberInfo] 获取签到统计失败:', e)
|
|
stats.value.checkInCount = 0
|
|
}
|
|
|
|
// 刷新store中的业务数据
|
|
refreshFromStore()
|
|
console.log('[memberInfo] fetchMemberInfo 执行完成')
|
|
} catch (err) {
|
|
console.error('[memberInfo] 获取会员信息失败:', err)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
function refreshFromStore() {
|
|
const store = getDefaultStore()
|
|
const pageData = getCenterPageData(store)
|
|
console.log('[memberInfo] refreshFromStore - pageData:', JSON.stringify(pageData))
|
|
stats.value = pageData.stats
|
|
cardInfo.value = pageData.cardInfo
|
|
bookingPreview.value = pageData.bookingPreview
|
|
checkIns.value = pageData.checkIns
|
|
couponPoints.value = pageData.couponPoints
|
|
console.log('[memberInfo] refreshFromStore - userInfo.value:', JSON.stringify(userInfo.value))
|
|
}
|
|
|
|
function goUserInfo() {
|
|
navigateToPage(PAGE.USER_INFO)
|
|
}
|
|
|
|
function goMemberCard() {
|
|
navigateToPage(PAGE.MEMBER_CARD)
|
|
}
|
|
|
|
function goPurchaseCard() {
|
|
navigateToPage(PAGE.PURCHASE_CARD)
|
|
}
|
|
|
|
function goBooking() {
|
|
navigateToPage(PAGE.BOOKING)
|
|
}
|
|
|
|
function onRenewCard() {
|
|
uni.showModal({
|
|
title: '续费会员卡',
|
|
content: '确认续费 90 天?',
|
|
success: (res) => {
|
|
if (!res.confirm) return
|
|
uni.showToast({ title: '续费成功', icon: 'success' })
|
|
}
|
|
})
|
|
}
|
|
|
|
function onQuickAction(type) {
|
|
const routes = {
|
|
coupon: PAGE.COUPONS,
|
|
points: PAGE.POINTS
|
|
}
|
|
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 onCouponViewAll() {
|
|
navigateToPage(PAGE.COUPONS)
|
|
}
|
|
|
|
function onUseCoupon() {
|
|
navigateToPage(PAGE.COUPONS)
|
|
}
|
|
|
|
function onRedeemPoints() {
|
|
navigateToPage(PAGE.POINTS)
|
|
}
|
|
|
|
function onSetting(key) {
|
|
const labels = {
|
|
password: '修改密码',
|
|
privacy: '隐私政策',
|
|
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 = []
|
|
couponPoints.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-coupon-points.css';
|
|
@import '@/common/style/memberInfo/member-info-settings.css';
|
|
@import '@/common/style/memberInfo/member-info-logout.css';
|
|
|
|
/* 页面布局:scroll-view + tabbar */
|
|
.member-info-page {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100vh;
|
|
overflow: hidden;
|
|
background: var(--gradient-sky);
|
|
}
|
|
|
|
.member-scroll-wrap {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.member-scroll {
|
|
height: 100%;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/* 固定 TabBar */
|
|
.tabbar-fixed {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 1000;
|
|
background-color: transparent;
|
|
}
|
|
</style>
|