Files
soul-yongping/app/api/admin/content/route.ts

189 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// app/api/admin/content/route.ts
// 内容模块管理API
import { NextRequest, NextResponse } from 'next/server'
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import { requireAdminResponse } from '@/lib/admin-auth'
const BOOK_DIR = path.join(process.cwd(), 'book')
// GET: 获取所有章节列表
export async function GET(req: NextRequest) {
const authErr = requireAdminResponse(req)
if (authErr) return authErr
try {
const chapters = getAllChapters()
return NextResponse.json({
success: true,
chapters,
total: chapters.length
})
} catch (error) {
return NextResponse.json(
{ error: '获取章节列表失败' },
{ status: 500 }
)
}
}
// POST: 创建新章节
export async function POST(req: NextRequest) {
const authErr = requireAdminResponse(req)
if (authErr) return authErr
try {
const body = await req.json()
const { title, content, category, tags } = body
if (!title || !content) {
return NextResponse.json(
{ error: '标题和内容不能为空' },
{ status: 400 }
)
}
// 生成文件名
const fileName = `${title}.md`
const filePath = path.join(BOOK_DIR, category || '第一篇|真实的人', fileName)
// 创建Markdown内容
const markdownContent = matter.stringify(content, {
title,
date: new Date().toISOString(),
tags: tags || [],
draft: false
})
// 写入文件
fs.writeFileSync(filePath, markdownContent, 'utf-8')
return NextResponse.json({
success: true,
message: '章节创建成功',
filePath
})
} catch (error) {
console.error('创建章节失败:', error)
return NextResponse.json(
{ error: '创建章节失败' },
{ status: 500 }
)
}
}
// PUT: 更新章节
export async function PUT(req: NextRequest) {
const authErr = requireAdminResponse(req)
if (authErr) return authErr
try {
const body = await req.json()
const { id, title, content, category, tags } = body
if (!id) {
return NextResponse.json(
{ error: '章节ID不能为空' },
{ status: 400 }
)
}
// id 格式: category/filename无 .md
const filePath = path.join(BOOK_DIR, `${id}.md`)
if (!fs.existsSync(filePath)) {
return NextResponse.json(
{ error: '章节文件不存在' },
{ status: 404 }
)
}
const markdownContent = matter.stringify(content ?? '', {
title: title ?? id.split('/').pop(),
date: new Date().toISOString(),
tags: tags || [],
draft: false
})
fs.writeFileSync(filePath, markdownContent, 'utf-8')
return NextResponse.json({
success: true,
message: '章节更新成功'
})
} catch (error) {
return NextResponse.json(
{ error: '更新章节失败' },
{ status: 500 }
)
}
}
// DELETE: 删除章节
export async function DELETE(req: NextRequest) {
const authErr = requireAdminResponse(req)
if (authErr) return authErr
try {
const { searchParams } = new URL(req.url)
const id = searchParams.get('id')
if (!id) {
return NextResponse.json(
{ error: '章节ID不能为空' },
{ status: 400 }
)
}
const filePath = path.join(BOOK_DIR, `${id}.md`)
if (!fs.existsSync(filePath)) {
return NextResponse.json(
{ error: '章节文件不存在' },
{ status: 404 }
)
}
fs.unlinkSync(filePath)
return NextResponse.json({
success: true,
message: '章节删除成功'
})
} catch (error) {
return NextResponse.json(
{ error: '删除章节失败' },
{ status: 500 }
)
}
}
// 辅助函数:获取所有章节
function getAllChapters() {
const chapters: any[] = []
// 遍历book目录下的所有子目录
const categories = fs.readdirSync(BOOK_DIR).filter(item => {
const itemPath = path.join(BOOK_DIR, item)
return fs.statSync(itemPath).isDirectory()
})
categories.forEach(category => {
const categoryPath = path.join(BOOK_DIR, category)
const files = fs.readdirSync(categoryPath).filter(file => file.endsWith('.md'))
files.forEach(file => {
const filePath = path.join(categoryPath, file)
const fileContent = fs.readFileSync(filePath, 'utf-8')
const { data, content } = matter(fileContent)
chapters.push({
id: `${category}/${file.replace('.md', '')}`,
title: data.title || file.replace('.md', ''),
category,
words: content.length,
date: data.date || fs.statSync(filePath).mtime.toISOString(),
tags: data.tags || [],
draft: data.draft || false,
filePath
})
})
})
return chapters.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
}