register.vue 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <template>
  2. <div class="root">
  3. <div class="logo">
  4. <img alt="哪吒乐跑" src="/logo.svg" height="40">
  5. <span class="title">哪吒乐跑 | 用户注册</span>
  6. </div>
  7. <a-form size="large" ref="formRef" :model="form" :rules="[]" class="form" @submit="handleSubmit">
  8. <a-form-item field="username" hide-label
  9. :rules="[{ required: true, message: '用户名不能为空' }, { minLength: 4, maxLength: 12, message: '用户名长度需在4~12位间' }]"
  10. :validate-trigger="['change']">
  11. <a-input placeholder="请输入用户名" allow-clear v-model="form.username">
  12. <template #prefix>
  13. <icon-user />
  14. </template>
  15. </a-input>
  16. </a-form-item>
  17. <a-form-item field="password" hide-label
  18. :rules="[{ required: true, message: '密码不能为空' }, { maxLength: 16, minLength: 8, message: '密码长度需在8~16位之间' }]"
  19. :validate-trigger="['change']">
  20. <a-input-password placeholder="请输入密码" allow-clear v-model="form.password">
  21. <template #prefix>
  22. <icon-lock />
  23. </template>
  24. </a-input-password>
  25. </a-form-item>
  26. <a-form-item field="password2" hide-label
  27. :rules="[{ required: true, message: '请再次输入密码' }, { maxLength: 16, minLength: 8, message: '密码长度需在8~16位之间' }]"
  28. :validate-trigger="['change']">
  29. <a-input-password placeholder="请再次输入密码" allow-clear v-model="form.password2">
  30. <template #prefix>
  31. <icon-lock />
  32. </template>
  33. </a-input-password>
  34. </a-form-item>
  35. <!-- <a-form-item field="email" hide-label :rules="[{ type: 'email', required: true, message: '请填写正确的邮箱地址' }]"
  36. :validate-trigger="['change']">
  37. <a-input placeholder="请输入邮箱" allow-clear v-model="form.email">
  38. <template #prefix>
  39. <icon-email />
  40. </template>
  41. </a-input>
  42. </a-form-item> -->
  43. <a-form-item field="captcha" hide-label :rules="[{ length: 4, required: true, message: '请正确填写图片验证码' }]">
  44. <a-input placeholder="请输入图片验证码" allow-clear v-model="form.captcha">
  45. <template #prefix>
  46. <icon-check-circle />
  47. </template>
  48. <template #append>
  49. <img alt="!点我重试" :src="ImageCaptcha" class="captcha" @click="getCaptcha()"
  50. v-if="!captchaLoading">
  51. <icon-loading v-else />
  52. </template>
  53. </a-input>
  54. </a-form-item>
  55. <!-- <a-form-item field="code" hide-label :rules="[{ length: 6, required: true, message: '请正确填写邮箱验证码' }]">
  56. <a-input placeholder="请输入邮箱验证码" allow-clear v-model="form.code">
  57. <template #prefix>
  58. <icon-code-square />
  59. </template>
  60. <template #append>
  61. <a-button type="text" style="width: 80px" @click="SendEmail" :disabled="state.smsSendBtn">
  62. <span v-if="!state.smsSendBtn">获取验证码</span>
  63. <span v-else>{{ state.time }} s</span>
  64. </a-button>
  65. </template>
  66. </a-input>
  67. </a-form-item> -->
  68. <a-button type="text" class="forgetpass" @click="emit('changeMode', 'login')">已有账号,去登录</a-button>
  69. <a-button :style="{ marginTop: '15px' }" class="formitem" type="primary" html-type="submit"
  70. :loading="state.okButton">立即注册</a-button>
  71. </a-form>
  72. </div>
  73. </template>
  74. <script setup>
  75. import { getImageCaptcha, sendEmail, register } from '@/api/login'
  76. import { Notification, Message } from '@arco-design/web-vue';
  77. import { ref, reactive, defineEmits } from 'vue'
  78. const emit = defineEmits(['changeMode'])
  79. const formRef = ref(null)
  80. let captchaLoading = ref(false)
  81. let CaptchaId = ref('')
  82. let ImageCaptcha = ref('')
  83. let form = reactive({
  84. username: '',
  85. password: '',
  86. password2: '',
  87. email: '',
  88. code: '',
  89. captcha: ''
  90. })
  91. let state = reactive({
  92. smsSendBtn: false,
  93. time: 60,
  94. okButton: false
  95. })
  96. const SendEmail = async () => {
  97. try {
  98. const v = await formRef.value.validateField(['email', 'captcha'])
  99. if (v) return
  100. let email = form.email
  101. let text = form.captcha
  102. state.smsSendBtn = true
  103. const interval = window.setInterval(() => {
  104. if (state.time-- <= 0) {
  105. state.time = 60
  106. state.smsSendBtn = false
  107. window.clearInterval(interval)
  108. }
  109. }, 1000)
  110. Message.loading('验证码发送中..')
  111. const res = await sendEmail({ email, text, id: CaptchaId.value, type: 'register' })
  112. if (!res || res.code != 0) {
  113. state.time = 60
  114. state.smsSendBtn = false
  115. window.clearInterval(interval)
  116. getImageCaptcha()
  117. form.captcha = ''
  118. if (res.code === -10501) {
  119. return Notification.error({
  120. title: '验证码输入错误',
  121. content: res?.msg ?? '请求出现错误,请稍后再试'
  122. })
  123. }
  124. return Notification.error({
  125. title: '获取验证码失败',
  126. content: res?.msg ?? '请求出现错误,请稍后再试'
  127. })
  128. }
  129. } catch (error) {
  130. Message.error('验证码发送失败')
  131. }
  132. }
  133. const getCaptcha = async () => {
  134. try {
  135. captchaLoading.value = true
  136. const res = await getImageCaptcha()
  137. if (!res || res.code != 0)
  138. return requestFailed('获取图片验证码失败!' + res?.msg ?? '')
  139. ImageCaptcha.value = res.data.img
  140. CaptchaId.value = res.data.id
  141. } catch (error) {
  142. requestFailed('获取图片验证码失败!')
  143. } finally {
  144. captchaLoading.value = false
  145. }
  146. }
  147. getCaptcha()
  148. const handleSubmit = async ({ values, errors }) => {
  149. try {
  150. state.okButton = true
  151. const v = await formRef.value.validate()
  152. if (v) return
  153. let data = { ...values }
  154. if (data.password !== data.password2) return Message.error('请确保两次输入的密码一致!')
  155. data.password = btoa(data.password)
  156. data.id = CaptchaId.value
  157. const res = await register(data)
  158. if (!res || res.code !== 0)
  159. return requestFailed(res.msg)
  160. Message.success('注册成功!请登录')
  161. emit('changeMode', 'login')
  162. } catch (error) {
  163. requestFailed(error.message)
  164. } finally {
  165. state.okButton = false
  166. }
  167. }
  168. const requestFailed = (msg) => {
  169. Notification.error({
  170. title: '错误',
  171. content: msg || '请求出现错误,请稍后再试',
  172. })
  173. }
  174. </script>
  175. <style scoped>
  176. .root {
  177. display: flex;
  178. gap: 40px;
  179. flex-direction: column;
  180. align-items: center;
  181. justify-content: center;
  182. margin: 20px
  183. }
  184. .form {
  185. width: 100%;
  186. }
  187. .formitem {
  188. width: 350px;
  189. min-height: 35px
  190. }
  191. .logo {
  192. display: flex
  193. }
  194. .logo .title {
  195. color: #f53f3f;
  196. font-size: 1.8em;
  197. font-weight: bold;
  198. margin-left: 15px;
  199. font-family: Alimama ShuHeiTi, -apple-system, BlinkMacSystemFont;
  200. }
  201. .forgetpass {
  202. width: 130px;
  203. margin-top: -10px;
  204. }
  205. .captcha {
  206. max-height: 35px;
  207. margin-right: -10px;
  208. }
  209. </style>