register.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <route lang="json5" type="page">
  2. {
  3. layout: 'default',
  4. style: {
  5. navigationStyle: 'custom',
  6. },
  7. }
  8. </route>
  9. <script lang="ts" setup>
  10. import { getCode, register } from '@/api/login'
  11. import { goBack, toPage } from '@/utils/page'
  12. import { toast } from '@/utils/toast'
  13. defineOptions({
  14. name: 'Register', // 注册
  15. })
  16. // 获取屏幕边界到安全区域距离
  17. const systemInfo = uni.getSystemInfoSync()
  18. const safeAreaInsets = systemInfo.safeAreaInsets
  19. // 表单数据
  20. const formData = ref({
  21. name: '',
  22. phone: '',
  23. verifyCode: '',
  24. pwd: '',
  25. code: '',
  26. })
  27. // 验证码倒计时
  28. const countdown = ref(0)
  29. const countdownTimer = ref<any>(null)
  30. // 获取验证码
  31. async function getVerificationCode() {
  32. // 验证手机号
  33. if (!formData.value.phone.trim()) {
  34. toast.error('Please enter phone number first')
  35. return
  36. }
  37. // 验证手机号格式
  38. const phoneRegex = /^1[3-9]\d{9}$/
  39. if (!phoneRegex.test(formData.value.phone)) {
  40. toast.error('Please enter valid phone number')
  41. return
  42. }
  43. // 防止重复点击
  44. if (countdown.value > 0) {
  45. return
  46. }
  47. try {
  48. // 显示加载状态
  49. uni.showLoading({
  50. title: 'Sending...',
  51. mask: true,
  52. })
  53. // 调用获取验证码接口
  54. await getCode(formData.value.phone)
  55. uni.hideLoading()
  56. toast.success('Verification code sent successfully')
  57. // 开始倒计时
  58. countdown.value = 60
  59. countdownTimer.value = setInterval(() => {
  60. countdown.value--
  61. if (countdown.value <= 0) {
  62. clearInterval(countdownTimer.value!)
  63. countdownTimer.value = null
  64. }
  65. }, 1000)
  66. }
  67. catch (error) {
  68. uni.hideLoading()
  69. toast.error(error.message || 'Failed to send verification code')
  70. }
  71. }
  72. // 注册处理
  73. async function handleRegister() {
  74. try {
  75. // 表单验证
  76. const isValid = await validateForm()
  77. if (!isValid)
  78. return
  79. // 显示加载状态
  80. uni.showLoading({
  81. title: 'Registering...',
  82. mask: true,
  83. })
  84. // 调用注册接口
  85. const registerData = {
  86. name: formData.value.name,
  87. phone: formData.value.phone,
  88. verifyCode: formData.value.verifyCode,
  89. pwd: formData.value.pwd,
  90. code: formData.value.code,
  91. }
  92. await register(registerData)
  93. uni.hideLoading()
  94. // 注册成功
  95. toast.success('Registration successful!')
  96. setTimeout(() => {
  97. toPage('/pages/login/login', {}, true)
  98. }, 1500)
  99. }
  100. catch (error) {
  101. uni.hideLoading()
  102. toast.error(error.message || 'Registration failed')
  103. }
  104. }
  105. // 表单验证
  106. function validateForm() {
  107. return new Promise((resolve) => {
  108. // 验证必填字段
  109. if (!formData.value.name.trim()) {
  110. toast.error('Please enter name')
  111. resolve(false)
  112. return
  113. }
  114. if (!formData.value.phone.trim()) {
  115. toast.error('Please enter phone number')
  116. resolve(false)
  117. return
  118. }
  119. // 验证手机号格式
  120. const phoneRegex = /^1[3-9]\d{9}$/
  121. if (!phoneRegex.test(formData.value.phone)) {
  122. toast.error('Please enter valid phone number')
  123. resolve(false)
  124. return
  125. }
  126. if (!formData.value.verifyCode.trim()) {
  127. toast.error('Please enter verification code')
  128. resolve(false)
  129. return
  130. }
  131. if (!formData.value.pwd.trim()) {
  132. toast.error('Please enter password')
  133. resolve(false)
  134. return
  135. }
  136. // 验证密码长度
  137. if (formData.value.pwd.length < 6 || formData.value.pwd.length > 20) {
  138. toast.error('Password should be 6-20 characters')
  139. resolve(false)
  140. return
  141. }
  142. resolve(true)
  143. })
  144. }
  145. // 页面卸载时清理定时器
  146. onUnmounted(() => {
  147. if (countdownTimer.value) {
  148. clearInterval(countdownTimer.value)
  149. }
  150. })
  151. </script>
  152. <template>
  153. <view class="register-page min-h-screen bg-white">
  154. <!-- 背景图片区域 -->
  155. <view class="auth-bg-section relative">
  156. <!-- 自定义导航栏 -->
  157. <view :style="{ paddingTop: `${safeAreaInsets?.top}px` }">
  158. <view class="h-88rpx flex items-center px-24rpx">
  159. <wd-icon name="thin-arrow-left" size="32rpx" @click="goBack" />
  160. </view>
  161. </view>
  162. <!-- Logo和标语 -->
  163. <view class="pb-40rpx pt-60rpx text-center">
  164. <view class="mb-20rpx flex items-center justify-center">
  165. <image src="/static/logo.png" class="mr-16rpx h-60rpx w-60rpx" />
  166. </view>
  167. </view>
  168. </view>
  169. <!-- 表单内容区域 -->
  170. <view class="flex flex-col px-20rpx">
  171. <view class="mb-40rpx" />
  172. <!-- 注册表单 -->
  173. <wd-form ref="form" :model="formData">
  174. <view class="mb-40rpx space-y-32rpx">
  175. <wd-input
  176. v-model="formData.name"
  177. prop="name"
  178. placeholder="Username"
  179. no-border
  180. custom-class="bandhu-auth-input-field"
  181. />
  182. <wd-input
  183. v-model="formData.phone"
  184. prop="phone"
  185. placeholder="+88 Mobile number"
  186. no-border
  187. custom-class="bandhu-auth-input-field"
  188. />
  189. <view class="flex items-center gap-20rpx">
  190. <wd-input
  191. v-model="formData.verifyCode"
  192. prop="verifyCode"
  193. placeholder="Verification Code"
  194. no-border
  195. custom-class="flex-1 bandhu-auth-input-field"
  196. />
  197. <wd-button
  198. type="error"
  199. plain
  200. :disabled="countdown > 0"
  201. custom-class="bandhu-auth-secondary-btn"
  202. @click="getVerificationCode"
  203. >
  204. {{ countdown > 0 ? `${countdown}s` : 'Get Code' }}
  205. </wd-button>
  206. </view>
  207. <wd-input
  208. v-model="formData.pwd"
  209. prop="pwd"
  210. placeholder="Password 6-20 characters"
  211. no-border
  212. show-password
  213. custom-class="bandhu-auth-input-field"
  214. />
  215. <wd-input
  216. v-model="formData.code"
  217. placeholder="Referrer Code"
  218. no-border
  219. custom-class="bandhu-auth-input-field"
  220. />
  221. </view>
  222. <!-- 注册按钮 -->
  223. <wd-button
  224. type="error"
  225. size="large"
  226. custom-class="mb-200rpx w-full bandhu-auth-primary-btn"
  227. @click="handleRegister"
  228. >
  229. Register
  230. </wd-button>
  231. </wd-form>
  232. <!-- 登录提示 -->
  233. <view class="text-center">
  234. <text class="text-28rpx text-#666">
  235. Already have account?
  236. </text>
  237. <text class="ml-10rpx text-28rpx text-[var(--wot-color-theme)]" @click="toPage('/pages/login/login')">
  238. Login Now
  239. </text>
  240. </view>
  241. </view>
  242. </view>
  243. </template>
  244. <style lang="scss" scoped>
  245. // 注册页面特有样式(如果有的话)
  246. </style>