会员个人中心页面初步完成

This commit is contained in:
时舟年
2026-06-11 14:26:49 +08:00
committed by liwentao
parent 1fa2fbd3f3
commit a0026b1da5
170 changed files with 18092 additions and 35 deletions
@@ -0,0 +1,270 @@
import { moduleMock } from './mockData.js'␍
␍
function clone(value) {␍
return JSON.parse(JSON.stringify(value))␍
}␍
␍
export function getDefaultModuleState() {␍
return {␍
trainingReport: clone(moduleMock.trainingReport),␍
coupons: clone(moduleMock.coupons),␍
couponCenter: clone(moduleMock.couponCenter),␍
pointsHistory: clone(moduleMock.pointsHistory),␍
pointsRewards: clone(moduleMock.pointsRewards),␍
redeemRecords: [],␍
referralRecords: clone(moduleMock.referralRecords),␍
myCourses: clone(moduleMock.myCourses),␍
checkInHistory: clone(moduleMock.checkInHistory)␍
}␍
}␍
␍
export function mergeModuleState(saved) {␍
const defaults = getDefaultModuleState()␍
if (!saved) return defaults␍
return {␍
trainingReport: { ...defaults.trainingReport, ...(saved.trainingReport || {}) },␍
coupons: saved.coupons?.length ? saved.coupons : defaults.coupons,␍
couponCenter: saved.couponCenter?.length ? saved.couponCenter : defaults.couponCenter,␍
pointsHistory: saved.pointsHistory?.length ? saved.pointsHistory : defaults.pointsHistory,␍
pointsRewards: saved.pointsRewards?.length ? saved.pointsRewards : defaults.pointsRewards,␍
redeemRecords: saved.redeemRecords || defaults.redeemRecords,␍
referralRecords: saved.referralRecords?.length ? saved.referralRecords : defaults.referralRecords,␍
myCourses: saved.myCourses ? mergeMyCourses(defaults.myCourses, saved.myCourses) : defaults.myCourses,␍
checkInHistory: saved.checkInHistory?.length ? saved.checkInHistory : defaults.checkInHistory␍
}␍
}␍
␍
function mergeMyCourses(defaults, saved) {␍
return {␍
group: saved.group || defaults.group,␍
private: saved.private || defaults.private,␍
online: saved.online?.length ? saved.online : defaults.online,␍
package: saved.package?.length ? saved.package : defaults.package␍
}␍
}␍
␍
function syncCouponSummary(store) {␍
const available = store.modules.coupons.filter((c) => c.status === 'available')␍
const top = available[0]␍
store.couponPoints = {␍
...store.couponPoints,␍
amount: top ? `¥${top.amount}` : '暂无',␍
couponDesc: top␍
? `满${top.minSpend}可用 · ${available.length}张`␍
: '暂无可用优惠券',␍
couponAction: available.length ? '去使用' : '去领取',␍
points: store.stats.pointsBalance,␍
pointsLabel: '我的积分',␍
pointsAction: '去兑换'␍
}␍
return store␍
}␍
␍
export function finalizeModules(store) {␍
syncCouponSummary(store)␍
store.checkIns = store.modules.checkInHistory.slice(0, 3).map((item) => ({ ...item }))␍
return store␍
}␍
␍
export function getTrainingReportData(store, period = 'week') {␍
const report = store.modules.trainingReport␍
const trend = period === 'month' ? report.monthlyHours : report.weeklyHours␍
const calTrend = period === 'month' ? report.monthlyCalories : report.weeklyHours.map((w, i) => ({␍
label: w.label,␍
value: Math.round((report.summary.calories / 7) * (w.value || 0.5))␍
}))␍
return {␍
...report,␍
period,␍
summary: {␍
...report.summary,␍
hours: store.stats.trainingHours ?? report.summary.hours,␍
visits: report.summary.visits ?? store.stats.checkInCount ?? 5␍
},␍
trendHours: trend.map((t) => ({ ...t, id: t.label })),␍
trendCalories: calTrend.map((t) => ({ ...t, id: t.label })),␍
sessions: report.sessions.map((s) => ({ ...s }))␍
}␍
}␍
␍
export function getTrainingSessionById(store, id) {␍
const session = store.modules.trainingReport.sessions.find((s) => s.id === Number(id))␍
if (!session) return null␍
return {␍
...session,␍
heartRate: '128 bpm',␍
comment: '动作标准,核心发力良好,下次可增加负重。',␍
checkInTime: `${session.date} ${session.time.split('-')[0]}`␍
}␍
}␍
␍
export function filterTrainingSessions(store, filters = {}) {␍
let list = store.modules.trainingReport.sessions.map((s) => ({ ...s }))␍
if (filters.type && filters.type !== 'all') {␍
list = list.filter((s) => s.type === filters.type)␍
}␍
return list␍
}␍
␍
export function getCouponsByStatus(store, status) {␍
return store.modules.coupons.filter((c) => c.status === status).map((c) => ({ ...c }))␍
}␍
␍
export function getCouponById(store, id) {␍
const c = store.modules.coupons.find((item) => item.id === Number(id))␍
return c ? { ...c } : null␍
}␍
␍
export function useCoupon(store, id) {␍
const coupon = store.modules.coupons.find((c) => c.id === id)␍
if (!coupon || coupon.status !== 'available') return null␍
coupon.status = 'used'␍
coupon.usedAt = new Date().toISOString().slice(0, 10)␍
syncCouponSummary(store)␍
return coupon␍
}␍
␍
export function deleteExpiredCoupon(store, id) {␍
const idx = store.modules.coupons.findIndex((c) => c.id === id && c.status === 'expired')␍
if (idx >= 0) store.modules.coupons.splice(idx, 1)␍
syncCouponSummary(store)␍
return store␍
}␍
␍
export function getCouponCenterList(store) {␍
return store.modules.couponCenter.map((c) => ({ ...c }))␍
}␍
␍
export function claimCouponFromCenter(store, centerId) {␍
const item = store.modules.couponCenter.find((c) => c.id === centerId)␍
if (!item || item.claimed) return { ok: false, message: '已领取或不存在' }␍
const nextId = store.modules.coupons.reduce((m, c) => Math.max(m, c.id || 0), 0) + 1␍
const expire = new Date()␍
expire.setDate(expire.getDate() + item.expireDays)␍
store.modules.coupons.unshift({␍
id: nextId,␍
status: 'available',␍
amount: item.amount,␍
title: item.title,␍
desc: item.desc,␍
expire: expire.toISOString().slice(0, 10),␍
minSpend: item.minSpend,␍
tag: item.tag,␍
rules: `领取后${item.expireDays}天内有效,满${item.minSpend}可用`,␍
scope: '全门店',␍
flow: '预约课程时使用'␍
})␍
item.claimed = true␍
syncCouponSummary(store)␍
return { ok: true, message: '领取成功' }␍
}␍
␍
export function getPointsPageData(store) {␍
return {␍
balance: store.stats.pointsBalance,␍
config: moduleMock.pointsConfig,␍
history: store.modules.pointsHistory.map((h) => ({ ...h })),␍
rewards: store.modules.pointsRewards.map((r) => ({ ...r })),␍
redeemRecords: (store.modules.redeemRecords || []).map((r) => ({ ...r }))␍
}␍
}␍
␍
function nextHistoryId(history) {␍
return (history || []).reduce((max, item) => Math.max(max, item.id || 0), 0) + 1␍
}␍
␍
function formatNow() {␍
const d = new Date()␍
const pad = (n) => String(n).padStart(2, '0')␍
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`␍
}␍
␍
export function redeemPointsReward(store, rewardId) {␍
const reward = store.modules.pointsRewards.find((r) => r.id === rewardId)␍
if (!reward || reward.stock <= 0) return { ok: false, message: '库存不足' }␍
if (store.stats.pointsBalance < reward.cost) {␍
return { ok: false, message: '积分不足' }␍
}␍
store.stats.pointsBalance -= reward.cost␍
reward.stock -= 1␍
store.modules.pointsHistory.unshift({␍
id: nextHistoryId(store.modules.pointsHistory),␍
type: 'spend',␍
title: `兑换${reward.name}`,␍
amount: -reward.cost,␍
time: formatNow(),␍
balance: store.stats.pointsBalance␍
})␍
store.modules.redeemRecords = store.modules.redeemRecords || []␍
store.modules.redeemRecords.unshift({␍
id: nextHistoryId(store.modules.redeemRecords),␍
name: reward.name,␍
cost: reward.cost,␍
time: formatNow()␍
})␍
syncCouponSummary(store)␍
return { ok: true, message: '兑换成功', reward }␍
}␍
␍
export function filterPointsHistory(store, filter = 'all') {␍
const list = store.modules.pointsHistory␍
if (filter === 'earn') return list.filter((h) => h.amount > 0).map((h) => ({ ...h }))␍
if (filter === 'spend') return list.filter((h) => h.amount < 0).map((h) => ({ ...h }))␍
return list.map((h) => ({ ...h }))␍
}␍
␍
export function getReferralPageData(store) {␍
return {␍
...store.referral,␍
records: store.modules.referralRecords.map((r) => ({ ...r })),␍
rules: moduleMock.referralRules,␍
rewardSummary: moduleMock.referralRewardSummary␍
}␍
}␍
␍
export function getMyCoursesData(store, tab) {␍
const data = store.modules.myCourses␍
if (tab === 'group') return { ...data.group }␍
if (tab === 'private') return { ...data.private }␍
if (tab === 'online') return { list: data.online.map((c) => ({ ...c })) }␍
if (tab === 'package') return { list: data.package.map((c) => ({ ...c })) }␍
return {}␍
}␍
␍
export function getOnlineCourseById(store, id) {␍
const course = store.modules.myCourses.online.find((c) => c.id === Number(id))␍
if (!course) return null␍
return {␍
...course,␍
chapters: [␍
{ id: 1, title: '热身激活', duration: '8分钟', done: true },␍
{ id: 2, title: '核心训练 A', duration: '12分钟', done: true },␍
{ id: 3, title: '核心训练 B', duration: '10分钟', done: true },␍
{ id: 4, title: '拉伸放松', duration: '8分钟', done: true },␍
{ id: 5, title: '进阶组合', duration: '15分钟', done: false },␍
{ id: 6, title: '总结复盘', duration: '5分钟', done: false }␍
],␍
comments: [{ user: '学员A', text: '跟着练很方便' }]␍
}␍
}␍
␍
export function updateOnlineProgress(store, courseId, progress) {␍
const course = store.modules.myCourses.online.find((c) => c.id === Number(courseId))␍
if (course) course.progress = progress␍
return course␍
}␍
␍
export function getCheckInHistory(store, filter = 'all') {␍
const list = store.modules.checkInHistory␍
if (filter === 'all') return list.map((i) => ({ ...i }))␍
return list.filter((i) => i.tagTheme === filter).map((i) => ({ ...i }))␍
}␍
␍
/** @deprecated use getMyCoursesData */␍
export function getMyCoursesByTab(store, tab) {␍
if (tab === 'ongoing') return store.modules.myCourses.group?.ongoing || []␍
if (tab === 'completed') return store.modules.myCourses.group?.completed || []␍
return []␍
}␍
␍
export { moduleMock }␍