feat: expand portal entry flows and dynamic recommendation routing
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { ref, onMounted } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { tenantPath } from "../utils/tenant";
|
||||
import { contentApi } from "../api/content";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const tenantRoute = (path) => tenantPath(path, route);
|
||||
const topics = ref([
|
||||
|
||||
const STATIC_TOPICS = [
|
||||
{
|
||||
id: 1,
|
||||
title: "程派艺术赏析:幽咽婉转后的风骨",
|
||||
@@ -56,7 +59,59 @@ const topics = ref([
|
||||
date: "2024-12-05",
|
||||
count: 15,
|
||||
},
|
||||
]);
|
||||
];
|
||||
|
||||
const topics = ref([...STATIC_TOPICS]);
|
||||
|
||||
const KNOWN_GENRES = [
|
||||
"京剧",
|
||||
"昆曲",
|
||||
"越剧",
|
||||
"黄梅戏",
|
||||
"豫剧",
|
||||
"评剧",
|
||||
"秦腔",
|
||||
"河北梆子",
|
||||
];
|
||||
|
||||
const findGenre = (topic) => {
|
||||
const text = (topic.title + topic.tag).toLowerCase();
|
||||
return KNOWN_GENRES.find((g) => text.includes(g));
|
||||
};
|
||||
|
||||
const navigateToTopic = (topic) => {
|
||||
const genre = findGenre(topic);
|
||||
const target = tenantRoute("/explore");
|
||||
|
||||
if (genre) {
|
||||
router.push({ path: target, query: { genre } });
|
||||
} else {
|
||||
// Fallback: navigate to explore without specific genre if no match found
|
||||
router.push(target);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const res = await contentApi.listTopics();
|
||||
if (res && Array.isArray(res) && res.length > 0) {
|
||||
topics.value = res.map((item, index) => ({
|
||||
id: item.id || index + 100, // Safe ID
|
||||
title: item.title || "未命名专题",
|
||||
desc: item.desc || `探索${item.title || "精彩内容"}的更多详情。`,
|
||||
cover:
|
||||
item.cover ||
|
||||
"https://images.unsplash.com/photo-1514306191717-452ec28c7f31?auto=format&fit=crop&w=800",
|
||||
tag: item.tag || "精选",
|
||||
date: item.date || new Date().toISOString().split("T")[0],
|
||||
count: item.count || 0,
|
||||
}));
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("Failed to load topics, using fallback:", err);
|
||||
// Keep STATIC_TOPICS
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -68,8 +123,9 @@ const topics = ref([
|
||||
|
||||
<!-- 1. Hero Topic -->
|
||||
<div
|
||||
v-if="topics.length > 0"
|
||||
class="relative w-full h-[400px] rounded-2xl overflow-hidden mb-12 group cursor-pointer shadow-lg"
|
||||
@click="$router.push(tenantRoute(`/explore?topic=${topics[0].id}`))"
|
||||
@click="navigateToTopic(topics[0])"
|
||||
>
|
||||
<img
|
||||
:src="topics[0].cover"
|
||||
@@ -112,13 +168,16 @@ const topics = ref([
|
||||
</div>
|
||||
|
||||
<!-- 2. Masonry-like Grid -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
<div
|
||||
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
|
||||
v-if="topics.length > 1"
|
||||
>
|
||||
<div
|
||||
v-for="(topic, idx) in topics.slice(1)"
|
||||
:key="topic.id"
|
||||
class="group bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden hover:shadow-xl transition-all cursor-pointer flex flex-col"
|
||||
:class="{ 'lg:col-span-2 flex-row': idx === 0 }"
|
||||
@click="$router.push(tenantRoute(`/explore?topic=${topic.id}`))"
|
||||
@click="navigateToTopic(topic)"
|
||||
>
|
||||
<!-- Cover -->
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user