会员个人中心页面初步完成
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<view class="scroll-container theme-light">
|
||||
<view class="bt-page mi-course-list">
|
||||
<MemberInfoSubNav title="预约课程" @back="goBack" />
|
||||
<view class="mi-course-list__filters">
|
||||
<view class="mi-course-list__date-bar">
|
||||
<view
|
||||
class="mi-course-list__mode"
|
||||
hover-class="mi-tap--hover"
|
||||
@tap="toggleDateMode"
|
||||
>
|
||||
<text class="mi-course-list__mode-text">{{ dateMode === 'day' ? '按天' : '按周' }}</text>
|
||||
</view>
|
||||
<scroll-view scroll-x class="mi-course-list__dates">
|
||||
<view
|
||||
v-for="d in dateOptions"
|
||||
:key="d.value"
|
||||
class="mi-course-list__date"
|
||||
:class="{ 'mi-course-list__date--active': selectedDate === d.value }"
|
||||
@tap="selectedDate = d.value"
|
||||
>
|
||||
<text class="mi-course-list__date-week">{{ d.week }}</text>
|
||||
<text class="mi-course-list__date-day">{{ d.day }}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<scroll-view scroll-x class="mi-course-list__chips">
|
||||
<view
|
||||
v-for="t in typeOptions"
|
||||
:key="t.key"
|
||||
class="bt-tab"
|
||||
:class="{ 'bt-tab--active': courseType === t.key }"
|
||||
@tap="courseType = t.key"
|
||||
>
|
||||
<text class="bt-tab__text">{{ t.label }}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="mi-course-list__row">
|
||||
<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" />
|
||||
</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" />
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bt-page__body">
|
||||
<view
|
||||
v-for="course in displayCourses"
|
||||
:key="course.id"
|
||||
class="mi-course-card"
|
||||
hover-class="mi-tap-card--hover"
|
||||
@tap="openDetail(course)"
|
||||
>
|
||||
<image class="mi-course-card__banner" :src="course.banner" mode="aspectFill" />
|
||||
<view class="mi-course-card__body">
|
||||
<view class="mi-course-card__head">
|
||||
<text class="mi-course-card__title">{{ course.title }}</text>
|
||||
<view class="mi-course-card__type" :class="'mi-course-card__type--' + course.type">
|
||||
<text>{{ course.type === 'group' ? '团课' : '私教' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mi-course-card__coach">
|
||||
<image class="mi-course-card__avatar" :src="course.coachAvatar" mode="aspectFill" />
|
||||
<text>{{ course.coach }}</text>
|
||||
</view>
|
||||
<text class="mi-course-card__meta">
|
||||
{{ course.startTime }}-{{ course.endTime }} · {{ course.location }}
|
||||
</text>
|
||||
<view class="mi-course-card__capacity">
|
||||
<view class="mi-course-card__bar">
|
||||
<view class="mi-course-card__bar-fill" :style="{ width: course.percent + '%' }"></view>
|
||||
</view>
|
||||
<text class="mi-course-card__cap-text">{{ course.enrolled }}/{{ course.capacity }}</text>
|
||||
<text v-if="course.scarcityLabel" class="mi-course-card__scarcity">{{ course.scarcityLabel }}</text>
|
||||
</view>
|
||||
<view class="mi-course-card__footer">
|
||||
<text class="mi-course-card__price">{{ course.price }}</text>
|
||||
<view
|
||||
class="mi-course-card__btn"
|
||||
:class="{ 'mi-course-card__btn--disabled': course.full }"
|
||||
@tap.stop="quickBook(course)"
|
||||
>
|
||||
<text>{{ course.full ? '已约满' : '预约' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!displayCourses.length" class="bt-empty">
|
||||
<text class="bt-empty__text">暂无符合条件的课程</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="mi-course-list__fab"
|
||||
hover-class="mi-tap-btn--hover"
|
||||
@tap="goMyBooking"
|
||||
>
|
||||
<image class="mi-course-list__fab-icon" src="/static/images/clock.png" mode="aspectFit" />
|
||||
<text class="mi-course-list__fab-text">我的预约</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MemberInfoSubNav from '@/components/memberInfo/MemberInfoSubNav.vue'
|
||||
import { PAGE, navigateToPage } from '@/common/constants/routes.js'
|
||||
import { loadMemberStore, persistMemberStore } from '@/common/memberInfo/store.js'
|
||||
import {
|
||||
courseCatalogMock,
|
||||
filterCourses,
|
||||
enrichCourseForDisplay,
|
||||
getWeekDates,
|
||||
bookCourse
|
||||
} from '@/common/memberInfo/bookingStore.js'
|
||||
import { subPageMixin } from '@/common/memberInfo/mixins.js'
|
||||
|
||||
const WEEK = ['日', '一', '二', '三', '四', '五', '六']
|
||||
|
||||
export default {
|
||||
components: { MemberInfoSubNav },
|
||||
mixins: [subPageMixin],
|
||||
data() {
|
||||
return {
|
||||
dateMode: 'day',
|
||||
selectedDate: '2024-07-15',
|
||||
courseType: 'all',
|
||||
coach: '全部',
|
||||
period: 'all',
|
||||
coaches: courseCatalogMock.coaches,
|
||||
typeOptions: courseCatalogMock.typeOptions,
|
||||
periodOptions: courseCatalogMock.periodOptions,
|
||||
courses: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
periodLabels() {
|
||||
return this.periodOptions.map((p) => p.label)
|
||||
},
|
||||
periodLabel() {
|
||||
return this.periodOptions.find((p) => p.key === this.period)?.label || '全部时段'
|
||||
},
|
||||
weekDates() {
|
||||
return getWeekDates(this.selectedDate)
|
||||
},
|
||||
dateOptions() {
|
||||
const dates = this.dateMode === 'week' ? this.weekDates : this.weekDates
|
||||
return dates.map((value) => {
|
||||
const d = new Date(value.replace(/-/g, '/'))
|
||||
return {
|
||||
value,
|
||||
week: WEEK[d.getDay()],
|
||||
day: `${d.getMonth() + 1}/${d.getDate()}`
|
||||
}
|
||||
})
|
||||
},
|
||||
displayCourses() {
|
||||
const filters = {
|
||||
date: this.dateMode === 'day' ? this.selectedDate : '',
|
||||
weekDates: this.dateMode === 'week' ? this.weekDates : [],
|
||||
type: this.courseType,
|
||||
coach: this.coach,
|
||||
period: this.period
|
||||
}
|
||||
return filterCourses(this.courses, filters).map(enrichCourseForDisplay)
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
const store = loadMemberStore()
|
||||
this.courses = store.courseCatalog.map((c) => ({ ...c }))
|
||||
if (!this.selectedDate && this.courses.length) {
|
||||
this.selectedDate = this.courses[0].date
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleDateMode() {
|
||||
this.dateMode = this.dateMode === 'day' ? 'week' : 'day'
|
||||
},
|
||||
onCoachChange(e) {
|
||||
this.coach = this.coaches[e.detail.value]
|
||||
},
|
||||
onPeriodChange(e) {
|
||||
this.period = this.periodOptions[e.detail.value].key
|
||||
},
|
||||
openDetail(course) {
|
||||
navigateToPage(`${PAGE.COURSE_DETAIL}?id=${course.id}`)
|
||||
},
|
||||
quickBook(course) {
|
||||
if (course.full) return
|
||||
navigateToPage(`${PAGE.COURSE_DETAIL}?id=${course.id}`)
|
||||
},
|
||||
goMyBooking() {
|
||||
navigateToPage(PAGE.BOOKING)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import '@/common/style/base.css';
|
||||
@import '@/common/style/memberInfo/pages/page-reset.css';
|
||||
@import '@/common/style/memberInfo/pages/sub-page-base.css';
|
||||
@import '@/common/style/memberInfo/member-info-component-reset.css';
|
||||
@import '@/common/style/memberInfo/member-info-sub-nav.css';
|
||||
@import '@/common/style/memberInfo/member-info-tap.css';
|
||||
@import '@/common/style/memberInfo/pages/body-test-common.css';
|
||||
@import '@/common/style/memberInfo/pages/module-pages-common.css';
|
||||
@import '@/common/style/memberInfo/pages/course-list-page.css';
|
||||
</style>
|
||||
Reference in New Issue
Block a user