497 lines
11 KiB
Plaintext
497 lines
11 KiB
Plaintext
<template>
|
|
<view class="page-container">
|
|
<scroll-view class="content-scroll" direction="vertical">
|
|
<view class="page-back-action" @tap="handleBackToLogin">
|
|
<text class="page-back-text">返回登录</text>
|
|
</view>
|
|
<!-- 步骤进度 -->
|
|
<view class="step-indicator">
|
|
<view class="step-item">
|
|
<view class="step-dot step-dot-completed"></view>
|
|
<text class="step-text">扫码绑定孩子</text>
|
|
</view>
|
|
<view class="step-line step-line-completed"></view>
|
|
<view class="step-item step-active">
|
|
<view class="step-dot step-dot-active"></view>
|
|
<text class="step-text step-text-active">家长账号与密码</text>
|
|
</view>
|
|
<view class="step-line"></view>
|
|
<view class="step-item">
|
|
<view class="step-dot"></view>
|
|
<text class="step-text">注册完成</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 已绑定学生展示 -->
|
|
<view class="student-summary">
|
|
<view class="summary-title-row">
|
|
<text class="summary-title">已绑定学生</text>
|
|
<uni-badge-view :text="students.length.toString()" badge-class="student-count-badge"></uni-badge-view>
|
|
</view>
|
|
<view class="student-card" v-for="student in students" :key="student.id">
|
|
<image class="student-avatar-small" :src="student.avatar || '/static/avatar-default.png'" mode="aspectFill"></image>
|
|
<text class="student-name-small">{{ student.name }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 表单区域 -->
|
|
<view class="form-section">
|
|
<text class="form-title">设置家长账号信息</text>
|
|
|
|
<view class="form-group">
|
|
<text class="form-label">家长姓名</text>
|
|
<input
|
|
class="form-input"
|
|
type="text"
|
|
v-model="form.parentName"
|
|
placeholder="请输入家长姓名"
|
|
maxlength="10"
|
|
/>
|
|
</view>
|
|
|
|
<view class="form-group">
|
|
<text class="form-label">手机号</text>
|
|
<input
|
|
class="form-input"
|
|
type="number"
|
|
v-model="form.phone"
|
|
placeholder="请输入手机号"
|
|
maxlength="11"
|
|
/>
|
|
</view>
|
|
|
|
<view class="form-group">
|
|
<text class="form-label">与学生的关系</text>
|
|
<picker class="relationship-picker" :value="relationshipIndex" :range="relationshipOptions" @change="handleRelationshipChange">
|
|
<view class="relationship-picker-content">
|
|
<text :class="form.relationship ? 'relationship-value' : 'relationship-placeholder'">{{ form.relationship || '请选择与学生的关系' }}</text>
|
|
</view>
|
|
</picker>
|
|
</view>
|
|
|
|
<view class="form-group">
|
|
<text class="form-label">登录密码</text>
|
|
<view class="input-wrapper">
|
|
<input
|
|
class="form-input-inner"
|
|
type="password"
|
|
v-model="form.password"
|
|
placeholder="请设置登录密码(6-20位)"
|
|
maxlength="20"
|
|
/>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="form-group">
|
|
<text class="form-label">确认密码</text>
|
|
<view class="input-wrapper">
|
|
<input
|
|
class="form-input-inner"
|
|
type="password"
|
|
v-model="form.confirmPassword"
|
|
placeholder="请再次输入密码"
|
|
maxlength="20"
|
|
/>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
|
|
<!-- 底部按钮 -->
|
|
<view class="footer-button-container">
|
|
<view
|
|
class="footer-button"
|
|
:class="canSubmit ? '' : 'footer-button-disabled'"
|
|
@tap="handleSubmit"
|
|
>
|
|
<text class="footer-button-text" :class="canSubmit ? '' : 'footer-button-text-disabled'">完成注册</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { apiRegister } from '../../api/auth'
|
|
import { apiCheckPhone } from '../../api/student'
|
|
import { registrationStudents } from '../../store/registration'
|
|
import { setUserInfo } from '../../store/user'
|
|
|
|
type ParentAccountForm = {
|
|
parentName: string
|
|
phone: string
|
|
relationship: string
|
|
password: string
|
|
confirmPassword: string
|
|
}
|
|
|
|
const form = reactive<ParentAccountForm>({
|
|
parentName: '',
|
|
phone: '',
|
|
relationship: '',
|
|
password: '',
|
|
confirmPassword: ''
|
|
})
|
|
|
|
const students = registrationStudents
|
|
const relationshipOptions = ['爸爸', '妈妈', '爷爷', '奶奶', '外公', '外婆', '其他亲属']
|
|
const relationshipIndex = ref(0)
|
|
|
|
const canSubmit = computed((): boolean => {
|
|
const parentNameReg = /^[\u4e00-\u9fa5]{2,10}$/
|
|
const phoneReg = /^1[3-9]\d{9}$/
|
|
return (
|
|
parentNameReg.test(form.parentName) &&
|
|
phoneReg.test(form.phone) &&
|
|
form.relationship.length > 0 &&
|
|
form.password.length >= 6 &&
|
|
form.password.length <= 20 &&
|
|
form.password === form.confirmPassword
|
|
)
|
|
})
|
|
|
|
function handleRelationshipChange(event: UniPickerChangeEvent) {
|
|
const index = event.detail.value as number
|
|
relationshipIndex.value = index
|
|
form.relationship = relationshipOptions[index]
|
|
}
|
|
|
|
/**
|
|
* 提交注册
|
|
*/
|
|
async function handleSubmit() {
|
|
if (!canSubmit.value) {
|
|
if (!form.parentName) {
|
|
uni.showToast({ title: '请输入家长姓名', icon: 'none' })
|
|
} else if (!/^[\u4e00-\u9fa5]{2,10}$/.test(form.parentName)) {
|
|
uni.showToast({ title: '请输入正确的家长姓名(2-10个汉字)', icon: 'none' })
|
|
} else if (!form.phone) {
|
|
uni.showToast({ title: '请输入手机号', icon: 'none' })
|
|
} else if (!/^1[3-9]\d{9}$/.test(form.phone)) {
|
|
uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
|
|
} else if (!form.relationship) {
|
|
uni.showToast({ title: '请选择与学生的关系', icon: 'none' })
|
|
} else if (form.password.length < 6 || form.password.length > 20) {
|
|
uni.showToast({ title: '密码长度应为6-20位', icon: 'none' })
|
|
} else if (form.password !== form.confirmPassword) {
|
|
uni.showToast({ title: '两次输入的密码不一致', icon: 'none' })
|
|
}
|
|
return
|
|
}
|
|
|
|
// 检查手机号是否已注册
|
|
uni.showLoading({ title: '检查中...' })
|
|
const checkRes = await apiCheckPhone(form.phone)
|
|
uni.hideLoading()
|
|
|
|
if (checkRes && checkRes.data && checkRes.data.exists) {
|
|
uni.showToast({
|
|
title: '该手机号已注册,请直接登录',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
// 提交注册
|
|
uni.showLoading({ title: '注册中...' })
|
|
|
|
const studentIds = students.value.map(s => s.id)
|
|
const res = await apiRegister({
|
|
parentName: form.parentName,
|
|
phone: form.phone,
|
|
relationship: form.relationship,
|
|
password: form.password,
|
|
students: studentIds
|
|
})
|
|
|
|
uni.hideLoading()
|
|
|
|
if (res && res.code === 0 && res.data) {
|
|
// 保存用户信息
|
|
setUserInfo(res.data)
|
|
|
|
// 跳转到注册完成页
|
|
uni.redirectTo({
|
|
url: '/pages/register/complete'
|
|
})
|
|
} else {
|
|
uni.showToast({
|
|
title: res?.message || '注册失败,请稍后重试',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
}
|
|
|
|
function handleBackToLogin() {
|
|
uni.reLaunch({
|
|
url: '/pages/login/index'
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.page-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex: 1;
|
|
background-color: #F5F5F5;
|
|
}
|
|
|
|
.content-scroll {
|
|
flex: 1;
|
|
padding: 16px 16px calc(96px + var(--uni-safe-area-inset-bottom));
|
|
}
|
|
|
|
.page-back-action {
|
|
align-self: flex-start;
|
|
padding: 8px 0;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.page-back-text {
|
|
font-size: 14px;
|
|
color: #6C63FF;
|
|
}
|
|
|
|
/* 步骤指示器 */
|
|
.step-indicator {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 16px;
|
|
background-color: #FFFFFF;
|
|
border-radius: 8px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.step-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
flex: 1;
|
|
}
|
|
|
|
.step-dot {
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 4px;
|
|
background-color: #E5E5E5;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.step-dot-completed {
|
|
background-color: #10B981;
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
|
|
.step-dot-active {
|
|
background-color: #6C63FF;
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.footer-button-text-disabled {
|
|
color: #999999;
|
|
}
|
|
|
|
.step-text {
|
|
font-size: 11px;
|
|
color: #999999;
|
|
text-align: center;
|
|
}
|
|
|
|
.step-text-active {
|
|
color: #6C63FF;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.step-line {
|
|
flex: 1;
|
|
height: 2px;
|
|
background-color: #E5E5E5;
|
|
margin: 0 4px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.step-line-completed {
|
|
background-color: #10B981;
|
|
}
|
|
|
|
/* 学生摘要 */
|
|
.student-summary {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 16px;
|
|
background-color: #FFFFFF;
|
|
border-radius: 8px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.summary-title {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: #333333;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.student-card {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
padding: 8px;
|
|
background-color: #F8F9FA;
|
|
border-radius: 6px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.student-avatar-small {
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 16px;
|
|
margin-right: 8px;
|
|
background-color: #E5E5E5;
|
|
}
|
|
|
|
.student-name-small {
|
|
font-size: 14px;
|
|
color: #333333;
|
|
}
|
|
|
|
/* 表单区域 */
|
|
.form-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 16px;
|
|
background-color: #FFFFFF;
|
|
border-radius: 8px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.form-title {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: #333333;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.form-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.form-label {
|
|
font-size: 14px;
|
|
color: #333333;
|
|
margin-bottom: 8px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.form-input {
|
|
height: 44px;
|
|
padding: 0 16px;
|
|
background-color: #F8F9FA;
|
|
border-radius: 8px;
|
|
border: 1px solid #E5E5E5;
|
|
font-size: 14px;
|
|
color: #333333;
|
|
}
|
|
|
|
.relationship-picker {
|
|
height: 44px;
|
|
background-color: #F8F9FA;
|
|
border-radius: 8px;
|
|
border: 1px solid #E5E5E5;
|
|
}
|
|
|
|
.relationship-picker-content {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
height: 44px;
|
|
padding: 0 16px;
|
|
}
|
|
|
|
.summary-title-row {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.student-count-badge {
|
|
background-color: #6C63FF;
|
|
color: #FFFFFF;
|
|
}
|
|
|
|
.relationship-value {
|
|
font-size: 14px;
|
|
color: #333333;
|
|
}
|
|
|
|
.relationship-placeholder {
|
|
font-size: 14px;
|
|
color: #999999;
|
|
}
|
|
|
|
.relationship-picker-arrow {
|
|
font-size: 16px;
|
|
color: #999999;
|
|
}
|
|
|
|
.input-wrapper {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
height: 44px;
|
|
background-color: #F8F9FA;
|
|
border-radius: 8px;
|
|
border: 1px solid #E5E5E5;
|
|
padding: 0 16px;
|
|
}
|
|
|
|
.form-input-inner {
|
|
flex: 1;
|
|
font-size: 14px;
|
|
color: #333333;
|
|
}
|
|
|
|
/* 底部按钮 */
|
|
.footer-button-container {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
padding: 16px 16px calc(16px + var(--uni-safe-area-inset-bottom));
|
|
background-color: #F5F5F5;
|
|
}
|
|
|
|
.footer-button {
|
|
height: 48px;
|
|
background-color: #6C63FF;
|
|
border-radius: 24px;
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.footer-button-disabled {
|
|
background-color: #E5E5E5;
|
|
}
|
|
|
|
.footer-button-text {
|
|
font-size: 16px;
|
|
color: #FFFFFF;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.footer-button-text-disabled {
|
|
color: #999999;
|
|
}
|
|
</style>
|