uni-app商城(十)个人中心

1.个人中心页面my.vue

<template>
	<view class="my-container">
		<my-login v-if="!token"></my-login>
		<my-userinfo v-else></my-userinfo>
	</view>
</template>

<script>
	import badgeMix from '@/mixins/tabbar-badge.js';
	import { mapState } from 'vuex';
	
	export default {
		mixins:[badgeMix],
		data() {
			return {
				
			};
		},
		computed:{
			...mapState('m_user',['token'])
		}
	}
</script>

<style lang="scss">
page,.my-container{
	height: 100%;
}
</style>

2. store-cart.js

export default {
	//为当前模块开启命名空间
	namespaced: true,
	state: () => ({
		// 购物车存储的数据,每个商品的数据对象
		cart: JSON.parse(uni.getStorageSync('cart') || '[]')
	}),
	//模块mutations方法
	mutations: {
		addToCart(state, goods) {
			const findRes = state.cart.find(x => x.id === goods.id);

			if (!findRes) {
				//如果购物车没有这个商品,直接push
				state.cart.push(goods);
			} else {
				//否则更新数量
				findRes.count++;
			}
			this.commit('m_cart/saveToStorage')
		},
		//游客保存购物车到本地
		saveToStorage(state) {
			uni.setStorageSync('cart', JSON.stringify(state.cart))
		},
		//更新购物车中商品的选中状态
		updateGoodsState(state, goods) {
			const findRes = state.cart.find(x => x.id === goods.id)
			if (findRes) {
				findRes.state = goods.state;
				this.commit('m_cart/saveToStorage');
			}
		},
		//更新商品的数量
		updateGoodsCount(state, goods) {
			const findRes = state.cart.find(x => x.id === goods.id)
			if (findRes) {
				findRes.count = goods.count;
				this.commit('m_cart/saveToStorage');
			}
		},
		//根据id删除商品
		removeGoodsById(state, id) {
			state.cart = state.cart.filter(x => x.id !== id);
			this.commit('m_cart/saveToStorage');
		},
		//更新购物车中所有商品的勾选状态
		updateAllGoodsState(state, newState) {
			state.cart.forEach(x => x.state = newState)
			this.commit('m_cart/saveToStorage')
		}
	},
	//模块getters属性
	getters: {
		//购物车中所有商品的数量
		total(state) {
			// let c = 0;
			// state.cart.forEach(goods => c += goods.count)
			// return c
			return state.cart.reduce((total, item) => total += item.count, 0)
		},
		//购物车中已勾选的商品数量
		checkedCount(state) {
			// 先使用 filter 方法,从购物车中过滤器已勾选的商品
			// 再使用 reduce 方法,将已勾选的商品总数量进行累加
			// reduce() 的返回值就是已勾选的商品的总数量
			return state.cart.filter(x => x.state).reduce((total, item) =>
				total += item.count, 0)
		},
		// 已勾选商品的总价格
		checkedGoodsAmount(state) {
			// 先使用 filter 方法,从购物车中过滤器已勾选的商品
			// 再使用 reduce 方法,将已勾选的商品数量 * 单价之后,进行累加
			// reduce() 的返回值就是已勾选的商品的总价
			// 最后调用 toFixed(2) 方法,保留两位小数
			return state.cart.filter(x => x.state).reduce((total, item) => total += item.count * item.price, 0).toFixed(
				2)
		}
	}
}

3.store-user.js

export default {
	// 开启命名空间
	namespaced: true,
	// 数据
	state: () => ({
		address: JSON.parse(uni.getStorageSync('address') || '{}'),
		token: uni.getStorageSync('token') || '',
		//用户信息对象
		userinfo: JSON.parse(uni.getStorageSync('userinfo') || '{}'),
		//重定向的object对象
		redirectInfo: null
	}),
	// 方法
	mutations: {
		//更新收货地址
		updateAddress(state, address) {
			state.address = address
			this.commit('m_user/saveAddressToStorage')
		},
		saveAddressToStorage(state) {
			uni.setStorageSync('address', JSON.stringify(state.address))
		},
		updateUserInfo(state, userinfo) {
			state.userinfo = userinfo
			this.commit('m_user/saveUserInfoToStorage')
		},
		saveUserInfoToStorage(state) {
			uni.setStorageSync('userinfo', JSON.stringify(state.userinfo))
		},
		updateToken(state, token) {
			state.token = token
			this.commit('m_user/saveTokenToStorage')
		},
		saveTokenToStorage(state) {
			uni.setStorageSync('token', JSON.stringify(state.token))
		},
		updateRedirectInfo(state,info){
			state.redirectInfo=info
			console.log(state.redirectInfo)
		}
	},
	getters: {
		addstr(state) {
			if (!state.address.provinceName) return '';
			return state.address.provinceName + state.address.cityName + state.address.countyName + state.address
				.detailInfo
		}
	}
}

4.结算组件my-settle.vue

<template>
	<view class="my-settle-container">
		<!-- 全选 -->
		<label class="radio" @click="changeAllState">
			<radio :checked="isFullCheck" /><text>全选</text>
		</label>
		<!-- 合计 -->
		<view class="amount-box">
			合计:<text class="amount">{{checkedGoodsAmount}}</text>
		</view>
		<!-- 结算 -->
		<view class="btn-settle" @click="settlement">结算({{checkedCount}})</view>
	</view>
</template>

<script>
	import {
		mapGetters,
		mapMutations,
		mapState
	} from 'vuex';
	export default {
		name: "my-settle",
		data() {
			return {
				//倒计时的秒数
				seconds: 3,
				//定时器id
				timer: null
			};
		},
		computed: {
			...mapGetters('m_cart', ['checkedCount', 'total', 'checkedGoodsAmount']),
			...mapGetters('m_user', ['addstr']),
			...mapState('m_user', ['token']),
			...mapState('m_cart', ['cart']),
			isFullCheck() {
				return this.total === this.checkedCount
			}
		},
		methods: {
			//使用 mapMutations 辅助函数,把 m_cart 模块提供的 updateAllGoodsState 方法映射到当前组件中使用
			...mapMutations('m_cart', ['updateAllGoodsState']),
			...mapMutations('m_user', ['updateRedirectInfo']),
			changeAllState() {
				// 修改购物车中所有商品的选中状态
				// !this.isFullcheck 表示:当前全选按钮的状态取反之后,就是最新的勾选状态
				this.updateAllGoodsState(!this.isFullCheck)
			},
			//点击结算按钮
			settlement() {
				if (!this.checkedCount) return uni.$showMsg('请选择要结算的商品');

				if (!this.addstr) return uni.$showMsg('请选择收货地址');

				//跳转登录
				if (!this.token) return this.delayNavigate();
				//创建订单
				this.payOrder();
			},
			payOrder() {
				// 1. 创建订单
				// 1.1 组织订单的信息对象
				const orderInfo = {
					// order_price:this.checkedGoodsAmount,
					order_price: 0.01,
					consignee_addr: this.addstr,
					goods: this.cart.filter(x => x.state).map(x => ({
						id: x.id,
						number: x.count,
						price: x.price
					}))
				}
				// 1.2 发起请求创建订单
				uni.request({
						url: uni.$baseUrl + '/api/User/PayOrder',
						method: 'POST',
						data: {
							orderInfo
						}
					})
					.then((res) => {
						// console.log(res.data.data);
						if (res.data.code != 200) return uni.$showMsg('创建订单失败!');
						// 1.3 得到服务器响应的订单编号
						const orderNumber = res.data.data.order_number;
						//2.订单预支付
						//2.1发起请求获取订单支付信息
						uni.request({
							url: uni.$baseUrl + '/api/User/PayOrder',
							method: 'POST',
							data: {
								orderInfo
							}
						}).then((res) => {
							//2.2预付订单生成失败
							if (res.data.code != 200) return uni.$showMsg('预付订单生成失败!');
							//2.3得到订单支付相关必要参数
							const payInfo = res.data.data.pay

							//3.发起微信支付
							//3.1调用uni.requestPayment发起微信支付
							uni.requestPayment(payInfo).then((res) => {
								//3.2未完成支付
								if(res.err) return uni.$showMsg('订单未支付!');
								//3.3完成支付,进一步查询支付结果
								uni.request({
									url: uni.$baseUrl + '/api/User/CHKOrder',
									data: {
										'payInfo': payInfo
									}
								}).then((res) => {
									if (res.data.code != 200) return uni.$showMsg('订单未支付!');
									uni.showToast({
										icon: 'success',
										title: '订单支付完成!'
									})
								})
							})

						})
					});
			},
			//延时导航到my页面
			delayNavigate() {
				this.seconds = 3;
				this.showTips(this.seconds);

				this.timer = setInterval(() => {
					this.seconds--;
					if (this.seconds <= 0) {
						clearInterval(this.timer);
						//登录之后返回购物车结算
						uni.switchTab({
							url: '/pages/my/my',
							success: () => {
								this.updateRedirectInfo({
									openType: 'switchTab',
									from: '/pages/cart/cart'
								})
							}
						})
						return;
					}
					this.showTips(this.seconds);
				}, 1000)
			},
			// 展示倒计时的提示消息
			showTips(n) {
				uni.showToast({
					icon: 'none',
					title: '请登录后再结算! ' + n + ' 秒之后自动跳转到登录页',
					mask: true,
					duration: 1500,
				})
			}
		}
	}
</script>

<style lang="scss">
	.my-settle-container {
		position: fixed;
		bottom: 0;
		left: 0;
		width: 100%;
		height: 50px;
		display: flex;
		justify-content: space-between;
		align-items: center;
		font-size: 14px;
		padding-left: 5px;

	}

	.radio {
		display: flex;
		align-items: center;
	}

	.amount-box {
		.amount {
			color: #c00000;
			font-weight: bold;
		}
	}

	.btn-settle {
		background-color: #c00000;
		height: 50px;
		color: white;
		line-height: 50px;
		padding: 0 5px;
		width: 100px;
		text-align: center;
	}
</style>

5.登录组件my-login.vue

<template>
	<view class="login-container">
		<uni-icons type="contact-filled" size="100" color="#AFAFAF"></uni-icons>
		<button type="primary" class="btn-login" @click="getUserInfo">一键登录</button>
		<text class="tips-text">登录后尽享更多权益</text>
	</view>
</template>

<script>
	import {
		mapMutations,
		mapState
	} from 'vuex';
	export default {
		name: "my-login",
		data() {
			return {

			};
		},
		computed: {
			...mapState('m_user', ['redirectInfo'])
		},
		methods: {
			...mapMutations('m_user', ['updateUserInfo', 'updateToken', 'updateRedirectInfo']),
			//用户授权之后,获取用户的基本信息
			getUserInfo() {
				let that = this;
				uni.getUserProfile({
					desc: '接口调试'
				}).then((res) => {
					// console.log(res);
					that.updateUserInfo(res.userInfo);
					that.getToken(res);
				});
			},
			getToken(info) {
				uni.login({
					provider: 'weixin', //使用微信登录
				}).then((res) => {
					const query = {
						code: res.code,
						encryptedData: info.encryptedData,
						iv: info.iv,
						rawData: info.rawData,
						signature: info.signature
					}
					console.log(query)

					uni.request({
							url: uni.$baseUrl + '/api/User/Login',
							method: 'POST',
							data: {
								query
							}
						})
						.then((res) => {
							// console.log(res.data.data);
							if (res.data.code != 200) return uni.$showMsg('登录失败!');
							uni.$showMsg('登录成功!');
							// 直接把 token 保存到/ vuex 中
							this.updateToken(res.data.data);
							this.navigateBack();
						});
				});
			},
			navigateBack() {
				if (this.redirectInfo && this.redirectInfo.openType === 'switchTab') {
					uni.switchTab({
						url: this.redirectInfo.from,
						complete: () => {
							this.updateRedirectInfo(null)
						}
					})
				}
			}
			
		}
	}
</script>

<style lang="scss">
	.login-container {
		height: 750rpx;
		background-color: #F8F8F8;
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		position: relative;
		overflow: hidden;

		&::after {
			content: ' ';
			display: block;
			width: 100%;
			height: 40px;
			background-color: white;
			position: absolute;
			bottom: 0;
			left: 0;
			border-radius: 100%;
			transform: translateY(50%);
		}

		.btn-login {
			width: 80%;
			border-radius: 100px;
			margin: 15px 0;
		}

		.tips-text {
			font-size: 12px;
			color: gray;
		}
	}
</style>

6.个人信息组件my.vue

<template>
	<view class="my-userinfo-container">
		<!-- 头像和昵称区域 -->
		<view class="top-box">
			<image :src="userinfo.avatarUrl" class="avatar"></image>
			<view class="nickname">{{userinfo.nickName}}</view>
		</view>
		
		<!-- 面板区域 -->
		<view class="panel-list">
			<!-- 面板1 -->
			<view class="panel">
				<view class="panel-body">
					<view class="panel-item">
						<text>8</text>
						<text>收藏的店铺</text>
					</view>
					<view class="panel-item">
						<text>8</text>
						<text>收藏的商品</text>
					</view>
					<view class="panel-item">
						<text>8</text>
						<text>关注的商品</text>
					</view>
					<view class="panel-item">
						<text>8</text>
						<text>足迹</text>
					</view>
				</view>
			</view>
			
			<!-- 面板2 -->
			<view class="panel">
				<view class="panel-title">
					我的订单
				</view>
				<view class="panel-body">
					<view class="panel-item">
						<image src="/static/my/待付款.png" class="icon"></image>
						<text>待付款</text>
					</view>
					<view class="panel-item">
						<image src="/static/my/待收货.png" class="icon"></image>
						<text>待收货</text>
					</view>
					<view class="panel-item">
						<image src="/static/my/换货.png" class="icon"></image>
						<text>退款/退货</text>
					</view>
					<view class="panel-item">
						<image src="/static/my/账单.png" class="icon"></image>
						<text>全部订单</text>
					</view>
				</view>
			</view>
			<!-- 面板3 -->
			<view class="panel">
				<view class="panel-list-item">
					<text>收货地址</text>
					<uni-icons type="arrowright" size="15"></uni-icons>
				</view>
				<view class="panel-list-item">
					<text>联系客服</text>
					<uni-icons type="arrowright" size="15"></uni-icons>
				</view>
				<view class="panel-list-item" @click="logout">
					<text>退出登录</text>
					<uni-icons type="arrowright" size="15"></uni-icons>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import {mapState,mapMutations} from 'vuex'
	export default {
		name: "my-userinfo",
		data() {
			return {

			};
		},
		computed:{
			...mapState('m_user',['userinfo'])
		},
		methods:{
			...mapMutations('m_user',['updateAddress','updateUserInfo','updateToken']),
			logout(){
				uni.showModal({
					title:'提示',
					content:'确认退出登录吗?'
				}).then((res)=>{
					if(res.confirm){
						this.updateAddress({});
						this.updateUserInfo({});
						this.updateToken('');
					}
				})
			}
		}
	}
</script>

<style lang="scss">
	.my-userinfo-container {
		height: 100%;
		background-color: #f4f4f4;

		.top-box {
			height: 400rpx;
			background-color: #55aaff;
			display: flex;
			justify-content: center;
			align-items: center;
			flex-direction: column;

			.avatar {
				width: 90px;
				height: 90px;
				border-radius: 45px;
				border: 2px solid #FFF;
				box-shadow: 0 1px 5px black;
			}

			.nickname {
				font-size: 16px;
				color: #ffffff;
				font-weight: bold;
				margin-top: 10px;
			}
		}
	}
	.panel-list{
		padding: 0 10px;
		position: relative;
		top:-10px;
		.panel{
			background-color: white;
			border-radius: 3px;
			margin-bottom: 8px;
			.panel-title{
				line-height: 45px;
				padding-left: 10px;
				font-size: 15px;
				border-bottom: 1px solid #f4f4f4;
			}
			.panel-body{
				display: flex;
				justify-content: space-around;
				.panel-item{
					display: flex;
					flex-direction: column;
					align-items: center;
					justify-content: space-around;
					padding: 10px 0;
					font-size: 13px;
					.icon{
						width: 35px;
						height: 35px;
					}
				}
			}
		}
	}
	.panel-list-item{
		display: flex;
		justify-content: space-between;
		align-items: center;
		font-size: 15px;padding: 0 10px;
		line-height: 45px;
	}
</style>

7.效果示例

uni-app商城(十)个人中心_第1张图片
uni-app商城(十)个人中心_第2张图片

你可能感兴趣的:(uni-app,uni-app,javascript,小程序,微信小程序)