|
|
@@ -39,7 +39,12 @@
|
|
|
<el-input v-model="form.mobile" disabled prefix-icon="Iphone" />
|
|
|
</el-form-item>
|
|
|
<el-form-item>
|
|
|
- <el-input v-model="form.sms_code" placeholder="收到的短信验证码" prefix-icon="Message" />
|
|
|
+ <div style="display: flex; width: 100%; gap: 10px;">
|
|
|
+ <el-input v-model="form.sms_code" placeholder="收到的短信验证码" prefix-icon="Message" style="flex: 1" />
|
|
|
+ <el-button type="primary" plain :disabled="countdown > 0" @click="openCaptchaDialog">
|
|
|
+ {{ countdown > 0 ? `${countdown}s` : '重新发送' }}
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
</el-form-item>
|
|
|
<el-form-item>
|
|
|
<el-input v-model="form.new_password" type="password" placeholder="新密码" prefix-icon="Lock" show-password />
|
|
|
@@ -54,12 +59,32 @@
|
|
|
</div>
|
|
|
</el-form>
|
|
|
|
|
|
+ <!-- Resend Captcha Dialog -->
|
|
|
+ <el-dialog v-model="captchaDialogVisible" title="安全验证" width="360px" append-to-body>
|
|
|
+ <el-form :model="captchaForm" label-width="0">
|
|
|
+ <el-form-item class="captcha-item">
|
|
|
+ <el-input v-model="captchaForm.code" placeholder="图形验证码" style="width: 60%" />
|
|
|
+ <div class="captcha-img" @click="fetchResendCaptcha" v-if="resendCaptchaImage">
|
|
|
+ <img :src="resendCaptchaImage" alt="captcha" />
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <span class="dialog-footer">
|
|
|
+ <el-button @click="captchaDialogVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="handleResendSmsConfirm" :loading="resendLoading">
|
|
|
+ 确认发送
|
|
|
+ </el-button>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
</el-card>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { ref, reactive, onMounted } from 'vue'
|
|
|
+import { ref, reactive, onMounted, onUnmounted } from 'vue'
|
|
|
import { useRouter } from 'vue-router'
|
|
|
import { getCaptcha, sendSms, resetPassword } from '../api/public'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
@@ -69,6 +94,17 @@ const activeStep = ref(0)
|
|
|
const loading = ref(false)
|
|
|
const captchaImage = ref('')
|
|
|
|
|
|
+// Resend Logic State
|
|
|
+const countdown = ref(0)
|
|
|
+let timer: any = null
|
|
|
+const captchaDialogVisible = ref(false)
|
|
|
+const resendCaptchaImage = ref('')
|
|
|
+const resendCaptchaId = ref('')
|
|
|
+const resendLoading = ref(false)
|
|
|
+const captchaForm = reactive({
|
|
|
+ code: ''
|
|
|
+})
|
|
|
+
|
|
|
const form = reactive({
|
|
|
mobile: '',
|
|
|
captcha_id: '',
|
|
|
@@ -88,6 +124,55 @@ const fetchCaptcha = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+const startCountdown = () => {
|
|
|
+ countdown.value = 60
|
|
|
+ if (timer) clearInterval(timer)
|
|
|
+ timer = setInterval(() => {
|
|
|
+ countdown.value--
|
|
|
+ if (countdown.value <= 0) {
|
|
|
+ clearInterval(timer)
|
|
|
+ }
|
|
|
+ }, 1000)
|
|
|
+}
|
|
|
+
|
|
|
+const openCaptchaDialog = () => {
|
|
|
+ captchaForm.code = ''
|
|
|
+ fetchResendCaptcha()
|
|
|
+ captchaDialogVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const fetchResendCaptcha = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getCaptcha()
|
|
|
+ resendCaptchaImage.value = res.data.image
|
|
|
+ resendCaptchaId.value = res.data.captcha_id
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleResendSmsConfirm = async () => {
|
|
|
+ if (!captchaForm.code) {
|
|
|
+ ElMessage.warning('请输入图形验证码')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ resendLoading.value = true
|
|
|
+ try {
|
|
|
+ await sendSms({
|
|
|
+ mobile: form.mobile,
|
|
|
+ captcha_id: resendCaptchaId.value,
|
|
|
+ captcha_code: captchaForm.code
|
|
|
+ })
|
|
|
+ ElMessage.success('验证码已发送')
|
|
|
+ captchaDialogVisible.value = false
|
|
|
+ startCountdown()
|
|
|
+ } catch (e) {
|
|
|
+ fetchResendCaptcha()
|
|
|
+ } finally {
|
|
|
+ resendLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
const handleSendSms = async () => {
|
|
|
if (!form.mobile || !form.captcha_code) {
|
|
|
ElMessage.warning('请输入手机号和图形验证码')
|
|
|
@@ -102,6 +187,7 @@ const handleSendSms = async () => {
|
|
|
})
|
|
|
ElMessage.success('验证码已发送 (模拟环境: 请检查后端日志)')
|
|
|
activeStep.value = 1
|
|
|
+ startCountdown()
|
|
|
} catch (e) {
|
|
|
fetchCaptcha() // Refresh captcha on fail
|
|
|
} finally {
|
|
|
@@ -133,6 +219,10 @@ const handleReset = async () => {
|
|
|
onMounted(() => {
|
|
|
fetchCaptcha()
|
|
|
})
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ if (timer) clearInterval(timer)
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|