做统一认证登录

This commit is contained in:
hero920103 committed 2026-09-19 21:44:04 +08:00
1 parent 1a4471e34d
commit fa281363fb
78 files changed
+8127 -1442

No files matched your search

+97
View File
@@ -0,0 +1,97 @@
<template>
<div class="auth-callback">
<div class="box">
<div v-if="error" class="error">
<p class="title">登录失败</p>
<p class="msg">{{ error }}</p>
<button class="btn" @click="retry">重新登录</button>
</div>
<div v-else class="loading">
<div class="spinner"></div>
<p>正在完成登录,请稍候…</p>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue";
import { handleAuthorizeCallback, redirectToAuthorize } from "@/utils/authClient";
const error = ref("");
async function finish() {
// hash 路由:参数位于 location.hash 之后,这里统一从 URL 中取出
const raw = window.location.href;
const queryStr = raw.includes("?") ? raw.slice(raw.indexOf("?") + 1) : "";
const query = Object.fromEntries(new URLSearchParams(queryStr));
try {
await handleAuthorizeCallback(query);
// 登录成功:清掉 URL 上的 code/state,进入首页
window.location.href = "#/home";
window.location.reload();
} catch (e) {
error.value = e?.message || "登录失败";
}
}
function retry() {
redirectToAuthorize();
}
onMounted(finish);
</script>
<style scoped>
.auth-callback {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.box {
background: #fff;
border-radius: 12px;
padding: 40px 36px;
width: 360px;
text-align: center;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
}
.spinner {
width: 36px;
height: 36px;
margin: 0 auto 16px;
border: 3px solid #e4e7ee;
border-top-color: #667eea;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.title {
font-size: 16px;
font-weight: 600;
color: #cf1322;
margin-bottom: 8px;
}
.msg {
font-size: 13px;
color: #5a6072;
margin-bottom: 20px;
}
.btn {
height: 40px;
padding: 0 24px;
border: none;
border-radius: 8px;
cursor: pointer;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
font-size: 14px;
}
</style>
+4 -5
View File
@@ -196,17 +196,17 @@ const performLoginRequest = async () => {
if (res && res.code === 200) {
// 登录成功:处理"记住我"
// 安全:只记住账号与租户名,绝不明文存储密码
if (rememberMe.value) {
localStorage.setItem("loginAccount", account.value);
localStorage.setItem("loginTenantName", tenant_name.value);
localStorage.setItem("loginPassword", password.value);
localStorage.setItem("loginRememberMe", "true");
} else {
localStorage.removeItem("loginAccount");
localStorage.removeItem("loginTenantName");
localStorage.removeItem("loginPassword");
localStorage.setItem("loginRememberMe", "false");
}
localStorage.removeItem("loginPassword");
authStore.setLoginInfo({ ...res.data, tenant_name: tenant_name.value });
@@ -327,17 +327,17 @@ const startGeetest4 = async () => {
});
if (loginRes && loginRes.code === 200) {
// 安全:只记住账号与租户名,绝不明文存储密码
if (rememberMe.value) {
localStorage.setItem("loginAccount", account.value);
localStorage.setItem("loginTenantName", tenant_name.value);
localStorage.setItem("loginPassword", password.value);
localStorage.setItem("loginRememberMe", "true");
} else {
localStorage.removeItem("loginAccount");
localStorage.removeItem("loginTenantName");
localStorage.removeItem("loginPassword");
localStorage.setItem("loginRememberMe", "false");
}
localStorage.removeItem("loginPassword");
authStore.setLoginInfo({ ...loginRes.data, tenant_name: tenant_name.value });
const { useTabsStore } = await import("@/stores");
@@ -471,7 +471,6 @@ onMounted(async () => {
if (savedRemember === "true") {
tenant_name.value = localStorage.getItem("loginTenantName") || "";
account.value = localStorage.getItem("loginAccount") || "";
password.value = localStorage.getItem("loginPassword") || "";
rememberMe.value = true;
}