181 lines
4.3 KiB
Vue
181 lines
4.3 KiB
Vue
<script setup lang="ts">
|
||
import { computed } from 'vue'
|
||
import { ElMessage } from 'element-plus'
|
||
import { SmsCodeInput } from '@/components'
|
||
import { isPhone } from '@/utils/validate'
|
||
|
||
interface Props {
|
||
phone: string
|
||
code: string
|
||
agree: boolean
|
||
}
|
||
|
||
const props = defineProps<Props>()
|
||
|
||
const emit = defineEmits<{
|
||
'update:phone': [value: string]
|
||
'update:code': [value: string]
|
||
'update:agree': [value: boolean]
|
||
getCode: [phone: string]
|
||
submit: []
|
||
}>()
|
||
|
||
const localPhone = computed({
|
||
get: () => props.phone,
|
||
set: (value: string) => emit('update:phone', value),
|
||
})
|
||
|
||
const localCode = computed({
|
||
get: () => props.code,
|
||
set: (value: string) => emit('update:code', value),
|
||
})
|
||
|
||
const localAgree = computed({
|
||
get: () => props.agree,
|
||
set: (value: boolean) => emit('update:agree', value),
|
||
})
|
||
|
||
function onGetCode(): void {
|
||
if (!isPhone(props.phone)) {
|
||
ElMessage.warning('手机号格式不正确')
|
||
return
|
||
}
|
||
emit('getCode', props.phone)
|
||
}
|
||
|
||
function onSubmit(): void {
|
||
if (!isPhone(props.phone)) {
|
||
ElMessage.warning('手机号格式不正确')
|
||
return
|
||
}
|
||
if (!props.code) {
|
||
ElMessage.warning('请输入验证码')
|
||
return
|
||
}
|
||
emit('submit')
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<form class="sms-login" @submit.prevent="onSubmit">
|
||
<div class="sms-login__field">
|
||
<label class="sms-login__label" for="sms-phone">手机号</label>
|
||
<input
|
||
id="sms-phone"
|
||
v-model="localPhone"
|
||
class="sms-login__input"
|
||
type="text"
|
||
placeholder="请输入手机号"
|
||
maxlength="11"
|
||
autocomplete="tel"
|
||
>
|
||
</div>
|
||
<div class="sms-login__field">
|
||
<label class="sms-login__label" for="sms-code">验证码</label>
|
||
<SmsCodeInput v-model:code="localCode" @get-code="onGetCode" />
|
||
</div>
|
||
<label class="sms-login__agree">
|
||
<input v-model="localAgree" type="checkbox">
|
||
<span>已阅读并同意<em>《用户协议》</em>和<em>《隐私政策》</em></span>
|
||
</label>
|
||
<button class="sms-login__submit" type="submit">
|
||
登录
|
||
</button>
|
||
</form>
|
||
</template>
|
||
|
||
<style lang="less" scoped>
|
||
.sms-login {
|
||
.flex(column, flex-start, stretch);
|
||
// 设计稿:表单列 x989,Tab 行底 412 → 首个标签 438 = 26
|
||
margin: 26px 0 0 17px;
|
||
width: 680px;
|
||
|
||
&__field {
|
||
.flex(column, flex-start, stretch);
|
||
gap: 8px;
|
||
width: 680px;
|
||
}
|
||
|
||
// 与账号密码登录两字段间距一致
|
||
&__field + &__field {
|
||
margin-top: 40px;
|
||
}
|
||
|
||
&__label {
|
||
font-size: 13px * @auth-font-scale; // 设计稿 13/500 #1F2937,×@auth-font-scale
|
||
font-weight: 500;
|
||
line-height: 17px * @auth-font-scale;
|
||
color: #1f2937;
|
||
}
|
||
|
||
// 设计稿:输入框 680×39、白底 + #DDE1E7 描边、文字 13/400(盒高随字体 ×@auth-font-scale)
|
||
&__input {
|
||
width: 100%;
|
||
height: 39px * @auth-font-scale;
|
||
padding: 0 12px * @auth-font-scale;
|
||
border: 1px solid #dde1e7;
|
||
border-radius: @radius-sm;
|
||
background: @white;
|
||
font-size: 13px * @auth-font-scale;
|
||
color: #1f2937;
|
||
outline: none;
|
||
transition: border-color 0.2s;
|
||
box-sizing: border-box;
|
||
|
||
&:focus {
|
||
border-color: @primary-strong;
|
||
}
|
||
|
||
&::placeholder {
|
||
color: #1f2937;
|
||
}
|
||
}
|
||
|
||
// 设计稿:协议行 @(989,622);验证码输入底 584 → 协议行 38
|
||
&__agree {
|
||
.flex(row, flex-start, center);
|
||
gap: 8px;
|
||
margin-top: 22px;
|
||
font-size: 12px * @auth-font-scale;
|
||
font-weight: 400;
|
||
line-height: 16px * @auth-font-scale;
|
||
color: #6b7280;
|
||
cursor: pointer;
|
||
|
||
input {
|
||
flex-shrink: 0;
|
||
width: 16px * @auth-font-scale;
|
||
height: 16px * @auth-font-scale;
|
||
margin: 0;
|
||
accent-color: @primary-strong;
|
||
}
|
||
|
||
// 设计稿:《用户协议》《隐私政策》为强调蓝,其余为次级灰
|
||
em {
|
||
font-style: normal;
|
||
color: @primary-strong;
|
||
}
|
||
}
|
||
|
||
// 设计稿:登录按钮 680×46 @y656、#024FFF 实底、文字 15/500(盒高随字体 ×@auth-font-scale)
|
||
&__submit {
|
||
width: 100%;
|
||
height: 46px * @auth-font-scale;
|
||
margin-top: 18px;
|
||
border: none;
|
||
border-radius: @radius-sm;
|
||
background: @primary-strong;
|
||
color: @white;
|
||
font-size: 15px * @auth-font-scale;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: background 0.2s;
|
||
|
||
&:hover {
|
||
background: @primary-hover;
|
||
}
|
||
}
|
||
}
|
||
</style>
|