index.vue 8.95 KB
<template>
  <view class="register-page">
    <!-- 头像区域 -->
    <view class="avatar-section">
      <view class="avatar-container">
        <image
          :src="formData.avatar || defaultAvatar"
          class="avatar-image"
          mode="aspectFill"
          @click="previewAvatar"
        />
      </view>
      <view class="change-avatar-btn" @click="changeAvatar">
        <text class="change-avatar-text">上传头像</text>
      </view>
    </view>

    <!-- 表单内容 -->
    <nut-form ref="formRef" :model-value="formData">
      <view class="form-container">
        <!-- 昵称 -->
        <nut-form-item label="昵称" prop="nickname" required :rules="[{ required: true, message: '请输入昵称' }]">
          <nut-input
            v-model="formData.nickname"
            placeholder="请输入昵称"
            input-align="right"
            clearable
          />
        </nut-form-item>

        <!-- 手机号 -->
        <nut-form-item label="手机号" prop="phone" required :rules="phoneRules">
          <view class="phone-input-container">
            <nut-input
              v-model="formData.phone"
              placeholder="请输入手机号"
              type="tel"
              maxlength="11"
              input-align="right"
              clearable
              class="phone-input"
            />
            <nut-button
              size="small"
              :disabled="codeCountdown > 0 || !isPhoneValid"
              @click="sendCode"
              class="code-btn"
            >
              {{ codeCountdown > 0 ? `${codeCountdown}s` : '获取验证码' }}
            </nut-button>
          </view>
        </nut-form-item>

        <!-- 验证码 -->
        <nut-form-item label="验证码" prop="verifyCode" required :rules="[{ required: true, message: '请输入验证码' }]">
          <nut-input
            v-model="formData.verifyCode"
            placeholder="请输入验证码"
            type="number"
            maxlength="6"
            input-align="right"
            clearable
          />
        </nut-form-item>

        <!-- 性别 -->
        <nut-form-item label="性别" prop="gender" body-align="right" required :rules="[{ required: true, message: '请选择性别' }]">
          <nut-radio-group v-model="formData.gender" direction="horizontal">
            <nut-radio label="男">男</nut-radio>
            <nut-radio label="女">女</nut-radio>
          </nut-radio-group>
        </nut-form-item>

        <!-- 生日 -->
        <nut-form-item label="生日" prop="birthday" label-position="top">
          <view class="birthday-item" @click="showDatePicker">
            <text class="birthday-value">{{ formData.birthday || '请选择生日' }}</text>
            <Right class="arrow-icon" />
          </view>
        </nut-form-item>

        <!-- 所在学校 -->
        <nut-form-item label="所在学校" prop="school" required :rules="[{ required: true, message: '请选择学校' }]" label-position="top">
          <view class="school-item" @click="showSchoolPicker">
            <text class="school-value">{{ formData.school || '请选择学校' }}</text>
            <Right class="arrow-icon" />
          </view>
        </nut-form-item>
      </view>
    </nut-form>

    <!-- 注册按钮 -->
    <view class="register-section">
      <nut-button
        color="#f97316"
        size="large"
        block
        @click="handleRegister"
        :loading="isRegistering"
      >
        {{ isRegistering ? '保存中...' : '保存' }}
      </nut-button>
    </view>

    <!-- 日期选择器 -->
    <nut-popup v-model:visible="datePickerVisible" position="bottom">
      <nut-date-picker
        v-model="dateValue"
        title="选择生日"
        @confirm="onDateConfirm"
        @cancel="datePickerVisible = false"
      />
    </nut-popup>

    <!-- 学校选择器 -->
    <nut-popup v-model:visible="schoolPickerVisible" position="bottom">
      <nut-picker
        v-model="schoolValue"
        :columns="schoolOptions"
        title="选择学校"
        @confirm="onSchoolConfirm"
        @cancel="schoolPickerVisible = false"
      />
    </nut-popup>

    <!-- 头像预览 -->
    <nut-image-preview
      v-model:show="avatarPreviewVisible"
      :images="[formData.avatar || defaultAvatar]"
    />

    <!-- 成功提示 -->
    <nut-toast
      v-model:visible="toastVisible"
      :msg="toastMessage"
      :type="toastType"
    />
  </view>
</template>

<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import Taro from '@tarojs/taro'
import { RectLeft, Right } from '@nutui/icons-vue-taro'
import './index.less'

// 主题配置
const themeVars = {
  navbarBackground: '#f97316',
  navbarColor: '#fff'
}

// 默认头像
const defaultAvatar = 'https://randomuser.me/api/portraits/men/32.jpg'

// 表单数据
const formData = reactive({
  avatar: '',
  nickname: '',
  phone: '',
  verifyCode: '',
  gender: '',
  birthday: '',
  school: ''
})

// 弹框控制
const datePickerVisible = ref(false)
const schoolPickerVisible = ref(false)
const avatarPreviewVisible = ref(false)
const toastVisible = ref(false)
const toastMessage = ref('')
const toastType = ref('success')

// 验证码相关
const codeCountdown = ref(0)
const isRegistering = ref(false)

// 日期选择
const dateValue = ref(new Date())

// 学校选择
const schoolValue = ref([])
const schoolOptions = ref([
  [
    { text: '上海理工大学', value: '上海理工大学' },
    { text: '上海大学', value: '上海大学' },
    { text: '华东理工大学', value: '华东理工大学' },
    { text: '上海交通大学', value: '上海交通大学' },
    { text: '复旦大学', value: '复旦大学' },
    { text: '同济大学', value: '同济大学' },
    { text: '华东师范大学', value: '华东师范大学' },
    { text: '上海财经大学', value: '上海财经大学' }
  ]
])

// 手机号验证规则
const phoneRules = [
  { required: true, message: '请输入手机号' },
  {
    pattern: /^1[3-9]\d{9}$/,
    message: '请输入正确的手机号格式'
  }
]

// 计算属性:手机号是否有效
const isPhoneValid = computed(() => {
  return /^1[3-9]\d{9}$/.test(formData.phone)
})

/**
 * 返回上一页
 */
const goBack = () => {
  Taro.navigateBack()
}

/**
 * 更换头像
 */
const changeAvatar = () => {
  Taro.chooseImage({
    count: 1,
    sizeType: ['compressed'],
    sourceType: ['album', 'camera'],
    success: (res) => {
      formData.avatar = res.tempFilePaths[0]
    }
  })
}

/**
 * 预览头像
 */
const previewAvatar = () => {
  avatarPreviewVisible.value = true
}

/**
 * 发送验证码
 */
const sendCode = () => {
  if (!isPhoneValid.value) {
    showToast('请输入正确的手机号', 'error')
    return
  }

  // 模拟发送验证码
  codeCountdown.value = 60
  const timer = setInterval(() => {
    codeCountdown.value--
    if (codeCountdown.value <= 0) {
      clearInterval(timer)
    }
  }, 1000)

  showToast('验证码已发送', 'success')
}

/**
 * 显示日期选择器
 */
const showDatePicker = () => {
  datePickerVisible.value = true
}

/**
 * 确认日期选择
 */
const onDateConfirm = ({ selectedValue }) => {
  formData.birthday = `${selectedValue[0]}-${String(selectedValue[1]).padStart(2, '0')}-${String(selectedValue[2]).padStart(2, '0')}`
  datePickerVisible.value = false
}

/**
 * 显示学校选择器
 */
const showSchoolPicker = () => {
  schoolPickerVisible.value = true
}

/**
 * 确认学校选择
 */
const onSchoolConfirm = ({ selectedOptions }) => {
  formData.school = selectedOptions[0].text
  schoolPickerVisible.value = false
}

/**
 * 显示提示信息
 */
const showToast = (message, type = 'success') => {
  toastMessage.value = message
  toastType.value = type
  toastVisible.value = true
}

/**
 * 表单验证
 */
const validateForm = () => {
  if (!formData.nickname.trim()) {
    showToast('请输入昵称', 'error')
    return false
  }

  if (!isPhoneValid.value) {
    showToast('请输入正确的手机号', 'error')
    return false
  }

  if (!formData.verifyCode.trim()) {
    showToast('请输入验证码', 'error')
    return false
  }

  if (!formData.gender) {
    showToast('请选择性别', 'error')
    return false
  }

  if (!formData.school) {
    showToast('请选择学校', 'error')
    return false
  }

  return true
}

/**
 * 处理注册
 */
const handleRegister = async () => {
  if (!validateForm()) {
    return
  }

  isRegistering.value = true

  try {
    // 模拟注册API调用
    await new Promise(resolve => setTimeout(resolve, 2000))

    // TODO: 这里应该调用实际的注册API
    // const result = await registerAPI(formData)

    showToast('注册成功', 'success')

    setTimeout(() => {
      // 注册成功后跳转到登录页面或首页
      Taro.navigateBack()
    }, 1500)

  } catch (error) {
    showToast('注册失败,请重试', 'error')
  } finally {
    isRegistering.value = false
  }
}

// 初始化
onMounted(() => {
  // 可以在这里进行初始化操作
})
</script>

<script>
export default {
  name: 'RegisterPage'
}
</script>