index.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <template>
  2. <div>
  3. <v-form @submit.prevent ref="phoneForm">
  4. <v-text-field v-model="loginData.phone" :disabled="props.phoneDisabled" :placeholder="$t('login.mobileNumberPlaceholder')" color="primary" variant="outlined" density="compact" :rules="phoneRules" validate-on="input">
  5. <template v-slot:prepend-inner>
  6. <span class="d-flex">
  7. <v-icon icon="mdi-cellphone" size="20"></v-icon>
  8. <span class="d-flex" id="menu-activator">
  9. <span class="phone-number">{{ currentArea }}</span>
  10. <v-icon size="20">mdi-chevron-down</v-icon>
  11. </span>
  12. <v-menu activator="#menu-activator">
  13. <v-list>
  14. <v-list-item v-for="(item, index) in items" :key="index" :value="index" @click="handleChangeCurrentArea(item)">
  15. <v-list-item-title>{{ item.label }}</v-list-item-title>
  16. </v-list-item>
  17. </v-list>
  18. </v-menu>
  19. </span>
  20. </template>
  21. </v-text-field>
  22. <v-text-field
  23. v-model="loginData.code"
  24. :placeholder="$t('login.enterCode')"
  25. color="primary"
  26. variant="outlined"
  27. density="compact"
  28. prepend-inner-icon="mdi-security"
  29. :rules="[v=> !!v || $t('login.enterCode')]"
  30. @keyup.enter="handleEnter"
  31. >
  32. <template #append-inner>
  33. <span v-if="showCode" class="login-code" @click="handleCode">{{ $t('login.getSmsCode') }}</span>
  34. <span v-else class="disable">{{ $t('login.retrieveAgain') }}{{ count }}s</span>
  35. </template>
  36. </v-text-field>
  37. </v-form>
  38. </div>
  39. </template>
  40. <script setup>
  41. defineOptions({ name: 'verification-code' })
  42. import { ref, reactive, defineExpose, defineEmits } from 'vue'
  43. import { setCodeTime } from '@/utils/code'
  44. import { sendSmsCode } from '@/api/common/index'
  45. import { useI18n } from '@/hooks/web/useI18n'
  46. import Snackbar from '@/plugins/snackbar'
  47. const emits = defineEmits(['handleEnter'])
  48. const { t } = useI18n()
  49. const props = defineProps({ phoneDisabled: Boolean })
  50. const phoneRules = ref([
  51. value => {
  52. if (value) return true
  53. return t('login.mobileNumberPlaceholder')
  54. },
  55. value => {
  56. if (value?.length <= 11 && /^1[3456789]\d{9}$/.test(value)) return true
  57. return t('login.correctPhoneNumber')
  58. }
  59. ])
  60. // 手机号区域
  61. const currentArea = ref('0086')
  62. const items = [
  63. { label: '中国大陆-0086', value: '0086' }
  64. ]
  65. const handleChangeCurrentArea = (e) => {
  66. currentArea.value = e.value
  67. }
  68. // 获取验证码
  69. const showCode = ref(true)
  70. const count = ref(0)
  71. const timer = ref(null)
  72. const handleCode = () => {
  73. if (!loginData.phone) {
  74. Snackbar.warning(t('login.mobileNumberPlaceholder'))
  75. return
  76. }
  77. count.value = 60
  78. setTime()
  79. getSmsCode()
  80. }
  81. const getSmsCode = async () => {
  82. const query = {
  83. phone: loginData.phone,
  84. scene: 30
  85. }
  86. // try {
  87. await sendSmsCode(query)
  88. Snackbar.success(t('login.sendCode'))
  89. // } catch (error) {
  90. // Snackbar.error(error.msg)
  91. // }
  92. }
  93. const setTime = () => {
  94. showCode.value = false
  95. timer.value = setInterval(() => {
  96. let number = count.value
  97. if (number > 0 && number <= 60) {
  98. count.value--
  99. setCodeTime(number - 1)
  100. } else {
  101. showCode.value = true
  102. clearInterval(timer.value)
  103. timer.value = null
  104. }
  105. }, 1000)
  106. }
  107. const autoTimer = () => {
  108. count.value = 0
  109. if(!count.value) return
  110. setTime()
  111. }
  112. autoTimer()
  113. const loginUserPhone = localStorage.getItem('loginUserPhone') || '13229740091'
  114. const loginData = reactive({
  115. phone: loginUserPhone, // 13229740091 小梅 // 15775026250 瑞森
  116. code: '123456'
  117. })
  118. const phoneForm = ref()
  119. const handleEnter = () => {
  120. emits('handleEnter')
  121. }
  122. defineExpose({
  123. loginData,
  124. phoneForm
  125. })
  126. </script>
  127. <style lang="scss" scoped>
  128. .login-code {
  129. width: 97px;
  130. color: var(--v-primary-base);
  131. text-align: end;
  132. font-size: 12px;
  133. cursor: pointer;
  134. }
  135. .disable {
  136. width: 72px;
  137. color: grey;
  138. font-size: 12px;
  139. }
  140. .phone-number {
  141. width: 34px;
  142. font-size: 12px;
  143. }
  144. </style>