2018-03-26 16:04:04 +08:00
|
|
|
<template>
|
|
|
|
<div class="md-captcha" v-show="isView || value || visible">
|
|
|
|
<template v-if="isView">
|
|
|
|
<div class="md-captcha-content">
|
|
|
|
<h2 class="md-captcha-title" v-if="title" v-text="title"></h2>
|
2018-04-11 15:22:40 +08:00
|
|
|
<div class="md-captcha-message">
|
2018-03-26 16:04:04 +08:00
|
|
|
<slot></slot>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<md-codebox
|
|
|
|
ref="codebox"
|
|
|
|
v-model="code"
|
|
|
|
:maxlength="maxlength"
|
|
|
|
:system="system"
|
|
|
|
:mask="mask"
|
|
|
|
@submit="$_onSubmit"
|
2018-08-27 19:17:20 +08:00
|
|
|
:closable="false"
|
|
|
|
:isView="true"
|
|
|
|
:justify="true"
|
|
|
|
:autofocus="false"
|
2018-09-14 16:03:24 +08:00
|
|
|
>
|
|
|
|
<footer class="md-captcha-footer">
|
2018-11-15 15:47:44 +08:00
|
|
|
<div class="md-captcha-error" v-if="errorMsg" v-text="errorMsg"></div>
|
|
|
|
<div class="md-captcha-brief" v-else v-text="brief"></div>
|
2018-09-14 16:03:24 +08:00
|
|
|
<button
|
|
|
|
class="md-captcha-btn"
|
|
|
|
v-if="count"
|
|
|
|
v-text="countBtnText"
|
|
|
|
:disabled="this.isCounting"
|
|
|
|
@click="$_onResend"
|
|
|
|
></button>
|
|
|
|
</footer>
|
|
|
|
</md-codebox>
|
2018-03-26 16:04:04 +08:00
|
|
|
</template>
|
|
|
|
<template v-else>
|
|
|
|
<md-dialog
|
|
|
|
:value="value"
|
|
|
|
:closable="true"
|
|
|
|
:appendTo="false"
|
|
|
|
position="center"
|
|
|
|
@input="$_onInput"
|
|
|
|
@show="$_onShow"
|
|
|
|
@hide="$_onHide"
|
|
|
|
>
|
|
|
|
<div class="md-captcha-content">
|
|
|
|
<h2 class="md-captcha-title" v-if="title" v-text="title"></h2>
|
2018-04-11 15:22:40 +08:00
|
|
|
<div class="md-captcha-message">
|
2018-03-26 16:04:04 +08:00
|
|
|
<slot></slot>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<md-codebox
|
|
|
|
ref="codebox"
|
|
|
|
v-model="code"
|
|
|
|
:maxlength="maxlength"
|
|
|
|
:system="system"
|
|
|
|
:closable="false"
|
|
|
|
:mask="mask"
|
2018-08-27 19:17:20 +08:00
|
|
|
:justify="true"
|
2018-03-26 16:04:04 +08:00
|
|
|
:autofocus="false"
|
|
|
|
@submit="$_onSubmit"
|
2018-09-14 16:03:24 +08:00
|
|
|
>
|
|
|
|
<footer class="md-captcha-footer">
|
2018-11-15 15:47:44 +08:00
|
|
|
<div class="md-captcha-error" v-if="errorMsg" v-text="errorMsg"></div>
|
|
|
|
<div class="md-captcha-brief" v-else v-text="brief"></div>
|
2018-09-14 16:03:24 +08:00
|
|
|
<button
|
|
|
|
class="md-captcha-btn"
|
|
|
|
v-if="count"
|
|
|
|
v-text="countBtnText"
|
|
|
|
:disabled="this.isCounting"
|
|
|
|
@click="$_onResend"
|
|
|
|
></button>
|
|
|
|
</footer>
|
|
|
|
</md-codebox>
|
2018-03-26 16:04:04 +08:00
|
|
|
</md-dialog>
|
|
|
|
</template>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
import Dialog from '../dialog'
|
|
|
|
import Codebox from '../codebox'
|
|
|
|
import Button from '../button'
|
2018-12-06 16:28:45 +08:00
|
|
|
import {mdDocument} from '../_util'
|
2018-03-26 16:04:04 +08:00
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'md-captcha',
|
|
|
|
|
|
|
|
components: {
|
|
|
|
[Dialog.name]: Dialog,
|
|
|
|
[Codebox.name]: Codebox,
|
|
|
|
[Button.name]: Button,
|
|
|
|
},
|
|
|
|
|
|
|
|
props: {
|
|
|
|
title: {
|
|
|
|
type: String,
|
|
|
|
},
|
2018-11-15 15:47:44 +08:00
|
|
|
brief: {
|
|
|
|
type: String,
|
|
|
|
default: '',
|
|
|
|
},
|
2018-03-26 16:04:04 +08:00
|
|
|
value: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
maxlength: {
|
|
|
|
type: [Number, String],
|
|
|
|
default: 4,
|
|
|
|
},
|
|
|
|
mask: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
system: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
2018-05-20 21:33:27 +08:00
|
|
|
autoCountdown: {
|
|
|
|
type: Boolean,
|
|
|
|
default: true,
|
|
|
|
},
|
2018-03-26 16:04:04 +08:00
|
|
|
appendTo: {
|
2018-12-06 16:28:45 +08:00
|
|
|
default: () => mdDocument.body,
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
count: {
|
|
|
|
type: Number,
|
|
|
|
default: 60,
|
|
|
|
},
|
2018-05-20 21:33:27 +08:00
|
|
|
countNormalText: {
|
|
|
|
type: String,
|
|
|
|
default: '发送验证码',
|
|
|
|
},
|
|
|
|
countActiveText: {
|
|
|
|
type: String,
|
|
|
|
default: '{$1}秒后重发',
|
|
|
|
},
|
2018-03-26 16:04:04 +08:00
|
|
|
isView: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
code: '',
|
|
|
|
visible: false,
|
2018-04-11 15:22:40 +08:00
|
|
|
errorMsg: '',
|
2018-03-26 16:04:04 +08:00
|
|
|
isCounting: false,
|
|
|
|
firstShown: false,
|
2018-05-20 21:33:27 +08:00
|
|
|
countBtnText: this.countNormalText,
|
2018-03-26 16:04:04 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
watch: {
|
|
|
|
value(val) {
|
|
|
|
if (val) {
|
|
|
|
this.code = ''
|
|
|
|
if (!this.firstShown) {
|
|
|
|
this.firstShown = true
|
2018-05-20 21:33:27 +08:00
|
|
|
this.$_onResend()
|
2018-03-26 16:04:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2018-04-11 15:22:40 +08:00
|
|
|
code(val) {
|
|
|
|
if (val && this.errorMsg) {
|
|
|
|
this.errorMsg = ''
|
|
|
|
}
|
|
|
|
},
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
if (this.appendTo && !this.isView) {
|
|
|
|
this.appendTo.appendChild(this.$el)
|
|
|
|
}
|
2018-05-20 21:33:27 +08:00
|
|
|
if (this.value || this.isView) {
|
2018-03-26 16:04:04 +08:00
|
|
|
this.firstShown = true
|
2018-05-20 21:33:27 +08:00
|
|
|
this.$_onResend()
|
2018-03-26 16:04:04 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-04-18 15:05:47 +08:00
|
|
|
beforeDestroy() {
|
|
|
|
if (this.appendTo && !this.isView) {
|
|
|
|
this.appendTo.removeChild(this.$el)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-03-26 16:04:04 +08:00
|
|
|
methods: {
|
|
|
|
// MARK: events handler, 如 $_onButtonClick
|
|
|
|
$_onInput(val) {
|
|
|
|
this.$emit('input', val)
|
|
|
|
},
|
|
|
|
$_onShow() {
|
|
|
|
this.visible = true
|
|
|
|
this.$refs.codebox.focus()
|
|
|
|
this.$emit('show')
|
|
|
|
},
|
|
|
|
$_onHide() {
|
|
|
|
this.visible = false
|
|
|
|
this.$refs.codebox.blur()
|
|
|
|
this.$emit('hide')
|
|
|
|
},
|
|
|
|
$_onSubmit(code) {
|
|
|
|
this.$emit('submit', code)
|
|
|
|
},
|
2018-05-20 21:33:27 +08:00
|
|
|
$_onResend() {
|
|
|
|
if (this.autoCountdown) {
|
|
|
|
this.countdown()
|
|
|
|
}
|
|
|
|
this.$emit('send', this.countdown)
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
// MARK: public methods
|
|
|
|
countdown() {
|
2018-04-24 22:49:00 +08:00
|
|
|
if (!this.count) {
|
|
|
|
return
|
|
|
|
}
|
2018-03-26 16:04:04 +08:00
|
|
|
clearInterval(this.__counter__)
|
2018-11-30 19:35:11 +08:00
|
|
|
const timestamp = Date.now()
|
|
|
|
let i = this.count
|
2018-03-26 16:04:04 +08:00
|
|
|
this.isCounting = true
|
2018-05-20 21:33:27 +08:00
|
|
|
this.countBtnText = this.countActiveText.replace('{$1}', i)
|
2018-04-23 17:33:32 +08:00
|
|
|
/* istanbul ignore next */
|
2018-03-26 16:04:04 +08:00
|
|
|
this.__counter__ = setInterval(() => {
|
2018-11-30 19:35:11 +08:00
|
|
|
if (i <= 1) {
|
2018-03-26 16:04:04 +08:00
|
|
|
this.resetcount()
|
|
|
|
} else {
|
2018-11-30 19:35:11 +08:00
|
|
|
i = this.count - Math.floor((Date.now() - timestamp) / 1000)
|
2018-05-20 21:33:27 +08:00
|
|
|
this.countBtnText = this.countActiveText.replace('{$1}', i)
|
2018-03-26 16:04:04 +08:00
|
|
|
}
|
|
|
|
}, 1000)
|
|
|
|
},
|
|
|
|
resetcount() {
|
|
|
|
this.isCounting = false
|
2018-05-20 21:33:27 +08:00
|
|
|
this.countBtnText = this.countNormalText
|
2018-03-26 16:04:04 +08:00
|
|
|
clearInterval(this.__counter__)
|
|
|
|
},
|
2018-04-11 15:22:40 +08:00
|
|
|
setError(msg) {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
this.errorMsg = msg
|
2018-12-17 17:20:12 +08:00
|
|
|
// this.code = ''
|
2018-04-11 15:22:40 +08:00
|
|
|
})
|
|
|
|
},
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="stylus">
|
2018-08-27 19:17:20 +08:00
|
|
|
.md-captcha
|
|
|
|
.md-dialog
|
2018-11-11 12:17:35 +08:00
|
|
|
.md-popup
|
2018-09-13 16:14:47 +08:00
|
|
|
z-index captcha-zindex
|
2018-08-27 19:17:20 +08:00
|
|
|
.md-dialog-body
|
2018-09-14 16:03:24 +08:00
|
|
|
padding 60px 60px 30px 60px
|
2018-08-27 19:17:20 +08:00
|
|
|
.md-dialog-content
|
|
|
|
margin-bottom number-keyboard-height
|
2018-09-14 16:03:24 +08:00
|
|
|
.md-codebox
|
|
|
|
margin-bottom 28px
|
2018-08-27 19:17:20 +08:00
|
|
|
|
|
|
|
.md-captcha-content
|
|
|
|
font-size captcha-font-size
|
|
|
|
color captcha-color
|
|
|
|
text-align center
|
|
|
|
line-height 1.2
|
|
|
|
margin-bottom 50px
|
|
|
|
|
|
|
|
.md-captcha-title
|
|
|
|
color captcha-title-color
|
|
|
|
font-size captcha-title-font-size
|
|
|
|
font-weight normal
|
|
|
|
line-height 1.15
|
|
|
|
margin 0 0 16px 0
|
|
|
|
|
|
|
|
.md-captcha-footer
|
2018-09-14 16:03:24 +08:00
|
|
|
margin 28px 0
|
2018-08-27 19:17:20 +08:00
|
|
|
display flex
|
|
|
|
font-size captcha-footer-font-size
|
|
|
|
justify-content space-between
|
|
|
|
align-items center
|
|
|
|
overflow hidden
|
|
|
|
|
2018-11-15 15:47:44 +08:00
|
|
|
.md-captcha-error, .md-captcha-brief
|
2018-08-27 19:17:20 +08:00
|
|
|
flex 1 1 0%
|
2018-11-15 15:47:44 +08:00
|
|
|
.md-captcha-error
|
2018-08-27 19:17:20 +08:00
|
|
|
color captcha-error-color
|
2018-11-15 15:47:44 +08:00
|
|
|
.md-captcha-brief
|
|
|
|
color captcha-brief-color
|
2018-08-27 19:17:20 +08:00
|
|
|
|
|
|
|
.md-captcha-btn
|
|
|
|
display inline-block
|
|
|
|
color captcha-btn-color
|
|
|
|
font-size captcha-footer-font-size
|
|
|
|
padding 0
|
|
|
|
margin 0 0 0 12px
|
|
|
|
border 0
|
|
|
|
border-radius 0
|
|
|
|
background none
|
|
|
|
&:disabled
|
|
|
|
color color-text-disabled
|
2018-03-26 16:04:04 +08:00
|
|
|
</style>
|