fix(@vben/web-antd): 重构企业微信绑定回调走核心路由
绑定回调从 /profile(动态路由)改为 /auth/social-login(核心路由), 解决页面刷新时动态路由未注册导致回调参数丢失的问题。 social-login.vue 通过 sessionStorage 区分绑定和登录操作, 绑定完成后自动跳转回个人中心。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,12 +12,15 @@ import { $t } from '@vben/locales';
|
||||
import { useAccessStore } from '@vben/stores';
|
||||
import { getUrlValue } from '@vben/utils';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import {
|
||||
checkCaptcha,
|
||||
getCaptcha,
|
||||
getTenantByWebsite,
|
||||
getTenantSimpleList,
|
||||
} from '#/api/core/auth';
|
||||
import { socialBind } from '#/api/system/social/user';
|
||||
import { useAuthStore } from '#/store';
|
||||
|
||||
defineOptions({ name: 'SocialLogin' });
|
||||
@@ -69,11 +72,35 @@ async function fetchTenantList() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 尝试登录:当账号已经绑定,socialLogin 会直接获得 token */
|
||||
/** 尝试登录或绑定 */
|
||||
const socialType = Number(getUrlValue('type'));
|
||||
const redirect = getUrlValue('redirect');
|
||||
const socialCode = query?.code as string;
|
||||
const socialState = query?.state as string;
|
||||
|
||||
// 检查是否为绑定操作(从个人中心发起)
|
||||
const bindAction = sessionStorage.getItem('socialBindAction');
|
||||
const bindType = sessionStorage.getItem('socialBindType');
|
||||
|
||||
async function tryBind() {
|
||||
const type = Number(bindType);
|
||||
sessionStorage.removeItem('socialBindAction');
|
||||
sessionStorage.removeItem('socialBindType');
|
||||
if (!type || !socialCode) {
|
||||
message.error('绑定失败:缺少参数');
|
||||
await router.replace('/profile');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await socialBind({ type, code: socialCode, state: socialState });
|
||||
message.success('绑定成功');
|
||||
} catch (error) {
|
||||
console.error('社交绑定失败:', error);
|
||||
message.error('绑定失败,请重试');
|
||||
}
|
||||
await router.replace('/profile');
|
||||
}
|
||||
|
||||
async function tryLogin() {
|
||||
// 用于登录后,基于 redirect 的重定向
|
||||
if (redirect) {
|
||||
@@ -125,10 +152,13 @@ async function handleVerifySuccess({ captchaVerification }: any) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 组件挂载时获取租户信息 */
|
||||
/** 组件挂载时:绑定操作走绑定流程,否则走登录流程 */
|
||||
onMounted(async () => {
|
||||
if (bindAction === 'bind') {
|
||||
await tryBind();
|
||||
return;
|
||||
}
|
||||
await fetchTenantList();
|
||||
|
||||
await tryLogin();
|
||||
});
|
||||
|
||||
|
||||
@@ -2,29 +2,21 @@
|
||||
import type { SystemSocialUserApi } from '#/api/system/social/user';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { confirm } from '@vben/common-ui';
|
||||
import { DICT_TYPE, SystemUserSocialTypeEnum } from '@vben/constants';
|
||||
import { getDictLabel } from '@vben/hooks';
|
||||
import { $t } from '@vben/locales';
|
||||
import { formatDateTime, getUrlValue } from '@vben/utils';
|
||||
import { formatDateTime } from '@vben/utils';
|
||||
|
||||
import { Avatar, Button, Image, message, Tag, Tooltip } from 'ant-design-vue';
|
||||
|
||||
import { socialAuthRedirect } from '#/api/core/auth';
|
||||
import {
|
||||
getBindSocialUserList,
|
||||
socialBind,
|
||||
socialUnbind,
|
||||
} from '#/api/system/social/user';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:activeName', v: string): void;
|
||||
}>();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
/** 已经绑定的平台 */
|
||||
const bindList = ref<SystemSocialUserApi.SocialUser[]>([]);
|
||||
|
||||
@@ -77,47 +69,19 @@ async function onBind(bind: SocialBindItem) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 将 type 存入 sessionStorage,避免放入 redirect_uri 导致参数被截断
|
||||
// 标记为绑定操作,回调走 /auth/social-login(核心路由,始终可用)
|
||||
sessionStorage.setItem('socialBindType', String(type));
|
||||
const redirectUri = `${location.origin}/profile`;
|
||||
sessionStorage.setItem('socialBindAction', 'bind');
|
||||
const redirectUri = `${location.origin}/auth/social-login`;
|
||||
window.location.href = await socialAuthRedirect(type, redirectUri);
|
||||
} catch (error) {
|
||||
console.error('社交绑定处理失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/** 监听路由变化,处理社交绑定回调 */
|
||||
async function bindSocial() {
|
||||
const code = route.query.code as string;
|
||||
const state = route.query.state as string;
|
||||
if (!code) {
|
||||
return;
|
||||
}
|
||||
// 优先从 sessionStorage 获取 type,兼容从 URL 参数获取
|
||||
const storedType = sessionStorage.getItem('socialBindType');
|
||||
const type = storedType ? Number(storedType) : Number(getUrlValue('type'));
|
||||
sessionStorage.removeItem('socialBindType');
|
||||
if (!type) {
|
||||
message.error('绑定失败:缺少社交平台类型');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await socialBind({ type, code, state });
|
||||
message.success('绑定成功');
|
||||
emit('update:activeName', 'userSocial');
|
||||
await loadBindList();
|
||||
} catch (error) {
|
||||
console.error('社交绑定失败:', error);
|
||||
message.error('绑定失败,请重试');
|
||||
} finally {
|
||||
window.history.replaceState({}, '', location.pathname);
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化 */
|
||||
onMounted(async () => {
|
||||
await loadBindList();
|
||||
await bindSocial();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user