uniapp 电商app 手机充值页面

本文介绍了一款电商App中手机充值功能的具体实现过程。包括如何获取手机充值配置、判断手机号的有效性和运营商类型,以及如何通过简单的动画效果提升用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

电商app支持手机充值

现在很多的电商app都是支持手机充值的,我们公司也实现了这个功能。

在这里插入图片描述
功能很简单,写文章主要是为了记录,没有什么技术难点。

获取手机充值配置

页面加载的时候,需要展示一个默认运营商的手机充值配置,我们公司默认的是联通的配置。

获取配置的接口可以写在onload函数中。

函数触发流程:

  1. 先判断公司是否有可用余额,这是一个接口。
  2. 在获取默认联通的手机配置信息,并渲染。

获取手机运营商

获取手机运营商的信息,一般都是通过手机号前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>

//微信充值 //支付接口测试 function balance(url, data) { uni.request({ url: cfg.originUrl + '/wx/mp/js_sig.do', data: { route: url }, method: 'GET', success: (res) => { jweixin.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来 appId: res.data.appId, // 必填,公众号的唯一标识 timestamp: res.data.timestamp, // 必填,生成签名的时间戳 nonceStr: res.data.nonceStr, // 必填,生成签名的随机串 signature: res.data.signature, // 必填,签名 jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表 }); jweixin.ready(function() { uni.request({ url: cfg.originUrl + '/wx/recharge/pay.do', method: 'POST', header: { 'Content-type': "application/x-www-form-urlencoded", }, data: JSON.stringify(data), success: function(res) { alert("下单成功"); alert(JSON.stringify(res)); alert(res.data.order_id); all.globalData.orderId = res.data.order_id; uni.setStorageSync('orderId', res.data.order_id); jweixin.chooseWXPay({ timestamp: res.data.payParams.timeStamp, // 支付签名时间戳 nonceStr: res.data.payParams.nonceStr, // 支付签名随机串 package: res.data.payParams.package, // 接口返回的prepay_id参数 signType: res.data.payParams.signType, // 签名方式 paySign: res.data.payParams.paySign, // 支付签名 success: function(e) { alert("支付成功"); alert(JSON.stringify(e)); // 支付成功后的回调函数 } }); } }) }); jweixin.error(function(res) { // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 console.log("验证失败!") }); } }) }
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶浩成520

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值