소스 검색

新增:新版用户端授权登录

Yahoo 4 년 전
부모
커밋
a3e455ba1a
8개의 변경된 파일과 256개의 추가작업 그리고 79개의 파일을 삭제
  1. 17 0
      api/captcha.js
  2. 9 15
      api/login/index.js
  3. 7 1
      api/user.js
  4. 16 21
      pages/login/components/main.vue
  5. 133 0
      pages/login/components/mp-weixin-mobile.vue
  6. 14 20
      pages/login/components/mp-weixin.vue
  7. 43 18
      pages/login/index.vue
  8. 17 4
      store/modules/user.js

+ 17 - 0
api/captcha.js

@@ -0,0 +1,17 @@
+import request from '@/utils/request'
+
+// api地址
+const api = {
+  image: 'captcha/image',
+  sendSmsCaptcha: 'captcha/sendSmsCaptcha'
+}
+
+// 图形验证码
+export function image() {
+  return request.get(api.image, {}, { load: false })
+}
+
+// 发送短信验证码
+export function sendSmsCaptcha(data) {
+  return request.post(api.sendSmsCaptcha, data, { load: false })
+}

+ 9 - 15
api/login/index.js

@@ -3,27 +3,21 @@ import request from '@/utils/request'
 // api地址
 const api = {
   login: 'passport/login',
-  mpWxLogin: 'passport/mpWxLogin',
-  captcha: 'passport/captcha',
-  sendSmsCaptcha: 'passport/sendSmsCaptcha'
+  loginMpWx: 'passport/loginMpWx',
+  loginMpWxMobile: 'passport/loginMpWxMobile',
 }
 
-// 用户登录
+// 用户登录(手机号+验证码)
 export function login(data) {
   return request.post(api.login, data)
 }
 
-// 微信小程序快捷登录
-export function mpWxLogin(data, option) {
-  return request.post(api.mpWxLogin, data, option)
+// 微信小程序快捷登录(获取微信用户基本信息)
+export function loginMpWx(data, option) {
+  return request.post(api.loginMpWx, data, option)
 }
 
-// 图形验证码
-export function captcha() {
-  return request.get(api.captcha, {}, { load: false })
-}
-
-// 发送短信验证码
-export function sendSmsCaptcha(data) {
-  return request.post(api.sendSmsCaptcha, data, { load: false })
+// 微信小程序快捷登录(授权手机号)
+export function loginMpWxMobile(data, option) {
+  return request.post(api.loginMpWxMobile, data, option)
 }

+ 7 - 1
api/user.js

@@ -3,7 +3,8 @@ import request from '@/utils/request'
 // api地址
 const api = {
   userInfo: 'user/info',
-  assets: 'user/assets'
+  assets: 'user/assets',
+  bindMobile: 'user/bindMobile'
 }
 
 // 当前登录的用户信息
@@ -20,3 +21,8 @@ export const info = (param, option) => {
 export const assets = (param, option) => {
   return request.get(api.assets, param)
 }
+
+// 绑定手机号
+export const bindMobile = (data, option) => {
+  return request.post(api.bindMobile, data, option)
+}

+ 16 - 21
pages/login/components/main.vue

@@ -1,5 +1,6 @@
 <template>
   <view class="container">
+
     <!-- 页面头部 -->
     <view class="header">
       <view class="title">
@@ -39,14 +40,21 @@
         <text>登录</text>
       </view>
     </view>
+
+    <!-- 微信授权手机号一键登录 -->
+    <!-- #ifdef MP-WEIXIN -->
+    <MpWeixinMobile :isParty="isParty" :partyData="partyData" />
+    <!-- #endif -->
+
   </view>
 </template>
 
 <script>
   import store from '@/store'
   import * as LoginApi from '@/api/login'
-  import { throttle, debounce } from '@/utils/util'
+  import * as CaptchaApi from '@/api/captcha'
   import * as Verify from '@/utils/verify'
+  import MpWeixinMobile from './mp-weixin-mobile'
 
   // 倒计时时长(秒)
   const times = 60
@@ -56,6 +64,10 @@
   const SUBMIT_LOGIN = 20
 
   export default {
+    components: {
+      MpWeixinMobile
+    },
+
     props: {
       // 是否存在第三方用户信息
       isParty: {
@@ -91,6 +103,7 @@
      * 生命周期函数--监听页面加载
      */
     created() {
+      console.log('main created')
       // 获取图形验证码
       this.getCaptcha()
     },
@@ -100,7 +113,7 @@
       // 获取图形验证码
       getCaptcha() {
         const app = this
-        LoginApi.captcha()
+        CaptchaApi.image()
           .then(result => app.captcha = result.data)
       },
 
@@ -166,7 +179,7 @@
       sendSmsCaptcha() {
         const app = this
         app.isLoading = true
-        LoginApi.sendSmsCaptcha({
+        CaptchaApi.sendSmsCaptcha({
             form: {
               captchaKey: app.captcha.key,
               captchaCode: app.captchaCode,
@@ -331,22 +344,4 @@
     box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.1);
     letter-spacing: 5rpx;
   }
-
-  // 微信授权登录
-  .wechat-auth {
-    display: flex;
-    justify-content: center;
-    margin-top: 40rpx;
-
-    .icon {
-      width: 38rpx;
-      height: 38rpx;
-      margin-right: 15rpx;
-    }
-
-    .title {
-      font-size: 28rpx;
-      color: #666666;
-    }
-  }
 </style>

+ 133 - 0
pages/login/components/mp-weixin-mobile.vue

@@ -0,0 +1,133 @@
+<template>
+  <!-- 微信授权手机号一键登录 -->
+  <view class="wechat-auth">
+    <button class="btn-normal" open-type="getPhoneNumber" @getphonenumber="handelMpWeixinMobileLogin($event)"
+      @click="clickPhoneNumber">
+      <view class="wechat-auth-container">
+        <image class="icon" src="../../../static/channel/wechat.png"></image>
+        <text class="title">微信手机号一键登录</text>
+      </view>
+    </button>
+  </view>
+</template>
+
+<script>
+  import store from '@/store'
+
+  export default {
+    props: {
+      // 是否存在第三方用户信息
+      isParty: {
+        type: Boolean,
+        default: () => false
+      },
+      // 第三方用户信息数据
+      partyData: {
+        type: Object
+      }
+    },
+
+    data() {
+      return {
+        // 微信小程序登录凭证 (code)
+        // 提交到后端,用于换取openid
+        code: ''
+      }
+    },
+
+    methods: {
+
+      // 按钮点击事件: 获取微信手机号按钮
+      // 实现目的: 在getphonenumber事件触发之前获取微信登录code
+      // 因为如果在getphonenumber事件中获取code的话,提交到后端的encryptedData会存在解密不了的情况
+      async clickPhoneNumber() {
+        this.code = await this.getCode()
+      },
+
+      // 微信授权获取手机号一键登录
+      // getphonenumber事件的回调方法
+      async handelMpWeixinMobileLogin({ detail }) {
+        const app = this
+        if (detail.errMsg !== 'getPhoneNumber:ok') {
+          return
+        }
+        app.isLoading = true
+        store.dispatch('LoginMpWxMobile', {
+            code: app.code,
+            encryptedData: detail.encryptedData,
+            iv: detail.iv,
+            isParty: app.isParty,
+            partyData: app.partyData,
+            refereeId: store.getters.refereeId
+          })
+          .then(result => {
+            // 显示登录成功
+            app.$toast(result.message)
+            // 跳转回原页面
+            setTimeout(() => {
+              app.onNavigateBack(1)
+            }, 2000)
+          })
+          .catch(err => {
+            console.log(err)
+            if (err.result.data.isBack) {
+              // 跳转回原页面
+              setTimeout(() => {
+                app.onNavigateBack(1)
+              }, 2000)
+            }
+          })
+          .finally(() => app.isLoading = false)
+      },
+
+      // 获取微信登录的code
+      // https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
+      getCode() {
+        return new Promise((resolve, reject) => {
+          uni.login({
+            provider: 'weixin',
+            success: res => {
+              console.log('code', res.code)
+              resolve(res.code)
+            },
+            fail: reject
+          })
+        })
+      },
+
+      /**
+       * 授权成功 跳转回原页面
+       */
+      onNavigateBack(delta = 1) {
+        uni.navigateBack({
+          delta: Number(delta)
+        })
+      }
+
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  // 微信授权登录
+  .wechat-auth {
+    width: 320rpx;
+    margin: 50rpx auto 0 auto;
+
+    .wechat-auth-container {
+      display: flex;
+      justify-content: center;
+    }
+
+    .icon {
+      width: 38rpx;
+      height: 38rpx;
+      margin-right: 15rpx;
+    }
+
+    .title {
+      font-size: 28rpx;
+      color: #666666;
+    }
+  }
+</style>

+ 14 - 20
pages/login/components/mp-weixin.vue

@@ -8,9 +8,7 @@
     <view class="auth-title">申请获取以下权限</view>
     <view class="auth-subtitle">获得你的公开信息(昵称、头像等)</view>
     <view class="login-btn">
-      <!-- 获取微信用户信息(旧版已弃用) -->
-      <!-- <button class="button btn-normal" open-type="getUserInfo" lang="zh_CN" @getuserinfo="getUserInfo">授权登录</button> -->
-      <!-- 获取微信用户信息(新版) -->
+      <!-- 获取微信用户信息 -->
       <button class="button btn-normal" @click.stop="getUserProfile">授权登录</button>
     </view>
     <view class="no-login-btn">
@@ -21,6 +19,7 @@
 
 <script>
   import store from '@/store'
+  import { isEmpty } from '@/utils/util'
 
   export default {
 
@@ -80,7 +79,14 @@
       async onAuthSuccess(userInfo) {
         const app = this
         // 提交到后端
-        store.dispatch('MpWxLogin', { code: await app.getCode(), userInfo })
+        store.dispatch('LoginMpWx', {
+            partyData: {
+              code: await app.getCode(),
+              oauth: 'MP-WEIXIN',
+              userInfo
+            },
+            refereeId: store.getters.refereeId
+          })
           .then(result => {
             // 一键登录成功
             app.$toast(result.message)
@@ -90,10 +96,12 @@
             }, 2000)
           })
           .catch(err => {
-            if (err.result.data.showError) {
+            const resultData = err.result.data
+            if (isEmpty(resultData)) {
               // 显示错误信息
               app.$toast(err.result.message)
-            } else {
+            }
+            if (resultData.isBindMobile) {
               // 将oauth提交给父级
               app.onEmitSuccess(userInfo)
             }
@@ -111,20 +119,6 @@
         })
       },
 
-      // /**
-      //  * 授权登录(旧版弃用)
-      //  */
-      // getUserInfo(e) {
-      //   const app = this
-      //   if (e.detail.errMsg === 'getUserInfo:ok') {
-      //     app.$emit('success', {
-      //       oauth: 'MP-WEIXIN', // 第三方登录类型: MP-WEIXIN
-      //       code: app.code, // 微信登录的code, 用于换取openid
-      //       userInfo: JSON.parse(e.detail.rawData) // 微信用户信息
-      //     })
-      //   }
-      // },
-
       /**
        * 暂不登录
        */

+ 43 - 18
pages/login/index.vue

@@ -1,13 +1,15 @@
 <template>
-  <div>
-    <MpWeixin v-if="isShowUserInfo" @success="onGetUserInfoSuccess" />
-    <Main v-else :isParty="isExistUserInfo" :partyData="partyData" />
-  </div>
+  <view v-if="isLoad" class="login">
+    <MpWeixin v-if="isMpWeixinAuth" @success="onGetUserInfoSuccess" />
+    <Main v-else :isParty="isParty" :partyData="partyData" />
+  </view>
 </template>
 
 <script>
   import Main from './components/main'
   import MpWeixin from './components/mp-weixin'
+  import SettingKeyEnum from '@/common/enum/setting/Key'
+  import SettingModel from '@/common/model/Setting'
 
   export default {
     components: {
@@ -17,10 +19,12 @@
 
     data() {
       return {
-        // 是否显示获取用户信息组件
-        isShowUserInfo: false,
-        // 是否已获取到了用户信息
-        isExistUserInfo: false,
+        // 数据加载完成 [防止在微信小程序端onLoad和view渲染同步进行]
+        isLoad: false,
+        // 是否显示微信小程序授权登录
+        isMpWeixinAuth: false,
+        // 是否存在第三方用户信息
+        isParty: false,
         // 第三方用户信息数据
         partyData: {}
       }
@@ -29,16 +33,37 @@
     /**
      * 生命周期函数--监听页面加载
      */
-    onLoad(options) {
-      const app = this
-      // 只有微信小程序才显示获取用户信息按钮
-      // #ifdef MP-WEIXIN
-      app.isShowUserInfo = wx.canIUse('getUserProfile')
-      // #endif
+    async onLoad(options) {
+      console.log('login onLoad')
+      // 设置当前是否显示微信小程序授权登录
+      await this.setShowUserInfo()
+      // 数据加载完成
+      this.isLoad = true
+      console.log('isLoad', true)
     },
 
     methods: {
 
+      /**
+       * 设置当前是否显示微信小程序授权登录
+       *  - 条件1: 只有微信小程序才显示获取用户信息按钮
+       *  - 条件2: 后台设置是否已开启该选项 [后台-客户端-注册设置]
+       */
+      async setShowUserInfo() {
+        console.log('setShowUserInfo start')
+        const app = this
+        // 判断当前客户端是微信小程序, 并且支持getUserProfile接口
+        const isMpWeixin = app.$platform === 'MP-WEIXIN' && wx.canIUse('getUserProfile')
+
+        // 获取后台设置
+        // 优化建议: 可以将isCache改为true启用缓存
+        await SettingModel.item(SettingKeyEnum.REGISTER.value, false)
+          .then(setting => {
+            app.isMpWeixinAuth = isMpWeixin && setting.isOauthMpweixin
+            console.log('setShowUserInfo complete')
+          })
+      },
+
       // 获取到用户信息的回调函数
       onGetUserInfoSuccess({ oauth, code, userInfo }) {
         // 记录第三方用户信息数据
@@ -49,10 +74,10 @@
 
       // 显示注册页面
       onShowRegister() {
-        // 是否显示获取用户信息组件
-        this.isShowUserInfo = false
-        // 是否已获取到了用户信息
-        this.isExistUserInfo = true
+        // 是否显示微信小程序授权登录
+        this.isMpWeixinAuth = false
+        // 已获取到了第三方用户信息
+        this.isParty = true
       }
     }
   }

+ 17 - 4
store/modules/user.js

@@ -33,7 +33,7 @@ const user = {
 
   actions: {
 
-    // 用户登录
+    // 用户登录(普通登录: 输入手机号和验证码)
     Login({ commit }, data) {
       return new Promise((resolve, reject) => {
         LoginApi.login({ form: data })
@@ -46,10 +46,23 @@ const user = {
       })
     },
 
-    // 微信小程序快捷登录
-    MpWxLogin({ commit }, data) {
+    // 微信小程序一键授权登录(获取用户基本信息)
+    LoginMpWx({ commit }, data) {
       return new Promise((resolve, reject) => {
-        LoginApi.mpWxLogin({ form: data }, { isPrompt: false })
+        LoginApi.loginMpWx({ form: data }, { isPrompt: false })
+          .then(response => {
+            const result = response.data
+            loginSuccess(commit, result)
+            resolve(response)
+          })
+          .catch(reject)
+      })
+    },
+
+    // 微信小程序一键授权登录(授权手机号)
+    LoginMpWxMobile({ commit }, data) {
+      return new Promise((resolve, reject) => {
+        LoginApi.loginMpWxMobile({ form: data }, { isPrompt: false })
           .then(response => {
             const result = response.data
             loginSuccess(commit, result)