feat: switch to global auth and tenant route prefix

This commit is contained in:
2026-01-26 18:04:05 +08:00
parent 8addf6f900
commit cde4fb8594
25 changed files with 479 additions and 7196 deletions

View File

@@ -1,6 +1,6 @@
<script setup>
import { ref, onMounted, watch } from "vue";
import { useRouter, useRoute } from "vue-router";
import { ref, onMounted } from "vue";
import { useRoute, useRouter } from "vue-router";
import { tenantPath } from "../utils/tenant";
const isLoggedIn = ref(false);
@@ -28,13 +28,6 @@ onMounted(() => {
checkAuth();
});
// Watch route changes to refresh auth state (e.g. after login redirect)
watch(
() => route.path,
() => {
checkAuth();
},
);
const logout = () => {
localStorage.removeItem("token");
@@ -102,10 +95,10 @@ const logout = () => {
<div class="flex items-center gap-4">
<template v-if="isLoggedIn">
<!-- Notification -->
<router-link
:to="tenantRoute('/me/notifications')"
class="relative w-10 h-10 flex items-center justify-center rounded-full hover:bg-slate-50 text-slate-600"
>
<router-link
:to="tenantRoute('/me/notifications')"
class="relative w-10 h-10 flex items-center justify-center rounded-full hover:bg-slate-50 text-slate-600"
>
<i class="pi pi-bell text-xl"></i>
<span
class="absolute top-2 right-2 w-2 h-2 bg-red-500 rounded-full border border-white"
@@ -113,10 +106,10 @@ const logout = () => {
</router-link>
<!-- Creator Entry -->
<router-link
:to="tenantRoute('/creator/apply')"
class="hidden sm:flex items-center gap-1 px-3 py-1.5 text-sm font-medium text-slate-600 hover:bg-slate-50 rounded-lg border border-slate-200"
>
<router-link
:to="tenantRoute('/creator/apply')"
class="hidden sm:flex items-center gap-1 px-3 py-1.5 text-sm font-medium text-slate-600 hover:bg-slate-50 rounded-lg border border-slate-200"
>
<i class="pi pi-pencil"></i>
<span>创作</span>
</router-link>
@@ -150,16 +143,16 @@ const logout = () => {
{{ user.phone }}
</p>
</div>
<router-link
:to="tenantRoute('/me')"
class="block px-4 py-2 text-sm text-slate-700 hover:bg-slate-50"
>个人中心</router-link
>
<router-link
:to="tenantRoute('/creator')"
class="block px-4 py-2 text-sm text-slate-700 hover:bg-slate-50"
>创作者中心</router-link
>
<router-link
:to="tenantRoute('/me')"
class="block px-4 py-2 text-sm text-slate-700 hover:bg-slate-50"
>个人中心</router-link
>
<router-link
:to="tenantRoute('/creator')"
class="block px-4 py-2 text-sm text-slate-700 hover:bg-slate-50"
>创作者中心</router-link
>
<div class="border-t border-slate-50 mt-1"></div>
<button
@click="logout"
@@ -173,11 +166,11 @@ const logout = () => {
</template>
<template v-else>
<router-link
:to="tenantRoute('/auth/login')"
class="bg-primary-600 text-white px-6 py-2 rounded-full font-medium hover:bg-primary-700 transition-all shadow-sm shadow-primary-100 active:scale-95"
>登录 / 注册</router-link
>
<router-link
:to="'/auth/login'"
class="bg-primary-600 text-white px-6 py-2 rounded-full font-medium hover:bg-primary-700 transition-all shadow-sm shadow-primary-100 active:scale-95"
>登录 / 注册</router-link
>
</template>
<!-- Mobile Menu Button -->

View File

@@ -21,11 +21,6 @@ const router = createRouter({
name: "content-detail",
component: () => import("../views/content/DetailView.vue"),
},
{
path: "t/:id",
name: "tenant-home",
component: () => import("../views/tenant/HomeView.vue"),
},
{
path: "explore",
name: "explore",
@@ -49,7 +44,7 @@ const router = createRouter({
],
},
{
path: "/t/:tenantCode/auth",
path: "/auth",
component: LayoutAuth,
children: [
{

View File

@@ -3,10 +3,12 @@ import { getTenantCode } from "./tenant";
export async function request(endpoint, options = {}) {
const tenantCode = getTenantCode();
if (!tenantCode) {
const isAuthRequest = endpoint.startsWith("/auth/");
const baseUrl = isAuthRequest ? "/v1" : tenantCode ? `/v1/t/${tenantCode}` : "/v1";
if (!tenantCode && !isAuthRequest && !endpoint.startsWith("/tenants")) {
throw new Error("Tenant code missing in URL");
}
const baseUrl = `/t/${tenantCode}/v1`;
const token = localStorage.getItem("token");
const headers = {
@@ -45,7 +47,7 @@ export async function request(endpoint, options = {}) {
if (res.status === 401) {
localStorage.removeItem("token");
localStorage.removeItem("user");
const loginPath = `/t/${tenantCode}/auth/login`;
const loginPath = tenantCode ? `/t/${tenantCode}/auth/login` : "/auth/login";
// Redirect to login if not already there
if (!window.location.pathname.includes("/auth/login")) {
window.location.href = loginPath;

View File

@@ -248,7 +248,7 @@ onMounted(fetchData);
v-for="creator in matchedCreators"
:key="creator.id"
class="flex items-center gap-3 p-3 rounded-xl hover:bg-slate-50 transition-colors cursor-pointer border border-transparent hover:border-slate-200"
@click="$router.push(tenantRoute(`/t/${creator.id}`))"
@click="$router.push(`/t/${creator.id}`)"
>
<img
:src="
@@ -397,12 +397,12 @@ onMounted(fetchData);
`https://api.dicebear.com/7.x/avataaars/svg?seed=${creator.id}`
"
class="w-10 h-10 rounded-full cursor-pointer"
@click="$router.push(tenantRoute(`/t/${creator.id}`))"
@click="$router.push(`/t/${creator.id}`)"
/>
<div class="flex-1 min-w-0">
<div
class="font-bold text-slate-900 text-sm truncate hover:text-primary-600 cursor-pointer"
@click="$router.push(tenantRoute(`/t/${creator.id}`))"
@click="$router.push(`/t/${creator.id}`)"
>
{{ creator.name }}
</div>

View File

@@ -47,7 +47,9 @@ const login = async () => {
life: 1000,
});
setTimeout(() => {
router.push(tenantPath("/", route));
const fallback = tenantPath("/", route);
const target = route.query?.redirect || fallback;
router.push(target);
}, 1000);
} catch (e) {
toast.add({