195 lines
5.3 KiB
TypeScript
195 lines
5.3 KiB
TypeScript
|
|
import { NextRequest, NextResponse } from 'next/server'
|
||
|
|
import { bookDB } from '@/lib/db'
|
||
|
|
import { bookData } from '@/lib/book-data'
|
||
|
|
import fs from 'fs/promises'
|
||
|
|
import path from 'path'
|
||
|
|
|
||
|
|
// 获取章节
|
||
|
|
export async function GET(req: NextRequest) {
|
||
|
|
try {
|
||
|
|
const { searchParams } = new URL(req.url)
|
||
|
|
const id = searchParams.get('id')
|
||
|
|
const action = searchParams.get('action')
|
||
|
|
|
||
|
|
// 导出所有章节
|
||
|
|
if (action === 'export') {
|
||
|
|
const data = await bookDB.exportAll()
|
||
|
|
return new NextResponse(data, {
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
'Content-Disposition': 'attachment; filename=book_sections.json'
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// 从文件系统读取章节内容
|
||
|
|
if (action === 'read' && id) {
|
||
|
|
// 查找章节文件路径
|
||
|
|
let filePath = ''
|
||
|
|
for (const part of bookData) {
|
||
|
|
for (const chapter of part.chapters) {
|
||
|
|
const section = chapter.sections.find(s => s.id === id)
|
||
|
|
if (section) {
|
||
|
|
filePath = section.filePath
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (filePath) break
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!filePath) {
|
||
|
|
return NextResponse.json({
|
||
|
|
success: false,
|
||
|
|
error: '章节不存在'
|
||
|
|
}, { status: 404 })
|
||
|
|
}
|
||
|
|
|
||
|
|
const fullPath = path.join(process.cwd(), filePath)
|
||
|
|
const content = await fs.readFile(fullPath, 'utf-8')
|
||
|
|
|
||
|
|
return NextResponse.json({
|
||
|
|
success: true,
|
||
|
|
section: { id, filePath, content }
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
if (id) {
|
||
|
|
const section = await bookDB.getSection(id)
|
||
|
|
return NextResponse.json({ success: true, section })
|
||
|
|
}
|
||
|
|
|
||
|
|
const sections = await bookDB.getAllSections()
|
||
|
|
return NextResponse.json({ success: true, sections })
|
||
|
|
} catch (error: any) {
|
||
|
|
console.error('Get book sections error:', error)
|
||
|
|
return NextResponse.json({
|
||
|
|
success: false,
|
||
|
|
error: error.message
|
||
|
|
}, { status: 500 })
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 创建或更新章节
|
||
|
|
export async function POST(req: NextRequest) {
|
||
|
|
try {
|
||
|
|
const body = await req.json()
|
||
|
|
const { action, data } = body
|
||
|
|
|
||
|
|
// 导入章节
|
||
|
|
if (action === 'import') {
|
||
|
|
const count = await bookDB.importSections(JSON.stringify(data))
|
||
|
|
return NextResponse.json({
|
||
|
|
success: true,
|
||
|
|
message: `成功导入 ${count} 个章节`
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// 同步book-data到数据库
|
||
|
|
if (action === 'sync') {
|
||
|
|
let count = 0
|
||
|
|
let sortOrder = 0
|
||
|
|
|
||
|
|
for (const part of bookData) {
|
||
|
|
for (const chapter of part.chapters) {
|
||
|
|
for (const section of chapter.sections) {
|
||
|
|
sortOrder++
|
||
|
|
const existing = await bookDB.getSection(section.id)
|
||
|
|
|
||
|
|
// 读取文件内容
|
||
|
|
let content = ''
|
||
|
|
try {
|
||
|
|
const fullPath = path.join(process.cwd(), section.filePath)
|
||
|
|
content = await fs.readFile(fullPath, 'utf-8')
|
||
|
|
} catch (e) {
|
||
|
|
console.warn(`Cannot read file: ${section.filePath}`)
|
||
|
|
}
|
||
|
|
|
||
|
|
if (existing) {
|
||
|
|
await bookDB.updateSection(section.id, {
|
||
|
|
title: section.title,
|
||
|
|
content,
|
||
|
|
price: section.price,
|
||
|
|
is_free: section.isFree
|
||
|
|
})
|
||
|
|
} else {
|
||
|
|
await bookDB.createSection({
|
||
|
|
id: section.id,
|
||
|
|
part_id: part.id,
|
||
|
|
chapter_id: chapter.id,
|
||
|
|
title: section.title,
|
||
|
|
content,
|
||
|
|
price: section.price,
|
||
|
|
is_free: section.isFree,
|
||
|
|
sort_order: sortOrder
|
||
|
|
})
|
||
|
|
}
|
||
|
|
count++
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return NextResponse.json({
|
||
|
|
success: true,
|
||
|
|
message: `成功同步 ${count} 个章节到数据库`
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// 创建单个章节
|
||
|
|
const section = await bookDB.createSection(data)
|
||
|
|
return NextResponse.json({ success: true, section })
|
||
|
|
} catch (error: any) {
|
||
|
|
console.error('Create/Import book section error:', error)
|
||
|
|
return NextResponse.json({
|
||
|
|
success: false,
|
||
|
|
error: error.message
|
||
|
|
}, { status: 500 })
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 更新章节
|
||
|
|
export async function PUT(req: NextRequest) {
|
||
|
|
try {
|
||
|
|
const body = await req.json()
|
||
|
|
const { id, ...updates } = body
|
||
|
|
|
||
|
|
if (!id) {
|
||
|
|
return NextResponse.json({
|
||
|
|
success: false,
|
||
|
|
error: '缺少章节ID'
|
||
|
|
}, { status: 400 })
|
||
|
|
}
|
||
|
|
|
||
|
|
// 如果要保存到文件系统
|
||
|
|
if (updates.content && updates.saveToFile) {
|
||
|
|
// 查找章节文件路径
|
||
|
|
let filePath = ''
|
||
|
|
for (const part of bookData) {
|
||
|
|
for (const chapter of part.chapters) {
|
||
|
|
const section = chapter.sections.find(s => s.id === id)
|
||
|
|
if (section) {
|
||
|
|
filePath = section.filePath
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (filePath) break
|
||
|
|
}
|
||
|
|
|
||
|
|
if (filePath) {
|
||
|
|
const fullPath = path.join(process.cwd(), filePath)
|
||
|
|
await fs.writeFile(fullPath, updates.content, 'utf-8')
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
await bookDB.updateSection(id, updates)
|
||
|
|
const section = await bookDB.getSection(id)
|
||
|
|
|
||
|
|
return NextResponse.json({ success: true, section })
|
||
|
|
} catch (error: any) {
|
||
|
|
console.error('Update book section error:', error)
|
||
|
|
return NextResponse.json({
|
||
|
|
success: false,
|
||
|
|
error: error.message
|
||
|
|
}, { status: 500 })
|
||
|
|
}
|
||
|
|
}
|