Files
zacfrontuser_v2/src/App.vue

332 lines
12 KiB
Vue
Raw Normal View History

2026-01-15 18:03:13 +08:00
<script setup>
import { RouterView, useRouter, useRoute } from "vue-router";
const { isWeChat } = useEnv();
import { useAgentStore } from "@/stores/agentStore";
import { useUserStore } from "@/stores/userStore";
import { useDialogStore } from "@/stores/dialogStore";
import { useAuthStore } from "@/stores/authStore";
import { useAppStore } from "@/stores/appStore";
import { useWeixinShare } from "@/composables/useWeixinShare";
import BindPhoneDialog from "@/components/BindPhoneDialog.vue";
import BindPhoneOnlyDialog from "@/components/BindPhoneOnlyDialog.vue";
const router = useRouter();
const route = useRoute();
const agentStore = useAgentStore();
const userStore = useUserStore();
const dialogStore = useDialogStore();
const authStore = useAuthStore();
const appStore = useAppStore();
const { setDynamicShare } = useWeixinShare();
onMounted(async () => {
// 初始化应用配置
await appStore.fetchAppConfig();
// 恢复微信授权状态(页面刷新或回调时)
authStore.restoreFromStorage();
// 检查是否是微信授权回调
const url = new URL(window.location.href);
const code = url.searchParams.get("code");
const state = url.searchParams.get("state");
if (code && state) {
// 这是微信授权回调,处理授权结果
console.log("Handling WeChat auth callback");
await handleWeixinAuthCallback(code);
} else {
// 正常初始化:加载用户信息等
await initializeApp();
}
getWeixinAuthUrl();
// 延迟配置微信分享
setTimeout(async () => {
if (isWeChat.value && window.jWeixin) {
await setDynamicShare();
}
}, 1000);
// 监听路由变化更新分享配置
router.afterEach(async () => {
if (isWeChat.value && window.jWeixin && !authStore.isWeixinAuthing) {
await setDynamicShare();
}
});
});
/**
* 处理微信授权回调
*/
const handleWeixinAuthCallback = async (code) => {
try {
console.log("🔄 WeChat auth callback: code=", code);
// 调用后端接口交换 token
const { data, error } = await useApiFetch("/user/wxh5Auth")
.post({ code })
.json();
console.log("📡 wxh5Auth response:", {
code: data.value?.code,
hasToken: !!data.value?.data?.accessToken,
error: error.value
});
if (data.value && !error.value && data.value.code === 200) {
// 保存 token
const token = data.value.data.accessToken;
localStorage.setItem("token", token);
localStorage.setItem("refreshAfter", data.value.data.refreshAfter);
localStorage.setItem("accessExpire", data.value.data.accessExpire);
// ⚠️ 重要:保存 token 后立即设置 tokenVersion防止被 checkTokenVersion 清除
const tokenVersion = import.meta.env.VITE_TOKEN_VERSION || "1.1";
localStorage.setItem("tokenVersion", tokenVersion);
console.log("✅ Token saved successfully, token:", token.substring(0, 20) + "...");
console.log("✅ Token saved to localStorage, userId:", data.value.data.userId || "unknown");
console.log(`✅ TokenVersion set to ${tokenVersion}`);
// 验证 token 是否真的保存成功
const savedToken = localStorage.getItem("token");
if (savedToken === token) {
console.log("✅ Token verification: localStorage中的token与保存的token一致");
} else {
console.error("❌ Token verification failed: localStorage中的token与保存的token不一致");
}
// 清除 URL 中的 code 和 state 参数
const url = new URL(window.location.href);
const params = new URLSearchParams(url.search);
params.delete("code");
params.delete("state");
const newUrl = `${url.origin}${url.pathname}${params.toString() ? "?" + params.toString() : ""}`;
window.history.replaceState({}, "", newUrl);
console.log("✅ URL cleaned, removed code and state parameters");
// 获取用户信息
console.log("👤 Fetching user info...");
try {
await userStore.fetchUserInfo();
console.log("✅ User info fetched:", {
mobile: userStore.mobile,
isLoggedIn: userStore.isLoggedIn
});
} catch (userInfoErr) {
console.error("❌ Failed to fetch user info:", userInfoErr);
// 用户信息获取失败,清除 token跳转到登录
authStore.resetAuthState();
await router.replace("/login");
return;
}
// 获取代理信息(已登录用户都尝试获取,后端会判断是否是代理)
try {
await agentStore.fetchAgentStatus();
} catch (agentErr) {
console.warn("Warning: Failed to fetch agent status:", agentErr);
// 不中断流程,只是警告
}
// 标记授权完成
authStore.completeWeixinAuth();
console.log("✅ WeChat auth marked as complete");
// 获取 pendingRoute 并跳转
const pendingRoute = authStore.pendingRoute
console.log("🎯 pendingRoute:", pendingRoute);
// if (pendingRoute) {
// // ⚠️ 重要:必须先跳转再清除,否则清除后 pendingRoute 为 null
// console.log("🚀 Navigating to pendingRoute:", pendingRoute);
// await router.replace(pendingRoute);
// authStore.clearPendingRoute();
// console.log("✅ Navigated to pendingRoute and cleared it");
// } else {
// // 默认跳转到首页
// console.log("📍 No pendingRoute found, navigating to home");
// await router.replace("/");
// }
} else {
console.error("❌ WeChat auth failed:", {
code: data.value?.code,
message: data.value?.msg || data.value?.message,
error: error.value
});
// 授权失败,重置状态
authStore.resetAuthState();
// 跳转到登录页
await router.replace("/login");
}
} catch (err) {
console.error("❌ Error handling WeChat auth callback:", err);
authStore.resetAuthState();
await router.replace("/login");
}
};
/**
* 初始化应用检查 token加载用户信息
*/
const initializeApp = async () => {
// 检查 token 版本
checkTokenVersion();
// 尝试刷新 token
await refreshTokenIfNeeded();
// 如果有 token加载用户信息和代理信息
const token = localStorage.getItem("token");
if (token) {
try {
await userStore.fetchUserInfo();
// 已登录用户都尝试获取代理信息,后端会判断是否是代理
await agentStore.fetchAgentStatus();
} catch (err) {
console.error("Error loading user info:", err);
}
}
};
/**
* 检查 token 版本清除不兼容的旧 token
* 注意只有在确实需要清除旧 token 时才清除避免误清除新保存的 token
*/
const checkTokenVersion = () => {
const CURRENT_TOKEN_VERSION = import.meta.env.VITE_TOKEN_VERSION || "1.1";
const storedVersion = localStorage.getItem("tokenVersion");
const hasToken = !!localStorage.getItem("token");
// 如果 tokenVersion 不存在或版本不匹配
if (!storedVersion || storedVersion !== CURRENT_TOKEN_VERSION) {
// 只有在有 token 的情况下才清除(避免清除刚保存的新 token
if (hasToken) {
console.log(`Token version mismatch: storedVersion=${storedVersion}, currentVersion=${CURRENT_TOKEN_VERSION}, clearing old auth data`);
// Token 版本不匹配,清除旧数据
localStorage.removeItem("token");
localStorage.removeItem("refreshAfter");
localStorage.removeItem("accessExpire");
localStorage.removeItem("userInfo");
localStorage.removeItem("agentInfo");
}
// 无论是否有 token都设置新的 tokenVersion
localStorage.setItem("tokenVersion", CURRENT_TOKEN_VERSION);
} else {
console.log(`Token version check passed: storedVersion=${storedVersion}, currentVersion=${CURRENT_TOKEN_VERSION}`);
}
};
/**
* 在需要时刷新 token
*/
const refreshTokenIfNeeded = async () => {
const token = localStorage.getItem("token");
if (!token) return;
const accessExpire = localStorage.getItem("accessExpire");
const refreshAfter = localStorage.getItem("refreshAfter");
const now = Date.now();
// 检查 token 是否已过期
if (accessExpire) {
const expireTime = parseInt(accessExpire) * 1000;
if (now > expireTime) {
console.log("Token expired");
return; // Token 已过期,不刷新,由路由守卫处理
}
}
// 检查是否需要刷新
if (refreshAfter) {
const refreshTime = parseInt(refreshAfter) * 1000;
if (now < refreshTime) {
return; // 还不需要刷新
}
}
// 执行 token 刷新
try {
const { data, error } = await useApiFetch("/user/getToken").post().json();
if (data.value && !error.value && data.value.code === 200) {
localStorage.setItem("token", data.value.data.accessToken);
localStorage.setItem("refreshAfter", data.value.data.refreshAfter);
localStorage.setItem("accessExpire", data.value.data.accessExpire);
console.log("Token refreshed successfully");
}
} catch (err) {
console.error("Error refreshing token:", err);
}
};
/**
* 发起微信授权 URL
* 这个逻辑已经在路由守卫中实现了
* 这里保留这个函数的备份以防需要其他地方调用
*/
const getWeixinAuthUrl = () => {
const isAuthenticated = localStorage.getItem("token");
// 检查 token 是否过期
const accessExpire = localStorage.getItem("accessExpire");
const now = Date.now();
let isTokenExpired = false;
if (accessExpire) {
isTokenExpired = now > parseInt(accessExpire) * 1000;
}
console.log("WeChat auth check:", {
isWeChat: isWeChat.value,
isAuthenticated,
isTokenExpired
});
if (isWeChat.value && !isAuthenticated && !isTokenExpired) {
console.log("🔄 Initiating WeChat auth flow");
// 如果正在授权中或已完成授权,则阻止重复授权
console.log("Auth store state:", {
isWeixinAuthing: authStore.isWeixinAuthing,
weixinAuthComplete: authStore.weixinAuthComplete
});
if (authStore.isWeixinAuthing || authStore.weixinAuthComplete) {
return;
}
// 保存目标路由
authStore.startWeixinAuth(route);
console.log("🔖 Saved pendingRoute for WeChat auth:", route.fullPath);
const appId = import.meta.env.VITE_WECHAT_APP_ID;
const url = new URL(window.location.href);
const params = new URLSearchParams(url.search);
params.delete("code");
params.delete("state");
2026-01-16 16:33:03 +08:00
// 使用配置的固定域名,如果没有配置则使用当前域名
const redirectDomain = import.meta.env.VITE_WECHAT_REDIRECT_DOMAIN || url.origin;
const cleanUrl = `${redirectDomain}${url.pathname}${params.toString() ? "?" + params.toString() : ""
2026-01-15 18:03:13 +08:00
}`;
const redirectUri = encodeURIComponent(cleanUrl);
2026-01-16 16:33:03 +08:00
console.log("🔗 WeChat redirectUri config:", {
configuredDomain: import.meta.env.VITE_WECHAT_REDIRECT_DOMAIN || "未配置(使用当前域名)",
currentOrigin: url.origin,
finalRedirectDomain: redirectDomain,
redirectUri: cleanUrl
});
2026-01-15 18:03:13 +08:00
const weixinAuthUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_base&state=snsapi_base#wechat_redirect`;
console.log(
"🔄 Triggering WeChat auth from route guard, pendingRoute:",
route.fullPath
);
window.location.href = weixinAuthUrl;
}
};
</script>
<template>
<RouterView />
<BindPhoneDialog />
<BindPhoneOnlyDialog />
</template>
<style scoped></style>