feat:完成微信开放平台扫码登录

This commit is contained in:
cyonjan 2025-05-21 15:15:31 +08:00
parent 428be99b77
commit 46d3cb715b
2 changed files with 0 additions and 231 deletions

View File

@ -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>

View File

@ -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>