feat: implement WeChat MP OAuth login
- Add wechat-mp.service.ts for MP web authorization - Add wechat-mp.routes.ts with /api/mp endpoints - Update EntryQRCode.vue to show H5 URL QR code - Update HomeView.vue with WeChat auth detection Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,16 +1,120 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { showLoadingToast, closeToast, showToast } from 'vant';
|
||||
import { useConnectionStore } from '../stores/connection';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const connectionStore = useConnectionStore();
|
||||
|
||||
// Check if already logged in
|
||||
onMounted(() => {
|
||||
const isProcessing = ref(false);
|
||||
|
||||
// API base URL
|
||||
const apiUrl = import.meta.env.VITE_API_URL || 'http://192.168.1.5:3000';
|
||||
|
||||
/**
|
||||
* 检测是否在微信环境中
|
||||
*/
|
||||
function isWechatBrowser(): boolean {
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
return ua.includes('micromessenger');
|
||||
}
|
||||
|
||||
/**
|
||||
* 用code完成登录
|
||||
*/
|
||||
async function loginWithCode(code: string) {
|
||||
isProcessing.value = true;
|
||||
showLoadingToast({ message: '登录中...', forbidClick: true });
|
||||
|
||||
try {
|
||||
const response = await fetch(`${apiUrl}/api/mp/login`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ code }),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
closeToast();
|
||||
|
||||
if (result.success && result.data) {
|
||||
// 设置用户信息
|
||||
connectionStore.setUser(
|
||||
result.data.userId,
|
||||
result.data.userName,
|
||||
result.data.sessionToken
|
||||
);
|
||||
|
||||
showToast({ message: '登录成功!', type: 'success' });
|
||||
|
||||
// 跳转到投票页面
|
||||
router.replace('/vote');
|
||||
} else {
|
||||
showToast({ message: result.error || '登录失败', type: 'fail' });
|
||||
isProcessing.value = false;
|
||||
}
|
||||
} catch (err) {
|
||||
closeToast();
|
||||
showToast({ message: '网络错误,请重试', type: 'fail' });
|
||||
isProcessing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到微信授权页面
|
||||
*/
|
||||
async function redirectToWechatAuth() {
|
||||
try {
|
||||
// 获取授权URL
|
||||
const currentUrl = window.location.href.split('?')[0]; // 移除已有的query参数
|
||||
const response = await fetch(
|
||||
`${apiUrl}/api/mp/auth-url?redirect_uri=${encodeURIComponent(currentUrl)}&scope=snsapi_base`
|
||||
);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success && result.data?.authUrl) {
|
||||
// 跳转到微信授权页面
|
||||
window.location.href = result.data.authUrl;
|
||||
} else {
|
||||
console.error('[HomeView] Failed to get auth URL:', result.error);
|
||||
showToast({ message: '获取授权链接失败', type: 'fail' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[HomeView] Failed to redirect to auth:', err);
|
||||
showToast({ message: '网络错误', type: 'fail' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理微信授权流程
|
||||
*/
|
||||
async function handleWechatAuth() {
|
||||
// 检查URL中是否有code参数(授权回调)
|
||||
const code = route.query.code as string;
|
||||
|
||||
if (code) {
|
||||
// 有code,用code完成登录
|
||||
console.log('[HomeView] Got code from callback, logging in...');
|
||||
await loginWithCode(code);
|
||||
} else {
|
||||
// 无code,跳转到授权页面
|
||||
console.log('[HomeView] No code, redirecting to auth...');
|
||||
await redirectToWechatAuth();
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时检查登录状态和微信环境
|
||||
onMounted(async () => {
|
||||
// 已登录则直接跳转
|
||||
if (connectionStore.userId && connectionStore.userName && connectionStore.userName !== '访客') {
|
||||
// Already logged in, redirect to vote page
|
||||
router.replace('/vote');
|
||||
return;
|
||||
}
|
||||
|
||||
// 在微信环境中自动处理授权
|
||||
if (isWechatBrowser()) {
|
||||
await handleWechatAuth();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user