智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

773 lines
19 KiB

<!--学员端首页落地页-->
<template>
<view class="main_box">
<!-- 自定义导航栏 -->
<view class="navbar_section">
<view class="welcome_info">
<view class="welcome_text">{{ welcomeText }}</view>
<view class="date_info">今天是{{ currentWeekDay }}</view>
</view>
</view>
<!-- 用户基本信息区域 -->
<view class="user_info_section" v-if="userInfo">
<view class="user_details">
<view class="user_name">{{ userInfo.name || '家长' }} 你好</view>
<view class="user_meta">
<text class="meta_item">入会时间{{ userInfo.create_year_month || '2024年01月' }}</text>
</view>
</view>
</view>
<!-- 学员选择卡片 -->
<view class="student_selector_section">
<view class="selector_header">
<view class="header_title">我的孩子</view>
<view class="switch_button" @click="openStudentPopup" v-if="studentList.length >= 1">
{{ studentList.length > 1 ? '切换' : '学员' }} ({{ studentList.length }})
</view>
</view>
<!-- 当前选中学员信息 -->
<view class="selected_student_card" v-if="selectedStudent">
<view class="student_avatar">
<image
:src="selectedStudent.headimg || '/static/default-avatar.png'"
class="avatar_image"
mode="aspectFill"
></image>
</view>
<view class="student_info">
<view class="student_name">{{ selectedStudent.name }}</view>
<view class="student_details">
<text class="detail_tag">{{ selectedStudent.gender_text }}</text>
<text class="detail_tag">{{ selectedStudent.age }}岁</text>
</view>
</view>
<view class="student_stats">
<view class="stat_item">
<view class="stat_number">{{ selectedStudent.total_courses || 0 }}</view>
<view class="stat_label">总课程</view>
</view>
</view>
</view>
<!-- 没有学员时的提示 -->
<view class="no_student_card" v-else>
<view class="no_student_text">暂无学员信息</view>
<view class="no_student_hint">请联系管理员添加学员</view>
</view>
</view>
<!-- 功能入口区域 -->
<view class="functions_section">
<view class="section_title">功能服务</view>
<view class="functions_grid">
<view class="function_item" @click="navigateToProfile">
<view class="function_icon profile_icon">
<image src="/static/icon-img/profile.png" class="icon_image"></image>
</view>
<view class="function_text">个人信息管理</view>
</view>
<view class="function_item" @click="navigateToPhysicalTest">
<view class="function_icon physical_icon">
<image src="/static/icon-img/chart.png" class="icon_image"></image>
</view>
<view class="function_text">体测数据</view>
</view>
<view class="function_item" @click="navigateToCourseSchedule">
<view class="function_icon schedule_icon">
<image src="/static/icon-img/calendar.png" class="icon_image"></image>
</view>
<view class="function_text">课程安排</view>
</view>
<view class="function_item" @click="navigateToCourseBooking">
<view class="function_icon booking_icon">
<image src="/static/icon-img/book.png" class="icon_image"></image>
</view>
<view class="function_text">课程预约</view>
</view>
<view class="function_item" @click="navigateToOrders">
<view class="function_icon order_icon">
<image src="/static/icon-img/order.png" class="icon_image"></image>
</view>
<view class="function_text">订单管理</view>
</view>
<view class="function_item" @click="navigateToContracts">
<view class="function_icon contract_icon">
<image src="/static/icon-img/contract.png" class="icon_image"></image>
</view>
<view class="function_text">合同管理</view>
</view>
<view class="function_item" @click="navigateToKnowledge">
<view class="function_icon knowledge_icon">
<image src="/static/icon-img/book-open.png" class="icon_image"></image>
</view>
<view class="function_text">知识库</view>
</view>
<view class="function_item" @click="navigateToMessages">
<view class="function_icon message_icon">
<image src="/static/icon-img/message.png" class="icon_image"></image>
</view>
<view class="function_text">消息管理</view>
<view class="message_badge" v-if="unreadCount > 0">{{ unreadCount }}</view>
</view>
<view class="function_item" @click="navigateToSettings">
<view class="function_icon settings_icon">
<image src="/static/icon-img/settings.png" class="icon_image"></image>
</view>
<view class="function_text">系统设置</view>
</view>
</view>
</view>
<!-- 学员选择弹窗 -->
<view class="student_popup" v-if="showStudentPopup" @click="closeStudentPopup">
<view class="popup_content" @click.stop>
<view class="popup_header">
<view class="popup_title">选择学员</view>
<view class="popup_close" @click="closeStudentPopup">×</view>
</view>
<view class="popup_student_list">
<view
v-for="student in studentList"
:key="student.id"
:class="['popup_student_item', selectedStudent && selectedStudent.id === student.id ? 'selected' : '']"
@click="selectStudentFromPopup(student)"
>
<view class="popup_student_avatar">
<image
:src="student.headimg || '/static/default-avatar.png'"
class="popup_avatar_image"
mode="aspectFill"
></image>
</view>
<view class="popup_student_info">
<view class="popup_student_name">{{ student.name }}</view>
<view class="popup_student_details">
<text class="popup_detail_tag">{{ student.gender_text }}</text>
<text class="popup_detail_tag">{{ student.age }}岁</text>
</view>
</view>
<view class="popup_select_icon" v-if="selectedStudent && selectedStudent.id === student.id">
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import apiRoute from '@/api/member.js'
export default {
data() {
return {
userInfo: {},
studentList: [],
selectedStudent: null,
showStudentPopup: false,
loading: false,
unreadCount: 0,
currentWeekDay: ''
}
},
computed: {
welcomeText() {
const hour = new Date().getHours()
if (hour < 12) {
return '早上好'
} else if (hour < 18) {
return '下午好'
} else {
return '晚上好'
}
}
},
onLoad() {
this.initPage()
},
onShow() {
// 页面显示时刷新数据
this.refreshData()
},
methods: {
async initPage() {
this.setCurrentWeekDay()
await this.loadUserInfo()
await this.loadStudentList()
this.loadUnreadMessageCount()
},
async refreshData() {
await this.loadStudentList()
this.loadUnreadMessageCount()
},
setCurrentWeekDay() {
const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
const today = new Date()
this.currentWeekDay = weekDays[today.getDay()]
},
async loadUserInfo() {
try {
// 从本地存储获取用户信息
const userInfo = uni.getStorageSync('userInfo')
if (userInfo) {
this.userInfo = userInfo
// 计算入会年月
if (userInfo.create_time) {
const createDate = new Date(userInfo.create_time)
this.userInfo.create_year_month = `${createDate.getFullYear()}${String(createDate.getMonth() + 1).padStart(2, '0')}`
}
}
} catch (error) {
console.error('获取用户信息失败:', error)
}
},
async loadStudentList() {
this.loading = true
try {
console.log('开始加载学员列表...')
// 调用真实API
const response = await apiRoute.getStudentList()
console.log('学员列表API响应:', response)
if (response.code === 1) {
this.studentList = response.data.list || []
console.log('加载到的学员列表:', this.studentList)
// 如果没有选中的学员且有学员列表,默认选中第一个
if (!this.selectedStudent && this.studentList.length > 0) {
this.selectedStudent = this.studentList[0]
this.loadSelectedStudentSummary()
}
} else {
console.error('获取学员列表失败:', response)
uni.showToast({
title: response.msg || '获取学员列表失败',
icon: 'none'
})
}
} catch (error) {
console.error('获取学员列表失败:', error)
uni.showToast({
title: '获取学员列表失败',
icon: 'none'
})
} finally {
this.loading = false
}
},
async loadSelectedStudentSummary() {
if (!this.selectedStudent) return
try {
console.log('加载学员概览信息:', this.selectedStudent.id)
// 调用真实API获取学员概览信息
const response = await apiRoute.getStudentSummary(this.selectedStudent.id)
console.log('学员概览API响应:', response)
if (response.code === 1) {
// 更新选中学员的概览信息
Object.assign(this.selectedStudent, response.data)
console.log('学员概览加载成功:', response.data)
} else {
console.error('获取学员概览失败:', response)
}
} catch (error) {
console.error('获取学员概览失败:', error)
}
},
async loadUnreadMessageCount() {
try {
// 调用真实API获取未读消息数量
const response = await apiRoute.getUnreadMessageCount()
console.log('未读消息数量API响应:', response)
if (response.code === 1) {
this.unreadCount = response.data.unread_count || 0
console.log('未读消息数量:', this.unreadCount)
}
} catch (error) {
console.error('获取未读消息数量失败:', error)
this.unreadCount = 0
}
},
openStudentPopup() {
if (this.studentList.length === 0) {
uni.showToast({
title: '暂无学员信息',
icon: 'none'
})
return
}
this.showStudentPopup = true
},
closeStudentPopup() {
this.showStudentPopup = false
},
selectStudentFromPopup(student) {
this.selectedStudent = student
console.log('选中学员:', student)
this.loadSelectedStudentSummary()
this.closeStudentPopup()
},
// 导航到各个功能页面
navigateToProfile() {
try {
if (!this.checkStudentSelected()) return
const studentId = this.selectedStudent.student_id || this.selectedStudent.id
console.log('准备跳转到个人信息管理页面, 学员ID:', studentId)
const url = `/pages/student/profile/index?student_id=${studentId}`
console.log('跳转URL:', url)
uni.navigateTo({
url: url
})
} catch (error) {
console.error('导航方法执行错误:', error)
uni.showToast({
title: '导航出错',
icon: 'none'
})
}
},
navigateToPhysicalTest() {
if (!this.checkStudentSelected()) return
const studentId = this.selectedStudent.student_id || this.selectedStudent.id
uni.navigateTo({
url: `/pages/student/physical-test/index?student_id=${studentId}`
})
},
navigateToCourseSchedule() {
if (!this.checkStudentSelected()) return
const studentId = this.selectedStudent.student_id || this.selectedStudent.id
uni.navigateTo({
url: `/pages/student/schedule/index?student_id=${studentId}`
})
},
navigateToCourseBooking() {
if (!this.checkStudentSelected()) return
const studentId = this.selectedStudent.student_id || this.selectedStudent.id
uni.navigateTo({
url: `/pages/student/course-booking/index?student_id=${studentId}`
})
},
navigateToOrders() {
if (!this.checkStudentSelected()) return
const studentId = this.selectedStudent.student_id || this.selectedStudent.id
uni.navigateTo({
url: `/pages/student/orders/index?student_id=${studentId}`
})
},
navigateToContracts() {
if (!this.checkStudentSelected()) return
const studentId = this.selectedStudent.student_id || this.selectedStudent.id
uni.navigateTo({
url: `/pages/student/contracts/index?student_id=${studentId}`
})
},
navigateToKnowledge() {
if (!this.checkStudentSelected()) return
const studentId = this.selectedStudent.student_id || this.selectedStudent.id
uni.navigateTo({
url: `/pages/student/knowledge/index?student_id=${studentId}`
})
},
navigateToMessages() {
if (!this.checkStudentSelected()) return
const studentId = this.selectedStudent.student_id || this.selectedStudent.id
uni.navigateTo({
url: `/pages/student/messages/index?student_id=${studentId}`
})
},
navigateToSettings() {
console.log('跳转到系统设置')
uni.navigateTo({
url: '/pages/student/settings/index'
})
},
checkStudentSelected() {
if (!this.selectedStudent) {
uni.showToast({
title: '请先选择学员',
icon: 'none'
})
return false
}
return true
}
}
}
</script>
<style lang="less" scoped>
.main_box {
background: #f8f9fa;
min-height: 100vh;
}
// 自定义导航栏
.navbar_section {
background: linear-gradient(135deg, #29D3B4 0%, #1BA297 100%);
padding: 40rpx 32rpx 32rpx;
// 小程序端适配状态栏
// #ifdef MP-WEIXIN
padding-top: 80rpx;
// #endif
.welcome_info {
color: #fff;
.welcome_text {
font-size: 36rpx;
font-weight: 600;
margin-bottom: 8rpx;
}
.date_info {
font-size: 24rpx;
opacity: 0.9;
}
}
}
// 用户信息区域
.user_info_section {
background: #fff;
padding: 24rpx 32rpx;
border-bottom: 1px solid #f0f0f0;
.user_details {
.user_name {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 8rpx;
}
.user_meta {
.meta_item {
font-size: 24rpx;
color: #666;
margin-right: 24rpx;
}
}
}
}
// 学员选择区域
.student_selector_section {
background: #fff;
margin: 20rpx;
border-radius: 16rpx;
padding: 32rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
.selector_header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.header_title {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
.switch_button {
background: #29d3b4;
color: #fff;
padding: 8rpx 16rpx;
border-radius: 16rpx;
font-size: 22rpx;
}
}
.selected_student_card {
display: flex;
align-items: center;
gap: 24rpx;
.student_avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
overflow: hidden;
.avatar_image {
width: 100%;
height: 100%;
}
}
.student_info {
flex: 1;
.student_name {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 8rpx;
}
.student_details {
display: flex;
gap: 12rpx;
.detail_tag {
font-size: 22rpx;
color: #666;
background: #f0f0f0;
padding: 4rpx 12rpx;
border-radius: 12rpx;
}
}
}
.student_stats {
text-align: center;
.stat_item {
.stat_number {
color: #29D3B4;
font-size: 32rpx;
font-weight: 600;
}
.stat_label {
color: #999;
font-size: 22rpx;
}
}
}
}
.no_student_card {
text-align: center;
padding: 40rpx 0;
.no_student_text {
font-size: 28rpx;
color: #666;
margin-bottom: 8rpx;
}
.no_student_hint {
font-size: 24rpx;
color: #999;
}
}
}
// 功能入口区域
.functions_section {
margin: 20rpx;
.section_title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
padding-left: 16rpx;
}
.functions_grid {
background: #fff;
border-radius: 16rpx;
padding: 32rpx 24rpx;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.function_item {
width: 22%;
margin-bottom: 32rpx;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
.function_icon {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12rpx;
&.profile_icon { background: rgba(52, 152, 219, 0.15); }
&.physical_icon { background: rgba(155, 89, 182, 0.15); }
&.schedule_icon { background: rgba(241, 196, 15, 0.15); }
&.booking_icon { background: rgba(230, 126, 34, 0.15); }
&.order_icon { background: rgba(231, 76, 60, 0.15); }
&.contract_icon { background: rgba(46, 204, 113, 0.15); }
&.knowledge_icon { background: rgba(52, 73, 94, 0.15); }
&.message_icon { background: rgba(41, 211, 180, 0.15); }
&.settings_icon { background: rgba(95, 95, 95, 0.15); }
.icon_image {
width: 32rpx;
height: 32rpx;
}
}
.function_text {
font-size: 22rpx;
color: #333;
text-align: center;
line-height: 1.2;
}
.message_badge {
position: absolute;
top: -4rpx;
right: 14rpx;
background: #ff4757;
color: #fff;
font-size: 18rpx;
padding: 2rpx 8rpx;
border-radius: 12rpx;
min-width: 16rpx;
text-align: center;
}
}
}
}
// 学员选择弹窗
.student_popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
.popup_content {
background: #fff;
border-radius: 16rpx;
width: 80%;
max-height: 60vh;
overflow: hidden;
.popup_header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx;
border-bottom: 1px solid #f0f0f0;
.popup_title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.popup_close {
font-size: 48rpx;
color: #999;
font-weight: 300;
}
}
.popup_student_list {
max-height: 50vh;
overflow-y: auto;
.popup_student_item {
display: flex;
align-items: center;
padding: 24rpx 32rpx;
border-bottom: 1px solid #f8f9fa;
gap: 24rpx;
&.selected {
background: rgba(41, 211, 180, 0.1);
}
.popup_student_avatar {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
overflow: hidden;
.popup_avatar_image {
width: 100%;
height: 100%;
}
}
.popup_student_info {
flex: 1;
.popup_student_name {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 8rpx;
}
.popup_student_details {
display: flex;
gap: 12rpx;
.popup_detail_tag {
font-size: 22rpx;
color: #666;
background: #f0f0f0;
padding: 2rpx 8rpx;
border-radius: 8rpx;
}
}
}
.popup_select_icon {
color: #29d3b4;
font-size: 32rpx;
font-weight: 600;
}
}
}
}
}
</style>