3 changed files with 281 additions and 87 deletions
@ -1,75 +1,164 @@ |
|||||
<template> |
<template> |
||||
<div class="flex"> |
<div class="phone-code-input"> |
||||
<GuipInput |
<!-- 手机号输入框 + 发送按钮 --> |
||||
ref="phoneNumber" |
<GuipFormItem column="column" addClass="w388"> |
||||
width="277px" |
<div slot="formLeft" class="form-top-icon"> |
||||
height="38px" |
<img src="../assets/franchise1/storeNum.svg" alt=""> |
||||
placeholder="请输入手机号码"/> |
<span>手机号码</span> |
||||
<GuipButton type="reverseMild" @click="sendCode" :btnstyle="{width:'99px',height:'38px'}" :disabled="isCounting">{{ countdownText }}</GuipButton> |
|
||||
</div> |
</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> |
<script> |
||||
import axios from 'axios'; |
import GuipFormItem from '@/components/GuipFormItem.vue'; |
||||
import GuipButton from '@/components/GuipButton.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() { |
data() { |
||||
return { |
return { |
||||
phoneValue: '', |
phone: this.value.phone, |
||||
countdown: 60, // 倒计时时间(秒) |
code: this.value.code, |
||||
isCounting: false, // 是否正在倒计时 |
countdown: 0, // 倒计时 |
||||
|
timer: null, // 定时器 |
||||
}; |
}; |
||||
}, |
}, |
||||
components: { |
|
||||
GuipButton, |
|
||||
GuipInput, |
|
||||
}, |
|
||||
computed: { |
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: { |
methods: { |
||||
async sendCode() { |
// 校验手机号 |
||||
if (!/^1\d{10}$/.test(this.$refs.phoneNumber.inputValue)) { |
validatePhone() { |
||||
this.$message.warning('请输入有效的手机号码'); |
console.log('ooooo'); |
||||
return; |
// formRef 固定名称 |
||||
} |
this.$refs.formRef?.validateField(this.phoneProp); |
||||
this.phoneValue = this.$refs.phoneNumber.inputValue; |
}, |
||||
// 根据实际接口请求 |
validateInput() { |
||||
try { |
// formRef 固定名称 |
||||
const response = await axios.post('/agentnew/ajax_send_verify_code', { phoneNumber: this.$refs.phoneNumber.value }); // 替换为实际API地址和参数名 |
// this.$refs.formRef?.validateField(this.phoneProp); |
||||
if (response.data.status) { // 根据后端返回的结构调整这里的判断条件 |
if (/^1[3-9]\d{9}$/.test(this.phone)) { |
||||
this.$message.success('验证码已发送'); |
this.$refs.formRef?.validateField(this.phoneProp, (errorMsg) => { |
||||
this.startCountdown(); |
if (!errorMsg) { |
||||
} else { |
console.log('-----00000'); |
||||
throw new Error(response.data.info || '发送失败'); // 使用后端返回的错误信息或者默认信息 |
// 校验通过,错误提示会自动消失 |
||||
|
}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() { |
startCountdown() { |
||||
this.isCounting = true; |
this.countdown = 60; |
||||
const interval = setInterval(() => { |
this.timer = setInterval(() => { |
||||
this.countdown--; |
this.countdown--; |
||||
if (this.countdown <= 0) { |
if (this.countdown <= 0) { |
||||
clearInterval(interval); |
clearInterval(this.timer); |
||||
this.isCounting = false; |
|
||||
this.countdown = 60; // 重置倒计时时间 |
|
||||
} |
} |
||||
}, 1000); |
}, 1000); |
||||
} |
} |
||||
} |
}, |
||||
}; |
beforeDestroy() { |
||||
</script> |
if (this.timer) clearInterval(this.timer); |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
<style lang="scss" scoped> |
<style scoped> |
||||
.flex{ |
.code-input-wrapper { |
||||
display: flex; |
display: flex; |
||||
justify-content: space-between; |
gap: 10px; |
||||
} |
flex: 1; |
||||
</style> |
} |
||||
|
</style> |
Loading…
Reference in new issue