categories/page.tsx - 分类列表页

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 优化订阅状态查找
← 返回目录