实现部分页面前后端相通
This commit is contained in:
@@ -11,82 +11,44 @@
|
||||
<view class="content-inner">
|
||||
<view class="user-card">
|
||||
<view class="user-row">
|
||||
<view class="big-avatar"><text>J</text></view>
|
||||
<view class="big-avatar"><text>{{ avatarText }}</text></view>
|
||||
<view class="user-info">
|
||||
<text class="user-name">{{ userInfo.nickname }}</text>
|
||||
<view class="user-tag">
|
||||
<text class="tag-symbol">★</text>
|
||||
<text>{{ userInfo.membershipLevel }}</text>
|
||||
<text>{{ userInfo.memberNo }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="edit-symbol" @click="editProfile">✎</text>
|
||||
</view>
|
||||
<view class="user-details">
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">会员编号</text>
|
||||
<text class="detail-value">{{ userInfo.memberNo }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">手机号</text>
|
||||
<text class="detail-value">{{ userInfo.phone }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">性别</text>
|
||||
<text class="detail-value">{{ userInfo.gender === 1 ? '男' : userInfo.gender === 2 ? '女' : '未设置' }}</text>
|
||||
<text class="detail-value">{{ genderLabel }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">生日</text>
|
||||
<text class="detail-value">{{ userInfo.birthday || '未设置' }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="detail-label">上次登录</text>
|
||||
<text class="detail-value">{{ userInfo.lastLoginAt || '暂无' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="stats-card">
|
||||
<view class="stat-item">
|
||||
<text class="stat-number">{{ userInfo.totalCourses }}</text>
|
||||
<text class="stat-label">总课时</text>
|
||||
<text class="stat-number">{{ userInfo.totalSignInDays }}</text>
|
||||
<text class="stat-label">累计签到(天)</text>
|
||||
</view>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number">{{ userInfo.streakDays }}</text>
|
||||
<text class="stat-label">连续打卡</text>
|
||||
</view>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-rating-row">
|
||||
<text class="stat-number">{{ userInfo.rating }}</text>
|
||||
<text class="star-icon">★</text>
|
||||
</view>
|
||||
<text class="stat-label">评分</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card-section">
|
||||
<view class="section-title-row">
|
||||
<text class="section-symbol">◆</text>
|
||||
<text class="section-title">我的会员卡</text>
|
||||
</view>
|
||||
<scroll-view class="card-scroll" scroll-x>
|
||||
<view v-for="(card, idx) in memberCards" :key="idx" class="member-card-item"
|
||||
:class="'card-type-' + card.cardType">
|
||||
<text class="card-name">{{ card.cardName }}</text>
|
||||
<text class="card-type-label">{{ card.typeLabel }}</text>
|
||||
<view class="card-details">
|
||||
<text v-if="card.remainingTimes !== null" class="card-remain">剩余 <text class="card-remain-num">{{ card.remainingTimes }}</text> 次</text>
|
||||
<text v-if="card.remainingAmount !== null" class="card-remain">余额 <text class="card-remain-num">{{ card.remainingAmount }}</text></text>
|
||||
<text v-if="card.expireTime" class="card-expire">有效期至 {{ card.expireTime }}</text>
|
||||
</view>
|
||||
<view class="card-status" :class="card.status">{{ card.statusLabel }}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="menu-section">
|
||||
<view class="menu-grid">
|
||||
<view class="menu-item" v-for="(menu, idx) in menus" :key="idx" @click="handleMenuClick(menu.key)">
|
||||
<text class="menu-symbol">{{ menu.symbol }}</text>
|
||||
<text class="menu-label">{{ menu.label }}</text>
|
||||
</view>
|
||||
<text class="stat-number">{{ userInfo.monthSignInCount }}</text>
|
||||
<text class="stat-label">本月签到</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -105,6 +67,7 @@
|
||||
</view>
|
||||
<view class="sign-right">
|
||||
<text class="sign-type">{{ record.typeLabel }}</text>
|
||||
<text class="sign-source">{{ record.sourceLabel }}</text>
|
||||
<text class="sign-status" :class="record.status">{{ record.statusLabel }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -116,16 +79,18 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const store = require('../../store/index')
|
||||
const memberApi = require('../../api/member')
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
statusBarHeight: 0,
|
||||
navBarHeight: 44,
|
||||
totalHeaderHeight: 44,
|
||||
userInfo: { nickname: 'Jason Wang', membershipLevel: '高级会员', memberNo: 'MEM2024A7K3', phone: '138****8888', gender: 1, birthday: '1995-06-15', totalCourses: 68, streakDays: 12, rating: '4.8' },
|
||||
memberCards: [{ cardName: '年卡 · 无限次', cardType: 'time', typeLabel: '时长卡', expireTime: '2027-06-15', status: 'active', statusLabel: '有效' }, { cardName: '储值卡 · 白金', cardType: 'stored', typeLabel: '储值卡', remainingAmount: 2580, expireTime: '2027-06-15', status: 'active', statusLabel: '有效' }, { cardName: '10次体验卡', cardType: 'count', typeLabel: '次卡', remainingTimes: 3, expireTime: '2026-12-31', status: 'active', statusLabel: '有效' }],
|
||||
menus: [{ symbol: '☰', label: '训练数据', key: 'data' }, { symbol: '★', label: '成就徽章', key: 'achievement' }, { symbol: '⚙', label: '账户设置', key: 'settings' }, { symbol: '▤', label: '我的预约', key: 'booking' }, { symbol: '◆', label: '购卡记录', key: 'cardPurchase' }, { symbol: '?', label: '帮助中心', key: 'help' }],
|
||||
signInRecords: [{ date: '07-15', time: '09:30', typeLabel: '扫码签到', status: 'success', statusLabel: '成功' }, { date: '07-14', time: '18:00', typeLabel: '扫码签到', status: 'success', statusLabel: '成功' }, { date: '07-13', time: '10:15', typeLabel: '手动签到', status: 'success', statusLabel: '成功' }, { date: '07-12', time: '08:45', typeLabel: '扫码签到', status: 'success', statusLabel: '成功' }]
|
||||
loading: true,
|
||||
userInfo: { nickname: '加载中...', memberNo: '', phone: '', gender: 0, birthday: '', lastLoginAt: '', totalSignInDays: 0, monthSignInCount: 0 },
|
||||
signInRecords: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
@@ -142,7 +107,62 @@
|
||||
this.navBarHeight = navBarHeight
|
||||
this.totalHeaderHeight = statusBarHeight + navBarHeight
|
||||
},
|
||||
methods: { editProfile() { uni.showToast({ title: '编辑资料', icon: 'none' }) }, goToSettings() { uni.showToast({ title: '设置页面', icon: 'none' }) }, handleMenuClick(key) { uni.showToast({ title: '功能: ' + key, icon: 'none' }) }, viewAllSignIn() { uni.showToast({ title: '全部签到记录', icon: 'none' }) } }
|
||||
onShow() {
|
||||
if (!store.isLoggedIn) {
|
||||
return
|
||||
}
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.loading = true
|
||||
try {
|
||||
const [memberResult, signInResult] = await Promise.allSettled([
|
||||
memberApi.getMemberInfo(),
|
||||
memberApi.getCheckInRecords({ page: 0, size: 5 })
|
||||
])
|
||||
|
||||
if (memberResult.status === 'fulfilled') {
|
||||
const info = memberResult.value
|
||||
this.userInfo = {
|
||||
nickname: info.nickname || '会员',
|
||||
memberNo: info.memberNo || ('ID' + (info.id || info.memberId || '')),
|
||||
phone: info.phone ? info.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : '未绑定',
|
||||
gender: info.gender || 0,
|
||||
birthday: info.birthday || '',
|
||||
lastLoginAt: info.lastLoginAt || '',
|
||||
totalSignInDays: info.totalSignInDays || 0,
|
||||
monthSignInCount: info.monthSignInCount || 0
|
||||
}
|
||||
}
|
||||
|
||||
if (signInResult.status === 'fulfilled') {
|
||||
const records = Array.isArray(signInResult.value)
|
||||
? signInResult.value
|
||||
: (signInResult.value.content || [])
|
||||
this.signInRecords = records.map(r => ({
|
||||
date: (r.checkInTime || r.createdAt || '').substring(5, 10) || '--',
|
||||
time: (r.checkInTime || r.createdAt || '').substring(11, 16) || '--',
|
||||
typeLabel: r.typeLabel || '签到',
|
||||
sourceLabel: r.sourceLabel || '小程序',
|
||||
status: r.status === 'SUCCESS' || r.status === 1 ? 'success' : 'fail',
|
||||
statusLabel: r.status === 'SUCCESS' || r.status === 1 ? '成功' : '失败'
|
||||
}))
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('个人中心数据加载失败:', e)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
editProfile() { uni.showToast({ title: '编辑资料', icon: 'none' }) },
|
||||
goToSettings() { uni.showToast({ title: '设置页面', icon: 'none' }) },
|
||||
viewAllSignIn() { uni.showToast({ title: '全部签到记录', icon: 'none' }) }
|
||||
},
|
||||
computed: {
|
||||
avatarText() { return (this.userInfo.nickname || '?').charAt(0) },
|
||||
genderLabel() { const g = this.userInfo.gender; return g === 1 ? '男' : g === 2 ? '女' : '未设置' }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -158,8 +178,7 @@
|
||||
.big-avatar { width: 56px; height: 56px; background: linear-gradient(135deg, #00E676, #00BFA5); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 24px; color: #1A1A1A; flex-shrink: 0; margin-right: 14px; }
|
||||
.user-info { flex: 1; display: flex; flex-direction: column; }
|
||||
.user-name { font-size: 18px; font-weight: 700; color: #1E1E1E; }
|
||||
.user-tag { font-size: 13px; color: #00C853; font-weight: 500; display: flex; align-items: center; }
|
||||
.tag-symbol { font-size: 12px; margin-right: 4px; }
|
||||
.user-tag { font-size: 13px; color: #00C853; font-weight: 500; }
|
||||
.edit-symbol { font-size: 20px; color: #7A7E84; }
|
||||
.user-details { background: #F5F7FA; border-radius: 12px; padding: 14px 16px; display: flex; flex-direction: column; }
|
||||
.detail-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
|
||||
@@ -170,31 +189,9 @@
|
||||
.stat-number { font-size: 24px; font-weight: 700; color: #00E676; }
|
||||
.stat-label { font-size: 12px; color: rgba(255,255,255,0.6); margin-top: 4px; }
|
||||
.stat-divider { width: 1px; background: rgba(255,255,255,0.15); }
|
||||
.stat-rating-row { display: flex; align-items: center; }
|
||||
.star-icon { font-size: 14px; color: #00E676; }
|
||||
.card-section { margin-bottom: 16px; }
|
||||
.section-title-row { display: flex; align-items: center; margin-bottom: 12px; }
|
||||
.section-symbol { font-size: 16px; color: #00E676; margin-right: 8px; }
|
||||
.section-title { font-size: 16px; font-weight: 700; color: #1E1E1E; }
|
||||
.card-scroll { display: flex; white-space: nowrap; }
|
||||
.member-card-item { display: inline-block; width: 200px; background: #FFFFFF; border-radius: 20px; padding: 16px; margin-right: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); position: relative; overflow: hidden; }
|
||||
.member-card-item::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; }
|
||||
.card-type-time::before { background: #00E676; }
|
||||
.card-type-stored::before { background: linear-gradient(135deg, #FFA502, #FF6B4A); }
|
||||
.card-type-count::before { background: #4A90D9; }
|
||||
.card-name { font-size: 15px; font-weight: 700; color: #1E1E1E; display: block; margin-top: 4px; }
|
||||
.card-type-label { font-size: 11px; color: #7A7E84; background: #F5F7FA; padding: 2px 8px; border-radius: 10px; margin-top: 4px; display: inline-block; }
|
||||
.card-details { margin-top: 12px; display: flex; flex-direction: column; }
|
||||
.card-remain { font-size: 13px; color: #7A7E84; }
|
||||
.card-remain-num { font-size: 16px; font-weight: 700; color: #00C853; margin: 0 2px; }
|
||||
.card-expire { font-size: 11px; color: #BDBDBD; }
|
||||
.card-status { position: absolute; top: 12px; right: 12px; font-size: 11px; font-weight: 600; padding: 2px 10px; border-radius: 20px; }
|
||||
.card-status.active { background: rgba(0,230,118,0.15); color: #00C853; }
|
||||
.menu-section { margin-bottom: 16px; }
|
||||
.menu-grid { display: flex; flex-wrap: wrap; }
|
||||
.menu-item { width: calc(33.33% - 8px); background: #FFFFFF; border-radius: 12px; padding: 16px 0; text-align: center; box-shadow: 0 4px 12px rgba(0,0,0,0.06); display: flex; flex-direction: column; align-items: center; margin-right: 12px; margin-bottom: 12px; }
|
||||
.menu-symbol { font-size: 22px; color: #7A7E84; }
|
||||
.menu-label { font-size: 13px; font-weight: 500; color: #7A7E84; }
|
||||
.sign-section { margin-bottom: 16px; }
|
||||
.sign-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
|
||||
.sign-header .section-title-row { margin-bottom: 0; }
|
||||
@@ -204,8 +201,10 @@
|
||||
.sign-date { font-size: 14px; font-weight: 600; color: #1E1E1E; }
|
||||
.sign-time { font-size: 12px; color: #7A7E84; margin-top: 2px; }
|
||||
.sign-right { display: flex; align-items: center; }
|
||||
.sign-type { font-size: 12px; color: #7A7E84; margin-right: 10px; }
|
||||
.sign-type { font-size: 12px; color: #7A7E84; margin-right: 6px; }
|
||||
.sign-source { font-size: 11px; color: #BDBDBD; background: #F5F7FA; padding: 1px 6px; border-radius: 8px; margin-right: 6px; }
|
||||
.sign-status { font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 20px; }
|
||||
.sign-status.success { background: rgba(0,230,118,0.15); color: #00C853; }
|
||||
.sign-status.fail { background: rgba(255,82,82,0.15); color: #FF5252; }
|
||||
.bottom-safe { height: 50px; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user