feat: 添加微信扫码登录功能
This commit is contained in:
@ -178,3 +178,11 @@ export const getWalletConfig = () => {
|
|||||||
}>
|
}>
|
||||||
>('/prod-api/app-api/pay/wallet/get-config', {})
|
>('/prod-api/app-api/pay/wallet/get-config', {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信登录二维码链接
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const getLoginQrcode = () => {
|
||||||
|
return useDollarFetchRequest.get<IResponse<string>>('/prod-api/app-api/member/auth/wx-login-url', {})
|
||||||
|
}
|
||||||
|
|||||||
28
components/wx.vue
Normal file
28
components/wx.vue
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<!-- 二维码弹窗 -->
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-dialog title="微信二维码登录" v-model="visible" width="30%" :close-on-click-modal="false" :close-on-press-escape="false" @before-close="close">
|
||||||
|
<qrcode-vue :value="qrcode" :size="350" :margin="8" colorDark="#2c3e50" colorLight="#f8f9fa" errorCorrectionLevel="H" />
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import QrcodeVue from 'qrcode.vue'
|
||||||
|
const visible = defineModel('visible', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
const qrcode = defineModel('qrcode', {
|
||||||
|
default: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
visible.value = false
|
||||||
|
qrcode.value = ''
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-dialog__body) {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
20
layouts/success.vue
Normal file
20
layouts/success.vue
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout-wrap">
|
||||||
|
<div class="flex flex-1 flex-col">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup></script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.layout-wrap {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #fbfcff;
|
||||||
|
width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
156
pages/auth-success/index.vue
Normal file
156
pages/auth-success/index.vue
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<template>
|
||||||
|
<div class="auth-success-container">
|
||||||
|
<!-- 顶部成功图标 -->
|
||||||
|
<div class="success-icon">
|
||||||
|
<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="40" cy="40" r="40" fill="#4CD964" />
|
||||||
|
<path d="M25 40L35 50L55 30" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 标题和描述 -->
|
||||||
|
<div class="text-content">
|
||||||
|
<h1 class="title">授权成功</h1>
|
||||||
|
<p class="desc">
|
||||||
|
您已完成微信授权,<br />
|
||||||
|
请返回电脑端继续操作
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 倒计时提示 -->
|
||||||
|
<!-- <div class="countdown" v-if="countdown > 0">
|
||||||
|
<p>页面将在 {{ countdown }} 秒后自动关闭</p>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<!-- 底部按钮 -->
|
||||||
|
<!-- <div class="btn-group">
|
||||||
|
<button class="close-btn" @click="closePage">立即关闭</button>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
definePageMeta({
|
||||||
|
layout: 'success',
|
||||||
|
})
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
|
||||||
|
// 倒计时秒数
|
||||||
|
const countdown = ref(5)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 启动倒计时
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
countdown.value--
|
||||||
|
if (countdown.value <= 0) {
|
||||||
|
clearInterval(timer)
|
||||||
|
// 倒计时结束后尝试关闭页面(微信环境可能限制,仅作尝试)
|
||||||
|
closePage()
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 关闭页面方法(微信环境中可能无法直接关闭,仅作提示)
|
||||||
|
const closePage = () => {
|
||||||
|
// 尝试关闭当前页面(部分浏览器支持)
|
||||||
|
if (window.close) {
|
||||||
|
window.close()
|
||||||
|
} else {
|
||||||
|
// 微信环境中提示用户手动关闭
|
||||||
|
alert('请手动关闭此页面,返回电脑端继续操作')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.auth-success-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success-icon {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
animation: pop 0.5s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pop {
|
||||||
|
0% {
|
||||||
|
transform: scale(0.8);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-content {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 48px;
|
||||||
|
background-color: #07c160;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 24px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn:hover {
|
||||||
|
background-color: #06b355;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 适配小屏手机 */
|
||||||
|
@media (max-width: 320px) {
|
||||||
|
.title {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.close-btn {
|
||||||
|
height: 44px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -64,7 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="!isLogin" class="mt-[30px] flex justify-between px-[20px]">
|
<div v-if="!isLogin" class="mt-[30px] flex justify-between px-[20px]">
|
||||||
<img src="~/assets/images/qq-v2.png" alt="QQ登录" class="social-icon" @click="handleLoginQQ" />
|
<img src="~/assets/images/qq-v2.png" alt="QQ登录" class="social-icon" @click="handleLoginQQ" />
|
||||||
<img src="~/assets/images/weixin-v2.png" alt="微信登录" class="social-icon" @click="handleLoginWechat" />
|
<img src="~/assets/images/weixin-v2.png" alt="微信登录" class="social-icon" @click="handleLoginWechatV2" />
|
||||||
<img src="~/assets/images/email-v2.png" alt="邮箱登录" class="social-icon" @click="handleLoginEmail" />
|
<img src="~/assets/images/email-v2.png" alt="邮箱登录" class="social-icon" @click="handleLoginEmail" />
|
||||||
<img src="~/assets/images/phone-v2.png" alt="手机登录" class="social-icon" @click="handleLoginPhone" />
|
<img src="~/assets/images/phone-v2.png" alt="手机登录" class="social-icon" @click="handleLoginPhone" />
|
||||||
</div>
|
</div>
|
||||||
@ -73,6 +73,9 @@
|
|||||||
<img src="~/assets/images/sign.png" alt="签到奖励" class="bonus-image" />
|
<img src="~/assets/images/sign.png" alt="签到奖励" class="bonus-image" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- wx二维码弹窗 -->
|
||||||
|
<wx v-model:visible="visible" v-model:qrcode="qrcode" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -80,7 +83,7 @@
|
|||||||
import { getCurrentInstance, computed, watchEffect, ref } from 'vue'
|
import { getCurrentInstance, computed, watchEffect, ref } from 'vue'
|
||||||
import { handleLoginQQ, handleLoginWechat } from '~/utils/login'
|
import { handleLoginQQ, handleLoginWechat } from '~/utils/login'
|
||||||
import type { UserStatisticsCountRespVO } from '~/api/personal-center/types'
|
import type { UserStatisticsCountRespVO } from '~/api/personal-center/types'
|
||||||
import { getUserStatistics } from '~/api/personal-center/index'
|
import { getUserStatistics, getLoginQrcode } from '~/api/personal-center/index'
|
||||||
import useUserStore from '~/stores/user'
|
import useUserStore from '~/stores/user'
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const app = useNuxtApp()
|
const app = useNuxtApp()
|
||||||
@ -90,6 +93,18 @@
|
|||||||
return !!userStore.token
|
return !!userStore.token
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 打开微信二维码
|
||||||
|
const qrcode = ref<string>()
|
||||||
|
const visible = ref<boolean>(false)
|
||||||
|
const handleLoginWechatV2 = () => {
|
||||||
|
getLoginQrcode().then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
visible.value = true
|
||||||
|
qrcode.value = res.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 获取用户统计信息
|
// 获取用户统计信息
|
||||||
const userStaticInfo = ref<UserStatisticsCountRespVO>()
|
const userStaticInfo = ref<UserStatisticsCountRespVO>()
|
||||||
const fetchUserStatistics = async () => {
|
const fetchUserStatistics = async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user