
3 changed files with 277 additions and 86 deletions
@ -1,75 +1,164 @@ |
|||
<template> |
|||
<div class="flex"> |
|||
<GuipInput |
|||
ref="phoneNumber" |
|||
width="277px" |
|||
height="38px" |
|||
placeholder="请输入手机号码"/> |
|||
<GuipButton type="reverseMild" @click="sendCode" :btnstyle="{width:'99px',height:'38px'}" :disabled="isCounting">{{ countdownText }}</GuipButton> |
|||
<div class="phone-code-input"> |
|||
<!-- 手机号输入框 + 发送按钮 --> |
|||
<GuipFormItem column="column" addClass="w388"> |
|||
<div slot="formLeft" class="form-top-icon"> |
|||
<img src="../assets/franchise1/storeNum.svg" alt=""> |
|||
<span>手机号码</span> |
|||
</div> |
|||
</template> |
|||
<el-form-item slot="formDom" :prop="phoneProp" :rules="phoneRules" style="display: flex;justify-content: space-between;"> |
|||
<el-input v-model="phone" @input="validateInput" |
|||
placeholder="请输入手机号" style="width: 277px;" clearable @blur="validatePhone"> |
|||
</el-input> |
|||
<GuipButton type="reverseMild" :btnstyle="{width:'99px',height:'38px'}" :disabled="!canSendCode" @click="sendCode" class="send-btn"> |
|||
{{ countdown > 0 ? `${countdown}s后重试` : '获取验证码' }}</GuipButton> |
|||
</el-form-item> |
|||
</GuipFormItem> |
|||
<!-- 验证码输入框 --> |
|||
<GuipFormItem column="column" addClass="w388"> |
|||
<div slot="formLeft" class="form-top-icon"> |
|||
<img src="../assets/franchise1/codeNumber.svg" alt=""> |
|||
<span>验证码</span> |
|||
</div> |
|||
<el-form-item slot="formDom" :prop="codeProp" :rules="codeRules"> |
|||
<div class="code-input-wrapper"> |
|||
<el-input v-model="code" placeholder="请输入验证码" clearable @blur="validateCode"></el-input> |
|||
</div> |
|||
</el-form-item> |
|||
</GuipFormItem> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import axios from 'axios'; |
|||
<script> |
|||
import GuipFormItem from '@/components/GuipFormItem.vue'; |
|||
import GuipButton from '@/components/GuipButton.vue'; |
|||
import GuipInput from '@/components/GuipInput.vue'; |
|||
|
|||
export default { |
|||
export default { |
|||
name: "PhoneCodeInput", |
|||
components:{ |
|||
GuipButton, |
|||
GuipFormItem, |
|||
}, |
|||
props: { |
|||
// 用于 Form 校验的 prop(如 'phone' 和 'code') |
|||
phoneProp: { |
|||
type: String, |
|||
default: "phone", |
|||
}, |
|||
codeProp: { |
|||
type: String, |
|||
default: "code", |
|||
}, |
|||
// 初始值(v-model) |
|||
value: { |
|||
type: Object, |
|||
default: () => ({ |
|||
phone: "", |
|||
code: "", |
|||
}), |
|||
}, |
|||
// 自定义校验规则(可选) |
|||
phoneRules: { |
|||
type: Array, |
|||
default: () => [ |
|||
{ required: true, message: "请输入手机号", trigger: "blur" }, |
|||
{ pattern: /^1[3-9]\d{9}$/, message: "手机号格式错误", trigger: "blur" }, |
|||
], |
|||
}, |
|||
codeRules: { |
|||
type: Array, |
|||
default: () => [ |
|||
{ required: true, message: "请输入验证码", trigger: "blur" }, |
|||
{ pattern: /^\d{6}$/, message: "验证码必须是6位数字", trigger: "blur" }, |
|||
], |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
phoneValue: '', |
|||
countdown: 60, // 倒计时时间(秒) |
|||
isCounting: false, // 是否正在倒计时 |
|||
phone: this.value.phone, |
|||
code: this.value.code, |
|||
countdown: 0, // 倒计时 |
|||
timer: null, // 定时器 |
|||
}; |
|||
}, |
|||
components: { |
|||
GuipButton, |
|||
GuipInput, |
|||
}, |
|||
computed: { |
|||
countdownText() { |
|||
return this.isCounting ? `${this.countdown}秒后重试` : '获取验证码'; |
|||
} |
|||
// 是否可以发送验证码(手机号格式正确且未在倒计时) |
|||
canSendCode() { |
|||
return /^1[3-9]\d{9}$/.test(this.phone) && this.countdown === 0; |
|||
}, |
|||
}, |
|||
watch: { |
|||
// 监听内部数据变化,同步到父组件 |
|||
phone(newVal) { |
|||
this.$emit("input", { ...this.value, phone: newVal }); |
|||
}, |
|||
code(newVal) { |
|||
this.$emit("input", { ...this.value, code: newVal }); |
|||
}, |
|||
// 监听外部 v-model 变化,更新内部数据 |
|||
value: { |
|||
deep: true, |
|||
handler(newVal) { |
|||
this.phone = newVal.phone; |
|||
this.code = newVal.code; |
|||
}, |
|||
}, |
|||
}, |
|||
methods: { |
|||
async sendCode() { |
|||
if (!/^1\d{10}$/.test(this.$refs.phoneNumber.inputValue)) { |
|||
this.$message.warning('请输入有效的手机号码'); |
|||
return; |
|||
} |
|||
this.phoneValue = this.$refs.phoneNumber.inputValue; |
|||
// 根据实际接口请求 |
|||
try { |
|||
const response = await axios.post('/agentnew/ajax_send_verify_code', { phoneNumber: this.$refs.phoneNumber.value }); // 替换为实际API地址和参数名 |
|||
if (response.data.status) { // 根据后端返回的结构调整这里的判断条件 |
|||
this.$message.success('验证码已发送'); |
|||
this.startCountdown(); |
|||
} else { |
|||
throw new Error(response.data.info || '发送失败'); // 使用后端返回的错误信息或者默认信息 |
|||
// 校验手机号 |
|||
validatePhone() { |
|||
console.log('ooooo'); |
|||
// formRef 固定名称 |
|||
this.$refs.formRef?.validateField(this.phoneProp); |
|||
}, |
|||
validateInput() { |
|||
// formRef 固定名称 |
|||
// this.$refs.formRef?.validateField(this.phoneProp); |
|||
if (/^1[3-9]\d{9}$/.test(this.phone)) { |
|||
this.$refs.formRef?.validateField(this.phoneProp, (errorMsg) => { |
|||
if (!errorMsg) { |
|||
console.log('-----00000'); |
|||
// 校验通过,错误提示会自动消失 |
|||
}else{ |
|||
console.log('776767676'); |
|||
} |
|||
} catch (error) { |
|||
console.error('发送验证码失败:', error); // 处理错误信息,可以在这里做更多的错误处理逻辑,比如重试机制等。 |
|||
this.$message.warning('发送验证码失败,请稍后再试'); |
|||
}); |
|||
} |
|||
}, |
|||
// 校验验证码 |
|||
validateCode() { |
|||
this.$refs.formRef?.validateField(this.codeProp); |
|||
}, |
|||
// 发送验证码 |
|||
sendCode() { |
|||
if (!this.canSendCode) return; |
|||
|
|||
// 模拟发送验证码(实际调用 API) |
|||
|
|||
this.startCountdown() |
|||
|
|||
this.$emit("send-code", this.phone); |
|||
}, |
|||
startCountdown() { |
|||
this.isCounting = true; |
|||
const interval = setInterval(() => { |
|||
this.countdown = 60; |
|||
this.timer = setInterval(() => { |
|||
this.countdown--; |
|||
if (this.countdown <= 0) { |
|||
clearInterval(interval); |
|||
this.isCounting = false; |
|||
this.countdown = 60; // 重置倒计时时间 |
|||
clearInterval(this.timer); |
|||
} |
|||
}, 1000); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
}, |
|||
beforeDestroy() { |
|||
if (this.timer) clearInterval(this.timer); |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.flex{ |
|||
<style scoped> |
|||
.code-input-wrapper { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
} |
|||
</style> |
|||
gap: 10px; |
|||
flex: 1; |
|||
} |
|||
</style> |
Loading…
Reference in new issue