智慧教务系统
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.
 
 
 
 
 
 

595 lines
14 KiB

<!--学员个人信息管理页面-->
<template>
<view class="main_box">
<!-- 自定义导航栏 -->
<view class="navbar_section">
<view class="navbar_back" @click="goBack">
<text class="back_icon"></text>
</view>
<view class="navbar_title">个人信息管理</view>
<view class="navbar_action"></view>
</view>
<!-- 学员头像区域 -->
<view class="avatar_section">
<view class="avatar_container">
<image
:src="studentInfo.headimg || '/static/default-avatar.png'"
class="avatar_image"
mode="aspectFill"
@click="uploadAvatar"
></image>
<view class="avatar_edit_icon" @click="uploadAvatar">
<text class="edit_text"></text>
</view>
</view>
<view class="student_name">{{ studentInfo.name || '学员姓名' }}</view>
<view class="student_basic_info">
<text class="info_tag">{{ studentInfo.gender_text }}</text>
<text class="info_tag">{{ studentInfo.ageText }}</text>
</view>
</view>
<!-- 基本信息表单 -->
<view class="form_section">
<view class="section_title">基本信息</view>
<view class="form_item">
<view class="form_label">姓名</view>
<fui-input
v-model="formData.name"
placeholder="请输入学员姓名"
borderColor="transparent"
backgroundColor="#f8f9fa"
:maxlength="20"
></fui-input>
</view>
<view class="form_item">
<view class="form_label">性别</view>
<fui-input
v-model="genderText"
placeholder="请选择性别"
borderColor="transparent"
backgroundColor="#f8f9fa"
readonly
@click="showGenderPicker = true"
>
<fui-icon name="arrowdown" color="#B2B2B2" :size="40"></fui-icon>
</fui-input>
<fui-picker
:options="genderOptions"
:show="showGenderPicker"
@change="changeGender"
@cancel="showGenderPicker = false"
></fui-picker>
</view>
<view class="form_item">
<view class="form_label">生日</view>
<fui-date-picker
:show="showDatePicker"
v-model="formData.birthday"
@change="changeBirthday"
@cancel="showDatePicker = false"
>
<fui-input
:value="birthdayText"
placeholder="请选择生日"
borderColor="transparent"
backgroundColor="#f8f9fa"
readonly
@click="showDatePicker = true"
>
<fui-icon name="arrowdown" color="#B2B2B2" :size="40"></fui-icon>
</fui-input>
</fui-date-picker>
</view>
<view class="form_item">
<view class="form_label">年龄</view>
<fui-input
:value="ageText"
placeholder="根据生日自动计算"
borderColor="transparent"
backgroundColor="#f0f0f0"
readonly
></fui-input>
</view>
</view>
<!-- 体测信息只读展示 -->
<view class="form_section">
<view class="section_title">体测信息</view>
<view class="form_item">
<view class="form_label">身高 (cm)</view>
<fui-input
:value="physicalTestInfo.height || '暂无数据'"
placeholder="暂无体测数据"
borderColor="transparent"
backgroundColor="#f0f0f0"
readonly
></fui-input>
</view>
<view class="form_item">
<view class="form_label">体重 (kg)</view>
<fui-input
:value="physicalTestInfo.weight || '暂无数据'"
placeholder="暂无体测数据"
borderColor="transparent"
backgroundColor="#f0f0f0"
readonly
></fui-input>
</view>
<view class="form_item" v-if="physicalTestInfo.test_date">
<view class="form_label">体测日期</view>
<fui-input
:value="physicalTestInfo.test_date"
placeholder="暂无体测数据"
borderColor="transparent"
backgroundColor="#f0f0f0"
readonly
></fui-input>
</view>
</view>
<!-- 联系信息 -->
<view class="form_section">
<view class="section_title">紧急联系人</view>
<view class="form_item">
<view class="form_label">联系人姓名</view>
<fui-input
v-model="formData.emergency_contact"
placeholder="请输入紧急联系人姓名"
borderColor="transparent"
backgroundColor="#f8f9fa"
:maxlength="20"
></fui-input>
</view>
<view class="form_item">
<view class="form_label">联系电话</view>
<fui-input
v-model="formData.contact_phone"
placeholder="请输入联系电话"
borderColor="transparent"
backgroundColor="#f8f9fa"
type="number"
:maxlength="11"
></fui-input>
</view>
<view class="form_item">
<view class="form_label">备注信息</view>
<fui-textarea
v-model="formData.note"
placeholder="其他需要说明的信息"
backgroundColor="#f8f9fa"
:maxlength="500"
:rows="4"
></fui-textarea>
</view>
</view>
<!-- 保存按钮 -->
<view class="save_section">
<fui-button
background="#29d3b4"
radius="12rpx"
:loading="saving"
@click="saveStudentInfo"
>
{{ saving ? '保存中...' : '保存信息' }}
</fui-button>
</view>
</view>
</template>
<script>
import apiRoute from '@/api/member.js'
export default {
data() {
return {
studentId: 0,
studentInfo: {},
physicalTestInfo: {}, // 体测信息
formData: {
name: '',
gender: '',
birthday: '',
emergency_contact: '',
contact_phone: '',
note: ''
},
saving: false,
showGenderPicker: false,
showDatePicker: false,
genderOptions: [
{ value: '1', text: '男' },
{ value: '2', text: '女' }
]
}
},
computed: {
genderText() {
const gender = this.genderOptions.find(item => item.value === this.formData.gender)
return gender ? gender.text : ''
},
birthdayText() {
return this.formData.birthday || ''
},
ageText() {
if (!this.formData.birthday) return ''
const today = new Date()
const birthDate = new Date(this.formData.birthday)
let age = today.getFullYear() - birthDate.getFullYear()
let months = today.getMonth() - birthDate.getMonth()
if (months < 0 || (months === 0 && today.getDate() < birthDate.getDate())) {
age--
months += 12
}
if (months < 0) {
months = 0
}
return age > 0 ? `${age}.${months.toString().padStart(2, '0')}` : `${months}个月`
}
},
onLoad(options) {
this.studentId = parseInt(options.student_id) || 0
if (this.studentId) {
this.loadStudentInfo()
} else {
uni.showToast({
title: '参数错误',
icon: 'none'
})
}
},
methods: {
goBack() {
uni.navigateBack()
},
async loadStudentInfo() {
try {
console.log('加载学员信息:', this.studentId)
// 调用真实API
const response = await apiRoute.getStudentInfo(this.studentId)
console.log('学员信息API响应:', response)
if (response.code === 1) {
this.studentInfo = response.data.student_info
this.physicalTestInfo = response.data.physical_test_info || {}
// 填充表单数据
this.formData = {
name: this.studentInfo.name || '',
gender: String(this.studentInfo.gender || ''),
birthday: this.studentInfo.birthday || '',
emergency_contact: this.studentInfo.emergency_contact || '',
contact_phone: this.studentInfo.contact_phone || '',
note: this.studentInfo.note || ''
}
console.log('学员信息加载成功:', this.studentInfo)
console.log('体测信息加载成功:', this.physicalTestInfo)
} else {
uni.showToast({
title: response.msg || '获取学员信息失败',
icon: 'none'
})
}
} catch (error) {
console.error('获取学员信息失败:', error)
uni.showToast({
title: '获取学员信息失败',
icon: 'none'
})
}
},
changeGender(e) {
this.formData.gender = e.value
this.showGenderPicker = false
},
changeBirthday(e) {
this.formData.birthday = e.result
this.showDatePicker = false
},
async uploadAvatar() {
try {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: async (res) => {
const tempFilePath = res.tempFilePaths[0]
console.log('选择的图片:', tempFilePath)
// 显示上传中提示
uni.showLoading({
title: '上传中...'
})
try {
// 调用通用头像上传API
const response = await apiRoute.uploadAvatarForAdd(tempFilePath)
console.log('头像上传API响应:', response)
if (response.code === 1) {
// 更新头像URL并保存到数据库
this.studentInfo.headimg = response.data.url
this.formData.headimg = response.data.url
// 立即保存头像到数据库
await this.saveAvatarToDatabase(response.data.url)
uni.showToast({
title: '头像上传成功',
icon: 'success'
})
} else {
throw new Error(response.msg || '上传失败')
}
} catch (uploadError) {
console.error('头像上传失败:', uploadError)
uni.showToast({
title: '头像上传失败',
icon: 'none'
})
} finally {
uni.hideLoading()
}
},
fail: (error) => {
console.error('选择图片失败:', error)
}
})
} catch (error) {
console.error('选择头像失败:', error)
}
},
async saveAvatarToDatabase(avatarUrl) {
try {
const updateData = {
student_id: this.studentId,
headimg: avatarUrl
}
console.log('保存头像到数据库:', updateData)
// 调用更新学员信息API,只更新头像字段
const response = await apiRoute.updateStudentInfo(updateData)
console.log('保存头像API响应:', response)
if (response.code !== 1) {
throw new Error(response.msg || '保存头像失败')
}
} catch (error) {
console.error('保存头像到数据库失败:', error)
throw error
}
},
async saveStudentInfo() {
// 表单验证
if (!this.formData.name.trim()) {
uni.showToast({
title: '请输入学员姓名',
icon: 'none'
})
return
}
if (!this.formData.gender) {
uni.showToast({
title: '请选择性别',
icon: 'none'
})
return
}
// 手机号验证
if (this.formData.contact_phone && !/^1[3-9]\d{9}$/.test(this.formData.contact_phone)) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
})
return
}
this.saving = true
try {
const updateData = {
student_id: this.studentId,
...this.formData
}
console.log('保存学员信息:', updateData)
// 调用真实API
const response = await apiRoute.updateStudentInfo(updateData)
console.log('更新学员信息API响应:', response)
if (response.code === 1) {
// 更新本地学员信息
Object.assign(this.studentInfo, this.formData)
uni.showToast({
title: '保存成功',
icon: 'success'
})
// 延迟返回上一页
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
uni.showToast({
title: response.message || '保存失败',
icon: 'none'
})
}
} catch (error) {
console.error('保存学员信息失败:', error)
uni.showToast({
title: '保存失败,请重试',
icon: 'none'
})
} finally {
this.saving = false
}
}
}
}
</script>
<style lang="less" scoped>
.main_box {
background: #f8f9fa;
min-height: 100vh;
}
// 自定义导航栏
.navbar_section {
display: flex;
justify-content: space-between;
align-items: center;
background: #29D3B4;
padding: 40rpx 32rpx 20rpx;
// 小程序端适配状态栏
// #ifdef MP-WEIXIN
padding-top: 80rpx;
// #endif
.navbar_back {
width: 60rpx;
.back_icon {
color: #fff;
font-size: 40rpx;
font-weight: 600;
}
}
.navbar_title {
color: #fff;
font-size: 32rpx;
font-weight: 600;
}
.navbar_action {
width: 60rpx;
}
}
// 头像区域
.avatar_section {
background: #fff;
padding: 40rpx 32rpx;
text-align: center;
.avatar_container {
position: relative;
display: inline-block;
margin-bottom: 24rpx;
.avatar_image {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
border: 4rpx solid #f0f0f0;
}
.avatar_edit_icon {
position: absolute;
bottom: 0;
right: 0;
width: 40rpx;
height: 40rpx;
background: #29d3b4;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 2rpx solid #fff;
.edit_text {
color: #fff;
font-size: 20rpx;
}
}
}
.student_name {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 12rpx;
}
.student_basic_info {
.info_tag {
display: inline-block;
font-size: 22rpx;
color: #666;
background: #f0f0f0;
padding: 6rpx 16rpx;
border-radius: 16rpx;
margin: 0 8rpx;
}
}
}
// 表单区域
.form_section {
background: #fff;
margin: 20rpx;
border-radius: 16rpx;
padding: 32rpx;
.section_title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 32rpx;
padding-bottom: 16rpx;
border-bottom: 1px solid #f0f0f0;
}
.form_item {
margin-bottom: 32rpx;
&:last-child {
margin-bottom: 0;
}
.form_label {
font-size: 26rpx;
color: #333;
margin-bottom: 12rpx;
font-weight: 500;
}
}
}
// 保存按钮区域
.save_section {
padding: 40rpx 32rpx;
padding-bottom: 80rpx;
}
</style>