feat: 我的页整合扫一扫/设置与提现、all-chapters去重、内容上传API、文档与后台登录
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
97
app/api/content/upload/route.ts
Normal file
97
app/api/content/upload/route.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* 内容上传 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 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user