uni-app+uniCloud开发微信小程序之小功能实现思路(持续更新中...)

1.all页实现筛选显示数据

需求分析

  • 从uniCloud中获取数据渲染到界面上
  • 让课程按照课程预约数倒序排序
  • 点击每一项分类之后显示对应的课程信息并更改抽屉旁的文字

实现思路

渲染数据用到了unicloud-db组件,倒序排列直接设置属性orderby="appointment desc"

<unicloud-db v-slot:default="{data, loading, error, options}" collection="starCourse" :where="fwhere" orderby="appointment desc" >
<view v-if="error">{{error.message}}</view>
	<view v-else>
		<view  class="classesone" @click="todetail(item._id)" v-for="(item,index) in data" :key="item._id">
		   	<view>
		   		<image :src="item.path" mode=""></image>
		   		<!-- <text class="hot">hot</text> -->
		   	</view>
		   	<view class="listdetail">
		   		<view><text>{{item.name}}</text></view>
		   		<view><text>¥{{item.price}}</text></view>
		   		
		   		<view>
		   			<text>立即抢购</text>
		   			<text>{{item.appointment}}人预约</text>
		   		</view>
		   		
		   	</view>
		   </view>
		   
	   </view>  
</unicloud-db>

点击切换显示的课程信息
data中的数据:
在这里插入图片描述
在这里插入图片描述
js控制部分

//每次点击分类项之后,切换界面上显示的内容
showSorted(id){
	console.log(this.sortinfo[id].name)
	if(id==0){
		//点击全部
		this.where=''
	}else{
		this.where=`sort=='${this.sortinfo[id].name}'`
	}
	//抽屉右侧文字更新
	this.sortcurrent=this.sortinfo[id].name
	//关闭抽屉
	this.$refs.showRight.close();
	
}
computed:{
	fwhere(){
		var newhere=this.where
		return newhere
	}
}

2.实现搜索页

这个部分因为微信小程序不支持uni-app中RegExp这个语法,如果要写成小程序,实现过程比较复杂,为了不影响进度,所以我写成了app形式的查询。
在这里插入图片描述

需求分析

1.input框内的数据能够自己跳动,点击搜索后搜素当前的值

2.点击搜索能够查询输入的内容

3.点击热门搜索,进入对应的词条内容
4.每次搜索后都可以留下搜索记录,点击删除可以清除历史记录,点击记录也可以进入对应词条的搜索内容

实现思路

实现需求1、2
搜索框部分代码

<view class="sh_search">
	<view>
		<text class="iconfont searchicon">&#xe606;</text>
		<input type="text" @focus="cleartimer"  v-model="searchinfo"  :placeholder="placeholder"/>
	</view>
	<view @click="tosearch">
		<text>搜索</text>
	</view>
</view>

需要的data部分:
在这里插入图片描述
在生命周期onLoad()中写控制placeholder跳动值得代码

onLoad() {
		//控制placeholder中数据的动态变化
		var _that=this
		_that.placetimer=setInterval(function(){
			_that.arrindex%=_that.placearr.length
			_that.arrindex++
			_that.placeholder=_that.placearr[_that.arrindex-1]
			// console.log(_that.arrindex)
		},3000)
}

鼠标聚焦时就清除定时器

cleartimer(){
	//清除定时器
	clearInterval(this.placetimer)
	//赋空值
	this.placeholder=''
},

点击搜索时判断表单有无输入值再判断搜索的内容

//点击搜索
tosearch(){
	// console.log(this.searchinfo)
	if(!this.searchinfo){
		//如果input为空,则让查询的内容等于placeholder中跳动的值
		this.wholeinfo=this.placeholder
	}else{
		//如果input不为空,则让查询的内容等于输入的内容
		this.wholeinfo=this.searchinfo
	}
	
	//点击搜索之后要清除定时器
	this.cleartimer()
},

以上逻辑就可以实现获取到表单的值,接下来需要将该值拿去做模糊查询并展示到界面上,这部分代码结合在需求3、4中

实现需求3、4

搜索历史、热门搜索、搜索结果页面代码

<view class="latest_search" v-show="isearchActive">
		<view class="ls_head">
			<text>最近搜索</text>
			<text @click="delhistory" class="iconfont">&#xe8b6;</text>
		</view>
		<view class="ls_content">
			<text v-for="item,index in searchistory" @click="searchinghot(item)">{{item}}</text>
		</view>
		
	</view>
</view>

<view class="hot_search"  v-show="ishotActive">
	<view class="hs_header">
		<text>热门搜索</text>
	</view>
	<view class="hs_content">
		<view @click="searchinghot('产后康复')">产后康复<text class="iconfont">&#xe65a;</text></view>
		<view @click="searchinghot('注意力集中训练')">注意力集中训练<text class="iconfont">&#xe65a;</text></view>
		<view @click="searchinghot('幼儿钢琴')">幼儿钢琴<text class="iconfont">&#xe65a;</text></view>
		<view @click="searchinghot('昆曲')">昆曲<text class="iconfont">&#xe65a;</text></view>
		<view @click="searchinghot('少儿编程')">少儿编程<text></text></view>
	</view>
</view>

//展示搜索结果
<view class="search_result" v-show="isearched">
	<unicloud-db v-slot:default="{data, loading, error, options}" collection="starCourse" :where="fwhere">
	  <view>
		<view class="single_header">
			搜索到<text>{{ data.length}}</text>门相关的课程
		</view>
		<view class="singleone" @click="todetail(item._id)" v-for="item,index in data " :key="index">
			<view>
				<image :src="item.path" mode="widthFix"></image>
			</view>
			<view class="info">
				<view>
					<text>{{item.name}}</text>
				</view>
				<view>
					<text>{{item.period}}学时</text>
					<text>0基础</text>
					<text>第{{item.term}}期</text>
				</view>
				<view>
					<text>¥{{item.price}}</text>
				</view>
				<view>
					<text>了解详情</text>
					<text>{{item.appointment}}人预约</text>
				</view>
				
			</view>
		</view>
	  </view>
	</unicloud-db>
</view>

data部分
在这里插入图片描述
模板字面量计算得到where模糊查询的条件

computed:{
	fwhere(){
		return {name:new RegExp(`${this.wholeinfo}`)}
	}
}

点击搜索之后控制板块间的显示隐藏,并将input的值拿来作为模糊查询的变量值,还要将搜索记录存入Vuex中

//点击搜索
tosearch(){
	// console.log(this.searchinfo)
	if(!this.searchinfo){
		//如果input为空,则让查询的内容等于placeholder中跳动的值
		this.wholeinfo=this.placeholder
	}else{
		//如果input不为空,则让查询的内容等于输入的内容
		this.wholeinfo=this.searchinfo
	}
	
	//每次点击搜索之后都要将信息存入历史搜索的vuex表中
	if(this.searchistory.indexOf(this.wholeinfo)==-1){
		this.$store.commit('searchistory',this.wholeinfo)
	}
	
	//点击搜索之后要清除定时器
	this.cleartimer()
	
	//点击搜索之后控制几个板块的显示隐藏
	this.ishotActive=false
	this.isearchActive=false
	this.isearched=true
},

Vuex中的state和mutations部分

//搜索的历史记录
searchistory:['书法','培训'],
//删除所有历史记录
delhistory(state){
	state.searchistory=[]
},
//添加搜索历史记录
searchistory(state,payload){
	state.searchistory.push(payload)
},

现在需要实现历史记录的删除,点击搜索等功能

searchinghot(data){
	this.wholeinfo=data
	
	//点击搜索之后要清楚定时器
	this.cleartimer()
	
	//点击搜索之后控制几个板块的显示隐藏
	this.ishotActive=false
	this.isearchActive=false
	this.isearched=true
	
	//每次点击搜索之后都要将信息存入历史搜索的vuex表中
	if(this.searchistory.indexOf(this.wholeinfo)==-1){
		this.$store.commit('searchistory',this.wholeinfo)
	}
},
//删除历史记录
delhistory(){
	// this.searchistory=[]
	this.$store.commit('delhistory')
	this.isearchActive=false
},

以上该部分的功能就全部实现了!

3.实现登录和注册

需求分析

  • 登录和注册的表单需要正则验证
  • 注册时,手机号表单失焦时要在数据库中验证是否已经存在本手机号
  • 点击登录时要在数据库中验证账号信息,点击注册要将信息存入数据表中

实现思路

首先要在数据库中创建一个表并模拟出各个字段
在这里插入图片描述
在表结构中修改权限并增加属性,这样才能保证注册时插入数据能有权限并且有对应的字段
在这里插入图片描述
代码编写:
前端显示界面,多用户通过首页跳转传过来的值来判断哪个该显示哪个该隐藏

<template>
	<view class="login">
		<!-- 学生登录 -->
		<view class="stulogin" v-show="stulogin">
			<view>欢迎加入<text>星空学堂</text></view>
			<view><input type="text" v-model="accountinfo" placeholder="请输入账号/手机号" /></view>
			<view><input type="text" v-model="passwordinfo" placeholder="请输入密码" /></view>
			<view @click="studentlogin"><text >登录</text></view>
			<view class="exchangeinfo">还没有账号?<text @click="toregist">注册一个</text></view>
			<view class="loginerr" v-show="stuloginerr">账号或密码输入有误!请重新输入</view>
		</view>
		<!-- 学生注册 -->
		<view class="sturegist" v-show="sturegist">
			<view>欢迎加入<text>星空学堂</text></view>
			<view>
				<input @blur="checkphone" type="text" v-model="registphone" placeholder="请输入手机号" />
				<text class="reg" v-show="showregistphone">手机号格式不正确</text>
				<text class="reg" v-show="showregistedphone">该手机号已经被注册了</text>
			</view>
			<view>
				<input @blur="checkpass" type="text" v-model="registpass" placeholder="请输入密码" />
				<text class="reg" v-show="showregistpass">最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符</text>
			</view>
			<view>
				<input @blur="checkrepass" type="text" v-model="registrepass" placeholder="再次输入密码" />
				<text class="reg" v-show="showregistrepass">两次密码不一致</text>
			</view>
			<view @click="studentregist"><text>注册</text></view>
			<view class="exchangeinfo">已有账号?<text @click="tologin">登录</text></view>
		</view>
		
		<!-- 教师登录 -->
		<view class="tealogin" v-show="tealogin">
			<view>欢迎使用<text>星空学堂</text></view>
			<view><input type="text" value="" placeholder="请输入讲师账号" /></view>
			<view><input type="text" value="" placeholder="请输入密码" /></view>
			<view><text>登录</text></view>
			<view class="loginerr" v-show="false">账号或密码输入有误!请重新输入</view>
		</view>
		
		<!-- 管理员登录 -->
		<view class="adminlogin" v-show="adminlogin">
			<view>欢迎加入<text>星空学堂</text></view>
			<view><input type="text" value="" placeholder="请输入管理员账号" /></view>
			<view><input type="text" value="" placeholder="请输入密码" /></view>
			<view><text>登录</text></view>
			<view class="loginerr" v-show="false">账号或密码输入有误!请重新输入</view>
		</view>
	</view>
</template>

data部分:

data() {
return {
	//v-on控制登录提示报错信息
	stuloginerr:false,
	//注册表单的双向的值
	accountinfo:'',
	passwordinfo:'',
	//v-on控制板块的显示
	stulogin:false,
	sturegist:false,
	tealogin:false,
	adminlogin:false,
	//v-on控制正则显示的布尔值
	showregistedphone:false,
	showregistphone:false,
	showregistpass:false,
	showregistrepass:false,
	//表单双向绑定的值
	registphone:'',
	registpass:'',
	registrepass:'',
	// 注册校验信息
	registinfophone:false,
	registinfopass:false,
	registinforepass:false,
};
},

生命周期控制显示的板块

onLoad({id}) {
	// console.log(id)
	//根据跳转传过来的值更改页面主题色
	if(id==0){
		uni.setNavigationBarColor({
			backgroundColor:'#00c499',
			frontColor: '#ffffff',
		})
		uni.setNavigationBarTitle({
		    title: '讲师登录'
		});
		//控制板块间的显示隐藏
		this.stulogin=false,
		this.sturegist=false,
		this.tealogin=true,
		this.adminlogin=false
	}
	if(id==1){
		uni.setNavigationBarColor({
			backgroundColor:'#3f95ff',
			frontColor: '#ffffff',
		})
		uni.setNavigationBarTitle({
		    title: '学员登录'
		});
		this.stulogin=true,
		this.sturegist=false,
		this.tealogin=false,
		this.adminlogin=false
	}
	if(id==2){
		uni.setNavigationBarColor({
			backgroundColor:'#ff557f',
			frontColor: '#ffffff',
		})
		uni.setNavigationBarTitle({
		    title: '管理员登录'
		});
		this.stulogin=false,
		this.sturegist=false,
		this.tealogin=false,
		this.adminlogin=true
	}	
}

切换到注册/登录时,控制navigationbar的样式和内容

//显示登录部分
tologin(){
		this.stulogin=true
		this.sturegist=false
		uni.setNavigationBarTitle({
		    title: '学员登录'
		});
	},
//显示注册部分
toregist(){
	this.stulogin=false
	this.sturegist=true
	uni.setNavigationBarTitle({
	    title: '学员注册'
	});
},

正则验证部分代码,验证手机号时用到了async ...await...,这个意思是async标记函数之后,函数体里面遇到await之后,要让await后面的代码以同步方式执行。具体的用法可自行查阅资料

//正则验证
async checkphone(){
	var pattern=/^[1]([3-9])[0-9]{9}$/;
	var res=pattern.test(this.registphone)
	if(res){
		this.showregistphone=false
		//输入的手机号符合正则之后需要异步查询数据库中该手机号是否已经存在
		const db = uniCloud.database()
		await db.collection('starStudent').where(`phone==${this.registphone}`).get()
		.then(res=>{
			if(res.result.data[0]){
				//如果手机号存在显示提示信息
				this.showregistedphone=true
				console.log(111)
				//修改校验标志的布尔值
				this.registinfophone=false;
			}else{
				this.showregistedphone=false
				//验证成功就修改校验标志的布尔值
				this.registinfophone=true;
			}
		}).catch(err=>{
			console.log(err)
		})
		
	}else{
		this.showregistphone=true
		
		//修改校验标志的布尔值
		this.registinfophone=false;
	}
},
checkpass(){
	var pattern=/^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/;
	var res=pattern.test(this.registpass);
	if(res){
		this.showregistpass=false
		
		//验证成功就修改校验标志的布尔值
		this.registinfopass=true;
	}else{
		this.showregistpass=true
		
		//修改校验标志的布尔值
		this.registinfopass=false;
	}
},
checkrepass(){
	var pattern=/^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/;
	var res=pattern.test(this.registpass);
	
	if(res && this.registpass==this.registrepass){
		this.showregistrepass=false
		
		//验证成功就修改校验标志的布尔值
		this.registinforepass=true;
	}else{
		this.showregistrepass=true
		
		//修改校验标志的布尔值
		this.registinforepass=false;
	}
},
},

学员登录和注册部分代码逻辑,讲师和管理员部分原理和此处代码逻辑类似

//学员注册
studentregist(){
	//所有表单都验证通过的时候才可以注册
	if(this.registinfophone && this.registinfopass && this.registinforepass){
		this.registphone,this.registpass
		const db =uniCloud.database();
		db.collection('starStudent').add({
			"nickName": "",
			"trueName": "",
			"gender": "",
			"birth": "",
			"email": "",
			"UID": 10000,
			"password": this.registpass,
			"occupation": "",
			"address": "",
			"profile": "",
			"phone": this.registphone
		})
	}
},

//学员登录
async studentlogin(){
	console.log(this.accountinfo,this.passwordinfo)
	
	// 如果表单的输入信息为空,则显示提示信息
	if(!this.accountinfo || !this.passwordinfo){
		
		//控制提示信息的显示
		this.stuloginerr=true
	}else{
		// 只有在表单不为空的时候才进行数据库查询信息
		
		// 查询数据库是否有该账户
		const db = uniCloud.database()
		
		var flag=true;
		 if(this.accountinfo.length==11){
			//如果输入input的内容长度有11位,那么说明输入的是手机号
		await db.collection('starStudent').where(`phone==${this.accountinfo}`).get()
			.then(res=>{
				console.log('mima:'+res.result.data)
				if(res.result.data[0]){
					this.passwordinfo==res.result.data[0].password?flag=true:flag=false
				}else{
					flag=false
				}
			}).catch(err=>{
				console.log(err)
			})
			
			if(flag){
				//跳转到对应用户界面首页
				
				//控制提示信息的隐藏
				this.stuloginerr=false
			}else{
				//控制提示信息的显示
				this.stuloginerr=true
			}
			console.log('flag:'+flag)
		}else{
			await db.collection('starStudent').where(`UID==${this.accountinfo}`).get()
			.then(res=>{
				if(res.result.data[0]){
					this.passwordinfo==res.result.data[0].password?flag=true:flag=false
				}else{
					flag=false
				}
			}).catch(err=>{
				console.log(err)
			})
			
			if(flag){
				//跳转到对应用户界面首页
				
				//控制提示信息的隐藏
				this.stuloginerr=false
			}else{
				//控制提示信息的显示
				this.stuloginerr=true
			}
			console.log('flag:'+flag)
		}
	}
},

以上该部分功能全部实现,接下来是测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注册成功!
在这里插入图片描述

功能扩展(记录登录状态)

如果在登录之后需要把当前登录的用户记录下来,只需要在vuex中增加一个登录状态表即可,当然也可以使用缓存来实现本功能。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
测试:
登录成功之后可以拿到当前登录用户的id,这个功能实现的意义在于:只有登录的用户才可以报名,上课等功能,登陆之后,拿到id就可以拿到用户的基本信息,用于界面的展示和用户资料修改等。
在这里插入图片描述

4.实现用户资料修改

需求分析

修改资料只需要借助update就可以实现,但是因为这个界面我用到了组件写的单选框,那么这个组件就不能使用v-model。而且修改头像的话需要文件上传

实现思路

在这里插入图片描述
因为每次登录之后会把用户id存入vuex,那么在进入资料修改页的时候要把资料提前加载出来

loginedID:this.$store.state.loginstate[0],
onLoad() {
	console.log(this.loginedID)
	const db=uniCloud.database();
	db.collection('starStudent').where(`_id=='${this.loginedID}'`).get()
	.then(res=>{
		console.log(res.result.data[0].nickName)
		this.imgpath=res.result.data[0].profile
		this.nickName=res.result.data[0].nickName
		this.trueName=res.result.data[0].trueName
		this.gender=res.result.data[0].gender
		this.birth=res.result.data[0].birth
		this.phone=res.result.data[0].phone
		this.email=res.result.data[0].email
		this.occupation=res.result.data[0].occupation
		this.address=res.result.data[0].address
		
		//调用函数,在页面刷新时将性别以数据库中的值显示到界面上
		this.changeGender(this.gender)
	}).catch(err=>{
		console.error(err)
	})
}
data() {
	return {
		imgpath:"",
		
		boychecked:false,
		girlchecked:false,
		secretchecked:false,
		
		loginedID:this.$store.state.loginstate[0],
		
		candidates:['学生','医生','厨师','电工','其他'],
		nickName:'',
		trueName:'',
		gender:'',
		birth:'',
		phone:'',
		email:'',
		occupation:'',
		address:'',
	}
}
<template>
<view class="myInfo">
	<view class="my_basic">
		<view @click="pickImg">
			<image :src="imgpath" mode="widthFix"></image>
		</view>
	
	</view>
	
	<view class="my_content">
		<view class="infone">
			<view class="desc">昵称</view>
			<view>
				<input type="text" placeholder="请输入您的昵称" v-model="nickName" />
			</view>
		</view>
		<view class="infone">
			<view class="desc">姓名</view>
			<view>
				<input type="text" placeholder="请输入您的真实姓名" v-model="trueName" />
			</view>
		</view>
		
		<view class="infone">
			<view class="desc">性别</view>
			<view>
				<radio-group  class="radio_gender" >
					<label>
						<radio color="#3f95ff" value="0" :checked="boychecked" @click="changeGender(0)"/><text></text>
					</label>
					<label>
						<radio color="#3f95ff" value="1" :checked="girlchecked"  @click="changeGender(1)"/><text></text>
					</label>
					<label>
						<radio color="#3f95ff" value="2" :checked="secretchecked" @click="changeGender(2)"/><text>保密</text>
					</label>
				</radio-group>
			</view>
		</view>
		<view class="infone">
			<view class="desc">生日</view>
			<view>
				<uni-datetime-picker
					:clear-icon="false"
				    type="date"
				    :value="birth"
					v-model="birth"
					:border="false"
				/>
			</view>
		</view>
		<view class="infone">
			<view class="desc">手机</view>
			<view>
				<input type="number" disabled placeholder="请输入您的手机号" v-model="phone"/>
			</view>
		</view>
		<view class="infone">
			<view class="desc">邮箱</view>
			<view>
				<input type="text" placeholder="请输入您的邮箱" v-model="email"/>
			</view>
		</view>
		
		<view class="infone">
			<view class="desc">职业</view>
			<view>
				<uni-combox :candidates="candidates" emptyTips="请选择正确的职业" placeholder="请选择您的职业" v-model="occupation"></uni-combox>
			</view>
		</view>
		
		<view class="infone">
			<view class="desc">现居地</view>
			<view>
				<input type="text" placeholder="请输入您的现居地" v-model="address" />
			</view>
		</view>
	</view>
	
	<view class="my_confirm">
		<view @click="saveMyInfo">
			<text>保存</text>
		</view>

	</view>
	<view>
		(手机号不可更改)
	</view>
<view>

	</view>
</view>
</template>

性别那块用到了组件,用不了v-model,所以需要手动控制。这里简单的解释一下这种组件的原理:修改原生的input radio的样式是非常麻烦的,所以在封装组件的时候,要把radio样式写的好看一点,那么就是直接将radio替换成了图片。

changeGender(index){
	this.gender=index
	if(index==0){
		this.boychecked=true
		this.girlchecked=false
		this.secretchecked=false
	}
	if(index==1){
		this.boychecked=false
		this.girlchecked=true
		this.secretchecked=false
	}
	if(index==2){
		this.boychecked=false
		this.girlchecked=false
		this.secretchecked=true
	}
},

修改头像

//修改头像
pickImg(){
	let _that=this
	uni.chooseImage({
		success: (res) => {
			console.log(res.tempFiles[0].name)
			//  this.imgpath=res.tempFilePaths[0]
			 
			 uniCloud.uploadFile({
				 cloudPath:'profile_'+res.tempFiles[0].name,
				 filePath:res.tempFilePaths[0]
			 }).then(datares=>{
				 // console.log(datares)
				 //fileID是拿到运存的的下载地址
				 _that.imgpath=datares.fileID
			 })
		}
	})
},

点击保存

saveMyInfo(){
	//将信息存入数据库
	const db =uniCloud.database();
	db.collection('starStudent').doc(`${this.loginedID}`).update({
		"trueName":this.trueName,
		"gender":this.gender,
		"birth":this.birth,
		"email":this.email,
		"occupation":this.occupation,
		"address":this.address
	})
	console.log('修改成功')
}

至此,用户资料修改功能就完成了

5.实现报名功能(2021.12.10)

效果演示
在这里插入图片描述
在这里插入图片描述

需求分析

报名系统最重要的就是报名功能,能够将用户填写的报名信息存入数据库中

  • 用户填写报名信息,能够将这些信息存入数据库
  • 信息填写完成后用户检查信息是否有误,可再次更改
  • 付款时可以选择优惠券付款

实现思路

这一块的前端主要代码,里面用到了uniapp提供的一个遮罩层的组件,组件有一点的bug,稍作修改

<!-- 报名信息填写 -->
<view>
<uni-popup ref="popup" type="center" background-color="#fff">
	<template>
<!-- 填写报名信息 -->
<view class="signupinfo" v-show="showsignupinfo">	
<form @submit="formSubmit" >
	<view class="uni-form-item uni-column">
		<view>姓名:</view>
		<input type="text" placeholder="请输入姓名" v-model="stuName" />
	</view>
	<view class="uni-form-item uni-column">
		<view>生日:</view>
		<view class="birth">
			<uni-datetime-picker
				:clear-icon="false"
				type="date"
				:value="stuBirth"
				v-model="stuBirth"	
			/>
		</view>
	</view>
	
	<view class="uni-form-item uni-column">
		<view>性别:</view>
		<radio-group name="gender" class="radio_gender" >
			<label>
				<radio color="#3f95ff" value="1"  @click="changeGender(1)"/><text></text>
			</label>
			<label>
				<radio color="#3f95ff" value="2"  @click="changeGender(2)"/><text></text>
			</label>
			<label>
				<radio color="#3f95ff" value="3"  @click="changeGender(3)"/><text>保密</text>
			</label>
		</radio-group>
	</view>
	<view class="uni-form-item uni-column">
		<view>手机:</view>
		<input type="number" placeholder="请输入手机号" v-model="stuPhone"/>
	</view>
	<view class="uni-btn-v">
		<button form-type="submit" >提交</button>
	</view>
</form>
</view>
					
	
<!-- 报名信息确认 -->
<view class="singupinfoconfirm" v-show="showsingupinfoconfirm">
	<view class="infohead"><text>请确认您的报名信息是否正确?</text></view>
	<view class="info">
		<view><text>姓名:</text><text>{{signupList.studentName}}</text></view>
		<view><text>生日:</text><text>{{signupList.studnetBirth}}</text></view>
		<view><text>性别:</text><text>{{signupList.studentGender==1?'男':(signupList.studentGender==2?'女':'保密')}}</text></view>
		<view><text>电话:</text><text>{{signupList.studentPhone}}</text></view>
	</view>
	<view class="confirm">
		<view @click="confirminfo">
			<text>确认</text>
		</view>
		<view @click="updateinfo">
			<text>我要修改</text>
		</view>
		
	</view>
</view>

	<!-- 付款报名 -->
	<view class="signuppayment" v-show="showsignuppayment"> 
		<view>
			
			<text>总共需要支付<text class="money">{{data.price-selectedcoupon |filterPrice}}</text></text>
		</view>
		<view v-if="couponinfo.length">
			<view style="margin: 20rpx 0;">
				<text >请选择优惠券</text>
			</view>
		<radio-group name="coupon" class="coupon" >
			
				<label v-for="item,index in couponinfo" :key="index">
					<text>{{item}}元优惠</text> <radio color="#3f95ff" @click="selectcoupon(index)"/>
				</label>
			
		 </radio-group>
			
		</view>
		<view @click="paysuccess" class="pay">确认</view>
		
	</view>

	</template>
</uni-popup>
</view>

data数据域

data() {
       return {
		//控制报名板块的显示隐藏
		showsignuppayment:false,
		showsingupinfoconfirm:false,
		showsignupinfo:true,
		
		//获取选中的优惠券的优惠价格的下标
		selectedcouponindex:'',
		//获取选中的优惠券的优惠价格
		selectedcoupon:'',
		//获取到当前登录用户的优惠券信息
		couponinfo:[],
		//当前登录的用户id
		stuId:'',
		value:0,
		vuexnum:this.$store.state.detailid,
		// 当前展示的商品id
		page_id:'',
        current: 0,
        mode: 'nav',
		stuName:'',
		stuBirth:'',
		stuGender:'',
		stuPhone:'',
		//获取到用户填写的报名信息
		signupList:''     
       }
   },

生命周期中拿到当前登录的学生id和当前课程的id,因为报名之后要将这两张表关联起来

onLoad({id}){
	//拿到传过来的id值
	this.page_id=id
	this.stuId=this.$store.state.loginstate[0]
	//读取当前用户的优惠券信息
	const db=uniCloud.database()
	db.collection('starStudent').where(`_id=="${this.stuId}"`).get()
	.then(res=>{
		this.couponinfo=res.result.data[0].coupon
		
	}).catch(err=>{
		console.log(err)
	})
},

在这里插入图片描述
第一个信息填写页面填写完成之后要让用户再次确认自己填写的信息,
注意这里有一个bug:性别radio单选表单的value值要记为1,2,3.不要从0开始计数。因为在写下面这块代码的时候,如果选择了第0个,也就是选择了性别男,就会默认当成是false
在这里插入图片描述

formSubmit() {
	var signupList={
		courseID:this.page_id,
		studentID:this.stuId,
		studentName:this.stuName,
		studnetBirth:this.stuBirth,
		studentGender:this.stuGender,
		studentPhone:this.stuPhone
	}
	this.signupList=signupList
	
	// 只有所有信息都填了之后才能提交
	if(this.stuName && this.stuBirth && this.stuGender && this.stuPhone){
		//控制板块显示
		this.showsingupinfoconfirm=true
		this.showsignupinfo=false
	}	
},

在这里插入图片描述
第二个页面比较简单,只是获取数据和控制界面显示,
这里有一个小细节,性别我存在数据库中是以1,2,3的形式存放的,但是在界面上显示的话,我们要显示为‘男’,‘女’,‘保密’才对。要实现这个功能很容易我们就想到用三元运算来写,但是这里有三个条件,所以我们需要用三元运算的嵌套来写
在这里插入图片描述

//确认信息
confirminfo(){
	this.showsingupinfoconfirm=false
	this.showsignuppayment=true
},
//修改报名信息
updateinfo(){
	this.showsingupinfoconfirm=false
	this.showsignupinfo=true
},

在这里插入图片描述
第三个界面要复杂一点:要实现优惠券的价格加减,还要在支付之后将信息存入数据库中

selectcoupon(index){
		//将选中的优惠券写到data数据域
		this.selectedcoupon=this.couponinfo[index]
		//将选中的优惠券的下标写到data数据域
		this.selectedcouponindex=index
	},

这里又有一个小bug:就算我没有选择优惠券,也会默认将第一张选中并且扣除成功
原因是在data里面我将selectedcouponindex设置为空字符串,在执行 this.couponinfo.splice(this.selectedcouponindex,1)这段代码的时候将空字符串当成false也就是当做第0个位置来执行了,所以代码做了一点bug修复操作

paysuccess(){
//显示toast提示
	uni.showToast({
	    title: '支付成功!',
	    duration: 2000
	});
	if(typeof this.selectedcouponindex !='string'){
		//要将数据库中选中的哪条优惠券数据删除
		this.couponinfo.splice(this.selectedcouponindex,1)
		//读取当前用户的优惠券信息
		const db=uniCloud.database()
		db.collection('starStudent').where(`_id=="${this.stuId}"`)
		.update({
			coupon:this.couponinfo
		})
	}
	//将报名信息存入数据库
	const db = uniCloud.database();
	db.collection('starApplicationForm').add(this.signupList)
	
	//关闭遮罩层显示
	this.$refs.popup.close()
	
	//支付成功后跳转页面到我的课程
	// 2秒后跳转
	setTimeout(function(){
		uni.reLaunch({
			url:'../../study/study'
		})
	},2000)
},

最后提醒一点报名表要修改表结构,不然插入不了数据
在这里插入图片描述

扩展功能

后面如果有多余的时间可以将扩展功能加上

  • 如果有多张相同价格优惠券存在,在显示的时候应该将其折叠起来,每用一张只减少其数量
  • 在下单支付成功之后应该再多添加几个字段,比如当前下单的时间、地点等

6.实现随机出现优惠券(2022.3.25)

在这里插入图片描述

需求分析

在用户登录之后,设计一个算法,随机出现图中框起来的优惠券模块,限时5分钟,优惠券的价格随机(10以内),领取之后将本张优惠券存储在本用户表里,优惠券可以用于购买课程的时候减少价格。

实现思路

点击登录后将当前时间之后的5分钟的时间戳存入缓存,再把随机出现的金额存入缓存,用于备选

//存入时间,
savetime(){
	//计算五分钟的倒计时
	
	 //1. js获取当前时间
	 var date=new Date();
	 //2. 获取当前分钟
	 var min=date.getMinutes();
	 //3. 设置当前时间+5分钟:把当前分钟数+5后的值重新设置为date对象的分钟数
	 date.setMinutes(min+5);
	 //将得到的时间存入缓存
	 window.sessionStorage.setItem('newdate',date)
	
	//随机出现的现金存入缓存
	var moneynum=Math.ceil(Math.random()*10)
	 window.sessionStorage.setItem('moneynum',moneynum)
},

vue界面代码

<view class="getcredits" v-if="coupnflag">
<view class="header">
	限时领取<text>{{mintime<10?'0'+mintime:mintime}}分{{secondtime<10?'0'+secondtime:secondtime}}秒</text>
</view>
<view class="coupn">
	<div class="cone">
	<div class="d2">商品券</div>
	<div class="d1">
	  <div>
		<span>{{money}}</span>
		<span></span>
	  </div>
	  <div>
		<p>无门槛</p>
		<p>购买课程时使用</p>
	  </div>
	</div>
	
	</div>
</view>
<view class="pull">
	<text @click="pullcoupn">立即领取</text>
</view>
</view>

data

data (){
	return{
		//随机出现的优惠券的数据
		exitcoupon:'',//本用户是否存在优惠券
		money: window.sessionStorage.getItem('moneynum'),//优惠券的钱
		mintime:'',//倒计时分钟
		secondtime:'',//倒计时秒
		rantime:'',//每日随机出现的时间,
		coupnflag:false
	}
}

生命周期调用

onLoad() {
	this.getcoupn()
	this.getusercoupn()
	},

实现功能的函数

async getusercoupn(){//将作业插入数据库的函数
	const db=uniCloud.database()
		const res = await db.collection('starStudent').where(`_id=="${this.loginID}"`)
		.get().then(val=>{
			// console.log(val.result.data[0].coupon)
			this.exitcoupon=val.result.data[0].coupon
		})
	},
async pullcoupn(){//点击领取优惠券
	const db=uniCloud.database()
	if(this.exitcoupon){//如果本用户有优惠券就直接在头部插入本张优惠券
		this.exitcoupon.unshift(Number(this.money))//需要将钱转为数字类型
		console.log(this.exitcoupon)
		//将修改的数据更新到数据库中
		const res = await db.collection('starStudent').where(`_id=="${this.loginID}"`)
		.update({
			coupon:this.exitcoupon
		})
		//更新成功之后提示并删除该模块的显示
		uni.showToast({
		    title: '领取成功!',
		    duration: 2000
		});
		this.coupnflag=false
	}else{//如果数组里面没有一张优惠券则定义空数组并push一个值
		this.exitcoupon=[]
		this.exitcoupon.unshift(Number(this.money))//需要将钱转为数字类型
		console.log(this.exitcoupon)
		//将修改的数据更新到数据库中
		const res = await db.collection('starStudent').where(`_id=="${this.loginID}"`)
		.update({
			coupon:this.exitcoupon
		})
		//更新成功之后提示并删除该模块的显示
		uni.showToast({
			title: '领取成功!',
			duration: 2000
		});
		this.coupnflag=false
	}
},
getcoupn(){//随机出现优惠券的函数

//随机出现优惠券的标志
var randomflag
var num=Math.ceil(Math.random()*10)
if(num>5){
	randomflag=true
}else{
	randomflag=false
}
// console.log(randomflag)
 //randomflag标志为真的时候就控制出现这个板块
 if(randomflag){
	 this.coupnflag=true//控制显示优惠券板块
	 var timer= setInterval(()=>{
	 	var nowtime = new Date()  //获取当前时间
	 	var endTime = new Date((window.sessionStorage.getItem('newdate')).toLocaleString());//结束时间
	 	var lefttime = endTime.getTime() - nowtime.getTime(),  //距离结束时间的毫秒数
	 	
	 	leftm = Math.floor(lefttime/(1000*60)%60),  //计算分钟数
	 	lefts = Math.floor(lefttime/1000%60);  //计算秒数
	 	this.mintime=leftm
	 	this.secondtime=lefts
	 	if(leftm==0 && lefts==0 ){//如果倒计时结束需要清空定时器并移除优惠券
	 		clearInterval(timer)
			this.coupnflag=false//时间结束也要将本模块隐藏
			
	 	}
	 },1000)
 }else{//否则就不出现
	 this.coupnflag=false
 }

},

以上就实现了本功能呢!
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值