271 lines
6.1 KiB
Vue
271 lines
6.1 KiB
Vue
<template>
|
||
<view class="tutoring-page">
|
||
<view class="header">
|
||
<text class="title">👤 一对一辅导</text>
|
||
<text class="subtitle">专属定制,精准提升</text>
|
||
</view>
|
||
|
||
<view class="content">
|
||
<view class="intro-section">
|
||
<text class="intro-title">服务特色</text>
|
||
<view class="feature-list">
|
||
<view class="feature-item">
|
||
<text class="feature-icon">✓</text>
|
||
<text class="feature-text">专属老师,一对一教学</text>
|
||
</view>
|
||
<view class="feature-item">
|
||
<text class="feature-icon">✓</text>
|
||
<text class="feature-text">定制学习计划,针对性强</text>
|
||
</view>
|
||
<view class="feature-item">
|
||
<text class="feature-icon">✓</text>
|
||
<text class="feature-text">灵活安排时间,上门服务</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="subject-list">
|
||
<text class="section-title">选择科目</text>
|
||
<view class="subject-grid">
|
||
<view
|
||
v-for="subject in subjects"
|
||
:key="subject.id"
|
||
class="subject-card"
|
||
@tap="selectSubject(subject)"
|
||
>
|
||
<text class="subject-icon">{{ subject.icon }}</text>
|
||
<text class="subject-name">{{ subject.name }}</text>
|
||
<text class="subject-price">¥{{ subject.price }}/小时</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="btn-book" @tap="bookNow">立即预约</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import api from '@/api/index.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
subjects: [],
|
||
loading: false
|
||
}
|
||
},
|
||
|
||
onLoad() {
|
||
this.loadServices()
|
||
},
|
||
|
||
methods: {
|
||
async loadServices() {
|
||
if (this.loading) return
|
||
|
||
this.loading = true
|
||
try {
|
||
const data = await api.tutoringApi.getServiceList()
|
||
|
||
// 智能判断返回的数据结构
|
||
let list = []
|
||
if (Array.isArray(data)) {
|
||
list = data
|
||
} else if (data.records) {
|
||
list = data.records
|
||
} else if (data.list) {
|
||
list = data.list
|
||
} else if (data.data) {
|
||
if (Array.isArray(data.data)) {
|
||
list = data.data
|
||
} else if (data.data.records) {
|
||
list = data.data.records
|
||
} else if (data.data.list) {
|
||
list = data.data.list
|
||
}
|
||
}
|
||
|
||
// 转换数据格式
|
||
this.subjects = list.map(service => ({
|
||
id: service.id,
|
||
name: service.name,
|
||
icon: service.icon || '📖',
|
||
price: service.price,
|
||
description: service.description,
|
||
features: this.parseFeatures(service.features),
|
||
teacherCount: service.teacherCount || service.teacher_count,
|
||
orderCount: service.orderCount || service.order_count,
|
||
rating: service.rating,
|
||
isHot: service.isHot === 1 || service.is_hot === 1,
|
||
isNew: service.isNew === 1 || service.is_new === 1
|
||
}))
|
||
|
||
console.log('一对一辅导服务加载成功:', this.subjects.length, '条')
|
||
} catch (error) {
|
||
console.error('加载服务失败:', error)
|
||
uni.showToast({
|
||
title: '加载失败,请重试',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
this.loading = false
|
||
}
|
||
},
|
||
|
||
parseFeatures(features) {
|
||
try {
|
||
return JSON.parse(features || '[]')
|
||
} catch {
|
||
return []
|
||
}
|
||
},
|
||
|
||
selectSubject(subject) {
|
||
// 跳转到教师列表,传递学科参数
|
||
uni.navigateTo({
|
||
url: `/pages/teacher/list?subject=${subject.name}`
|
||
})
|
||
},
|
||
|
||
bookNow() {
|
||
uni.switchTab({
|
||
url: '/pages/booking/quick-booking'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
@import '@/static/css/common.scss';
|
||
|
||
.tutoring-page {
|
||
min-height: 100vh;
|
||
background: #f8f8f8;
|
||
}
|
||
|
||
.header {
|
||
background: linear-gradient(135deg, $primary-color 0%, $primary-light 100%);
|
||
padding: 50rpx 30rpx 40rpx;
|
||
text-align: center;
|
||
|
||
.title {
|
||
display: block;
|
||
font-size: 40rpx;
|
||
font-weight: bold;
|
||
color: #ffffff;
|
||
margin-bottom: 15rpx;
|
||
}
|
||
|
||
.subtitle {
|
||
display: block;
|
||
font-size: 26rpx;
|
||
color: rgba(255, 255, 255, 0.9);
|
||
}
|
||
}
|
||
|
||
.content {
|
||
padding: 30rpx;
|
||
}
|
||
|
||
.intro-section {
|
||
background: #ffffff;
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
margin-bottom: 30rpx;
|
||
|
||
.intro-title {
|
||
display: block;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.feature-list {
|
||
.feature-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15rpx;
|
||
margin-bottom: 15rpx;
|
||
|
||
.feature-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
background: $primary-color;
|
||
color: #ffffff;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.feature-text {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.subject-list {
|
||
margin-bottom: 30rpx;
|
||
|
||
.section-title {
|
||
display: block;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.subject-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.subject-card {
|
||
background: #ffffff;
|
||
border-radius: 16rpx;
|
||
padding: 30rpx 20rpx;
|
||
text-align: center;
|
||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||
|
||
.subject-icon {
|
||
display: block;
|
||
font-size: 48rpx;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.subject-name {
|
||
display: block;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.subject-price {
|
||
display: block;
|
||
font-size: 24rpx;
|
||
color: #ff6b00;
|
||
}
|
||
}
|
||
}
|
||
|
||
.btn-book {
|
||
width: 100%;
|
||
height: 88rpx;
|
||
background: linear-gradient(135deg, $primary-color 0%, $primary-light 100%);
|
||
color: #ffffff;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
border-radius: 44rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
</style>
|