categories/page.tsx - 分类列表页
基本信息
| 属性 | 值 |
|---|---|
| 路径 | src/app/categories/page.tsx |
| 类型 | Next.js 页面组件 (Server Component) |
| 功能 | 显示所有提示词分类的层级列表 |
功能描述
展示平台的分类体系,包括一级分类及其子分类。每个分类显示提示词数量,登录用户可订阅/取消订阅分类。
导入依赖
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { unstable_cache } from "next/cache";
import { FolderOpen, ChevronRight } from "lucide-react";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import { SubscribeButton } from "@/components/categories/subscribe-button";
数据筛选
可见提示词条件
const visiblePromptFilter = {
isPrivate: false,
isUnlisted: false,
deletedAt: null,
};
缓存数据获取
getCategories()
使用 unstable_cache 缓存分类数据。
const getCategories = unstable_cache(
async () => { /* ... */ },
["categories-page"],
{ tags: ["categories"] }
);
缓存配置:
- 缓存键:
"categories-page" - 重新验证标签:
"categories"
数据查询流程
1. 查询所有一级分类(parentId: null)
└── 包含子分类(按 order 排序)
2. 获取所有分类 ID
3. 聚合查询各分类的可见提示词数量
4. 将数量附加到分类对象
组件逻辑
用户订阅状态
const subscriptions = session?.user
? await db.categorySubscription.findMany({
where: { userId: session.user.id },
select: { categoryId: true },
})
: [];
const subscribedIds = new Set(subscriptions.map((s) => s.categoryId));
UI 结构
Container
├── Header
│ ├── Title: "Categories"
│ └── Description
└── Categories List
└── Section (foreach category)
├── Category Header
│ ├── Icon
│ ├── Name (link)
│ ├── SubscribeButton (if logged in)
│ └── Prompt Count
├── Description (optional)
└── Subcategories (if any)
└── Item (foreach child)
├── Icon
├── Name (link)
├── SubscribeButton
└── Description
空状态
当没有分类时:
Centered Box
├── FolderOpen icon
└── "No categories yet"
翻译键值
| 键值 | 用途 |
|---|---|
categories.title | 页面标题 |
categories.description | 页面描述 |
categories.noCategories | 空状态文本 |
categories.prompts | "prompts" 标签 |
组件引用
SubscribeButton- 订阅/取消订阅按钮
- categoryId: 分类 ID
- categoryName: 分类名称
- initialSubscribed: 初始订阅状态
- iconOnly: 仅显示图标(列表模式)
路由
| 路径 | 说明 |
|---|---|
/categories | 分类列表页(当前) |
/categories/${slug} | 分类详情页 |
数据结构
分类对象
{
id: string;
name: string;
slug: string;
description?: string;
icon?: string;
order: number;
promptCount: number;
children: ChildCategory[];
}
子分类对象
{
id: string;
name: string;
slug: string;
description?: string;
icon?: string;
order: number;
promptCount: number;
}
性能优化
- 使用
unstable_cache缓存分类数据 - 单次聚合查询获取所有分类的提示词数量
- 使用
Set优化订阅状态查找