98 lines
2.7 KiB
TypeScript
98 lines
2.7 KiB
TypeScript
/**
|
||
* 内容上传 API
|
||
* 供科室/Skill 直接上传单篇文章到书籍内容,写入 chapters 表
|
||
* 字段:标题、定价、内容、格式、插入内容中的图片(URL 列表)
|
||
*/
|
||
|
||
import { NextRequest, NextResponse } from 'next/server'
|
||
import { query } from '@/lib/db'
|
||
|
||
function slug(id: string): string {
|
||
return id.replace(/\s+/g, '-').replace(/[^\w\u4e00-\u9fa5-]/g, '').slice(0, 30) || 'section'
|
||
}
|
||
|
||
export async function POST(request: NextRequest) {
|
||
try {
|
||
const body = await request.json()
|
||
const {
|
||
title,
|
||
price = 1,
|
||
content = '',
|
||
format = 'markdown',
|
||
images = [],
|
||
partId = 'part-1',
|
||
partTitle = '真实的人',
|
||
chapterId = 'chapter-1',
|
||
chapterTitle = '未分类',
|
||
isFree = false,
|
||
sectionId
|
||
} = body
|
||
|
||
if (!title || typeof title !== 'string') {
|
||
return NextResponse.json(
|
||
{ success: false, error: '标题 title 不能为空' },
|
||
{ status: 400 }
|
||
)
|
||
}
|
||
|
||
// 若内容中含占位符 {{image_0}} {{image_1}},用 images 数组替换
|
||
let finalContent = typeof content === 'string' ? content : ''
|
||
if (Array.isArray(images) && images.length > 0) {
|
||
images.forEach((url: string, i: number) => {
|
||
finalContent = finalContent.replace(
|
||
new RegExp(`\\{\\{image_${i}\\}\\}`, 'g'),
|
||
url.startsWith('http') ? `` : url
|
||
)
|
||
})
|
||
}
|
||
// 未替换的占位符去掉
|
||
finalContent = finalContent.replace(/\{\{image_\d+\}\}/g, '')
|
||
|
||
const wordCount = (finalContent || '').length
|
||
const id = sectionId || `upload.${slug(title)}.${Date.now()}`
|
||
|
||
await query(
|
||
`INSERT INTO chapters (id, part_id, part_title, chapter_id, chapter_title, section_title, content, word_count, is_free, price, sort_order, status)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 9999, 'published')
|
||
ON DUPLICATE KEY UPDATE
|
||
section_title = VALUES(section_title),
|
||
content = VALUES(content),
|
||
word_count = VALUES(word_count),
|
||
is_free = VALUES(is_free),
|
||
price = VALUES(price),
|
||
updated_at = CURRENT_TIMESTAMP`,
|
||
[
|
||
id,
|
||
partId,
|
||
partTitle,
|
||
chapterId,
|
||
chapterTitle,
|
||
title,
|
||
finalContent,
|
||
wordCount,
|
||
!!isFree,
|
||
Number(price) || 1
|
||
]
|
||
)
|
||
|
||
return NextResponse.json({
|
||
success: true,
|
||
id,
|
||
message: '内容已上传并写入 chapters 表',
|
||
title,
|
||
price: Number(price) || 1,
|
||
isFree: !!isFree,
|
||
wordCount
|
||
})
|
||
} catch (error) {
|
||
console.error('[Content Upload]', error)
|
||
return NextResponse.json(
|
||
{
|
||
success: false,
|
||
error: '上传失败: ' + (error as Error).message
|
||
},
|
||
{ status: 500 }
|
||
)
|
||
}
|
||
}
|