hookehuyr

✨ feat(手机验证码组件): 提交表单数据后,校验后弹框手机号绑定

......@@ -24,6 +24,7 @@ declare module '@vue/runtime-core' {
GroupField: typeof import('./src/components/GroupField/index.vue')['default']
IdentityField: typeof import('./src/components/IdentityField/index.vue')['default']
ImageUploaderField: typeof import('./src/components/ImageUploaderField/index.vue')['default']
LoginBox: typeof import('./src/components/LoginBox/index.vue')['default']
MarqueeField: typeof import('./src/components/MarqueeField/index.vue')['default']
MultiRuleField: typeof import('./src/components/MultiRuleField/index.vue')['default']
MyComponent: typeof import('./src/components/AppointmentField/MyComponent.vue')['default']
......
<template>
<div class="login-section">
<van-config-provider :theme-vars="themeVars">
<van-form ref="form" @submit="onSubmit">
<van-cell-group inset style="border: 1px solid #EAEAEA;">
<van-field v-if="use_widget" v-model="phone" name="phone" label="手机号" placeholder="手机号" readonly clickable
:rules="[{ validator, message: '请输入正确手机号' }]"
@touchstart.stop="showKeyboard" />
<van-field v-else v-model="phone" name="phone" label="手机号" placeholder="手机号"
:rules="[{ validator, message: '请输入正确手机号' }]" />
<van-field v-model="code" center clearable name="code" type="digit" label="短信验证码" placeholder="请输入短信验证码"
:formatter="formatter" :rules="[{ required: true, message: '请填写验证码' }]">
<template #button>
<van-button @click="sendCode" v-if="countDown.current.value.total === limit" size="small" type="primary"
:disabled="disabled">
<span>发送验证码</span>
</van-button>
<van-button v-else size="small" type="primary" :disabled="disabled">
<span>{{ countDown.current.value.seconds }} 秒重新发送</span>
</van-button>
</template>
</van-field>
</van-cell-group>
</van-form>
</van-config-provider>
</div>
<van-number-keyboard v-model="phone" :show="keyboard_show" :maxlength="11" @blur="onBlur" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useCountDown } from '@vant/use';
import { wxInfo } from '@/utils/tools';
import { styleColor } from '@/constant.js';
import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
const $route = useRoute();
const $router = useRouter();
const emit = defineEmits(['on-submit'])
const form = ref(null);
const submit = () => {
let valid = form.value.validate();
valid
.then(() => {
form.value.submit();
})
.catch(error => {
console.error(error);
Toast({
message: '请检查后再次提交',
icon: 'cross',
});
})
}
defineExpose({
submit
})
const themeVars = {
buttonPrimaryBackground: styleColor.baseColor,
buttonPrimaryBorderColor: styleColor.baseColor,
buttonPrimaryColor: styleColor.baseFontColor,
CellVerticalPadding: '14px'
};
const onSubmit = () => {
emit('on-submit', {
phone: phone.value,
code: code.value,
})
}
// 判断是否显示控件
let use_widget = ref(true);
/**
* 手机号码校验
* 函数返回 true 表示校验通过,false 表示不通过
* @param {*} val
*/
const validator = (val) => {
let flag = false;
// 简单判断手机号位数
if (/1\d{10}/.test(val) && phone.value.length === 11) {
disabled.value = false;
flag = true;
} else {
disabled.value = true;
flag = false;
}
return flag
};
const phone = ref('');
const code = ref('');
// TAG: 开发环境测试数据
if (import.meta.env.DEV) {
phone.value = import.meta.env.VITE_ID
code.value = import.meta.env.VITE_PIN
}
onMounted(() => {
/**
* 判断微信环境看是否弹出控件框
* 桌面微信直接输入
* 其他环境弹出输入框
*/
if (wxInfo().isiOS || wxInfo().isAndroid) {
use_widget.value = true;
} else {
use_widget.value = false;
}
})
// 手机号输入控件控制
const keyboard_show = ref(false);
const showKeyboard = () => { // 弹出数字弹框
keyboard_show.value = true;
};
const onBlur = () => { // 数字键盘失焦回调
keyboard_show.value = false;
if (phone.value.length === 11) {
disabled.value = false;
}
};
// 设置发送短信倒计时
// TAG: vant 自带倒计时函数
const limit = ref(60000); // 配置倒计时秒数
const countDown = useCountDown({
// 倒计时 24 小时
time: limit.value,
onFinish: () => {
countDown.reset();
}
});
const sendCode = () => { // 发送验证码
countDown.start();
axios.post('/srv/?a=bind_phone&t=get_code', {
phone: phone.value
})
.then(res => {
if (res.data.code === 1) {
Toast.success('发送成功');
} else {
console.warn(res.data);
if (!res.data.show) return false;
Toast({
message: res.data.msg,
icon: 'close',
});
}
})
.catch(err => {
console.error(err);
})
};
const disabled = ref(true);
// 过滤输入的数字 只能四位
const formatter = (value) => value.substring(0, 4);
</script>
<style lang="less" scoped>
</style>
<template>
<login-box ref="form" @on-submit="onSubmit"></login-box>
<div class="btn" @click="submit">
登&nbsp;录
</div>
</template>
<script setup>
import LoginBox from '@/components/LoginBox'
import { onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import {
Cookies,
$,
_,
axios,
storeToRefs,
mainStore,
Toast,
useTitle,
} from '@/utils/generatePackage.js';
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
const form = ref(null);
const submit = () => {
form.value.submit();
}
const onSubmit = (values) => {
axios.post('/srv/?a=b_login', {
phone: values.phone,
pin: values.code,
})
.then(res => {
if (res.data.code === 1) {
$router.push({
path: '/business/index'
});
} else {
console.warn(res.data);
Toast({
message: res.data.msg,
icon: 'close',
});
}
})
.catch(err => {
console.error(err);
})
};
</script>
<style
lang="less"
scoped>
</style>
<!--
* @Date: 2022-07-18 10:22:22
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-06-24 16:30:22
* @LastEditTime: 2024-06-26 10:29:41
* @FilePath: /data-table/src/views/index.vue
* @Description: 首页
-->
......@@ -113,6 +113,20 @@
close-on-click-action
@cancel="onApprovalCancel"
/>
<van-overlay :show="bind_tel_show" z-index="100">
<div class="bind-tel-wrapper">
<div class="block">
<div style="text-align: center; padding: 1rem; padding-top: 0; font-weight: bold;">手机号绑定</div>
<login-box ref="bindForm" @on-submit="onBindSubmit"></login-box>
<div style="padding: 1rem; padding-bottom: 0;">
<van-button round block type="primary" :color="styleColor.baseColor" @click="bindSubmit">
绑&nbsp;定
</van-button>
</div>
</div>
</div>
</van-overlay>
</template>
<script setup>
......@@ -131,11 +145,12 @@ import {
import { useRoute } from "vue-router";
import { queryFormAPI, postVerifyPasswordAPI } from "@/api/form.js";
import { addFormDataAPI, queryFormDataAPI, modiFormDataAPI } from "@/api/data.js";
import { showSuccessToast, showFailToast } from "vant";
import { showSuccessToast, showFailToast, showConfirmDialog } from "vant";
import { wxInfo, getUrlParams } from "@/utils/tools";
import { styleColor } from "@/constant.js";
import { sharePage } from '@/composables/useShare.js'
import wx from 'weixin-js-sdk'
import LoginBox from '@/components/LoginBox/index.vue';
// 获取表单设置
const store = mainStore();
......@@ -259,6 +274,53 @@ const onApprovalCancel = () => {
}
// TODO: 等待调试发送短信接口
const bind_tel_show = ref(false);
// setTimeout(() => {
// showConfirmDialog({
// title: '温馨提示',
// message:
// '您还没有绑定手机号,是否去绑定?',
// confirmButtonColor: styleColor.baseColor
// })
// .then(() => {
// // on confirm
// bind_tel_show.value = true;
// })
// .catch(() => {
// // on cancel
// });
// }, 2000);
const bindForm = ref(null);
const bindSubmit = () => {
bindForm.value.submit();
}
const onBindSubmit = (values) => {
axios.post('/srv/?a=b_login', {
phone: values.phone,
pin: values.code,
})
.then(res => {
if (res.data.code === 1) {
$router.push({
path: '/business/index'
});
} else {
console.warn(res.data);
Toast({
message: res.data.msg,
icon: 'close',
});
}
})
.catch(err => {
console.error(err);
})
};
onMounted(async () => {
// TAG: 全局背景色
document
......@@ -1024,6 +1086,20 @@ const onSubmit = async (values) => {
}
}
.bind-tel-wrapper {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
.block {
width: 80vw;
background-color: #fff;
padding: 1rem;
border-radius: 5px;
}
}
.PHeader-Text {
padding: 1rem;
font-weight: bold;
......