feat: tenant-scoped routing and portal navigation

This commit is contained in:
2026-01-08 21:30:46 +08:00
parent f3aa92078a
commit 3e095c57f3
52 changed files with 1111 additions and 670 deletions

View File

@@ -1,8 +1,12 @@
<script setup>
import { onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import { contentApi } from '../../api/content';
import { tenantApi } from '../../api/tenant';
import { tenantPath } from '../../utils/tenant';
const route = useRoute();
const tenantRoute = (path) => tenantPath(path, route);
const contents = ref([]);
const bannerItems = ref([]);
const trendingItems = ref([]);
@@ -97,7 +101,7 @@ onMounted(fetchData);
<div class="absolute bottom-0 left-0 p-10 max-w-2xl text-white">
<div class="inline-block px-3 py-1 bg-red-600 text-white text-xs font-bold rounded mb-3">置顶推荐</div>
<h2 class="text-4xl font-bold mb-4 leading-tight cursor-pointer hover:underline"
@click="$router.push(`/contents/${item.id}`)">{{ item.title }}</h2>
@click="$router.push(tenantRoute(`/contents/${item.id}`))">{{ item.title }}</h2>
<p class="text-lg text-slate-200 line-clamp-2">{{ item.description || item.title }}</p>
</div>
</div>
@@ -167,7 +171,7 @@ onMounted(fetchData);
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div 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(`/creators/${creator.id}`)">
@click="$router.push(tenantRoute(`/t/${creator.id}`))">
<img :src="creator.avatar || `https://api.dicebear.com/7.x/avataaars/svg?seed=${creator.id}`"
class="w-12 h-12 rounded-full border border-slate-100">
<div class="flex-1 min-w-0">
@@ -178,7 +182,7 @@ onMounted(fetchData);
</div>
</div>
<router-link v-for="item in contents" :key="item.id" :to="`/contents/${item.id}`"
<router-link v-for="item in contents" :key="item.id" :to="tenantRoute(`/contents/${item.id}`)"
class="block bg-white rounded-2xl shadow-sm border border-slate-100 p-6 hover:shadow-xl hover:border-primary-100 transition-all duration-300 group cursor-pointer active:scale-[0.99]">
<div class="flex gap-8">
<div class="flex-1 min-w-0 flex flex-col">
@@ -254,10 +258,10 @@ onMounted(fetchData);
<div class="space-y-4">
<div v-for="creator in recommendedCreators" :key="creator.id" class="flex items-center gap-3">
<img :src="creator.avatar || `https://api.dicebear.com/7.x/avataaars/svg?seed=${creator.id}`"
class="w-10 h-10 rounded-full cursor-pointer" @click="$router.push(`/creators/${creator.id}`)">
class="w-10 h-10 rounded-full cursor-pointer" @click="$router.push(tenantRoute(`/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(`/creators/${creator.id}`)">{{ creator.name }}</div>
@click="$router.push(tenantRoute(`/t/${creator.id}`))">{{ creator.name }}</div>
<div class="text-xs text-slate-500 truncate">粉丝 {{ creator.stats?.followers || 0 }}</div>
</div>
<button
@@ -278,7 +282,7 @@ onMounted(fetchData);
:class="index === 0 ? 'text-red-500' : (index === 1 ? 'text-orange-500' : 'text-yellow-500')">{{
index + 1 }}</span>
<div class="flex-1">
<h4 @click="$router.push(`/contents/${item.id}`)"
<h4 @click="$router.push(tenantRoute(`/contents/${item.id}`))"
class="text-sm font-medium text-slate-800 line-clamp-2 hover:text-primary-600 cursor-pointer">
{{ item.title }}</h4>
<span class="text-xs text-slate-400 mt-1 block">{{ item.views }} 阅读</span>
@@ -301,4 +305,3 @@ onMounted(fetchData);
</div>
</div>
</div>