- 建立 vux store文件夹 index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
import request,{PostHeader} from '@/pages/bbt_api/http.js'
Vue.use(Vuex)
// 本地存储中用户信息的 key
const USER_INFO = 'userInfo'
// 本地存储中确认订单信息的 key
const ORDER_INFO = 'orderInfo'
// 购物车信息的 key
const SHOPPING_INFO = 'shoppingCartInfo'
// 用户状态信息的 key
const USER_STATE_INFO = 'userstateinfo'
// 上级用户的id的 key
const PARENT_ID = 'parentid'
const store = new Vuex.Store({
state: {
// 用户信息
userInfo: uni.getStorageSync(USER_INFO) ? JSON.parse(uni.getStorageSync(USER_INFO)) : { id: 22},
// 确认订单信息
orderInfo:uni.getStorageSync(ORDER_INFO) ? JSON.parse(uni.getStorageSync(ORDER_INFO)) : {},
// 购物车订单信息
shoppingCartInfo:uni.getStorageSync(SHOPPING_INFO) ? JSON.parse(uni.getStorageSync(SHOPPING_INFO)) : {},
// 用户状态信息
userStateInfo:uni.getStorageSync(USER_STATE_INFO) ? JSON.parse(uni.getStorageSync(USER_STATE_INFO)) : {},
// 上级用户id
parentId: uni.getStorageSync(PARENT_ID)
},
mutations: {
// 更新用户信息
updateUserInfo(state,userInfo){
// 对数据做持久化处理
uni.setStorageSync(USER_INFO,JSON.stringify(userInfo));
// 更新 state 中的数据
state.userInfo = {...state.userInfo,...userInfo}
},
// 更新确认订单信息
updateOrderInfo(state,orderInfo){
// 对数据做持久化处理
uni.setStorageSync(ORDER_INFO,JSON.stringify(orderInfo));
// 更新 state 中的数据
state.orderInfo = {...state.orderInfo,...orderInfo}
},
// 更新购物车订单信息
updateShoppingCartInfo(state,shoppingCartInfo){
// 对数据做持久化处理
uni.setStorageSync(ORDER_INFO,JSON.stringify(shoppingCartInfo));
// 更新 state 中的数据
state.shoppingCartInfo = {...shoppingCartInfo}
},
// 更新用户状态信息
updateUserStateInfo(state,userStateInfo){
// 对数据做持久化处理
uni.setStorageSync(USER_STATE_INFO,JSON.stringify(userStateInfo));
// 更新 state 中的数据
state.userStateInfo = {...userStateInfo}
},
// 更新上级用户id
updateParentId(state,parentId){
// 如果没有上级用户的id
if(parentId==='undefined') return uni.removeStorageSync(PARENT_ID)
// 对数据做持久化处理
uni.setStorageSync(PARENT_ID,parentId);
// 更新 state 中的数据
state.parentId = parentId
},
// 清空用户信息
clearUserInfo(state){
state.userInfo = {}
state.userStateInfo = {}
// 清空本地存储中的用户信息
uni.clearStorageSync()
}
},
actions:{
// 绑定上级用户的方法
async bindSuperiorUser(context){
try{
// 如果不是通过上级用户分享的小程序码进入的,则终止函数执行
if(!context.state.parentId) return
// 准备请求参数
const requestPayload = {
userid:context.state.userInfo.id,
topid:context.state.parentId
}
// 发送请求
await request('/UserResourcesWX/updateBd',PostHeader,requestPayload)
// console.log(context)
}catch(e){
//TODO handle the exception
}
},
// 提交上级用户的分享记录
async submitRecords(context){
try{
// 如果没有绑定上级用户或者没有登录,则终止函数执行
if(!context.state.parentId || !context.state.userInfo.id) return
// 如果有绑定上级用户,则准备请求参数
const requestPayload = {
userid:context.state.userInfo.id,
topid:context.state.parentId
}
// 发送请求
await request('/UserResourcesWX/addBd',PostHeader,requestPayload)
}catch(e){
//TODO handle the exception
}
}
}
})
export default store
登录页面代码
<template>
<view class="Login_container" :style="'height:'+ screenHeight +'px !important;'">
<view class="logo_box">
<image src="../../static/login_banner.png" mode="" class="logo"></image>
</view>
<!-- <button class="phone_btn" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">获取手机号一键登录</button> -->
<!-- <view class="other-login-methods_box">
<view class="line"></view>
<view class="other-login-methods_btn">其他登录方式</view>
<view class="line"></view>
</view> -->
<button class="wx-login_box" @click="wxLogin">微信授权登录</button>
</view>
</template>
<script>
import {
mapState,
mapMutations,
mapActions
} from 'vuex'
export default {
computed: {
...mapState(['userInfo'])
},
data() {
return {
//用户openid
userOpenid: '',
// 当前用户签名
session_key: '',
// 当前设备的可使用高度
screenHeight: '',
// 开关阀
flag: true
}
},
onLoad() {
// 获取当前设备的可使用窗口高度
this.screenHeight = uni.getSystemInfoSync().windowHeight;
// 调用获取请求参数 code 的方法
this.getCodeData()
},
// 页面卸载时触发(点击返回按钮)
onUnload() {},
methods: {
...mapMutations(['updateUserInfo']),
...mapActions(['submitRecords']),
// 获取请求参数 code 的方法
getCodeData() {
// 调用微信提供的接口获取 code
uni.login({
success: async (res) => {
// 准备请求参数
const requestPayload = {
code: res.code
}
// 发送请求
const result = await this.$request('/userLong/findOpenId', this.$PostHeader,
requestPayload)
// 如果请求失败,则终止函数执行
if (result.status !== '200') return
// 将响应的数据保存到data中
this.userOpenid = result.data
this.session_key = result.session_key
// 调用 store 的方法将数据保存到 store 中,并在 store 中做持久化处理
this.updateUserInfo({
...this.userInfo,
session_key: result.session_key,
userOpenid: result.data
})
}
})
},
// 处理函数,当手机号登录按钮被点击时触发,获取用户手机号
async getPhoneNumber(e) {
try {
// 如果阀门关闭,则终止函数
if (!this.flag) return
// 进来后,关闭阀门,知道当前执行完毕后再开启
this.flag = false
// 如果用户不同意授权
if (e.detail.errMsg === "getPhoneNumber:fail user deny") {
// 提示用户
uni.showToast({
icon: "none",
title: '请允许获取手机号,否则功能不可用!',
})
// 开启阀门,并终止函数执行
return this.flag = true
}
// 如果用户同意授权,准备获取手机号的请求参数
const queryInfo = {
// 加密数据
encryptDataB64: e.detail.encryptedData,
// 签名
sessionKeyB64: this.session_key,
// 初始向量
ivB64: e.detail.iv
}
// 发送请求
const result = await this.$request('/WechatDecryptDataUtil/jmphone', this.$PostHeader, queryInfo)
// 如果请求失败,终止函数执行
if (result.status !== '200') return
// 如果请求成功,拿到当前用户的手机号
const phone = JSON.parse(result.data).phoneNumber
// 准备手机号登录的请求参数
const requestPayload = {
// 当前用户手机号
phone: phone,
// 当前用户的 openid
openid: this.userOpenid
}
// 发送请求
const res = await this.$request('/userLong/addUer2', this.$PostHeader, requestPayload)
// 如果请求失败,终止函数执行
if (res.status !== '200') return
// 如果请求成功,调用 store 的方法保存数据到 store 中,并做持久化处理
this.updateUserInfo({
id: result.data
})
// 返回之前的页面
uni.navigateBack()
// 开启阀门
this.flag = true
} catch (e) {
// 开启阀门
this.flag = true
//TODO handle the exception
}
},
// 微信授权登录的方法
wxLogin() {
try {
// 如果阀门关闭,则终止函数
if (!this.flag) return
// 进来后,关闭阀门,知道当前执行完毕后再开启
this.flag = false
// 获取用户基本信息
uni.getUserProfile({
// 不写不弹提示框
desc: '正在获取',
// 当用户同意授权的时候触发
success: async (res) => {
// 调用 store 的方法将数据保存到 store 中,并在 store 中做持久化处理
this.updateUserInfo({
...this.userInfo,
...res.userInfo
})
// 准备请求参数
const requestPayload = {
openid: this.userOpenid,
...res.userInfo,
topid: 0
}
// 发送请求
const result = await this.$request('/userLong/loginUers', this.$PostHeader,
requestPayload)
// 如果请求失败,则终止函数执行
if (result.status !== '200') return
// 调用 store 的方法保存数据到 store 中,并在 store 中做持久化处理
this.updateUserInfo({
...this.userInfo,
id: result.data
})
// 调用提交分享记录的方法
await this.submitRecords()
// 返回之前的页面
uni.navigateBack()
// 开启阀门
this.flag = true
},
// 当用户拒绝授权的时候触发
fail: () => {
// 开启阀门
this.flag = true
}
})
} catch (e) {
// 开启阀门
this.flag = true
//TODO handle the exception
}
},
}
}
</script>
<style scoped lang="scss">
.Login_container {
background-color: #fff;
overflow: auto;
// 登录图片盒子
.logo_box {
width: 750rpx;
height: 252rpx;
margin: 0 auto;
margin-top: 220rpx;
.logo {
width: 100%;
height: 100%;
}
}
// 获取手机号按钮
.phone_btn {
width: 680rpx;
height: 90rpx;
color: #0B8495;
font-size: 30rpx;
text-align: center;
margin: 0 auto;
margin-top: 300rpx;
border-radius: 45rpx;
border: 1px solid #0B8495;
line-height: 90rpx;
background-color: #fff !important;
}
// 其它登录方式
.other-login-methods_box {
display: flex;
justify-content: space-around;
margin-top: 130rpx;
.line {
width: 220rpx;
height: 2rpx;
background-color: #F5F5F5;
}
.other-login-methods_btn {
font-size: 20rpx;
color: #999999;
line-height: 0.2;
}
}
// 微信登录盒子
.wx-login_box {
width: 300rpx;
height: 90rpx;
background-color: #fff !important;
color: #09BB07;
font-size: 30rpx;
border-radius: 45rpx;
border: 1px solid #09BB07;
text-align: center;
line-height: 90rpx;
margin-top: 90rpx;
}
}
</style>
我的页面代码
<template>
<view class="my_container">
<view class="headBg_box">
<!-- 页面标题 -->
<view class="head_title">我的</view>
<!-- 已登录状态 -->
<view class="login-state_box" v-if="userInfo.id">
<view class="left_box">
<view class="avatar_box">
<!-- <image :src="userInfo.avatarUrl" mode="" class="avatar"></image> -->
<open-data type="userAvatarUrl" class="avatar"></open-data>
</view>
<view class="info_box">
<view class="name_box">
<!-- <view class="name">{{userInfo.nickName}}</view> -->
<open-data type="userNickName" class="name"></open-data>
<view class="icon_edit" v-if="userInfo.id">
<image :src="require('../../static/icon_edit.png')" mode="" class="photo"
@click="onServiceItemClick('user-info')"></image>
</view>
</view>
<view class="level_box" v-if="userStateInfo.vips===0">普通用户</view>
<view class="level_box" v-else-if="userStateInfo.vips===1">业务员</view>
<view class="level_box" v-else-if="userStateInfo.vips===2">经销商</view>
</view>
</view>
<!-- 成为经销商按钮 -->
<!-- <view class="right_box" v-if="userStateInfo.vips !== 2">
<button class="add_btn" plain :border="false"
@click="onServiceItemClick('add-distributor')">成为经销商</button>
</view> -->
<!-- 二维码按钮 -->
<view class="code_box" @click="onCodeClick" v-if="userStateInfo.vips===1 || userStateInfo.vips===2">
<image :src="require('../../static/icon_code.png')" mode="" class="photo"></image>
<view class="label_box">二维码</view>
</view>
</view>
<!-- 未登录状态 -->
<view class="logout-state_box" @click="onLoginClick" v-else>
<view class="avatar_box">
<image :src="require('../../static/default_avatar.png')" mode="" class="avatar"></image>
</view>
<view class="tip_box">未登录</view>
</view>
</view>
<!-- 账户盒子 -->
<view class="account_box">
<view class="balance_box" @click="onServiceItemClick('my-balance')">
<view class="number_box">{{userStateInfo.topupMoney}}</view>
<view class="label_box">
<image :src="require('../../static/icon_balance.png')" class="label_icon" mode=""></image>
<text class="label_desc">账户余额</text>
</view>
</view>
<!-- 分割线 -->
<view class="line_box">
<view class="line"></view>
</view>
<view class="balance_box" @click="onServiceItemClick('my-points')">
<view class="number_box">{{userStateInfo.earningsMoney}}</view>
<view class="label_box">
<image :src="require('../../static/icon_integral.png')" class="label_icon" mode=""></image>
<text class="label_desc">我的积分</text>
</view>
</view>
</view>
<!-- 我的服务盒子 -->
<view class="service_box">
<view class="head_box">
<view class="head-title_box">我的服务</view>
</view>
<view class="list_box">
<view class="list_item" @click="onServiceItemClick('my-collection')">
<image :src="require('../../static/service_01.png')" mode="" class="photo"></image>
<view class="label_box">我的收藏</view>
</view>
<view class="list_item" @click="onServiceItemClick('receiving-address')">
<image :src="require('../../static/service_02.png')" mode="" class="photo"></image>
<view class="label_box">收货地址</view>
</view>
<view class="list_item" @click="onServiceItemClick('my-comments')">
<image :src="require('../../static/service_03.png')" mode="" class="photo"></image>
<view class="label_box">我的评价</view>
</view>
<view class="list_item" @click="onServiceItemClick('my-info')">
<image :src="require('../../static/service_04.png')" mode="" class="photo"></image>
<view class="label_box">我的信息</view>
</view>
<view class="list_item" @click="onServiceItemClick('team-hotline')">
<image :src="require('../../static/service_05.png')" mode="" class="photo"></image>
<view class="label_box">团购热线</view>
</view>
<view class="list_item" @click="onServiceItemClick('resource-promotion')" v-if="userStateInfo.vips===2">
<image :src="require('../../static/service_06.png')" mode="" class="photo"></image>
<view class="label_box">资源推介</view>
</view>
<view class="list_item" @click="onServiceItemClick('my-team')"
v-if="userStateInfo.vips===1 || userStateInfo.vips===2">
<image :src="require('../../static/service_07.png')" mode="" class="photo"></image>
<view class="label_box">我的团队</view>
</view>
<view class="list_item" @click="onServiceItemClick('about-us')">
<image :src="require('../../static/service_08.png')" mode="" class="photo"></image>
<view class="label_box">关于我们</view>
</view>
</view>
</view>
<!-- 二维码弹出层 -->
<van-popup :show="isShowCodePopup" @close="onCloseCodePopup" round closeable>
<image :src="userStateInfo.ewm" mode="" class="code-photo_box" v-if="userStateInfo.vips!==0"></image>
<!-- <view class="code-photo_box"></view> -->
</van-popup>
</view>
</template>
<script>
import {mapState,mapMutations} from 'vuex'
export default {
computed: {
...mapState(['userInfo', 'userStateInfo'])
},
data() {
return {
// 控制二维码弹出层的显示与隐藏
isShowCodePopup: false,
}
},
onShow() {
// 调用获取用户状态的方法
this.getUserState()
},
methods: {
...mapMutations(['updateUserStateInfo']),
// 获取用户状态的方法
async getUserState() {
try {
// 如果没有登录或者已经获取过用户状态,则终止函数执行
if (!this.userInfo.id) return
// 准备请求参数
const requestPayload = {
id: this.userInfo.id
}
// 发送请求
const res = await this.$request('/userLong/findId', this.$PostHeader, requestPayload)
// 如果请求失败,则终止函数执行
if (res.status !== '200') return
// 如果请求成功,调用 store 的 mutation
this.updateUserStateInfo(res.data)
} catch (e) {
//TODO handle the exception
}
},
// 处理函数,当登录按钮被点击时触发
onLoginClick() {
// 跳转到登录页面
uni.navigateTo({
url: '/pages/home/Login'
})
},
// 处理函数,当服务项被点击时触发
onServiceItemClick(address) {
// 如果用户未登录
if (!this.userInfo.id) {
// 跳转到登录页面,并终止函数执行
return uni.navigateTo({
url: '/pages/home/Login'
})
}
// 跳转到对应的页面
uni.navigateTo({
url: '/pages/my/' + address
})
},
// 处理函数,当二维码被点击时触发
onCodeClick() {
// 显示二维码弹出层
this.isShowCodePopup = true
},
// 处理函数,当关闭二维码弹出层时触发
onCloseCodePopup() {
// 隐藏二维码弹出层
this.isShowCodePopup = false
}
}
}
</script>
<style lang="scss" scoped>
.my_container {
// 头部容器
.headBg_box {
width: 750rpx;
height: 400rpx;
background-image: linear-gradient(45deg, #7cba3f, #a8da78);
padding-top: 60rpx;
box-sizing: border-box;
.head_title {
display: flex;
justify-content: center;
font-size: 34rpx;
font-weight: bold;
color: #FFFCF0;
letter-spacing: 5rpx;
}
.login-state_box,
{
display: flex;
margin-top: 52rpx;
margin-left: 60rpx;
justify-content: space-between;
.left_box {
display: flex;
flex-wrap: wrap;
.avatar_box {
overflow: hidden;
margin-right: 19rpx;
width: 100rpx;
height: 100rpx;
border-radius: 50%;
.avatar {
width: 100%;
height: 100%;
}
}
.info_box {
display: flex;
flex-direction: column;
.name_box {
margin-bottom: 10rpx;
font-size: 34rpx;
font-weight: bold;
color: #FFFCF0;
margin-left: 10rpx;
display: flex;
.name {
margin-right: 33rpx;
}
.icon_edit {
width: 26rpx;
height: 26rpx;
.photo {
width: 100%;
height: 100%;
}
}
}
.level_box {
width: 165rpx;
height: 50rpx;
background: url('~@/static/icon_level.png') no-repeat;
background-size: 100% 100%;
display: flex;
align-items: center;
padding-left: 55rpx;
box-sizing: border-box;
font-size: 24rpx;
font-weight: 400;
color: #FFFFFF;
}
}
}
.right_box {
margin: 20rpx;
width: 160rpx;
height: 60rpx;
border: 1rpx solid #fff;
border-radius: 35rpx;
display: flex;
justify-content: center;
align-items: center;
.add_btn {
display: flex;
justify-content: center;
align-items: center;
font-size: 20rpx;
font-weight: 400;
color: #fff;
border: none;
}
}
.code_box {
display: flex;
flex-direction: column;
align-items: center;
margin-right: 47rpx;
.photo {
width: 65rpx;
height: 57rpx;
}
.label_box {
padding-top: 8rpx;
font-size: 24rpx;
font-weight: bold;
color: #FFFFFF;
}
}
}
.logout-state_box {
margin-top: 53rpx;
margin-left: 60rpx;
font-size: 34rpx;
font-weight: bold;
color: #FFFCF0;
display: flex;
.avatar_box {
margin-right: 19rpx;
width: 100rpx;
height: 100rpx;
.avatar {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.info_box {
display: flex;
flex-direction: column;
.name_box {
margin-bottom: 10rpx;
font-size: 34rpx;
font-weight: bold;
color: #FFFCF0;
margin-left: 10rpx;
display: flex;
.name {
margin-right: 33rpx;
}
.icon_edit {
width: 26rpx;
height: 26rpx;
.photo {
width: 100%;
height: 100%;
}
}
}
.level_box {
width: 165rpx;
height: 50rpx;
background: url('~@/static/icon_level.png') no-repeat;
background-size: 100% 100%;
display: flex;
align-items: center;
padding-left: 55rpx;
box-sizing: border-box;
font-size: 24rpx;
font-weight: 400;
color: #FFFFFF;
}
}
.tip_box {
margin-top: 10rpx;
font-size: 50rpx;
font-weight: bold;
color: #ddd;
}
}
}
// 账户盒子
.account_box {
width: 710rpx;
height: 148rpx;
background: #FFFFFF;
margin: -72rpx 20rpx 0;
border-radius: 10px;
display: flex;
justify-content: space-between;
padding: 0 115rpx;
box-sizing: border-box;
box-shadow: 8rpx 12rpx 10rpx rgba(0, 0, 0, 0.3);
.balance_box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
.number_box {
margin-top: 30rpx;
}
.label_box {
margin-bottom: 27rpx;
display: flex;
align-items: center;
.label_icon {
width: 34rpx;
height: 29rpx;
margin-right: 10rpx;
}
.label_desc {
font-size: 24rpx;
font-weight: 400;
color: #333333;
opacity: 0.8;
}
}
}
.line_box {
display: flex;
align-items: center;
height: 100%;
.line {
width: 2rpx;
height: 43rpx;
background: #F0F0F0;
}
}
}
// 服务盒子
.service_box {
margin: 25rpx;
display: flex;
flex-direction: column;
width: 710rpx;
// height: 480rpx;
background: #FFFFFF;
border-radius: 10px;
box-shadow: 8rpx 12rpx 10rpx rgba(0, 0, 0, 0.3);
.head_box {
display: flex;
justify-content: center;
.head-title_box {
padding: 40rpx 0 16rpx;
width: 690rpx;
border-bottom: 2rpx solid #F5F5F5;
font-size: 28rpx;
font-weight: 400;
color: #333333;
}
}
.list_box {
display: flex;
flex-wrap: wrap;
.list_item {
flex: 25% 0;
display: flex;
flex-direction: column;
align-items: center;
.photo {
margin-top: 34rpx;
margin-bottom: 20rpx;
width: 75rpx;
height: 75rpx;
border-radius: 50%;
}
.label_box {
margin-bottom: 60rpx;
font-size: 24rpx;
font-weight: 400;
color: #333333;
}
}
}
}
// 二维码弹出层
.code-photo_box {
margin: 80rpx 50rpx 50rpx;
width: 400rpx;
height: 400rpx;
// background-color: skyblue;
// .
}
// 补丁样式(完成后的修修补补)
.mt_22 {
margin-top: 22rpx;
}
}
</style>