Ver código fonte

Merge branch 'jobFair' of https://git.citupro.com/zhengnaiwen_citu/menduner into jobFair

lifanagju_citu 3 semanas atrás
pai
commit
7328bb2306

+ 1 - 0
components.d.ts

@@ -32,6 +32,7 @@ declare module 'vue' {
     DatePicker: typeof import('./src/components/DatePicker/index.vue')['default']
     Echarts: typeof import('./src/components/Echarts/index.vue')['default']
     ElBacktop: typeof import('element-plus/es')['ElBacktop']
+    ElCascader: typeof import('element-plus/es')['ElCascader']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElSegmented: typeof import('element-plus/es')['ElSegmented']
     Empty: typeof import('./src/components/Empty/index.vue')['default']

+ 19 - 0
src/api/common/qrcodeLogin.js

@@ -0,0 +1,19 @@
+import request from '@/config/axios'
+
+// 获取小程序登陆码
+export const getWeXinLoginQrCode = async (params, signal) => {
+	return await request.download({
+		url: '/app-api/menduner/system/auth/weixin/login/qrcode',
+		params,
+		signal
+	})
+}
+
+// 检查小程序是否授权登陆
+export const checkWeXinLoginAuthorize = async (data, signal) => {
+	return await request.post({
+		url: '/app-api/menduner/system/auth/weixin/login/authorize/code',
+		data,
+		signal
+	})
+}

+ 5 - 2
src/config/axios/service.js

@@ -253,7 +253,6 @@ service.interceptors.response.use(
       }
     }
     if (code === 500) {
-      // Snackbar.error(t('sys.api.errMsg500'))
       if (!isConfirmDialogOpen) {
         isConfirmDialogOpen = true
         Confirm(t('common.confirmTitle'), t('sys.api.errMsg500'), {
@@ -319,7 +318,11 @@ service.interceptors.response.use(
     } else if (message.includes('Request failed with status code')) {
       message = t('sys.api.apiRequestFailed') + message.substr(message.length - 3)
     }
-    Snackbar.error(message)
+
+    if (error.config && error.config.url && error.config.url === '/app-api/menduner/system/auth/weixin/login/authorize/code') {
+      console.log(error, '取消请求')
+    }
+    else Snackbar.error(message)
     return Promise.reject(error)
   }
 )

+ 12 - 0
src/store/user.js

@@ -76,6 +76,18 @@ export const useUserStore = defineStore('user',
           }).catch(err => { reject(err) })
         })
       },
+      // 扫码登录
+      async handleWeXinQrCodeLogin (data) {
+        this.token = data.accessToken
+        setToken(data.accessToken)
+        setRefreshToken(data.refreshToken)
+        this.accountInfo = data
+        localStorage.setItem('accountInfo', JSON.stringify(data))
+        localStorage.setItem('expiresTime', data.expiresTime) // token过期时间
+        updateEventList(true) // 获取规则配置跟踪列表
+        await this.getUserInfos()
+        await this.getUserBaseInfos('')
+      },
       // 密码登录
       async handlePasswordLogin(data) {
         return new Promise((resolve, reject) => {

+ 133 - 23
src/views/login/index.vue

@@ -28,10 +28,10 @@
           </div>
           <!-- 个人登录 -->
           <div v-show="!isEnterpriseLogin" class="login-tab">
-            <v-tabs v-model="tab" align-tabs="center" color="primary" class="mb-10" @update:modelValue="tabChange">
+            <v-tabs v-model="tab" align-tabs="center" color="primary" :class="`mb-${tab === 3 ? 6 : 9}`" @update:modelValue="tabChange">
               <v-tab :value="2">账号</v-tab>
               <v-tab :value="1">验证码</v-tab>
-              <!-- <v-tab :value="3">微信</v-tab> -->
+              <v-tab :value="3">微信扫码</v-tab>
             </v-tabs>
             <v-window v-model="tab">
                 <!-- 验证码登录 -->
@@ -42,25 +42,33 @@
               <v-window-item :value="2">
                 <passwordFrom ref="passRef" @handleEnter="handleLogin"></passwordFrom>
               </v-window-item>
-              <!-- <v-window-item :value="3">
-                <div v-if="showQrCode" class="d-flex align-center flex-column">
-                  <span class="text-decoration-underline">微信扫描二维码进行登录</span>
-                  <v-img src="https://minio.citupro.com/dev/menduner/login-qrCode.png" width="150" height="150"></v-img>
+              <v-window-item :value="3">
+                <div v-if="showQrCode" class="d-flex align-center flex-column position-relative">
+                  <v-img :src="qrCodeUrl" width="200" height="200"></v-img>
+                  <span class="color-666 font-size-13 mt-3">请使用微信扫描二维码登录“门墩儿”</span>
+                  <span v-if="remainderZhShow" class="color-warning font-size-13 mt-1">请在{{ remainderZhShow }}内扫码授权登录</span>
+
+                  <div v-if="qrCodeDisabled" class="disabledBox">
+                    <div class="disabledContent">
+                      <div class="color-666">请重新刷新二维码</div>
+                      <v-btn color="primary" class="mt-5" elevation="0" @click="disabledClick">点击刷新</v-btn>
+                    </div>
+                  </div>
                 </div>
                 <div v-else style="height: 150px; line-height: 150px; text-align: center;">
                   加载中 . . .
                 </div>
-              </v-window-item> -->
+              </v-window-item>
             </v-window>
           </div>
           <div class="font-size-14">
-            <span class="float-left tips color-666 cursor-pointer" v-if="tab === 2" @click="router.push(isEnterpriseLogin ? '/forgotPasswordEnt': '/forgotPassword')">忘记密码</span>
-            <span class="float-right color-error cursor-pointer border-bottom-error" @click="router.push('/register/selected')">还没有登录账户?去注册</span>
+            <span v-if="tab === 2" class="float-left tips color-666 cursor-pointer" @click="router.push(isEnterpriseLogin ? '/forgotPasswordEnt': '/forgotPassword')">忘记密码</span>
+            <span v-if="tab !== 3" class="float-right color-error cursor-pointer border-bottom-error" @click="router.push('/register/selected')">还没有登录账户?去注册</span>
           </div>
-          <v-btn :loading="loginLoading" color="primary" class="white--text mt-5" min-width="350" @click.stop="handleLogin">
+          <v-btn v-if="tab !== 3" :loading="loginLoading" color="primary" class="white--text mt-5" min-width="350" @click.stop="handleLogin">
             {{ $t('login.login') }}
           </v-btn>
-          <div class="login-tips mt-3">
+          <div class="login-tips mt-3" v-if="tab !== 3">
               <v-icon v-if="isAgree" size="25" color="primary" class="mr-1" @click="isAgree = !isAgree">mdi-check-circle</v-icon>
               <v-icon v-else size="25" color="grey" class="mr-1" @click="isAgree = !isAgree">mdi-circle-outline</v-icon>
               {{ $t('login.agreeLogin') }}
@@ -104,6 +112,8 @@ import about from '@/views/about/index.vue'
 import { useRoute } from 'vue-router'; const route = useRoute()
 import Verify from '@/components/Verifition'
 import { useMallStore } from '@/store/mall'
+import { generateUUID } from '@/utils/index'
+import { getWeXinLoginQrCode, checkWeXinLoginAuthorize } from '@/api/common/qrcodeLogin'
 
 const isMobile = ref(false)
 onMounted(async () => {
@@ -116,6 +126,7 @@ onMounted(async () => {
 const logoBgUrl = ref('')
 const preferred = ref({})
 const carouselList = ref([])
+
 const getSystemWebContent = async () => {
   const data = await getWebContent()
   logoBgUrl.value = data.pcLoginBackground && data.pcLoginBackground.length ? data.pcLoginBackground[0].img : 'https://minio.menduner.com/dev/menduner/login-bgc.jpg'
@@ -223,21 +234,104 @@ const handleLogin = async () => {
   }
 }
 
+// 微信扫码-小程序授权登录
+const qrCodeUrl = ref(null)
+const showQrCode = ref(true)
+const qrCodeDisabled = ref(true )
+const query = ref({
+  clientId: null
+})
+
+const remainder = ref(0)
+const remainderZhShow = ref('')
+const remainderTimer = ref(null)
+const abortController = ref(null)
+const formatDuration = (time) => {
+  var seconds = Math.floor(time / 1000)
+  var minutes = Math.floor(seconds / 60)
+  var remainingSeconds = seconds % 60
+  minutes = minutes.toString().padStart(2, '0')
+  remainingSeconds = remainingSeconds.toString().padStart(2, '0')
+  return `${minutes}分${remainingSeconds}秒`
+}
+const remainderCalc = () => {
+  remainder.value -= 1000
+  remainderZhShow.value = formatDuration(remainder.value)
+  if (remainder.value <= 0) {
+    qrCodeDisabled.value = true
+    // 取消所有正在进行的请求
+    if (abortController.value) {
+      abortController.value.abort() 
+      abortController.value = null
+    }
+    handleAuthorize(true)
+  }
+}
+// 初始化倒计时
+const countdownTime = 60000 * 5 // 倒计时五分钟
+const initIntervalFun = () => {
+  remainder.value = countdownTime // 初始倒计时时间
+  if (remainderTimer.value) clearInterval(remainderTimer.value); remainderTimer.value = null // 每一次点击都清除上一个轮询
+  // 倒计时计算
+  remainderCalc()
+  remainderTimer.value = setInterval(() => { remainderCalc() }, 1000)
+}
+
+// 轮巡查询是否授权成功
+const handleAuthorize = async (stop) => {
+  // 二维码失效停止请求
+  if (stop) return
+  try {
+    abortController.value = new AbortController()
+    const signal = abortController.value.signal
+    const data = await checkWeXinLoginAuthorize(query.value, signal)
+    if (!data) return
+    query.value.clientId = data.clientId
+
+    // 等待扫码授权中
+    if (data.status === '0' || !data.appMdeAuthLoginRespVO || !Object.keys(data.appMdeAuthLoginRespVO).length) {
+      handleAuthorize()
+      return
+    }
+    
+    // 授权成功,返回登录信息
+    await userStore.handleWeXinQrCodeLogin(data.appMdeAuthLoginRespVO)
+    router.push('/')
+  } catch (error) {
+    console.log(error, 'error')
+  }
+}
+
+// 小程序二维码获取
+const getSocialAuthRedirect = async () => {
+  showQrCode.value = false
+  try {
+    const data = await getWeXinLoginQrCode(query.value)
+    qrCodeUrl.value = URL.createObjectURL(data)
+    qrCodeDisabled.value = false
+    showQrCode.value = true
+    initIntervalFun()
+    handleAuthorize()
+  } catch {
+    showQrCode.value = false
+  }
+}
 
-// const getSocialAuthRedirect = async () => {
-//   const params = {
-//     type: '34',
-//     redirectUri: 'https://www.baidu.com'
-//   }
-//   const res = await socialAuthRedirect(params)
-//   const otherUrl = res?.url
-//   if (otherUrl) window.open(otherUrl)
-// }
+// 二维码过期重新生成
+const disabledClick = () => {
+  qrCodeDisabled.value = false
+  query.value.clientId = generateUUID()
+  getSocialAuthRedirect()
+}
 
-// const showQrCode = ref(false)
 const tabChange = (val) => {
   if (val === 3) {
-    // getSocialAuthRedirect()
+    if (abortController.value) {
+      abortController.value.abort()
+      abortController.value = null
+    }
+    query.value.clientId = generateUUID()
+    getSocialAuthRedirect()
   }
 }
 
@@ -257,10 +351,25 @@ const verifySuccess = (params) => {
 const windowOpen = (url) => {
   if (url) window.open(url)
 }
-
 </script>
 
 <style lang="scss" scoped>
+.disabledBox {
+  position: absolute;
+  top: 0;
+  left: 0;
+  background: rgb(255 255 255 / 90%);
+  height: 100%;
+  width: 100%;
+}
+.disabledContent {
+  height: 90%;
+  width: 100%;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
 .box {
   position: relative;
   width: 100%;
@@ -305,6 +414,7 @@ const windowOpen = (url) => {
   background-color: #fff;
   border-radius: 8px;
   padding: 36px 50px;
+  height: 392px;
 }
 .left {
   display: flex;