155 lines
4.6 KiB
Vue
155 lines
4.6 KiB
Vue
<template>
|
|
<tm-modal :show="state.show" :overlayClick="false" position="bottom" :showCancel="props.showCancel" title="您的设备需要验证"
|
|
height="650rpx" zIndex="100000" cancelText="取消" confirmText="确认" @close="props.close">
|
|
<tm-form ref="formRef" v-model="form" :rules="formRules" direction="vertical">
|
|
<tm-form-item name="mobilePhone" label="手机号">
|
|
<tm-input :disabled="state.fixedPhone" v-model.trim="form.mobilePhone" :maxlength="11"
|
|
placeholder="请输入手机号" />
|
|
</tm-form-item>
|
|
<view class="verify-device-imp-model__spacer" />
|
|
<tm-form-item name="code" label="验证码">
|
|
<tm-input v-model.trim="form.code" :maxlength="6" placeholder="请输入验证码"
|
|
:disabled="form.mobilePhone.length != 11">
|
|
<template v-slot:right>
|
|
<tm-button class="verify-device-imp-model__code-btn" color="primary" size="m" @click="getCode"
|
|
:disabled="state.codeBtnDisabled">
|
|
<text>获取验证码</text><text v-if="state.isTiming">{{ state.countDown }} s</text>
|
|
</tm-button>
|
|
</template>
|
|
</tm-input>
|
|
</tm-form-item>
|
|
</tm-form>
|
|
<template #footer>
|
|
<tm-button block color="primary" @tap="doSubmit" :disabled="state.verifyBtnDisabled">验 证</tm-button>
|
|
</template>
|
|
</tm-modal>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, reactive, watch, onUnmounted } from "vue"
|
|
|
|
import { constant } from "@@/index"
|
|
import { userApi } from "@@/api"
|
|
import { getMiniUniqueCode, getDeviceKey } from "@@/utils/mini-tool"
|
|
import { buildUserDeviceFingerprint } from "@@/utils/device-unique"
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
showCancel?: boolean
|
|
close?: () => void
|
|
}>(),
|
|
{
|
|
showCancel: true,
|
|
close: () => void 0,
|
|
},
|
|
)
|
|
|
|
const formRef = ref()
|
|
const form = reactive<any>({
|
|
mobilePhone: "",
|
|
code: "",
|
|
})
|
|
const state = reactive({
|
|
show: false,
|
|
fixedPhone: "",
|
|
countDown: 60,
|
|
codeBtnDisabled: true,
|
|
verifyBtnDisabled: false,
|
|
isTiming: false,
|
|
})
|
|
const formRules = reactive<any>({
|
|
mobilePhone: [{ required: true, message: "请输入手机号" }],
|
|
code: [{ required: true, message: "请输入验证码" }],
|
|
})
|
|
let timer: any = null
|
|
|
|
// 获取验证码
|
|
const getCode = async () => {
|
|
if (state.codeBtnDisabled) return
|
|
|
|
try {
|
|
uni.showLoading({ title: "发送中...", mask: true })
|
|
const res: any = await userApi.getMobilePhoneCode(form.mobilePhone)
|
|
if (res.code == 0) {
|
|
state.codeBtnDisabled = true
|
|
state.isTiming = true
|
|
timer = setInterval(() => {
|
|
state.countDown--
|
|
if (state.countDown === 0) {
|
|
state.isTiming = false
|
|
state.codeBtnDisabled = false
|
|
state.countDown = 60
|
|
clearInterval(timer)
|
|
}
|
|
}, 1000)
|
|
} else {
|
|
uni.showToast({ title: res.msg || "验证码发送失败", icon: "none" })
|
|
}
|
|
} catch (error: any) {
|
|
uni.showToast({ title: error.message, icon: "none" })
|
|
} finally {
|
|
uni.hideLoading()
|
|
}
|
|
}
|
|
|
|
watch(
|
|
() => form.mobilePhone,
|
|
(val) => {
|
|
if (val.length == 11) {
|
|
state.codeBtnDisabled = false
|
|
} else {
|
|
state.codeBtnDisabled = true
|
|
}
|
|
},
|
|
)
|
|
|
|
// 提交设备验证
|
|
const doSubmit = async () => {
|
|
formRef.value.submit()
|
|
const { isPass } = formRef.value.validate()
|
|
if (!isPass) return
|
|
|
|
uni.showLoading({ title: "验证中...", mask: true })
|
|
const fingerprint = await buildUserDeviceFingerprint(false)
|
|
const params = {
|
|
mobilePhone: form.mobilePhone,
|
|
code: form.code,
|
|
deviceUniqueCode: fingerprint?.fingerprint,
|
|
}
|
|
const res: any = await userApi.verifyDevice(params)
|
|
if (res.code != 0) {
|
|
uni.showToast({ title: res.msg || "验证失败", icon: "none" })
|
|
return
|
|
}
|
|
uni.hideLoading()
|
|
uni.showToast({ title: "设备验证成功", icon: "none" })
|
|
state.show = false
|
|
}
|
|
|
|
function openDialog(fixedPhone?: string) {
|
|
state.fixedPhone = fixedPhone ?? ""
|
|
form.mobilePhone = fixedPhone ?? ""
|
|
state.show = true
|
|
}
|
|
|
|
defineExpose({
|
|
openDialog,
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
clearInterval(timer)
|
|
})
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.verify-device-imp-model__spacer {
|
|
height: 10rpx;
|
|
}
|
|
|
|
.verify-device-imp-model__code-btn {
|
|
margin-left: 20rpx;
|
|
padding-left: 16rpx;
|
|
padding-right: 16rpx;
|
|
}
|
|
</style>
|