Files
zacfrontuser_v2/src/App.vue
2026-02-14 12:25:55 +08:00

336 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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";
import WechatOverlay from "@/components/WechatOverlay.vue";
import { useSEO } from "@/composables/useSEO";
const { updateSEOByRoute } = useSEO();
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();
updateSEOByRoute();
// 延迟配置微信分享
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");
// // 使用配置的固定域名,如果没有配置则使用当前域名
// const redirectDomain = import.meta.env.VITE_WECHAT_REDIRECT_DOMAIN || url.origin;
// const cleanUrl = `${redirectDomain}${url.pathname}${params.toString() ? "?" + params.toString() : ""
// }`;
// const redirectUri = encodeURIComponent(cleanUrl);
// console.log("🔗 WeChat redirectUri config:", {
// configuredDomain: import.meta.env.VITE_WECHAT_REDIRECT_DOMAIN || "未配置(使用当前域名)",
// currentOrigin: url.origin,
// finalRedirectDomain: redirectDomain,
// redirectUri: cleanUrl
// });
// 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 />
<WechatOverlay />
<BindPhoneOnlyDialog />
</template>
<style scoped></style>