feat: 我的页整合扫一扫/设置与提现、all-chapters去重、内容上传API、文档与后台登录

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
卡若
2026-02-20 18:50:16 +08:00
parent 09fb67d2af
commit 0e4baa4b7f
27 changed files with 1526 additions and 347 deletions

View 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') ? `![图${i + 1}](${url})` : 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 }
)
}
}