17 changed files with 596 additions and 150 deletions
After Width: | Height: | Size: 9.8 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 8.3 KiB |
@ -0,0 +1,138 @@ |
|||||||
|
<template> |
||||||
|
<div class="button" :class="class1" @click.capture.stop="check"> |
||||||
|
<img v-if="loading" src="../assets/img/icon/loading-white.png" alt=""> |
||||||
|
<slot v-if="showText"></slot> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: "BaseButton", |
||||||
|
props: { |
||||||
|
loading: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
}, |
||||||
|
loadingWithText: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
}, |
||||||
|
disabled: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
}, |
||||||
|
type: { |
||||||
|
type: String, |
||||||
|
default: 'primary' |
||||||
|
}, |
||||||
|
active: { |
||||||
|
type: Boolean, |
||||||
|
default: true |
||||||
|
}, |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return {} |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
class1() { |
||||||
|
return [this.type, this.active ? '' : 'no-active', this.disabled && 'disabled'] |
||||||
|
}, |
||||||
|
showText() { |
||||||
|
if (this.loading) { |
||||||
|
return this.loadingWithText |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
|
}, |
||||||
|
created() { |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
check() { |
||||||
|
if (this.disabled) return |
||||||
|
if (this.loading) return |
||||||
|
return this.$emit('click') |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
@import "../assets/scss/index"; |
||||||
|
|
||||||
|
.button { |
||||||
|
color: white; |
||||||
|
height: 4rem; |
||||||
|
line-height: 4rem; |
||||||
|
border-radius: .3rem; |
||||||
|
//width: 100%; |
||||||
|
font-size: 1.4rem; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
|
||||||
|
img { |
||||||
|
height: 1.6rem; |
||||||
|
margin-right: .5rem; |
||||||
|
animation: animal .8s infinite linear; |
||||||
|
|
||||||
|
@keyframes animal { |
||||||
|
0% { |
||||||
|
transform: rotate(-360deg); |
||||||
|
} |
||||||
|
100% { |
||||||
|
transform: rotate(0deg); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.primary { |
||||||
|
background: $primary-btn-color; |
||||||
|
|
||||||
|
&:active { |
||||||
|
background: $disable-primary-btn-color; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.no-active { |
||||||
|
&:active { |
||||||
|
&.primary { |
||||||
|
background: $primary-btn-color; |
||||||
|
} |
||||||
|
|
||||||
|
&.dark { |
||||||
|
background: $second-btn-color; |
||||||
|
} |
||||||
|
|
||||||
|
&.white { |
||||||
|
background: white; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.disabled { |
||||||
|
&.primary { |
||||||
|
background: gainsboro; |
||||||
|
color: white; |
||||||
|
} |
||||||
|
|
||||||
|
&:active { |
||||||
|
&.primary { |
||||||
|
background: gainsboro; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.dark { |
||||||
|
background: $second-btn-color; |
||||||
|
|
||||||
|
&:active { |
||||||
|
background: $second-btn-color-tran; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.white { |
||||||
|
background: white; |
||||||
|
color: black; |
||||||
|
border: 1px solid gainsboro; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,130 @@ |
|||||||
|
<template> |
||||||
|
<div class="VerificationCode"> |
||||||
|
<BaseHeader mode="light" :isClose="true"> |
||||||
|
<template v-slot:right> |
||||||
|
<span class="f16">帮助</span> |
||||||
|
</template> |
||||||
|
</BaseHeader> |
||||||
|
<div class="content"> |
||||||
|
<div class="notice"> |
||||||
|
<div class="title">请输入验证码</div> |
||||||
|
<div class="sub-title">验证码已通过短信发送到+86 13800138000</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<LoginInput autofocus type="code" |
||||||
|
v-model="code" |
||||||
|
placeholder="请输入验证码" |
||||||
|
v-model:isSendVerificationCode="isSendVerificationCode" |
||||||
|
@send="sendCode" |
||||||
|
/> |
||||||
|
<div class="options"> |
||||||
|
<span> |
||||||
|
收不到短信?<span class="link" @click="getVoiceCode">获取语音验证码</span> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
|
||||||
|
<b-button :loading="loading" :active="false" :disabled="code.length < 4" @click="login"> |
||||||
|
{{ loading ? '登录中' : '登录' }} |
||||||
|
</b-button> |
||||||
|
|
||||||
|
<!-- <ConfirmDialog></ConfirmDialog>--> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import Check from "../../components/Check"; |
||||||
|
import LoginInput from "./components/LoginInput"; |
||||||
|
import ConfirmDialog from "../../components/dialog/ConfirmDialog"; |
||||||
|
|
||||||
|
export default { |
||||||
|
name: "VerificationCode", |
||||||
|
components: { |
||||||
|
Check, |
||||||
|
LoginInput, |
||||||
|
ConfirmDialog |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
showAnim: false, |
||||||
|
showTooltip: false, |
||||||
|
loading: false, |
||||||
|
phone: '', |
||||||
|
password: '', |
||||||
|
code: '', |
||||||
|
isSendVerificationCode: true, |
||||||
|
} |
||||||
|
}, |
||||||
|
created() { |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
getVoiceCode(){ |
||||||
|
this.$showConfirmDialog('','语音验证码') |
||||||
|
}, |
||||||
|
//TODO loading样式不对 |
||||||
|
async sendCode() { |
||||||
|
this.$showLoading() |
||||||
|
await this.$sleep(500) |
||||||
|
this.$hideLoading() |
||||||
|
this.isSendVerificationCode = true |
||||||
|
}, |
||||||
|
login() { |
||||||
|
this.loading = true |
||||||
|
setTimeout(() => { |
||||||
|
this.isSendVerificationCode = true |
||||||
|
this.loading = false |
||||||
|
}, 1000) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
@import "../../assets/scss/index"; |
||||||
|
|
||||||
|
.VerificationCode { |
||||||
|
position: fixed; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
bottom: 0; |
||||||
|
top: 0; |
||||||
|
overflow: auto; |
||||||
|
color: black; |
||||||
|
font-size: 1.4rem; |
||||||
|
background: white; |
||||||
|
|
||||||
|
.content { |
||||||
|
padding: 6rem 3rem; |
||||||
|
//padding-top: 6rem; |
||||||
|
|
||||||
|
.notice { |
||||||
|
margin-bottom: 2rem; |
||||||
|
margin-top: 4rem; |
||||||
|
display: flex; |
||||||
|
align-items: flex-start; |
||||||
|
flex-direction: column; |
||||||
|
|
||||||
|
.title { |
||||||
|
font-size: 2rem; |
||||||
|
margin-bottom: 1rem; |
||||||
|
} |
||||||
|
|
||||||
|
.sub-title { |
||||||
|
font-size: 1.2rem; |
||||||
|
color: $second-text-color; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.button { |
||||||
|
margin-bottom: .5rem; |
||||||
|
} |
||||||
|
|
||||||
|
.options { |
||||||
|
font-size: 1.2rem; |
||||||
|
margin-top: 2rem; |
||||||
|
margin-bottom: 2rem; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,179 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<div class="input-number" v-if="type === 'phone'"> |
||||||
|
<div class="left"> |
||||||
|
<span>+86</span> |
||||||
|
<div class="arrow"></div> |
||||||
|
</div> |
||||||
|
<div class="right flex1"> |
||||||
|
<input :autofocus="autofocus" v-model="value" type="text" :placeholder="placeholder"> |
||||||
|
<img v-if="value" src="../../../assets/img/icon/login/close-full-gray.png" alt="" @click="value=''"> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="input-number" v-if="type === 'password'"> |
||||||
|
<div class="right flex1"> |
||||||
|
<input :autofocus="autofocus" v-model="value" type="password" :placeholder="placeholder"> |
||||||
|
<img v-if="value" src="../../../assets/img/icon/login/close-full-gray.png" alt="" @click="value=''"> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="input-number" v-if="type === 'code'"> |
||||||
|
<div class="left no-border flex1"> |
||||||
|
<input :autofocus="autofocus" v-model="value" type="text" :placeholder="placeholder"> |
||||||
|
<img v-if="value" src="../../../assets/img/icon/login/close-full-gray.png" alt="" @click="value=''"> |
||||||
|
</div> |
||||||
|
<div class="right" @click="send"> |
||||||
|
<span :class="isSendVerificationCode && 'disabled'">{{ verificationCodeBtnText }}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: "LoginInput", |
||||||
|
props: { |
||||||
|
modelValue: '', |
||||||
|
placeholder: '', |
||||||
|
type: { |
||||||
|
type: String, |
||||||
|
default: 'phone' |
||||||
|
}, |
||||||
|
autofocus: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
}, |
||||||
|
isSendVerificationCode: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
}, |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
verificationCodeBtnText: 60 |
||||||
|
} |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
value: { |
||||||
|
get() { |
||||||
|
return this.modelValue |
||||||
|
}, |
||||||
|
set(e) { |
||||||
|
this.$emit('update:modelValue', e) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
isSendVerificationCode: { |
||||||
|
immediate: true, |
||||||
|
handler(newVal, oldVal) { |
||||||
|
if (newVal) { |
||||||
|
this.verificationCodeBtnText = 60 |
||||||
|
let ticker = setInterval(() => { |
||||||
|
if (this.verificationCodeBtnText > 0) { |
||||||
|
this.verificationCodeBtnText-- |
||||||
|
} else { |
||||||
|
this.verificationCodeBtnText = '重新发送' |
||||||
|
this.$emit('update:isSendVerificationCode', false) |
||||||
|
clearInterval(ticker) |
||||||
|
} |
||||||
|
}, 1000) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
send(){ |
||||||
|
if (!this.isSendVerificationCode){ |
||||||
|
this.$emit('send') |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
@import "../../../assets/scss/index"; |
||||||
|
|
||||||
|
.input-number { |
||||||
|
display: flex; |
||||||
|
background: whitesmoke; |
||||||
|
padding: 1.5rem 1rem; |
||||||
|
font-size: 1.4rem; |
||||||
|
|
||||||
|
.left { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
margin-right: 1rem; |
||||||
|
padding-right: 1rem; |
||||||
|
position: relative; |
||||||
|
|
||||||
|
&.no-border { |
||||||
|
&::before { |
||||||
|
content: ''; |
||||||
|
display: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.flex1 { |
||||||
|
flex: 1; |
||||||
|
margin-right: 0; |
||||||
|
padding-right: 0; |
||||||
|
} |
||||||
|
|
||||||
|
img { |
||||||
|
top: 50%; |
||||||
|
transform: translateY(-50%); |
||||||
|
right: 1rem; |
||||||
|
position: absolute; |
||||||
|
height: 1.5rem; |
||||||
|
} |
||||||
|
|
||||||
|
.arrow { |
||||||
|
margin-top: .4rem; |
||||||
|
margin-left: .5rem; |
||||||
|
width: 0; |
||||||
|
height: 0; |
||||||
|
border: .3rem solid transparent; |
||||||
|
border-top: .5rem solid black; |
||||||
|
} |
||||||
|
|
||||||
|
&::before { |
||||||
|
content: ' '; |
||||||
|
position: absolute; |
||||||
|
width: 1px; |
||||||
|
height: .8rem; |
||||||
|
top: 4px; |
||||||
|
right: 0; |
||||||
|
background: gainsboro; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.right { |
||||||
|
//background: red; |
||||||
|
position: relative; |
||||||
|
|
||||||
|
&.flex1 { |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
|
||||||
|
img { |
||||||
|
top: 50%; |
||||||
|
transform: translateY(-50%); |
||||||
|
right: 1rem; |
||||||
|
position: absolute; |
||||||
|
height: 1.5rem; |
||||||
|
} |
||||||
|
|
||||||
|
.disabled { |
||||||
|
color: $second-text-color; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
input { |
||||||
|
width: 90%; |
||||||
|
outline: none; |
||||||
|
border: none; |
||||||
|
background: whitesmoke; |
||||||
|
caret-color: red; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue