Browse Source

完善手机密码登录和Vuex状态管理

sfmind 2 years ago
parent
commit
93352b5386

+ 25 - 16
yudao-ui-app/App.vue

@@ -1,22 +1,31 @@
 <script>
-	export default {
-		onLaunch: function() {
-			console.log('App Launch')
-		},
-		onShow: function() {
-			console.log('App Show')
-		},
-		onHide: function() {
-			console.log('App Hide')
-		}
-	}
+export default {
+  onLaunch: function () {
+    console.log('App Launch')
+    // #ifdef H5
+    //在页面加载时读取sessionStorage里的状态信息
+    if (sessionStorage.getItem('store')) {
+      this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem('store'))))
+    }
+    //在页面刷新时将vuex里的信息保存到sessionStorage里
+    window.addEventListener('beforeunload', () => {
+      sessionStorage.setItem('store', JSON.stringify(this.$store.state))
+    })
+    // #endif
+  },
+  onShow: function () {
+    console.log('App Show')
+  },
+  onHide: function () {
+    console.log('App Hide')
+  }
+}
 </script>
 
 <style lang="scss">
-  /* 引入uView基础样式 */
-  @import "@/uni_modules/uview-ui/index.scss";
-
-  /*每个页面公共scss */
-  @import "app.scss";
+/* 引入uView基础样式 */
+@import '@/uni_modules/uview-ui/index.scss';
 
+/*每个页面公共scss */
+@import 'app.scss';
 </style>

+ 4 - 1
yudao-ui-app/common/api.js

@@ -2,12 +2,15 @@ const { http } = uni.$u
 
 /* login */
 //使用手机 + 密码登录
-export const passwordLogin = params => http.post('/app-api/member/user/login', params)
+export const passwordLogin = params => http.post('/app-api/member/login', params)
 //发送手机验证码
 export const sendSmsCode = params => http.post('/app-api/member/send-sms-code', params)
 //使用手机 + 验证码登录
 export const smsLogin = params => http.post('/app-api/member/sms-login', params)
 
+//获取用户信息
+export const getUserInfo = params => http.get('/app-api/member/user/get', params)
+
 /* index */
 // 获取滚动图数据
 export const getBannerData = params => http.get('/app-api/index', params)

+ 6 - 1
yudao-ui-app/common/config.js

@@ -1,3 +1,8 @@
 module.exports = {
-    baseUrl: 'http://192.168.3.199:8086'
+  //后端接口地址
+  baseUrl: 'http://127.0.0.1:48080',
+  header: {
+    //租户ID
+    'tenant-id': 1
+  }
 }

+ 3 - 5
yudao-ui-app/common/mixin.js

@@ -1,7 +1,5 @@
 export default {
-    data() {
-        return {
-
-        }
-    }
+  data() {
+    return {}
+  }
 }

+ 4 - 2
yudao-ui-app/main.js

@@ -1,14 +1,16 @@
 import Vue from 'vue'
 import App from './App'
 
+// 引入全局uView
+import uView from '@/uni_modules/uview-ui'
+
 // vuex
 import store from './store'
 
 Vue.config.productionTip = false
 Vue.prototype.$store = store
 
-// 引入全局uView
-import uView from '@/uni_modules/uview-ui'
+
 
 App.mpType = 'app'
 Vue.use(uView)

+ 7 - 2
yudao-ui-app/pages/cart/cart.vue

@@ -4,7 +4,7 @@
       <u-empty mode="car" width="500rpx" height="500rpx" icon="/static/images/empty/cart.png"></u-empty>
     </view>
 
-    <view class="login-tips-box">
+    <view v-if="!hasLogin" class="login-tips-box">
       <view class="login-tips">
         <navigator url="/pages/login/login" open-type="navigate" hover-class="none">
           <text class="login-link">登录</text>
@@ -23,7 +23,12 @@ export default {
     }
   },
   onLoad() {},
-  methods: {}
+  methods: {},
+  computed: {
+    hasLogin() {
+      return this.$store.getters.hasLogin
+    }
+  }
 }
 </script>
 

+ 23 - 23
yudao-ui-app/pages/login/login.vue

@@ -53,15 +53,13 @@ import { passwordLogin, sendSmsCode, smsLogin } from '../../common/api'
 export default {
   data() {
     return {
-      //租户ID
-      agent: 1,
       currentModeIndex: 0,
       loginModeList: ['密码登录', '验证码登录'],
       inputType: 'password',
       codeDisabled: false,
       codeTips: '',
       formData: {
-        mobile: '15601691234',
+        mobile: '',
         password: '',
         code: ''
       },
@@ -131,17 +129,17 @@ export default {
         })
 
         //scene:1登陆获取验证码场景
-        sendSmsCode({ agent: 1, mobile: mobile, scene: 1 })
+        sendSmsCode({ mobile: mobile, scene: 1 })
           .then(res => {
             //console.log(res)
             uni.hideLoading()
-            if (res.data.code === 0) {
+            if (res.code === 0) {
               // 这里此提示会被this.start()方法中的提示覆盖
               uni.$u.toast('验证码已发送')
               // 通知验证码组件内部开始倒计时
               this.$refs.uCode.start()
             } else {
-              uni.$u.toast(res.data.msg)
+              uni.$u.toast(res.msg)
             }
           })
           .catch(err => {
@@ -153,26 +151,30 @@ export default {
     },
     handleSubmit() {
       this.$refs.form.validate().then(res => {
-        uni.$u.toast('登录')
         if (this.currentModeIndex === 0) {
-          passwordLogin({ agent: 1, mobile: this.formData.mobile, password: this.formData.password })
-            .then(res => {
-              if (res.data.code === 0) {
-                uni.$u.toast('登录成功')
-                // TODO 登录成功,保存toke
-              } else {
-                uni.$u.toast(res.data.msg)
-                // TODO 登录失败
-              }
-            })
-            .catch(err => {
-              uni.$u.toast('服务器接口请求异常')
-            })
+          this.handleLoginPromise(passwordLogin({ mobile: this.formData.mobile, password: this.formData.password }))
         } else if (this.currentModeIndex === 1) {
-          smsLogin({ agent: 1, mobile: this.formData.mobile, code: this.formData.code })
+          this.handleLoginPromise(smsLogin({ mobile: this.formData.mobile, code: this.formData.code }))
         }
       })
     },
+    handleLoginPromise(promise) {
+      promise
+        .then(res => {
+          if (res.code === 0) {
+            this.$store.commit('setToken', res.data)
+            uni.$u.toast('登录成功')
+            setTimeout(() => {
+              this.navigateBack()
+            }, 1000)
+          } else {
+            uni.$u.toast(res.msg)
+          }
+        })
+        .catch(err => {
+          uni.$u.toast('接口请求失败')
+        })
+    },
     navigateBack() {
       uni.navigateBack()
     }
@@ -200,8 +202,6 @@ export default {
   }
 }
 
-
-
 .lk-group {
   height: 40rpx;
   margin-top: 40rpx;

+ 31 - 13
yudao-ui-app/pages/user/user.vue

@@ -2,8 +2,8 @@
   <view class="container">
     <view class="user-header">
       <view class="user-info" @click="loginOrJump('/pages/profile/profile')">
-        <u-avatar size="80" :src="avatar"></u-avatar>
-        <text class="nick-name">{{ nickName }}</text>
+        <u-avatar size="80" :src="userInfo.avatar"></u-avatar>
+        <text class="nick-name">{{ hasLogin ? userInfo.nickname || '游客' : '点击登录' }}</text>
       </view>
     </view>
 
@@ -19,8 +19,8 @@
       </view>
 
       <view class="order-status-box">
-        <u-grid :border="false" :col="orderStatusList.length"
-          ><u-grid-item v-for="(item, index) in orderStatusList" :key="index">
+        <u-grid :border="false" :col="orderStatusList.length">
+          <u-grid-item v-for="(item, index) in orderStatusList" :key="index">
             <u-icon :name="item.icon" :size="32"></u-icon>
             <text class="grid-title">{{ item.title }}</text>
           </u-grid-item>
@@ -45,13 +45,12 @@
       <u-cell class="fun-item" :border="false" icon="gift" title="分销中心" isLink></u-cell>
       <u-cell class="fun-item" :border="false" icon="tags" title="领券中心" isLink></u-cell>
       <u-cell class="fun-item" :border="false" icon="coupon" title="我的优惠券" isLink></u-cell>
-      <u-cell class="fun-item" :border="false" icon="map" title="收货地址"  @click="loginOrJump('/pages/address/list')" isLink></u-cell>
+      <u-cell class="fun-item" :border="false" icon="map" title="收货地址" @click="loginOrJump('/pages/address/list')" isLink></u-cell>
     </u-cell-group>
 
-    <view class="logout-btn">
-      <u-button type="error" color="#ea322b" text="确定"></u-button>
+    <view v-if="hasLogin" class="logout-btn">
+      <u-button type="error" color="#ea322b" text="退出登录" @click="logout"></u-button>
     </view>
-
   </view>
 </template>
 
@@ -59,8 +58,6 @@
 export default {
   data() {
     return {
-      avatar: '',
-      nickName: '点击登录',
       orderStatusList: [
         { icon: 'rmb-circle', title: '待支付' },
         { icon: 'car', title: '代发货' },
@@ -76,13 +73,34 @@ export default {
   },
   onLoad() {},
   methods: {
-    loginOrJump(pageUrl){
-      // TODO 判断是否已经登录逻辑
-      if (!uni.getStorageSync('token')) {
+    loginOrJump(pageUrl) {
+      if (!this.hasLogin) {
         uni.$u.route('/pages/login/login')
       } else {
         uni.$u.route(pageUrl)
       }
+    },
+    logout() {
+      uni.showModal({
+        title: '提示',
+        content: '您确定要退出登录吗',
+        success: res => {
+          if (res.confirm) {
+            console.log('用户点击确定')
+            this.$store.commit('logout')
+          } else if (res.cancel) {
+            console.log('用户点击取消')
+          }
+        }
+      })
+    }
+  },
+  computed: {
+    userInfo() {
+      return this.$store.state.userInfo
+    },
+    hasLogin() {
+      return this.$store.getters.hasLogin
     }
   }
 }

+ 49 - 11
yudao-ui-app/store/index.js

@@ -1,26 +1,64 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
+import { getUserInfo } from '@/common/api'
 
 Vue.use(Vuex) // vue的插件机制
 
 // Vuex.Store 构造器选项
 const store = new Vuex.Store({
-    // 为了不和页面或组件的data中的造成混淆,state中的变量前面建议加上$符号
-    state: {
-        // 用户信息
-        $userInfo: {
-            id: ''
+  state: {
+    openExamine: false, // 是否开启审核状态。用于小程序、App 等审核时,关闭部分功能。TODO 芋艿:暂时没找到刷新的地方
+    token: uni.getStorageSync('token'), // 用户身份 Token
+    userInfo: {}, // 用户基本信息
+    timerIdent: false // 全局 1s 定时器,只在全局开启一个,所有需要定时执行的任务监听该值即可,无需额外开启 TODO 芋艿:需要看看
+  },
+  getters: {
+    hasLogin(state) {
+      return !!state.token
+    }
+  },
+  mutations: {
+    // 更新 state 的通用方法
+    setStateAttr(state, param) {
+      if (param instanceof Array) {
+        for (let item of param) {
+          state[item.key] = item.val
         }
+      } else {
+        state[param.key] = param.val
+      }
     },
-    mutations: {
-
-    },
-    actions: {
+    // 更新token
+    setToken(state, data) {
+      // 设置 Token
+      const { token } = data
+      state.token = token
+      uni.setStorageSync('token', token)
 
+      // 加载用户信息
+      this.dispatch('obtainUserInfo')
     },
-    getters:{
-
+    // 退出登录
+    logout(state) {
+      // 清空 Token
+      state.token = ''
+      uni.removeStorageSync('token')
+      // 清空用户信息 TODO 芋艿:这里 setTimeout 的原因是,上面可能还有一些 request 请求。后续得优化下
+      setTimeout(() => {
+        state.userInfo = {}
+      }, 1100)
+    }
+  },
+  actions: {
+    // 获得用户基本信息
+    async obtainUserInfo({ state, commit }) {
+      const res = await getUserInfo()
+      commit('setStateAttr', {
+        key: 'userInfo',
+        val: res.data
+      })
     }
+  }
 })
 
 export default store

+ 1 - 0
yudao-ui-app/util/request/index.js

@@ -4,6 +4,7 @@ import config from '@/common/config'
 uni.$u.http.setConfig((defaultConfig) => {
     /* defaultConfig 为默认全局配置 */
     defaultConfig.baseURL = config.baseUrl /* 根域名 */
+    defaultConfig.header = config.header
     return defaultConfig
 })
 

+ 17 - 9
yudao-ui-app/util/request/requestInterceptors.js

@@ -2,13 +2,21 @@
  * 请求拦截
  * @param {Object} http
  */
-module.exports = (vm) => {
-    uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作
-        // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
-        config.data = config.data || {}
-        // 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中
-        // console.log(vm.$store.state);
-        return config
-    }, (config) => // 可使用async await 做异步操作
-        Promise.reject(config))
+module.exports = vm => {
+  uni.$u.http.interceptors.request.use(
+    config => {
+      // 可使用async await 做异步操作
+      // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
+      config.data = config.data || {}
+      // 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中
+      // console.log(vm.$store.state)
+      if (vm.$store.getters.hasLogin) {
+        config.header.authorization = 'Bearer ' + vm.$store.state.token
+      }
+      return config
+    },
+    (
+      config // 可使用async await 做异步操作
+    ) => Promise.reject(config)
+  )
 }

+ 13 - 13
yudao-ui-app/util/request/responseInterceptors.js

@@ -2,16 +2,16 @@
  * 响应拦截
  * @param {Object} http
  */
-module.exports = (vm) => {
-    uni.$u.http.interceptors.response.use((res) => {
-        /* 对响应成功做点什么 可使用async await 做异步操作*/
-        const data = res.data
-        /*
-         可以根据业务情况做相应的处理
-        */
-        return res
-    }, (err) => {
-        /*  对响应错误做点什么 (statusCode !== 200)*/
-        return Promise.reject(err)
-    })
-}
+module.exports = vm => {
+  uni.$u.http.interceptors.response.use(
+    res => {
+      //对响应成功做点什么 可使用async await 做异步操作
+      //可以根据业务情况做相应的处理
+      return res.data
+    },
+    err => {
+      //对响应错误做点什么 (statusCode !== 200)
+      return Promise.reject(err)
+    }
+  )
+}