- 引入
- 代码演示
- 基本
- 使用插槽及其他配置
- API
- Cashier Props
- Cashier Methods
- next(scene, option)
- Captcha Slots
- header
- footer
- channel
- payButton
- scene
- Cashier Events
- @select(item: {text, value})
- @pay(item: {text, value})
- @cancel()
- @show()
- @hide()
Cashier 收银台

业务支付弹窗,支持支付渠道选择和支付验证码发送
引入
import { Cashier } from 'mand-mobile'Vue.component(Cashier.name, Cashier)
代码演示
基本

<template><div class="md-example-child md-example-child-cashier"><md-fieldtitle="支付结果"><md-radio-listv-model="cashierResult":options="cashierResults"/></md-field><md-fieldtitle="支付配置"><md-input-itemtitle="支付金额"align="right"type="money"v-model="cashierAmount"></md-input-item><md-field-itemtitle="发送验证码"align="right"><md-switch v-model="isCashierCaptcha"></md-switch></md-field-item></md-field><md-button @click="isCashierhow = !isCashierhow">{{ isCashierhow ? '收起收银台' : '唤起收银台' }}</md-button><md-cashierref="cashier"v-model="isCashierhow":channels="cashierChannels":channel-limit="2":payment-amount="cashierAmount"payment-describe="关于支付金额的特殊说明"large-radius@select="onCashierSelect"@pay="onCashierPay"@cancel="onCashierCancel"></md-cashier></div></template><script>import {Button, RadioList, Field, FieldItem, InputItem, Switch, Cashier, Toast} from 'mand-mobile'export default {name: 'cashier-demo',components: {[Button.name]: Button,[RadioList.name]: RadioList,[Field.name]: Field,[FieldItem.name]: FieldItem,[InputItem.name]: InputItem,[Switch.name]: Switch,[Cashier.name]: Cashier,},data() {return {isCashierhow: false,isCashierCaptcha: false,cashierAmount: '100.00',cashierResult: 'success',cashierResults: [{text: '支付成功',value: 'success',},{text: '支付失败',value: 'fail',},],cashierChannels: [{icon: 'cashier-icon-1',text: '招商银行(0056)',value: '001',},{icon: 'cashier-icon-2',text: '支付宝支付',value: '002',},{icon: 'cashier-icon-3',text: '微信支付',value: '003',},{icon: 'cashier-icon-4',text: 'QQ钱包支付',value: '004',},{icon: 'cashier-icon-5',text: '一网通支付',value: '005',},],}},computed: {cashier() {return this.$refs.cashier},},methods: {doPay() {if (this.isCashierCaptcha) {this.cashier.next('captcha', {text: 'Verification code sent to 156 **** 8965',brief: 'The latest verification code is still valid',autoCountdown: false,countNormalText: 'Send Verification code',countActiveText: 'Retransmission after {$1}s',onSend: countdown => {console.log('[Mand Mobile] Send Captcha')this.sendCaptcha().then(() => {countdown()})},onSubmit: code => {console.log(`[Mand Mobile] Send Submit ${code}`)this.checkCaptcha(code).then(res => {if (res) {this.createPay().then(() => {this.cashier.next(this.cashierResult)})}})},})} else {this.createPay().then(() => {this.cashier.next(this.cashierResult, {buttonText: '好的',handler: () => {this.isCashierhow = falseToast.info(`${this.cashierResult}点击`)},})})}},// Create a pay request & check pay resultcreatePay() {this.cashier.next('loading')return new Promise(resolve => {this.timer = setTimeout(() => {resolve()}, 3000)})},// Create a captcha sending requestsendCaptcha() {return new Promise(resolve => {this.timer = setTimeout(() => {resolve()}, 200)})},// Create a captcha checking requestcheckCaptcha(code) {return new Promise(resolve => {this.timer = setTimeout(() => {resolve(!!code)}, 200)})},onCashierSelect(item) {console.log(`[Mand Mobile] Select ${JSON.stringify(item)}`)},onCashierPay(item) {console.log(`[Mand Mobile] Pay ${JSON.stringify(item)}`)this.doPay()},onCashierCancel() {// Abort pay request or checking requestthis.timer && clearTimeout(this.timer)},},}</script><style lang="stylus">.md-example-child-cashier.md-fieldmargin-bottom 30px.md-cashier-channel-item.item-icon.cashier-icon-1background url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAABHklEQVR4Ae2WgUYEURSGh70oQIB6gh6gHmBsqhfqHdq2hAJTUYAACMCytqQISUDAVpsEsWi09TX/XFcxYeJ0E/vzMf4z7uc6cJMQWi6l1egU5AUYkfszXZp8TVFmBfwyWbhZU0UcXKrbdWMJ5ZLwNaIwl5CY1BPen8HgAtoT1dn6pJ/dnRoKn64p01mpztQpj1eGwsNlyuTPsDX92W/P+A70j6FQ3BxR5nI3dP4bNDPeochmYZTD+xvsz8HBvP8evWhmLvScb1Cm3/Mo6sLcXLg5BcMHQhgO1BkL+8fUjP6NLLw9MRB+R0h19h+F4x3WYSystVe/rx/zJ0+MXtxHVNstxBO6ZqKw2tiLINxJQrzULenKxjvVWV3W3GLwfAD9KR4TBA12SgAAAABJRU5ErkJggg==') center no-repeatbackground-size 26px.item-icon.cashier-icon-2background url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAB7ElEQVR4Ac2WA6weQRSFb62gtuPajetGtW0FNcO6cVK7XdRu2Ia149R2Z6bP9r6T+yb5bZ7k/Bh9gzt3l1hXfzUiS+4iU36GK2AnTq6AP/PYJ/42JhZ+oPAp7CTWYDDUVHu4IDneCaD8kkTgV4r4zA5+akBuivhMI56llyLv768wXkpfYNK3NGXAaHQhpxlHY9KAlpwc6Qojt6W2urZYnYoFWA5XhWhTSaf/dmHYDqc2/v+NFPiZDLmKzv7pxAPAZIvWZPwbjrqN8B242LU6edUtgMZGGjS3XI8R6IRTj/yI2xhiPNofA7CPCyiuRAL8wM9FUy6AH8I5urwE/gwb8FSdS311+ldz1KsIgGIpmWpNGEGSQYbaC7f1gWIyPClD3uaJBgWeld3x/S3MyCwkWwz1AfqsWCzV8EIfIAeJqd6GAcuHx7oFylz4AVlqGl116gQ/c3HABTTkFH1pywPD1Esy//V0wdQMlJe6Rex3MtQ2OvO/fRgZXbziGVqqP+CmXm0m/AED2WT9G0GOU4sg/sYVCZLCyngrLTHRJ9K9Gl4jWzShYDoj+5Ih7keQiSQWcwgTHqKBPrP8wanK/D+QLzwOH4DeOgDu+maeiPwmBS9RuFNJA1pyV9JfhF33BHS9vZVxhFTWjCn2kYZVAyRlGm3AoxGeAAAAAElFTkSuQmCC') center no-repeatbackground-size 26px.item-icon.cashier-icon-3background url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAYCAYAAADpnJ2CAAABiklEQVR4AbWVAWRCURSGf8gIGQyYgUEAgyAAbCCAAAQQGBAYIGAwAAgIwAMJGIsqRTAgQPAQEsKDu//kXHLddV+v+w6f0HnvP/e8/5yLYPzgAXN0yICsSUoyZUeW+l/nlFs45miSRF9scpKRBDM0rhGqacXmRobhE8/wwsQtMZHYyjv/E2swYU9MZPZW1DVGWoLYEQt88ffR/W7DyEIHCn3ab4gVKpjhzbayHlOI9K2QHqZFNsSctKSSCEI78oE17h1PTJy8PnRwjYdNjlanpEdqsLHC04XnltA2+KuWiudoe9y7xQLvWKF6JlSVE5DjxZZf3CRs91nV3zqjXYxw55iuk9PlGQKJGaZ4hoR123lM8cqc3yu+dSqC40BS4lkSdf9zQcY4tSic2LQLQgc5K+jmrl3Wu0DiUkxy4+o72LEJnDISUrDjtKREwTHc0DkalSA2sfPqE62oKWKJDWRmgzd+BKENaUGjLMGjzmbbLoiigmvSk/tMnKa3y0DQ9vdIM9S6gKCK6FqLGX+Ik2Cgy7oRZQAAAABJRU5ErkJggg==') center no-repeatbackground-size 26px.item-icon.cashier-icon-4background url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAcCAYAAAB75n/uAAADaElEQVR4AWIgADiAOAaI1wDxUxZAadUA5GoTBCd59Wzbtm3btm3btm3btm3btt/5+v/6uLXRl/q7qu+SRc/OzKbXIhAh5ZXB1QZLyf8ANz+noAseNZhc3ETb4NOaocUiX+JFlYJiEuU1cdNBzGQSjbVWN3bu3BkHDx5EgQIFQsb69u2LjRs3IkWKFHqgE+ICndUNFCB27drFIBxDoUKFcP/+fZLj9rIpL05wVV1co0YNEBQdP3484sWLx9OjXbt2JD5//mwvwBaHV1KvPctCsEyLFy9GxIgRQeErV67g2rVrePz4sf1eOEBGLtB56tQpEPPmzQO/x4gRAx8+fADRvXt3R02PJnaQw97inKnCYkiLTBjf2IJ5bQTkxJax0KdpdiSPK44CxBcdk5LE7qqWaGxDwZv5AmxyzjtTLKiVP3QfNfakTVBZdDzOHHPDhESREBxkQA3Br4Vh8WlyJAr568Leq634MC4yPs63onz2UPEVySL7vswcc6LoeJIx+vPXmWNgW8ooSBs+DDcgY2LBoYEWvBoaDVeaJMSNlvFD+G5sZJYLsaMGlTJiGOxPFRXUuJ8x+nnREO16+ui+nAzm4qSRUT5qWES2Bpbg7OCwuNcjJok1nawMzjlUix4Oq5NHhrr3WJqonnqj5/HUJ9IEnkAnx5n6rMSRQFLQ0VpmkSSslVlNkyAkD647/y8pkx9vC6XiYrf4tnh6dEocHapWsDdNVK/Y/Pnz8XvdYlOiH6rlx7fh3eFx8iDg54uyZcvq13W8jT1s3boVPyYPVYXg/+8vfJ4/htedayT42d/TAzoaNmyoB7gquj3QJXkqNQBPZwZ6gCBtgcpp06bZBPD79QMmQFNUhYMpj4M+dOYEHdT3y0f8nDsBX3u3wpdujU1l4OHhgQgRIsBqld+K7VNbBgU1mlhNx6SZuYtVq1ZRUL2e04TaGuLTbmnP7uDv379Ily4dxZ/bOqkGPt5Mk802i+bNm4MHy5ZccokzYJOMN/jn6WxBscxhwVfM29sbjsBSsmclMoc47x9q2BffLP00x/TfM0DQvkYqjB45BHyT+Q7zNeNvpWuntmhUIgq4RtsHaokObJS2nHRAf2a1s5/s3NFXtvOzauE6qeWoRHUMHjT4mQJBfGpws8HKyrrKHOOcso57DlJDFPwHtUxGlWBNgLkAAAAASUVORK5CYII=') center no-repeatbackground-size 26px.item-icon.cashier-icon-5background url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAABPlBMVEUAAAC/AEDIFS3GFS3HFS3HFS3HFS3MADPGFC7GFS3FFSvHFS3GFS3HFS3HFS3KIjnooKnmmKPJHDTMLELqqLHmlaDIGjHONEnssLjkjJjHFi7////hgI3rqrLdcoDwwsjUS17KITjed4T44+XIGC/LJz3++fr119vQPFD//v7NMEXgf43ca3r78PLZX3DVUWPpoavut77IGTD44+bxxszmlqHxw8nHFy/44OPttr3LJjz99/jaZXXXWWrhgY7+/P3//f3XV2jzzdPgf4zut7/nmqTxxMrllJ/yyM7dcH/++vvMK0HWUmTQO0/ZYXHba3r77vDJHTTts7v22Nzxxcv55OffdoXed4XRP1PedIPaZHThg5D11dnVTmDJHzb77e/55+rLJj377/Hqp7DkjprTRlnlkZzRPlLNL0TXVmdZnHwTAAAAD3RSTlMABEqUzPH/BXDmMNZV+P145yZGAAABMklEQVR4AXTQ02KcARCG4Z/v2t5vVdv2to1t2/d/BcnEfE7H45xxPT8IIQx8z3WuikRjnItFI5dj8QRXJOIXsWSKa1LJ81iaG9Kn0XiKW6TiFoskuFXCtopyh+jRfTFMJpvLA4ViqQxUqrU6MdfxwJSkBtCUWkBb6oDn+Jh796UHD3n0WHoCT6Vnz8F3AsyLl6+k1zQk6Q1vpXdA4IQWe//h4yfp85evFvz2/YdlQOhgfkq/nkm/pT9S96/1NifBf9L/HpnePql/QIMYa0tHGhoekRkdk16NT0yCtQ2AKalIfVrSDO9npbl5TGCnPO9KC7AoaQmWpRUwvj1hVWoDa+vaKMPmlrbBePa+LzvVCsDu3j7AweEyxSAJghFfwOONMnyRjS+Z4Etg+JIm4USNNzsAAPHdK2mIKv4bAAAAAElFTkSuQmCC') center no-repeatbackground-size 26px</style>
使用插槽及其他配置

<template>
<div class="md-example-child md-example-child-cashier">
<md-button @click="isCashierhow = !isCashierhow">{{ isCashierhow ? '收起收银台' : '唤起收银台' }}</md-button>
<md-cashier
ref="cashier"
v-model="isCashierhow"
:channels="cashierChannels"
:payment-amount="cashierAmount"
payment-describe="关于支付金额的特殊说明"
large-radius
@show="onCashierShow"
@select="onCashierSelect"
@pay="onCashierPay"
@cancel="onCashierCancel"
>
<div slot-scope="{ scene }" slot="header">
<md-notice-bar
v-if="scene === 'choose'"
mode="closable"
icon="warn"
type="warning"
>
该银行3:00-12:00系统维护,请更换其他银行卡
</md-notice-bar>
</div>
<div slot-scope="{ scene }" slot="footer">
<div v-if="scene === 'choose' && !isCashierInitialed" class="cashier-loading">
<md-activity-indicator :size="30" vertical>加载中...</md-activity-indicator>
</div>
</div>
<div slot="payButton" style="display:flex;">
<md-icon name="checked"></md-icon>发起支付
</div>
<div slot="scene" class="custom-scene">
Custom Scene
</div>
</md-cashier>
</div>
</template>
<script>
import {Button, Icon, Cashier, Toast, NoticeBar, ActivityIndicator} from 'mand-mobile'
export default {
name: 'cashier-demo',
components: {
[Button.name]: Button,
[Cashier.name]: Cashier,
[Icon.name]: Icon,
[NoticeBar.name]: NoticeBar,
[ActivityIndicator.name]: ActivityIndicator,
},
data() {
return {
isCashierhow: false,
isCashierInitialed: false,
isCashierCaptcha: false,
cashierAmount: '100.00',
cashierResult: 'success',
cashierResults: [
{
text: '支付成功',
value: 'success',
},
{
text: '支付失败',
value: 'fail',
},
],
cashierChannels: [
{
img: 'https://pt-starimg.didistatic.com/static/starimg/img/rZBbFoIJEJ1546934427562.png',
text: 'XX银行(1234)',
desc: '当前银行维护中',
value: '001',
disabled: true,
action: {
text: '更换',
handler: () => {
Toast.info('点击更换银行卡')
},
},
},
],
}
},
computed: {
cashier() {
return this.$refs.cashier
},
},
methods: {
doPay() {
if (this.isCashierCaptcha) {
this.cashier.next('captcha', {
text: 'Verification code sent to 156 **** 8965',
autoCountdown: false,
countNormalText: 'Send Verification code',
countActiveText: 'Retransmission after {$1}s',
onSend: countdown => {
console.log('[Mand Mobile] Send Captcha')
this.sendCaptcha().then(() => {
countdown()
})
},
onSubmit: code => {
console.log(`[Mand Mobile] Send Submit ${code}`)
this.checkCaptcha(code).then(res => {
if (res) {
this.createPay().then(() => {
this.cashier.next(this.cashierResult)
})
}
})
},
})
} else {
this.createPay().then(() => {
this.cashier.next(this.cashierResult, {
actions: [
{
buttonText: '返回',
handler: () => {
this.cashier.next('choose')
},
},
{
buttonText: '重试',
handler: () => {
this.cashier.next('custom')
},
},
],
})
})
}
},
// Create a pay request & check pay result
createPay() {
this.cashier.next('loading')
return new Promise(resolve => {
this.timer = setTimeout(() => {
resolve()
}, 3000)
})
},
// Create a captcha sending request
sendCaptcha() {
return new Promise(resolve => {
this.timer = setTimeout(() => {
resolve()
}, 200)
})
},
// Create a captcha checking request
checkCaptcha(code) {
return new Promise(resolve => {
this.timer = setTimeout(() => {
resolve(!!code)
}, 200)
})
},
onCashierShow() {
setTimeout(() => {
this.isCashierInitialed = true
}, 2000)
},
onCashierSelect(item) {
console.log(`[Mand Mobile] Select ${JSON.stringify(item)}`)
},
onCashierPay(item) {
console.log(`[Mand Mobile] Pay ${JSON.stringify(item)}`)
this.doPay()
},
onCashierCancel() {
// Abort pay request or checking request
this.timer && clearTimeout(this.timer)
},
},
}
</script>
<style lang="stylus">
.md-example-child-cashier
.md-field
margin-bottom 30px
.custom-scene
min-height 300px
display flex
justify-content center
align-items center
font-size 32px
.cashier-loading
position absolute
top 0
left 0
right 0
bottom 0
background rgba(255, 255, 255, 0.95)
z-index 1400
display flex
align-items center
justify-content center
</style>
API
Cashier Props
| 属性 | 说明 | 类型 | 默认值 | 备注 |
|---|---|---|---|---|
| v-model | 收银台是否显示 | Boolean | false | - |
| channels | 支付渠道数据源 | Array<{text, value, icon, iconSvg, img, action}> | [] | icon可作为className或组件Icon的name属性, iconSvg为是否使用svg图标, img为图标链接(与icon二选一), action为特殊动作回调 |
| channel-limit | 支付渠道超出限制数目时展示更多支付渠道按钮 | Number | 2 | - |
| default-index | 默认选中支付渠道索引 | Number | 0 | - |
| title | 收银台弹窗标题 | String | 支付 | - |
| large-radius 2.4.0+ | 选择器标题栏大圆角模式 | Boolean | false | - |
| payment-title | 支付金额标题 | String | 支付金额(元) | 支持html fragment |
| payment-amount | 支付金额 | String | 0.00 | 支持html fragment |
| payment-describe | 支付金额说明 | String | - | 支持html fragment |
| pay-button-text | 确认支付按钮文案 | String | 确认支付 | - |
| pay-button-disabled | 禁用支付按钮 | Boolean | false | - |
| more-button-text | 更多支付渠道按钮文案 | String | 更多支付方式 | 支持html fragment |
Cashier Methods
next(scene, option)
进入收银台下一步
| 参数 | 说明 | 类型 | 默认值 | 备注 |
|---|---|---|---|---|
| scene | 步骤场景标识 | String | - | choose(支付渠道选择)captcha(发送验证码)loading(支付中)success(支付成功)fail(支付失败)custom(自定义,使用插槽scene填充内容) |
| option | 当前步骤场景配置 | Object | 属性如下所示 | - |
captchaoption属性 说明 类型 默认值 备注 text 发送验证码说明 String - - brief 发送验证码简要描述 String - - maxlength 验证码位数 Number 4若为 -1则不限制输入长度count 验证码重新发送倒计时 Number 60若为 0则不显示重新发送autoCountdown 是否自动开始倒计时,否则需手动调用 countdownBoolean true- countNormalText 发送验证码正常状态文字 String 发送验证码- countActiveText 发送验证码及倒计时按钮文案配置项 String {$1}秒后重发- onSend 验证码发送回调 Function(countdown: Function) - countdown为开始倒计时方法onSubmit 验证码提交回调 Function(code: String) - code为输入的验证码loadingoption属性 说明 类型 默认值 备注 text 支付中说明 String 支付结果查询中…支持 html fragmentsuccessoption属性 说明 类型 默认值 备注 text 支付成功说明 String 支付成功支持 html fragmentbuttonText 按钮文案 String 我知道了支持 html fragmenthandler 按钮点击回调 Function - - actions 按钮组 Array<{buttonText, handler}> - 有两个按钮时使用 failoption属性 说明 类型 默认值 备注 text 支付失败说明 String 支付失败,请稍后重试支持 html fragmentbuttonText 按钮文案 String 我知道了支持 html fragmenthandler 按钮点击回调 Function - - actions 按钮组 Array<{buttonText, handler}> - 有两个按钮时使用
Captcha Slots
header
头部内容scoped插槽
<div slot-scope="{ scene }" slot="header">
<md-notice-bar
v-if="scene === 'choose'"
mode="closable"
icon="warn"
type="warning"
></md-notice-bar>
</div>
footer
底部内容scoped插槽
channel
支付渠道区域插槽,可用于添加支付渠道特殊操作,如添加银行卡
payButton
发起支付插槽
scene
自定义场景插槽,使用next('custom')打开
Cashier Events
@select(item: {text, value})
支付渠道选中事件
@pay(item: {text, value})
支付渠道确认并发起支付事件
@cancel()
取消支付事件
@show()
收银台弹窗展示事件
@hide()
收银台弹窗隐藏事件
