Files
danyang-match/h5-demo/src/pages/auth/BindPhonePage.vue
T
WorkBuddy 69ebf33e18
CI/CD Pipeline / Backend Build & Test (push) Canceled after 0s
CI/CD Pipeline / Admin Web Build (push) Canceled after 0s
CI/CD Pipeline / Mini Program Compile Check (push) Canceled after 0s
CI/CD Pipeline / Migration Validation (push) Canceled after 0s
CI/CD Pipeline / Test Shell Guard (Phase 23 Gate) (push) Canceled after 0s
CI/CD Pipeline / UI Contracts (source-structure gates) (push) Canceled after 0s
CI/CD Pipeline / E2E (live stack) (push) Canceled after 0s
release: freeze demo v1.1.0 2026-10-19
2026-10-19 20:36:22 +08:00

178 lines
4.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<PageLayout title="绑定手机号">
<div class="bind">
<div class="bind__hero">
<div class="bind__icon">机</div>
<div class="bind__title">绑定手机号</div>
<div class="bind__desc">绑定后可用于找回账号、接收平台通知</div>
</div>
<div class="card">
<van-field
v-model="phone"
type="tel"
maxlength="11"
label="手机号"
placeholder="请输入本人手机号"
:border="false"
@update:model-value="error = ''"
/>
<van-field
v-model="code"
type="digit"
maxlength="6"
label="验证码"
placeholder="请输入验证码"
@update:model-value="error = ''"
>
<template #button>
<van-button size="small" type="primary" :disabled="countdown > 0" @click="onSendCode">
{{ countdown > 0 ? countdown + 's' : '获取验证码' }}
</van-button>
</template>
</van-field>
</div>
<van-checkbox v-model="agreed" class="bind__agree" icon-size="16">
我已阅读并同意《用户服务协议》和《隐私政策》
</van-checkbox>
<p v-if="error" class="bind__error">{{ error }}</p>
<div class="bind__actions">
<van-button type="primary" block round :loading="submitting" @click="onSubmit">
确认绑定
</van-button>
</div>
<p class="bind__tip">手机号仅用于账号安全与平台通知,不会向其他用户展示。</p>
</div>
</PageLayout>
</template>
<script setup lang="ts">
import { onBeforeUnmount, ref } from 'vue'
import { useRouter } from 'vue-router'
import { authService } from '@/api/services'
import { useAppStore } from '@/stores/app'
import PageLayout from '@/layouts/PageLayout.vue'
const router = useRouter()
const appStore = useAppStore()
const phone = ref('')
const code = ref('')
const agreed = ref(false)
const error = ref('')
const submitting = ref(false)
const countdown = ref(0)
let timer: ReturnType<typeof setInterval> | null = null
function onSendCode() {
error.value = ''
if (!/^1\d{10}$/.test(phone.value)) {
error.value = '请输入正确的手机号'
return
}
// 演示端不提供短信网关,仅作占位提示
appStore.toast('验证码已发送(演示)')
countdown.value = 60
timer = setInterval(() => {
countdown.value -= 1
if (countdown.value <= 0 && timer) {
clearInterval(timer)
timer = null
}
}, 1000)
}
async function onSubmit() {
error.value = ''
if (!agreed.value) {
error.value = '请先阅读并同意协议'
return
}
if (!/^1\d{10}$/.test(phone.value)) {
error.value = '请输入正确的手机号'
return
}
if (!code.value) {
error.value = '请输入验证码'
return
}
submitting.value = true
try {
await authService.bindPhone({ phone: phone.value, phoneCode: code.value })
appStore.toastSuccess('手机号绑定成功')
router.replace('/home')
} catch (err: any) {
error.value = err?.message || '绑定失败,请稍后重试'
} finally {
submitting.value = false
}
}
onBeforeUnmount(() => {
if (timer) clearInterval(timer)
})
</script>
<style scoped>
.bind {
padding: 16px;
}
.bind__hero {
text-align: center;
padding: 24px 0 20px;
}
.bind__icon {
width: 56px;
height: 56px;
border-radius: 16px;
margin: 0 auto 12px;
background: var(--mini-brand-gradient);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: 600;
}
.bind__title {
font-size: 18px;
font-weight: 600;
color: var(--mini-text-strong);
}
.bind__desc {
font-size: 13px;
color: var(--mini-text-secondary);
margin-top: 6px;
}
.card {
background: var(--mini-surface);
border-radius: var(--mini-radius);
box-shadow: var(--mini-shadow);
overflow: hidden;
}
.bind__agree {
margin-top: 14px;
font-size: 12px;
color: var(--mini-text-secondary);
}
.bind__error {
color: var(--mini-danger);
font-size: 13px;
margin: 12px 4px 0;
}
.bind__actions {
margin-top: 20px;
}
.bind__tip {
font-size: 11px;
color: var(--mini-text-muted);
text-align: center;
margin-top: 16px;
line-height: 1.6;
}
</style>