123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- <template>
- <div>
- <v-form @submit.prevent ref="phoneForm">
- <v-text-field
- v-if="props.showEmailInput"
- v-model="loginData.email"
- placeholder="请输入企业邮箱"
- color="primary"
- variant="outlined"
- density="compact"
- validate-on="input"
- prepend-inner-icon="mdi-email"
- :rules="emailRules"
- ></v-text-field>
- <v-text-field v-model="loginData.phone" counter="11" :disabled="props.phoneDisabled" :placeholder="$t('login.mobileNumberPlaceholder')" color="primary" variant="outlined" density="compact" :rules="phoneRules" validate-on="input">
- <template v-slot:prepend-inner>
- <span class="d-flex">
- <v-icon icon="mdi-cellphone" size="20"></v-icon>
- <!-- <span class="d-flex" id="menu-activator">
- <span class="phone-number">{{ currentArea }}</span>
- <v-icon size="20">mdi-chevron-down</v-icon>
- </span>
- <v-menu activator="#menu-activator">
- <v-list>
- <v-list-item v-for="(item, index) in items" :key="index" :value="index" @click="handleChangeCurrentArea(item)">
- <v-list-item-title>{{ item.label }}</v-list-item-title>
- </v-list-item>
- </v-list>
- </v-menu> -->
- </span>
- </template>
- </v-text-field>
- <v-text-field
- v-model="loginData.code"
- :placeholder="$t('login.enterCode')"
- color="primary"
- variant="outlined"
- density="compact"
- prepend-inner-icon="mdi-security"
- :rules="codeValid"
- @keyup.enter="handleEnter"
- >
- <template #append-inner>
- <span v-if="showCode" class="login-code" @click="handleCode">{{ $t('login.getSmsCode') }}</span>
- <span v-else class="disable">{{ $t('login.retrieveAgain') }}{{ count }}s</span>
- </template>
- </v-text-field>
- </v-form>
- </div>
- </template>
- <script setup>
- defineOptions({ name: 'verification-code' })
- import { ref, reactive } from 'vue'
- import { setCodeTime } from '@/utils/code'
- import { checkEmail } from '@/utils/validate'
- import { sendSmsCode } from '@/api/common/index'
- import { useI18n } from '@/hooks/web/useI18n'
- import Snackbar from '@/plugins/snackbar'
- const emits = defineEmits(['handleEnter'])
- const { t } = useI18n()
- const props = defineProps({
- phoneDisabled: Boolean,
- phone: String,
- showEmailInput: { // 需要输入邮箱
- type: Boolean,
- default: false
- },
- scene: { // 短信验证码scene参数: 30-手机号登陆 31-修改手机 32-修改密码 33-忘记密码
- type: [Number, String],
- default: 30
- }
- })
- const phoneRules = ref([
- value => {
- if (value) return true
- return t('login.mobileNumberPlaceholder')
- },
- value => {
- if (value?.length <= 11 && /^1[3456789]\d{9}$/.test(value)) return true
- return t('login.correctPhoneNumber')
- }
- ])
- const codeValid = ref([
- value => {
- if (value) return true
- return '请输入验证码'
- },
- value => {
- if (/^\d{6}$/.test(value)) return true
- return '请输入正确格式的六位数字验证码'
- }
- ])
- const emailRules = ref([
- value => {
- if (value) return true
- return props.placeholder ? props.placeholder : '请输入企业邮箱'
- },
- value => {
- if (checkEmail(value)) return true
- return '请输入正确的企业邮箱'
- }
- ])
- // 手机号区域
- // const currentArea = ref('0086')
- // const items = [
- // { label: '中国大陆-0086', value: '0086' }
- // ]
- // const handleChangeCurrentArea = (e) => {
- // currentArea.value = e.value
- // }
- // 获取验证码
- const showCode = ref(true)
- const count = ref(0)
- const timer = ref(null)
- const handleCode = () => {
- if (!loginData.phone) {
- Snackbar.warning(t('login.mobileNumberPlaceholder'))
- return
- }
- count.value = 60
- setTime()
- getSmsCode()
- }
- const getSmsCode = async () => {
- const query = {
- phone: loginData.phone,
- scene: props.scene ? props.scene-0 : 30
- }
- // try {
- await sendSmsCode(query)
- Snackbar.success(t('login.sendCode'))
- // } catch (error) {
- // Snackbar.error(error.msg)
- // }
- }
- const setTime = () => {
- showCode.value = false
- timer.value = setInterval(() => {
- let number = count.value
- if (number > 0 && number <= 60) {
- count.value--
- setCodeTime(number - 1)
- } else {
- showCode.value = true
- clearInterval(timer.value)
- timer.value = null
- }
- }, 1000)
- }
- const autoTimer = () => {
- count.value = 0
- if(!count.value) return
- setTime()
- }
- autoTimer()
- const loginUserPhone = localStorage.getItem('loginUserPhone') || ''
- const loginData = reactive({
- email: '',
- phone: loginUserPhone,
- code: ''
- })
- if (props.phone) loginData.phone = props.phone
- const phoneForm = ref()
- const handleEnter = () => {
- emits('handleEnter')
- }
- const resetPhone = () => {
- loginData.phone = ''
- loginData.code = ''
- count.value = 0
- }
- defineExpose({
- resetPhone,
- loginData,
- phoneForm
- })
- </script>
- <style lang="scss" scoped>
- .login-code {
- width: 97px;
- color: var(--v-primary-base);
- text-align: end;
- font-size: 12px;
- cursor: pointer;
- }
- .disable {
- width: 72px;
- color: grey;
- font-size: 12px;
- }
- .phone-number {
- width: 34px;
- font-size: 12px;
- }
- </style>
|