Files
WAI_Project_UNIX/components/sms-btn.uvue

222 lines
4.0 KiB
Plaintext

<template>
<slot :disabled="isDisabled" :countdown="countdown" :btnText="btnText">
<cl-button text :disabled="isDisabled" @tap="open">
{{ btnText }}
</cl-button>
</slot>
<cl-popup
v-model="captcha.visible"
ref="popupRef"
direction="center"
:title="t('获取短信验证码')"
:size="500"
>
<view class="p-3 pt-2 pb-4 w-full" v-if="captcha.visible">
<view class="flex flex-row items-center">
<cl-input
v-model="code"
:placeholder="t('验证码')"
:maxlength="4"
autofocus
:clearable="false"
:pt="{
className: 'flex-1 mr-2 !h-[70rpx]'
}"
@confirm="send"
></cl-input>
<view
class="dark:!bg-surface-800 bg-surface-100 rounded-lg h-[70rpx] w-[200rpx] flex flex-row justify-center items-center"
@tap="getCaptcha"
>
<cl-loading v-if="captcha.loading" :size="28"></cl-loading>
<cl-svg
v-else
class="h-full w-full pointer-events-none"
:src="captcha.img"
></cl-svg>
</view>
</view>
<cl-button
type="primary"
:disabled="code == ''"
:loading="captcha.sending"
:pt="{
className: '!h-[70rpx] mt-3'
}"
@tap="send"
>
{{ t("发送短信") }}
</cl-button>
</view>
</cl-popup>
</template>
<script lang="ts" setup>
import { computed, reactive, ref } from "vue";
import { useUi } from "@/uni_modules/cool-ui";
import { $t, t } from "@/locale";
import { isDark, parse, service, type Response } from "@/cool";
const props = defineProps({
phone: String
});
const emit = defineEmits(["success"]);
const popupRef = ref<ClPopupComponentPublicInstance | null>(null);
const ui = useUi();
type Captcha = {
visible: boolean;
loading: boolean;
sending: boolean;
img: string;
};
// 验证码
const captcha = reactive<Captcha>({
visible: false,
loading: false,
sending: false,
img: ""
});
// 倒计时
const countdown = ref(0);
// 是否禁用
const isDisabled = computed(() => countdown.value > 0 || props.phone == "");
// 按钮文案
const btnText = computed(() =>
countdown.value > 0 ? $t("{n}s后重新获取", { n: countdown.value }) : t("获取验证码")
);
const code = ref("");
const captchaId = ref("");
// 清空
function clear() {
code.value = "";
captchaId.value = "";
}
// 关闭
function close() {
captcha.visible = false;
captcha.img = "";
clear();
}
// 开始倒计时
function startCountdown() {
countdown.value = 60;
let timer: number = 0;
function fn() {
countdown.value--;
if (countdown.value < 1) {
clearInterval(timer);
}
}
// @ts-ignore
timer = setInterval(() => {
fn();
}, 1000);
fn();
}
// 获取图片验证码
async function getCaptcha() {
clear();
captcha.loading = true;
type Res = {
captchaId: string;
data: string;
};
await service.user.login
.captcha({ color: isDark.value ? "#ffffff" : "#2c3142", phone: props.phone })
.then((res) => {
const data = parse<Res>(res)!;
captchaId.value = data.captchaId;
captcha.img = data.data;
})
.catch((err) => {
ui.showToast({
message: (err as Response).message!
});
});
setTimeout(() => {
captcha.loading = false;
}, 200);
}
// 发送短信
async function send() {
if (code.value != "") {
captcha.sending = true;
await service.user.login
.smsCode({
phone: props.phone,
code: code.value,
captchaId: captchaId.value
})
.then(() => {
ui.showToast({
message: t("短信已发送,请查收")
});
startCountdown();
close();
emit("success");
})
.catch((err) => {
ui.showToast({
message: (err as Response).message!
});
getCaptcha();
});
captcha.sending = false;
} else {
ui.showToast({
message: t("请填写验证码")
});
}
}
// 打开
function open() {
if (props.phone != "") {
if (/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(props.phone!)) {
captcha.visible = true;
getCaptcha();
} else {
ui.showToast({
message: t("请填写正确的手机号格式")
});
}
}
}
defineExpose({
open,
send,
getCaptcha,
startCountdown
});
</script>