summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/payload-posts.ts192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/lib/payload-posts.ts b/src/lib/payload-posts.ts
new file mode 100644
index 0000000..7cf1a56
--- /dev/null
+++ b/src/lib/payload-posts.ts
@@ -0,0 +1,192 @@
+import { getPayload } from 'payload'
+import config from '@payload-config'
+import type { Media } from '@/../payload-types'
+
+// Payload 文章类型
+export interface PayloadPost {
+ id: number
+ title: string
+ slug: string
+ description?: string
+ content: unknown // Lexical 富文本内容
+ featuredImage?: Media | number
+ author?: string
+ tags?: { tag: string; id?: string }[]
+ status: 'draft' | 'published'
+ publishedAt?: string
+ createdAt: string
+ updatedAt: string
+}
+
+// 转换后的文章类型(用于前端展示)
+export interface BlogPost {
+ id: number
+ title: string
+ slug: string
+ url: string
+ description: string
+ content: unknown
+ image?: string
+ author: string
+ tags: string[]
+ date: Date
+ createdAt: Date
+ updatedAt: Date
+}
+
+// 获取 Payload 实例
+async function getPayloadClient() {
+ return getPayload({ config })
+}
+
+// 将 Payload 文章转换为博客文章格式
+function transformPost(post: PayloadPost): BlogPost {
+ // 处理封面图片 URL
+ let imageUrl: string | undefined
+ if (post.featuredImage && typeof post.featuredImage === 'object') {
+ imageUrl = post.featuredImage.url || undefined
+ }
+
+ // 处理标签数组
+ const tags = post.tags?.map((t) => t.tag).filter(Boolean) || []
+
+ // 处理日期
+ const date = post.publishedAt ? new Date(post.publishedAt) : new Date(post.createdAt)
+
+ return {
+ id: post.id,
+ title: post.title,
+ slug: post.slug,
+ url: `/posts/${post.slug}`,
+ description: post.description || '',
+ content: post.content,
+ image: imageUrl,
+ author: post.author || 'Admin',
+ tags,
+ date,
+ createdAt: new Date(post.createdAt),
+ updatedAt: new Date(post.updatedAt),
+ }
+}
+
+// 获取所有已发布的文章(按发布时间排序)
+export async function getPublishedPosts(options?: {
+ limit?: number
+ page?: number
+}): Promise<{ posts: BlogPost[]; totalDocs: number; totalPages: number }> {
+ const payload = await getPayloadClient()
+
+ const result = await payload.find({
+ collection: 'posts',
+ where: {
+ status: { equals: 'published' },
+ },
+ sort: '-publishedAt',
+ limit: options?.limit || 10,
+ page: options?.page || 1,
+ depth: 1, // 获取关联的 media 数据
+ })
+
+ return {
+ posts: result.docs.map((doc) => transformPost(doc as unknown as PayloadPost)),
+ totalDocs: result.totalDocs,
+ totalPages: result.totalPages,
+ }
+}
+
+// 根据 slug 获取单篇文章
+export async function getPostBySlug(slug: string): Promise<BlogPost | null> {
+ const payload = await getPayloadClient()
+
+ const result = await payload.find({
+ collection: 'posts',
+ where: {
+ slug: { equals: slug },
+ status: { equals: 'published' },
+ },
+ limit: 1,
+ depth: 1,
+ })
+
+ if (result.docs.length === 0) {
+ return null
+ }
+
+ return transformPost(result.docs[0] as unknown as PayloadPost)
+}
+
+// 获取所有已发布文章的 slug(用于静态生成)
+export async function getAllPostSlugs(): Promise<string[]> {
+ const payload = await getPayloadClient()
+
+ const result = await payload.find({
+ collection: 'posts',
+ where: {
+ status: { equals: 'published' },
+ },
+ limit: 1000,
+ depth: 0,
+ })
+
+ return result.docs.map((doc) => (doc as unknown as PayloadPost).slug)
+}
+
+// 根据标签获取文章
+export async function getPostsByTag(
+ tag: string,
+ options?: { limit?: number; page?: number }
+): Promise<{ posts: BlogPost[]; totalDocs: number; totalPages: number }> {
+ const payload = await getPayloadClient()
+
+ const result = await payload.find({
+ collection: 'posts',
+ where: {
+ and: [
+ { status: { equals: 'published' } },
+ { 'tags.tag': { equals: tag } },
+ ],
+ },
+ sort: '-publishedAt',
+ limit: options?.limit || 10,
+ page: options?.page || 1,
+ depth: 1,
+ })
+
+ return {
+ posts: result.docs.map((doc) => transformPost(doc as unknown as PayloadPost)),
+ totalDocs: result.totalDocs,
+ totalPages: result.totalPages,
+ }
+}
+
+// 获取所有标签
+export async function getAllTags(): Promise<{ tag: string; count: number }[]> {
+ const payload = await getPayloadClient()
+
+ const result = await payload.find({
+ collection: 'posts',
+ where: {
+ status: { equals: 'published' },
+ },
+ limit: 1000,
+ depth: 0,
+ })
+
+ // 统计标签
+ const tagCounts = new Map<string, number>()
+
+ for (const doc of result.docs) {
+ const post = doc as unknown as PayloadPost
+ if (post.tags) {
+ for (const { tag } of post.tags) {
+ if (tag) {
+ tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1)
+ }
+ }
+ }
+ }
+
+ return Array.from(tagCounts.entries())
+ .map(([tag, count]) => ({ tag, count }))
+ .sort((a, b) => b.count - a.count)
+}