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