电商app支持手机充值
现在很多的电商app都是支持手机充值的,我们公司也实现了这个功能。
功能很简单,写文章主要是为了记录,没有什么技术难点。
获取手机充值配置
页面加载的时候,需要展示一个默认运营商的手机充值配置,我们公司默认的是联通的配置。
获取配置的接口可以写在onload函数中。
函数触发流程:
- 先判断公司是否有可用余额,这是一个接口。
- 在获取默认联通的手机配置信息,并渲染。
获取手机运营商
获取手机运营商的信息,一般都是通过手机号前3位或者前4位,所以统一一下,当手机位数超过4位时,进行手机运营商的判断。
充值功能实现
充值的功能,先判断手机号是否存在并合法,手机号的校验可以通过正则表达式,此处通过比较简单的方式来进行校验。
此处为了实现提示信息的效果,如果没有手机号或者手机号有误时,会有动画,这个动画通过animate.css来实现,通过添加或者移除class类名的形式来改变样式。
chongzhi(){
if(!this.phone){
this.msg = "请输入您的手机号码";
this.animateClass = "shake";
setTimeout(()=>{
this.animateClass = "";
}, 1000);
return;
}
if(!/(^1[0-9]{10}$)/.test(this.phone)){
this.msg = "手机号不正确,请重新输入";
this.animateClass = "shake";
setTimeout(()=>{
this.animateClass = "";
}, 1000);
return;
}
this.msg = "";
console.log(this.list[this.currentIndex]);
//此处的接口是为了调用充值接口来出现充值功能
this.$request.urlRequest(
"/gate/mobile/cost/recharge",
{
mobile:this.phone,
itemId:this.list[this.currentIndex].itemId
},
'POST',
(res) => {
if(res.code === 200){
this.delPhone();
this.msg = "";
this.showFlag = true;
this.num = this.list[this.currentIndex].price;
this.orderId = res.result.serialno;
this.id = res.result.id;
}
}
)
}
完整代码
<template>
<view class="container">
<view class="info animated" :class="msg?animateClass:''" v-if="msg" style="font-size:26upx;">
<text class="iconfont icon-jinggao" style="font-size:30upx;"></text><text>{{msg}}</text>
</view>
<view class="inp">
<text class="iconfont icon-shouji"></text>
<view>
<input type="number" :value="phone" placeholder="请输入您要充值的手机号" placeholder-class="grey" @input="input">
<text v-if="phone">{{operator}}</text>
</view>
<text class="iconfont icon-guanbi1" @click="delPhone"></text>
</view>
<view class="list">
<view v-for="(item,index) in list" class="list-item" :class="{'active':currentIndex===index && !item.enable,'disabled':item.enable,'weizhiClass':weizhiFlag}" @click="checkItem(index)">
<view>
<text class="money" :class="{'disabledtxt':weizhiFlag ||(item.enable && !weizhiFlag)}">{{item.facePrice}}</text>元
</view>
<view>
<text v-if="!item.enable">售价:{{item.price}}元</text>
<text v-else>备货中</text>
</view>
</view>
</view>
<view class="btn" @click="chongzhi">立即充值</view>
<pay-style ref="payStyle" :num="num" baseUrl="/gate/mobile/cost/pay" :showFlag="showFlag" @modalFun="modalFun" :orderId="orderId" @payBack="payBack"/>
<view class="tanchuang" v-if="toastFlag" @click="toastFun">
<view class="toast" @click.stop>
<view class="toast-tit">通知</view>
<view class="toast-con">
系统维护中,对您造成不便,敬请谅解!请稍后再试!
</view>
<view class="toast-btn" v-if="systemFlag" @click="toastEnter">确定</view>
<view class="toast-btns" v-else>
<text @click="toastFun">否</text>
<text @click="retypePay">是</text>
</view>
</view>
</view>
</view>
</template>
<script>
import payStyle from "@/components/payStyle.vue"
export default{
data(){
return{
list:[],
currentIndex:4,
phone:undefined,
msg:"",
chooseTypeNum:1,
showFlag:false,
toastFlag:false,
animateClass:"",
systemFlag:false,
operator:"",
orderId:undefined,
num:0,
id:undefined,
weizhiFlag:false
}
},
components:{
payStyle
},
onNavigationBarButtonTap(e) {
if(e.index === 0){
uni.navigateTo({
url:"/pages/chongzhi/recharge"
})
}
},
onLoad() {
this.check();
},
methods:{
payBack(flag){
this.showFlag = false;
if(flag){
uni.navigateTo({
url:"/pages/chongzhi/recharge"
})
this.delPhone();
}else{
this.modalFun();
}
},
modalFun(){
this.$request.urlRequest(
"/gate/mobile/cost/cancel", {
id:this.id,
contype:"form"
},
'POST',
res=>{
if(res.code === 200){
console.log("订单取消成功");
uni.showToast({
title: '充值订单已关闭'
});
}else{
console.log("订单取消失败");
}
}
)
this.showFlag = false;
},
input(e){
console.log(222,this.currentIndex);
this.phone = e.detail.value;
if(e.detail.value.length >= 4){
this.currentIndex = 4;
this.$request.urlRequest(
"/gate/mobile/cost/config", {
mobile:e.detail.value,
contype:"form"
},
'POST',
(res) => {
if(res.code === 200){
this.list = res.result.mobileRechargeConfigVos;
console.log(this.currentIndex,1111,this.list[this.currentIndex]);
if(this.currentIndex !==undefined && this.list[this.currentIndex].enable){
this.currentIndex = undefined;
}
let index = res.result.operator;
let msg = ""
if(index===1){
msg = "移动"
this.weizhiFlag = false;
}else if(index === 2){
msg = "联通"
this.weizhiFlag = false;
}else if(index === 3){
msg = "电信"
this.weizhiFlag = false;
}else{
msg = "未知"
this.weizhiFlag = true;
this.currentIndex = undefined;
}
this.operator = `${"("+ msg+")"}`
}
}
)
}else if(e.detail.value.length < 4){
this.operator="";
}
},
check(){
this.$request.urlRequest(
"/gate/mobile/cost/check", {},
'POST',
(res) => {
if(res.result){
this.getList();
}else{
this.systemFlag = true;
this.toastFlag = true;
}
}
)
},
getList(){
this.$request.urlRequest(
"/gate/mobile/cost/config", {},
'POST',
(res) => {
if(res.code === 200){
console.log(res);
this.list = res.result.mobileRechargeConfigVos;
if(this.list[0].operator && this.list[0].operator == 4){
console.log("当前为未知手机号");
this.weizhiFlag = true;
this.currentIndex = undefined;
}else{
this.weizhiFlag = false;
}
}
}
)
},
toastEnter(){
this.toastFlag = false;
this.systemFlag = false;
setTimeout(()=>{
uni.navigateBack();
uni.hideToast();
},100)
},
toastFun(){
this.toastFlag = false;
},
chooseType(index){
this.chooseTypeNum = index;
},
delPhone(){
this.phone = "";
},
checkItem(index){
if(this.weizhiFlag){
this.currentIndex = undefined;
return;
}
if(this.list[index].enable){
return;
};
this.currentIndex = index;
},
chongzhi(){
if(!this.phone){
this.msg = "请输入您的手机号码";
this.animateClass = "shake";
setTimeout(()=>{
this.animateClass = "";
}, 1000);
return;
}
if(!/(^1[0-9]{10}$)/.test(this.phone)){
this.msg = "手机号不正确,请重新输入";
this.animateClass = "shake";
setTimeout(()=>{
this.animateClass = "";
}, 1000);
return;
}
if(this.currentIndex === undefined){
this.msg = "请选择充值面额";
this.animateClass = "shake";
setTimeout(()=>{
this.animateClass = "";
}, 1000);
return;
}
this.msg = "";
console.log(this.list[this.currentIndex]);
this.$request.urlRequest(
"/gate/mobile/cost/recharge",
{
mobile:this.phone,
itemId:this.list[this.currentIndex].itemId
},
'POST',
(res) => {
if(res.code === 200){
this.msg = "";
this.showFlag = true;
this.num = this.list[this.currentIndex].price;
this.orderId = res.result.serialno;
this.id = res.result.id;
}
}
)
}
}
}
</script>
<style lang="scss" scoped>
page{
position: relative;
height:100%;
}
.container{
width:702upx;
margin:78upx auto 0;
}
.icon-xuanzhong{
color:#FF7424;
}
.icon-weixuanzhong-01{
color:#EEEEEE;
}
.tanchuang{
position: fixed;
bottom:0;
left:0;
top:0;
right:0;
background:rgba(0,0,0,.4);
.toast{
position: absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
width:560upx;
height:424upx;
background:#fff;
text-align: center;
border-radius: 10upx;
overflow: hidden;
.toast-btns{
position: absolute;
bottom:0;
left:0;
width:100%;
height:80upx;
line-height: 80upx;
border-top:1px solid #EEEEEE;
color:#9A9A9A;
font-size:30upx;
display: flex;
align-items: center;
text{
flex:1;
text-align: center;
}
text:last-child{
color:#FF4C4C;
border-left:1px solid #EEEEEE;
}
}
.toast-btn{
width:490upx;
height:70upx;
line-height: 70upx;
background:#FF4C4C;
border-radius: 10upx;
color:#fff;
font-size:30upx;
margin:0 auto;
}
.toast-con{
height:232upx;
width:450upx;
margin:0 auto;
text-align: left;
padding:0 20upx;
box-sizing: border-box;
font-size:26upx;
color:#343434;
line-height: 40upx;
display: flex;
align-items: center;
}
.toast-tit{
height:80upx;
line-height: 80upx;
background:linear-gradient(to right,#FF4C4C,#FF9A6C);
font-size:30upx;
color:#fff;
}
}
}
.info{
position: absolute;
color:#D32020;
font-size:24upx;
top:26upx;
left:32upx;
padding:0 20upx;
box-sizing: border-box;
.iconfont{
margin-right:5upx;
font-size:26upx;
position: relative;
top:2upx;
left:0;
}
}
.btn{
width:100%;
height:86upx;
line-height: 86upx;
margin-top:90upx;
background:#FF7424;
border-radius: 10upx;
font-size:40upx;
color:#fff;
text-align: center;
box-shadow: 0 2upx 10upx 3upx rgba(0,0,0,.1);
}
.list{
width:100%;
display: flex;
margin:55upx auto;
flex-wrap: wrap;
justify-content: space-between;
&::after {
content: '';
width:204upx;
}
.list-item{
width:204upx;
height:136upx;
margin-bottom:24upx;
border: 1px solid #DEDEDE;
border-radius: 10upx;
box-shadow: 0 0 10upx 3upx rgba(255,76,76,.1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
&:hover{
cursor: pointer;
}
view{
font-size:26upx;
color:#666666;
line-height: 40upx;
}
.money{
color:#343434;
font-size:40upx;
font-family: DIN;
}
.disabledtxt{
color:#9A9A9A;
}
}
.active{
border:1px solid #FF4C4C;
}
.disabled{
background:#EEEEEE;
}
.weizhiClass{
background:#EEEEEE;
}
}
.inp{
width:100%;
height:100upx;
line-height: 100upx;
border-bottom:1px solid #9A9A9A;
// border-radius: 10upx;
display: flex;
align-items: center;
view{
flex:1;
display: flex;
align-items: center;
justify-content: flex-start;
text{
font-size:22upx;
color:#9A9A9A;
}
input{
font-size:40upx;
font-family: DIN;
color:#343434;
}
.grey{
font-size:30upx;
color:#9A9A9A;
}
}
text{
flex-shrink: 0;
padding:0 10upx;
font-size:30upx;
color:#DDDDDD;
font-size:43upx;
}
text:first-child{
color:#9A9A9A;
font-size:43upx;
}
text.icon-guanbi1{
padding-left:20upx;
}
}
</style>