🎉 v1.3.1: 完美版本 - H5和小程序100%统一,64章精准数据,寻找合作伙伴功能

This commit is contained in:
卡若
2026-01-14 12:50:00 +08:00
parent 326c9e6905
commit 5420499117
87 changed files with 18849 additions and 248 deletions

View File

@@ -0,0 +1,89 @@
// app/api/book/chapter/[id]/route.ts
// 获取章节详情
import { NextRequest, NextResponse } from 'next/server'
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
const BOOK_DIR = path.join(process.cwd(), 'book')
export async function GET(
req: NextRequest,
{ params }: { params: { id: string } }
) {
try {
const chapterId = params.id
// 根据ID查找对应的Markdown文件
const chapterFile = findChapterFile(chapterId)
if (!chapterFile) {
return NextResponse.json(
{ error: '章节不存在' },
{ status: 404 }
)
}
const fileContent = fs.readFileSync(chapterFile, 'utf-8')
const { data, content } = matter(fileContent)
// 判断是否需要购买前3章免费
const needPurchase = !isFreeChapter(chapterId)
// 如果需要购买,检查用户是否已购买
// TODO: 从token中获取用户信息检查购买状态
const chapter = {
id: chapterId,
title: data.title || path.basename(chapterFile, '.md'),
content: content,
words: content.length,
updateTime: data.date || fs.statSync(chapterFile).mtime.toISOString(),
needPurchase,
prevChapterId: null, // TODO: 实现上下章导航
nextChapterId: null
}
return NextResponse.json(chapter)
} catch (error) {
console.error('获取章节失败:', error)
return NextResponse.json(
{ error: '获取章节失败' },
{ status: 500 }
)
}
}
// 查找章节文件
function findChapterFile(chapterId: string): string | null {
const categories = fs.readdirSync(BOOK_DIR).filter(item => {
const itemPath = path.join(BOOK_DIR, item)
return fs.statSync(itemPath).isDirectory()
})
for (const category of categories) {
const categoryPath = path.join(BOOK_DIR, category)
const files = fs.readdirSync(categoryPath).filter(file => file.endsWith('.md'))
for (const file of files) {
const slug = `${category}/${file.replace('.md', '')}`
if (slug === chapterId || file.replace('.md', '') === chapterId) {
return path.join(categoryPath, file)
}
}
}
return null
}
// 判断是否免费章节前3章免费
function isFreeChapter(chapterId: string): boolean {
const freeChapters = [
'序言',
'第一章',
'第二章'
]
return freeChapters.some(free => chapterId.includes(free))
}