feat:完成微信开放平台扫码登录
This commit is contained in:
parent
428be99b77
commit
46d3cb715b
@ -1,43 +0,0 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
defineProps({
|
||||
msg: String,
|
||||
})
|
||||
|
||||
const count = ref(0)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>{{ msg }}</h1>
|
||||
|
||||
<div class="card">
|
||||
<button type="button" @click="count++">count is {{ count }}</button>
|
||||
<p>
|
||||
Edit
|
||||
<code>components/HelloWorld.vue</code> to test HMR
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Check out
|
||||
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
|
||||
>create-vue</a
|
||||
>, the official Vue + Vite starter
|
||||
</p>
|
||||
<p>
|
||||
Learn more about IDE Support for Vue in the
|
||||
<a
|
||||
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
|
||||
target="_blank"
|
||||
>Vue Docs Scaling up Guide</a
|
||||
>.
|
||||
</p>
|
||||
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
</style>
|
@ -1,188 +0,0 @@
|
||||
<template>
|
||||
<div class="wx-login-container">
|
||||
<div class="qrcode-container">
|
||||
<el-image
|
||||
v-loading="loading"
|
||||
:src="qrcodeUrl"
|
||||
fit="contain"
|
||||
class="qrcode-image"
|
||||
>
|
||||
<template #error>
|
||||
<div class="image-error">二维码加载失败</div>
|
||||
</template>
|
||||
</el-image>
|
||||
|
||||
<div class="status-message">
|
||||
<el-alert
|
||||
v-if="errorMessage"
|
||||
:title="errorMessage"
|
||||
type="error"
|
||||
show-icon
|
||||
:closable="false"
|
||||
/>
|
||||
<div v-else-if="!loading" class="scan-tip">
|
||||
请使用微信扫一扫登录
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-skeleton :rows="3" animated v-if="loading" />
|
||||
</div>
|
||||
|
||||
<div class="action-area">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
@click="refreshQrcode"
|
||||
:loading="refreshing"
|
||||
>
|
||||
刷新二维码
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import axios from 'axios'
|
||||
|
||||
const props = defineProps({
|
||||
// 微信公众号appid
|
||||
appid: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
// 微信公众号appsecret
|
||||
appsecret: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const loading = ref(true)
|
||||
const refreshing = ref(false)
|
||||
const qrcodeUrl = ref('')
|
||||
const errorMessage = ref('')
|
||||
let pollTimer = null
|
||||
let ticket = ref('')
|
||||
|
||||
// 获取微信接口访问令牌
|
||||
const getAccessToken = async () => {
|
||||
try {
|
||||
const response = await axios.get(`/api/wechat/token?appid=${props.appid}&secret=${props.appsecret}`)
|
||||
return response.data.access_token
|
||||
} catch (error) {
|
||||
throw new Error('获取访问令牌失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 生成临时二维码
|
||||
const generateQrcode = async (access_token) => {
|
||||
try {
|
||||
const response = await axios.post(`/api/wechat/qrcode/create?access_token=${access_token}`, {
|
||||
expire_seconds: 600,
|
||||
action_name: 'QR_STR_SCENE',
|
||||
action_info: {
|
||||
scene: {
|
||||
scene_str: 'login_' + Date.now()
|
||||
}
|
||||
}
|
||||
})
|
||||
return response.data
|
||||
} catch (error) {
|
||||
throw new Error('生成二维码失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 获取二维码
|
||||
const fetchQrcode = async () => {
|
||||
try {
|
||||
errorMessage.value = ''
|
||||
loading.value = true
|
||||
|
||||
// 获取访问令牌
|
||||
const access_token = await getAccessToken()
|
||||
|
||||
// 生成临时二维码
|
||||
const qrcodeData = await generateQrcode(access_token)
|
||||
ticket.value = qrcodeData.ticket
|
||||
qrcodeUrl.value = `https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=${qrcodeData.ticket}`
|
||||
|
||||
// 开始轮询检查扫码状态
|
||||
startPolling()
|
||||
} catch (error) {
|
||||
errorMessage.value = error.message || '二维码获取失败,请重试'
|
||||
} finally {
|
||||
loading.value = false
|
||||
refreshing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 开始轮询检查状态
|
||||
const startPolling = () => {
|
||||
clearInterval(pollTimer)
|
||||
pollTimer = setInterval(async () => {
|
||||
try {
|
||||
const response = await axios.get(`/api/wechat/scan/check?ticket=${ticket.value}`)
|
||||
const data = response.data
|
||||
|
||||
if (data.status === 'success') {
|
||||
clearInterval(pollTimer)
|
||||
emit('success', data)
|
||||
} else if (data.status === 'expired') {
|
||||
errorMessage.value = '二维码已过期,请刷新'
|
||||
clearInterval(pollTimer)
|
||||
}
|
||||
} catch (error) {
|
||||
errorMessage.value = '网络异常,请检查连接'
|
||||
clearInterval(pollTimer)
|
||||
}
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
// 刷新二维码
|
||||
const refreshQrcode = () => {
|
||||
refreshing.value = true
|
||||
fetchQrcode()
|
||||
}
|
||||
|
||||
onMounted(fetchQrcode)
|
||||
onBeforeUnmount(() => clearInterval(pollTimer))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.wx-login-container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.qrcode-container {
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.qrcode-image {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
|
||||
.scan-tip {
|
||||
color: #666;
|
||||
margin: 15px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.action-area {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.image-error {
|
||||
height: 300px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user