diff --git a/src/components/GuipFormItem.vue b/src/components/GuipFormItem.vue index f38d3b5..e4ab6d1 100644 --- a/src/components/GuipFormItem.vue +++ b/src/components/GuipFormItem.vue @@ -43,7 +43,7 @@ export default { // } }, mounted(){ - console.log(this.required,'required----'); + // console.log(this.required,'required----'); } } </script> diff --git a/src/components/PhoneCode.vue b/src/components/PhoneCode.vue index ccc58d7..90bd4d7 100644 --- a/src/components/PhoneCode.vue +++ b/src/components/PhoneCode.vue @@ -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> - </template> - - <script> -import axios from 'axios'; + <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> + <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 GuipFormItem from '@/components/GuipFormItem.vue'; import GuipButton from '@/components/GuipButton.vue'; -import GuipInput from '@/components/GuipInput.vue'; - export default { - data() { - return { - phoneValue: '', - countdown: 60, // 倒计时时间(秒) - isCounting: false, // 是否正在倒计时 - }; +export default { + name: "PhoneCodeInput", + components:{ + GuipButton, + GuipFormItem, + }, + props: { + // 用于 Form 校验的 prop(如 'phone' 和 'code') + phoneProp: { + type: String, + default: "phone", }, - components: { - GuipButton, - GuipInput, + codeProp: { + type: String, + default: "code", }, - computed: { - countdownText() { - return this.isCounting ? `${this.countdown}秒后重试` : '获取验证码'; - } + // 初始值(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 { + phone: this.value.phone, + code: this.value.code, + countdown: 0, // 倒计时 + timer: null, // 定时器 + }; + }, + computed: { + // 是否可以发送验证码(手机号格式正确且未在倒计时) + 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 || '发送失败'); // 使用后端返回的错误信息或者默认信息 - } - } catch (error) { - console.error('发送验证码失败:', error); // 处理错误信息,可以在这里做更多的错误处理逻辑,比如重试机制等。 - this.$message.warning('发送验证码失败,请稍后再试'); - } - }, - startCountdown() { - this.isCounting = true; - const interval = setInterval(() => { - this.countdown--; - if (this.countdown <= 0) { - clearInterval(interval); - this.isCounting = false; - this.countdown = 60; // 重置倒计时时间 + }, + methods: { + // 校验手机号 + 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'); } - }, 1000); + }); } - } - }; - </script> + }, + // 校验验证码 + validateCode() { + this.$refs.formRef?.validateField(this.codeProp); + }, + // 发送验证码 + sendCode() { + if (!this.canSendCode) return; - <style lang="scss" scoped> - .flex{ - display: flex; - justify-content: space-between; + // 模拟发送验证码(实际调用 API) + + this.startCountdown() + + this.$emit("send-code", this.phone); + }, + startCountdown() { + this.countdown = 60; + this.timer = setInterval(() => { + this.countdown--; + if (this.countdown <= 0) { + clearInterval(this.timer); + } + }, 1000); } - </style> \ No newline at end of file + }, + beforeDestroy() { + if (this.timer) clearInterval(this.timer); + }, +}; +</script> + +<style scoped> +.code-input-wrapper { + display: flex; + gap: 10px; + flex: 1; +} +</style> \ No newline at end of file diff --git a/src/views/Franchise.vue b/src/views/Franchise.vue index 2512e7e..93aaefe 100644 --- a/src/views/Franchise.vue +++ b/src/views/Franchise.vue @@ -28,7 +28,8 @@ <!-- <div class="ud__modal__header"> </div> --> - <el-form :model="form" :rules="rules" class="el-row demo-ruleForm" ref="formRef"> + <el-form :model="form" :rules="rules" + class="el-row demo-ruleForm" ref="formRef"> <div class="right-form"> <GuipFormItem column="column" addClass="w388"> <div slot="formLeft" class="form-top-icon"> @@ -51,39 +52,60 @@ </div> <GuipInput slot="formDom" ref="GuipInput" v-model="form.name" prop="name" placeholder="您的真实姓名"/> </GuipFormItem> + + <!-- <PhoneCode v-model="form.phoneCode" :phone-prop="'phone'" + :code-prop="'code'" @send-code="handleSendCode" /> --> <GuipFormItem column="column" addClass="w388"> <div slot="formLeft" class="form-top-icon"> <img src="../assets/franchise1/storeNum.svg" alt=""> <span>手机号码</span> </div> - <PhoneCode slot="formDom" ref="PhoneCode" v-model="form.phone" prop="phone"></PhoneCode> + <el-form-item slot="formDom" prop="phone" + style="width: 100%;"> + <div style="width: 100%;" class="flex-between"> + <el-input v-model="form.phone" @input="clearPhoneError" + placeholder="请输入手机号" style="width: 277px;" clearable + @blur="validatePhone"> + </el-input> + <GuipButton type="reverseMild" + :btnstyle="{ width: '99px', height: '38px' }" + :disabled="!canSend || countdown > 0" @click="sendCode" + class="send-btn"> + {{ countdown > 0 ? `${countdown}s后重试` : '获取验证码' }}</GuipButton> + </div> + </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> - <GuipInput slot="formDom" ref="GuipInput" v-model="form.sms_code" prop="sms_code" placeholder="填写验证码"/> + <el-form-item slot="formDom" prop="sms_code"> + <el-input v-model="form.sms_code" placeholder="请输入验证码" clearable + @blur="validateCode" @input="clearCodeError"></el-input> + </el-form-item> </GuipFormItem> </div> </el-form> <div class="ud__modal__footer"> <div class="step-box__footer"> - <GuipButton :btnstyle="btnstyleObj" type="primary" @click="goAddFranchise">加盟并进入后台</GuipButton> + <GuipButton :btnstyle="btnstyleObj" type="primary" @click="goAddFranchise"> + 加盟并进入后台</GuipButton> <p class="attention"> <el-checkbox v-model="checked"></el-checkbox> <b>代理商需要阅读并同意<a href="">《哈哈哈哈》</a></b> </p> </div> - + </div> </div> </div> - + </div> - + </div> - + </div> </div> <Footer></Footer> @@ -92,7 +114,7 @@ </div> </template> <script> -import PhoneCode from '@/components/PhoneCode.vue'; +// import PhoneCode from '@/components/PhoneCode.vue'; import GuipButton from '@/components/GuipButton.vue'; import GuipInput from '@/components/GuipInput.vue'; import GuipFormItem from '@/components/GuipFormItem.vue'; @@ -100,8 +122,31 @@ import Footer from '@/components/Footer.vue'; export default { data() { + // 手机号验证规则 + const validatePhone = (rule, value, callback) => { + if (!value) { + return callback(new Error('请输入手机号')) + } + if (!/^1[3-9]\d{9}$/.test(value)) { + return callback(new Error('手机号格式不正确')) + } + callback() + } + + // 验证码验证规则 + const validateCode = (rule, value, callback) => { + if (!value) { + return callback(new Error('请输入验证码')) + } + // 校验可改 + if (!/^\d{4,6}$/.test(value)) { + return callback(new Error('验证码必须是4-6位数字')) + } + callback() + } + return { - checked:true, + checked: true, btnstyleObj: { width: '388px', height: '46px' @@ -114,6 +159,8 @@ export default { nick: '', recommended_aid: '', }, + countdown: 0, + timer: null, rules: { tid: [ { required: true, message: '请输入订单号', trigger: 'blur' } @@ -125,19 +172,20 @@ export default { { required: true, message: '请输入真实姓名', trigger: 'blur' } ], phone: [ - { required: true, message: '请输入手机号', trigger: 'blur' } + { validator: validatePhone, trigger: 'blur' } ], sms_code: [ - { required: true, message: '请输入验证码', trigger: 'blur' } + { validator: validateCode, trigger: 'blur' } ] }, + }; }, components: { GuipButton, GuipInput, GuipFormItem, - PhoneCode, + // PhoneCode, Footer }, mounted(){ @@ -145,7 +193,55 @@ export default { this.form.recommended_aid = this.$route.aid; } }, + computed: { + canSend() { + return /^1[3-9]\d{9}$/.test(this.form.phone) + } + }, methods: { + // 校验手机号 + validatePhone() { + this.$refs.formRef.validateField('phone') + }, + + // 校验验证码 + validateCode() { + this.$refs.formRef.validateField('code') + }, + + // 手机号输入时清除错误 + clearPhoneError() { + if (/^1[3-9]\d{9}$/.test(this.form.phone)) { + this.$refs.formRef.clearValidate('phone') + } + }, + + // 验证码输入时清除错误 + clearCodeError() { + if (/^\d{6}$/.test(this.form.code)) { + this.$refs.formRef.clearValidate('code') + } + }, + // 发送验证码 + sendCode() { + if (!this.canSend || this.countdown > 0) return + + // 模拟发送验证码 + console.log('发送验证码到:', this.form.phone) + + // 开始倒计时 + this.countdown = 60 + this.timer = setInterval(() => { + this.countdown-- + if (this.countdown <= 0) { + clearInterval(this.timer) + } + }, 1000) + + // 实际项目中这里调用API发送验证码 + // this.$api.sendSmsCode({ phone: this.formData.phone }) + }, + goAddFranchise(){ console.log(this.form) const that = this @@ -173,30 +269,39 @@ export default { } }); } - } + }, + beforeDestroy() { + if (this.timer) clearInterval(this.timer); + }, } </script> <style lang="scss" scoped> @import '../style/franchise.scss'; - +::v-deep .el-form-item { + margin-bottom: 0; +} .right-form { padding: 40px 40px 0; } -.form-item1{ + +.form-item1 { margin-bottom: 24px; } -.attention{ + +.attention { margin-top: 20px; - b{ + + b { font-weight: normal; - a{ + + a { text-decoration: none; color: #006AFF; } } } -.web-req-right-top{ + +.web-req-right-top { flex: 1; } - </style> \ No newline at end of file