优化会员信息模块及首页组件,清理冗余图片资源

This commit is contained in:
future
2026-06-07 22:41:55 +08:00
parent be7eabdbb1
commit 51bdf15613
111 changed files with 667 additions and 523 deletions
+44 -44
View File
@@ -5,7 +5,7 @@ export const memberCenterMock = {
name: '张小芳',
phone: '13812345678 已绑定微信',
memberLevel: '黄金会员',
avatar: '/static/images/AvatarEditWrap.png'
avatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AvatarEditWrap.png'
},
stats: {
checkInCount: 128,
@@ -75,7 +75,7 @@ export const userInfoMock = {
height: '165',
weight: '63.5',
fitnessGoals: ['减脂', '塑形'],
avatar: '/static/images/AvatarEditWrap.png'
avatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AvatarEditWrap.png'
}
export const fitnessGoalOptions = ['减脂', '塑形', '增肌', '提升耐力', '改善体态']
@@ -102,7 +102,7 @@ export const memberCardMock = {
time: '2024-07-12 09:05',
value: '-1次',
valueType: 'negative',
icon: '/static/images/dumbbell.png',
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/dumbbell.png',
iconTheme: 'orange'
},
{
@@ -112,7 +112,7 @@ export const memberCardMock = {
time: '2024-07-11 18:30',
value: '-1天',
valueType: 'negative',
icon: '/static/images/mappin.png',
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/mappin.png',
iconTheme: 'green'
},
{
@@ -122,7 +122,7 @@ export const memberCardMock = {
time: '2024-07-01 10:00',
value: '+90天',
valueType: 'positive',
icon: '/static/images/pluscircle.png',
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/pluscircle.png',
iconTheme: 'orange'
}
],
@@ -156,14 +156,14 @@ export const bodyTestMock = {
{ step: 3, title: '确认连接', desc: '点击下方按钮搜索并配对设备' }
],
metricDefs: [
{ key: 'weight', label: '体重', unit: 'kg', icon: '/static/images/target.png' },
{ key: 'bmi', label: 'BMI', unit: '', icon: '/static/images/activity.png' },
{ key: 'bodyFat', label: '体脂率', unit: '%', icon: '/static/images/trendingdown.png' },
{ key: 'muscleMass', label: '肌肉量', unit: 'kg', icon: '/static/images/dumbbell.png' },
{ key: 'visceralFat', label: '内脏脂肪', unit: '级', icon: '/static/images/alertcircle.png' },
{ key: 'bmr', label: '基础代谢', unit: 'kcal', icon: '/static/images/clock.png' },
{ key: 'bodyWater', label: '体水分', unit: '%', icon: '/static/images/shield.png' },
{ key: 'boneMass', label: '骨量', unit: 'kg', icon: '/static/images/user.png' }
{ key: 'weight', label: '体重', unit: 'kg', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/target.png' },
{ key: 'bmi', label: 'BMI', unit: '', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/activity.png' },
{ key: 'bodyFat', label: '体脂率', unit: '%', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/trendingdown.png' },
{ key: 'muscleMass', label: '肌肉量', unit: 'kg', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/dumbbell.png' },
{ key: 'visceralFat', label: '内脏脂肪', unit: '级', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/alertcircle.png' },
{ key: 'bmr', label: '基础代谢', unit: 'kcal', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/clock.png' },
{ key: 'bodyWater', label: '体水分', unit: '%', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/shield.png' },
{ key: 'boneMass', label: '骨量', unit: 'kg', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user.png' }
],
radarLabels: [
{ key: 'weight', label: '体重控制' },
@@ -185,7 +185,7 @@ export const bodyTestMock = {
title: '燃脂 HIIT 团课',
coach: '李明教练',
schedule: '每周二、四 19:00',
banner: '/static/images/AC1Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC1Banner.png',
tag: '减脂推荐'
},
{
@@ -193,7 +193,7 @@ export const bodyTestMock = {
title: '核心力量塑形',
coach: '王强教练',
schedule: '每周一、三 18:30',
banner: '/static/images/AC2Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC2Banner.png',
tag: '塑形推荐'
}
],
@@ -352,7 +352,7 @@ export const bookingMock = {
{
id: 1,
title: '瑜伽基础班',
banner: '/static/images/AC1Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC1Banner.png',
status: 'booked',
statusLabel: '已预约',
schedule: '07月15日 09:00-10:00',
@@ -368,7 +368,7 @@ export const bookingMock = {
{
id: 2,
title: '私教健身课',
banner: '/static/images/AC2Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC2Banner.png',
status: 'pending',
statusLabel: '待上课',
schedule: '07月18日 14:00-15:00',
@@ -386,7 +386,7 @@ export const bookingMock = {
{
id: 3,
title: '动感单车',
banner: '/static/images/AC1Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC1Banner.png',
status: 'completed',
statusLabel: '已完成',
schedule: '07月10日 19:00-20:00',
@@ -397,7 +397,7 @@ export const bookingMock = {
{
id: 4,
title: '普拉提进阶',
banner: '/static/images/AC2Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC2Banner.png',
status: 'cancelled',
statusLabel: '已取消',
schedule: '07月05日 10:00-11:00',
@@ -428,7 +428,7 @@ export const courseCatalogMock = {
title: '瑜伽基础班',
type: 'group',
coach: '李明教练',
coachAvatar: '/static/images/user0.png',
coachAvatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user0.png',
date: '2024-07-15',
startTime: '09:00',
endTime: '10:00',
@@ -438,7 +438,7 @@ export const courseCatalogMock = {
price: '次卡扣 1 次',
payType: 'session',
period: 'morning',
banner: '/static/images/AC1Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC1Banner.png',
intro: '适合零基础学员,重点提升柔韧性与呼吸控制。',
suitable: '久坐办公族、初学者、想改善体态者',
coachBio: '国家一级瑜伽指导员,5年教学经验',
@@ -454,7 +454,7 @@ export const courseCatalogMock = {
title: 'HIIT 燃脂团课',
type: 'group',
coach: '赵敏教练',
coachAvatar: '/static/images/user1.png',
coachAvatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user1.png',
date: '2024-07-15',
startTime: '19:00',
endTime: '20:00',
@@ -464,7 +464,7 @@ export const courseCatalogMock = {
price: '时长卡',
payType: 'duration',
period: 'evening',
banner: '/static/images/AC1Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC1Banner.png',
intro: '高强度间歇训练,快速燃脂提升心肺。',
suitable: '有一定运动基础、目标减脂者',
coachBio: 'ACE 认证教练,擅长 HIIT 与动感单车',
@@ -477,7 +477,7 @@ export const courseCatalogMock = {
title: '私教 · 力量训练',
type: 'private',
coach: '王强教练',
coachAvatar: '/static/images/user2.png',
coachAvatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user2.png',
date: '2024-07-16',
startTime: '14:00',
endTime: '15:00',
@@ -487,7 +487,7 @@ export const courseCatalogMock = {
price: '私教课时卡',
payType: 'private',
period: 'afternoon',
banner: '/static/images/AC2Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC2Banner.png',
intro: '一对一力量训练,定制训练计划。',
suitable: '增肌塑形、康复训练',
coachBio: 'NSCA 认证私教,8年从业经验',
@@ -500,7 +500,7 @@ export const courseCatalogMock = {
title: '普拉提进阶',
type: 'group',
coach: '李明教练',
coachAvatar: '/static/images/user0.png',
coachAvatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user0.png',
date: '2024-07-17',
startTime: '10:30',
endTime: '11:30',
@@ -510,7 +510,7 @@ export const courseCatalogMock = {
price: '次卡扣 1 次',
payType: 'session',
period: 'morning',
banner: '/static/images/AC2Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC2Banner.png',
intro: '核心稳定与体态矫正进阶课程。',
suitable: '有普拉提基础者',
coachBio: '国家一级瑜伽指导员',
@@ -523,7 +523,7 @@ export const courseCatalogMock = {
title: '动感单车',
type: 'group',
coach: '赵敏教练',
coachAvatar: '/static/images/user1.png',
coachAvatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user1.png',
date: '2024-07-18',
startTime: '18:30',
endTime: '19:30',
@@ -533,7 +533,7 @@ export const courseCatalogMock = {
price: '储值卡 ¥39',
payType: 'stored',
period: 'evening',
banner: '/static/images/AC1Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC1Banner.png',
intro: '音乐骑行,团队氛围燃脂。',
suitable: '所有级别,可调节阻力',
coachBio: 'ACE 认证教练',
@@ -720,10 +720,10 @@ export const moduleMock = {
rule: '签到、训练、邀请好友、购课均可获得积分;积分可用于商城兑换。'
},
pointsRewards: [
{ id: 1, name: '团课体验券', cost: 500, stock: 12, icon: '/static/images/ticket.png' },
{ id: 2, name: '运动毛巾', cost: 800, stock: 5, icon: '/static/images/dumbbell.png' },
{ id: 3, name: '私教体验30分钟', cost: 2000, stock: 3, icon: '/static/images/usercheck.png' },
{ id: 4, name: '蛋白粉小样', cost: 350, stock: 20, icon: '/static/images/star.png' }
{ id: 1, name: '团课体验券', cost: 500, stock: 12, icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/ticket.png' },
{ id: 2, name: '运动毛巾', cost: 800, stock: 5, icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/dumbbell.png' },
{ id: 3, name: '私教体验30分钟', cost: 2000, stock: 3, icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/usercheck.png' },
{ id: 4, name: '蛋白粉小样', cost: 350, stock: 20, icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/star.png' }
],
pointsHistory: [
{ id: 1, type: 'earn', title: '团课签到', amount: 50, time: '2024-07-12 09:10', balance: 1250 },
@@ -739,11 +739,11 @@ export const moduleMock = {
'积分可用于兑换课程体验券及周边礼品'
],
referralRecords: [
{ id: 1, name: '李**', avatar: '/static/images/user0.png', status: 'purchased', statusLabel: '已购课', time: '2024-07-05', reward: '+300积分', rewardStatus: '已发放' },
{ id: 2, name: '王**', avatar: '/static/images/user1.png', status: 'registered', statusLabel: '已注册', time: '2024-06-20', reward: '+100积分', rewardStatus: '已发放' },
{ id: 3, name: '陈**', avatar: '/static/images/user2.png', status: 'invited', statusLabel: '已邀请', time: '2024-06-15', reward: '待注册', rewardStatus: '待发放' },
{ id: 4, name: '赵**', avatar: '/static/images/user3.png', status: 'purchased', statusLabel: '已购课', time: '2024-06-01', reward: '+300积分', rewardStatus: '已发放' },
{ id: 5, name: '刘**', avatar: '/static/images/user0.png', status: 'registered', statusLabel: '已注册', time: '2024-05-28', reward: '+100积分', rewardStatus: '已发放' }
{ id: 1, name: '李**', avatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user0.png', status: 'purchased', statusLabel: '已购课', time: '2024-07-05', reward: '+300积分', rewardStatus: '已发放' },
{ id: 2, name: '王**', avatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user1.png', status: 'registered', statusLabel: '已注册', time: '2024-06-20', reward: '+100积分', rewardStatus: '已发放' },
{ id: 3, name: '陈**', avatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user2.png', status: 'invited', statusLabel: '已邀请', time: '2024-06-15', reward: '待注册', rewardStatus: '待发放' },
{ id: 4, name: '赵**', avatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user3.png', status: 'purchased', statusLabel: '已购课', time: '2024-06-01', reward: '+300积分', rewardStatus: '已发放' },
{ id: 5, name: '刘**', avatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user0.png', status: 'registered', statusLabel: '已注册', time: '2024-05-28', reward: '+100积分', rewardStatus: '已发放' }
],
referralRewardSummary: {
totalPoints: 800,
@@ -763,7 +763,7 @@ export const moduleMock = {
id: 1,
title: '瑜伽基础班',
coach: '李明教练',
banner: '/static/images/AC1Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC1Banner.png',
progress: 6,
total: 12,
schedule: '每周二、四 09:00',
@@ -778,7 +778,7 @@ export const moduleMock = {
id: 3,
title: '动感单车入门',
coach: '赵敏教练',
banner: '/static/images/AC1Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC1Banner.png',
progress: 8,
total: 8,
schedule: '已结课',
@@ -791,7 +791,7 @@ export const moduleMock = {
private: {
remaining: 7,
coach: '王强教练',
coachAvatar: '/static/images/user2.png',
coachAvatar: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user2.png',
nextClass: '07月15日 14:00',
bookings: [
{ id: 2, title: '私教 · 力量训练', time: '07月18日 14:00', status: '已预约', location: 'B区私教室' }
@@ -804,7 +804,7 @@ export const moduleMock = {
{
id: 201,
title: '居家核心训练',
cover: '/static/images/AC2Banner.png',
cover: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC2Banner.png',
duration: '45分钟',
progress: 60,
chapters: 6,
@@ -814,7 +814,7 @@ export const moduleMock = {
{
id: 202,
title: '直播 · 晨间拉伸',
cover: '/static/images/AC1Banner.png',
cover: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC1Banner.png',
duration: '30分钟',
progress: 0,
liveTime: '07月20日 07:00',
@@ -825,7 +825,7 @@ export const moduleMock = {
{
id: 301,
title: '28天减脂训练营',
banner: '/static/images/AC1Banner.png',
banner: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AC1Banner.png',
progress: 3,
total: 10,
coach: '李明教练',
+1 -1
View File
@@ -275,7 +275,7 @@ export function renewMemberCard(store, addDays = 90) {
time: formatRecordTime(new Date()),
value: `+${addDays}`,
valueType: 'positive',
icon: '/static/images/pluscircle.png',
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/pluscircle.png',
iconTheme: 'orange'
})
@@ -0,0 +1,33 @@
@font-face {
font-family: "iconfont"; /* Project id */
src: url('tabbar.ttf?t=1780818759010') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-home:before {
content: "\e666";
}
.icon-course:before {
content: "\e692";
}
.icon-train:before {
content: "\e8be";
}
.icon-discover:before {
content: "\e726";
}
.icon-profile:before {
content: "\e501";
}
@@ -0,0 +1,45 @@
<template>
<view class="skeleton" :style="{ padding: padding }">
<slot />
</view>
</template>
<script setup>
defineProps({
padding: {
type: String,
default: '20rpx'
}
})
</script>
<style lang="scss" scoped>
.skeleton {
background-color: #f5f5f5;
min-height: 100vh;
}
:deep(.skeleton-shimmer) {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
:deep(.skeleton-line) {
height: 32rpx;
border-radius: 16rpx;
}
:deep(.skeleton-block) {
border-radius: 16rpx;
}
:deep(.skeleton-circle) {
border-radius: 50%;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
</style>
+72 -86
View File
@@ -8,11 +8,13 @@
hover-class="tab-item--hover"
@tap.stop="onTabTap(index)"
>
<image
:src="currentActiveIndex === index ? tab.iconActive : tab.icon"
mode="aspectFit"
class="tab-icon"
/>
<!-- 判断是否使用字体图标我的页面用字体其他用图片 -->
<text
v-if="tab.useFontIcon"
:class="['iconfont', tab.icon]"
class="tab-icon-font"
:style="{ fontSize: tab.fontSize}"
></text>
<text class="tab-label">{{ tab.label }}</text>
</view>
</view>
@@ -34,32 +36,27 @@ const props = defineProps({
const emit = defineEmits(['update:active', 'tab-change'])
// 当前激活的索引 - 默认从路由获取
const currentActiveIndex = ref(-1)
// 是否需要显示 TabBar
const shouldShowTabBar = ref(true)
// 不需要显示 TabBar 的页面路径列表(注意:不要带开头的 /)
const HIDE_TABBAR_PAGES = [
'pages/memberInfo/courseList', // 预约课程
'pages/memberInfo/courseDetail', // 课程详情
'pages/memberInfo/booking', // 我的预约
'pages/memberInfo/bodyTestReport', // 体测报告
'pages/groupCourse/list', // 团课列表
'pages/groupCourse/detail', // 团课详情
'pages/searchCourse/searchCourse', // 搜索课程
'pages/checkIn/checkIn', // 会员签到
'pages/memberInfo/myCourses', // 我的课程
'pages/memberInfo/coupons', // 我的优惠券
'pages/memberInfo/points', // 我的积分
'pages/memberInfo/pointsMall', // 积分商城
'pages/memberInfo/referral', // 邀请好友
'pages/memberInfo/userInfo', // 个人信息
'pages/memberInfo/memberCard', // 我的会员卡
'pages/memberInfo/courseList',
'pages/memberInfo/courseDetail',
'pages/memberInfo/booking',
'pages/memberInfo/bodyTestReport',
'pages/groupCourse/list',
'pages/groupCourse/detail',
'pages/searchCourse/searchCourse',
'pages/checkIn/checkIn',
'pages/memberInfo/myCourses',
'pages/memberInfo/coupons',
'pages/memberInfo/points',
'pages/memberInfo/pointsMall',
'pages/memberInfo/referral',
'pages/memberInfo/userInfo',
'pages/memberInfo/memberCard',
]
// 从路由获取当前激活的 tab
function getActiveIndexFromRoute() {
const routePath = getCurrentRoutePath()
const index = getTabIndexByRoute(routePath)
@@ -67,16 +64,12 @@ function getActiveIndexFromRoute() {
return index >= 0 ? index : 0
}
// 同步激活状态(高优先级:路由 > props)
function syncActiveState() {
// 优先从路由获取(最准确)
const routeIndex = getActiveIndexFromRoute()
if (routeIndex >= 0) {
currentActiveIndex.value = routeIndex
return
}
// 其次使用 props
if (props.active >= 0) {
currentActiveIndex.value = props.active
} else if (props.activeTab >= 0) {
@@ -86,23 +79,16 @@ function syncActiveState() {
}
}
// 检查当前页面是否需要隐藏 TabBar
function checkShouldShow() {
let routePath = getCurrentRoutePath()
// 标准化路径:去掉开头的 /
if (routePath.startsWith('/')) {
routePath = routePath.slice(1)
}
// 去掉查询参数(?后面的内容)
if (routePath.includes('?')) {
routePath = routePath.split('?')[0]
}
// 检查是否在隐藏列表中
const shouldHide = HIDE_TABBAR_PAGES.includes(routePath)
shouldShowTabBar.value = !shouldHide
console.log('=== TabBar 显示控制 ===')
console.log('原始路径:', getCurrentRoutePath())
console.log('标准化路径:', routePath)
@@ -110,25 +96,19 @@ function checkShouldShow() {
console.log('是否显示 TabBar:', shouldShowTabBar.value)
}
// 监听路由变化(页面切换时自动同步)
let routeWatcher = null
let appRouteCallback = null
onMounted(() => {
// 初始同步
syncActiveState()
checkShouldShow()
// #ifdef APP-PLUS
// App 端:监听页面显示
routeWatcher = setInterval(() => {
syncActiveState()
checkShouldShow()
}, 300)
// #endif
// #ifdef MP-WEIXIN
// 小程序端:监听路由变化
if (typeof uni.onAppRoute === 'function') {
appRouteCallback = () => {
setTimeout(() => {
@@ -143,11 +123,8 @@ onMounted(() => {
onBeforeUnmount(() => {
// #ifdef APP-PLUS
if (routeWatcher) {
clearInterval(routeWatcher)
}
if (routeWatcher) { clearInterval(routeWatcher) }
// #endif
// #ifdef MP-WEIXIN
if (appRouteCallback && typeof uni.offAppRoute === 'function') {
uni.offAppRoute(appRouteCallback)
@@ -155,44 +132,48 @@ onBeforeUnmount(() => {
// #endif
})
// 监听 props 变化
watch(() => props.active, () => {
const routeIndex = getActiveIndexFromRoute()
if (routeIndex !== currentActiveIndex.value) {
syncActiveState()
}
if (routeIndex !== currentActiveIndex.value) { syncActiveState() }
})
// tabs 配置:只有"我的"用字体图标
const tabs = [
{
path: PAGE.INDEX,
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/tabBar/home.png',
iconActive: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/tabBar/active/home.png',
label: '首页'
icon: 'icon-home',
label: '首页',
useFontIcon: true,
fontSize:"36rpx"
},
{
path: PAGE.COURSE,
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/tabBar/course.png',
iconActive: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/tabBar/active/course.png',
label: '课程'
icon: 'icon-course',
iconActive: '/static/tabBar/active/course.png',
label: '课程',
useFontIcon: true,
fontSize:"36rpx"
},
{
path: PAGE.TRAIN,
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/tabBar/train.png',
iconActive: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/tabBar/active/train.png',
label: '训练'
icon: 'icon-train',
label: '训练',
useFontIcon: true,
fontSize:"48rpx"
},
{
path: PAGE.DISCOVER,
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/tabBar/discover.png',
iconActive: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/tabBar/active/discover.png',
label: '发现'
icon: 'icon-discover',
label: '发现',
useFontIcon: true,
fontSize:"48rpx"
},
{
path: PAGE.MEMBER,
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/tabBar/profile.png',
iconActive: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/tabBar/active/profile.png',
label: '我的'
icon: 'icon-profile',
label: '我的',
useFontIcon: true,
fontSize:"36rpx"
}
]
@@ -200,37 +181,22 @@ let isSwitching = false
function onTabTap(index) {
if (isSwitching) return
const targetPath = TAB_ROUTES[index]
const currentPath = TAB_ROUTES[currentActiveIndex.value]
if (targetPath === currentPath) return
console.log('Tab 点击:', index, targetPath)
// 1. 立即更新 UI 高亮
currentActiveIndex.value = index
// 2. 通知父组件
emit('update:active', index)
emit('tab-change', index)
// 3. 显示 loading(可选)
let timer = setTimeout(() => {
uni.showLoading({ title: '加载中...', mask: true })
}, 50)
isSwitching = true
// 4. 执行跳转
uni.switchTab({
url: targetPath,
success: () => {
console.log('switchTab 成功:', targetPath)
},
success: () => { console.log('switchTab 成功:', targetPath) },
fail: (err) => {
console.error('switchTab 失败:', err)
// 降级
uni.reLaunch({ url: targetPath })
},
complete: () => {
@@ -238,7 +204,6 @@ function onTabTap(index) {
uni.hideLoading()
setTimeout(() => {
isSwitching = false
// 跳转完成后,再次同步确保高亮正确
syncActiveState()
checkShouldShow()
}, 100)
@@ -248,19 +213,24 @@ function onTabTap(index) {
</script>
<style lang="scss" scoped>
// 引入字体图标 CSS(定义 @font-face
@import '/common/style/tabbar_icon/tabbar.css';
.tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 120rpx;
background: #1A4A6F;
background: rgba(200, 225, 238, 0.8);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
display: flex;
justify-content: space-around;
align-items: center;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.06);
box-shadow: 0 -4rpx 24rpx rgba(120, 185, 215, 0.2);
border-radius: 32rpx 32rpx 0 0;
z-index: 999;
}
@@ -278,18 +248,34 @@ function onTabTap(index) {
transform: scale(0.95);
}
// 图片图标样式
.tab-icon {
width: 40rpx;
height: 40rpx;
}
// 字体图标样式
.tab-icon-font {
font-size: 44rpx;
line-height: 1;
}
// 字体图标颜色控制(根据选中状态)
.tab-item .iconfont {
color: gray; // 未选中颜色
}
.tab-item.active .iconfont {
color: #5A98B0; // 选中颜色
}
.tab-label {
font-size: 22rpx;
color: #94a3b8;
color: #8AABBB;
}
.tab-item.active .tab-label {
color: #f97316;
color: #5A98B0;
font-weight: 600;
}
</style>
@@ -0,0 +1,85 @@
<!-- components/GlobalLoading.vue -->
<template>
<view v-if="visible" class="global-loading">
<view class="loading-mask"></view>
<view class="loading-content">
<view class="loading-spinner"></view>
<text class="loading-text">{{ text }}</text>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
const visible = ref(false)
const text = ref('加载中...')
// 显示
function show(loadingText = '加载中...') {
visible.value = true
text.value = loadingText
}
// 隐藏
function hide() {
visible.value = false
}
// 挂载到全局
if (typeof uni !== 'undefined') {
uni.$globalLoading = { show, hide }
}
</script>
<style lang="scss" scoped>
.global-loading {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
}
.loading-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
}
.loading-content {
position: relative;
background-color: rgba(0, 0, 0, 0.7);
border-radius: 16rpx;
padding: 32rpx 48rpx;
display: flex;
flex-direction: column;
align-items: center;
gap: 20rpx;
}
.loading-spinner {
width: 48rpx;
height: 48rpx;
border: 4rpx solid rgba(255, 255, 255, 0.3);
border-top-color: #fff;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.loading-text {
color: #fff;
font-size: 24rpx;
}
</style>
@@ -1,7 +1,5 @@
<template>
<!-- 轮播图容器 -->
<view class="banner-container">
<!-- 轮播图组件 -->
<swiper
class="banner-swiper"
:circular="true"
@@ -11,15 +9,10 @@
:indicator-dots="false"
@change="onSwiperChange"
>
<!-- 轮播项 -->
<swiper-item v-for="(banner, index) in banners" :key="index">
<!-- 轮播内容 -->
<view class="banner-content">
<!-- 轮播图片 -->
<image :src="banner.image" mode="aspectFill" class="banner-image" />
<!-- 图片遮罩层 -->
<view class="banner-overlay"></view>
<!-- 轮播文字信息 -->
<view class="banner-text">
<text class="banner-title">{{ banner.title }}</text>
<text class="banner-subtitle">{{ banner.subtitle }}</text>
@@ -28,7 +21,6 @@
</view>
</swiper-item>
</swiper>
<!-- 轮播指示器点 -->
<view class="banner-dots">
<view
v-for="(_, index) in banners"
@@ -42,7 +34,6 @@
<script setup>
import { ref } from 'vue'
// 轮播图数据列表
const banners = [
{
image: 'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=800&q=80',
@@ -64,29 +55,25 @@ const banners = [
}
]
// 当前轮播索引,用于控制指示器激活状态
const currentIndex = ref(0)
// 轮播图切换时的回调函数,更新当前索引
const onSwiperChange = (e) => {
currentIndex.value = e.detail.current
}
</script>
<style lang="scss" scoped>
/* 轮播图容器样式 */
.banner-container {
position: relative;
z-index: 2;
width: 100%;
}
/* 轮播图组件样式 */
.banner-swiper {
width: 100%;
height: 360rpx;
height: 480rpx;
}
/* 轮播内容容器样式 */
.banner-content {
width: 100%;
height: 100%;
@@ -94,78 +81,108 @@ const onSwiperChange = (e) => {
overflow: hidden;
}
/* 轮播图片样式 */
.banner-image {
width: 100%;
height: 100%;
}
/* 图片遮罩层样式,添加渐变效果 */
.banner-overlay {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(11, 43, 75, 0.85) 0%, rgba(26, 74, 111, 0.6) 100%);
}
/* 轮播文字信息容器样式 */
.wave-transition {
position: absolute;
left: 0;
right: 0;
bottom: -2rpx;
height: 100rpx;
z-index: 3;
overflow: hidden;
}
.wt-layer {
position: absolute;
left: -10%;
width: 120%;
height: 100%;
}
.wt-layer-1 {
bottom: 0;
background: #C0DDE9;
border-radius: 45% 55% 0 0;
opacity: 0.9;
}
.wt-layer-2 {
bottom: -10rpx;
background: #D4EAF2;
border-radius: 55% 45% 0 0;
opacity: 0.85;
}
.wt-layer-3 {
bottom: -20rpx;
background: #E8F4F9;
border-radius: 40% 60% 0 0;
opacity: 0.9;
}
.banner-text {
position: absolute;
left: 32rpx;
left: 36rpx;
top: 50%;
transform: translateY(-50%);
z-index: 2;
}
/* 轮播标题样式 */
.banner-title {
display: block;
font-size: 48rpx;
font-weight: 800;
color: #ffffff;
margin-bottom: 8rpx;
text-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.3);
text-shadow: 0 4rpx 16rpx rgba(80, 150, 190, 0.4);
}
/* 轮播副标题样式 */
.banner-subtitle {
display: block;
font-size: 56rpx;
font-weight: 800;
color: #f97316;
color: #E0F0FA;
margin-bottom: 16rpx;
text-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.3);
text-shadow: 0 4rpx 16rpx rgba(80, 150, 190, 0.4);
}
/* 轮播描述文字样式 */
.banner-desc {
display: block;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
color: rgba(255, 255, 255, 0.85);
}
/* 轮播指示器容器样式 */
.banner-dots {
display: flex;
justify-content: center;
gap: 16rpx;
margin-top: 24rpx;
margin-top: -100rpx;
position: relative;
z-index: 3;
}
/* 轮播指示器点样式 */
.dot {
width: 48rpx;
height: 8rpx;
border-radius: 9999rpx;
background: #d1d5db;
background: #D0E4EE;
transition: all 0.3s ease;
}
/* 轮播指示器激活状态样式 */
.dot.active {
width: 64rpx;
background: #f97316;
background: linear-gradient(90deg, #7AB5CC, #9CCFDF);
}
</style>
</style>
@@ -1,21 +1,15 @@
<template>
<!-- 快捷入口容器 -->
<view class="quick-entry">
<!-- 快捷入口项 -->
<view
v-for="(item, index) in entries"
:key="index"
class="entry-item"
@tap="QEClick(item.path)"
>
<!-- 入口图标容器 -->
<view :class="['entry-icon', { accent: item.accent }]">
<!-- 入口图标图片 -->
<image :src="item.icon" mode="aspectFit" class="icon-img" />
</view>
<!-- 入口标题 -->
<text class="entry-title">{{ item.title }}</text>
<!-- 入口描述 -->
<text class="entry-desc">{{ item.desc }}</text>
</view>
</view>
@@ -28,7 +22,6 @@ const QEClick = path => {
url:path
})
}
// 快捷入口数据列表
const entries = [
{
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/icons/course.png',
@@ -66,18 +59,21 @@ const entries = [
</script>
<style lang="scss" scoped>
/* 快捷入口容器样式 */
.quick-entry {
display: flex;
justify-content: space-between;
padding: 32rpx 24rpx;
background: #ffffff;
background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
margin: 24rpx;
border-radius: 24rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
border-radius: 28rpx;
box-shadow: 0 8rpx 32rpx rgba(120, 185, 215, 0.18);
border: 1rpx solid rgba(255, 255, 255, 0.7);
position: relative;
z-index: 3;
}
/* 快捷入口项样式 */
.entry-item {
display: flex;
flex-direction: column;
@@ -85,40 +81,36 @@ const entries = [
flex: 1;
}
/* 入口图标容器样式 */
.entry-icon {
width: 104rpx;
height: 104rpx;
border-radius: 20rpx;
background: #072A4E;
border-radius: 24rpx;
background: linear-gradient(135deg, #7AB5CC 0%, #9CCFDF 100%);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
box-shadow: 0 6rpx 20rpx rgba(122, 181, 204, 0.35);
}
/* 入口图标图片样式 */
.icon-img {
width: 52rpx;
height: 52rpx;
}
/* 入口图标强调色样式(橙色背景) */
.entry-icon.accent {
background: #FC5A15;
background: linear-gradient(135deg, #6BA8C0 0%, #8CC5D5 100%);
}
/* 入口标题样式 */
.entry-title {
font-size: 26rpx;
font-weight: 600;
color: #1a202c;
color: #2D4A5A;
margin-bottom: 4rpx;
}
/* 入口描述文字样式 */
.entry-desc {
font-size: 22rpx;
color: #94a3b8;
color: #8AABBB;
}
</style>
</style>
@@ -9,7 +9,7 @@
<view class="view-more">
<text>查看更多</text>
<text class="arrow">
<uni-icons type="right" size="20" color="#94a3b8"/>
<uni-icons type="right" size="20" color="#8CA0B0"/>
</text>
</view>
</view>
@@ -94,41 +94,21 @@ const getCourseTypeName = (type) => {
// 根据课程信息获取标签文本
const getTag = (course) => {
// 满员标签
if (course.currentMembers >= course.maxMembers) {
return '已满员'
}
// 已结束的课程
if (course.status === '2') {
return '已结束'
}
// 高人气标签(参与人数超过最大人数的80%)
if (course.currentMembers / course.maxMembers >= 0.8) {
return '热门'
}
// 课程类型标签
if (course.currentMembers >= course.maxMembers) return '已满员'
if (course.status === '2') return '已结束'
if (course.currentMembers / course.maxMembers >= 0.8) return '热门'
return getCourseTypeName(course.courseType)
}
// 根据课程信息获取标签样式类型
const getTagType = (course) => {
// 满员标签样式
if (course.currentMembers >= course.maxMembers) {
return 'full'
}
// 已结束标签样式
if (course.status === '2') {
return 'ended'
}
// 热门标签样式
if (course.currentMembers / course.maxMembers >= 0.8) {
return 'hot'
}
// 默认样式
if (course.currentMembers >= course.maxMembers) return 'full'
if (course.status === '2') return 'ended'
if (course.currentMembers / course.maxMembers >= 0.8) return 'hot'
return 'default'
}
// 计算课程时长(从startTime和endTime计算)
// 计算课程时长
const calculateDuration = (startTime, endTime) => {
if (!startTime || !endTime) return '60分钟'
const start = new Date(startTime)
@@ -137,9 +117,8 @@ const calculateDuration = (startTime, endTime) => {
return `${durationMinutes}分钟`
}
// 获取课程难度(基于课程类型和描述简单判断)
// 获取课程难度
const getCourseLevel = (course) => {
// 可以根据实际需求调整逻辑
if (course.courseType === '2') return '中级'
if (course.courseType === '3') return '高级'
if (course.courseType === '1') return '初级'
@@ -148,169 +127,61 @@ const getCourseLevel = (course) => {
// 处理图片URL
const getImageUrl = (coverImage) => {
if (!coverImage) {
return 'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=400&q=80'
}
// 如果已经是完整URL直接返回,否则拼接基础路径
if (coverImage.startsWith('http')) {
return coverImage
}
// 这里需要根据您的实际图片基础路径配置
if (!coverImage) return 'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=400&q=80'
if (coverImage.startsWith('http')) return coverImage
return `https://your-domain.com${coverImage}`
}
// 获取推荐课程(按最火排序,返回5条)
// 获取推荐课程
const fetchRecommendCourses = async () => {
try {
const res = await getGroupCoursePage({
page: 0,
size: 5,
sort: 'current_members', // 按参与人数排序
order: 'desc' // 降序,即最火的在前
page: 0, size: 5, sort: 'current_members', order: 'desc'
}, { cache: true, cacheTime: 5 * 60 * 1000 })
if (res && res.content && Array.isArray(res.content)) {
// 将后端数据转换为组件所需格式
courses.value = res.content.map(course => ({
id: course.id,
image: getImageUrl(course.coverImage),
tag: getTag(course),
tagType: getTagType(course),
name: course.courseName || '未知课程',
id: course.id, image: getImageUrl(course.coverImage), tag: getTag(course),
tagType: getTagType(course), name: course.courseName || '未知课程',
duration: calculateDuration(course.startTime, course.endTime),
level: getCourseLevel(course),
participants: course.currentMembers || 0,
// 保存原始数据供点击事件使用
rawData: course
level: getCourseLevel(course), participants: course.currentMembers || 0, rawData: course
}))
} else {
// 如果没有数据,使用提供的示例数据作为fallback
useFallbackData()
}
} catch (err) {
// console.error('获取推荐课程失败:', err)
// 使用提供的示例数据作为fallback
useFallbackData()
}
} else { useFallbackData() }
} catch (err) { useFallbackData() }
}
// 使用提供的响应数据作为默认数据
const useFallbackData = () => {
const fallbackContent = [
{
id: "3",
courseName: "燃脂搏击",
courseType: "2",
startTime: "2026-06-10T18:30:00",
endTime: "2026-06-10T19:30:00",
maxMembers: 20,
currentMembers: 20,
status: "0",
coverImage: "/images/kickboxing.jpg",
description: "高强度间歇训练,配合音乐快速燃脂,释放压力。名额已满,无法预约。"
},
{
id: "2",
courseName: "清晨流瑜伽",
courseType: "1",
startTime: "2026-06-12T09:00:00",
endTime: "2026-06-12T10:30:00",
maxMembers: 15,
currentMembers: 5,
status: "0",
coverImage: "/images/yoga_flow.jpg",
description: "适合有一定基础的学员,通过流畅的体式连接呼吸,唤醒身体能量。"
},
{
id: "4",
courseName: "哈他瑜伽",
courseType: "1",
startTime: "2026-06-01T15:20:00",
endTime: "2026-06-01T16:50:00",
maxMembers: 12,
currentMembers: 3,
status: "0",
coverImage: "/images/hatha_yoga.jpg",
description: "基础哈他瑜伽,适合所有级别。距开始不足30分钟,已停止预约。"
},
{
id: "6",
courseName: "蜜桃臀塑造",
courseType: "3",
startTime: "2026-05-30T19:00:00",
endTime: "2026-05-30T20:00:00",
maxMembers: 10,
currentMembers: 8,
status: "2",
coverImage: "/images/glute.jpg",
description: "针对性训练臀部肌肉群,课程已于5月30日结束,无法预约。"
},
{
id: "7",
courseName: "午间冥想放松",
courseType: "1",
startTime: "2026-05-31T12:00:00",
endTime: "2026-05-31T13:00:00",
maxMembers: 15,
currentMembers: 6,
status: "2",
coverImage: "/images/meditation_noon.jpg",
description: "午间冥想课程,已于5月31日结束。"
}
{ id: "3", courseName: "燃脂搏击", courseType: "2", startTime: "2026-06-10T18:30:00", endTime: "2026-06-10T19:30:00", maxMembers: 20, currentMembers: 20, status: "0", coverImage: "/images/kickboxing.jpg", description: "高强度间歇训练" },
{ id: "2", courseName: "清晨流瑜伽", courseType: "1", startTime: "2026-06-12T09:00:00", endTime: "2026-06-12T10:30:00", maxMembers: 15, currentMembers: 5, status: "0", coverImage: "/images/yoga_flow.jpg", description: "流畅体式" },
{ id: "4", courseName: "哈他瑜伽", courseType: "1", startTime: "2026-06-01T15:20:00", endTime: "2026-06-01T16:50:00", maxMembers: 12, currentMembers: 3, status: "0", coverImage: "/images/hatha_yoga.jpg", description: "基础瑜伽" },
{ id: "6", courseName: "蜜桃臀塑造", courseType: "3", startTime: "2026-05-30T19:00:00", endTime: "2026-05-30T20:00:00", maxMembers: 10, currentMembers: 8, status: "2", coverImage: "/images/glute.jpg", description: "臀部训练" },
{ id: "7", courseName: "午间冥想放松", courseType: "1", startTime: "2026-05-31T12:00:00", endTime: "2026-05-31T13:00:00", maxMembers: 15, currentMembers: 6, status: "2", coverImage: "/images/meditation_noon.jpg", description: "冥想" }
]
courses.value = fallbackContent.map(course => ({
id: course.id,
image: getImageUrl(course.coverImage),
tag: getTag(course),
tagType: getTagType(course),
name: course.courseName || '未知课程',
id: course.id, image: getImageUrl(course.coverImage), tag: getTag(course),
tagType: getTagType(course), name: course.courseName || '未知课程',
duration: calculateDuration(course.startTime, course.endTime),
level: getCourseLevel(course),
participants: course.currentMembers || 0,
rawData: course
level: getCourseLevel(course), participants: course.currentMembers || 0, rawData: course
}))
}
// 处理参与课程点击
const handleJoinCourse = (course) => {
// 根据课程状态判断是否可以参与
if (course.rawData.status === '2') {
uni.showToast({
title: '课程已结束',
icon: 'none'
})
return
}
if (course.rawData.currentMembers >= course.rawData.maxMembers) {
uni.showToast({
title: '课程已满员',
icon: 'none'
})
return
}
// 跳转到课程详情页
uni.navigateTo({
url: `/pages/course/detail?id=${course.id}`
})
if (course.rawData.status === '2') { uni.showToast({ title: '课程已结束', icon: 'none' }); return }
if (course.rawData.currentMembers >= course.rawData.maxMembers) { uni.showToast({ title: '课程已满员', icon: 'none' }); return }
uni.navigateTo({ url: `/pages/course/detail?id=${course.id}` })
}
// 组件挂载时获取数据
onMounted(() => {
fetchRecommendCourses()
})
onMounted(() => { fetchRecommendCourses() })
</script>
<style lang="scss">
/* 推荐课程容器样式 */
.recommend-courses {
padding: 0 24rpx;
margin-bottom: 32rpx;
position: relative;
z-index: 1;
}
/* 区域标题栏样式 */
.section-header {
display: flex;
justify-content: space-between;
@@ -318,50 +189,46 @@ onMounted(() => {
margin-bottom: 24rpx;
}
/* 区域标题样式 */
.section-title {
font-size: 34rpx;
font-weight: 700;
color: #1a202c;
color: #2D4A5A;
}
/* 查看更多按钮样式 */
.view-more {
display: flex;
align-items: center;
gap: 4rpx;
font-size: 26rpx;
color: #94a3b8;
color: #8AABBB;
}
/* 箭头图标样式 */
.arrow {
font-size: 32rpx;
}
/* 课程横向滚动容器样式 */
.courses-scroll {
white-space: nowrap;
}
/* 课程列表样式 */
.courses-list {
display: inline-flex;
gap: 48rpx;
}
/* 课程卡片样式 */
.course-card {
width: 320rpx;
background: #ffffff;
background: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border-radius: 24rpx;
overflow: hidden;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
box-shadow: 0 8rpx 28rpx rgba(120, 185, 215, 0.18);
border: 1rpx solid rgba(255, 255, 255, 0.6);
display: inline-block;
vertical-align: top;
}
/* 课程图片区域样式 */
.course-image {
height: 280rpx;
position: relative;
@@ -371,7 +238,6 @@ onMounted(() => {
padding: 20rpx;
}
/* 课程封面图片样式 */
.img {
position: absolute;
left: 0;
@@ -380,17 +246,15 @@ onMounted(() => {
height: 100%;
}
/* 图片渐变遮罩样式 */
.course-overlay {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%);
background: linear-gradient(to top, rgba(45, 74, 90, 0.7) 0%, transparent 60%);
}
/* 课程标签样式 */
.course-tag {
position: absolute;
top: 16rpx;
@@ -400,47 +264,33 @@ onMounted(() => {
font-size: 20rpx;
font-weight: 600;
color: #ffffff;
background: #f97316;
background: linear-gradient(135deg, #7AB5CC, #9CCFDF);
z-index: 2;
/* 热门标签 */
&.hot {
background: #ef4444;
background: linear-gradient(135deg, #6BA8C0, #8CC5D5);
}
/* 新课标签 */
&.new {
background: #10b981;
background: linear-gradient(135deg, #6DB5C8, #90CEDD);
}
/* 免费标签 */
&.free {
background: #3b82f6;
background: linear-gradient(135deg, #7AB5CC, #9CCFDF);
}
/* 满员标签 */
&.full {
background: #64748b;
background: linear-gradient(135deg, #A0B8C8, #B8CCD8);
}
/* 已结束标签 */
&.ended {
background: #94a3b8;
background: linear-gradient(135deg, #B0C0CC, #C4D2DC);
}
/* 默认标签 */
&.default {
background: #f97316;
background: linear-gradient(135deg, #7AB5CC, #9CCFDF);
}
}
/* 课程信息区域样式 */
.course-info {
position: relative;
z-index: 2;
}
/* 课程名称样式 */
.course-name {
display: block;
font-size: 28rpx;
@@ -449,14 +299,12 @@ onMounted(() => {
margin-bottom: 8rpx;
}
/* 课程元信息容器样式 */
.course-meta {
display: flex;
gap: 16rpx;
align-items: center;
}
/* 课程元信息项样式 */
.meta-item {
display: flex;
align-items: end;
@@ -465,7 +313,6 @@ onMounted(() => {
color: rgba(255, 255, 255, 0.8);
}
/* 元信息图标样式 */
.meta-icon {
font-size: 20rpx;
image{
@@ -476,7 +323,6 @@ onMounted(() => {
}
}
/* 课程底部区域样式 */
.course-footer {
padding: 16rpx 10rpx;
display: flex;
@@ -484,16 +330,14 @@ onMounted(() => {
align-items: center;
}
/* 参与人数信息样式 */
.participants {
display: flex;
align-items: center;
gap: 6rpx;
font-size: 22rpx;
color: #94a3b8;
color: #8AABBB;
}
/* 火热图标样式 */
.fire-icon {
font-size: 24rpx;
image{
@@ -504,14 +348,14 @@ onMounted(() => {
}
}
/* 去参与按钮样式 */
.join-btn {
padding: 12rpx 28rpx;
background: transparent;
border: 2rpx solid #f97316;
background: linear-gradient(135deg, #7AB5CC 0%, #9CCFDF 100%);
border: none;
border-radius: 9999rpx;
font-size: 22rpx;
font-weight: 600;
color: #f97316;
color: #ffffff;
box-shadow: 0 6rpx 16rpx rgba(122, 181, 204, 0.35);
}
</style>
@@ -9,7 +9,7 @@
<view class="view-more">
<text>查看更多</text>
<text class="arrow">
<uni-icons type="right" size="20" color="#94a3b8"></uni-icons>
<uni-icons type="right" size="20" color="#8CA0B0"></uni-icons>
</text>
</view>
</view>
@@ -77,12 +77,12 @@ const recommends = [
</script>
<style lang="scss" scoped>
/* 今日推荐容器样式 */
.today-recommend {
padding: 0 24rpx;
position: relative;
z-index: 1;
}
/* 区域标题栏样式 */
.section-header {
display: flex;
justify-content: space-between;
@@ -90,45 +90,42 @@ const recommends = [
margin-bottom: 24rpx;
}
/* 区域标题样式 */
.section-title {
font-size: 34rpx;
font-weight: 700;
color: #1a202c;
color: #2D4A5A;
}
/* 查看更多按钮样式 */
.view-more {
display: flex;
align-items: center;
gap: 4rpx;
font-size: 26rpx;
color: #94a3b8;
color: #8AABBB;
}
/* 箭头图标样式 */
.arrow {
font-size: 32rpx;
}
/* 推荐列表样式 */
.recommend-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
/* 推荐项卡片样式 */
.recommend-item {
display: flex;
gap: 24rpx;
background: #ffffff;
background: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border-radius: 24rpx;
padding: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
box-shadow: 0 8rpx 28rpx rgba(120, 185, 215, 0.18);
border: 1rpx solid rgba(255, 255, 255, 0.6);
}
/* 推荐项图片样式 */
.item-image {
width: 200rpx;
height: 160rpx;
@@ -136,7 +133,6 @@ const recommends = [
flex-shrink: 0;
}
/* 推荐项内容区域样式 */
.item-content {
flex: 1;
display: flex;
@@ -145,40 +141,35 @@ const recommends = [
min-width: 0;
}
/* 推荐项标题样式 */
.item-title {
font-size: 30rpx;
font-weight: 600;
color: #1a202c;
color: #2D4A5A;
margin-bottom: 12rpx;
}
/* 推荐项标签列表样式 */
.item-tags {
display: flex;
gap: 12rpx;
margin-bottom: 12rpx;
}
/* 推荐项标签样式 */
.tag {
padding: 6rpx 16rpx;
background: #f1f5f9;
background: rgba(122, 181, 204, 0.12);
border-radius: 8rpx;
font-size: 22rpx;
color: #64748b;
color: #6BA8C0;
}
/* 推荐项描述文字样式 */
.item-desc {
font-size: 24rpx;
color: #94a3b8;
color: #8AABBB;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 推荐项操作区域样式 */
.item-action {
display: flex;
flex-direction: column;
@@ -188,15 +179,13 @@ const recommends = [
flex-shrink: 0;
}
/* 开始训练按钮样式 */
.start-btn {
padding: 16rpx 28rpx;
background: linear-gradient(135deg, #f97316 0%, #fb923c 100%);
background: linear-gradient(135deg, #7AB5CC 0%, #9CCFDF 100%);
border-radius: 9999rpx;
box-shadow: 0 4rpx 16rpx rgba(249, 115, 22, 0.4);
box-shadow: 0 6rpx 20rpx rgba(122, 181, 204, 0.4);
}
/* 开始训练按钮文字样式 */
.start-btn-text {
font-size: 24rpx;
font-weight: 600;
@@ -204,10 +193,9 @@ const recommends = [
white-space: nowrap;
}
/* 参与人数文字样式 */
.participants {
font-size: 22rpx;
color: #94a3b8;
color: #8AABBB;
white-space: nowrap;
}
</style>
</style>
@@ -13,7 +13,7 @@
<text class="body-report-section__history-link">历史记录</text>
<image
class="body-report-section__link-arrow"
src="/static/images/chevronright3.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright3.png"
mode="aspectFit"
/>
</view>
@@ -34,7 +34,7 @@
>
<image
class="body-report-section__view-icon"
src="/static/images/filetext.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/filetext.png"
mode="aspectFit"
/>
<text class="body-report-section__view-report">查看报告</text>
@@ -77,7 +77,7 @@
<view class="body-report-section__goal">
<image
class="body-report-section__goal-icon"
src="/static/images/target.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/target.png"
mode="aspectFit"
/>
<text class="body-report-section__goal-text">
@@ -87,7 +87,7 @@
<view class="body-report-section__change">
<image
class="body-report-section__change-icon"
src="/static/images/trendingdown.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/trendingdown.png"
mode="aspectFit"
/>
<text class="body-report-section__metric-value-2">
@@ -13,7 +13,7 @@
<text class="booking-section__view-all">预约记录</text>
<image
class="booking-section__link-arrow"
src="/static/images/chevronright4.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright4.png"
mode="aspectFit"
/>
</view>
@@ -41,13 +41,13 @@
<view class="booking-section__meta-inner">
<image
class="booking-section__icon-coach"
src="/static/images/user2.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user2.png"
mode="aspectFit"
/>
<text class="booking-section__coach">教练{{ item.coach }}</text>
<image
class="booking-section__icon-location"
src="/static/images/mappin1.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/mappin1.png"
mode="aspectFit"
/>
<text class="booking-section__text">{{ item.location }}</text>
@@ -13,7 +13,7 @@
<text class="checkin-section__view-all">查看全部</text>
<image
class="checkin-section__link-arrow"
src="/static/images/chevronright2.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright2.png"
mode="aspectFit"
/>
</view>
@@ -13,7 +13,7 @@
<text class="coupon-section__view-all">更多详情</text>
<image
class="coupon-section__link-arrow"
src="/static/images/chevronright5.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright5.png"
mode="aspectFit"
/>
</view>
@@ -6,12 +6,12 @@
<view class="profile-header__nav-left">
<image
class="profile-header__icon-bell"
src="/static/images/bell.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/bell.png"
mode="aspectFit"
/>
<image
class="profile-header__icon-settings"
src="/static/images/settings.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/settings.png"
mode="aspectFit"
/>
</view>
@@ -37,7 +37,7 @@
<view class="profile-header__avatar-badge">
<image
class="profile-header__avatar-badge-icon"
src="/static/images/camera.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/camera.png"
mode="aspectFit"
/>
</view>
@@ -49,7 +49,7 @@
<view class="profile-header__badge">
<image
class="profile-header__badge-icon"
src="/static/images/crown0.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/crown0.png"
mode="aspectFit"
/>
<text class="profile-header__level">{{ userInfo.memberLevel }}</text>
@@ -100,7 +100,7 @@ export default {
emits: ['user-info'],
computed: {
displayAvatar() {
return this.userInfo.avatar || '/static/images/AvatarEditWrap.png'
return this.userInfo.avatar || 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AvatarEditWrap.png'
}
},
data() {
@@ -8,7 +8,7 @@
>
<image
class="logout-section__icon"
src="/static/images/logout.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/logout.png"
mode="aspectFit"
/>
<text class="logout-section__text">退出登录</text>
@@ -17,7 +17,7 @@
>
查看全部
</text>
<image class="member-card-section__link-arrow" src="/static/images/chevronright12.png" mode="aspectFit" />
<image class="member-card-section__link-arrow" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright12.png" mode="aspectFit" />
</view>
</view>
</view>
@@ -46,7 +46,7 @@
class="member-card-preview__icon-stroke"
></view>
</view>
<image class="member-card-preview__icon-line" src="/static/images/Line_2_468.png" mode="aspectFill" />
<image class="member-card-preview__icon-line" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/Line_2_468.png" mode="aspectFill" />
</view>
<text
class="member-card-preview__name"
@@ -101,7 +101,7 @@
<view class="member-card-tip">
<view class="member-card-tip__inner">
<view class="member-card-tip__content">
<image class="member-card-tip__icon" src="/static/images/clock1.png" mode="aspectFit" />
<image class="member-card-tip__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/clock1.png" mode="aspectFit" />
<text
class="member-card-tip__text"
>
@@ -17,12 +17,12 @@
<view v-if="item.key === 'booking'" class="quick-actions__icon">
<image
class="quick-actions__icon-part"
src="/static/images/Vector_2_490.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/Vector_2_490.png"
mode="aspectFit"
/>
<image
class="quick-actions__icon-part"
src="/static/images/Vector_2_491.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/Vector_2_491.png"
mode="aspectFit"
/>
<view class="quick-actions__border-wrap">
@@ -31,12 +31,12 @@
</view>
<image
class="quick-actions__icon-part"
src="/static/images/Vector_2_493.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/Vector_2_493.png"
mode="aspectFit"
/>
<image
class="quick-actions__icon-part"
src="/static/images/Vector_2_494.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/Vector_2_494.png"
mode="aspectFit"
/>
</view>
@@ -94,15 +94,15 @@ export default {
return {
row1: [
{ key: 'booking', label: '预约课程', textClass: 'quick-actions__title', icon: '' },
{ key: 'bodyTest', label: '智能体测', textClass: 'quick-actions__title-2', icon: '/static/images/mappin2.png' },
{ key: 'bodyReport', label: '体测报告', textClass: 'quick-actions__title-3', icon: '/static/images/activity.png' },
{ key: 'trainReport', label: '训练报告', textClass: 'quick-actions__coach', icon: '/static/images/usercheck.png' }
{ key: 'bodyTest', label: '智能体测', textClass: 'quick-actions__title-2', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/mappin2.png' },
{ key: 'bodyReport', label: '体测报告', textClass: 'quick-actions__title-3', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/activity.png' },
{ key: 'trainReport', label: '训练报告', textClass: 'quick-actions__coach', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/usercheck.png' }
],
row2: [
{ key: 'coupon', label: '我的优惠券', textClass: 'quick-actions__text', icon: '/static/images/ticket.png' },
{ key: 'points', label: '我的积分', textClass: 'quick-actions__points-desc', icon: '/static/images/star.png' },
{ key: 'referral', label: '邀请好友', textClass: 'quick-actions__title-4', icon: '/static/images/share2.png' },
{ key: 'course', label: '我的课程', textClass: 'quick-actions__text-2', icon: '/static/images/play.png' }
{ key: 'coupon', label: '我的优惠券', textClass: 'quick-actions__text', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/ticket.png' },
{ key: 'points', label: '我的积分', textClass: 'quick-actions__points-desc', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/star.png' },
{ key: 'referral', label: '邀请好友', textClass: 'quick-actions__title-4', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/share2.png' },
{ key: 'course', label: '我的课程', textClass: 'quick-actions__text-2', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/play.png' }
]
}
}
@@ -12,7 +12,7 @@
<text class="referral-section__records-link">规则说明</text>
<image
class="referral-section__link-arrow"
src="/static/images/chevronright11.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright11.png"
mode="aspectFit"
/>
</view>
@@ -43,7 +43,7 @@
</text>
<image
class="settings-section__item-arrow"
src="/static/images/chevronright10.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright10.png"
mode="aspectFit"
/>
</view>
@@ -68,32 +68,32 @@ export default {
{
key: 'notify',
label: '通知设置',
icon: '/static/images/bell.png',
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/bell.png',
iconWrapClass: ''
},
{
key: 'password',
label: '修改密码',
icon: '/static/images/Vector_2_727.png',
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/Vector_2_727.png',
iconWrapClass: 'settings-section__item-icon-wrap--blue'
},
{
key: 'privacy',
label: '隐私政策',
icon: '/static/images/shield.png',
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/shield.png',
iconWrapClass: 'settings-section__item-icon-wrap--green'
},
{
key: 'nfc',
label: 'NFC 门禁卡',
subtitle: '已绑定',
icon: '/static/images/ticket.png',
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/ticket.png',
iconWrapClass: ''
},
{
key: 'delete',
label: '注销账户',
icon: '/static/images/userx.png',
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/userx.png',
iconWrapClass: 'settings-section__item-icon-wrap--red',
labelClass: 'settings-section__item-label--danger'
}
@@ -5,7 +5,7 @@
<view class="sub-nav__back" @tap.stop="$emit('back')">
<image
class="sub-nav__back-icon"
src="/static/images/chevronleft.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronleft.png"
mode="aspectFit"
/>
</view>
+1
View File
@@ -3,6 +3,7 @@
{
"path": "pages/index/index",
"style": {
"navigationStyle":"custom",
"navigationBarTitleText": "健身房",
"app-plus": {
"animationType": "fade-in",
+180 -27
View File
@@ -1,28 +1,43 @@
<template>
<view class="home-page">
<!-- 骨架屏 -->
<HomeSkeleton v-if="loading" />
<!-- 水波纹背景 - 顶层显示 -->
<view class="bg-wrapper">
<image src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/wave_top.png" mode="widthFix" class="wave-bg wave-top" />
<image src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/wave_bottom.png" mode="widthFix" class="wave-bg wave-bottom" />
</view>
<!-- 固定白色块滚动时显示 -->
<view class="hand" :style="{height : handHeight + 'rpx'}" v-show="isShow"></view>
<!-- 滚动内容区域 -->
<scroll-view
scroll-y
refresher-enabled
:refresher-triggered="isRefreshing"
refresher-default-style="none"
@refresherrefresh="onRefresh"
@scroll="handleScroll"
class="scroll-container"
>
<!-- 实际内容 -->
<template v-else>
<!-- Banner轮播 -->
<BannerSwiper />
<!-- 功能入口 -->
<QuickEntry />
<!-- 推荐课程 -->
<RecommendCourses />
<!-- 今日推荐 -->
<TodayRecommend />
<!-- 底部占位 -->
<view class="bottom-placeholder"></view>
<!-- TabBar -->
<TabBar />
</template>
<!-- 内容 -->
<view class="home-page">
<!-- 骨架屏 -->
<HomeSkeleton v-if="loading" />
<!-- 实际内容 -->
<template v-else>
<BannerSwiper />
<QuickEntry />
<RecommendCourses />
<TodayRecommend />
<!-- 底部占位 TabBar 留出空间 -->
<view class="bottom-placeholder"></view>
</template>
</view>
</scroll-view>
<!-- TabBar 固定在底部不参与滚动 -->
<view class="tabbar-fixed">
<TabBar />
</view>
</template>
@@ -36,23 +51,161 @@ import TabBar from '@/components/TabBar.vue'
import HomeSkeleton from '@/components/Skeleton/HomeSkeleton.vue'
const loading = ref(true)
const isShow = ref(false)
const handHeight = ref(0)
const scrollDistance = ref(0)
const isRefreshing = ref(false)
// 滚动监听
const handleScroll = (e) => {
const distance = e.detail.scrollTop
scrollDistance.value = distance
// 控制白色块显示/隐藏
isShow.value = distance > 238
}
// 下拉刷新处理
const onRefresh = async () => {
console.log('开始下拉刷新')
isRefreshing.value = true
try {
await refreshData()
isRefreshing.value = false
uni.showToast({
title: '刷新成功',
icon: 'success'
})
} catch (error) {
console.error('刷新失败', error)
isRefreshing.value = false
uni.showToast({
title: '刷新失败',
icon: 'error'
})
}
}
// 刷新数据
const refreshData = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('数据已刷新')
resolve()
}, 1500)
})
}
onMounted(() => {
setTimeout(() => {
loading.value = false
}, 1500)
// 获取胶囊按钮高度
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
const navTotalHeight = menuButtonInfo.top + menuButtonInfo.height
handHeight.value = navTotalHeight * 2
})
</script>
<style lang="scss" scoped>
/* 背景包装器 - 固定在最底层 */
.bg-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
pointer-events: none;
}
.wave-bg {
position: fixed;
left: 0;
width: 100%;
pointer-events: none;
opacity: 0.6;
}
.wave-top {
top: 0;
opacity: 0.5;
}
.wave-bottom {
bottom: 100rpx;
opacity: 0.35;
}
/* 滚动容器 */
.scroll-container {
position: relative;
z-index: 1;
height: 100vh;
width: 100%;
background: linear-gradient(180deg, #D6EEF8 0%, #E4F2FA 15%, #EEF6FB 30%, #F5FAFD 50%, #FAFCFE 70%, #FFFFFF 100%);
}
/* 主内容区域 */
.home-page {
min-height: 100vh;
background-color: #f0f4f8;
padding-bottom: 160rpx;
padding-bottom: 160rpx; /* 为 TabBar 留出空间 */
}
/* 固定白色块 */
.hand {
position: fixed;
top: 0;
left: 0;
z-index: 100;
background-color: white;
width: 100%;
}
/* 固定 TabBar */
.tabbar-fixed {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 20;
background-color: transparent;
}
.bottom-placeholder {
height: 40rpx;
height: 120rpx; /* 调整高度,避免内容被 TabBar 遮挡 */
}
</style>
/* 其他样式保持不变 */
.glow {
position: absolute;
border-radius: 50%;
pointer-events: none;
z-index: 0;
}
.glow-1 {
width: 400rpx;
height: 400rpx;
top: 60rpx;
right: -100rpx;
background: radial-gradient(circle, rgba(160, 210, 235, 0.35) 0%, transparent 70%);
}
.glow-2 {
width: 300rpx;
height: 300rpx;
top: 500rpx;
left: -80rpx;
background: radial-gradient(circle, rgba(180, 220, 240, 0.3) 0%, transparent 70%);
}
.glow-3 {
width: 250rpx;
height: 250rpx;
top: 900rpx;
right: -60rpx;
background: radial-gradient(circle, rgba(170, 215, 238, 0.25) 0%, transparent 70%);
}
</style>
@@ -35,7 +35,7 @@
<view v-if="connected" class="bt-card">
<view class="bt-device">
<view class="bt-device__icon-wrap">
<image class="bt-device__icon" src="/static/images/shield.png" mode="aspectFit" />
<image class="bt-device__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/shield.png" mode="aspectFit" />
</view>
<view class="bt-device__info">
<text class="bt-device__name">连接成功</text>
@@ -34,7 +34,7 @@
:hover-stay-time="150"
@tap="startMeasure"
>
<image class="bt-btn__icon" src="/static/images/activity.png" mode="aspectFit" />
<image class="bt-btn__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/activity.png" mode="aspectFit" />
<text class="bt-btn__text">开始体测</text>
</view>
<view
@@ -53,7 +53,7 @@
<text class="bt-card__title">设备状态</text>
<view class="bt-device">
<view class="bt-device__icon-wrap">
<image class="bt-device__icon" src="/static/images/mappin2.png" mode="aspectFit" />
<image class="bt-device__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/mappin2.png" mode="aspectFit" />
</view>
<view class="bt-device__info">
<text class="bt-device__name">{{ device.name }}</text>
@@ -121,10 +121,10 @@ export default {
latest: null,
device: {},
quickLinks: [
{ key: 'history', label: '历史记录', icon: '/static/images/clock.png' },
{ key: 'compare', label: '历史对比', icon: '/static/images/trendingdown.png' },
{ key: 'trend', label: '趋势分析', icon: '/static/images/activity.png' },
{ key: 'report', label: '体测报告', icon: '/static/images/filetext.png' }
{ key: 'history', label: '历史记录', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/clock.png' },
{ key: 'compare', label: '历史对比', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/trendingdown.png' },
{ key: 'trend', label: '趋势分析', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/activity.png' },
{ key: 'report', label: '体测报告', icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/filetext.png' }
]
}
},
@@ -94,7 +94,7 @@
<text class="bt-trend-link__text">查看完整趋势分析</text>
<image
class="bt-trend-link__arrow"
src="/static/images/chevronright3.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright3.png"
mode="aspectFit"
/>
</view>
@@ -140,7 +140,7 @@
:hover-stay-time="150"
@tap="exportReport"
>
<image class="bt-btn__icon" src="/static/images/filetext.png" mode="aspectFit" />
<image class="bt-btn__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/filetext.png" mode="aspectFit" />
<text class="bt-btn__text">导出 PDF</text>
</view>
<view
@@ -149,7 +149,7 @@
:hover-stay-time="150"
@tap="shareReport"
>
<image class="bt-btn__icon" src="/static/images/share2.png" mode="aspectFit" />
<image class="bt-btn__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/share2.png" mode="aspectFit" />
<text class="bt-btn__text">分享</text>
</view>
<view
@@ -76,7 +76,7 @@
<text class="bt-card__title">设备管理</text>
<view class="bt-device">
<view class="bt-device__icon-wrap">
<image class="bt-device__icon" src="/static/images/mappin2.png" mode="aspectFit" />
<image class="bt-device__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/mappin2.png" mode="aspectFit" />
</view>
<view class="bt-device__info">
<text class="bt-device__name">{{ device.name }}</text>
@@ -44,7 +44,7 @@
>
<image
class="booking-page__alert-icon"
src="/static/images/clock1.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/clock1.png"
mode="aspectFit"
/>
<text class="booking-page__alert-text">{{ upcomingAlert }}</text>
@@ -82,7 +82,7 @@
<view class="bk-card__meta-row">
<image
class="bk-card__meta-icon"
src="/static/images/clock0.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/clock0.png"
mode="aspectFit"
/>
<text class="bk-card__meta-text">{{ item.schedule }}</text>
@@ -90,7 +90,7 @@
<view class="bk-card__meta-row">
<image
class="bk-card__meta-icon"
src="/static/images/user0.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/user0.png"
mode="aspectFit"
/>
<text class="bk-card__meta-text">{{ item.coach }}</text>
@@ -27,7 +27,7 @@
@tap="showDetail(item)"
>
<view class="mi-mod-checkin-row__icon" :class="'mi-mod-checkin-row__icon--' + item.tagTheme">
<image class="mi-mod-checkin-row__icon-img" src="/static/images/usercheck.png" mode="aspectFit" />
<image class="mi-mod-checkin-row__icon-img" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/usercheck.png" mode="aspectFit" />
</view>
<view class="mi-mod-checkin-row__info">
<text class="mi-mod-checkin-row__title">{{ item.title }}</text>
@@ -39,13 +39,13 @@
<picker :range="coaches" @change="onCoachChange">
<view class="mi-course-list__picker">
<text>{{ coach }}</text>
<image class="mi-course-list__arrow" src="/static/images/chevronright3.png" mode="aspectFit" />
<image class="mi-course-list__arrow" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright3.png" mode="aspectFit" />
</view>
</picker>
<picker :range="periodLabels" @change="onPeriodChange">
<view class="mi-course-list__picker">
<text>{{ periodLabel }}</text>
<image class="mi-course-list__arrow" src="/static/images/chevronright3.png" mode="aspectFit" />
<image class="mi-course-list__arrow" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright3.png" mode="aspectFit" />
</view>
</picker>
</view>
@@ -103,7 +103,7 @@
hover-class="mi-tap-btn--hover"
@tap="goMyBooking"
>
<image class="mi-course-list__fab-icon" src="/static/images/clock.png" mode="aspectFit" />
<image class="mi-course-list__fab-icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/clock.png" mode="aspectFit" />
<text class="mi-course-list__fab-text">我的预约</text>
</view>
</view>
@@ -8,7 +8,7 @@
<view class="mc-hero__title-row">
<image
class="mc-hero__crown"
src="/static/images/crown.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/crown.png"
mode="aspectFit"
/>
<text class="mc-hero__name">{{ card.name }}</text>
@@ -31,7 +31,7 @@
>
<image
class="mc-hero__renew-icon"
src="/static/images/refreshcw.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/refreshcw.png"
mode="aspectFit"
/>
<text class="mc-hero__renew-text">立即续费</text>
@@ -16,7 +16,7 @@
<view class="bt-card">
<text class="bt-card__title">视频播放</text>
<view class="mi-online-player">
<image class="mi-online-player__play" src="/static/images/play.png" mode="aspectFit" />
<image class="mi-online-player__play" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/play.png" mode="aspectFit" />
<text class="mi-online-player__hint">点击播放支持倍速与拖拽</text>
</view>
<view class="mi-online-controls">
@@ -13,19 +13,19 @@
<text class="bt-card__title">快捷入口</text>
<view class="bt-grid">
<view class="bt-grid__item" hover-class="mi-tap--hover" @tap="goMall">
<image class="bt-grid__icon" src="/static/images/star.png" mode="aspectFit" />
<image class="bt-grid__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/star.png" mode="aspectFit" />
<text class="bt-grid__label">积分商城</text>
</view>
<view class="bt-grid__item" hover-class="mi-tap--hover" @tap="goHistory">
<image class="bt-grid__icon" src="/static/images/clock.png" mode="aspectFit" />
<image class="bt-grid__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/clock.png" mode="aspectFit" />
<text class="bt-grid__label">积分明细</text>
</view>
<view class="bt-grid__item" hover-class="mi-tap--hover" @tap="checkIn">
<image class="bt-grid__icon" src="/static/images/usercheck.png" mode="aspectFit" />
<image class="bt-grid__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/usercheck.png" mode="aspectFit" />
<text class="bt-grid__label">签到赚积分</text>
</view>
<view class="bt-grid__item" hover-class="mi-tap--hover" @tap="goReferral">
<image class="bt-grid__icon" src="/static/images/share2.png" mode="aspectFit" />
<image class="bt-grid__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/share2.png" mode="aspectFit" />
<text class="bt-grid__label">邀请赚积分</text>
</view>
</view>
@@ -25,7 +25,7 @@
:hover-stay-time="150"
@tap="shareInvite"
>
<image class="bt-btn__icon" src="/static/images/share2.png" mode="aspectFit" />
<image class="bt-btn__icon" src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/share2.png" mode="aspectFit" />
<text class="bt-btn__text">分享给好友</text>
</view>
</view>
@@ -21,7 +21,7 @@
>
<image
class="avatar-block__icon"
src="/static/images/camera.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/camera.png"
mode="aspectFit"
/>
<text class="avatar-block__text">更换</text>
@@ -41,7 +41,7 @@
<text class="Pixso-paragraph-2_813">{{ name }}</text>
<image
class="Pixso-vector-2_814"
src="/static/images/chevronright1.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright1.png"
mode="aspectFit"
/>
</view>
@@ -70,7 +70,7 @@
</view>
<image
class="Pixso-vector-2_823"
src="/static/images/chevronright.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright.png"
mode="aspectFit"
/>
</view>
@@ -90,7 +90,7 @@
>
<image
class="gender-btn__icon"
src="/static/images/venus.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/venus.png"
mode="aspectFit"
/>
<text class="gender-btn__text"></text>
@@ -104,7 +104,7 @@
>
<image
class="gender-btn__icon"
src="/static/images/mars.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/mars.png"
mode="aspectFit"
/>
<text class="gender-btn__text"></text>
@@ -125,7 +125,7 @@
<text class="Pixso-paragraph-2_844">{{ birthday }}</text>
<image
class="Pixso-vector-2_845"
src="/static/images/chevronright0.png"
src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/chevronright0.png"
mode="aspectFit"
/>
</view>
@@ -228,7 +228,7 @@ import {
showValidationError
} from '@/common/memberInfo/validate.js'
const DEFAULT_AVATAR = '/static/images/AvatarEditWrap.png'
const DEFAULT_AVATAR = 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/AvatarEditWrap.png'
export default {
components: { MemberInfoSubNav },
Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 764 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 561 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Some files were not shown because too many files have changed in this diff Show More